krb5 commit [krb5-1.22]: Fix krb5 GSS MIC verification
[email protected] Wed, 20 Aug 2025 14:30:52 -0400 (EDT)
| Newsgroups | gmane.comp.encryption.kerberos.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://github.com/krb5/krb5/commit/2531770c10115cb8b5ff529f813d86fa5a36db4c commit 2531770c10115cb8b5ff529f813d86fa5a36db4c Author: Greg Hudson <[email protected]> Date: Sun Aug 17 02:55:40 2025 -0400 Fix krb5 GSS MIC verification Commit 7ae0adcdf16687810f747e284c9fb571a561c5bd contains a pair of bugs that, in combination, result in the acceptance of MIC tokens with invalid checksums. In kg_verify_checksum_v3(), properly set bytes 4..7 to 0xFF in the composed token header for MIC tokens. In verify_mic_v3(), properly check the return value of kg_verify_checksum_v3(). In t_invalid.c, test invalid MIC tokens by altering the bytes of a valid MIC. Reported by Francis Dupont. CVE-2025-57736: MIT krb5 release 1.22 incorrectly accepts krb5 GSS-API MIC tokens with invalid checksums. (cherry picked from commit 83cd76b11b069afbc6162edecb30096571e89dd5) ticket: 9181 version_fixed: 1.22.1 src/lib/gssapi/krb5/util_crypt.c | 10 +++++++--- src/lib/gssapi/krb5/verify_mic.c | 11 ++++------- src/tests/gssapi/t_invalid.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c index 28411429b..386842e8a 100644 --- a/src/lib/gssapi/krb5/util_crypt.c +++ b/src/lib/gssapi/krb5/util_crypt.c @@ -322,12 +322,16 @@ kg_verify_checksum_v3(krb5_context context, krb5_key key, krb5_keyusage usage, uint8_t ckhdr[16]; krb5_boolean valid; - /* Compose an RFC 4121 token header with EC and RRC set to 0. */ + /* + * Compose an RFC 4121 token header for the checksum. For a wrap token, + * the EC and RRC fields have the value 0 for the checksum operation, + * regardless of their values in the actual token (RFC 4121 section 4.2.4). + * For a MIC token, the corresponding four bytes have the value 0xFF. + */ store_16_be(toktype, ckhdr); ckhdr[2] = flags; ckhdr[3] = 0xFF; - store_16_be(0, ckhdr + 4); - store_16_be(0, ckhdr + 6); + store_32_be((toktype == KG2_TOK_MIC_MSG) ? 0xFFFFFFFF : 0, ckhdr + 4); store_64_be(seqnum, ckhdr + 8); /* Verify the checksum over the data and composed header. */ diff --git a/src/lib/gssapi/krb5/verify_mic.c b/src/lib/gssapi/krb5/verify_mic.c index 9852f4991..1c11d2016 100644 --- a/src/lib/gssapi/krb5/verify_mic.c +++ b/src/lib/gssapi/krb5/verify_mic.c @@ -90,7 +90,6 @@ verify_mic_v3(krb5_context context, OM_uint32 *minor_status, krb5_gss_ctx_id_rec *ctx, struct k5input *in, gss_buffer_t message) { - OM_uint32 status; krb5_keyusage usage; krb5_key key; krb5_cksumtype cksumtype; @@ -124,12 +123,10 @@ verify_mic_v3(krb5_context context, OM_uint32 *minor_status, } assert(key != NULL); - status = kg_verify_checksum_v3(context, key, usage, cksumtype, - KG2_TOK_MIC_MSG, flags, seqnum, - message->value, message->length, - in->ptr, in->len); - if (status != GSS_S_COMPLETE) - return status; + if (!kg_verify_checksum_v3(context, key, usage, cksumtype, KG2_TOK_MIC_MSG, + flags, seqnum, message->value, message->length, + in->ptr, in->len)) + return GSS_S_BAD_SIG; return g_seqstate_check(ctx->seqstate, seqnum); } diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c index c4a5a99ba..ecbf5ec21 100644 --- a/src/tests/gssapi/t_invalid.c +++ b/src/tests/gssapi/t_invalid.c @@ -397,6 +397,34 @@ test_iov_large_asn1_wrapper(gss_ctx_id_t ctx) free(iov[0].buffer.value); } +static void +test_cfx_verify_mic(gss_ctx_id_t ctx) +{ + OM_uint32 major, minor; + gss_buffer_desc message, token; + uint8_t msg[] = "message"; + uint8_t mic[] = "\x04\x04\x00\xFF\xFF\xFF\xFF\xFF" + "\x00\x00\x00\x00\x00\x00\x00\x00\x97\xE9\x63\x3F\x9D\x82\x2B\x74" + "\x67\x94\x8A\xD0"; + size_t i; + + message.value = msg; + message.length = sizeof(msg) - 1; + token.value = mic; + token.length = sizeof(mic) - 1; + + major = gss_verify_mic(&minor, ctx, &message, &token, NULL); + check_gsserr("gss_verify_mic", major, minor); + + for (i = 0; i < token.length; i++) { + mic[i]++; + major = gss_verify_mic(&minor, ctx, &message, &token, NULL); + if (major != GSS_S_DEFECTIVE_TOKEN && major != GSS_S_BAD_SIG) + abort(); + mic[i]--; + } +} + /* Process wrap and MIC tokens with incomplete headers. */ static void test_short_header(gss_ctx_id_t ctx) @@ -598,6 +626,7 @@ main(int argc, char **argv) test_cfx_short_plaintext(ctx, cfx_subkey); test_cfx_large_ec(ctx, cfx_subkey); test_iov_large_asn1_wrapper(ctx); + test_cfx_verify_mic(ctx); free_fake_context(ctx); for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {