public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
To: git-commits@fedoraproject.org
Subject: [rpms/nss] rawhide: Cherry-pick remaining confirmed patches from RHEL nss-3.124
Date: Fri, 21 Aug 2026 11:21:17 GMT	[thread overview]
Message-ID: <178731127753.1.3970567500217179951.rpms-nss-ee18cf1cde5c@fedoraproject.org> (raw)

            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(), &params->saltLength, saltLength);
+     ASSERT_EQ(&params->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 = &params;
++    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

                 reply	other threads:[~2026-08-21 11:21 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178731127753.1.3970567500217179951.rpms-nss-ee18cf1cde5c@fedoraproject.org \
    --to=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox