public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/nss] rawhide: Cherry-pick remaining confirmed patches from RHEL nss-3.124
@ 2026-08-21 11:21
0 siblings, 0 replies; only message in thread
From: @ 2026-08-21 11:21 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/nss
Branch : rawhide
Commit : ee18cf1cde5c422bca0f4519cb6e1a5e118d2bf9
Author : Krenželok František <fkrenzel@redhat.com>
Date : 2026-08-20T13:43:38+02:00
Stats : +849/-0 in 4 file(s)
URL : https://src.fedoraproject.org/rpms/nss/c/ee18cf1cde5c422bca0f4519cb6e1a5e118d2bf9?branch=rawhide
Log:
Cherry-pick remaining confirmed patches from RHEL nss-3.124
Line-level diff against NSS 3.127 source confirmed all three absent:
- nss-3.124-fips-key-import-fix: add force-mode to
pk11_ImportSymKeyWithTempl so unwrap paths can import symmetric keys
into a FIPS token via CKM_CONCATENATE_DATA_AND_BASE when direct
import fails
- nss-3.124-fix-pub-key-import-encapsulate: fix PK11_Encapsulate to
import the public key onto the slot before use instead of relying on
pubKey->pkcs11ID; fix NULL slot handling and wincx in Decapsulate
- nss-3.124-allow-hash-override-pss: allow PSS hash algorithm override
instead of hard-failing on hash mismatch; fix sec_DecodeRSAPSSParams
to tolerate empty params
---
diff --git a/nss-3.124-allow-hash-override-pss.patch b/nss-3.124-allow-hash-override-pss.patch
new file mode 100644
index 0000000..9e5443a
--- /dev/null
+++ b/nss-3.124-allow-hash-override-pss.patch
@@ -0,0 +1,489 @@
+# HG changeset patch
+# User Robert Relyea <rrelyea@redhat.com>
+# Date 1781635239 25200
+# Tue Jun 16 11:40:39 2026 -0700
+# Branch NSS_3_124_BRANCH
+# Node ID c85110e0f7ba48ef44c9b535a9c3bccf78f8416d
+# Parent 4b0e3f33a2e76a77e36b435eb3cc1eb06f14249d
+nss-3.124-allow-hash-override-pss.patch
+
+diff --git a/cmd/certutil/certutil.c b/cmd/certutil/certutil.c
+--- a/cmd/certutil/certutil.c
++++ b/cmd/certutil/certutil.c
+@@ -228,16 +228,20 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
+ return SECFailure;
+ }
+
+ /* Change cert type to RSA-PSS, if desired. */
+ if (pssCertificate) {
+ /* force a PSS signature. We can do a PSS signature with an
+ * RSA key, this will force us to generate a PSS signature */
+ signAlgTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
++ /* we are reusing an algorithm id, prevent the assert when we try
++ * to set the parameters of that algorithm id */
++ spki->algorithm.parameters.data = NULL;
++ spki->algorithm.parameters.len = 0;
+ /* override the SPKI algorithm id. */
+ rv = SEC_CreateSignatureAlgorithmID(arena, &spki->algorithm,
+ signAlgTag, hashAlgTag,
+ NULL, NULL, pubk);
+ if (rv != SECSuccess) {
+ PORT_FreeArena(arena, PR_FALSE);
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ SECU_PrintError(progName, "unable to set algorithm ID");
+diff --git a/gtests/cryptohi_gtest/cryptohi_unittest.cc b/gtests/cryptohi_gtest/cryptohi_unittest.cc
+--- a/gtests/cryptohi_gtest/cryptohi_unittest.cc
++++ b/gtests/cryptohi_gtest/cryptohi_unittest.cc
+@@ -105,17 +105,17 @@ class SignParamsTestF : public ::testing
+ SECItem *saltLengthItem =
+ SEC_ASN1EncodeInteger(arena_.get(), ¶ms->saltLength, saltLength);
+ ASSERT_EQ(¶ms->saltLength, saltLengthItem);
+ }
+
+ void CheckHashAlg(SECKEYRSAPSSParams *params, SECOidTag hashAlgTag) {
+ // If hash algorithm is SHA-1, it must be omitted in the parameters
+ if (hashAlgTag == SEC_OID_SHA1) {
+- EXPECT_EQ(nullptr, params->hashAlg);
++ EXPECT_EQ(nullptr, params->hashAlg) << "oid==" << SECOID_FindOIDTagDescription(SECOID_GetAlgorithmTag(params->hashAlg));
+ } else {
+ EXPECT_NE(nullptr, params->hashAlg);
+ EXPECT_EQ(hashAlgTag, SECOID_GetAlgorithmTag(params->hashAlg));
+ }
+ }
+
+ void CheckMaskAlg(SECKEYRSAPSSParams *params, SECOidTag hashAlgTag) {
+ SECStatus rv;
+@@ -225,22 +225,16 @@ TEST_P(SignParamsTest, CreateRsaPss) {
+ } else {
+ srcParams = NULL;
+ }
+
+ SECItem *params = SEC_CreateSignatureAlgorithmParameters(
+ arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg,
+ srcParams, privk_.get());
+
+- if (hashAlg != SEC_OID_UNKNOWN && srcHashAlg != SEC_OID_UNKNOWN &&
+- hashAlg != srcHashAlg) {
+- EXPECT_EQ(nullptr, params);
+- return;
+- }
+-
+ EXPECT_NE(nullptr, params);
+
+ SECKEYRSAPSSParams pssParams;
+ PORT_Memset(&pssParams, 0, sizeof(pssParams));
+ SECStatus rv =
+ SEC_QuickDERDecodeItem(arena_.get(), &pssParams,
+ SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate), params);
+ ASSERT_EQ(SECSuccess, rv);
+@@ -294,83 +288,100 @@ TEST_P(SignParamsTest, CreateRsaPssWithE
+
+ TEST_P(SignParamsTest, CreateRsaPssWithInvalidHashAlg) {
+ SECOidTag srcHashAlg = std::get<1>(GetParam());
+
+ SECItem *srcParams;
+ if (srcHashAlg != SEC_OID_UNKNOWN) {
+ SECKEYRSAPSSParams pssParams;
+ ASSERT_NO_FATAL_FAILURE(
+- CreatePssParams(&pssParams, srcHashAlg, srcHashAlg));
++ CreatePssParams(&pssParams, SEC_OID_MD5, SEC_OID_MD5));
+ srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams,
+ SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate));
+ ASSERT_NE(nullptr, srcParams);
+ } else {
+ srcParams = NULL;
+ }
+
+ SECItem *params = SEC_CreateSignatureAlgorithmParameters(
+- arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, SEC_OID_MD5,
++ arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, srcHashAlg,
+ srcParams, privk_.get());
+
+- EXPECT_EQ(nullptr, params);
++ /* override invalid hash with valid hash */
++ EXPECT_NE(nullptr, params);
++ /* assert params ->hashAlg != SEC_OID_MD5 */
+ }
+
+ TEST_P(SignParamsSourceTest, CreateRsaPssWithInvalidHashAlg) {
+ SECOidTag hashAlg = GetParam();
+
+ SECItem *srcParams;
+ SECKEYRSAPSSParams pssParams;
+ ASSERT_NO_FATAL_FAILURE(
+- CreatePssParams(&pssParams, SEC_OID_MD5, SEC_OID_MD5));
++ CreatePssParams(&pssParams, hashAlg, hashAlg));
+ srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams,
+ SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate));
+ ASSERT_NE(nullptr, srcParams);
+
+ SECItem *params = SEC_CreateSignatureAlgorithmParameters(
+- arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg,
++ arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, SEC_OID_MD4,
+ srcParams, privk_.get());
+
+ EXPECT_EQ(nullptr, params);
+ }
+
+ TEST_P(SignParamsSourceTest, CreateRsaPssWithInvalidSaltLength) {
+ SECOidTag hashAlg = GetParam();
+
+ SECItem *srcParams;
+ SECKEYRSAPSSParams pssParams;
+ ASSERT_NO_FATAL_FAILURE(
+- CreatePssParams(&pssParams, SEC_OID_SHA512, SEC_OID_SHA512, 100));
++ CreatePssParams(&pssParams, SEC_OID_SHA512, SEC_OID_SHA512, 110));
+ srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams,
+ SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate));
+ ASSERT_NE(nullptr, srcParams);
+
+ SECItem *params = SEC_CreateSignatureAlgorithmParameters(
+ arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg,
+ srcParams, privk_.get());
+
+ EXPECT_EQ(nullptr, params);
+ }
+
+ TEST_P(SignParamsSourceTest, CreateRsaPssWithHashMismatch) {
+ SECOidTag hashAlg = GetParam();
+
+ SECItem *srcParams;
+ SECKEYRSAPSSParams pssParams;
++ if ((hashAlg == SEC_OID_UNKNOWN) || (hashAlg == SEC_OID_SHA512)) {
++ hashAlg = SEC_OID_SHA1;
++ }
+ ASSERT_NO_FATAL_FAILURE(
+- CreatePssParams(&pssParams, SEC_OID_SHA256, SEC_OID_SHA512));
++ CreatePssParams(&pssParams, hashAlg, SEC_OID_SHA512));
+ srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams,
+ SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate));
+ ASSERT_NE(nullptr, srcParams);
+
+ SECItem *params = SEC_CreateSignatureAlgorithmParameters(
+- arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg,
++ arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, SEC_OID_UNKNOWN,
+ srcParams, privk_.get());
+
+- EXPECT_EQ(nullptr, params);
++ EXPECT_NE(nullptr, params);
++
++ PORT_Memset(&pssParams, 0, sizeof(pssParams));
++ SECStatus rv =
++ SEC_QuickDERDecodeItem(arena_.get(), &pssParams,
++ SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate), params);
++ ASSERT_EQ(SECSuccess, rv);
++ ASSERT_NO_FATAL_FAILURE(CheckHashAlg(&pssParams, hashAlg));
++ ASSERT_NO_FATAL_FAILURE(CheckMaskAlg(&pssParams, hashAlg));
++ ASSERT_NO_FATAL_FAILURE(CheckSaltLength(&pssParams, hashAlg));
++
++ // The default trailer field (1) must be omitted
++ EXPECT_EQ(nullptr, pssParams.trailerField.data);
+ }
+
+ INSTANTIATE_TEST_SUITE_P(
+ SignParamsTestCases, SignParamsTest,
+ ::testing::Combine(::testing::Values(SEC_OID_UNKNOWN, SEC_OID_SHA1,
+ SEC_OID_SHA224, SEC_OID_SHA256,
+ SEC_OID_SHA384, SEC_OID_SHA512),
+ ::testing::Values(SEC_OID_UNKNOWN, SEC_OID_SHA1,
+diff --git a/lib/cryptohi/seckey.c b/lib/cryptohi/seckey.c
+--- a/lib/cryptohi/seckey.c
++++ b/lib/cryptohi/seckey.c
+@@ -2876,21 +2876,23 @@ sec_DecodeRSAPSSParams(PLArenaPool *aren
+ SECKEYRSAPSSParams pssParams;
+ SECOidTag hashAlg;
+ SECOidTag maskHashAlg;
+ unsigned long saltLength;
+ unsigned long trailerField;
+ SECStatus rv;
+
+ PORT_Memset(&pssParams, 0, sizeof(pssParams));
+- rv = SEC_QuickDERDecodeItem(arena, &pssParams,
+- SECKEY_RSAPSSParamsTemplate,
+- params);
+- if (rv != SECSuccess) {
+- return rv;
++ if (params && (params->len != 0)) {
++ rv = SEC_QuickDERDecodeItem(arena, &pssParams,
++ SECKEY_RSAPSSParamsTemplate,
++ params);
++ if (rv != SECSuccess) {
++ return rv;
++ }
+ }
+
+ if (pssParams.hashAlg) {
+ hashAlg = SECOID_GetAlgorithmTag(pssParams.hashAlg);
+ } else {
+ hashAlg = SEC_OID_SHA1; /* default, SHA-1 */
+ }
+
+diff --git a/lib/cryptohi/secsign.c b/lib/cryptohi/secsign.c
+--- a/lib/cryptohi/secsign.c
++++ b/lib/cryptohi/secsign.c
+@@ -814,16 +814,18 @@ sec_CreateRSAPSSParameters(PLArenaPool *
+ SECOidTag hashAlgTag,
+ const SECItem *params,
+ int modBytes)
+ {
+ SECKEYRSAPSSParams pssParams;
+ int hashLength;
+ unsigned long saltLength;
+ PRBool defaultSHA1 = PR_FALSE;
++ PRBool overWriteHash = PR_TRUE;
++ PRBool overWriteMask = PR_TRUE;
+ SECStatus rv;
+
+ PORT_Memset(&pssParams, 0, sizeof(pssParams));
+
+ if (params && params->data) {
+ /* The parameters field should either be empty or contain
+ * valid RSA-PSS parameters */
+ PORT_Assert(!(params->len == 2 &&
+@@ -831,16 +833,18 @@ sec_CreateRSAPSSParameters(PLArenaPool *
+ params->data[1] == 0));
+ rv = SEC_QuickDERDecodeItem(arena, &pssParams,
+ SECKEY_RSAPSSParamsTemplate,
+ params);
+ if (rv != SECSuccess) {
+ return NULL;
+ }
+ defaultSHA1 = PR_TRUE;
++ overWriteHash = PR_FALSE;
++ overWriteMask = PR_FALSE;
+ }
+
+ if (pssParams.trailerField.data) {
+ unsigned long trailerField;
+
+ rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField,
+ &trailerField);
+ if (rv != SECSuccess) {
+@@ -851,19 +855,21 @@ sec_CreateRSAPSSParameters(PLArenaPool *
+ return NULL;
+ }
+ }
+
+ /* Determine the hash algorithm to use, based on hashAlgTag and
+ * pssParams.hashAlg; there are 6 cases.
+ * case:
+ * 1) We have params and params.hashAlg and we have a specified hashAlgTag,
+- * make sure that hashAlgTag specified by the appication matches.
++ * make sure that hashAlgTag specified by the appication matches, othersize we
++ * overwrite params.hashAlg with hashAlgTag.
+ * 2) We have params, but no params.hashAlg and we have a specified
+- * hashAlg, make sure the hashAlgTag matches SEC_OID_SHA1.
++ * hashAlg, make sure the hashAlgTag matches SEC_OID_SHA1, otherwise we
++ * overwrite params.hashAlg with hashAlgTag..
+ * 3) we did not specify any parameters but we did specified
+ * a hashAlgTag. Use the specified hash algtag.
+ * 4) We have params and params.hashAlg and we did not specify a
+ * hashAlgTag, use the hashAlg from the parameter.
+ * 5) We have params, but no params.hashAlg and we did not specify a
+ * hashAlgTag, use the SEC_OID_SHA1
+ * 6) We did not specify any parameters, nor did we specify a
+ * hashAlgTag, use the key size to select an appropriate hashAlg.
+@@ -873,36 +879,42 @@ sec_CreateRSAPSSParameters(PLArenaPool *
+
+ if (pssParams.hashAlg) {
+ tag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
+ } else if (defaultSHA1) {
+ tag = SEC_OID_SHA1;
+ }
+
+ if (tag != SEC_OID_UNKNOWN && tag != hashAlgTag) {
+- PORT_SetError(SEC_ERROR_INVALID_ARGS);
+- return NULL;
++ overWriteHash = PR_TRUE;
+ }
+ } else if (hashAlgTag == SEC_OID_UNKNOWN) {
+ if (pssParams.hashAlg) {
+ hashAlgTag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
+ } else if (defaultSHA1) {
+ hashAlgTag = SEC_OID_SHA1;
+ } else {
+ /* Find a suitable hash algorithm based on the NIST recommendation */
+ if (modBytes <= 384) { /* 128, in NIST 800-57, Part 1 */
+ hashAlgTag = SEC_OID_SHA256;
+ } else if (modBytes <= 960) { /* 192, NIST 800-57, Part 1 */
+ hashAlgTag = SEC_OID_SHA384;
+ } else {
+ hashAlgTag = SEC_OID_SHA512;
+ }
++ overWriteHash = PR_TRUE;
+ }
+ }
+
++ /* handle the case where the params invalidly encoded SEC_OID_SHA1. This
++ * will force the correct encoding */
++ if ((hashAlgTag == SEC_OID_SHA1) && pssParams.hashAlg) {
++ overWriteHash = PR_TRUE;
++ }
++
+ /* explicitly restrict hashAlg to SHA2 variants */
+ if (hashAlgTag != SEC_OID_SHA1 && hashAlgTag != SEC_OID_SHA224 &&
+ hashAlgTag != SEC_OID_SHA256 && hashAlgTag != SEC_OID_SHA384 &&
+ hashAlgTag != SEC_OID_SHA512) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return NULL;
+ }
+
+@@ -927,23 +939,24 @@ sec_CreateRSAPSSParameters(PLArenaPool *
+ &pssParams.maskAlg->parameters);
+ if (rv != SECSuccess) {
+ return NULL;
+ }
+
+ /* Following the recommendation in RFC 4055, assume the hash
+ * algorithm identical to pssParam.hashAlg */
+ if (SECOID_GetAlgorithmTag(&maskHashAlg) != hashAlgTag) {
+- PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+- return NULL;
++ overWriteMask = PR_TRUE;
++ }
++ if (hashAlgTag == SEC_OID_SHA1) {
++ overWriteMask = PR_TRUE;
+ }
+ } else if (defaultSHA1) {
+ if (hashAlgTag != SEC_OID_SHA1) {
+- PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+- return NULL;
++ overWriteMask = PR_TRUE;
+ }
+ }
+
+ hashLength = HASH_ResultLenByOidTag(hashAlgTag);
+
+ if (modBytes < hashLength + 2) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+@@ -961,42 +974,38 @@ sec_CreateRSAPSSParameters(PLArenaPool *
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+ } else if (defaultSHA1) {
+ saltLength = 20;
+ }
+
+ /* Fill in the parameters */
+- if (pssParams.hashAlg) {
++ if (overWriteHash) {
+ if (hashAlgTag == SEC_OID_SHA1) {
+ /* Omit hashAlg if the the algorithm is SHA-1 (default) */
+ pssParams.hashAlg = NULL;
+- }
+- } else {
+- if (hashAlgTag != SEC_OID_SHA1) {
++ } else {
+ pssParams.hashAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID));
+ if (!pssParams.hashAlg) {
+ return NULL;
+ }
+ rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag,
+ NULL);
+ if (rv != SECSuccess) {
+ return NULL;
+ }
+ }
+ }
+
+- if (pssParams.maskAlg) {
++ if (overWriteMask) {
+ if (hashAlgTag == SEC_OID_SHA1) {
+ /* Omit maskAlg if the the algorithm is SHA-1 (default) */
+ pssParams.maskAlg = NULL;
+- }
+- } else {
+- if (hashAlgTag != SEC_OID_SHA1) {
++ } else {
+ SECItem *hashAlgItem;
+
+ PORT_Assert(pssParams.hashAlg != NULL);
+
+ hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg,
+ SEC_ASN1_GET(SECOID_AlgorithmIDTemplate));
+ if (!hashAlgItem) {
+ return NULL;
+@@ -1086,17 +1095,16 @@ SEC_CreateSignatureAlgorithmParameters(P
+ const SECItem *params,
+ const SECKEYPrivateKey *key)
+ {
+ PORT_SetError(0);
+ switch (signAlgTag) {
+ case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
+ return SEC_CreateRSAPSSParameters(arena, result,
+ hashAlgTag, params, key, NULL);
+-
+ default:
+ if (params == NULL)
+ return NULL;
+ if (result == NULL)
+ result = SECITEM_AllocItem(arena, NULL, 0);
+ if (result == NULL) {
+ return NULL;
+ }
+@@ -1112,16 +1120,19 @@ SEC_CreateVerifyAlgorithmParameters(PLAr
+ SECOidTag signAlgTag,
+ SECOidTag hashAlgTag,
+ const SECItem *params,
+ const SECKEYPublicKey *key)
+ {
+ PORT_SetError(0);
+ switch (signAlgTag) {
+ case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
++ if ((hashAlgTag == SEC_OID_UNKNOWN) && ((params == NULL) || (params->len == 0))){
++ return NULL;
++ }
+ return SEC_CreateRSAPSSParameters(arena, result,
+ hashAlgTag, params, NULL, key);
+
+ default:
+ if (params == NULL)
+ return NULL;
+ if (result == NULL)
+ result = SECITEM_AllocItem(arena, NULL, 0);
+diff --git a/tests/cert/cert.sh b/tests/cert/cert.sh
+--- a/tests/cert/cert.sh
++++ b/tests/cert/cert.sh
+@@ -2234,20 +2234,18 @@ EOF
+ # Signature: RSA-PSS (with conflicting hash algorithm)
+ CERTNAME="TestUser-rsa-pss7"
+
+ CU_ACTION="Generate Cert Request for $CERTNAME"
+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
+ certu -R -d "${PROFILEDIR}" -f "${R_PWFILE}" -z "${R_NOISE_FILE}" --pss -o req 2>&1
+
+ CU_ACTION="Sign ${CERTNAME}'s Request"
+- RETEXPECTED=255
+ certu -C -c "TestCA-rsa-pss" --pss-sign -Z SHA512 -m "${CERTSERIAL}" -v 60 -d "${P_R_CADIR}" \
+ -i req -o "${CERTNAME}.cert" -f "${R_PWFILE}" "$1" 2>&1
+- RETEXPECTED=0
+
+ CERTSERIAL=`expr $CERTSERIAL + 1`
+
+ # Subject certificate: RSA-PSS
+ # Issuer certificate: RSA-PSS
+ # Signature: RSA-PSS (with compatible hash algorithm)
+ CERTNAME="TestUser-rsa-pss8"
+
+@@ -2345,20 +2343,18 @@ EOF
+ # Signature: RSA-PSS (with conflicting hash algorithm, default parameters)
+ CERTNAME="TestUser-rsa-pss11"
+
+ CU_ACTION="Generate Cert Request for $CERTNAME"
+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
+ certu -R -d "${PROFILEDIR}" -f "${R_PWFILE}" -z "${R_NOISE_FILE}" --pss -o req 2>&1
+
+ CU_ACTION="Sign ${CERTNAME}'s Request"
+- RETEXPECTED=255
+ certu -C -c "TestCA-rsa-pss-sha1" --pss-sign -Z SHA256 -m "${CERTSERIAL}" -v 60 -d "${P_R_CADIR}" \
+ -i req -o "${CERTNAME}.cert" -f "${R_PWFILE}" "$1" 2>&1
+- RETEXPECTED=0
+ }
+
+ cert_test_orphan_key_delete()
+ {
+ CU_ACTION="Create orphan key in serverdir"
+ certu -G -k ec -q nistp256 -f "${R_PWFILE}" -z ${R_NOISE_FILE} -d ${PROFILEDIR}
+ # Let's get the key ID of the first orphan key.
+ # The output of certutil -K (list keys) isn't well formatted.
diff --git a/nss-3.124-fips-key-import-fix.patch b/nss-3.124-fips-key-import-fix.patch
new file mode 100644
index 0000000..346daa5
--- /dev/null
+++ b/nss-3.124-fips-key-import-fix.patch
@@ -0,0 +1,137 @@
+diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c
+--- a/lib/pk11wrap/pk11skey.c
++++ b/lib/pk11wrap/pk11skey.c
+@@ -436,11 +436,11 @@
+ }
+
+ static PK11SymKey *
+ pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
+ PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate,
+- unsigned int templateCount, SECItem *key, void *wincx)
++ unsigned int templateCount, SECItem *key, PRBool force, void *wincx)
+ {
+ PK11SymKey *symKey;
+ SECStatus rv;
+
+ symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
+@@ -461,16 +461,65 @@
+ symKey->origin = origin;
+
+ /* import the keys */
+ rv = PK11_CreateNewObject(slot, symKey->session, keyTemplate,
+ templateCount, isToken, &symKey->objectID);
+- if (rv != SECSuccess) {
++ if (rv == SECSuccess) {
++ return symKey;
++ }
++ /* we failed to create the key, if force isn't set, we just fail now */
++ if (!force) {
++ PK11_FreeSymKey(symKey);
++ return NULL;
++ }
++ /* if force is set, we are simulating an unwrap, probably from another token, we
++ * are probably here because we are trying to import into a FIPS token. Normally
++ * we would want this to fail, but the application got here because they are using
++ * unwrap, which is the correct way to do this, so try to import the key into
++ * the FIPS token my hand */
++ /* first generate a seed key */
++ PK11SymKey *seedKey = PK11_KeyGen(slot, CKM_SHA256_HMAC, NULL, 256, wincx);
++
++ if (seedKey == NULL) {
+ PK11_FreeSymKey(symKey);
+ return NULL;
+ }
+
+- return symKey;
++ /* now append our key data to the seed key and truncate the seed key */
++ CK_KEY_DERIVATION_STRING_DATA params = { 0 };
++ CK_MECHANISM mechanism = { 0, NULL, 0 };
++ params.pData = key->data;
++ params.ulLen = key->len;
++ mechanism.mechanism = CKM_CONCATENATE_DATA_AND_BASE;
++ mechanism.pParameter = ¶ms;
++ mechanism.ulParameterLen = sizeof(params);
++
++ /* derive removed the CKA_VALUE_LEN before it called us, but now we need
++ * it back. We know there is space in the template because derive leaves
++ * space for the CKA_VALUE_LEN attribute. Any other callers that set force
++ * should also make sure there is space for the CKA_VALUE_LEN */
++ CK_ULONG valueLen; /* Don't define this in the 'if' statement, because it
++ * would go out of scope before we use it */
++ if (!pk11_FindAttrInTemplate(keyTemplate, templateCount, CKA_VALUE_LEN)) {
++ valueLen = (CK_ULONG)key->len;
++ keyTemplate[templateCount].type = CKA_VALUE_LEN;
++ keyTemplate[templateCount].pValue = (void *)&valueLen;
++ keyTemplate[templateCount].ulValueLen = sizeof(valueLen);
++ templateCount++;
++ }
++
++ CK_RV crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
++ seedKey->objectID, keyTemplate,
++ templateCount,
++ &symKey->objectID);
++ PK11_FreeSymKey(seedKey);
++ if (crv == CKR_OK) {
++ return symKey;
++ }
++
++ PK11_FreeSymKey(symKey);
++ return NULL;
+ }
+
+ /*
+ * turn key bits into an appropriate key object
+ */
+@@ -504,11 +553,11 @@
+ templateCount = attrs - keyTemplate;
+ PR_ASSERT(templateCount + 1 <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
+
+ keyType = PK11_GetKeyType(type, key->len);
+ symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE,
+- keyTemplate, templateCount, key, wincx);
++ keyTemplate, templateCount, key, PR_FALSE, wincx);
+ return symKey;
+ }
+ /* Import a PKCS #11 data object and return it as a key. This key is
+ * only useful in a limited number of mechanisms, such as HKDF. */
+ PK11SymKey *
+@@ -583,11 +632,11 @@
+ templateCount = attrs - keyTemplate;
+ PR_ASSERT(templateCount + 1 <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
+
+ keyType = PK11_GetKeyType(type, key->len);
+ symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, isPerm,
+- keyTemplate, templateCount, key, wincx);
++ keyTemplate, templateCount, key, PR_FALSE, wincx);
+ if (symKey && isPerm) {
+ symKey->owner = PR_FALSE;
+ }
+ return symKey;
+ }
+@@ -2667,11 +2716,11 @@
+ outKey.type = siBuffer;
+
+ if (PK11_DoesMechanism(slot, target)) {
+ symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
+ isPerm, keyTemplate,
+- templateCount, &outKey, wincx);
++ templateCount, &outKey, PR_TRUE, wincx);
+ } else {
+ slot = PK11_GetBestSlot(target, wincx);
+ if (slot == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MODULE);
+ PORT_Free(outKey.data);
+@@ -2679,11 +2728,11 @@
+ *crvp = CKR_DEVICE_ERROR;
+ return NULL;
+ }
+ symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
+ isPerm, keyTemplate,
+- templateCount, &outKey, wincx);
++ templateCount, &outKey, PR_TRUE, wincx);
+ PK11_FreeSlot(slot);
+ }
+ PORT_Free(outKey.data);
+
+ if (crvp)
+
diff --git a/nss-3.124-fix-pub-key-import-encapsulate.patch b/nss-3.124-fix-pub-key-import-encapsulate.patch
new file mode 100644
index 0000000..39cccc7
--- /dev/null
+++ b/nss-3.124-fix-pub-key-import-encapsulate.patch
@@ -0,0 +1,217 @@
+# HG changeset patch
+# User Robert Relyea <rrelyea@redhat.com>
+# Date 1781029720 25200
+# Tue Jun 09 11:28:40 2026 -0700
+# Branch NSS_3_124_BRANCH
+# Node ID 1e0565f958c9e9ce4713a19eeee3541286133fb6
+# Parent d9ba1487c7c6821154edd972c88cecba1d458503
+nss-3.124-fix-pub-key-import-encapsulate.patch
+
+diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c
+--- a/lib/pk11wrap/pk11skey.c
++++ b/lib/pk11wrap/pk11skey.c
+@@ -3124,33 +3124,54 @@ SECStatus
+ PK11_Encapsulate(SECKEYPublicKey *pubKey, CK_MECHANISM_TYPE target,
+ PK11AttrFlags attrFlags, CK_FLAGS opFlags,
+ PK11SymKey **outKey, SECItem **outCiphertext)
+ {
+ PORT_Assert(pubKey);
+ PORT_Assert(outKey);
+ PORT_Assert(outCiphertext);
+
+- PK11SlotInfo *slot = pubKey->pkcs11Slot;
+
+ PK11SymKey *sharedSecret = NULL;
+ SECItem *ciphertext = NULL;
+
+ CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
+ unsigned int templateCount;
+
++
+ CK_ATTRIBUTE *attrs;
+ CK_BBOOL cktrue = CK_TRUE;
+ CK_BBOOL ckfalse = CK_FALSE;
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+ CK_MECHANISM_TYPE kemType = pk11_mapKemKeyType(pubKey->keyType);
+ CK_MECHANISM mech = { kemType, NULL, 0 };
+ CK_ULONG ciphertextLen = 0;
+- CK_RV crv;
++ CK_RV crv = CKR_OK;
++
++ PK11SlotInfo *slot = pubKey->pkcs11Slot;
++
++ if (slot == NULL) {
++ CK_MECHANISM_TYPE mechs[] = { kemType, target};
++ CK_ULONG mech_count = PR_ARRAY_SIZE(mechs);
++ slot = PK11_GetBestSlotMultiple(mechs, mech_count, NULL /*sigh*/);
++ } else {
++ /* should we check if the slot can do target and kemtype
++ * here and move the public key if it can't? */
++ slot = PK11_ReferenceSlot(slot);
++ }
++ if (slot == NULL) {
++ goto loser; /* error already set */
++ }
++
++ CK_OBJECT_HANDLE id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE);
++
++ if (id == CK_INVALID_HANDLE) {
++ goto loser; /* error already set */
++ }
+
+ /* set up the target key template */
+ attrs = keyTemplate;
+ PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
+ attrs++;
+
+ PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
+ attrs++;
+@@ -3162,30 +3183,30 @@ PK11_Encapsulate(SECKEYPublicKey *pubKey
+ PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
+
+ *outKey = NULL;
+ *outCiphertext = NULL;
+
+ /* create a struxture for the target key */
+ sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, NULL);
+ if (sharedSecret == NULL) {
+- PORT_SetError(SEC_ERROR_NO_MEMORY);
+- return SECFailure;
++ crv = CKR_HOST_MEMORY;
++ goto loser;
+ }
+ sharedSecret->origin = PK11_OriginDerive;
+
+ /* this path is KEM mechanism agnostic */
+ if (PK11_CheckPKCS11Version(slot, 3, 2, PR_TRUE) >= 0) {
+ pk11_EnterKeyMonitor(sharedSecret);
+ /* get the length the normal PKCS #11 way. This works no matter
+ * what the KEM is and we don't have to try to guess the KEM length
+ * from the key */
+ crv = PK11_GETTAB(slot)->C_EncapsulateKey(sharedSecret->session,
+ &mech,
+- pubKey->pkcs11ID,
++ id,
+ keyTemplate,
+ templateCount,
+ NULL,
+ &ciphertextLen,
+ &sharedSecret->objectID);
+ pk11_ExitKeyMonitor(sharedSecret);
+ if ((crv != CKR_OK) && (crv != CKR_BUFFER_TOO_SMALL) &&
+ (crv != CKR_KEY_SIZE_RANGE)) {
+@@ -3197,17 +3218,17 @@ PK11_Encapsulate(SECKEYPublicKey *pubKey
+ goto loser;
+ }
+ pk11_EnterKeyMonitor(sharedSecret);
+ /* Now do the encapsulate */
+ /* NOTE: the PKCS #11 order of the parameters is different from
+ * the vendor interface */
+ crv = PK11_GETTAB(slot)->C_EncapsulateKey(sharedSecret->session,
+ &mech,
+- pubKey->pkcs11ID,
++ id,
+ keyTemplate,
+ templateCount,
+ ciphertext->data,
+ &ciphertextLen,
+ &sharedSecret->objectID);
+ pk11_ExitKeyMonitor(sharedSecret);
+ if (crv != CKR_OK) {
+ goto loser;
+@@ -3228,21 +3249,21 @@ PK11_Encapsulate(SECKEYPublicKey *pubKey
+ if (crv != CKR_OK) {
+ goto loser;
+ }
+ KEMInterfaceFunctions = (CK_NSS_KEM_FUNCTIONS *)(KEMInterface->pFunctionList);
+
+ /* the old API expected the parameter set as a parameter, the
+ * pkcs11 v3.2 gets it from the key */
+ kemParameterSet = PK11_ReadULongAttribute(slot,
+- pubKey->pkcs11ID,
++ id,
+ CKA_NSS_PARAMETER_SET);
+ if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
+ kemParameterSet = PK11_ReadULongAttribute(slot,
+- pubKey->pkcs11ID,
++ id,
+ CKA_PARAMETER_SET);
+ if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
+ crv = CKR_PUBLIC_KEY_INVALID;
+ goto loser;
+ }
+ }
+ /* The old interface only ever supported KYBER768 and MLKEM768
+ * SOME versions of RHEL has MLKEM1024 support, if we want to
+@@ -3259,39 +3280,48 @@ PK11_Encapsulate(SECKEYPublicKey *pubKey
+ if (ciphertext == NULL) {
+ crv = CKR_HOST_MEMORY;
+ goto loser;
+ }
+
+ pk11_EnterKeyMonitor(sharedSecret);
+ crv = KEMInterfaceFunctions->C_Encapsulate(sharedSecret->session,
+ &mech,
+- pubKey->pkcs11ID,
++ id,
+ keyTemplate,
+ templateCount,
+ &sharedSecret->objectID,
+ ciphertext->data,
+ &ciphertextLen);
+ pk11_ExitKeyMonitor(sharedSecret);
+ if (crv != CKR_OK) {
+ goto loser;
+ }
+
+ PORT_Assert(ciphertextLen == ciphertext->len);
+ }
+
++ PK11_FreeSlot(slot);
++
+ *outKey = sharedSecret;
+ *outCiphertext = ciphertext;
+
+ return SECSuccess;
+
+ loser:
+- PK11_FreeSymKey(sharedSecret);
++ if (slot) {
++ PK11_FreeSlot(slot);
++ }
++ if (sharedSecret) {
++ PK11_FreeSymKey(sharedSecret);
++ }
+ SECITEM_FreeItem(ciphertext, PR_TRUE);
+- PORT_SetError(PK11_MapError(crv));
++ if (crv != CKR_OK) {
++ PORT_SetError(PK11_MapError(crv));
++ }
+ return SECFailure;
+ }
+
+ SECStatus
+ PK11_Decapsulate(SECKEYPrivateKey *privKey, const SECItem *ciphertext,
+ CK_MECHANISM_TYPE target, PK11AttrFlags attrFlags,
+ CK_FLAGS opFlags, PK11SymKey **outKey)
+ {
+@@ -3312,17 +3342,17 @@ PK11_Decapsulate(SECKEYPrivateKey *privK
+ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
+ CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
+ CK_MECHANISM_TYPE kemType = pk11_mapKemKeyType(privKey->keyType);
+ CK_MECHANISM mech = { kemType, NULL, 0 };
+
+ CK_RV crv;
+
+ *outKey = NULL;
+- sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, NULL);
++ sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, privKey->wincx);
+ if (sharedSecret == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ sharedSecret->origin = PK11_OriginUnwrap;
+
+ attrs = keyTemplate;
+ PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
diff --git a/nss.spec b/nss.spec
index 12073bf..670c3de 100644
--- a/nss.spec
+++ b/nss.spec
@@ -152,6 +152,12 @@ Patch42: nss-3.124-annocheck.fix.patch
Patch50: nss-3.110-dissable_test-ssl_policy_pkix_oscp.patch
# Fix Ed25519/Ed448 key storage and display in secutil/softoken
Patch51: nss-3.124-fix-ed-key-storage.patch
+# FIPS-compatible symmetric key import via CKM_CONCATENATE_DATA_AND_BASE
+Patch52: nss-3.124-fips-key-import-fix.patch
+# Fix PK11_Encapsulate to import the public key before use and handle NULL slot
+Patch53: nss-3.124-fix-pub-key-import-encapsulate.patch
+# Allow PSS hash algorithm override instead of failing on mismatch
+Patch54: nss-3.124-allow-hash-override-pss.patch
# ML-DSA support patches that haven't made it to the 3.118.1 release
Patch60: nss-3.118-ml-dsa-leancrypto.patch
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-08-21 11:21 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-21 11:21 [rpms/nss] rawhide: Cherry-pick remaining confirmed patches from RHEL nss-3.124
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox