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..a63b4f1 --- /dev/null +++ b/nss-3.124-allow-hash-override-pss.patch @@ -0,0 +1,395 @@ +# HG changeset patch +# User Robert Relyea +# Date 1781635239 25200 +# Tue Jun 16 11:40:39 2026 -0700 +# Branch NSS_3_124_BRANCH +# Node ID 7cc6c51cdb9e8deaf246b87856517e0c1a21ffb3 +# Parent 4b0e3f33a2e76a77e36b435eb3cc1eb06f14249d +nss-3.124-allow-hash-override-pss.patch + +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/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; +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-revert-hmac-pkcs12-fips-default.patch b/nss-3.124-revert-hmac-pkcs12-fips-default.patch new file mode 100644 index 0000000..e165c02 --- /dev/null +++ b/nss-3.124-revert-hmac-pkcs12-fips-default.patch @@ -0,0 +1,36 @@ +# HG changeset patch +# User Robert Relyea +# Date 1781629595 25200 +# Tue Jun 16 10:06:35 2026 -0700 +# Branch NSS_3_124_BRANCH +# Node ID b38b82d220e288befed5176cd2ebb04df5fc3317 +# Parent 07371c5f55e422e28311ef00131462bcf2058882 +nss-3.124-revert-hmac-pkcs12-fips-default.patch + +diff --git a/cmd/pk12util/pk12util.c b/cmd/pk12util/pk12util.c +--- a/cmd/pk12util/pk12util.c ++++ b/cmd/pk12util/pk12util.c +@@ -1159,20 +1159,23 @@ main(int argc, char **argv) + if (certCipher == SEC_OID_UNKNOWN) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString); + pk12uErrno = PK12UERR_INVALIDALGORITHM; + goto done; + } + } + } ++#ifdef nodef ++ /* default to old encodings on rhel-8 and rhel-9 */ + /* in FIPS mode default to encoding with pkcs5v2 for the MAC */ + if (PK11_IsFIPS()) { + hash = SEC_OID_HMAC_SHA256; + } ++#endif + if (pk12util.options[opt_Mac].activated) { + char *hashString = pk12util.options[opt_Mac].arg; + + hash = PKCS12U_MapHashFromString(hashString); + /* We don't support creating Mac-less pkcs 12 files */ + if (hash == SEC_OID_UNKNOWN) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + SECU_PrintError(progName, "Algorithm: \"%s\"", hashString); diff --git a/nss.spec b/nss.spec index 69ed8c3..b6f5499 100644 --- a/nss.spec +++ b/nss.spec @@ -3,7 +3,7 @@ # NOTE: To avoid NVR clashes of nspr* packages: # - reset %%{nspr_release} to 1, when updating %%{nspr_version} # - increment %%{nspr_version}, when updating the NSS part only -%global baserelease 3 +%global baserelease 4 %global nss_release %baserelease # release number between nss and nspr are different. This typically # happens with a new version of nss was release, but nspr was not updated @@ -151,24 +151,26 @@ Patch4: iquote.patch Patch12: nss-signtool-format.patch Patch20: nss-3.101-extend-db-dump-time.patch # connect our shared library to the build root loader flags (needed for -relro) -Patch31: nss-dso-ldflags.patch +Patch21: nss-dso-ldflags.patch # keep RHEL 8 semantics of disabling md4 and md5 even if the env variable is set -Patch32: nss-3.112-disable-md5.patch +Patch22: nss-3.112-disable-md5.patch # dbm is disabled on RHEL9, make the man pages reflect that %if %{with dbm} %else -Patch33: nss-no-dbm-man-page.patch +Patch23: nss-no-dbm-man-page.patch %endif # not upstreamable patch... # WARNING: Need to make this patch work before checking!!! $$$$@@@ -Patch34: nss-3.71-fix-lto-gtests.patch +Patch24: nss-3.71-fix-lto-gtests.patch # disable ech -Patch35: nss-3.124-disable-ech.patch +Patch25: nss-3.124-disable-ech.patch # don't fail if our build machine can't access the internet -Patch36: nss-3.101-skip-ocsp-if-not-connected.patch -# dont upstream, must be after patch36 (sigh) -Patch37: nss-3.124-revert-libpkix-default.patch -Patch38: nss-3.124-no-p12-smime-policy.patch +Patch26: nss-3.101-skip-ocsp-if-not-connected.patch +# dont upstream, must be after patch26 (sigh) +Patch27: nss-3.124-revert-libpkix-default.patch +Patch28: nss-3.124-no-p12-smime-policy.patch +Patch29: nss-3.124-revert-hmac-pkcs12-fips-default.patch +Patch37: nss-3.124-allow-hash-override-pss.patch Patch39: nss-3.79-revert-distrusted-certs.patch Patch40: nss-3.90-dh-test-update.patch @@ -1197,6 +1199,10 @@ update-crypto-policies &> /dev/null || : %changelog +* Tue Jun 16 2026 Bob Relyea - 3.124.0-4 +- fix pkcs12 defaults +- fix pss issues + * Tue Jun 9 2026 Bob Relyea - 3.124.0-3 - drop crmf