From a599b39ea9f8028f26c84bd13150dfbd12cc5b89 Mon Sep 17 00:00:00 2001 From: Julien Rische Date: Thu, 8 Jun 2023 15:43:12 +0200 Subject: [PATCH] Allow to set PAC ticket signature as optional Resolves: rhbz#2178298 Signed-off-by: Julien Rische --- ...-to-set-PAC-ticket-signature-as-opti.patch | 276 ++++++++++++++++++ krb5.spec | 7 +- 2 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 0019-downstream-Allow-to-set-PAC-ticket-signature-as-opti.patch diff --git a/0019-downstream-Allow-to-set-PAC-ticket-signature-as-opti.patch b/0019-downstream-Allow-to-set-PAC-ticket-signature-as-opti.patch new file mode 100644 index 0000000..e086c96 --- /dev/null +++ b/0019-downstream-Allow-to-set-PAC-ticket-signature-as-opti.patch @@ -0,0 +1,276 @@ +From 5ace3ea56c0d507ca3d976d06c0e68aa63c52f26 Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Wed, 15 Mar 2023 15:56:34 +0100 +Subject: [PATCH] [downstream] Allow to set PAC ticket signature as optional + +MS-PAC states that "The ticket signature SHOULD be included in tickets +that are not encrypted to the krbtgt account". However, the +implementation of krb5_kdc_verify_ticket() will require the ticket +signature to be present in case the target of the request is a service +principal. + +In gradual upgrade environments, it results in S4U2Proxy requests +against a 1.20 KDC using a service ticket generated by an older version +KDC to fail. + +This commit adds a krb5_kdc_verify_ticket_ext() function with an extra +switch parameter to tolerate the absence of ticket signature in this +scenario. If the ticket signature is present, it has to be valid, +regardless of this parameter. + +This parameter is set based on the "optional_pac_tkt_chksum" string +attribute of the TGT KDB entry. +--- + doc/admin/admin_commands/kadmin_local.rst | 6 ++++ + doc/appdev/refs/api/index.rst | 1 + + src/include/kdb.h | 1 + + src/include/krb5/krb5.hin | 40 +++++++++++++++++++++++ + src/kdc/kdc_util.c | 26 ++++++++++++--- + src/lib/krb5/krb/pac.c | 31 +++++++++++++++--- + src/lib/krb5/libkrb5.exports | 1 + + src/lib/krb5_32.def | 1 + + src/man/kadmin.man | 6 ++++ + 9 files changed, 105 insertions(+), 8 deletions(-) + +diff --git a/doc/admin/admin_commands/kadmin_local.rst b/doc/admin/admin_commands/kadmin_local.rst +index cf75e61584..45cce8bb57 100644 +--- a/doc/admin/admin_commands/kadmin_local.rst ++++ b/doc/admin/admin_commands/kadmin_local.rst +@@ -671,6 +671,12 @@ KDC: + is in the same format as those used by the **pkinit_cert_match** + option in :ref:`krb5.conf(5)`. (New in release 1.16.) + ++**optional_pac_tkt_chksum** ++ Boolean value defining the behavior of the KDC in case an expected ++ ticket checksum signed with one of this principal keys is not ++ present in the PAC. This is typically the case for TGS or ++ cross-realm TGS principals when processing S4U2Proxy requests. ++ + This command requires the **modify** privilege. + + Alias: **setstr** +diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst +index d12be47c3c..9b95ebd0f9 100644 +--- a/doc/appdev/refs/api/index.rst ++++ b/doc/appdev/refs/api/index.rst +@@ -225,6 +225,7 @@ Rarely used public interfaces + krb5_is_referral_realm.rst + krb5_kdc_sign_ticket.rst + krb5_kdc_verify_ticket.rst ++ krb5_kdc_verify_ticket_ext.rst + krb5_kt_add_entry.rst + krb5_kt_end_seq_get.rst + krb5_kt_get_entry.rst +diff --git a/src/include/kdb.h b/src/include/kdb.h +index 21bddcfb88..b65c300d8a 100644 +--- a/src/include/kdb.h ++++ b/src/include/kdb.h +@@ -134,6 +134,7 @@ + /* String attribute names recognized by krb5 */ + #define KRB5_KDB_SK_SESSION_ENCTYPES "session_enctypes" + #define KRB5_KDB_SK_REQUIRE_AUTH "require_auth" ++#define KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM "optional_pac_tkt_chksum" + + #if !defined(_WIN32) + +diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin +index 2ba4010514..404719a3a4 100644 +--- a/src/include/krb5/krb5.hin ++++ b/src/include/krb5/krb5.hin +@@ -8355,6 +8355,46 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt, + const krb5_keyblock *server, + const krb5_keyblock *privsvr, krb5_pac *pac_out); + ++/** ++ * Verify a PAC, possibly including ticket signature ++ * ++ * @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) ++ * @paran [in] optional_tkt_chksum Whether to require a ticket checksum ++ * @param [out] pac_out Verified PAC (NULL if no PAC included) ++ * ++ * This function is an extension of krb5_kdc_verify_ticket(), adding the @a ++ * optional_tkt_chksum parameter allowing to tolerate the absence of the PAC ++ * ticket signature. ++ * ++ * 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 and ++ * @a optional_tkt_chksum is FALSE, 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. ++ * ++ * 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 ++ */ ++krb5_error_code KRB5_CALLCONV ++krb5_kdc_verify_ticket_ext(krb5_context context, ++ const krb5_enc_tkt_part *enc_tkt, ++ krb5_const_principal server_princ, ++ const krb5_keyblock *server, ++ const krb5_keyblock *privsvr, ++ krb5_boolean optional_tkt_chksum, ++ 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, +diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c +index b7a9aa4992..bdf1bf2dc8 100644 +--- a/src/kdc/kdc_util.c ++++ b/src/kdc/kdc_util.c +@@ -535,6 +535,8 @@ get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt, + krb5_key_data *kd; + krb5_keyblock old_key; + krb5_kvno kvno; ++ krb5_boolean optional_tkt_chksum; ++ char *str = NULL; + int tries; + + *pac_out = NULL; +@@ -545,8 +547,23 @@ get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt, + NULL, pac_out); + } + +- ret = krb5_kdc_verify_ticket(context, enc_tkt, sprinc, server_key, +- tgt_key, pac_out); ++ /* Check if the absence of ticket signature is tolerated for this realm */ ++ ret = krb5_dbe_get_string(context, tgt, ++ KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM, &str); ++ /* TODO: should be using _krb5_conf_boolean(), but os-proto.h is not ++ * available here. ++ */ ++ optional_tkt_chksum = !ret && str && (strncasecmp(str, "true", 4) == 0 ++ || strncasecmp(str, "t", 1) == 0 ++ || strncasecmp(str, "yes", 3) == 0 ++ || strncasecmp(str, "y", 1) == 0 ++ || strncasecmp(str, "1", 1) == 0 ++ || strncasecmp(str, "on", 2) == 0); ++ ++ krb5_dbe_free_string(context, str); ++ ++ ret = krb5_kdc_verify_ticket_ext(context, enc_tkt, sprinc, server_key, ++ tgt_key, optional_tkt_chksum, pac_out); + if (ret != KRB5KRB_AP_ERR_MODIFIED && ret != KRB5_BAD_ENCTYPE) + return ret; + +@@ -559,8 +576,9 @@ get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt, + ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL); + if (ret) + return ret; +- ret = krb5_kdc_verify_ticket(context, enc_tkt, sprinc, server_key, +- &old_key, pac_out); ++ ret = krb5_kdc_verify_ticket_ext(context, enc_tkt, sprinc, server_key, ++ &old_key, optional_tkt_chksum, ++ pac_out); + krb5_free_keyblock_contents(context, &old_key); + if (!ret) + return 0; +diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c +index 954482e0c7..738887b388 100644 +--- a/src/lib/krb5/krb/pac.c ++++ b/src/lib/krb5/krb/pac.c +@@ -636,6 +636,19 @@ 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) ++{ ++ return krb5_kdc_verify_ticket_ext(context, enc_tkt, server_princ, server, ++ privsvr, FALSE, pac_out); ++} ++ ++krb5_error_code KRB5_CALLCONV ++krb5_kdc_verify_ticket_ext(krb5_context context, ++ const krb5_enc_tkt_part *enc_tkt, ++ krb5_const_principal server_princ, ++ const krb5_keyblock *server, ++ const krb5_keyblock *privsvr, ++ krb5_boolean optional_tkt_chksum, ++ krb5_pac *pac_out) + { + krb5_error_code ret; + krb5_pac pac = NULL; +@@ -643,7 +656,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; ++ krb5_boolean is_service_tkt, has_tkt_chksum = FALSE; + size_t i, j; + + *pac_out = NULL; +@@ -706,11 +719,21 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt, + + ret = verify_checksum(context, pac, KRB5_PAC_TICKET_CHECKSUM, privsvr, + KRB5_KEYUSAGE_APP_DATA_CKSUM, recoded_tkt); +- if (ret) +- goto cleanup; ++ if (ret) { ++ if (!optional_tkt_chksum) ++ goto cleanup; ++ else if (ret != ENOENT) ++ goto cleanup; ++ /* Otherwise ticket signature is absent but optional. Proceed... */ ++ } else { ++ has_tkt_chksum = TRUE; ++ } + } ++ /* Else, we make the assumption the ticket signature is absent in case this ++ * is not a service ticket. ++ */ + +- ret = verify_pac_checksums(context, pac, is_service_tkt, server, privsvr); ++ ret = verify_pac_checksums(context, pac, has_tkt_chksum, server, privsvr); + if (ret) + goto cleanup; + +diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports +index 4c50e935a2..d4b0455c8c 100644 +--- a/src/lib/krb5/libkrb5.exports ++++ b/src/lib/krb5/libkrb5.exports +@@ -463,6 +463,7 @@ krb5_is_thread_safe + krb5_kdc_rep_decrypt_proc + krb5_kdc_sign_ticket + krb5_kdc_verify_ticket ++krb5_kdc_verify_ticket_ext + 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 b1610974b1..6ecd92c1ec 100644 +--- a/src/lib/krb5_32.def ++++ b/src/lib/krb5_32.def +@@ -510,3 +510,4 @@ EXPORTS + k5_sname_compare @474 ; PRIVATE GSSAPI + krb5_kdc_sign_ticket @475 ; + krb5_kdc_verify_ticket @476 ; ++ krb5_kdc_verify_ticket_ext @477 ; +diff --git a/src/man/kadmin.man b/src/man/kadmin.man +index 73e1b03cdb..54efd4ebc9 100644 +--- a/src/man/kadmin.man ++++ b/src/man/kadmin.man +@@ -715,6 +715,12 @@ attributes required for the client certificate used by the + principal during PKINIT authentication. The matching expression + is in the same format as those used by the \fBpkinit_cert_match\fP + option in krb5.conf(5)\&. (New in release 1.16.) ++.TP ++\fBoptional_pac_tkt_chksum\fP ++Boolean value defining the behavior of the KDC in case an expected ticket ++checksum signed with one of this principal keys is not present in the PAC. This ++is typically the case for TGS or cross-realm TGS principals when processing ++S4U2Proxy requests. + .UNINDENT + .sp + This command requires the \fBmodify\fP privilege. +-- +2.40.1 + diff --git a/krb5.spec b/krb5.spec index 7ac7935..ea56638 100644 --- a/krb5.spec +++ b/krb5.spec @@ -34,7 +34,7 @@ # # baserelease is what we have standardized across Fedora and what # rpmdev-bumpspec knows how to handle. -%global baserelease 8 +%global baserelease 8.1 # This should be e.g. beta1 or %%nil %global pre_release %nil @@ -101,6 +101,7 @@ Patch15: 0015-downstream-Allow-KRB5KDF-MD5-and-MD4-in-FIPS-mode.patch Patch16: 0016-Add-PAC-full-checksums.patch Patch17: 0017-Fix-possible-double-free-during-KDB-creation.patch Patch18: 0018-Fix-meridian-type-in-kadmin-datetime-parser.patch +Patch19: 0019-downstream-Allow-to-set-PAC-ticket-signature-as-opti.patch License: MIT URL: https://web.mit.edu/kerberos/www/ @@ -665,6 +666,10 @@ exit 0 %{_libdir}/libkadm5srv_mit.so.* %changelog +* Thu Jun 08 2023 Julien Rische - 1.20.1-8.1 +- Allow to set PAC ticket signature as optional +- Resolves: rhbz#2178298 + * Wed Feb 22 2023 Julien Rische - 1.20.1-8 - Fix datetime parsing in kadmin on s390x - Resolves: rhbz#2169985