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
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. */
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;
}
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);
}
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)
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++) {