[31685] in CVS-changelog-for-Kerberos-V5
krb5 commit [krb5-1.22]: Check PAC server checksum verification result
daemon@ATHENA.MIT.EDU (ghudson@mit.edu)
Mon Nov 9 12:03:00 2026
From: ghudson@mit.edu
To: cvs-krb5@mit.edu
Message-Id: <20261109170255.71EBB105839@krbdev.mit.edu>
Date: Mon, 9 Nov 2026 12:02:55 -0500 (EST)
MIME-Version: 1.0
Reply-To: krbdev@mit.edu
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: cvs-krb5-bounces@mit.edu
https://github.com/krb5/krb5/commit/ba3f7e11e7bb3f1ef1a6deb5ea9cb6ffc7546e84
commit ba3f7e11e7bb3f1ef1a6deb5ea9cb6ffc7546e84
Author: Alejandro Pacheco <alepacheco99@gmail.com>
Date: Fri Oct 16 11:48:06 2026 +0200
Check PAC server checksum verification result
In verify_pac_checksums(), stop if the server checksum does not
verify. In krb5_pac_verify_ext(), validate the client principal
before the checksums, so that a client mismatch does not leave the PAC
marked as verified. Add a test case.
CVE-2026-111423:
In MIT krb5 release 1.21 and later, server applications will
erroneously treat the PAC within a ticket as verified when the server
checksum is invalid.
[ghudson@mit.edu: edited commit message]
(cherry picked from commit ffb49b20a30c01ac799e2444542fc9dc748ff8db)
ticket: 9259
version_fixed: 1.22.3
src/lib/krb5/krb/pac.c | 14 +++++---
src/lib/krb5/krb/t_pac.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+), 5 deletions(-)
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
index 51c4b6a1c..17c20a455 100644
--- a/src/lib/krb5/krb/pac.c
+++ b/src/lib/krb5/krb/pac.c
@@ -538,6 +538,8 @@ verify_pac_checksums(krb5_context context, const krb5_pac pac,
/* Verify the server checksum over the PAC copy. */
ret = verify_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM, server,
KRB5_KEYUSAGE_APP_DATA_CKSUM, ©);
+ if (ret)
+ goto cleanup;
}
if (privsvr != NULL && expect_full_checksum) {
@@ -711,15 +713,17 @@ krb5_pac_verify_ext(krb5_context context,
{
krb5_error_code ret;
- if (server != NULL || privsvr != NULL) {
- ret = verify_pac_checksums(context, pac, FALSE, server, privsvr);
+ /* Validate the client first, so that the PAC is only marked as verified
+ * if all of the requested checks pass. */
+ if (principal != NULL) {
+ ret = k5_pac_validate_client(context, pac, authtime,
+ principal, with_realm);
if (ret)
return ret;
}
- if (principal != NULL) {
- ret = k5_pac_validate_client(context, pac, authtime,
- principal, with_realm);
+ if (server != NULL || privsvr != NULL) {
+ ret = verify_pac_checksums(context, pac, FALSE, server, privsvr);
if (ret)
return ret;
}
diff --git a/src/lib/krb5/krb/t_pac.c b/src/lib/krb5/krb/t_pac.c
index 81f1642ab..98762333e 100644
--- a/src/lib/krb5/krb/t_pac.c
+++ b/src/lib/krb5/krb/t_pac.c
@@ -33,6 +33,7 @@
*/
#include "k5-int.h"
+#include "authdata.h"
#define U(x) (uint8_t *)x
@@ -816,6 +817,87 @@ test_pac_ticket_signature(krb5_context context)
krb5_free_ticket(context, ticket);
}
+/* Check that krb5_pac_verify() marks a PAC as verified only if every
+ * requested check passes. */
+static void
+test_pac_verify_marks_verified(krb5_context context, krb5_const_principal p)
+{
+ krb5_error_code ret;
+ krb5_pac pac;
+ krb5_data data;
+ krb5_principal wrong;
+ uint32_t i;
+
+ ret = krb5_parse_name(context, "wrong@WIN2K3.THINKER.LOCAL", &wrong);
+ if (ret)
+ err(context, ret, "krb5_parse_name");
+
+ ret = krb5_pac_init(context, &pac);
+ if (ret)
+ err(context, ret, "krb5_pac_init");
+ ret = krb5_pac_sign(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock, &data);
+ if (ret)
+ err(context, ret, "krb5_pac_sign");
+ krb5_pac_free(context, pac);
+
+ ret = krb5_pac_parse(context, data.data, data.length, &pac);
+ if (ret)
+ err(context, ret, "krb5_pac_parse");
+ ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock);
+ if (ret)
+ err(context, ret, "krb5_pac_verify");
+ if (!pac->verified)
+ err(context, 0, "PAC not marked verified");
+ krb5_pac_free(context, pac);
+
+ /* A wrong server key must fail even if the privsvr checksum is good. */
+ ret = krb5_pac_parse(context, data.data, data.length, &pac);
+ if (ret)
+ err(context, ret, "krb5_pac_parse");
+ ret = krb5_pac_verify(context, pac, authtime, p, &kdc_keyblock,
+ &kdc_keyblock);
+ if (ret != KRB5KRB_AP_ERR_MODIFIED)
+ err(context, ret, "krb5_pac_verify with wrong server key");
+ if (pac->verified)
+ err(context, 0, "PAC marked verified with wrong server key");
+ krb5_pac_free(context, pac);
+
+ /* A client principal mismatch must not mark the PAC as verified. */
+ ret = krb5_pac_parse(context, data.data, data.length, &pac);
+ if (ret)
+ err(context, ret, "krb5_pac_parse");
+ ret = krb5_pac_verify(context, pac, authtime, wrong, &member_keyblock,
+ NULL);
+ if (ret != KRB5KRB_AP_WRONG_PRINC)
+ err(context, ret, "krb5_pac_verify with wrong principal");
+ if (pac->verified)
+ err(context, 0, "PAC marked verified with wrong principal");
+ krb5_pac_free(context, pac);
+
+ /* Corrupt the server checksum and verify with only the server key. */
+ ret = krb5_pac_parse(context, data.data, data.length, &pac);
+ if (ret)
+ err(context, ret, "krb5_pac_parse");
+ for (i = 0; i < pac->nbuffers; i++) {
+ if (pac->buffers[i].type == KRB5_PAC_SERVER_CHECKSUM)
+ break;
+ }
+ if (i == pac->nbuffers)
+ err(context, 0, "no server checksum buffer");
+ pac->data.data[pac->buffers[i].offset + PAC_SIGNATURE_DATA_LENGTH] ^= 1;
+ ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock, NULL);
+ if (ret != KRB5KRB_AP_ERR_MODIFIED)
+ err(context, ret, "krb5_pac_verify with bad server checksum");
+ if (pac->verified)
+ err(context, 0, "PAC marked verified with bad server checksum");
+ krb5_pac_free(context, pac);
+
+ krb5_free_data_contents(context, &data);
+ krb5_free_principal(context, wrong);
+}
+
int
main(int argc, char **argv)
{
@@ -1144,6 +1226,8 @@ main(int argc, char **argv)
krb5_pac_free(context, pac);
+ test_pac_verify_marks_verified(context, p);
+
krb5_free_principal(context, p);
krb5_free_context(context);
_______________________________________________
cvs-krb5 mailing list
cvs-krb5@mit.edu
https://mailman.mit.edu/mailman/listinfo/cvs-krb5