Support PAC with KDC extended signature and without ticket signature
Resolves: rhbz#2169477 Signed-off-by: Julien Rische <jrische@redhat.com>
This commit is contained in:
parent
588f556722
commit
7d215a54da
673
Add-PAC-full-checksums.patch
Normal file
673
Add-PAC-full-checksums.patch
Normal file
@ -0,0 +1,673 @@
|
||||
From bf3e55bcd66c5d35fddadc94fd680bdd57508bce Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Thu, 22 Dec 2022 03:05:23 -0500
|
||||
Subject: [PATCH] Add PAC full checksums
|
||||
|
||||
A paper by Tom Tervoort noted that computing the PAC privsvr checksum
|
||||
over only the server checksum is vulnerable to collision attacks
|
||||
(CVE-2022-37967). In response, Microsoft has added a second KDC
|
||||
checksum over the full contents of the PAC. Generate and verify full
|
||||
KDC checksums in PACs for service tickets. Update the t_pac.c ticket
|
||||
test case to use a ticket issued by a recent version of Active
|
||||
Directory (provided by Stefan Metzmacher).
|
||||
|
||||
ticket: 9084 (new)
|
||||
---
|
||||
doc/appdev/refs/macros/index.rst | 1 +
|
||||
src/include/krb5/krb5.hin | 1 +
|
||||
src/lib/krb5/krb/pac.c | 92 +++++++++--------
|
||||
src/lib/krb5/krb/pac_sign.c | 146 +++++++++++++++-----------
|
||||
src/lib/krb5/krb/t_pac.c | 171 ++++++++++++++++++-------------
|
||||
src/tests/t_authdata.py | 5 +-
|
||||
6 files changed, 242 insertions(+), 174 deletions(-)
|
||||
|
||||
diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst
|
||||
index c6ea088742..22ef2b2f42 100644
|
||||
--- a/doc/appdev/refs/macros/index.rst
|
||||
+++ b/doc/appdev/refs/macros/index.rst
|
||||
@@ -247,6 +247,7 @@ Public
|
||||
KRB5_PAC_SERVER_CHECKSUM.rst
|
||||
KRB5_PAC_TICKET_CHECKSUM.rst
|
||||
KRB5_PAC_UPN_DNS_INFO.rst
|
||||
+ KRB5_PAC_FULL_CHECKSUM.rst
|
||||
KRB5_PADATA_AFS3_SALT.rst
|
||||
KRB5_PADATA_AP_REQ.rst
|
||||
KRB5_PADATA_AS_CHECKSUM.rst
|
||||
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||
index 8e59628bd9..12a1d441b8 100644
|
||||
--- a/src/include/krb5/krb5.hin
|
||||
+++ b/src/include/krb5/krb5.hin
|
||||
@@ -8187,6 +8187,7 @@ krb5_verify_authdata_kdc_issued(krb5_context context,
|
||||
#define KRB5_PAC_TICKET_CHECKSUM 16 /**< Ticket checksum */
|
||||
#define KRB5_PAC_ATTRIBUTES_INFO 17 /**< PAC attributes */
|
||||
#define KRB5_PAC_REQUESTOR 18 /**< PAC requestor SID */
|
||||
+#define KRB5_PAC_FULL_CHECKSUM 19 /**< KDC full checksum */
|
||||
|
||||
struct krb5_pac_data;
|
||||
/** PAC data structure to convey authorization information */
|
||||
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
|
||||
index 2f6ad4e1df..9c00178a28 100644
|
||||
--- a/src/lib/krb5/krb/pac.c
|
||||
+++ b/src/lib/krb5/krb/pac.c
|
||||
@@ -500,7 +500,8 @@ zero_signature(krb5_context context, const krb5_pac pac, krb5_ui_4 type,
|
||||
size_t i;
|
||||
|
||||
assert(type == KRB5_PAC_SERVER_CHECKSUM ||
|
||||
- type == KRB5_PAC_PRIVSVR_CHECKSUM);
|
||||
+ type == KRB5_PAC_PRIVSVR_CHECKSUM ||
|
||||
+ type == KRB5_PAC_FULL_CHECKSUM);
|
||||
assert(data->length >= pac->data.length);
|
||||
|
||||
for (i = 0; i < pac->pac->cBuffers; i++) {
|
||||
@@ -567,17 +568,17 @@ verify_checksum(krb5_context context, const krb5_pac pac, uint32_t buffer_type,
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
-verify_server_checksum(krb5_context context, const krb5_pac pac,
|
||||
- const krb5_keyblock *server)
|
||||
+verify_pac_checksums(krb5_context context, const krb5_pac pac,
|
||||
+ krb5_boolean expect_full_checksum,
|
||||
+ const krb5_keyblock *server, const krb5_keyblock *privsvr)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
- krb5_data copy; /* PAC with zeroed checksums */
|
||||
+ krb5_data copy, server_checksum;
|
||||
|
||||
+ /* Make a copy of the PAC with zeroed out server and privsvr checksums. */
|
||||
ret = krb5int_copy_data_contents(context, &pac->data, ©);
|
||||
if (ret)
|
||||
return ret;
|
||||
-
|
||||
- /* Zero out both checksum buffers */
|
||||
ret = zero_signature(context, pac, KRB5_PAC_SERVER_CHECKSUM, ©);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
@@ -585,32 +586,46 @@ verify_server_checksum(krb5_context context, const krb5_pac pac,
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
- ret = verify_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM, server,
|
||||
- KRB5_KEYUSAGE_APP_DATA_CKSUM, ©);
|
||||
+ if (server != NULL) {
|
||||
+ /* Verify the server checksum over the PAC copy. */
|
||||
+ ret = verify_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM, server,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, ©);
|
||||
+ }
|
||||
|
||||
-cleanup:
|
||||
- free(copy.data);
|
||||
- return ret;
|
||||
-}
|
||||
+ if (privsvr != NULL && expect_full_checksum) {
|
||||
+ /* Zero the full checksum buffer in the copy and verify the full
|
||||
+ * checksum over the copy with all three checksums zeroed. */
|
||||
+ ret = zero_signature(context, pac, KRB5_PAC_FULL_CHECKSUM, ©);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ ret = verify_checksum(context, pac, KRB5_PAC_FULL_CHECKSUM, privsvr,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, ©);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
|
||||
-static krb5_error_code
|
||||
-verify_kdc_checksum(krb5_context context, const krb5_pac pac,
|
||||
- const krb5_keyblock *privsvr)
|
||||
-{
|
||||
- krb5_error_code ret;
|
||||
- krb5_data server_checksum;
|
||||
+ if (privsvr != NULL) {
|
||||
+ /* Verify the privsvr checksum over the server checksum. */
|
||||
+ ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,
|
||||
+ &server_checksum);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH)
|
||||
+ return KRB5_BAD_MSIZE;
|
||||
+ server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
|
||||
+ server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;
|
||||
|
||||
- ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,
|
||||
- &server_checksum);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH)
|
||||
- return KRB5_BAD_MSIZE;
|
||||
- server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
|
||||
- server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;
|
||||
+ ret = verify_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, privsvr,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, &server_checksum);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ pac->verified = TRUE;
|
||||
|
||||
- return verify_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, privsvr,
|
||||
- KRB5_KEYUSAGE_APP_DATA_CKSUM, &server_checksum);
|
||||
+cleanup:
|
||||
+ free(copy.data);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
/* Per MS-PAC 2.8.3, tickets encrypted to TGS and password change principals
|
||||
@@ -638,6 +653,7 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
|
||||
krb5_authdata **authdata, *orig, **ifrel = NULL, **recoded_ifrel = NULL;
|
||||
uint8_t z = 0;
|
||||
krb5_authdata zpac = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC, 1, &z };
|
||||
+ krb5_boolean is_service_tkt;
|
||||
size_t i, j;
|
||||
|
||||
*pac_out = NULL;
|
||||
@@ -679,7 +695,8 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
- if (privsvr != NULL && k5_pac_should_have_ticket_signature(server_princ)) {
|
||||
+ is_service_tkt = k5_pac_should_have_ticket_signature(server_princ);
|
||||
+ if (privsvr != NULL && is_service_tkt) {
|
||||
/* To check the PAC ticket signatures, re-encode the ticket with the
|
||||
* PAC contents replaced by a single zero. */
|
||||
orig = ifrel[j];
|
||||
@@ -703,8 +720,9 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- ret = krb5_pac_verify_ext(context, pac, enc_tkt->times.authtime, NULL,
|
||||
- server, privsvr, FALSE);
|
||||
+ ret = verify_pac_checksums(context, pac, is_service_tkt, server, privsvr);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
|
||||
*pac_out = pac;
|
||||
pac = NULL;
|
||||
@@ -740,14 +758,8 @@ krb5_pac_verify_ext(krb5_context context,
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
- if (server != NULL) {
|
||||
- ret = verify_server_checksum(context, pac, server);
|
||||
- if (ret != 0)
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- if (privsvr != NULL) {
|
||||
- ret = verify_kdc_checksum(context, pac, privsvr);
|
||||
+ if (server != NULL || privsvr != NULL) {
|
||||
+ ret = verify_pac_checksums(context, pac, FALSE, server, privsvr);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -759,8 +771,6 @@ krb5_pac_verify_ext(krb5_context context,
|
||||
return ret;
|
||||
}
|
||||
|
||||
- pac->verified = TRUE;
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c
|
||||
index 0f9581abbb..8ea61ac17b 100644
|
||||
--- a/src/lib/krb5/krb/pac_sign.c
|
||||
+++ b/src/lib/krb5/krb/pac_sign.c
|
||||
@@ -187,26 +187,41 @@ k5_pac_encode_header(krb5_context context, krb5_pac pac)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-krb5_error_code KRB5_CALLCONV
|
||||
-krb5_pac_sign(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
- krb5_const_principal principal, const krb5_keyblock *server_key,
|
||||
- const krb5_keyblock *privsvr_key, krb5_data *data)
|
||||
+/* Find the buffer of type buftype in pac and write within it a checksum of
|
||||
+ * type cksumtype over data. Set *cksum_out to the checksum. */
|
||||
+static krb5_error_code
|
||||
+compute_pac_checksum(krb5_context context, krb5_pac pac, uint32_t buftype,
|
||||
+ const krb5_keyblock *key, krb5_cksumtype cksumtype,
|
||||
+ const krb5_data *data, krb5_data *cksum_out)
|
||||
{
|
||||
- return krb5_pac_sign_ext(context, pac, authtime, principal, server_key,
|
||||
- privsvr_key, FALSE, data);
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_data buf;
|
||||
+ krb5_crypto_iov iov[2];
|
||||
+
|
||||
+ ret = k5_pac_locate_buffer(context, pac, buftype, &buf);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ assert(buf.length > PAC_SIGNATURE_DATA_LENGTH);
|
||||
+ *cksum_out = make_data(buf.data + PAC_SIGNATURE_DATA_LENGTH,
|
||||
+ buf.length - PAC_SIGNATURE_DATA_LENGTH);
|
||||
+ iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
+ iov[0].data = *data;
|
||||
+ iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
|
||||
+ iov[1].data = *cksum_out;
|
||||
+ return krb5_c_make_checksum_iov(context, cksumtype, key,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, iov, 2);
|
||||
}
|
||||
|
||||
-krb5_error_code KRB5_CALLCONV
|
||||
-krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
- krb5_const_principal principal,
|
||||
- const krb5_keyblock *server_key,
|
||||
- const krb5_keyblock *privsvr_key, krb5_boolean with_realm,
|
||||
- krb5_data *data)
|
||||
+static krb5_error_code
|
||||
+sign_pac(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
+ krb5_const_principal principal, const krb5_keyblock *server_key,
|
||||
+ const krb5_keyblock *privsvr_key, krb5_boolean with_realm,
|
||||
+ krb5_boolean is_service_tkt, krb5_data *data)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
- krb5_data server_cksum, privsvr_cksum;
|
||||
+ krb5_data full_cksum, server_cksum, privsvr_cksum;
|
||||
krb5_cksumtype server_cksumtype, privsvr_cksumtype;
|
||||
- krb5_crypto_iov iov[2];
|
||||
|
||||
data->length = 0;
|
||||
data->data = NULL;
|
||||
@@ -214,67 +229,53 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
if (principal != NULL) {
|
||||
ret = k5_insert_client_info(context, pac, authtime, principal,
|
||||
with_realm);
|
||||
- if (ret != 0)
|
||||
+ if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
- /* Create zeroed buffers for both checksums */
|
||||
+ /* Create zeroed buffers for all checksums. */
|
||||
ret = k5_insert_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM,
|
||||
server_key, &server_cksumtype);
|
||||
- if (ret != 0)
|
||||
+ if (ret)
|
||||
return ret;
|
||||
-
|
||||
ret = k5_insert_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,
|
||||
privsvr_key, &privsvr_cksumtype);
|
||||
- if (ret != 0)
|
||||
+ if (ret)
|
||||
return ret;
|
||||
+ if (is_service_tkt) {
|
||||
+ ret = k5_insert_checksum(context, pac, KRB5_PAC_FULL_CHECKSUM,
|
||||
+ privsvr_key, &privsvr_cksumtype);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
- /* Now, encode the PAC header so that the checksums will include it */
|
||||
+ /* Encode the PAC header so that the checksums will include it. */
|
||||
ret = k5_pac_encode_header(context, pac);
|
||||
- if (ret != 0)
|
||||
- return ret;
|
||||
-
|
||||
- /* Generate the server checksum over the entire PAC */
|
||||
- ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,
|
||||
- &server_cksum);
|
||||
- if (ret != 0)
|
||||
+ if (ret)
|
||||
return ret;
|
||||
|
||||
- assert(server_cksum.length > PAC_SIGNATURE_DATA_LENGTH);
|
||||
-
|
||||
- iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
- iov[0].data = pac->data;
|
||||
-
|
||||
- iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
|
||||
- iov[1].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
|
||||
- iov[1].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
+ if (is_service_tkt) {
|
||||
+ /* Generate a full KDC checksum over the whole PAC. */
|
||||
+ ret = compute_pac_checksum(context, pac, KRB5_PAC_FULL_CHECKSUM,
|
||||
+ privsvr_key, privsvr_cksumtype,
|
||||
+ &pac->data, &full_cksum);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
- ret = krb5_c_make_checksum_iov(context, server_cksumtype,
|
||||
- server_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
|
||||
- iov, sizeof(iov)/sizeof(iov[0]));
|
||||
- if (ret != 0)
|
||||
+ /* Generate the server checksum over the whole PAC, including the full KDC
|
||||
+ * checksum if we added one. */
|
||||
+ ret = compute_pac_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM,
|
||||
+ server_key, server_cksumtype, &pac->data,
|
||||
+ &server_cksum);
|
||||
+ if (ret)
|
||||
return ret;
|
||||
|
||||
- /* Generate the privsvr checksum over the server checksum buffer */
|
||||
- ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,
|
||||
+ /* Generate the privsvr checksum over the server checksum buffer. */
|
||||
+ ret = compute_pac_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,
|
||||
+ privsvr_key, privsvr_cksumtype, &server_cksum,
|
||||
&privsvr_cksum);
|
||||
- if (ret != 0)
|
||||
- return ret;
|
||||
-
|
||||
- assert(privsvr_cksum.length > PAC_SIGNATURE_DATA_LENGTH);
|
||||
-
|
||||
- iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
- iov[0].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
|
||||
- iov[0].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
-
|
||||
- iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
|
||||
- iov[1].data.data = privsvr_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
|
||||
- iov[1].data.length = privsvr_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
-
|
||||
- ret = krb5_c_make_checksum_iov(context, privsvr_cksumtype,
|
||||
- privsvr_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
|
||||
- iov, sizeof(iov)/sizeof(iov[0]));
|
||||
- if (ret != 0)
|
||||
+ if (ret)
|
||||
return ret;
|
||||
|
||||
data->data = k5memdup(pac->data.data, pac->data.length, &ret);
|
||||
@@ -288,6 +289,26 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_pac_sign(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
+ krb5_const_principal principal, const krb5_keyblock *server_key,
|
||||
+ const krb5_keyblock *privsvr_key, krb5_data *data)
|
||||
+{
|
||||
+ return sign_pac(context, pac, authtime, principal, server_key,
|
||||
+ privsvr_key, FALSE, FALSE, data);
|
||||
+}
|
||||
+
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
+ krb5_const_principal principal,
|
||||
+ const krb5_keyblock *server_key,
|
||||
+ const krb5_keyblock *privsvr_key, krb5_boolean with_realm,
|
||||
+ krb5_data *data)
|
||||
+{
|
||||
+ return sign_pac(context, pac, authtime, principal, server_key, privsvr_key,
|
||||
+ with_realm, FALSE, data);
|
||||
+}
|
||||
+
|
||||
/* Add a signature over der_enc_tkt in privsvr to pac. der_enc_tkt should be
|
||||
* encoded with a dummy PAC authdata element containing a single zero byte. */
|
||||
static krb5_error_code
|
||||
@@ -359,6 +380,7 @@ krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,
|
||||
krb5_error_code ret;
|
||||
krb5_data *der_enc_tkt = NULL, pac_data = empty_data();
|
||||
krb5_authdata **list, *pac_ad;
|
||||
+ krb5_boolean is_service_tkt;
|
||||
size_t count;
|
||||
|
||||
/* Reallocate space for another authdata element in enc_tkt. */
|
||||
@@ -377,7 +399,8 @@ krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,
|
||||
memmove(list + 1, list, (count + 1) * sizeof(*list));
|
||||
list[0] = pac_ad;
|
||||
|
||||
- if (k5_pac_should_have_ticket_signature(server_princ)) {
|
||||
+ is_service_tkt = k5_pac_should_have_ticket_signature(server_princ);
|
||||
+ if (is_service_tkt) {
|
||||
ret = encode_krb5_enc_tkt_part(enc_tkt, &der_enc_tkt);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
@@ -388,9 +411,8 @@ krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- ret = krb5_pac_sign_ext(context, pac, enc_tkt->times.authtime,
|
||||
- client_princ, server, privsvr, with_realm,
|
||||
- &pac_data);
|
||||
+ ret = sign_pac(context, pac, enc_tkt->times.authtime, client_princ, server,
|
||||
+ privsvr, with_realm, is_service_tkt, &pac_data);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
diff --git a/src/lib/krb5/krb/t_pac.c b/src/lib/krb5/krb/t_pac.c
|
||||
index 173bde7bab..81f1642ab0 100644
|
||||
--- a/src/lib/krb5/krb/t_pac.c
|
||||
+++ b/src/lib/krb5/krb/t_pac.c
|
||||
@@ -607,78 +607,102 @@ check_pac(krb5_context context, int index, const unsigned char *pdata,
|
||||
|
||||
static const krb5_keyblock ticket_sig_krbtgt_key = {
|
||||
0, ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
- 32, U("\x7a\x58\x98\xd2\xaf\xa6\xaf\xc0\x6a\xce\x06\x04\x4b\xc2\x70\x84"
|
||||
- "\x9b\x8e\x0a\x6c\x4c\x07\xdc\x6f\xbb\x48\x43\xe1\xd2\xaa\x97\xf7")
|
||||
+ 32, U("\x03\x73\x81\xEC\x43\x96\x7B\xC2\xAC\x3D\xF5\x2A\xAE\x95\xA6\x8E"
|
||||
+ "\xBE\x24\x58\xDB\xCE\x52\x28\x20\xAF\x5E\xB7\x04\xA2\x22\x71\x4F")
|
||||
};
|
||||
|
||||
static const krb5_keyblock ticket_sig_server_key = {
|
||||
- 0, ENCTYPE_ARCFOUR_HMAC,
|
||||
- 16, U("\xed\x23\x11\x20\x7a\x21\x44\x20\xbf\xc0\x8d\x36\xf7\xf6\xb2\x3e")
|
||||
+ 0, ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
+ 32, U("\x11\x4A\x84\xE3\x14\x8F\xAA\xB1\xFA\x7B\x53\x51\xB2\x8A\xC2\xF1"
|
||||
+ "\xFD\x19\x6D\x61\xE0\xF3\xF2\x3E\x1F\xDB\xD3\xC1\x79\x7D\xC1\xEE")
|
||||
};
|
||||
|
||||
+/* A ticket issued by an Active Directory KDC (Windows Server 2022), containing
|
||||
+ * a PAC with a full checksum. */
|
||||
static const krb5_data ticket_data = {
|
||||
- .length = 972, .data =
|
||||
- "\x61\x82\x03\xC8\x30\x82\x03\xC4\xA0\x03\x02\x01\x05\xA1\x0A\x1B"
|
||||
- "\x08\x43\x44\x4F\x4D\x2E\x43\x4F\x4D\xA2\x0F\x30\x0D\xA0\x03\x02"
|
||||
- "\x01\x01\xA1\x06\x30\x04\x1B\x02\x73\x31\xA3\x82\x03\x9E\x30\x82"
|
||||
- "\x03\x9A\xA0\x03\x02\x01\x17\xA1\x03\x02\x01\x03\xA2\x82\x03\x8C"
|
||||
- "\x04\x82\x03\x88\x44\x31\x61\x20\x17\xC9\xFE\xBC\xAC\x46\xB5\x77"
|
||||
- "\xE9\x68\x04\x4C\x9B\x31\x91\x0C\xC1\xD4\xDD\xEF\xC7\x34\x20\x08"
|
||||
- "\x90\x91\xE8\x79\xE0\xB5\x03\x26\xA4\x65\xDE\xEC\x47\x03\x2A\x8F"
|
||||
- "\x61\xE7\x4D\x38\x5A\x42\x95\x5A\xF9\x2F\x41\x2C\x2A\x6E\x60\xA1"
|
||||
- "\xEB\x51\xB3\xBD\x4C\x00\x41\x2A\x44\x76\x08\x37\x1A\x51\xFD\x65"
|
||||
- "\x67\x7E\xBF\x3D\x90\x86\xE3\x9A\x54\x6B\x67\xA8\x08\x7A\x73\xCC"
|
||||
- "\xC3\xB7\x4B\xD5\x5C\x3A\x14\x6C\xC1\x5F\x54\x4B\x92\x55\xB4\xB7"
|
||||
- "\x92\x23\x3F\x53\x89\x47\x8E\x1F\x8B\xB9\xDB\x3B\x93\xE8\x70\xE4"
|
||||
- "\x24\xB8\x9D\xF0\x0E\x35\x28\xF8\x7A\x27\x5D\xF7\x25\x97\x9C\xF5"
|
||||
- "\x9F\x9F\x64\x04\xF2\xA3\xAB\x11\x15\xB6\xDA\x18\xD6\x46\xD5\xE6"
|
||||
- "\xB8\x08\xDE\x0A\x62\xFD\xF8\xAA\x52\x90\xD9\x67\x29\xB2\xCD\x06"
|
||||
- "\xB6\xB0\x50\x2B\x3F\x0F\xA3\xA5\xBF\xAA\x6E\x40\x03\xD6\x5F\x02"
|
||||
- "\xBC\xD8\x18\x47\x97\x09\xD7\xE4\x96\x3B\xCB\xEB\x92\x2C\x3C\x49"
|
||||
- "\xFF\x1F\x71\xE0\x52\x94\x0F\x8B\x9F\xB8\x2A\xBB\x9C\xE2\xA3\xDD"
|
||||
- "\x38\x89\xE2\xB1\x0B\x9E\x1F\x7A\xB3\xE3\xD2\xB0\x94\xDC\x87\xBE"
|
||||
- "\x37\xA6\xD3\xB3\x29\x35\x9A\x72\xC3\x7A\xF1\xA9\xE6\xC5\xD1\x26"
|
||||
- "\x83\x65\x44\x17\xBA\x55\xA8\x5E\x94\x26\xED\xE9\x8A\x93\x11\x5D"
|
||||
- "\x7E\x20\x1B\x9C\x15\x9E\x13\x37\x03\x4D\xDD\x99\x51\xD8\x66\x29"
|
||||
- "\x6A\xB9\xFB\x49\xFE\x52\x78\xDA\x86\x85\xA9\xA3\xB9\xEF\xEC\xAD"
|
||||
- "\x35\xA6\x8D\xAC\x0F\x75\x22\xBB\x0B\x49\x1C\x13\x52\x40\xC9\x52"
|
||||
- "\x69\x09\x54\xD1\x0F\x94\x3F\x22\x48\x67\xB0\x96\x28\xAA\xE6\x28"
|
||||
- "\xD9\x0C\x08\xEF\x51\xED\x15\x5E\xA2\x53\x59\xA5\x03\xB4\x06\x20"
|
||||
- "\x3D\xCC\xB4\xC5\xF8\x8C\x73\x67\xA3\x21\x3D\x19\xCD\xD4\x12\x28"
|
||||
- "\xD2\x93\xDE\x0D\xF0\x71\x10\x50\xD6\x33\x35\x04\x11\x64\x43\x39"
|
||||
- "\xC3\xDF\x96\xE3\x66\xE3\x85\xCA\xE7\x67\x14\x3A\xF0\x43\xAA\xBB"
|
||||
- "\xD4\x1D\xB5\x24\xB5\x74\x90\x25\xA7\x87\x7E\xDB\xD3\x83\x8A\x3A"
|
||||
- "\x69\xA8\x2D\xAF\xB7\xB8\xF3\xDC\x13\xAF\x45\x61\x3F\x59\x39\x7E"
|
||||
- "\x69\xDE\x0C\x04\xF1\x10\x6B\xB4\x56\xFA\x21\x9F\x72\x2B\x60\x86"
|
||||
- "\xE3\x23\x0E\xC4\x51\xF6\xBE\xD8\xE1\x5F\xEE\x73\x4C\x17\x4C\x2C"
|
||||
- "\x1B\xFB\x9F\x1F\x7A\x3B\x07\x5B\x8E\xF1\x01\xAC\xD6\x30\x94\x8A"
|
||||
- "\x5D\x22\x6F\x08\xCE\xED\x5E\xB6\xDB\x86\x8C\x87\xEB\x8D\x91\xFF"
|
||||
- "\x0A\x86\x30\xBD\xC0\xF8\x25\xE7\xAE\x24\x35\xF2\xFC\xE5\xFD\x1B"
|
||||
- "\xB0\x05\x4A\xA3\xE5\xEB\x2E\x05\xAD\x99\x67\x49\x87\xE6\xB3\x87"
|
||||
- "\x82\xA4\x59\xA7\x6E\xDD\xF2\xB6\x66\xE8\xF7\x70\xF5\xBD\xC9\x0E"
|
||||
- "\xFA\x9C\x79\x84\xD4\x9B\x05\x0E\xBB\xF5\xDB\xEF\xFC\xCC\x26\xF2"
|
||||
- "\x93\xCF\xD2\x04\x3C\xA9\x2C\x65\x42\x97\x86\xD8\x38\x0A\x1E\xF6"
|
||||
- "\xD6\xCA\x30\xB5\x1A\xEC\xFB\xBA\x3B\x84\x57\xB0\xFD\xFB\xE6\xBC"
|
||||
- "\xF2\x76\xF6\x4C\xBB\xAB\xB1\x31\xA1\x27\x7C\xE6\xE6\x81\xB6\xCE"
|
||||
- "\x84\x86\x40\xB6\x40\x33\xC4\xF8\xB4\x15\xCF\xAA\xA5\x51\x78\xB9"
|
||||
- "\x8B\x50\x25\xB2\x88\x86\x96\x72\x8C\x71\x4D\xB5\x3A\x94\x86\x77"
|
||||
- "\x0E\x95\x9B\x16\x93\xEF\x3A\x11\x79\xBA\x83\xF7\x74\xD3\x8D\xBA"
|
||||
- "\x15\xE1\x2C\x04\x57\xA8\x92\x1E\x9D\x00\x8E\x20\xFD\x30\x70\xE7"
|
||||
- "\xF5\x65\x2F\x19\x0C\x94\xBA\x03\x71\x12\x96\xCD\xC8\xB4\x96\xDB"
|
||||
- "\xCE\x19\xC2\xDF\x3C\xC2\xF6\x3D\x53\xED\x98\xA5\x41\x72\x2A\x22"
|
||||
- "\x7B\xF3\x2B\x17\x6C\xE1\x39\x7D\xAE\x9B\x11\xF9\xC1\xA6\x9E\x9F"
|
||||
- "\x89\x3C\x12\xAA\x94\x74\xA7\x4F\x70\xE8\xB9\xDE\x04\xF0\x9D\x39"
|
||||
- "\x24\x2D\x92\xE8\x46\x2D\x2E\xF0\x40\x66\x1A\xD9\x27\xF9\x98\xF1"
|
||||
- "\x81\x1D\x70\x62\x63\x30\x6D\xCD\x84\x04\x5F\xFA\x83\xD3\xEC\x8D"
|
||||
- "\x86\xFB\x40\x61\xC1\x8A\x45\xFF\x7B\xD9\xD4\x18\x61\x7F\x51\xE3"
|
||||
- "\xFC\x1E\x18\xF0\xAF\xC6\x18\x2C\xE1\x6D\x5D\xF9\x62\xFC\x20\xA3"
|
||||
- "\xB2\x8A\x5F\xE5\xBB\x29\x0F\x99\x63\x07\x88\x38\x3A\x3B\x73\x2A"
|
||||
- "\x6D\xDA\x3D\xA8\x0D\x8F\x56\x41\x89\x82\xE5\xB8\x61\x00\x64\x7D"
|
||||
- "\x17\x0C\xCE\x03\x55\x8F\xF4\x5B\x0D\x50\xF2\xEB\x05\x67\xBE\xDB"
|
||||
- "\x7B\x75\xC5\xEA\xA1\xAB\x1D\xB0\x3C\x6D\x42\x08\x0B\x9A\x45\x20"
|
||||
- "\xA8\x8F\xE5\x67\x47\x30\xDE\x93\x5F\x43\x05\xEB\xA8\x2D\x80\xF5"
|
||||
- "\x1A\xB8\x4A\x4E\x42\x2D\x0B\x7A\xDC\x46\x20\x2D\x13\x17\xDD\x4B"
|
||||
- "\x94\x96\xAA\x1F\x06\x0C\x1F\x62\x07\x9C\x40\xA1"
|
||||
+ .length = 1307, .data =
|
||||
+ "\x61\x82\x05\x17\x30\x82\x05\x13\xA0\x03\x02\x01\x05\xA1\x0F\x1B"
|
||||
+ "\x0D\x57\x32\x30\x32\x32\x2D\x4C\x37\x2E\x42\x41\x53\x45\xA2\x2A"
|
||||
+ "\x30\x28\xA0\x03\x02\x01\x01\xA1\x21\x30\x1F\x1B\x04\x63\x69\x66"
|
||||
+ "\x73\x1B\x17\x77\x32\x30\x32\x32\x2D\x31\x31\x38\x2E\x77\x32\x30"
|
||||
+ "\x32\x32\x2D\x6C\x37\x2E\x62\x61\x73\x65\xA3\x82\x04\xCD\x30\x82"
|
||||
+ "\x04\xC9\xA0\x03\x02\x01\x12\xA1\x03\x02\x01\x05\xA2\x82\x04\xBB"
|
||||
+ "\x04\x82\x04\xB7\x44\x5C\x7B\x5A\x3F\x2E\xA3\x50\x34\xDE\xB0\x69"
|
||||
+ "\x23\x2D\x47\x89\x2C\xC0\xA3\xF9\xDD\x70\xAA\xA5\x1E\xFE\x74\xE5"
|
||||
+ "\x19\xA2\x4F\x65\x6C\x9E\x00\xB4\x60\x00\x7C\x0C\x29\x43\x31\x99"
|
||||
+ "\x77\x02\x73\xED\xB9\x40\xF5\xD2\xD1\xC9\x20\x0F\xE3\x38\xF9\xCC"
|
||||
+ "\x5E\x2A\xBD\x1F\x91\x66\x1A\xD8\x2A\x80\x3C\x2C\x00\x3C\x1E\xC9"
|
||||
+ "\x2A\x29\x19\x19\x96\x18\x54\x03\x97\x8F\x1D\x5F\xDB\xE9\x66\x68"
|
||||
+ "\xCD\xB1\xD5\x00\x35\x69\x49\x45\xF1\x6A\x78\x7B\x37\x71\x87\x14"
|
||||
+ "\x1C\x98\x4D\x69\xCB\x1B\xD8\xF5\xA3\xD8\x53\x4A\x75\x76\x62\xBA"
|
||||
+ "\x6C\x3F\xEA\x8B\x97\x21\xCA\x8A\x46\x4B\x38\xDA\x09\x9F\x5A\xC8"
|
||||
+ "\x38\xFF\x34\x97\x5B\xA2\xE5\xBA\xC9\x87\x17\xD8\x08\x05\x7A\x83"
|
||||
+ "\x04\xD6\x02\x8E\x9B\x18\xB6\x40\x1A\xF7\x47\x25\x24\x3E\x37\x1E"
|
||||
+ "\xF6\xC1\x3A\x1F\xCA\xB3\x43\x5A\xAE\x94\x83\x31\xAF\xFB\xEE\xED"
|
||||
+ "\x46\x71\xEF\xE2\x37\x37\x15\xFE\x1B\x0B\x9E\xF8\x3E\x0C\x43\x96"
|
||||
+ "\xB6\x0A\x04\x78\xF8\x5E\xAA\x33\x1F\xE2\x07\x5A\x8D\xC4\x4E\x32"
|
||||
+ "\x6D\xD6\xA0\xC5\xEA\x3D\x12\x59\xD4\x41\x40\x4E\xA1\xD8\xBE\xED"
|
||||
+ "\x17\xCB\x68\xCC\x59\xCB\x53\xB2\x0E\x58\x8A\xA9\x33\x7F\x6F\x2B"
|
||||
+ "\x37\x89\x08\x44\xBA\xC7\x67\x17\xBB\x91\xF7\xC3\x0F\x00\xF8\xAA"
|
||||
+ "\xA1\x33\xA6\x08\x47\xCA\xFA\xE8\x49\x27\x45\x46\xF1\xC1\xC3\x5F"
|
||||
+ "\xE2\x45\x0A\x7D\x64\x52\x8C\x2E\xE1\xDE\xFF\xB2\x64\xEC\x69\x98"
|
||||
+ "\x15\xDF\x9E\xB1\xEB\xD6\x9D\x08\x06\x4E\x73\xC1\x0B\x71\x21\x05"
|
||||
+ "\x9E\xBC\xA2\x17\xCF\xB3\x70\xF4\xEF\xB8\x69\xA9\x94\x27\xFD\x5E"
|
||||
+ "\x72\xB1\x2D\xD2\x20\x1B\x57\x80\xAB\x38\x97\xCF\x22\x68\x4F\xB8"
|
||||
+ "\xB7\x17\x53\x25\x67\x0B\xED\xD1\x58\x20\x0D\x45\xF9\x09\xFA\xE7"
|
||||
+ "\x61\x3E\xDB\xC2\x59\x7B\x3A\x3B\x59\x81\x51\xAA\xA4\x81\xF4\x96"
|
||||
+ "\x3B\xE1\x6F\x6F\xF4\x8E\x68\x9E\xBA\x1E\x0F\xF2\x44\x68\x11\xFC"
|
||||
+ "\x2B\x5F\xBE\xF2\xEA\x07\x80\xB9\xCA\x9E\x41\xBD\x2F\x81\xF5\x11"
|
||||
+ "\x2A\x12\xF3\x4F\xD6\x12\x16\x0F\x21\x90\xF1\xD3\x1E\xF1\xA4\x94"
|
||||
+ "\x46\xEA\x30\xF3\x84\x06\xC1\xA4\x51\xFC\x43\x35\xBD\xEF\x4D\x89"
|
||||
+ "\x1D\xA5\x44\xB2\x69\xC4\x0F\xBF\x86\x01\x08\x44\x77\xD5\xB4\xB7"
|
||||
+ "\x5C\x3F\xA7\xD4\x2F\x39\x73\x85\x88\xEE\xB1\x64\x1D\x80\x6C\xEE"
|
||||
+ "\x6E\x31\x90\x92\x0D\xA1\xB7\xC4\x5C\xCC\xEE\x91\xC8\xCB\x11\x2D"
|
||||
+ "\x4A\x1A\x7D\x43\x8F\xEB\x60\x09\xED\x1B\x07\x58\xBE\xBC\xBD\x29"
|
||||
+ "\xF3\xB3\xA3\x4F\xC5\x8A\x30\x33\xB9\xA9\x9F\x43\x08\x27\x15\xC4"
|
||||
+ "\x9C\x5D\x8E\xBD\x5C\x05\xC6\x05\x9C\x87\x60\x08\x1E\xE2\x52\xB8"
|
||||
+ "\x45\x8D\x28\xB6\x2C\x15\x46\x74\x9F\x0E\xAA\x6B\x70\x3A\x2A\x55"
|
||||
+ "\x45\x26\xB2\x58\x4D\x35\xA6\xF1\x96\xBE\x60\xB2\x71\x7B\xF8\x54"
|
||||
+ "\xB9\x90\x21\x8E\xB9\x0F\x35\x98\x5E\x88\xEB\x1A\x53\xB4\x59\x7F"
|
||||
+ "\xAF\x69\x1C\x61\x67\xF4\xF6\xBD\xAC\x24\xCD\xB7\xA9\x67\xE8\xA1"
|
||||
+ "\x83\x85\x5F\x11\x74\x1F\xF7\x4C\x78\x36\xEF\x50\x74\x88\x58\x4B"
|
||||
+ "\x1A\x9F\x84\x9A\x9A\x05\x92\xEC\x1D\xD5\xF3\xC4\x95\x51\x28\xE2"
|
||||
+ "\x3F\x32\x87\xB2\xFD\x21\x27\x66\xE4\x6B\x85\x2F\xDC\x7B\xC0\x22"
|
||||
+ "\xEB\x7A\x94\x20\x5A\x7B\xD3\x7A\xB9\x5B\xF8\x1A\x5A\x84\x4E\xA1"
|
||||
+ "\x73\x41\x53\xD2\x60\xF7\x7C\xEE\x68\x59\x85\x80\xFC\x3D\x70\x4B"
|
||||
+ "\x04\x32\xE7\xF2\xFD\xBD\xB3\xD9\x21\xE2\x37\x56\xA2\x16\xCC\xDE"
|
||||
+ "\x8A\xD3\xBC\x71\xEF\x58\x19\x0E\x45\x8A\x5B\x53\xD6\x77\x30\x6A"
|
||||
+ "\xA7\xF8\x68\x06\x4E\x07\xCA\xCE\x30\xD7\x35\xAB\x1A\xC7\x18\xD4"
|
||||
+ "\xC6\x2F\x1A\xFF\xE9\x7A\x94\x0B\x76\x5E\x7E\x29\x0C\xE6\xD3\x3B"
|
||||
+ "\x5B\x44\x96\xA8\xF1\x29\x23\x95\xD9\x79\xB3\x39\xFC\x76\xED\xE1"
|
||||
+ "\x1E\x67\x4E\xF7\xE8\x7B\x7A\x12\x9E\xD8\x4B\x35\x09\x0A\xF2\xC1"
|
||||
+ "\x63\x5B\xEE\xFD\x2A\xC2\xA6\x66\x30\x3C\x1F\x95\xAF\x65\x22\x95"
|
||||
+ "\x14\x1D\xF5\xD5\xDC\x38\x79\x35\x1C\xCD\x24\x47\xE0\xFD\x08\xC8"
|
||||
+ "\xF4\x15\x55\x9F\xD9\xC7\xAC\x3F\x67\xB3\x4F\xEB\x26\x7C\x8E\xD6"
|
||||
+ "\x74\xB3\x0A\xCD\xE7\xFA\xBE\x7E\xA3\x3E\xEC\x61\x50\x77\x52\x56"
|
||||
+ "\xCF\x90\x5D\x48\xFB\xD4\x2C\x6C\x61\x8B\xDD\x2B\xF5\x92\x1F\x30"
|
||||
+ "\xBF\x3F\x80\x0D\x31\xDB\xB2\x0B\x7D\x84\xE3\xA6\x42\x7F\x00\x38"
|
||||
+ "\x44\x02\xC5\xB8\xD9\x58\x29\x9D\x68\x5C\x32\x8B\x76\xAE\xED\x15"
|
||||
+ "\xF9\x7C\xAE\x7B\xB6\x8E\xD6\x54\x24\xFF\xFA\x87\x05\xEF\x15\x08"
|
||||
+ "\x5E\x4B\x21\xA2\x2F\x49\xE7\x0F\xC3\xD0\xB9\x49\x22\xEF\xD5\xCA"
|
||||
+ "\xB2\x11\xF2\x17\xB6\x77\x24\x68\x76\xB2\x07\xF8\x0A\x73\xDD\x65"
|
||||
+ "\x9C\x75\x64\xF7\xA1\xC6\x23\x08\x84\x72\x3E\x54\x2E\xEB\x9B\x40"
|
||||
+ "\xA6\x83\x87\xEB\xB5\x00\x40\x4F\xE1\x72\x2A\x59\x3A\x06\x60\x29"
|
||||
+ "\x7E\x25\x2F\xD8\x80\x40\x8C\x59\xCA\xCF\x8E\x44\xE4\x2D\x84\x7E"
|
||||
+ "\xCB\xFD\x1E\x3B\xD5\xFF\x9A\xB9\x66\x93\x6D\x5E\xC8\xB7\x13\x26"
|
||||
+ "\xD6\x38\x1B\x2B\xE1\x87\x96\x05\xD5\xF3\xAB\x68\xF7\x12\x62\x2C"
|
||||
+ "\x58\xC1\xC9\x85\x3C\x72\xF1\x26\xEE\xC0\x09\x5F\x1D\x4B\xAC\x01"
|
||||
+ "\x41\xC8\x12\xF8\xF3\x93\x43\x41\xFF\xEC\x0B\x80\xE2\xEE\x20\x85"
|
||||
+ "\x25\xCD\x6C\x30\x8C\x0D\x24\x2E\xBA\x19\xEA\x28\x7F\xCF\xD5\x10"
|
||||
+ "\x5C\xE9\xB2\x9D\x5F\x16\xE4\xC0\xF3\xCC\xD9\x68\x4A\x05\x08\x70"
|
||||
+ "\x17\x26\xC8\x5C\x4A\xBF\x94\x6A\x0E\xD5\xDA\x67\x47\x4B\xAF\x44"
|
||||
+ "\xE3\x94\xAA\x05\xDB\xA2\x49\x74\xFA\x5C\x69\xAB\x44\xB7\xF7\xBA"
|
||||
+ "\xAE\x7A\x23\x87\xEB\x54\x7E\x80\xF1\x5B\x60\xA5\x93\xE5\xD4\x24"
|
||||
+ "\x84\xF7\x0A\x16\x10\xBE\xE9\x4D\xD8\x6B\x15\x40\x5D\x74\xDA\x1B"
|
||||
+ "\xFF\x2E\x4D\x17\x9D\x35\xF7\x0D\xCF\x66\x38\x0D\x8A\xE4\xDD\x6B"
|
||||
+ "\xE1\x0F\x1F\xBD\xFD\x4F\x30\x37\x3F\x96\xB4\x92\x54\xD3\x9A\x7A"
|
||||
+ "\xD1\x5B\x5B\xA9\x54\x16\xE6\x24\xAB\xD4\x23\x39\x7D\xD2\xC7\x09"
|
||||
+ "\xFA\xD4\x86\x55\x4D\x60\xC2\x87\x67\x6B\xE6"
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -686,7 +710,7 @@ test_pac_ticket_signature(krb5_context context)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_ticket *ticket;
|
||||
- krb5_principal sprinc;
|
||||
+ krb5_principal cprinc, sprinc;
|
||||
krb5_authdata **authdata1, **authdata2;
|
||||
krb5_pac pac, pac2, pac3;
|
||||
uint32_t *list;
|
||||
@@ -701,7 +725,13 @@ test_pac_ticket_signature(krb5_context context)
|
||||
if (ret)
|
||||
err(context, ret, "while decrypting ticket");
|
||||
|
||||
- ret = krb5_parse_name(context, "s1@CDOM.COM", &sprinc);
|
||||
+ ret = krb5_parse_name(context, "administrator@W2022-L7.BASE", &cprinc);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "krb5_parse_name");
|
||||
+
|
||||
+ ret = krb5_parse_name(context,
|
||||
+ "cifs/w2022-118.w2022-l7.base@W2022-L7.BASE",
|
||||
+ &sprinc);
|
||||
if (ret)
|
||||
err(context, ret, "krb5_parse_name");
|
||||
|
||||
@@ -713,7 +743,7 @@ test_pac_ticket_signature(krb5_context context)
|
||||
|
||||
/* In this test, the server is also the client. */
|
||||
ret = krb5_pac_verify(context, pac, ticket->enc_part2->times.authtime,
|
||||
- ticket->server, NULL, NULL);
|
||||
+ cprinc, NULL, NULL);
|
||||
if (ret)
|
||||
err(context, ret, "while verifying PAC client info");
|
||||
|
||||
@@ -722,7 +752,7 @@ test_pac_ticket_signature(krb5_context context)
|
||||
ticket->enc_part2->authorization_data = NULL;
|
||||
|
||||
ret = krb5_kdc_sign_ticket(context, ticket->enc_part2, pac, sprinc,
|
||||
- sprinc, &ticket_sig_server_key,
|
||||
+ cprinc, &ticket_sig_server_key,
|
||||
&ticket_sig_krbtgt_key, FALSE);
|
||||
if (ret)
|
||||
err(context, ret, "while signing ticket");
|
||||
@@ -781,6 +811,7 @@ test_pac_ticket_signature(krb5_context context)
|
||||
krb5_pac_free(context, pac);
|
||||
krb5_pac_free(context, pac2);
|
||||
krb5_pac_free(context, pac3);
|
||||
+ krb5_free_principal(context, cprinc);
|
||||
krb5_free_principal(context, sprinc);
|
||||
krb5_free_ticket(context, ticket);
|
||||
}
|
||||
diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py
|
||||
index 4fbdbec052..b0666c3b81 100644
|
||||
--- a/src/tests/t_authdata.py
|
||||
+++ b/src/tests/t_authdata.py
|
||||
@@ -11,7 +11,7 @@ realm = K5Realm(krb5_conf=conf)
|
||||
# container.
|
||||
mark('baseline authdata')
|
||||
out = realm.run(['./adata', realm.host_princ])
|
||||
-if '?512: ' not in out or '^-42: Hello' not in out:
|
||||
+if '?128: [6, 7, 10, 16, 19]' not in out or '^-42: Hello' not in out:
|
||||
fail('expected authdata not seen for basic request')
|
||||
|
||||
# Requested authdata is copied into the ticket, with KDC-only types
|
||||
@@ -239,6 +239,9 @@ realm.run(['./s4u2proxy', usercache, 'service/2'])
|
||||
out = realm.run(['./adata', '-p', realm.user_princ, 'service/2'])
|
||||
if '+97: [indcl]' not in out or '[inds1]' in out:
|
||||
fail('correct auth-indicator not seen for S4U2Proxy req')
|
||||
+# Make sure a PAC with an S4U_DELEGATION_INFO(11) buffer is included.
|
||||
+if '?128: [1, 6, 7, 10, 11, 16, 19]' not in out:
|
||||
+ fail('PAC with delegation info not seen for S4U2Proxy req')
|
||||
|
||||
# Get another S4U2Proxy ticket including request-authdata.
|
||||
realm.run(['./s4u2proxy', usercache, 'service/2', '-2', 'proxy_ad'])
|
||||
--
|
||||
2.39.2
|
||||
|
840
Add-PAC-ticket-signature-APIs.patch
Normal file
840
Add-PAC-ticket-signature-APIs.patch
Normal file
@ -0,0 +1,840 @@
|
||||
From 48be25aaa27487fcbbba76044083de37211b30e7 Mon Sep 17 00:00:00 2001
|
||||
From: Isaac Boukris <iboukris@gmail.com>
|
||||
Date: Fri, 7 Jan 2022 13:46:24 -0500
|
||||
Subject: [PATCH] Add PAC ticket signature APIs
|
||||
|
||||
Microsoft added a third PAC signature over the ticket to prevent
|
||||
servers from setting the forwardable flag on evidence tickets. Add
|
||||
new APIs to generate and verify ticket signatures, as well as defines
|
||||
for this and other new PAC buffer types. Deprecate the old signing
|
||||
functions as they cannot generate ticket signatures. Modify several
|
||||
error returns to better match the protocol errors generated by Active
|
||||
Directory.
|
||||
|
||||
[ghudson@mit.edu: adjusted contracts for KDC requirements; simplified
|
||||
and commented code changes; wrote commit message. rharwood@redhat.com
|
||||
also did some work on this commit.]
|
||||
|
||||
ticket: 9043 (new)
|
||||
---
|
||||
doc/appdev/refs/api/index.rst | 2 +
|
||||
doc/appdev/refs/macros/index.rst | 6 +
|
||||
src/include/krb5/krb5.hin | 98 +++++++++++------
|
||||
src/lib/krb5/krb/deps | 5 +-
|
||||
src/lib/krb5/krb/int-proto.h | 12 ++
|
||||
src/lib/krb5/krb/pac.c | 148 ++++++++++++++++++++++++-
|
||||
src/lib/krb5/krb/pac_sign.c | 121 ++++++++++++++++++++
|
||||
src/lib/krb5/krb/t_pac.c | 182 +++++++++++++++++++++++++++++++
|
||||
src/lib/krb5/libkrb5.exports | 2 +
|
||||
src/lib/krb5_32.def | 3 +
|
||||
src/plugins/kdb/test/kdb_test.c | 6 +-
|
||||
11 files changed, 544 insertions(+), 41 deletions(-)
|
||||
|
||||
diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst
|
||||
index 9e03fd386f..d12be47c3c 100644
|
||||
--- a/doc/appdev/refs/api/index.rst
|
||||
+++ b/doc/appdev/refs/api/index.rst
|
||||
@@ -223,6 +223,8 @@ Rarely used public interfaces
|
||||
krb5_init_creds_step.rst
|
||||
krb5_init_keyblock.rst
|
||||
krb5_is_referral_realm.rst
|
||||
+ krb5_kdc_sign_ticket.rst
|
||||
+ krb5_kdc_verify_ticket.rst
|
||||
krb5_kt_add_entry.rst
|
||||
krb5_kt_end_seq_get.rst
|
||||
krb5_kt_get_entry.rst
|
||||
diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst
|
||||
index 001fb386a7..c6ea088742 100644
|
||||
--- a/doc/appdev/refs/macros/index.rst
|
||||
+++ b/doc/appdev/refs/macros/index.rst
|
||||
@@ -234,12 +234,18 @@ Public
|
||||
KRB5_NT_UNKNOWN.rst
|
||||
KRB5_NT_WELLKNOWN.rst
|
||||
KRB5_NT_X500_PRINCIPAL.rst
|
||||
+ KRB5_PAC_ATTRIBUTES_INFO.rst
|
||||
KRB5_PAC_CLIENT_INFO.rst
|
||||
+ KRB5_PAC_CLIENT_CLAIMS.rst
|
||||
KRB5_PAC_CREDENTIALS_INFO.rst
|
||||
KRB5_PAC_DELEGATION_INFO.rst
|
||||
+ KRB5_PAC_DEVICE_CLAIMS.rst
|
||||
+ KRB5_PAC_DEVICE_INFO.rst
|
||||
KRB5_PAC_LOGON_INFO.rst
|
||||
KRB5_PAC_PRIVSVR_CHECKSUM.rst
|
||||
+ KRB5_PAC_REQUESTOR.rst
|
||||
KRB5_PAC_SERVER_CHECKSUM.rst
|
||||
+ KRB5_PAC_TICKET_CHECKSUM.rst
|
||||
KRB5_PAC_UPN_DNS_INFO.rst
|
||||
KRB5_PADATA_AFS3_SALT.rst
|
||||
KRB5_PADATA_AP_REQ.rst
|
||||
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||
index a7060aa733..8e59628bd9 100644
|
||||
--- a/src/include/krb5/krb5.hin
|
||||
+++ b/src/include/krb5/krb5.hin
|
||||
@@ -1918,7 +1918,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
|
||||
#define KRB5_AUTHDATA_CAMMAC 96
|
||||
#define KRB5_AUTHDATA_WIN2K_PAC 128
|
||||
#define KRB5_AUTHDATA_ETYPE_NEGOTIATION 129 /**< RFC 4537 */
|
||||
-#define KRB5_AUTHDATA_SIGNTICKET 512 /**< formerly 142 in krb5 1.8 */
|
||||
+#define KRB5_AUTHDATA_SIGNTICKET 512 /**< @deprecated use PAC */
|
||||
#define KRB5_AUTHDATA_FX_ARMOR 71
|
||||
#define KRB5_AUTHDATA_AUTH_INDICATOR 97
|
||||
#define KRB5_AUTHDATA_AP_OPTIONS 143
|
||||
@@ -8181,6 +8181,12 @@ krb5_verify_authdata_kdc_issued(krb5_context context,
|
||||
#define KRB5_PAC_CLIENT_INFO 10 /**< Client name and ticket info */
|
||||
#define KRB5_PAC_DELEGATION_INFO 11 /**< Constrained delegation info */
|
||||
#define KRB5_PAC_UPN_DNS_INFO 12 /**< User principal name and DNS info */
|
||||
+#define KRB5_PAC_CLIENT_CLAIMS 13 /**< Client claims information */
|
||||
+#define KRB5_PAC_DEVICE_INFO 14 /**< Device information */
|
||||
+#define KRB5_PAC_DEVICE_CLAIMS 15 /**< Device claims information */
|
||||
+#define KRB5_PAC_TICKET_CHECKSUM 16 /**< Ticket checksum */
|
||||
+#define KRB5_PAC_ATTRIBUTES_INFO 17 /**< PAC attributes */
|
||||
+#define KRB5_PAC_REQUESTOR 18 /**< PAC requestor SID */
|
||||
|
||||
struct krb5_pac_data;
|
||||
/** PAC data structure to convey authorization information */
|
||||
@@ -8338,56 +8344,84 @@ krb5_pac_verify_ext(krb5_context context, const krb5_pac pac,
|
||||
krb5_boolean with_realm);
|
||||
|
||||
/**
|
||||
- * Sign a PAC.
|
||||
+ * Verify a PAC, possibly including ticket signature
|
||||
*
|
||||
- * @param [in] context Library context
|
||||
- * @param [in] pac PAC handle
|
||||
- * @param [in] authtime Expected timestamp
|
||||
- * @param [in] principal Expected principal name (or NULL)
|
||||
- * @param [in] server_key Key for server checksum
|
||||
- * @param [in] privsvr_key Key for KDC checksum
|
||||
- * @param [out] data Signed PAC encoding
|
||||
+ * @param [in] context Library context
|
||||
+ * @param [in] enc_tkt Ticket enc-part, possibly containing a PAC
|
||||
+ * @param [in] server_princ Canonicalized name of ticket server
|
||||
+ * @param [in] server Key to validate server checksum (or NULL)
|
||||
+ * @param [in] privsvr Key to validate KDC checksum (or NULL)
|
||||
+ * @param [out] pac_out Verified PAC (NULL if no PAC included)
|
||||
*
|
||||
- * This function signs @a pac using the keys @a server_key and @a privsvr_key
|
||||
- * and returns the signed encoding in @a data. @a pac is modified to include
|
||||
- * the server and KDC checksum buffers. Use krb5_free_data_contents() to free
|
||||
- * @a data when it is no longer needed.
|
||||
+ * If a PAC is present in @a enc_tkt, verify its signatures. If @a privsvr is
|
||||
+ * not NULL and @a server_princ is not a krbtgt or kadmin/changepw service,
|
||||
+ * require a ticket signature over @a enc_tkt in addition to the KDC signature.
|
||||
+ * Place the verified PAC in @a pac_out. If an invalid PAC signature is found,
|
||||
+ * return an error matching the Windows KDC protocol code for that condition as
|
||||
+ * closely as possible.
|
||||
*
|
||||
- * @version New in 1.10
|
||||
+ * If no PAC is present in @a enc_tkt, set @a pac_out to NULL and return
|
||||
+ * successfully.
|
||||
+ *
|
||||
+ * @note This function does not validate the PAC_CLIENT_INFO buffer. If a
|
||||
+ * specific value is expected, the caller can make a separate call to
|
||||
+ * krb5_pac_verify_ext() with a principal but no keys.
|
||||
+ *
|
||||
+ * @retval 0 Success; otherwise - Kerberos error codes
|
||||
+ *
|
||||
+ * @version New in 1.20
|
||||
*/
|
||||
krb5_error_code KRB5_CALLCONV
|
||||
+krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
|
||||
+ krb5_const_principal server_princ,
|
||||
+ const krb5_keyblock *server,
|
||||
+ const krb5_keyblock *privsvr, krb5_pac *pac_out);
|
||||
+
|
||||
+/** @deprecated Use krb5_kdc_sign_ticket() instead. */
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
krb5_pac_sign(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
krb5_const_principal principal, const krb5_keyblock *server_key,
|
||||
const krb5_keyblock *privsvr_key, krb5_data *data);
|
||||
|
||||
+/** @deprecated Use krb5_kdc_sign_ticket() instead. */
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
+ krb5_const_principal principal,
|
||||
+ const krb5_keyblock *server_key,
|
||||
+ const krb5_keyblock *privsvr_key, krb5_boolean with_realm,
|
||||
+ krb5_data *data);
|
||||
+
|
||||
/**
|
||||
- * Sign a PAC, possibly with a specified realm.
|
||||
+ * Sign a PAC, possibly including a ticket signature
|
||||
*
|
||||
* @param [in] context Library context
|
||||
+ * @param [in] enc_tkt The ticket for the signature
|
||||
* @param [in] pac PAC handle
|
||||
- * @param [in] authtime Expected timestamp
|
||||
- * @param [in] principal Principal name (or NULL)
|
||||
- * @param [in] server_key Key for server checksum
|
||||
- * @param [in] privsvr_key Key for KDC checksum
|
||||
+ * @param [in] server_princ Canonical ticket server name
|
||||
+ * @param [in] client_princ PAC_CLIENT_INFO principal (or NULL)
|
||||
+ * @param [in] server Key for server checksum
|
||||
+ * @param [in] privsvr Key for KDC and ticket checksum
|
||||
* @param [in] with_realm If true, include the realm of @a principal
|
||||
- * @param [out] data Signed PAC encoding
|
||||
*
|
||||
- * This function is similar to krb5_pac_sign(), but adds a parameter
|
||||
- * @a with_realm. If @a with_realm is true, the PAC_CLIENT_INFO field of the
|
||||
- * signed PAC will include the realm of @a principal as well as the name. This
|
||||
- * flag is necessary to generate PACs for cross-realm S4U2Self referrals.
|
||||
+ * Sign @a pac using the keys @a server and @a privsvr. Include a ticket
|
||||
+ * signature over @a enc_tkt if @a server_princ is not a TGS or kadmin/changepw
|
||||
+ * principal name. Add the signed PAC's encoding to the authorization data of
|
||||
+ * @a enc_tkt in the first slot, wrapped in an AD-IF-RELEVANT container. If @a
|
||||
+ * client_princ is non-null, add a PAC_CLIENT_INFO buffer, including the realm
|
||||
+ * if @a with_realm is true.
|
||||
*
|
||||
- * @version New in 1.17
|
||||
+ * @retval 0 on success, otherwise - Kerberos error codes
|
||||
+ *
|
||||
+ * @version New in 1.20
|
||||
*/
|
||||
krb5_error_code KRB5_CALLCONV
|
||||
-krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
- krb5_const_principal principal,
|
||||
- const krb5_keyblock *server_key,
|
||||
- const krb5_keyblock *privsvr_key, krb5_boolean with_realm,
|
||||
- krb5_data *data);
|
||||
+krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,
|
||||
+ const krb5_pac pac, krb5_const_principal server_princ,
|
||||
+ krb5_const_principal client_princ,
|
||||
+ const krb5_keyblock *server, const krb5_keyblock *privsvr,
|
||||
+ krb5_boolean with_realm);
|
||||
|
||||
-
|
||||
-/*
|
||||
+/**
|
||||
* Read client information from a PAC.
|
||||
*
|
||||
* @param [in] context Library context
|
||||
diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps
|
||||
index 439ca02725..cd842b03cd 100644
|
||||
--- a/src/lib/krb5/krb/deps
|
||||
+++ b/src/lib/krb5/krb/deps
|
||||
@@ -709,7 +709,7 @@ pac.so pac.po $(OUTPRE)pac.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
||||
$(top_srcdir)/include/k5-utf8.h $(top_srcdir)/include/krb5.h \
|
||||
$(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
|
||||
$(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
|
||||
- authdata.h pac.c
|
||||
+ authdata.h int-proto.h pac.c
|
||||
pac_sign.so pac_sign.po $(OUTPRE)pac_sign.$(OBJEXT): \
|
||||
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
|
||||
$(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
|
||||
@@ -720,7 +720,8 @@ pac_sign.so pac_sign.po $(OUTPRE)pac_sign.$(OBJEXT): \
|
||||
$(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/k5-utf8.h \
|
||||
$(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
|
||||
$(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
|
||||
- $(top_srcdir)/include/socket-utils.h authdata.h pac_sign.c
|
||||
+ $(top_srcdir)/include/socket-utils.h authdata.h int-proto.h \
|
||||
+ pac_sign.c
|
||||
padata.so padata.po $(OUTPRE)padata.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
||||
$(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
|
||||
$(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
|
||||
diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
|
||||
index fe61bebf5b..453ed60c6c 100644
|
||||
--- a/src/lib/krb5/krb/int-proto.h
|
||||
+++ b/src/lib/krb5/krb/int-proto.h
|
||||
@@ -386,4 +386,16 @@ k5_get_proxy_cred_from_kdc(krb5_context context, krb5_flags options,
|
||||
krb5_ccache ccache, krb5_creds *in_creds,
|
||||
krb5_creds **out_creds);
|
||||
|
||||
+/* Return true if mprinc will match any hostname in a host-based principal name
|
||||
+ * (possibly due to ignore_acceptor_hostname) with krb5_sname_match(). */
|
||||
+krb5_boolean
|
||||
+k5_sname_wildcard_host(krb5_context context, krb5_const_principal mprinc);
|
||||
+
|
||||
+/* Guess the appropriate name-type for a principal based on the name. */
|
||||
+krb5_int32
|
||||
+k5_infer_principal_type(krb5_principal princ);
|
||||
+
|
||||
+krb5_boolean
|
||||
+k5_pac_should_have_ticket_signature(krb5_const_principal sprinc);
|
||||
+
|
||||
#endif /* KRB5_INT_FUNC_PROTO__ */
|
||||
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
|
||||
index 1b9ef12276..6eb23d8090 100644
|
||||
--- a/src/lib/krb5/krb/pac.c
|
||||
+++ b/src/lib/krb5/krb/pac.c
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "k5-int.h"
|
||||
+#include "int-proto.h"
|
||||
#include "authdata.h"
|
||||
|
||||
#define MAX_BUFFERS 4096
|
||||
@@ -552,8 +553,10 @@ k5_pac_verify_server_checksum(krb5_context context,
|
||||
checksum.checksum_type = load_32_le(p);
|
||||
checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||||
+ if (checksum.checksum_type == CKSUMTYPE_SHA1)
|
||||
+ return KRB5KDC_ERR_SUMTYPE_NOSUPP;
|
||||
if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||||
- return KRB5KRB_AP_ERR_INAPP_CKSUM;
|
||||
+ return KRB5KRB_ERR_GENERIC;
|
||||
|
||||
pac_data.length = pac->data.length;
|
||||
pac_data.data = k5memdup(pac->data.data, pac->data.length, &ret);
|
||||
@@ -586,7 +589,7 @@ k5_pac_verify_server_checksum(krb5_context context,
|
||||
}
|
||||
|
||||
if (valid == FALSE)
|
||||
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||||
+ ret = KRB5KRB_AP_ERR_MODIFIED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -623,7 +626,7 @@ k5_pac_verify_kdc_checksum(krb5_context context,
|
||||
checksum.length = privsvr_checksum.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||||
if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||||
- return KRB5KRB_AP_ERR_INAPP_CKSUM;
|
||||
+ return KRB5KRB_ERR_GENERIC;
|
||||
|
||||
server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
|
||||
server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;
|
||||
@@ -635,11 +638,148 @@ k5_pac_verify_kdc_checksum(krb5_context context,
|
||||
return ret;
|
||||
|
||||
if (valid == FALSE)
|
||||
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||||
+ ret = KRB5KRB_AP_ERR_MODIFIED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static krb5_error_code
|
||||
+verify_ticket_checksum(krb5_context context, const krb5_pac pac,
|
||||
+ const krb5_data *ticket, const krb5_keyblock *privsvr)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_checksum checksum;
|
||||
+ krb5_data checksum_data;
|
||||
+ krb5_boolean valid;
|
||||
+ krb5_octet *p;
|
||||
+
|
||||
+ ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_TICKET_CHECKSUM,
|
||||
+ &checksum_data);
|
||||
+ if (ret != 0)
|
||||
+ return KRB5KRB_AP_ERR_MODIFIED;
|
||||
+
|
||||
+ if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH)
|
||||
+ return KRB5_BAD_MSIZE;
|
||||
+
|
||||
+ p = (krb5_octet *)checksum_data.data;
|
||||
+ checksum.checksum_type = load_32_le(p);
|
||||
+ checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
+ checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||||
+ if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||||
+ return KRB5KRB_ERR_GENERIC;
|
||||
+
|
||||
+ ret = krb5_c_verify_checksum(context, privsvr,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, ticket,
|
||||
+ &checksum, &valid);
|
||||
+ if (ret != 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return valid ? 0 : KRB5KRB_AP_ERR_MODIFIED;
|
||||
+}
|
||||
+
|
||||
+/* Per MS-PAC 2.8.3, tickets encrypted to TGS and password change principals
|
||||
+ * should not have ticket signatures. */
|
||||
+krb5_boolean
|
||||
+k5_pac_should_have_ticket_signature(krb5_const_principal sprinc)
|
||||
+{
|
||||
+ if (IS_TGS_PRINC(sprinc))
|
||||
+ return FALSE;
|
||||
+ if (sprinc->length == 2 && data_eq_string(sprinc->data[0], "kadmin") &&
|
||||
+ data_eq_string(sprinc->data[1], "changepw"))
|
||||
+ return FALSE;
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
|
||||
+ krb5_const_principal server_princ,
|
||||
+ const krb5_keyblock *server,
|
||||
+ const krb5_keyblock *privsvr, krb5_pac *pac_out)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_pac pac = NULL;
|
||||
+ krb5_data *recoded_tkt = NULL;
|
||||
+ krb5_authdata **authdata, *orig, **ifrel = NULL, **recoded_ifrel = NULL;
|
||||
+ uint8_t z = 0;
|
||||
+ krb5_authdata zpac = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC, 1, &z };
|
||||
+ size_t i, j;
|
||||
+
|
||||
+ *pac_out = NULL;
|
||||
+
|
||||
+ /*
|
||||
+ * Find the position of the PAC in the ticket authdata. ifrel will be the
|
||||
+ * decoded AD-IF-RELEVANT container at position i containing a PAC, and j
|
||||
+ * will be the offset within the container.
|
||||
+ */
|
||||
+ authdata = enc_tkt->authorization_data;
|
||||
+ for (i = 0; authdata != NULL && authdata[i] != NULL; i++) {
|
||||
+ if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT)
|
||||
+ continue;
|
||||
+
|
||||
+ ret = krb5_decode_authdata_container(context,
|
||||
+ KRB5_AUTHDATA_IF_RELEVANT,
|
||||
+ authdata[i], &ifrel);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ for (j = 0; ifrel[j] != NULL; j++) {
|
||||
+ if (ifrel[j]->ad_type == KRB5_AUTHDATA_WIN2K_PAC)
|
||||
+ break;
|
||||
+ }
|
||||
+ if (ifrel[j] != NULL)
|
||||
+ break;
|
||||
+
|
||||
+ krb5_free_authdata(context, ifrel);
|
||||
+ ifrel = NULL;
|
||||
+ }
|
||||
+
|
||||
+ /* Stop and return successfully if we didn't find a PAC. */
|
||||
+ if (ifrel == NULL) {
|
||||
+ ret = 0;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ ret = krb5_pac_parse(context, ifrel[j]->contents, ifrel[j]->length, &pac);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (privsvr != NULL && k5_pac_should_have_ticket_signature(server_princ)) {
|
||||
+ /* To check the PAC ticket signatures, re-encode the ticket with the
|
||||
+ * PAC contents replaced by a single zero. */
|
||||
+ orig = ifrel[j];
|
||||
+ ifrel[j] = &zpac;
|
||||
+ ret = krb5_encode_authdata_container(context,
|
||||
+ KRB5_AUTHDATA_IF_RELEVANT,
|
||||
+ ifrel, &recoded_ifrel);
|
||||
+ ifrel[j] = orig;
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ orig = authdata[i];
|
||||
+ authdata[i] = recoded_ifrel[0];
|
||||
+ ret = encode_krb5_enc_tkt_part(enc_tkt, &recoded_tkt);
|
||||
+ authdata[i] = orig;
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ ret = verify_ticket_checksum(context, pac, recoded_tkt, privsvr);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ ret = krb5_pac_verify_ext(context, pac, enc_tkt->times.authtime, NULL,
|
||||
+ server, privsvr, FALSE);
|
||||
+
|
||||
+ *pac_out = pac;
|
||||
+ pac = NULL;
|
||||
+
|
||||
+cleanup:
|
||||
+ krb5_pac_free(context, pac);
|
||||
+ krb5_free_data(context, recoded_tkt);
|
||||
+ krb5_free_authdata(context, ifrel);
|
||||
+ krb5_free_authdata(context, recoded_ifrel);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
krb5_error_code KRB5_CALLCONV
|
||||
krb5_pac_verify(krb5_context context,
|
||||
const krb5_pac pac,
|
||||
diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c
|
||||
index 12f0259b4f..0f9581abbb 100644
|
||||
--- a/src/lib/krb5/krb/pac_sign.c
|
||||
+++ b/src/lib/krb5/krb/pac_sign.c
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "k5-int.h"
|
||||
+#include "int-proto.h"
|
||||
#include "authdata.h"
|
||||
|
||||
/* draft-brezak-win2k-krb-authz-00 */
|
||||
@@ -286,3 +287,123 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+/* Add a signature over der_enc_tkt in privsvr to pac. der_enc_tkt should be
|
||||
+ * encoded with a dummy PAC authdata element containing a single zero byte. */
|
||||
+static krb5_error_code
|
||||
+add_ticket_signature(krb5_context context, const krb5_pac pac,
|
||||
+ krb5_data *der_enc_tkt, const krb5_keyblock *privsvr)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_data ticket_cksum;
|
||||
+ krb5_cksumtype ticket_cksumtype;
|
||||
+ krb5_crypto_iov iov[2];
|
||||
+
|
||||
+ /* Create zeroed buffer for checksum. */
|
||||
+ ret = k5_insert_checksum(context, pac, KRB5_PAC_TICKET_CHECKSUM,
|
||||
+ privsvr, &ticket_cksumtype);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_TICKET_CHECKSUM,
|
||||
+ &ticket_cksum);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
+ iov[0].data = *der_enc_tkt;
|
||||
+ iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
|
||||
+ iov[1].data = make_data(ticket_cksum.data + PAC_SIGNATURE_DATA_LENGTH,
|
||||
+ ticket_cksum.length - PAC_SIGNATURE_DATA_LENGTH);
|
||||
+ ret = krb5_c_make_checksum_iov(context, ticket_cksumtype, privsvr,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, iov, 2);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ store_32_le(ticket_cksumtype, ticket_cksum.data);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Set *out to an AD-IF-RELEVANT authdata element containing a PAC authdata
|
||||
+ * element with contents pac_data. */
|
||||
+static krb5_error_code
|
||||
+encode_pac_ad(krb5_context context, krb5_data *pac_data, krb5_authdata **out)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_authdata *container[2], **encoded_container = NULL;
|
||||
+ krb5_authdata pac_ad = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC };
|
||||
+ uint8_t z = 0;
|
||||
+
|
||||
+ pac_ad.contents = (pac_data != NULL) ? (uint8_t *)pac_data->data : &z;
|
||||
+ pac_ad.length = (pac_data != NULL) ? pac_data->length : 1;
|
||||
+ container[0] = &pac_ad;
|
||||
+ container[1] = NULL;
|
||||
+
|
||||
+ ret = krb5_encode_authdata_container(context, KRB5_AUTHDATA_IF_RELEVANT,
|
||||
+ container, &encoded_container);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ *out = encoded_container[0];
|
||||
+ free(encoded_container);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,
|
||||
+ const krb5_pac pac, krb5_const_principal server_princ,
|
||||
+ krb5_const_principal client_princ,
|
||||
+ const krb5_keyblock *server, const krb5_keyblock *privsvr,
|
||||
+ krb5_boolean with_realm)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_data *der_enc_tkt = NULL, pac_data = empty_data();
|
||||
+ krb5_authdata **list, *pac_ad;
|
||||
+ size_t count;
|
||||
+
|
||||
+ /* Reallocate space for another authdata element in enc_tkt. */
|
||||
+ list = enc_tkt->authorization_data;
|
||||
+ for (count = 0; list != NULL && list[count] != NULL; count++);
|
||||
+ list = realloc(enc_tkt->authorization_data, (count + 2) * sizeof(*list));
|
||||
+ if (list == NULL)
|
||||
+ return ENOMEM;
|
||||
+ list[count] = NULL;
|
||||
+ enc_tkt->authorization_data = list;
|
||||
+
|
||||
+ /* Create a dummy PAC for ticket signing and make it the first element. */
|
||||
+ ret = encode_pac_ad(context, NULL, &pac_ad);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ memmove(list + 1, list, (count + 1) * sizeof(*list));
|
||||
+ list[0] = pac_ad;
|
||||
+
|
||||
+ if (k5_pac_should_have_ticket_signature(server_princ)) {
|
||||
+ ret = encode_krb5_enc_tkt_part(enc_tkt, &der_enc_tkt);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ assert(privsvr != NULL);
|
||||
+ ret = add_ticket_signature(context, pac, der_enc_tkt, privsvr);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ ret = krb5_pac_sign_ext(context, pac, enc_tkt->times.authtime,
|
||||
+ client_princ, server, privsvr, with_realm,
|
||||
+ &pac_data);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ /* Replace the dummy PAC with the signed real one. */
|
||||
+ ret = encode_pac_ad(context, &pac_data, &pac_ad);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ free(list[0]->contents);
|
||||
+ free(list[0]);
|
||||
+ list[0] = pac_ad;
|
||||
+
|
||||
+cleanup:
|
||||
+ krb5_free_data(context, der_enc_tkt);
|
||||
+ krb5_free_data_contents(context, &pac_data);
|
||||
+ return ret;
|
||||
+}
|
||||
diff --git a/src/lib/krb5/krb/t_pac.c b/src/lib/krb5/krb/t_pac.c
|
||||
index ccd165380d..173bde7bab 100644
|
||||
--- a/src/lib/krb5/krb/t_pac.c
|
||||
+++ b/src/lib/krb5/krb/t_pac.c
|
||||
@@ -605,6 +605,186 @@ check_pac(krb5_context context, int index, const unsigned char *pdata,
|
||||
krb5_pac_free(context, pac);
|
||||
}
|
||||
|
||||
+static const krb5_keyblock ticket_sig_krbtgt_key = {
|
||||
+ 0, ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
+ 32, U("\x7a\x58\x98\xd2\xaf\xa6\xaf\xc0\x6a\xce\x06\x04\x4b\xc2\x70\x84"
|
||||
+ "\x9b\x8e\x0a\x6c\x4c\x07\xdc\x6f\xbb\x48\x43\xe1\xd2\xaa\x97\xf7")
|
||||
+};
|
||||
+
|
||||
+static const krb5_keyblock ticket_sig_server_key = {
|
||||
+ 0, ENCTYPE_ARCFOUR_HMAC,
|
||||
+ 16, U("\xed\x23\x11\x20\x7a\x21\x44\x20\xbf\xc0\x8d\x36\xf7\xf6\xb2\x3e")
|
||||
+};
|
||||
+
|
||||
+static const krb5_data ticket_data = {
|
||||
+ .length = 972, .data =
|
||||
+ "\x61\x82\x03\xC8\x30\x82\x03\xC4\xA0\x03\x02\x01\x05\xA1\x0A\x1B"
|
||||
+ "\x08\x43\x44\x4F\x4D\x2E\x43\x4F\x4D\xA2\x0F\x30\x0D\xA0\x03\x02"
|
||||
+ "\x01\x01\xA1\x06\x30\x04\x1B\x02\x73\x31\xA3\x82\x03\x9E\x30\x82"
|
||||
+ "\x03\x9A\xA0\x03\x02\x01\x17\xA1\x03\x02\x01\x03\xA2\x82\x03\x8C"
|
||||
+ "\x04\x82\x03\x88\x44\x31\x61\x20\x17\xC9\xFE\xBC\xAC\x46\xB5\x77"
|
||||
+ "\xE9\x68\x04\x4C\x9B\x31\x91\x0C\xC1\xD4\xDD\xEF\xC7\x34\x20\x08"
|
||||
+ "\x90\x91\xE8\x79\xE0\xB5\x03\x26\xA4\x65\xDE\xEC\x47\x03\x2A\x8F"
|
||||
+ "\x61\xE7\x4D\x38\x5A\x42\x95\x5A\xF9\x2F\x41\x2C\x2A\x6E\x60\xA1"
|
||||
+ "\xEB\x51\xB3\xBD\x4C\x00\x41\x2A\x44\x76\x08\x37\x1A\x51\xFD\x65"
|
||||
+ "\x67\x7E\xBF\x3D\x90\x86\xE3\x9A\x54\x6B\x67\xA8\x08\x7A\x73\xCC"
|
||||
+ "\xC3\xB7\x4B\xD5\x5C\x3A\x14\x6C\xC1\x5F\x54\x4B\x92\x55\xB4\xB7"
|
||||
+ "\x92\x23\x3F\x53\x89\x47\x8E\x1F\x8B\xB9\xDB\x3B\x93\xE8\x70\xE4"
|
||||
+ "\x24\xB8\x9D\xF0\x0E\x35\x28\xF8\x7A\x27\x5D\xF7\x25\x97\x9C\xF5"
|
||||
+ "\x9F\x9F\x64\x04\xF2\xA3\xAB\x11\x15\xB6\xDA\x18\xD6\x46\xD5\xE6"
|
||||
+ "\xB8\x08\xDE\x0A\x62\xFD\xF8\xAA\x52\x90\xD9\x67\x29\xB2\xCD\x06"
|
||||
+ "\xB6\xB0\x50\x2B\x3F\x0F\xA3\xA5\xBF\xAA\x6E\x40\x03\xD6\x5F\x02"
|
||||
+ "\xBC\xD8\x18\x47\x97\x09\xD7\xE4\x96\x3B\xCB\xEB\x92\x2C\x3C\x49"
|
||||
+ "\xFF\x1F\x71\xE0\x52\x94\x0F\x8B\x9F\xB8\x2A\xBB\x9C\xE2\xA3\xDD"
|
||||
+ "\x38\x89\xE2\xB1\x0B\x9E\x1F\x7A\xB3\xE3\xD2\xB0\x94\xDC\x87\xBE"
|
||||
+ "\x37\xA6\xD3\xB3\x29\x35\x9A\x72\xC3\x7A\xF1\xA9\xE6\xC5\xD1\x26"
|
||||
+ "\x83\x65\x44\x17\xBA\x55\xA8\x5E\x94\x26\xED\xE9\x8A\x93\x11\x5D"
|
||||
+ "\x7E\x20\x1B\x9C\x15\x9E\x13\x37\x03\x4D\xDD\x99\x51\xD8\x66\x29"
|
||||
+ "\x6A\xB9\xFB\x49\xFE\x52\x78\xDA\x86\x85\xA9\xA3\xB9\xEF\xEC\xAD"
|
||||
+ "\x35\xA6\x8D\xAC\x0F\x75\x22\xBB\x0B\x49\x1C\x13\x52\x40\xC9\x52"
|
||||
+ "\x69\x09\x54\xD1\x0F\x94\x3F\x22\x48\x67\xB0\x96\x28\xAA\xE6\x28"
|
||||
+ "\xD9\x0C\x08\xEF\x51\xED\x15\x5E\xA2\x53\x59\xA5\x03\xB4\x06\x20"
|
||||
+ "\x3D\xCC\xB4\xC5\xF8\x8C\x73\x67\xA3\x21\x3D\x19\xCD\xD4\x12\x28"
|
||||
+ "\xD2\x93\xDE\x0D\xF0\x71\x10\x50\xD6\x33\x35\x04\x11\x64\x43\x39"
|
||||
+ "\xC3\xDF\x96\xE3\x66\xE3\x85\xCA\xE7\x67\x14\x3A\xF0\x43\xAA\xBB"
|
||||
+ "\xD4\x1D\xB5\x24\xB5\x74\x90\x25\xA7\x87\x7E\xDB\xD3\x83\x8A\x3A"
|
||||
+ "\x69\xA8\x2D\xAF\xB7\xB8\xF3\xDC\x13\xAF\x45\x61\x3F\x59\x39\x7E"
|
||||
+ "\x69\xDE\x0C\x04\xF1\x10\x6B\xB4\x56\xFA\x21\x9F\x72\x2B\x60\x86"
|
||||
+ "\xE3\x23\x0E\xC4\x51\xF6\xBE\xD8\xE1\x5F\xEE\x73\x4C\x17\x4C\x2C"
|
||||
+ "\x1B\xFB\x9F\x1F\x7A\x3B\x07\x5B\x8E\xF1\x01\xAC\xD6\x30\x94\x8A"
|
||||
+ "\x5D\x22\x6F\x08\xCE\xED\x5E\xB6\xDB\x86\x8C\x87\xEB\x8D\x91\xFF"
|
||||
+ "\x0A\x86\x30\xBD\xC0\xF8\x25\xE7\xAE\x24\x35\xF2\xFC\xE5\xFD\x1B"
|
||||
+ "\xB0\x05\x4A\xA3\xE5\xEB\x2E\x05\xAD\x99\x67\x49\x87\xE6\xB3\x87"
|
||||
+ "\x82\xA4\x59\xA7\x6E\xDD\xF2\xB6\x66\xE8\xF7\x70\xF5\xBD\xC9\x0E"
|
||||
+ "\xFA\x9C\x79\x84\xD4\x9B\x05\x0E\xBB\xF5\xDB\xEF\xFC\xCC\x26\xF2"
|
||||
+ "\x93\xCF\xD2\x04\x3C\xA9\x2C\x65\x42\x97\x86\xD8\x38\x0A\x1E\xF6"
|
||||
+ "\xD6\xCA\x30\xB5\x1A\xEC\xFB\xBA\x3B\x84\x57\xB0\xFD\xFB\xE6\xBC"
|
||||
+ "\xF2\x76\xF6\x4C\xBB\xAB\xB1\x31\xA1\x27\x7C\xE6\xE6\x81\xB6\xCE"
|
||||
+ "\x84\x86\x40\xB6\x40\x33\xC4\xF8\xB4\x15\xCF\xAA\xA5\x51\x78\xB9"
|
||||
+ "\x8B\x50\x25\xB2\x88\x86\x96\x72\x8C\x71\x4D\xB5\x3A\x94\x86\x77"
|
||||
+ "\x0E\x95\x9B\x16\x93\xEF\x3A\x11\x79\xBA\x83\xF7\x74\xD3\x8D\xBA"
|
||||
+ "\x15\xE1\x2C\x04\x57\xA8\x92\x1E\x9D\x00\x8E\x20\xFD\x30\x70\xE7"
|
||||
+ "\xF5\x65\x2F\x19\x0C\x94\xBA\x03\x71\x12\x96\xCD\xC8\xB4\x96\xDB"
|
||||
+ "\xCE\x19\xC2\xDF\x3C\xC2\xF6\x3D\x53\xED\x98\xA5\x41\x72\x2A\x22"
|
||||
+ "\x7B\xF3\x2B\x17\x6C\xE1\x39\x7D\xAE\x9B\x11\xF9\xC1\xA6\x9E\x9F"
|
||||
+ "\x89\x3C\x12\xAA\x94\x74\xA7\x4F\x70\xE8\xB9\xDE\x04\xF0\x9D\x39"
|
||||
+ "\x24\x2D\x92\xE8\x46\x2D\x2E\xF0\x40\x66\x1A\xD9\x27\xF9\x98\xF1"
|
||||
+ "\x81\x1D\x70\x62\x63\x30\x6D\xCD\x84\x04\x5F\xFA\x83\xD3\xEC\x8D"
|
||||
+ "\x86\xFB\x40\x61\xC1\x8A\x45\xFF\x7B\xD9\xD4\x18\x61\x7F\x51\xE3"
|
||||
+ "\xFC\x1E\x18\xF0\xAF\xC6\x18\x2C\xE1\x6D\x5D\xF9\x62\xFC\x20\xA3"
|
||||
+ "\xB2\x8A\x5F\xE5\xBB\x29\x0F\x99\x63\x07\x88\x38\x3A\x3B\x73\x2A"
|
||||
+ "\x6D\xDA\x3D\xA8\x0D\x8F\x56\x41\x89\x82\xE5\xB8\x61\x00\x64\x7D"
|
||||
+ "\x17\x0C\xCE\x03\x55\x8F\xF4\x5B\x0D\x50\xF2\xEB\x05\x67\xBE\xDB"
|
||||
+ "\x7B\x75\xC5\xEA\xA1\xAB\x1D\xB0\x3C\x6D\x42\x08\x0B\x9A\x45\x20"
|
||||
+ "\xA8\x8F\xE5\x67\x47\x30\xDE\x93\x5F\x43\x05\xEB\xA8\x2D\x80\xF5"
|
||||
+ "\x1A\xB8\x4A\x4E\x42\x2D\x0B\x7A\xDC\x46\x20\x2D\x13\x17\xDD\x4B"
|
||||
+ "\x94\x96\xAA\x1F\x06\x0C\x1F\x62\x07\x9C\x40\xA1"
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+test_pac_ticket_signature(krb5_context context)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_ticket *ticket;
|
||||
+ krb5_principal sprinc;
|
||||
+ krb5_authdata **authdata1, **authdata2;
|
||||
+ krb5_pac pac, pac2, pac3;
|
||||
+ uint32_t *list;
|
||||
+ size_t len, i;
|
||||
+ krb5_data data;
|
||||
+
|
||||
+ ret = krb5_decode_ticket(&ticket_data, &ticket);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "while decoding ticket");
|
||||
+
|
||||
+ ret = krb5_decrypt_tkt_part(context, &ticket_sig_server_key, ticket);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "while decrypting ticket");
|
||||
+
|
||||
+ ret = krb5_parse_name(context, "s1@CDOM.COM", &sprinc);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "krb5_parse_name");
|
||||
+
|
||||
+ ret = krb5_kdc_verify_ticket(context, ticket->enc_part2, sprinc,
|
||||
+ &ticket_sig_server_key,
|
||||
+ &ticket_sig_krbtgt_key, &pac);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "while verifying ticket");
|
||||
+
|
||||
+ /* In this test, the server is also the client. */
|
||||
+ ret = krb5_pac_verify(context, pac, ticket->enc_part2->times.authtime,
|
||||
+ ticket->server, NULL, NULL);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "while verifying PAC client info");
|
||||
+
|
||||
+ /* We know there is only a PAC in this test's ticket. */
|
||||
+ authdata1 = ticket->enc_part2->authorization_data;
|
||||
+ ticket->enc_part2->authorization_data = NULL;
|
||||
+
|
||||
+ ret = krb5_kdc_sign_ticket(context, ticket->enc_part2, pac, sprinc,
|
||||
+ sprinc, &ticket_sig_server_key,
|
||||
+ &ticket_sig_krbtgt_key, FALSE);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "while signing ticket");
|
||||
+
|
||||
+ authdata2 = ticket->enc_part2->authorization_data;
|
||||
+ assert(authdata2 != NULL);
|
||||
+ assert(authdata2[1] == NULL);
|
||||
+
|
||||
+ assert(authdata1[0]->length == authdata2[0]->length);
|
||||
+ assert(memcmp(authdata1[0]->contents, authdata2[0]->contents,
|
||||
+ authdata1[0]->length) == 0);
|
||||
+
|
||||
+ /* Test adding signatures to a new PAC. */
|
||||
+ ret = krb5_pac_init(context, &pac2);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "krb5_pac_init");
|
||||
+
|
||||
+ ret = krb5_pac_get_types(context, pac, &len, &list);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "krb5_pac_get_types");
|
||||
+
|
||||
+ for (i = 0; i < len; i++) {
|
||||
+ /* Skip server_cksum, privsvr_cksum, and ticket_cksum. */
|
||||
+ if (list[i] == 6 || list[i] == 7 || list[i] == 16)
|
||||
+ continue;
|
||||
+
|
||||
+ ret = krb5_pac_get_buffer(context, pac, list[i], &data);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "krb5_pac_get_buffer");
|
||||
+
|
||||
+ ret = krb5_pac_add_buffer(context, pac2, list[i], &data);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "krb5_pac_add_buffer");
|
||||
+
|
||||
+ krb5_free_data_contents(context, &data);
|
||||
+ }
|
||||
+ free(list);
|
||||
+
|
||||
+ krb5_free_authdata(context, authdata1);
|
||||
+ krb5_free_authdata(context, ticket->enc_part2->authorization_data);
|
||||
+ ticket->enc_part2->authorization_data = NULL;
|
||||
+
|
||||
+ ret = krb5_kdc_sign_ticket(context, ticket->enc_part2, pac2, sprinc, NULL,
|
||||
+ &ticket_sig_server_key, &ticket_sig_krbtgt_key,
|
||||
+ FALSE);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "while signing ticket");
|
||||
+
|
||||
+ /* We can't compare the data since the order of the buffers may differ. */
|
||||
+ ret = krb5_kdc_verify_ticket(context, ticket->enc_part2, sprinc,
|
||||
+ &ticket_sig_server_key,
|
||||
+ &ticket_sig_krbtgt_key, &pac3);
|
||||
+ if (ret)
|
||||
+ err(context, ret, "while verifying ticket");
|
||||
+
|
||||
+ krb5_pac_free(context, pac);
|
||||
+ krb5_pac_free(context, pac2);
|
||||
+ krb5_pac_free(context, pac3);
|
||||
+ krb5_free_principal(context, sprinc);
|
||||
+ krb5_free_ticket(context, ticket);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
@@ -618,6 +798,8 @@ main(int argc, char **argv)
|
||||
if (ret)
|
||||
err(NULL, 0, "krb5_init_contex");
|
||||
|
||||
+ test_pac_ticket_signature(context);
|
||||
+
|
||||
ret = krb5_set_default_realm(context, "WIN2K3.THINKER.LOCAL");
|
||||
if (ret)
|
||||
err(context, ret, "krb5_set_default_realm");
|
||||
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
|
||||
index 48ae46f5c4..28784ec67c 100644
|
||||
--- a/src/lib/krb5/libkrb5.exports
|
||||
+++ b/src/lib/krb5/libkrb5.exports
|
||||
@@ -462,6 +462,8 @@ krb5_is_permitted_enctype
|
||||
krb5_is_referral_realm
|
||||
krb5_is_thread_safe
|
||||
krb5_kdc_rep_decrypt_proc
|
||||
+krb5_kdc_sign_ticket
|
||||
+krb5_kdc_verify_ticket
|
||||
krb5_kt_add_entry
|
||||
krb5_kt_client_default
|
||||
krb5_kt_close
|
||||
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
|
||||
index 209c6aaef5..8c3469a96c 100644
|
||||
--- a/src/lib/krb5_32.def
|
||||
+++ b/src/lib/krb5_32.def
|
||||
@@ -506,3 +506,6 @@ EXPORTS
|
||||
; new in 1.20
|
||||
krb5_marshal_credentials @472
|
||||
krb5_unmarshal_credentials @473
|
||||
+ k5_sname_compare @474 ; PRIVATE GSSAPI
|
||||
+ krb5_kdc_sign_ticket @475 ;
|
||||
+ krb5_kdc_verify_ticket @476 ;
|
||||
diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c
|
||||
index 38d371cb86..7d033acae4 100644
|
||||
--- a/src/plugins/kdb/test/kdb_test.c
|
||||
+++ b/src/plugins/kdb/test/kdb_test.c
|
||||
@@ -675,7 +675,7 @@ verify_kdc_signature(krb5_context context, krb5_pac pac,
|
||||
int tries;
|
||||
|
||||
ret = krb5_pac_verify(context, pac, 0, NULL, NULL, tgt_key);
|
||||
- if (ret != KRB5KRB_AP_ERR_BAD_INTEGRITY)
|
||||
+ if (ret != KRB5KRB_AP_ERR_MODIFIED)
|
||||
return ret;
|
||||
|
||||
kvno = tgt->key_data[0].key_data_kvno - 1;
|
||||
@@ -684,7 +684,7 @@ verify_kdc_signature(krb5_context context, krb5_pac pac,
|
||||
for (tries = 2; tries > 0 && kvno > 0; tries--, kvno--) {
|
||||
ret = krb5_dbe_find_enctype(context, tgt, -1, -1, kvno, &kd);
|
||||
if (ret)
|
||||
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||||
+ return KRB5KRB_AP_ERR_MODIFIED;
|
||||
ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -697,7 +697,7 @@ verify_kdc_signature(krb5_context context, krb5_pac pac,
|
||||
kvno = kd->key_data_kvno - 1;
|
||||
}
|
||||
|
||||
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||||
+ return KRB5KRB_AP_ERR_MODIFIED;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
--
|
||||
2.39.2
|
||||
|
258
Factor-out-PAC-checksum-verification.patch
Normal file
258
Factor-out-PAC-checksum-verification.patch
Normal file
@ -0,0 +1,258 @@
|
||||
From b0372e31b81321a820204450a35c7633caf1b7dd Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Fri, 14 Jan 2022 02:05:58 -0500
|
||||
Subject: [PATCH] Factor out PAC checksum verification
|
||||
|
||||
Reduce code repetition in PAC checksum handling by adding a helper
|
||||
function. Remove the unnecessary prefix on several function names.
|
||||
---
|
||||
src/lib/krb5/krb/pac.c | 173 +++++++++++++----------------------------
|
||||
1 file changed, 55 insertions(+), 118 deletions(-)
|
||||
|
||||
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
|
||||
index 6eb23d8090..2f6ad4e1df 100644
|
||||
--- a/src/lib/krb5/krb/pac.c
|
||||
+++ b/src/lib/krb5/krb/pac.c
|
||||
@@ -493,10 +493,8 @@ k5_pac_validate_client(krb5_context context,
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
-k5_pac_zero_signature(krb5_context context,
|
||||
- const krb5_pac pac,
|
||||
- krb5_ui_4 type,
|
||||
- krb5_data *data)
|
||||
+zero_signature(krb5_context context, const krb5_pac pac, krb5_ui_4 type,
|
||||
+ krb5_data *data)
|
||||
{
|
||||
PAC_INFO_BUFFER *buffer = NULL;
|
||||
size_t i;
|
||||
@@ -530,151 +528,89 @@ k5_pac_zero_signature(krb5_context context,
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
-k5_pac_verify_server_checksum(krb5_context context,
|
||||
- const krb5_pac pac,
|
||||
- const krb5_keyblock *server)
|
||||
+verify_checksum(krb5_context context, const krb5_pac pac, uint32_t buffer_type,
|
||||
+ const krb5_keyblock *key, krb5_keyusage usage,
|
||||
+ const krb5_data *data)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
- krb5_data pac_data; /* PAC with zeroed checksums */
|
||||
+ krb5_data buffer;
|
||||
+ krb5_cksumtype cksumtype;
|
||||
krb5_checksum checksum;
|
||||
- krb5_data checksum_data;
|
||||
krb5_boolean valid;
|
||||
- krb5_octet *p;
|
||||
+ size_t cksumlen;
|
||||
|
||||
- ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,
|
||||
- &checksum_data);
|
||||
+ ret = k5_pac_locate_buffer(context, pac, buffer_type, &buffer);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
-
|
||||
- if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH)
|
||||
+ if (buffer.length < PAC_SIGNATURE_DATA_LENGTH)
|
||||
return KRB5_BAD_MSIZE;
|
||||
|
||||
- p = (krb5_octet *)checksum_data.data;
|
||||
- checksum.checksum_type = load_32_le(p);
|
||||
- checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
- checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||||
- if (checksum.checksum_type == CKSUMTYPE_SHA1)
|
||||
+ cksumtype = load_32_le(buffer.data);
|
||||
+ if (buffer_type == KRB5_PAC_SERVER_CHECKSUM && cksumtype == CKSUMTYPE_SHA1)
|
||||
return KRB5KDC_ERR_SUMTYPE_NOSUPP;
|
||||
- if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||||
+ if (!krb5_c_is_keyed_cksum(cksumtype))
|
||||
return KRB5KRB_ERR_GENERIC;
|
||||
|
||||
- pac_data.length = pac->data.length;
|
||||
- pac_data.data = k5memdup(pac->data.data, pac->data.length, &ret);
|
||||
- if (pac_data.data == NULL)
|
||||
- return ret;
|
||||
-
|
||||
- /* Zero out both checksum buffers */
|
||||
- ret = k5_pac_zero_signature(context, pac, KRB5_PAC_SERVER_CHECKSUM,
|
||||
- &pac_data);
|
||||
- if (ret != 0) {
|
||||
- free(pac_data.data);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- ret = k5_pac_zero_signature(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,
|
||||
- &pac_data);
|
||||
- if (ret != 0) {
|
||||
- free(pac_data.data);
|
||||
+ /* There may be an RODCIdentifier trailer (see [MS-PAC] 2.8), so look up
|
||||
+ * the length of the checksum by its type. */
|
||||
+ ret = krb5_c_checksum_length(context, cksumtype, &cksumlen);
|
||||
+ if (ret)
|
||||
return ret;
|
||||
- }
|
||||
+ if (cksumlen > buffer.length - PAC_SIGNATURE_DATA_LENGTH)
|
||||
+ return KRB5_BAD_MSIZE;
|
||||
+ checksum.checksum_type = cksumtype;
|
||||
+ checksum.length = cksumlen;
|
||||
+ checksum.contents = (uint8_t *)buffer.data + PAC_SIGNATURE_DATA_LENGTH;
|
||||
|
||||
- ret = krb5_c_verify_checksum(context, server,
|
||||
- KRB5_KEYUSAGE_APP_DATA_CKSUM,
|
||||
- &pac_data, &checksum, &valid);
|
||||
+ ret = krb5_c_verify_checksum(context, key, usage, data, &checksum, &valid);
|
||||
+ return ret ? ret : (valid ? 0 : KRB5KRB_AP_ERR_MODIFIED);
|
||||
+}
|
||||
|
||||
- free(pac_data.data);
|
||||
+static krb5_error_code
|
||||
+verify_server_checksum(krb5_context context, const krb5_pac pac,
|
||||
+ const krb5_keyblock *server)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_data copy; /* PAC with zeroed checksums */
|
||||
|
||||
- if (ret != 0) {
|
||||
+ ret = krb5int_copy_data_contents(context, &pac->data, ©);
|
||||
+ if (ret)
|
||||
return ret;
|
||||
- }
|
||||
|
||||
- if (valid == FALSE)
|
||||
- ret = KRB5KRB_AP_ERR_MODIFIED;
|
||||
+ /* Zero out both checksum buffers */
|
||||
+ ret = zero_signature(context, pac, KRB5_PAC_SERVER_CHECKSUM, ©);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ ret = zero_signature(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, ©);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ ret = verify_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM, server,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, ©);
|
||||
|
||||
+cleanup:
|
||||
+ free(copy.data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
-k5_pac_verify_kdc_checksum(krb5_context context,
|
||||
- const krb5_pac pac,
|
||||
- const krb5_keyblock *privsvr)
|
||||
+verify_kdc_checksum(krb5_context context, const krb5_pac pac,
|
||||
+ const krb5_keyblock *privsvr)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
- krb5_data server_checksum, privsvr_checksum;
|
||||
- krb5_checksum checksum;
|
||||
- krb5_boolean valid;
|
||||
- krb5_octet *p;
|
||||
-
|
||||
- ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,
|
||||
- &privsvr_checksum);
|
||||
- if (ret != 0)
|
||||
- return ret;
|
||||
-
|
||||
- if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH)
|
||||
- return KRB5_BAD_MSIZE;
|
||||
+ krb5_data server_checksum;
|
||||
|
||||
ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,
|
||||
&server_checksum);
|
||||
- if (ret != 0)
|
||||
+ if (ret)
|
||||
return ret;
|
||||
-
|
||||
if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH)
|
||||
return KRB5_BAD_MSIZE;
|
||||
-
|
||||
- p = (krb5_octet *)privsvr_checksum.data;
|
||||
- checksum.checksum_type = load_32_le(p);
|
||||
- checksum.length = privsvr_checksum.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
- checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||||
- if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||||
- return KRB5KRB_ERR_GENERIC;
|
||||
-
|
||||
server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
|
||||
server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;
|
||||
|
||||
- ret = krb5_c_verify_checksum(context, privsvr,
|
||||
- KRB5_KEYUSAGE_APP_DATA_CKSUM,
|
||||
- &server_checksum, &checksum, &valid);
|
||||
- if (ret != 0)
|
||||
- return ret;
|
||||
-
|
||||
- if (valid == FALSE)
|
||||
- ret = KRB5KRB_AP_ERR_MODIFIED;
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static krb5_error_code
|
||||
-verify_ticket_checksum(krb5_context context, const krb5_pac pac,
|
||||
- const krb5_data *ticket, const krb5_keyblock *privsvr)
|
||||
-{
|
||||
- krb5_error_code ret;
|
||||
- krb5_checksum checksum;
|
||||
- krb5_data checksum_data;
|
||||
- krb5_boolean valid;
|
||||
- krb5_octet *p;
|
||||
-
|
||||
- ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_TICKET_CHECKSUM,
|
||||
- &checksum_data);
|
||||
- if (ret != 0)
|
||||
- return KRB5KRB_AP_ERR_MODIFIED;
|
||||
-
|
||||
- if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH)
|
||||
- return KRB5_BAD_MSIZE;
|
||||
-
|
||||
- p = (krb5_octet *)checksum_data.data;
|
||||
- checksum.checksum_type = load_32_le(p);
|
||||
- checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
|
||||
- checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||||
- if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||||
- return KRB5KRB_ERR_GENERIC;
|
||||
-
|
||||
- ret = krb5_c_verify_checksum(context, privsvr,
|
||||
- KRB5_KEYUSAGE_APP_DATA_CKSUM, ticket,
|
||||
- &checksum, &valid);
|
||||
- if (ret != 0)
|
||||
- return ret;
|
||||
-
|
||||
- return valid ? 0 : KRB5KRB_AP_ERR_MODIFIED;
|
||||
+ return verify_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, privsvr,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, &server_checksum);
|
||||
}
|
||||
|
||||
/* Per MS-PAC 2.8.3, tickets encrypted to TGS and password change principals
|
||||
@@ -761,7 +697,8 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
- ret = verify_ticket_checksum(context, pac, recoded_tkt, privsvr);
|
||||
+ ret = verify_checksum(context, pac, KRB5_PAC_TICKET_CHECKSUM, privsvr,
|
||||
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, recoded_tkt);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -804,13 +741,13 @@ krb5_pac_verify_ext(krb5_context context,
|
||||
krb5_error_code ret;
|
||||
|
||||
if (server != NULL) {
|
||||
- ret = k5_pac_verify_server_checksum(context, pac, server);
|
||||
+ ret = verify_server_checksum(context, pac, server);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (privsvr != NULL) {
|
||||
- ret = k5_pac_verify_kdc_checksum(context, pac, privsvr);
|
||||
+ ret = verify_kdc_checksum(context, pac, privsvr);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
--
|
||||
2.39.2
|
||||
|
184
Use-14-instead-of-9-for-unkeyed-SHA-1-checksum.patch
Normal file
184
Use-14-instead-of-9-for-unkeyed-SHA-1-checksum.patch
Normal file
@ -0,0 +1,184 @@
|
||||
From b6ada496a285a7b350e28c97b53b6f659a9a94b9 Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Sat, 11 Dec 2021 01:25:34 -0500
|
||||
Subject: [PATCH] Use 14 instead of 9 for unkeyed SHA-1 checksum
|
||||
|
||||
Although MIT krb5 had been using the value 9 for unkeyed SHA-1 since
|
||||
its 1.0 release in 1996, RFC 3961 instead assigned this value to
|
||||
rsa-md5-des3 (likely never used), and assigned the values 10 and 14 to
|
||||
SHA-1. Heimdal and Microsoft use the value 14. Unkeyed SHA-1 almost
|
||||
never appears on the wire, but has been seen in PKINIT asChecksum
|
||||
fields in replies from Windows KDCs (despite the field being specified
|
||||
as a keyed checksum).
|
||||
|
||||
Define a new symbol CKSUMTYPE_SHA1 with the value 14, and use it where
|
||||
we currently use CKSUMTYPE_NIST_SHA. Continue to allow the value 9
|
||||
for ABI compatibility. Remove the pkinit_clnt.c workaround as the
|
||||
value 14 will now work without adjustment.
|
||||
|
||||
ticket: 9040 (new)
|
||||
---
|
||||
doc/appdev/refs/macros/index.rst | 1 +
|
||||
src/include/krb5/krb5.hin | 6 ++++++
|
||||
src/lib/crypto/crypto_tests/t_cksums.c | 2 +-
|
||||
src/lib/crypto/krb/cksumtypes.c | 6 ++++++
|
||||
src/lib/gssapi/mechglue/g_saslname.c | 3 +--
|
||||
src/lib/krb5/os/trace.c | 2 +-
|
||||
src/plugins/kdb/test/kdb_test.c | 2 +-
|
||||
src/plugins/preauth/pkinit/pkinit_clnt.c | 11 ++---------
|
||||
src/plugins/preauth/pkinit/pkinit_srv.c | 4 ++--
|
||||
9 files changed, 21 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst
|
||||
index 788d094bff..001fb386a7 100644
|
||||
--- a/doc/appdev/refs/macros/index.rst
|
||||
+++ b/doc/appdev/refs/macros/index.rst
|
||||
@@ -42,6 +42,7 @@ Public
|
||||
CKSUMTYPE_RSA_MD4_DES.rst
|
||||
CKSUMTYPE_RSA_MD5.rst
|
||||
CKSUMTYPE_RSA_MD5_DES.rst
|
||||
+ CKSUMTYPE_SHA1.rst
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA1_96.rst
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA256_128.rst
|
||||
ENCTYPE_AES256_CTS_HMAC_SHA1_96.rst
|
||||
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||
index d2cf1eba2a..a7060aa733 100644
|
||||
--- a/src/include/krb5/krb5.hin
|
||||
+++ b/src/include/krb5/krb5.hin
|
||||
@@ -449,6 +449,11 @@ typedef struct _krb5_crypto_iov {
|
||||
#define ENCTYPE_CAMELLIA256_CTS_CMAC 0x001a /**< RFC 6803 */
|
||||
#define ENCTYPE_UNKNOWN 0x01ff
|
||||
|
||||
+/*
|
||||
+ * Historically we used the value 9 for unkeyed SHA-1. RFC 3961 assigns this
|
||||
+ * value to rsa-md5-des3, which fortunately is unused. For ABI compatibility
|
||||
+ * we allow either 9 or 14 for SHA-1.
|
||||
+ */
|
||||
#define CKSUMTYPE_CRC32 0x0001
|
||||
#define CKSUMTYPE_RSA_MD4 0x0002
|
||||
#define CKSUMTYPE_RSA_MD4_DES 0x0003
|
||||
@@ -459,6 +464,7 @@ typedef struct _krb5_crypto_iov {
|
||||
#define CKSUMTYPE_RSA_MD5_DES 0x0008
|
||||
#define CKSUMTYPE_NIST_SHA 0x0009
|
||||
#define CKSUMTYPE_HMAC_SHA1_DES3 0x000c /* @deprecated removed */
|
||||
+#define CKSUMTYPE_SHA1 0x000d /**< RFC 3962 */
|
||||
#define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f /**< RFC 3962. Used with
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA1_96 */
|
||||
#define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010 /**< RFC 3962. Used with
|
||||
diff --git a/src/lib/crypto/crypto_tests/t_cksums.c b/src/lib/crypto/crypto_tests/t_cksums.c
|
||||
index 84408fb68a..de5ed3a22b 100644
|
||||
--- a/src/lib/crypto/crypto_tests/t_cksums.c
|
||||
+++ b/src/lib/crypto/crypto_tests/t_cksums.c
|
||||
@@ -54,7 +54,7 @@ struct test {
|
||||
},
|
||||
{
|
||||
{ KV5M_DATA, 0, "" },
|
||||
- CKSUMTYPE_NIST_SHA, 0, 0, { KV5M_DATA, 0, "" },
|
||||
+ CKSUMTYPE_SHA1, 0, 0, { KV5M_DATA, 0, "" },
|
||||
{ KV5M_DATA, 20,
|
||||
"\xDA\x39\xA3\xEE\x5E\x6B\x4B\x0D\x32\x55\xBF\xEF\x95\x60\x18\x90"
|
||||
"\xAF\xD8\x07\x09" }
|
||||
diff --git a/src/lib/crypto/krb/cksumtypes.c b/src/lib/crypto/krb/cksumtypes.c
|
||||
index f5fbe8a2a7..25a3ffd2d2 100644
|
||||
--- a/src/lib/crypto/krb/cksumtypes.c
|
||||
+++ b/src/lib/crypto/krb/cksumtypes.c
|
||||
@@ -46,6 +46,12 @@ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = {
|
||||
krb5int_unkeyed_checksum, NULL,
|
||||
20, 20, CKSUM_UNKEYED },
|
||||
|
||||
+ { CKSUMTYPE_SHA1,
|
||||
+ "sha", { 0 }, "SHA-1",
|
||||
+ NULL, &krb5int_hash_sha1,
|
||||
+ krb5int_unkeyed_checksum, NULL,
|
||||
+ 20, 20, CKSUM_UNKEYED },
|
||||
+
|
||||
{ CKSUMTYPE_HMAC_MD5_ARCFOUR,
|
||||
"hmac-md5-rc4", { "hmac-md5-enc", "hmac-md5-earcfour" },
|
||||
"Microsoft HMAC MD5",
|
||||
diff --git a/src/lib/gssapi/mechglue/g_saslname.c b/src/lib/gssapi/mechglue/g_saslname.c
|
||||
index e25f9e0a53..2be0c8a69a 100644
|
||||
--- a/src/lib/gssapi/mechglue/g_saslname.c
|
||||
+++ b/src/lib/gssapi/mechglue/g_saslname.c
|
||||
@@ -58,8 +58,7 @@ oidToSaslName(OM_uint32 *minor, const gss_OID mech,
|
||||
iov[2].data.length = sizeof(cksumBuf);
|
||||
iov[2].data.data = (char *)cksumBuf;
|
||||
|
||||
- *minor = krb5_k_make_checksum_iov(NULL, CKSUMTYPE_NIST_SHA,
|
||||
- NULL, 0, iov, 3);
|
||||
+ *minor = krb5_k_make_checksum_iov(NULL, CKSUMTYPE_SHA1, NULL, 0, iov, 3);
|
||||
if (*minor != 0)
|
||||
return GSS_S_FAILURE;
|
||||
|
||||
diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
|
||||
index e9b99f4ca0..abb8a3f21b 100644
|
||||
--- a/src/lib/krb5/os/trace.c
|
||||
+++ b/src/lib/krb5/os/trace.c
|
||||
@@ -93,7 +93,7 @@ hash_bytes(krb5_context context, const void *ptr, size_t len)
|
||||
krb5_data d = make_data((void *) ptr, len);
|
||||
char *s = NULL;
|
||||
|
||||
- if (krb5_k_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0, &d,
|
||||
+ if (krb5_k_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, &d,
|
||||
&cksum) != 0)
|
||||
return NULL;
|
||||
if (cksum.length >= 2)
|
||||
diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c
|
||||
index 95a6062e2a..38d371cb86 100644
|
||||
--- a/src/plugins/kdb/test/kdb_test.c
|
||||
+++ b/src/plugins/kdb/test/kdb_test.c
|
||||
@@ -205,7 +205,7 @@ make_keyblock(krb5_kvno kvno, krb5_enctype etype, int32_t salttype,
|
||||
(int)salttype, princstr, (int)realm->length, realm->data) < 0)
|
||||
abort();
|
||||
d = string2data(hashstr);
|
||||
- check(krb5_c_make_checksum(NULL, CKSUMTYPE_NIST_SHA, NULL, 0, &d, &cksum));
|
||||
+ check(krb5_c_make_checksum(NULL, CKSUMTYPE_SHA1, NULL, 0, &d, &cksum));
|
||||
|
||||
/* Make the appropriate number of input bytes from the hash result. */
|
||||
for (pos = 0; pos < keybytes; pos += n) {
|
||||
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||
index 9b991ffe05..021e5f0723 100644
|
||||
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||
@@ -119,8 +119,8 @@ pa_pkinit_gen_req(krb5_context context,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0,
|
||||
- der_req, &cksum);
|
||||
+ retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,
|
||||
+ &cksum);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
TRACE_PKINIT_CLIENT_REQ_CHECKSUM(context, &cksum);
|
||||
@@ -701,13 +701,6 @@ pkinit_as_rep_parse(krb5_context context,
|
||||
pkiDebug("failed to decode reply_key_pack\n");
|
||||
goto cleanup;
|
||||
}
|
||||
- /*
|
||||
- * This is hack but Windows sends back SHA1 checksum
|
||||
- * with checksum type of 14. There is currently no
|
||||
- * checksum type of 14 defined.
|
||||
- */
|
||||
- if (key_pack->asChecksum.checksum_type == 14)
|
||||
- key_pack->asChecksum.checksum_type = CKSUMTYPE_NIST_SHA;
|
||||
retval = krb5_c_make_checksum(context,
|
||||
key_pack->asChecksum.checksum_type,
|
||||
&key_pack->replyKey,
|
||||
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||
index 3ae56c0641..3bff456f8f 100644
|
||||
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||
@@ -546,8 +546,8 @@ pkinit_server_verify_padata(krb5_context context,
|
||||
goto cleanup;
|
||||
}
|
||||
der_req = cb->request_body(context, rock);
|
||||
- retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0,
|
||||
- der_req, &cksum);
|
||||
+ retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,
|
||||
+ &cksum);
|
||||
if (retval) {
|
||||
pkiDebug("unable to calculate AS REQ checksum\n");
|
||||
goto cleanup;
|
||||
--
|
||||
2.39.2
|
||||
|
140
downstream-Support-PAC-full-checksum-w-o-ticket-chec.patch
Normal file
140
downstream-Support-PAC-full-checksum-w-o-ticket-chec.patch
Normal file
@ -0,0 +1,140 @@
|
||||
From 8ded82fb279198f3fa20fb7c836e77290e7bc6f6 Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Fri, 24 Mar 2023 16:22:06 +0100
|
||||
Subject: [PATCH] [downstream] Support PAC full checksum w/o ticket checksum
|
||||
|
||||
---
|
||||
doc/appdev/refs/api/index.rst | 1 +
|
||||
src/include/krb5/krb5.hin | 38 +++++++++++++++++++++++++++++++++++
|
||||
src/lib/krb5/krb/pac.c | 10 ++++++++-
|
||||
src/lib/krb5/krb/pac_sign.c | 17 ++++++++++++++++
|
||||
src/lib/krb5/libkrb5.exports | 1 +
|
||||
5 files changed, 66 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst
|
||||
index d12be47c3c..ff813108bb 100644
|
||||
--- a/doc/appdev/refs/api/index.rst
|
||||
+++ b/doc/appdev/refs/api/index.rst
|
||||
@@ -248,6 +248,7 @@ Rarely used public interfaces
|
||||
krb5_os_localaddr.rst
|
||||
krb5_pac_add_buffer.rst
|
||||
krb5_pac_free.rst
|
||||
+ krb5_pac_full_sign_compat.rst
|
||||
krb5_pac_get_buffer.rst
|
||||
krb5_pac_get_types.rst
|
||||
krb5_pac_init.rst
|
||||
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||
index 12a1d441b8..dbe87561c5 100644
|
||||
--- a/src/include/krb5/krb5.hin
|
||||
+++ b/src/include/krb5/krb5.hin
|
||||
@@ -8392,6 +8392,44 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
const krb5_keyblock *privsvr_key, krb5_boolean with_realm,
|
||||
krb5_data *data);
|
||||
|
||||
+/**
|
||||
+ * Compatibility function used by IPA if the 1.20 KDB diver API is not
|
||||
+ * available. It generates PAC signatures, including the extended KDC one when
|
||||
+ * relevant.
|
||||
+ *
|
||||
+ * It is similar to krb5_kdc_sign_ticket(), except it will not generate the
|
||||
+ * PAC ticket signature, and therefore does not expect encrypted ticket part as
|
||||
+ * parameter.
|
||||
+ *
|
||||
+ * @param [in] context Library context
|
||||
+ * @param [in] pac PAC handle
|
||||
+ * @param [in] authtime Expected timestamp
|
||||
+ * @param [in] client_princ Client principal name (or NULL)
|
||||
+ * @param [in] server_princ Server principal name
|
||||
+ * @param [in] server_key Key for server checksum
|
||||
+ * @param [in] privsvr_key Key for KDC checksum
|
||||
+ * @param [in] with_realm If true, include the realm of @a client_princ
|
||||
+ * @param [out] data Signed PAC encoding
|
||||
+ *
|
||||
+ * This function signs @a pac using the keys @a server_key and @a privsvr_key
|
||||
+ * and returns the signed encoding in @a data. @a pac is modified to include
|
||||
+ * the server and KDC checksum buffers. Use krb5_free_data_contents() to free
|
||||
+ * @a data when it is no longer needed.
|
||||
+ *
|
||||
+ * If @a with_realm is true, the PAC_CLIENT_INFO field of the signed PAC will
|
||||
+ * include the realm of @a client_princ as well as the name. This flag is
|
||||
+ * necessary to generate PACs for cross-realm S4U2Self referrals.
|
||||
+ */
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_pac_full_sign_compat(krb5_context context, krb5_pac pac,
|
||||
+ krb5_timestamp authtime,
|
||||
+ krb5_const_principal client_princ,
|
||||
+ krb5_const_principal server_princ,
|
||||
+ const krb5_keyblock *server_key,
|
||||
+ const krb5_keyblock *privsvr_key,
|
||||
+ krb5_boolean with_realm,
|
||||
+ krb5_data *data);
|
||||
+
|
||||
/**
|
||||
* Sign a PAC, possibly including a ticket signature
|
||||
*
|
||||
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
|
||||
index 9c00178a28..b7fa064100 100644
|
||||
--- a/src/lib/krb5/krb/pac.c
|
||||
+++ b/src/lib/krb5/krb/pac.c
|
||||
@@ -757,9 +757,17 @@ krb5_pac_verify_ext(krb5_context context,
|
||||
krb5_boolean with_realm)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
+ krb5_boolean has_full_chksum;
|
||||
|
||||
if (server != NULL || privsvr != NULL) {
|
||||
- ret = verify_pac_checksums(context, pac, FALSE, server, privsvr);
|
||||
+ /* Fail only if full checksum is present and invalid.
|
||||
+ * Proceed if absent.
|
||||
+ */
|
||||
+ ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_FULL_CHECKSUM, NULL);
|
||||
+ has_full_chksum = ret != ENOENT;
|
||||
+
|
||||
+ ret = verify_pac_checksums(context, pac, has_full_chksum, server,
|
||||
+ privsvr);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c
|
||||
index 8ea61ac17b..7c3a86d8eb 100644
|
||||
--- a/src/lib/krb5/krb/pac_sign.c
|
||||
+++ b/src/lib/krb5/krb/pac_sign.c
|
||||
@@ -309,6 +309,23 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||||
with_realm, FALSE, data);
|
||||
}
|
||||
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_pac_full_sign_compat(krb5_context context, krb5_pac pac,
|
||||
+ krb5_timestamp authtime,
|
||||
+ krb5_const_principal client_princ,
|
||||
+ krb5_const_principal server_princ,
|
||||
+ const krb5_keyblock *server_key,
|
||||
+ const krb5_keyblock *privsvr_key,
|
||||
+ krb5_boolean with_realm,
|
||||
+ krb5_data *data)
|
||||
+{
|
||||
+ krb5_boolean is_service_tkt;
|
||||
+
|
||||
+ is_service_tkt = k5_pac_should_have_ticket_signature(server_princ);
|
||||
+ return sign_pac(context, pac, authtime, client_princ, server_key,
|
||||
+ privsvr_key, with_realm, is_service_tkt, data);
|
||||
+}
|
||||
+
|
||||
/* Add a signature over der_enc_tkt in privsvr to pac. der_enc_tkt should be
|
||||
* encoded with a dummy PAC authdata element containing a single zero byte. */
|
||||
static krb5_error_code
|
||||
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
|
||||
index 28784ec67c..ac94e0c236 100644
|
||||
--- a/src/lib/krb5/libkrb5.exports
|
||||
+++ b/src/lib/krb5/libkrb5.exports
|
||||
@@ -508,6 +508,7 @@ krb5_os_localaddr
|
||||
krb5_overridekeyname
|
||||
krb5_pac_add_buffer
|
||||
krb5_pac_free
|
||||
+krb5_pac_full_sign_compat
|
||||
krb5_pac_get_buffer
|
||||
krb5_pac_get_types
|
||||
krb5_pac_init
|
||||
--
|
||||
2.40.1
|
||||
|
11
krb5.spec
11
krb5.spec
@ -18,7 +18,7 @@ Summary: The Kerberos network authentication system
|
||||
Name: krb5
|
||||
Version: 1.18.2
|
||||
# for prerelease, should be e.g., 0.% {prerelease}.1% { ?dist } (without spaces)
|
||||
Release: 22%{?dist}
|
||||
Release: 23%{?dist}
|
||||
|
||||
# lookaside-cached sources; two downloads and a build artifact
|
||||
Source0: https://web.mit.edu/kerberos/dist/krb5/1.18/krb5-%{version}%{prerelease}.tar.gz
|
||||
@ -94,6 +94,11 @@ Patch148: downstream-Fix-dejagnu-unit-tests-directory-name-for-RPC-lib.patch
|
||||
Patch149: krb5-krad-larger-attrs.patch
|
||||
Patch150: krb5-krad-remote.patch
|
||||
Patch151: Fix-integer-overflows-in-PAC-parsing.patch
|
||||
Patch152: Use-14-instead-of-9-for-unkeyed-SHA-1-checksum.patch
|
||||
Patch153: Add-PAC-ticket-signature-APIs.patch
|
||||
Patch154: Factor-out-PAC-checksum-verification.patch
|
||||
Patch155: Add-PAC-full-checksums.patch
|
||||
Patch156: downstream-Support-PAC-full-checksum-w-o-ticket-chec.patch
|
||||
|
||||
License: MIT
|
||||
URL: http://web.mit.edu/kerberos/www/
|
||||
@ -704,6 +709,10 @@ exit 0
|
||||
%{_libdir}/libkadm5srv_mit.so.*
|
||||
|
||||
%changelog
|
||||
* Wed May 31 2023 Julien Rische <jrische@redhat.com> - 1.18.2-23
|
||||
- Support PAC with KDC extended signature and without ticket signature
|
||||
- Resolves: rhbz#2169477
|
||||
|
||||
* Tue Nov 08 2022 Julien Rische <jrische@redhat.com> - 1.18.2-22
|
||||
- Fix integer overflows in PAC parsing (CVE-2022-42898)
|
||||
- Resolves: rhbz#2140968
|
||||
|
Loading…
Reference in New Issue
Block a user