]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Fix krb5 GSS MIC verification
authorGreg Hudson <ghudson@mit.edu>
Sun, 17 Aug 2025 06:55:40 +0000 (02:55 -0400)
committerGreg Hudson <ghudson@mit.edu>
Tue, 19 Aug 2025 21:08:42 +0000 (17:08 -0400)
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.

ticket: 9181
tags: pullup
target_version: 1.22-next

src/lib/gssapi/krb5/util_crypt.c
src/lib/gssapi/krb5/verify_mic.c
src/tests/gssapi/t_invalid.c

index 28411429bf6eb35f4bf20e2f405ac3194de6dcce..386842e8a6e327a9ed4ed18ab94fa4fea522f54b 100644 (file)
@@ -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. */
index 9852f49912a93e866d81ca8a641fe756e115af71..1c11d2016fcaac319c4ac35f1b56637c34489acf 100644 (file)
@@ -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);
 }
index c4a5a99ba9e4653203183688914b19914b380577..ecbf5ec216234d98074bca565584a3be81580232 100644 (file)
@@ -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++) {