diff --git a/SOURCES/Try-harder-to-avoid-password-change-replay-errors.patch b/SOURCES/Try-harder-to-avoid-password-change-replay-errors.patch new file mode 100644 index 0000000..0c12935 --- /dev/null +++ b/SOURCES/Try-harder-to-avoid-password-change-replay-errors.patch @@ -0,0 +1,91 @@ +From d0f65d35675131dc299ad300722d4c358db9d4f4 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 4 Mar 2022 00:45:00 -0500 +Subject: [PATCH] Try harder to avoid password change replay errors + +Commit d7b3018d338fc9c989c3fa17505870f23c3759a8 (ticket 7905) changed +change_set_password() to prefer TCP. However, because UDP_LAST falls +back to UDP after one second, we can still get a replay error due to a +dropped packet, before the TCP layer has a chance to retry. + +Instead, try k5_sendto() with NO_UDP, and only fall back to UDP after +TCP fails completely without reaching a server. In sendto_kdc.c, +implement an ONLY_UDP transport strategy to allow the UDP fallback. + +ticket: 9037 +--- + src/lib/krb5/os/changepw.c | 9 ++++++++- + src/lib/krb5/os/os-proto.h | 1 + + src/lib/krb5/os/sendto_kdc.c | 12 ++++++++---- + 3 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c +index 9f968da7f..c59232586 100644 +--- a/src/lib/krb5/os/changepw.c ++++ b/src/lib/krb5/os/changepw.c +@@ -255,9 +255,16 @@ change_set_password(krb5_context context, + callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup; + krb5_free_data_contents(callback_ctx.context, &chpw_rep); + ++ /* UDP retransmits may be seen as replays. Only try UDP after other ++ * transports fail completely. */ + code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm, +- &sl, UDP_LAST, &callback_info, &chpw_rep, ++ &sl, NO_UDP, &callback_info, &chpw_rep, + ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL); ++ if (code == KRB5_KDC_UNREACH) { ++ code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm, ++ &sl, ONLY_UDP, &callback_info, &chpw_rep, ++ ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL); ++ } + if (code) + goto cleanup; + +diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h +index 7cf5a4879..69d4ec34e 100644 +--- a/src/lib/krb5/os/os-proto.h ++++ b/src/lib/krb5/os/os-proto.h +@@ -49,6 +49,7 @@ typedef enum { + UDP_FIRST = 0, + UDP_LAST, + NO_UDP, ++ ONLY_UDP + } k5_transport_strategy; + + /* A single server hostname or address. */ +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index fffe0262f..e790a5198 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -795,11 +795,14 @@ resolve_server(krb5_context context, const krb5_data *realm, + int err, result; + char portbuf[PORT_LENGTH]; + +- /* Skip UDP entries if we don't want UDP. */ ++ /* Skip entries excluded by the strategy. */ + if (strategy == NO_UDP && entry->transport == UDP) + return 0; ++ if (strategy == ONLY_UDP && entry->transport != UDP && ++ entry->transport != TCP_OR_UDP) ++ return 0; + +- transport = (strategy == UDP_FIRST) ? UDP : TCP; ++ transport = (strategy == UDP_FIRST || strategy == ONLY_UDP) ? UDP : TCP; + if (entry->hostname == NULL) { + /* Added by a module, so transport is either TCP or UDP. */ + ai.ai_socktype = socktype_for_transport(entry->transport); +@@ -843,8 +846,9 @@ resolve_server(krb5_context context, const krb5_data *realm, + } + + /* For TCP_OR_UDP entries, add each address again with the non-preferred +- * transport, unless we are avoiding UDP. Flag these as deferred. */ +- if (retval == 0 && entry->transport == TCP_OR_UDP && strategy != NO_UDP) { ++ * transport, if there is one. Flag these as deferred. */ ++ if (retval == 0 && entry->transport == TCP_OR_UDP && ++ (strategy == UDP_FIRST || strategy == UDP_LAST)) { + transport = (strategy == UDP_FIRST) ? TCP : UDP; + for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { + a->ai_socktype = socktype_for_transport(transport); +-- +2.35.1 + diff --git a/SOURCES/Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest.patch b/SOURCES/Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest.patch new file mode 100644 index 0000000..a33f2e9 --- /dev/null +++ b/SOURCES/Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest.patch @@ -0,0 +1,135 @@ +From 5c093c6bad9fd1a7ce418435be03074714ad958c Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Fri, 11 Mar 2022 12:04:14 +0100 +Subject: [PATCH] Use SHA-256 instead of SHA-1 for PKINIT CMS digest + +Various organizations including NIST have been strongly recommending to +stop using SHA-1 for digital signatures for some years already. CMS +digest is used to generate such signatures, hence it should be upgraded +to use SHA-256. +--- + .../preauth/pkinit/pkinit_crypto_openssl.c | 42 ++++++++++--------- + 1 file changed, 23 insertions(+), 19 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 25bcef292..dc7ce7b23 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -1240,7 +1240,7 @@ cms_signeddata_create(krb5_context context, + /* will not fill-out EVP_PKEY because it's on the smartcard */ + + /* Set digest algs */ +- p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1); ++ p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha256); + + if (p7si->digest_alg->parameter != NULL) + ASN1_TYPE_free(p7si->digest_alg->parameter); +@@ -1251,7 +1251,8 @@ cms_signeddata_create(krb5_context context, + /* Set sig algs */ + if (p7si->digest_enc_alg->parameter != NULL) + ASN1_TYPE_free(p7si->digest_enc_alg->parameter); +- p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption); ++ p7si->digest_enc_alg->algorithm = ++ OBJ_nid2obj(NID_sha256WithRSAEncryption); + if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new())) + goto cleanup; + p7si->digest_enc_alg->parameter->type = V_ASN1_NULL; +@@ -1262,11 +1263,11 @@ cms_signeddata_create(krb5_context context, + alen = data_len; + } else { + /* add signed attributes */ +- /* compute sha1 digest over the EncapsulatedContentInfo */ ++ /* compute sha256 digest over the EncapsulatedContentInfo */ + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) + goto cleanup; +- EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); ++ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); + EVP_DigestUpdate(ctx, data, data_len); + md_tmp = EVP_MD_CTX_md(ctx); + EVP_DigestFinal_ex(ctx, md_data, &md_len); +@@ -1295,12 +1296,14 @@ cms_signeddata_create(krb5_context context, + } /* signed attributes */ + + #ifndef WITHOUT_PKCS11 +- /* Some tokens can only do RSAEncryption without sha1 hash */ +- /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash +- * function and the hash value into an ASN.1 value of type DigestInfo +- * DigestInfo::=SEQUENCE { +- * digestAlgorithm AlgorithmIdentifier, +- * digest OCTET STRING } ++ /* ++ * Some tokens can only do RSAEncryption without a hash. To compute ++ * sha256WithRSAEncryption, encode the algorithm ID for the hash ++ * function and the hash value into an ASN.1 value of type DigestInfo: ++ * DigestInfo ::= SEQUENCE { ++ * digestAlgorithm AlgorithmIdentifier, ++ * digest OCTET STRING ++ * } + */ + if (id_cryptoctx->pkcs11_method == 1 && + id_cryptoctx->mech == CKM_RSA_PKCS) { +@@ -1312,7 +1315,7 @@ cms_signeddata_create(krb5_context context, + if (cms_msg_type != CMS_SIGN_DRAFT9) + EVP_DigestInit_ex(ctx, md_tmp, NULL); + else +- EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); ++ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); + EVP_DigestUpdate(ctx, abuf, alen); + EVP_DigestFinal_ex(ctx, md_data2, &md_len2); + EVP_MD_CTX_free(ctx); +@@ -1320,7 +1323,7 @@ cms_signeddata_create(krb5_context context, + alg = X509_ALGOR_new(); + if (alg == NULL) + goto cleanup2; +- X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha1), V_ASN1_NULL, NULL); ++ X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha256), V_ASN1_NULL, NULL); + alg_len = i2d_X509_ALGOR(alg, NULL); + alg_buf = malloc(alg_len); + if (alg_buf == NULL) +@@ -1355,7 +1358,7 @@ cms_signeddata_create(krb5_context context, + #endif + { + pkiDebug("mech = %s\n", +- id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS"); ++ id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA256_RSA_PKCS" : "FS"); + retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen, + &sig, &sig_len); + } +@@ -4228,7 +4231,7 @@ create_signature(unsigned char **sig, unsigned int *sig_len, + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) + return ENOMEM; +- EVP_SignInit(ctx, EVP_sha1()); ++ EVP_SignInit(ctx, EVP_sha256()); + EVP_SignUpdate(ctx, data, data_len); + *sig_len = EVP_PKEY_size(pkey); + if ((*sig = malloc(*sig_len)) == NULL) +@@ -4741,10 +4744,11 @@ pkinit_get_certs_pkcs11(krb5_context context, + + #ifndef PKINIT_USE_MECH_LIST + /* +- * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but +- * many cards seems to be confused about whether they are capable of +- * this or not. The safe thing seems to be to ignore the mechanism list, +- * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves. ++ * We'd like to use CKM_SHA256_RSA_PKCS for signing if it's available, but ++ * historically many cards seem to be confused about whether they are ++ * capable of mechanisms or not. The safe thing seems to be to ignore the ++ * mechanism list, always use CKM_RSA_PKCS and calculate the sha256 digest ++ * ourselves. + */ + + id_cryptoctx->mech = CKM_RSA_PKCS; +@@ -4772,7 +4776,7 @@ pkinit_get_certs_pkcs11(krb5_context context, + if (mechp[i] == CKM_RSA_PKCS) { + /* This seems backwards... */ + id_cryptoctx->mech = +- (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS; ++ (info.flags & CKF_SIGN) ? CKM_SHA256_RSA_PKCS : CKM_RSA_PKCS; + } + } + free(mechp); +-- +2.35.1 + diff --git a/SPECS/krb5.spec b/SPECS/krb5.spec index 83ca697..b94d8da 100644 --- a/SPECS/krb5.spec +++ b/SPECS/krb5.spec @@ -12,7 +12,7 @@ Summary: The Kerberos network authentication system Name: krb5 Version: 1.15.1 -Release: 51%{?dist} +Release: 54%{?dist} # - Maybe we should explode from the now-available-to-everybody tarball instead? # http://web.mit.edu/kerberos/dist/krb5/1.13/krb5-1.13.2-signed.tar @@ -141,6 +141,8 @@ Patch228: Do-expiration-warnings-for-all-init_creds-APIs.patch Patch229: Remove-vestigial-svr_principal.c-code.patch Patch230: Fix-LDAP-policy-enforcement-of-pw_expiration.patch Patch231: Fix-KDC-null-deref-on-TGS-inner-body-null-server.patch +Patch232: Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest.patch +Patch233: Try-harder-to-avoid-password-change-replay-errors.patch License: MIT URL: http://web.mit.edu/kerberos/www/ @@ -415,6 +417,8 @@ ONLY by kerberos itself. Do not depend on this package. %patch229 -p1 -b .Remove-vestigial-svr_principal.c-code %patch230 -p1 -b .Fix-LDAP-policy-enforcement-of-pw_expiration %patch231 -p1 -b .Fix-KDC-null-deref-on-TGS-inner-body-null-server +%patch232 -p1 -b .Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest +%patch233 -p1 -b .Try-harder-to-avoid-password-change-replay-errors ln NOTICE LICENSE @@ -922,6 +926,14 @@ exit 0 %{_libdir}/libkadm5srv_mit.so.* %changelog +* Wed Apr 27 2022 Julien Rische - 1.15.1-54 +- Try harder to avoid password change replay errors +- Resolves: #2063163 + +* Thu Apr 7 2022 Julien Rische - 1.15.1-53 +- Backport usage of SHA-256 instead of SHA-1 for PKINIT CMS digest +- Resolves: #2066319 + * Wed Oct 20 2021 Antonio Torres - 1.15.1-51 - Fix KDC null deref on TGS inner body null server (CVE-2021-37750) - Resolves: #1997599