From ed6f9c6a95f2b8ff811f37b43f5f099698237e25 Mon Sep 17 00:00:00 2001 From: Robert Relyea Date: Tue, 9 Jun 2026 20:44:50 -0700 Subject: [PATCH] Resolves: RHEL-182530 - rebase fixes - restore rhel-9 dropping of pkcs12 and smime policy - restore mlkem aliases - add mlkem key lengths to the mechanism info - fix crash if you try to encapsulate with an unimported public key - restore distrusted certs to certdata.txt even though we never reference them to make tests happy. --- nss-3.124-add-ml-kem-key-size-mech-info.patch | 60 ++ nss-3.124-el9-fix-ed-key-storage.patch | 821 ++++++++++++++++++ ...9-ml-dsa-test-for-sign-verify-pkcs12.patch | 654 ++++++++++++++ ...3.124-fix-pub-key-import-encapsulate.patch | 217 +++++ nss-3.124-ml-kem-alias-fix.patch | 80 ++ nss-3.124-no-p12-smime-policy.patch | 160 ++++ nss.spec | 22 +- 7 files changed, 2011 insertions(+), 3 deletions(-) create mode 100644 nss-3.124-add-ml-kem-key-size-mech-info.patch create mode 100644 nss-3.124-el9-fix-ed-key-storage.patch create mode 100644 nss-3.124-el9-ml-dsa-test-for-sign-verify-pkcs12.patch create mode 100644 nss-3.124-fix-pub-key-import-encapsulate.patch create mode 100644 nss-3.124-ml-kem-alias-fix.patch create mode 100644 nss-3.124-no-p12-smime-policy.patch diff --git a/nss-3.124-add-ml-kem-key-size-mech-info.patch b/nss-3.124-add-ml-kem-key-size-mech-info.patch new file mode 100644 index 0000000..f80b695 --- /dev/null +++ b/nss-3.124-add-ml-kem-key-size-mech-info.patch @@ -0,0 +1,60 @@ +# HG changeset patch +# User Robert Relyea +# Date 1781030209 25200 +# Tue Jun 09 11:36:49 2026 -0700 +# Branch NSS_3_124_BRANCH +# Node ID 9d51dda84f46517faa8b9cf6abe4311e1ae3e2ac +# Parent 2a7bb3310ced138c06a588fc47b9f98e3f9faa68 +nss-3.124-add-ml-kem-key-size-mech-info.patch + +diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c +--- a/lib/softoken/pkcs11.c ++++ b/lib/softoken/pkcs11.c +@@ -35,16 +35,17 @@ + #include "secoid.h" + #include "sftkdb.h" + #include "utilpars.h" + #include "ec.h" + #include "secasn1.h" + #include "secerr.h" + #include "lgglue.h" + #include "kem.h" ++#include "kyber.h" + + PRBool parentForkedAfterC_Initialize; + + #ifndef NO_FORK_CHECK + + PRBool sftkForkCheckDisabled; + + #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED) +@@ -676,23 +677,23 @@ static const struct mechanismList mechan + { CKM_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }, + { CKM_IKE1_EXTENDED_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE }, + /* -------------------- Kyber Operations ----------------------- */ + #ifndef NSS_DISABLE_KYBER +- { CKM_NSS_KYBER_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE }, +- { CKM_NSS_KYBER, { 0, 0, CKF_KEM }, PR_TRUE }, ++ { CKM_NSS_KYBER_KEY_PAIR_GEN, { KYBER768_PUBLIC_KEY_BYTES, KYBER768_PUBLIC_KEY_BYTES, CKF_GENERATE_KEY_PAIR }, PR_TRUE }, ++ { CKM_NSS_KYBER, { KYBER768_PUBLIC_KEY_BYTES, KYBER768_PUBLIC_KEY_BYTES, CKF_KEM }, PR_TRUE }, + #endif +- { CKM_NSS_ML_KEM_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE }, +- { CKM_NSS_ML_KEM, { 0, 0, CKF_KEM }, PR_TRUE }, +- { CKM_ML_KEM_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE }, +- { CKM_ML_KEM, { 0, 0, CKF_KEM }, PR_TRUE }, ++ { CKM_NSS_ML_KEM_KEY_PAIR_GEN, { KYBER768_PUBLIC_KEY_BYTES, MLKEM1024_PUBLIC_KEY_BYTES, CKF_GENERATE_KEY_PAIR }, PR_TRUE }, ++ { CKM_NSS_ML_KEM, { KYBER768_PUBLIC_KEY_BYTES, MLKEM1024_PUBLIC_KEY_BYTES, CKF_KEM }, PR_TRUE }, ++ { CKM_ML_KEM_KEY_PAIR_GEN, { KYBER768_PUBLIC_KEY_BYTES, MLKEM1024_PUBLIC_KEY_BYTES, CKF_GENERATE_KEY_PAIR }, PR_TRUE }, ++ { CKM_ML_KEM, { KYBER768_PUBLIC_KEY_BYTES, MLKEM1024_PUBLIC_KEY_BYTES, CKF_KEM }, PR_TRUE }, + /* don't advertize ML_DSA support until we have it working in freebl */ + { CKM_ML_DSA_KEY_PAIR_GEN, { ML_DSA_44_PUBLICKEY_LEN, ML_DSA_87_PUBLICKEY_LEN, CKF_GENERATE }, PR_TRUE }, + { CKM_ML_DSA, { ML_DSA_44_PUBLICKEY_LEN, ML_DSA_87_PUBLICKEY_LEN, CKF_SN_VR }, PR_TRUE }, + }; + static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]); + + /* sigh global so fipstokn can read it */ + PRBool nsc_init = PR_FALSE; diff --git a/nss-3.124-el9-fix-ed-key-storage.patch b/nss-3.124-el9-fix-ed-key-storage.patch new file mode 100644 index 0000000..7d83836 --- /dev/null +++ b/nss-3.124-el9-fix-ed-key-storage.patch @@ -0,0 +1,821 @@ +# HG changeset patch +# User Robert Relyea +# Date 1781049891 25200 +# Tue Jun 09 17:04:51 2026 -0700 +# Branch NSS_3_124_BRANCH +# Node ID 06a3884cf6203361c0f25221b132233356e0c415 +# Parent c05574d73be6479439416e07fa31fb3f0ce553b7 +nss-3.124_el9-fix-ed-key-storage.patch + +diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c +--- a/cmd/lib/secutil.c ++++ b/cmd/lib/secutil.c +@@ -1600,16 +1600,24 @@ secu_PrintSubjectPublicKeyInfo(FILE *out + case dsaKey: + SECU_PrintDSAPublicKey(out, pk, "DSA Public Key", level + 1); + break; + + case ecKey: + secu_PrintECPublicKey(out, pk, "EC Public Key", level + 1); + break; + ++ case ecMontKey: ++ secu_PrintECPublicKey(out, pk, "EC Montgomery Public Key", level + 1); ++ break; ++ ++ case edKey: ++ secu_PrintECPublicKey(out, pk, "EC Edwards Public Key", level + 1); ++ break; ++ + case mldsaKey: + SECU_PrintMLDSAPublicKey(out, pk, "ML-DSA Public Key", level + 1); + break; + + case kyberKey: + SECU_PrintMLKEMPublicKey(out, pk, "ML-KEM Public Key", level + 1); + break; + +diff --git a/cmd/pk11importtest/pk11importtest.c b/cmd/pk11importtest/pk11importtest.c +--- a/cmd/pk11importtest/pk11importtest.c ++++ b/cmd/pk11importtest/pk11importtest.c +@@ -188,16 +188,18 @@ static const char *const usageInfo[] = { + " -f pwFile file to fetch the password from", + " -p pwString password", + " -n force pub key to be rebuilt", + " -r skip rsa test", + " -D skip dsa test", + " -h skip dh test", + " -e skip ec test", + " -K skip mk-kem test", ++ " -w skip ed test", ++ " -g skip ec montgomery test", + }; + static int nUsageInfo = sizeof(usageInfo) / sizeof(char *); + + static void + Usage(char *progName, FILE *outFile) + { + int i; + fprintf(outFile, "Usage: %s [ commands ] options\n", progName); +@@ -213,46 +215,52 @@ enum { + opt_PWFile, + opt_PWString, + opt_NoPub, + opt_NoRSA, + opt_NoDSA, + opt_NoDH, + opt_NoEC, + opt_NoMLKEM, ++ opt_NoED, ++ opt_NoECMont, + }; + + static secuCommandFlag options[] = { + { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_KeySize */ 'k', PR_TRUE, 0, PR_FALSE }, + { /* opt_ECCurve */ 'C', PR_TRUE, 0, PR_FALSE }, + { /* opt_PWFile */ 'f', PR_TRUE, 0, PR_FALSE }, + { /* opt_PWString */ 'p', PR_TRUE, 0, PR_FALSE }, + { /* opt_NoPub */ 'n', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoRSA */ 'r', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoDSA */ 'D', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoDH */ 'h', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoEC */ 'e', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoMLKEM */ 'K', PR_FALSE, 0, PR_FALSE }, ++ { /* opt_NoED */ 'w', PR_FALSE, 0, PR_FALSE }, ++ { /* opt_NoECMont */ 'g', PR_FALSE, 0, PR_FALSE }, + }; + + int + main(int argc, char **argv) + { + char *progName; + SECStatus rv; + secuCommand args; + PK11SlotInfo *slot = NULL; + PRBool failed = PR_FALSE; + secuPWData pwArgs = { PW_NONE, 0 }; + PRBool doRSA = PR_TRUE; + PRBool doDSA = PR_TRUE; + PRBool doDH = PR_FALSE; /* NSS currently can't export wrapped DH keys */ + PRBool doEC = PR_TRUE; + PRBool doMLKEM = PR_TRUE; ++ PRBool doED = PR_TRUE; ++ PRBool doECMont = PR_TRUE; + PRBool noPub = PR_FALSE; + PQGParams *pqgParams = NULL; + int keySize; + + args.numCommands = 0; + args.numOptions = sizeof(options) / sizeof(secuCommandFlag); + args.commands = NULL; + args.options = options; +@@ -407,16 +415,61 @@ main(int argc, char **argv) + CKM_ML_KEM_KEY_PAIR_GEN, + noPub, ¶mSet, &pwArgs); + if (rv != SECSuccess) { + fprintf(stderr, "MLKEM Import Failed!\n"); + failed = PR_TRUE; + } + } + ++ if (doED) { ++ SECKEYECParams ecParams; ++ SECOidData *curve = SECOID_FindOIDByTag(SEC_OID_ED25519); ++ ecParams.data = PORT_Alloc(curve->oid.len + 2); ++ if (ecParams.data == NULL) { ++ rv = SECFailure; ++ goto ed_failed; ++ } ++ ecParams.data[0] = SEC_ASN1_OBJECT_ID; ++ ecParams.data[1] = (unsigned char)curve->oid.len; ++ PORT_Memcpy(&ecParams.data[2], curve->oid.data, curve->oid.len); ++ ecParams.len = curve->oid.len + 2; ++ rv = handleEncryptedPrivateImportTest(progName, slot, "EDDSA", ++ CKM_EC_EDWARDS_KEY_PAIR_GEN, ++ noPub, &ecParams, &pwArgs); ++ PORT_Free(ecParams.data); ++ ed_failed: ++ if (rv != SECSuccess) { ++ fprintf(stderr, "EDDSA Import Failed!\n"); ++ failed = PR_TRUE; ++ } ++ } ++ if (doECMont) { ++ SECKEYECParams ecParams; ++ SECOidData *curve = SECOID_FindOIDByTag(SEC_OID_X25519); ++ ecParams.data = PORT_Alloc(curve->oid.len + 2); ++ if (ecParams.data == NULL) { ++ rv = SECFailure; ++ goto ecmont_failed; ++ } ++ ecParams.data[0] = SEC_ASN1_OBJECT_ID; ++ ecParams.data[1] = (unsigned char)curve->oid.len; ++ PORT_Memcpy(&ecParams.data[2], curve->oid.data, curve->oid.len); ++ ecParams.len = curve->oid.len + 2; ++ rv = handleEncryptedPrivateImportTest(progName, slot, "EC Mont", ++ CKM_EC_MONTGOMERY_KEY_PAIR_GEN, ++ noPub, &ecParams, &pwArgs); ++ PORT_Free(ecParams.data); ++ ecmont_failed: ++ if (rv != SECSuccess) { ++ fprintf(stderr, "EC Montgomery Import Failed!\n"); ++ failed = PR_TRUE; ++ } ++ } ++ + if (pqgParams) { + PK11_PQG_DestroyParams(pqgParams); + } + + if (slot) { + PK11_FreeSlot(slot); + } + +diff --git a/lib/softoken/lowkey.c b/lib/softoken/lowkey.c +--- a/lib/softoken/lowkey.c ++++ b/lib/softoken/lowkey.c +@@ -40,16 +40,21 @@ const SEC_ASN1Template nsslowkey_Private + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, + offsetof(NSSLOWKEYPrivateKeyInfo, algorithm), + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, + { SEC_ASN1_OCTET_STRING, + offsetof(NSSLOWKEYPrivateKeyInfo, privateKey) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, + offsetof(NSSLOWKEYPrivateKeyInfo, attributes), + nsslowkey_SetOfAttributeTemplate }, ++ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | ++ SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | ++ SEC_ASN1_XTRN | 1, ++ offsetof(NSSLOWKEYPrivateKeyInfo, publicKey), ++ SEC_ASN1_SUB(SEC_BitStringTemplate) }, + { 0 } + }; + + const SEC_ASN1Template nsslowkey_SubjectPublicKeyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYSubjectPublicKeyInfo) }, + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, + offsetof(NSSLOWKEYSubjectPublicKeyInfo, algorithm), + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, +@@ -396,16 +401,18 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPr + break; + rv = SECITEM_CopyItem(arena, &pubk->u.dh.base, + &privk->u.dh.base); + if (rv == SECSuccess) + return pubk; + } + break; + case NSSLOWKEYECKey: ++ case NSSLOWKEYECEdwardsKey: ++ case NSSLOWKEYECMontgomeryKey: + pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof(NSSLOWKEYPublicKey)); + if (pubk != NULL) { + SECStatus rv; + + pubk->arena = arena; + pubk->keyType = privk->keyType; + +@@ -628,16 +635,18 @@ nsslowkey_CopyPrivateKey(NSSLOWKEYPrivat + if (rv != SECSuccess) + break; + rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.base), + &(privKey->u.dh.base)); + if (rv != SECSuccess) + break; + break; + case NSSLOWKEYECKey: ++ case NSSLOWKEYECEdwardsKey: ++ case NSSLOWKEYECMontgomeryKey: + rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.version), + &(privKey->u.ec.version)); + if (rv != SECSuccess) + break; + rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.publicValue), + &(privKey->u.ec.publicValue)); + if (rv != SECSuccess) + break; +diff --git a/lib/softoken/lowkeyti.h b/lib/softoken/lowkeyti.h +--- a/lib/softoken/lowkeyti.h ++++ b/lib/softoken/lowkeyti.h +@@ -45,16 +45,17 @@ typedef struct NSSLOWKEYAttributeStr NSS + ** A PKCS#8 private key info object + */ + struct NSSLOWKEYPrivateKeyInfoStr { + PLArenaPool *arena; + SECItem version; + SECAlgorithmID algorithm; + SECItem privateKey; + NSSLOWKEYAttribute **attributes; ++ SECItem publicKey; + }; + typedef struct NSSLOWKEYPrivateKeyInfoStr NSSLOWKEYPrivateKeyInfo; + #define NSSLOWKEY_PRIVATE_KEY_INFO_VERSION 0 /* what we *create* */ + + struct NSSLOWKEYSubjectPublicKeyInfoStr { + PLArenaPool *arena; + SECAlgorithmID algorithm; + SECItem subjectPublicKey; +@@ -62,18 +63,20 @@ struct NSSLOWKEYSubjectPublicKeyInfoStr + typedef struct NSSLOWKEYSubjectPublicKeyInfoStr NSSLOWKEYSubjectPublicKeyInfo; + + typedef enum { + NSSLOWKEYNullKey = 0, + NSSLOWKEYRSAKey = 1, + NSSLOWKEYDSAKey = 2, + NSSLOWKEYDHKey = 4, + NSSLOWKEYECKey = 5, +- NSSLOWKEYMLDSAKey = 6, +- NSSLOWKEYMLKEMKey = 7, ++ NSSLOWKEYECEdwardsKey = 6, ++ NSSLOWKEYECMontgomeryKey = 7, ++ NSSLOWKEYMLDSAKey = 8, ++ NSSLOWKEYMLKEMKey = 9, + } NSSLOWKEYType; + + /* ML KEM low structures packages a key with it's parameters. + * The ML KEM freebl didn't define these because all the functions + * take raw keys and param separately */ + typedef struct MLKEMPrivateKeyStr MLKEMPrivateKey; + typedef struct MLKEMPublicKeyStr MLKEMPublicKey; + +diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c +--- a/lib/softoken/pkcs11.c ++++ b/lib/softoken/pkcs11.c +@@ -2220,19 +2220,24 @@ sftk_GetPubKey(SFTKObject *object, CK_KE + crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dh.base, + object, CKA_BASE); + if (crv != CKR_OK) + break; + crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dh.publicValue, + object, CKA_VALUE); + break; + case CKK_EC_EDWARDS: ++ pubKey->keyType = NSSLOWKEYECEdwardsKey; ++ goto ec_continue; + case CKK_EC_MONTGOMERY: ++ pubKey->keyType = NSSLOWKEYECMontgomeryKey; ++ goto ec_continue; + case CKK_EC: + pubKey->keyType = NSSLOWKEYECKey; ++ ec_continue: + crv = sftk_Attribute2SSecItem(arena, + &pubKey->u.ec.ecParams.DEREncoding, + object, CKA_EC_PARAMS); + if (crv != CKR_OK) + break; + + /* Fill out the rest of the ecParams structure + * based on the encoded params +@@ -2448,19 +2453,24 @@ sftk_mkPrivKey(SFTKObject *object, CK_KE + itemTemplateCount++; + SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount, + &privKey->u.dh.privateValue, CKA_VALUE); + itemTemplateCount++; + /* privKey was zero'd so public value is already set to NULL, 0 + * if we don't set it explicitly */ + break; + case CKK_EC_EDWARDS: ++ privKey->keyType = NSSLOWKEYECEdwardsKey; ++ goto ec_continue; + case CKK_EC_MONTGOMERY: ++ privKey->keyType = NSSLOWKEYECMontgomeryKey; ++ goto ec_continue; + case CKK_EC: + privKey->keyType = NSSLOWKEYECKey; ++ ec_continue: + crv = sftk_Attribute2SSecItem(arena, + &privKey->u.ec.ecParams.DEREncoding, + object, CKA_EC_PARAMS); + if (crv != CKR_OK) + break; + + /* Fill out the rest of the ecParams structure + * based on the encoded params +@@ -2511,16 +2521,17 @@ sftk_mkPrivKey(SFTKObject *object, CK_KE + break; + + #ifndef NSS_DISABLE_KYBER + case CKK_NSS_KYBER: + #endif + case CKK_NSS_ML_KEM: + case CKK_ML_KEM: + privKey->keyType = NSSLOWKEYMLKEMKey; ++ + crv = sftk_GetULongAttribute(object, CKA_PARAMETER_SET, + ¶mSet); + if (crv != CKR_OK) { + crv = sftk_GetULongAttribute(object, CKA_NSS_PARAMETER_SET, + ¶mSet); + if (crv != CKR_OK) { + break; + } +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -6462,35 +6462,31 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS + unsigned char seedData[KYBER_KEYPAIR_COIN_BYTES]; + + /* generate the seed here so we can record it with + * the private key */ + seed.data = seedData; + seed.len = sizeof(seedData); + rv = RNG_GenerateGlobalRandomBytes(seed.data, seed.len); + if (rv != SECSuccess) { +- fprintf(stderr, "Generate bytes failed nbytes=%d err=%d\n", +- seed.len, PORT_GetError()); + crv = sftk_MapCryptError(PORT_GetError()); + goto kyber_done; + } + + KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(genParamSet); + if (!sftk_kyber_AllocPrivKeyItem(kyberParams, &privKey)) { + crv = CKR_HOST_MEMORY; + goto kyber_done; + } + if (!sftk_kyber_AllocPubKeyItem(kyberParams, &pubKey)) { + crv = CKR_HOST_MEMORY; + goto kyber_done; + } + rv = Kyber_NewKey(kyberParams, &seed, &privKey, &pubKey); + if (rv != SECSuccess) { +- fprintf(stderr, "Generate Kyber_NewKey failed nbytes=%d err=%d\n", +- seed.len, PORT_GetError()); + crv = sftk_MapCryptError(PORT_GetError()); + goto kyber_done; + } + + crv = sftk_AddAttributeType(publicKey, CKA_VALUE, sftk_item_expand(&pubKey)); + if (crv != CKR_OK) { + goto kyber_done; + } +@@ -6899,16 +6895,17 @@ sftk_PackagePrivateKey(SFTKObject *key, + dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk, + nsslowkey_DSAPrivateKeyExportTemplate); + prepare_low_pqg_params_for_asn1(&lk->u.dsa.params); + param = SEC_ASN1EncodeItem(NULL, NULL, &(lk->u.dsa.params), + nsslowkey_PQGParamsTemplate); + algorithm = SEC_OID_ANSIX9_DSA_SIGNATURE; + break; + case NSSLOWKEYECKey: ++ algorithm = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + prepare_low_ec_priv_key_for_asn1(lk); + /* Public value is encoded as a bit string so adjust length + * to be in bits before ASN encoding and readjust + * immediately after. + * + * Since the SECG specification recommends not including the + * parameters as part of ECPrivateKey, we zero out the curveOID + * length before encoding and restore it later. +@@ -6923,18 +6920,36 @@ sftk_PackagePrivateKey(SFTKObject *key, + + #ifdef EC_DEBUG + fordebug = &pki->privateKey; + SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKey", lk->keyType, + fordebug); + #endif + + param = SECITEM_DupItem(&lk->u.ec.ecParams.DEREncoding); +- +- algorithm = SEC_OID_ANSIX962_EC_PUBLIC_KEY; ++ break; ++ /* X25519, ED25519, X448, and ED448 encode the private key ++ * as just and int. The public key and Curve come from the ++ * generaly key structure */ ++ case NSSLOWKEYECEdwardsKey: ++ algorithm = SEC_OID_ED25519; ++ goto ec_continue; ++ case NSSLOWKEYECMontgomeryKey: ++ algorithm = SEC_OID_X25519; ++ ec_continue: ++ prepare_low_ec_priv_key_for_asn1(lk); ++ /* if we have a public key, copy it to pki public key */ ++ if (lk->u.ec.publicValue.len) { ++ pki->publicKey = lk->u.ec.publicValue; ++ pki->publicKey.len <<= 3; ++ } ++ dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, ++ &lk->u.ec.privateValue, ++ SEC_ASN1_GET(SEC_OctetStringTemplate)); ++ param = NULL; + break; + case NSSLOWKEYMLKEMKey: { + SECItem seed = { siBuffer, NULL, 0 }; + SECItem rawKey = { siBuffer, NULL, 0 }; + dummy = NULL; + + switch (lk->u.mlkem.mlkemParams) { + case params_ml_kem768: +@@ -7255,16 +7270,18 @@ sftk_unwrapPrivateKey(SFTKObject *key, S + SECStatus rv = SECFailure; + const SEC_ASN1Template *keyTemplate, *paramTemplate; + void *paramDest = NULL; + PLArenaPool *arena; + NSSLOWKEYPrivateKey *lpk = NULL; + NSSLOWKEYPrivateKeyInfo *pki = NULL; + CK_RV crv = CKR_KEY_TYPE_INCONSISTENT; + CK_ULONG paramSet = 0; ++ const SECOidData *oidData = NULL; ++ SECOidTag pkiAlg = SEC_OID_UNKNOWN; + + arena = PORT_NewArena(2048); + if (!arena) { + return SECFailure; + } + + pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(arena, + sizeof(NSSLOWKEYPrivateKeyInfo)); +@@ -7280,17 +7297,18 @@ sftk_unwrapPrivateKey(SFTKObject *key, S + + lpk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(arena, + sizeof(NSSLOWKEYPrivateKey)); + if (lpk == NULL) { + goto loser; + } + lpk->arena = arena; + +- switch (SECOID_GetAlgorithmTag(&pki->algorithm)) { ++ pkiAlg = SECOID_GetAlgorithmTag(&pki->algorithm); ++ switch (pkiAlg) { + case SEC_OID_PKCS1_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: + keyTemplate = nsslowkey_RSAPrivateKeyTemplate; + paramTemplate = NULL; + paramDest = NULL; + lpk->keyType = NSSLOWKEYRSAKey; + prepare_low_rsa_priv_key_for_asn1(lpk); + break; +@@ -7306,16 +7324,52 @@ sftk_unwrapPrivateKey(SFTKObject *key, S + case SEC_OID_ANSIX962_EC_PUBLIC_KEY: + keyTemplate = nsslowkey_ECPrivateKeyTemplate; + paramTemplate = NULL; + paramDest = &(lpk->u.ec.ecParams.DEREncoding); + lpk->keyType = NSSLOWKEYECKey; + prepare_low_ec_priv_key_for_asn1(lpk); + prepare_low_ecparams_for_asn1(&lpk->u.ec.ecParams); + break; ++ case SEC_OID_X25519: ++ lpk->keyType = NSSLOWKEYECMontgomeryKey; ++ goto ecx_continue; ++ case SEC_OID_ED25519: ++ lpk->keyType = NSSLOWKEYECEdwardsKey; ++ ecx_continue: ++ /* we decode the whole key here rather than do the normal ++ * later decode step */ ++ keyTemplate = NULL; ++ paramTemplate = NULL; ++ paramDest = NULL; ++ oidData = SECOID_FindOIDByTag(pkiAlg); ++ if (oidData == NULL) { ++ goto loser; ++ } ++ /* CURVE is provided by the tag, not encoded in the parameters ++ * for the x25519, x448, ed25519 and ed448 keys */ ++ if (SEC_ASN1EncodeItem(arena, &(lpk->u.ec.ecParams.DEREncoding), ++ &oidData->oid, ++ SEC_ASN1_GET(SEC_ObjectIDTemplate)) == NULL) { ++ goto loser; ++ } ++ prepare_low_ec_priv_key_for_asn1(lpk); ++ /* private key is a simple octet string, just decode it now */ ++ rv = SEC_QuickDERDecodeItem(arena, &(lpk->u.ec.privateValue), ++ SEC_ASN1_GET(SEC_OctetStringTemplate), ++ &(pki->privateKey)); ++ if (rv != SECSuccess) { ++ goto loser; ++ } ++ if (pki->publicKey.len) { ++ lpk->u.ec.publicValue = pki->publicKey; ++ /* convert length in bits to length in bytes */ ++ lpk->u.ec.publicValue.len >>= 3; ++ } ++ break; + case SEC_OID_ML_KEM_768: + paramSet = CKP_ML_KEM_768; + goto mlkem_next; + case SEC_OID_ML_KEM_1024: + paramSet = CKP_ML_KEM_1024; + mlkem_next: + lpk->keyType = NSSLOWKEYMLKEMKey; + goto pq_next; +@@ -7341,36 +7395,37 @@ sftk_unwrapPrivateKey(SFTKObject *key, S + case SEC_ASN1_OCTET_STRING: + keyTemplate = nsslowkey_PQPrivateKeyTemplate; + break; + case SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE: + keyTemplate = nsslowkey_PQBothSeedAndPrivateKeyTemplate; + break; + default: + keyTemplate = NULL; +- break; ++ PORT_SetError(SEC_ERROR_BAD_KEY); ++ goto loser; + } + + paramTemplate = NULL; + paramDest = NULL; + /* genpq encodes ocect, not integer, so no need to prep it */ + break; + default: + keyTemplate = NULL; + paramTemplate = NULL; + paramDest = NULL; +- break; +- } +- +- if (!keyTemplate) { +- goto loser; ++ PORT_SetError(SEC_ERROR_BAD_KEY); ++ goto loser; + } + + /* decode the private key and any algorithm parameters */ +- rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey); ++ rv = SECSuccess; ++ if (keyTemplate) { ++ rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey); ++ } + + if (lpk->keyType == NSSLOWKEYECKey) { + /* convert length in bits to length in bytes */ + lpk->u.ec.publicValue.len >>= 3; + rv = SECITEM_CopyItem(arena, + &(lpk->u.ec.ecParams.DEREncoding), + &(pki->algorithm.parameters)); + if (rv != SECSuccess) { +@@ -7557,19 +7612,25 @@ sftk_unwrapPrivateKey(SFTKObject *key, S + break; + #ifdef notdef + case NSSLOWKEYDHKey: + template = dhTemplate; + templateCount = sizeof(dhTemplate) / sizeof(CK_ATTRIBUTE); + keyType = CKK_DH; + break; + #endif +- /* what about fortezza??? */ ++ case NSSLOWKEYECEdwardsKey: ++ keyType = CKK_EC_EDWARDS; ++ goto ec_import_continue; ++ case NSSLOWKEYECMontgomeryKey: ++ keyType = CKK_EC_MONTGOMERY; ++ goto ec_import_continue; + case NSSLOWKEYECKey: + keyType = CKK_EC; ++ ec_import_continue: + /* if we weren't passed the CKA_NSS_DB, get it + * from the public key */ + if (!sftk_hasAttribute(key, CKA_NSS_DB)) { + if (lpk->u.ec.publicValue.len == 0) { + crv = CKR_KEY_TYPE_INCONSISTENT; + goto loser; + } + crv = sftk_AddAttributeType(key, CKA_NSS_DB, +diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c +--- a/lib/softoken/pkcs11u.c ++++ b/lib/softoken/pkcs11u.c +@@ -1639,16 +1639,18 @@ stfk_CopyTokenPrivateKey(SFTKObject *des + crv = stfk_CopyTokenAttributes(destObject, src_to, mldsaPrivKeyAttrs, + mldsaPrivKeyAttrsCount); + break; + case CKK_DH: + crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs, + dhPrivKeyAttrsCount); + break; + case CKK_EC: ++ case CKK_EC_EDWARDS: ++ case CKK_EC_MONTGOMERY: + crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs, + ecPrivKeyAttrsCount); + break; + default: + crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types + * of token keys into our database. */ + } + fail: +@@ -1703,16 +1705,18 @@ stfk_CopyTokenPublicKey(SFTKObject *dest + crv = stfk_CopyTokenAttributes(destObject, src_to, mldsaPubKeyAttrs, + mldsaPubKeyAttrsCount); + break; + case CKK_DH: + crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs, + dhPubKeyAttrsCount); + break; + case CKK_EC: ++ case CKK_EC_EDWARDS: ++ case CKK_EC_MONTGOMERY: + crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs, + ecPubKeyAttrsCount); + break; + default: + crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types + * of token keys into our database. */ + } + fail: +diff --git a/lib/util/secoid.c b/lib/util/secoid.c +--- a/lib/util/secoid.c ++++ b/lib/util/secoid.c +@@ -637,20 +637,20 @@ CONST_OID curve25519[] = { 0x2B, 0x06, 0 + Binary encoding: 3005 0603 2B65 70 + + The same algorithm identifiers are used for identifying a public key, + a private key, and a signature (for the two EdDSA related OIDs). + Additional encoding information is provided below for each of these + locations. + */ + +-CONST_OID ed25519PublicKey[] = { 0x2B, 0x65, 0x70 }; +-CONST_OID ed25519Signature[] = { 0x2B, 0x65, 0x70 }; +- + /*https://www.rfc-editor.org/rfc/rfc8410#section-3*/ ++/* 1.3.101.112 */ ++CONST_OID ed25519[] = { 0x2B, 0x65, 0x70 }; ++/* 1.3.101.110 */ + CONST_OID x25519PublicKey[] = { 0x2b, 0x65, 0x6e }; + + /* + * ML-DSA OIDs + * https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration + */ + CONST_OID mlDsa44[] = { DSA2, 17 }; + CONST_OID mlDsa65[] = { DSA2, 18 }; +@@ -1866,21 +1866,24 @@ const static SECOidData oids[SEC_OID_TOT + OD(hmac_sha3_224, SEC_OID_HMAC_SHA3_224, "HMAC SHA3-224", CKM_SHA3_224_HMAC, INVALID_CERT_EXTENSION), + OD(hmac_sha3_256, SEC_OID_HMAC_SHA3_256, "HMAC SHA3-256", CKM_SHA3_256_HMAC, INVALID_CERT_EXTENSION), + OD(hmac_sha3_384, SEC_OID_HMAC_SHA3_384, "HMAC SHA3-384", CKM_SHA3_384_HMAC, INVALID_CERT_EXTENSION), + OD(hmac_sha3_512, SEC_OID_HMAC_SHA3_512, "HMAC SHA3-512", CKM_SHA3_512_HMAC, INVALID_CERT_EXTENSION), + + ODE(SEC_OID_XYBER768D00, + "X25519+Kyber768 key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + +- OD(ed25519Signature, SEC_OID_ED25519_SIGNATURE, "X9.62 EDDSA signature", CKM_EDDSA, +- INVALID_CERT_EXTENSION), ++ /* SEC_OID_ED25519_PUBLIC_KEY and SEC_OID_ED25519_SIGNATURE have the same ++ * values, so we should only have one entry in the table, We can't ++ * shift the values of the other entries, so just leav a dead spot here */ ++ ODE(SEC_OID_RESERVED_OLD_EDSIG, "Reserved", CKM_INVALID_MECHANISM, ++ INVALID_CERT_EXTENSION), + +- OD(ed25519PublicKey, SEC_OID_ED25519_PUBLIC_KEY, +- "X9.62 elliptic edwards curve public key", CKM_EC_EDWARDS_KEY_PAIR_GEN, INVALID_CERT_EXTENSION), ++ OD(ed25519, SEC_OID_ED25519, ++ "X9.62 Elliptic Edwards Curve 25519", CKM_EDDSA, INVALID_CERT_EXTENSION), + + OD(dhSinglePassstdDHsha1kdfscheme, SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME, + "Eliptic Curve Diffie-Hellman Single Pass Standard with SHA1 KDF", CKM_ECDH1_DERIVE, + INVALID_CERT_EXTENSION), + OD(dhSinglePassstdDHsha224kdfscheme, SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME, + "Eliptic Curve Diffie-Hellman Single Pass Standard with SHA224 KDF", CKM_ECDH1_DERIVE, + INVALID_CERT_EXTENSION), + OD(dhSinglePassstdDHsha256kdfscheme, SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME, +diff --git a/lib/util/secoidt.h b/lib/util/secoidt.h +--- a/lib/util/secoidt.h ++++ b/lib/util/secoidt.h +@@ -509,18 +509,18 @@ typedef enum { + + SEC_OID_HMAC_SHA3_224 = 368, + SEC_OID_HMAC_SHA3_256 = 369, + SEC_OID_HMAC_SHA3_384 = 370, + SEC_OID_HMAC_SHA3_512 = 371, + + SEC_OID_XYBER768D00 = 372, + +- SEC_OID_ED25519_SIGNATURE = 373, +- SEC_OID_ED25519_PUBLIC_KEY = 374, ++ SEC_OID_RESERVED_OLD_EDSIG = 373, ++ SEC_OID_ED25519 = 374, + + SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME = 375, + SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME = 376, + SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME = 377, + SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME = 378, + SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME = 379, + SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME = 380, + SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME = 381, +@@ -558,16 +558,20 @@ typedef enum { + /* ML-DSA Public keys and signatures use the same identifier */ + #define SEC_OID_ML_DSA_44_SIGNATURE SEC_OID_ML_DSA_44 + #define SEC_OID_ML_DSA_44_PUBLIC_KEY SEC_OID_ML_DSA_44 + #define SEC_OID_ML_DSA_65_SIGNATURE SEC_OID_ML_DSA_65 + #define SEC_OID_ML_DSA_65_PUBLIC_KEY SEC_OID_ML_DSA_65 + #define SEC_OID_ML_DSA_87_SIGNATURE SEC_OID_ML_DSA_87 + #define SEC_OID_ML_DSA_87_PUBLIC_KEY SEC_OID_ML_DSA_87 + ++/* EDDSA have the same identifiers for public keys and signatures */ ++#define SEC_OID_ED25519_SIGNATURE SEC_OID_ED25519 ++#define SEC_OID_ED25519_PUBLIC_KEY SEC_OID_ED25519 ++ + typedef enum { + INVALID_CERT_EXTENSION = 0, + UNSUPPORTED_CERT_EXTENSION = 1, + SUPPORTED_CERT_EXTENSION = 2 + } SECSupportExtenTag; + + struct SECOidDataStr { + SECItem oid; +diff --git a/tests/tools/tools.sh b/tests/tools/tools.sh +--- a/tests/tools/tools.sh ++++ b/tests/tools/tools.sh +@@ -123,16 +123,17 @@ tools_init() + cp ${QADIR}/tools/PKCS5WithImplicitKDF.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-valid-sha256.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-valid-sha256-sha512.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-valid-sha512.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-invalid-bad-iter.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-invalid-bad-salt.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-invalid-no-length.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/corrupted_cert_bag.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/openssl-ed25519.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-768-seed.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-768-priv.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-768-both.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-1024-seed.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-1024-priv.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-1024-both.p12 ${TOOLSDIR}/data + + +@@ -531,16 +532,27 @@ tools_p12_import_rsa_pss_private_key() + ${BINDIR}/certutil -d ${P_R_COPYDIR} -K -f ${R_PWFILE} | grep '^<[0-9 ]*> *rsaPss' + ret=$? + html_msg $ret 0 "Listing RSA-PSS private key imported from PKCS#12 file" + check_tmpfile + + return $ret + } + ++tools_p12_import_ed25519_private_key() ++{ ++ echo "$SCRIPTNAME: Importing ED25519 private key from PKCS#12 file --------------" ++ ${BINDIR}/pk12util -i ${TOOLSDIR}/data/openssl-ed25519.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -W 'test' 2>&1 ++ ret=$? ++ html_msg $ret 0 "Importing ED25519 private key from PKCS#12 file" ++ check_tmpfile ++ ++ return $ret ++} ++ + tools_p12_ml_kem_import() + { + echo "$SCRIPTNAME: Testing ml-kem compatibility with pkcs12 --------------" + for i in 768 1024 + do + for j in 'seed' 'priv' 'both' + do + echo "${BINDIR}/pk12util -i ${TOOLSDIR}/data/openssl-ml-kem-$i-$j.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -W 'test' 2>&1" +@@ -611,16 +623,17 @@ tools_p12() + tools_p12_export_list_import_all_pkcs12v2pbe_ciphers + else + tools_p12_export_list_import_most_ciphers + fi + tools_p12_export_with_none_ciphers + tools_p12_export_with_invalid_ciphers + tools_p12_import_old_files + tools_p12_import_pbmac1_samples ++ tools_p12_import_ed25519_private_key + tools_p12_ml_kem_import + if using_sql; then + tools_p12_import_rsa_pss_private_key + #tools_p12_policy + fi + } + + ############################## tools_sign ############################## diff --git a/nss-3.124-el9-ml-dsa-test-for-sign-verify-pkcs12.patch b/nss-3.124-el9-ml-dsa-test-for-sign-verify-pkcs12.patch new file mode 100644 index 0000000..4f2bbc4 --- /dev/null +++ b/nss-3.124-el9-ml-dsa-test-for-sign-verify-pkcs12.patch @@ -0,0 +1,654 @@ +# HG changeset patch +# User Robert Relyea +# Date 1781050448 25200 +# Tue Jun 09 17:14:08 2026 -0700 +# Branch NSS_3_124_BRANCH +# Node ID 07371c5f55e422e28311ef00131462bcf2058882 +# Parent d6768ddf181e1f22b2b07b427eb2af4cf78d1d28 +nss-3.124-el9-ml-dsa-test-for-sign-verify-pkcs12.patch + +diff --git a/cmd/certutil/certutil.c b/cmd/certutil/certutil.c +--- a/cmd/certutil/certutil.c ++++ b/cmd/certutil/certutil.c +@@ -1155,18 +1155,20 @@ PrintSyntax() + FPS "\t%s -F -k key-id [-d certdir] [-P dbprefix]\n", + progName); + FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n" + "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName); + FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n" + "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName); + FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n" + "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName); +- FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n", +- progName); ++ FPS "\t%s -G [-h token-name] -k mldsa -q paramset [-f pwfile]\n" ++ "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName); ++ FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|mldsa|all]\n", ++ progName); + FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n"); + FPS "\t%s --upgrade-merge --source-dir upgradeDir --upgrade-id uniqueID\n", + progName); + FPS "\t\t [--upgrade-token-name tokenName] [-d targetDBDir]\n"); + FPS "\t\t [-P targetDBPrefix] [--source-prefix upgradeDBPrefix]\n"); + FPS "\t\t [-f targetPWfile] [-@ upgradePWFile]\n"); + FPS "\t%s --merge --source-dir sourceDBDir [-d targetDBdir]\n", + progName); +@@ -1389,16 +1391,19 @@ luG(enum usage_level ul, const char *com + FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", ""); + FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", ""); + FPS "%-20s c2tnb191v2, c2tnb191v3, \n", ""); + FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", ""); + FPS "%-20s c2pnb272w1, c2pnb304w1, \n", ""); + FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", ""); + FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", ""); + FPS "%-20s sect131r1, sect131r2\n", ""); ++ FPS "%-20s ML-DSA parameter set (mldsa only)\n", ++ " -q paramset"); ++ FPS "%-20s valid values are ml-dsa-44, ml-dsa-65, ml-dsa-87:\n", ""); + FPS "%-20s Key database directory (default is ~/.netscape)\n", + " -d keydir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s\n" + "%-20s PKCS #11 key Attributes.\n", + " --keyAttrFlags attrflags", ""); + FPS "%-20s Comma separated list of key attribute attribute flags,\n", ""); +@@ -1481,16 +1486,17 @@ luK(enum usage_level ul, const char *com + "-K"); + if (ul == usage_selected && !is_my_command) + return; + FPS "%-20s Name of token to search (\"all\" for all tokens)\n", + " -h token-name "); + + FPS "%-20s Key type (\"all\" (default), \"dsa\"," + " \"ec\"," ++ " \"mldsa\"," + " \"rsa\")\n", + " -k key-type"); + FPS "%-20s The nickname of the key or associated certificate\n", + " -n name"); + FPS "%-20s Specify the password file\n", + " -f password-file"); + FPS "%-20s Key database directory (default is ~/.netscape)\n", + " -d keydir"); +@@ -1641,16 +1647,20 @@ luR(enum usage_level ul, const char *com + FPS "%-20s Create a certificate request restricted to RSA-PSS (rsa only)\n", + " --pss"); + FPS "%-20s Name of file containing PQG parameters (dsa only)\n", + " -q pqgfile"); + FPS "%-20s Elliptic curve name (ec only)\n", + " -q curve-name"); + FPS "%-20s See the \"-G\" option for a full list of supported names.\n", + ""); ++ FPS "%-20s ML-DSA parameter set (mldsa only)\n", ++ " -q paramset"); ++ FPS "%-20s See the \"-G\" option for a full list of supported names.\n", ++ ""); + FPS "%-20s Specify the password file\n", + " -f pwfile"); + FPS "%-20s Key database directory (default is ~/.netscape)\n", + " -d keydir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n", + " -p phone"); +@@ -1821,16 +1831,20 @@ luS(enum usage_level ul, const char *com + FPS "%-20s Create a certificate restricted to RSA-PSS (rsa only)\n", + " --pss"); + FPS "%-20s Name of file containing PQG parameters (dsa only)\n", + " -q pqgfile"); + FPS "%-20s Elliptic curve name (ec only)\n", + " -q curve-name"); + FPS "%-20s See the \"-G\" option for a full list of supported names.\n", + ""); ++ FPS "%-20s ML-DSA parameter set (mldsa only)\n", ++ " -q paramset"); ++ FPS "%-20s See the \"-G\" option for a full list of supported names.\n", ++ ""); + FPS "%-20s Self sign\n", + " -x"); + FPS "%-20s Sign the certificate with RSA-PSS (the issuer key must be rsa)\n", + " --pss-sign"); + FPS "%-20s Cert serial number\n", + " -m serial-number"); + FPS "%-20s Time Warp\n", + " -w warp-months"); +@@ -2773,19 +2787,44 @@ certutil_main(int argc, char **argv, PRB + sourceDir = certutil.options[opt_SourceDir].arg; + + if (certutil.options[opt_UpgradeID].activated) + upgradeID = certutil.options[opt_UpgradeID].arg; + + if (certutil.options[opt_UpgradeTokenName].activated) + upgradeTokenName = certutil.options[opt_UpgradeTokenName].arg; + ++ /* must be before opt_KeySize! */ ++ /* -k key type */ ++ if (certutil.options[opt_KeyType].activated) { ++ char *arg = certutil.options[opt_KeyType].arg; ++ if (PL_strcmp(arg, "rsa") == 0) { ++ keytype = rsaKey; ++ } else if (PL_strcmp(arg, "dsa") == 0) { ++ keytype = dsaKey; ++ } else if (PL_strcmp(arg, "ec") == 0) { ++ keytype = ecKey; ++ } else if (PL_strcmp(arg, "mldsa") == 0) { ++ keytype = mldsaKey; ++ } else if (PL_strcmp(arg, "all") == 0) { ++ keytype = nullKey; ++ } else { ++ /* use an existing private/public key pair */ ++ keysource = arg; ++ } ++ } else if (certutil.commands[cmd_ListKeys].activated) { ++ keytype = nullKey; ++ } ++ + if (certutil.options[opt_KeySize].activated) { + keysize = PORT_Atoi(certutil.options[opt_KeySize].arg); +- if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) { ++ /* mldsa limits are much different that rsa and dsa, don't ++ * do the check here */ ++ if ((keytype != mldsaKey) && ++ ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS))) { + PR_fprintf(PR_STDERR, + "%s -g: Keysize must be between %d and %d.\n", + progName, MIN_KEY_BITS, MAX_KEY_BITS); + return 255; + } + if (keytype == ecKey) { + PR_fprintf(PR_STDERR, "%s -g: Not for ec keys.\n", progName); + return 255; +@@ -2806,35 +2845,16 @@ certutil_main(int argc, char **argv, PRB + hashAlgTag = SECU_StringToSignatureAlgTag(arg); + if (hashAlgTag == SEC_OID_UNKNOWN) { + PR_fprintf(PR_STDERR, "%s -Z: %s is not a recognized type.\n", + progName, arg); + return 255; + } + } + +- /* -k key type */ +- if (certutil.options[opt_KeyType].activated) { +- char *arg = certutil.options[opt_KeyType].arg; +- if (PL_strcmp(arg, "rsa") == 0) { +- keytype = rsaKey; +- } else if (PL_strcmp(arg, "dsa") == 0) { +- keytype = dsaKey; +- } else if (PL_strcmp(arg, "ec") == 0) { +- keytype = ecKey; +- } else if (PL_strcmp(arg, "all") == 0) { +- keytype = nullKey; +- } else { +- /* use an existing private/public key pair */ +- keysource = arg; +- } +- } else if (certutil.commands[cmd_ListKeys].activated) { +- keytype = nullKey; +- } +- + if (certutil.options[opt_KeyOpFlagsOn].activated) { + keyOpFlagsOn = GetOpFlags(certutil.options[opt_KeyOpFlagsOn].arg); + } + if (certutil.options[opt_KeyOpFlagsOff].activated) { + keyOpFlagsOff = GetOpFlags(certutil.options[opt_KeyOpFlagsOff].arg); + keyOpFlagsOn &= ~keyOpFlagsOff; /* make off override on */ + } + if (certutil.options[opt_KeyAttrFlags].activated) { +@@ -2867,19 +2887,22 @@ certutil_main(int argc, char **argv, PRB + srcCertPrefix = certutil.options[opt_SourcePrefix].arg; + } else { + Usage(); + } + } + + /* -q PQG file or curve name */ + if (certutil.options[opt_PQGFile].activated) { +- if ((keytype != dsaKey) && (keytype != ecKey)) { ++ if ((keytype != dsaKey) && (keytype != ecKey) && ++ (keytype != mldsaKey)) { + PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys" +- " (-k dsa) or a named curve for EC keys (-k ec)\n)", ++ " (-k dsa)\n" ++ " or a named curve for EC keys (-k ec)\n" ++ " or a parameter set for ML-DSA keys (-k mldsa)\n", + progName); + return 255; + } + } + + /* -s subject name */ + if (certutil.options[opt_Subject].activated) { + subject = CERT_AsciiToName(certutil.options[opt_Subject].arg); +diff --git a/cmd/certutil/keystuff.c b/cmd/certutil/keystuff.c +--- a/cmd/certutil/keystuff.c ++++ b/cmd/certutil/keystuff.c +@@ -512,16 +512,17 @@ CERTUTIL_GeneratePrivateKey(KeyType keyt + int publicExponent, const char *noise, + SECKEYPublicKey **pubkeyp, const char *pqgFile, + PK11AttrFlags attrFlags, CK_FLAGS opFlagsOn, + CK_FLAGS opFlagsOff, secuPWData *pwdata) + { + CK_MECHANISM_TYPE mechanism; + PK11RSAGenParams rsaparams; + SECKEYPQGParams *dsaparams = NULL; ++ CK_ULONG paramSet; + void *params; + SECKEYPrivateKey *privKey = NULL; + + if (slot == NULL) + return NULL; + + if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess) + return NULL; +@@ -564,16 +565,60 @@ CERTUTIL_GeneratePrivateKey(KeyType keyt + } + break; + case ecKey: + mechanism = CKM_EC_KEY_PAIR_GEN; + /* For EC keys, PQGFile determines EC parameters */ + if ((params = (void *)getECParams(pqgFile)) == NULL) + return NULL; + break; ++ case mldsaKey: ++ mechanism = CKM_ML_DSA_KEY_PAIR_GEN; ++ /* set paramset */ ++ paramSet = 0; ++ if (pqgFile) { ++ if (PORT_Strcasecmp(pqgFile, "ML-DSA-44") == 0) { ++ paramSet = CKP_ML_DSA_44; ++ } else if (PORT_Strcasecmp(pqgFile, "ML-DSA-65") == 0) { ++ paramSet = CKP_ML_DSA_65; ++ } else if (PORT_Strcasecmp(pqgFile, "ML-DSA-87") == 0) { ++ paramSet = CKP_ML_DSA_87; ++ } else { ++ /* if we set pqgfile, it had better be right, don't ++ * fall back to key size */ ++ return NULL; ++ } ++ } else ++ switch (size) { ++ /* optionally use the size, either the actual size in bytes ++ * or the short hand ('44', '65', '87') */ ++ case 44: ++ case 2560: ++ paramSet = CKP_ML_DSA_44; ++ break; ++ case 65: ++ case 4032: ++ paramSet = CKP_ML_DSA_65; ++ break; ++ case 87: ++ case 4896: ++ paramSet = CKP_ML_DSA_87; ++ break; ++ default: ++ /* force a size to be specified somewhere */ ++ return NULL; ++ } ++ /* paranoia, shouldn't be able to happen logically. Code ++ * scanners will scream, but I like belt and suspenders */ ++ if (paramSet == 0) { ++ return NULL; ++ } ++ params = ¶mSet; ++ break; ++ + default: + return NULL; + } + + fprintf(stderr, "\n\n"); + fprintf(stderr, "Generating key. This may take a few moments...\n\n"); + + privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism, params, pubkeyp, +diff --git a/cmd/pk11importtest/pk11importtest.c b/cmd/pk11importtest/pk11importtest.c +--- a/cmd/pk11importtest/pk11importtest.c ++++ b/cmd/pk11importtest/pk11importtest.c +@@ -214,32 +214,34 @@ enum { + opt_ECCurve, + opt_PWFile, + opt_PWString, + opt_NoPub, + opt_NoRSA, + opt_NoDSA, + opt_NoDH, + opt_NoEC, ++ opt_NoMLDSA, + opt_NoMLKEM, + opt_NoED, + opt_NoECMont, + }; + + static secuCommandFlag options[] = { + { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_KeySize */ 'k', PR_TRUE, 0, PR_FALSE }, + { /* opt_ECCurve */ 'C', PR_TRUE, 0, PR_FALSE }, + { /* opt_PWFile */ 'f', PR_TRUE, 0, PR_FALSE }, + { /* opt_PWString */ 'p', PR_TRUE, 0, PR_FALSE }, + { /* opt_NoPub */ 'n', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoRSA */ 'r', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoDSA */ 'D', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoDH */ 'h', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoEC */ 'e', PR_FALSE, 0, PR_FALSE }, ++ { /* opt_NoMLDSA */ 'm', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoMLKEM */ 'K', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoED */ 'w', PR_FALSE, 0, PR_FALSE }, + { /* opt_NoECMont */ 'g', PR_FALSE, 0, PR_FALSE }, + }; + + int + main(int argc, char **argv) + { +@@ -248,16 +250,18 @@ main(int argc, char **argv) + secuCommand args; + PK11SlotInfo *slot = NULL; + PRBool failed = PR_FALSE; + secuPWData pwArgs = { PW_NONE, 0 }; + PRBool doRSA = PR_TRUE; + PRBool doDSA = PR_TRUE; + PRBool doDH = PR_FALSE; /* NSS currently can't export wrapped DH keys */ + PRBool doEC = PR_TRUE; ++ PRBool doMLDSA = PR_FALSE; ++ CK_ML_DSA_PARAMETER_SET_TYPE mldsaParamSet = CKP_ML_DSA_44; + PRBool doMLKEM = PR_TRUE; + PRBool doED = PR_TRUE; + PRBool doECMont = PR_TRUE; + PRBool noPub = PR_FALSE; + PQGParams *pqgParams = NULL; + int keySize; + + args.numCommands = 0; +@@ -308,16 +312,19 @@ main(int argc, char **argv) + doDSA = PR_FALSE; + } + if (args.options[opt_NoDH].activated) { + doDH = PR_FALSE; + } + if (args.options[opt_NoEC].activated) { + doEC = PR_FALSE; + } ++ if (args.options[opt_NoMLDSA].activated) { ++ doMLDSA = PR_FALSE; ++ } + if (args.options[opt_NoMLKEM].activated) { + doMLKEM = PR_FALSE; + } + + slot = PK11_GetInternalKeySlot(); + if (slot == NULL) { + SECU_PrintError(progName, "Couldn't find the internal key slot\n"); + return 255; +@@ -403,16 +410,26 @@ main(int argc, char **argv) + PORT_Free(ecParams.data); + ec_failed: + if (rv != SECSuccess) { + fprintf(stderr, "ECC Import Failed!\n"); + failed = PR_TRUE; + } + } + ++ if (doMLDSA) { ++ rv = handleEncryptedPrivateImportTest(progName, slot, "MLDSA", ++ CKM_ML_DSA_KEY_PAIR_GEN, ++ noPub, &mldsaParamSet, &pwArgs); ++ if (rv != SECSuccess) { ++ fprintf(stderr, "MLDSA Import Failed!\n"); ++ failed = PR_TRUE; ++ } ++ } ++ + if (doMLKEM) { + CK_ML_KEM_PARAMETER_SET_TYPE paramSet = CKP_ML_KEM_768; + + rv = handleEncryptedPrivateImportTest(progName, slot, "MLKEM", + CKM_ML_KEM_KEY_PAIR_GEN, + noPub, ¶mSet, &pwArgs); + if (rv != SECSuccess) { + fprintf(stderr, "MLKEM Import Failed!\n"); +diff --git a/tests/cert/cert.sh b/tests/cert/cert.sh +--- a/tests/cert/cert.sh ++++ b/tests/cert/cert.sh +@@ -101,16 +101,19 @@ cert_init() + fi + + cert_add_algorithm "RSA" "" "" "false" 0 + if [ -z ${NSS_DISABLE_DSA} ]; then + cert_add_algorithm "DSA" "-dsa" "-k dsa" "true" 20000 + fi + # NOTE: curve is added later, so the full command would be '-k ec -q curve' + cert_add_algorithm "ECC" "-ec" "-k ec -q" "true" 10000 ++ cert_add_algorithm "ML-DSA-44" "-ml-dsa-44" "-k mldsa -q ml-dsa-44" "false" 30000 ++ cert_add_algorithm "ML-DSA-65" "-ml-dsa-65" "-k mldsa -q ml-dsa-65" "false" 40000 ++ cert_add_algorithm "ML-DSA-87" "-ml-dsa-87" "-k mldsa -q ml-dsa-87" "false" 50000 + # currently rsa-pss is only enabled for a subset of tests + # this will enable a full suite of RSA-PSS certs, and we would + # then remove the explicit ones + # ulike the other tests, we would need to change ssl tests as this + # will rename some of the RSA-PSS certificates. + #cert_add_algorithm "RSA-PSS" "-rsa-pss" "-k rsa -pss -Z sha256" "true" + #cert_add_algorithm "RSA-PSS-SHA1" "-rsa-pss-sha1" "-k rsa -pss -Z sha1" "true" + +@@ -519,16 +522,25 @@ cert_CA() + cert_dsa_CA "${CUR_CADIR}" "${NICKNAME}" "${SIGNER}" "${TRUSTARG}" "${DOMAIN}" "${CERTSERIAL}" + ;; + ECC) + cert_ec_CA "${CUR_CADIR}" "${NICKNAME}" "${SIGNER}" "${TRUSTARG}" "${DOMAIN}" "${CERTSERIAL}" "${ALG}" + ;; + RSA-PSS) + cert_rsa_pss_CA "${CUR_CADIR}" "${NICKNAME}" "${SIGNER}" "${TRUSTARG}" "${DOMAIN}" "${CERTSERIAL}" "${ALG}" + ;; ++ ML-DSA-44) ++ cert_ml_dsa_CA ml-dsa-44 "${CUR_CADIR}" "${NICKNAME}" "${SIGNER}" "${TRUSTARG}" "${DOMAIN}" "${CERTSERIAL}" ++ ;; ++ ML-DSA-65) ++ cert_ml_dsa_CA ml-dsa-65 "${CUR_CADIR}" "${NICKNAME}" "${SIGNER}" "${TRUSTARG}" "${DOMAIN}" "${CERTSERIAL}" ++ ;; ++ ML-DSA-87) ++ cert_ml_dsa_CA ml-dsa-65 "${CUR_CADIR}" "${NICKNAME}" "${SIGNER}" "${TRUSTARG}" "${DOMAIN}" "${CERTSERIAL}" ++ ;; + *) + Exit 9 "Fatal - unknown key type ${KEY_TYPE}, failed to create CA cert" + ;; + esac + } + + + +@@ -672,19 +684,78 @@ CERTSCRIPT + CU_ACTION="Exporting DSA Root Cert" + certu -L -n $NICKNAME -r -d ${LPROFILE} -o root-dsa.cert + if [ "$RET" -ne 0 ]; then + Exit 7 "Fatal - failed to export dsa root cert" + fi + cp root-dsa.cert ${NICKNAME}.ca.cert + } + +++################################ cert_ml_dsa_CA ############################# ++# local shell function to build the Temp. Certificate Authority (CA) ++# used for testing purposes, creating a CA Certificate and a root cert ++# This is the ML-DSA version of cert_CA. ++########################################################################## ++cert_ml_dsa_CA() ++{ ++ PARAM_SET=$1 ++ CUR_CADIR=$2 ++ NICKNAME=$3 ++ SIGNER=$4 ++ TRUSTARG=$5 ++ DOMAIN=$6 ++ CERTSERIAL=$7 + ++ echo "$SCRIPTNAME: Creating a ML-DSA ($PARAM_SET) CA Certificate $NICKNAME ==========================" ++ ++ if [ ! -d "${CUR_CADIR}" ]; then ++ mkdir -p "${CUR_CADIR}" ++ fi ++ cd ${CUR_CADIR} ++ pwd ++ ++ LPROFILE=. ++ if [ -n "${MULTIACCESS_DBM}" ]; then ++ LPROFILE="multiaccess:${DOMAIN}" ++ fi + ++ ################# Creating a ML-DSA CA Cert ############################### ++ # ++ CU_ACTION="Creating ML-DSA ($PARAM_SET) CA Cert $NICKNAME " ++ CU_SUBJECT=$ALL_CU_SUBJECT ++ certu -S -n $NICKNAME -k mldsa -q $PARAM_SET -t $TRUSTARG -v 600 $SIGNER \ ++ -d ${LPROFILE} -1 -2 -5 -f ${R_PWFILE} -z ${R_NOISE_FILE} \ ++ -m $CERTSERIAL 2>&1 <&1 + + CU_ACTION="Loading root cert module to ${CERTNAME}'s Cert DB (ext.)" + modu -add "RootCerts" -libfile "${ROOTCERTSFILE}" -dbdir "${PROFILEDIR}" 2>&1 + +diff --git a/tests/tools/tools.sh b/tests/tools/tools.sh +--- a/tests/tools/tools.sh ++++ b/tests/tools/tools.sh +@@ -124,24 +124,32 @@ tools_init() + cp ${QADIR}/tools/pbmac1-valid-sha256.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-valid-sha256-sha512.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-valid-sha512.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-invalid-bad-iter.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-invalid-bad-salt.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/pbmac1-invalid-no-length.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/corrupted_cert_bag.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ed25519.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/ietf-ml-dsa-44-both.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/ietf-ml-dsa-44-key.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/ietf-ml-dsa-65-both.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/ietf-ml-dsa-65-key.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/ietf-ml-dsa-87-both.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/ietf-ml-dsa-87-key.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/openssl-ml-dsa-44.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/openssl-ml-dsa-65.p12 ${TOOLSDIR}/data ++ cp ${QADIR}/tools/openssl-ml-dsa-87.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-768-seed.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-768-priv.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-768-both.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-1024-seed.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-1024-priv.p12 ${TOOLSDIR}/data + cp ${QADIR}/tools/openssl-ml-kem-1024-both.p12 ${TOOLSDIR}/data + +- + cd ${TOOLSDIR} + } + + ########################## list_p12_file ############################### + # List the key and cert in the specified p12 file + ######################################################################## + list_p12_file() + { +@@ -543,16 +551,43 @@ tools_p12_import_ed25519_private_key() + ${BINDIR}/pk12util -i ${TOOLSDIR}/data/openssl-ed25519.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -W 'test' 2>&1 + ret=$? + html_msg $ret 0 "Importing ED25519 private key from PKCS#12 file" + check_tmpfile + + return $ret + } + ++tools_p12_ml_dsa_import() ++{ ++ echo "$SCRIPTNAME: Testing ml-dsa compatibility with pkcs12 --------------" ++ for i in 44 65 87 ++ do ++ echo "${BINDIR}/pk12util -i ${TOOLSDIR}/data/openssl-ml-dsa-$i.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -W 'test' 2>&1" ++ ${BINDIR}/pk12util -i ${TOOLSDIR}/data/openssl-ml-dsa-$i.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -W 'test' 2>&1 ++ ret=$? ++ html_msg $ret 0 "Importing openssl encoded ml-dsa-$i private key from PKCS#12 file" ++ check_tmpfile ++ for j in 'key' 'both' ++ do ++ echo "${BINDIR}/pk12util -i ${TOOLSDIR}/data/ietf-ml-dsa-$i-$j.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -W 'test' 2>&1" ++ ${BINDIR}/pk12util -i ${TOOLSDIR}/data/ietf-ml-dsa-$i-$j.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -W 'test' 2>&1 ++ ret=$? ++ html_msg $ret 0 "Importing openssl encoded ml-dsa-$i private key from PKCS#12 file" ++ check_tmpfile ++ html_msg $ret 0 "Importing ietf sample ml-dsa-$i-$j private key from PKCS#12 file" ++ ++ # each cert has the same issuer/sn, so we can't hold more than one in ++ # the data base ++ echo "${BINDIR}/certutil -F -n \"ietf ml-dsa-$i-$j sample\" -d ${P_R_COPYDIR} -f ${R_PWFILE}" ++ ${BINDIR}/certutil -F -n "ietf ml-dsa-$i-$j sample" -d ${P_R_COPYDIR} -f ${R_PWFILE} ++ done ++ done ++} ++ + tools_p12_ml_kem_import() + { + echo "$SCRIPTNAME: Testing ml-kem compatibility with pkcs12 --------------" + for i in 768 1024 + do + for j in 'seed' 'priv' 'both' + do + echo "${BINDIR}/pk12util -i ${TOOLSDIR}/data/openssl-ml-kem-$i-$j.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -W 'test' 2>&1" +@@ -624,16 +659,17 @@ tools_p12() + else + tools_p12_export_list_import_most_ciphers + fi + tools_p12_export_with_none_ciphers + tools_p12_export_with_invalid_ciphers + tools_p12_import_old_files + tools_p12_import_pbmac1_samples + tools_p12_import_ed25519_private_key ++ tools_p12_ml_dsa_import + tools_p12_ml_kem_import + if using_sql; then + tools_p12_import_rsa_pss_private_key + #tools_p12_policy + fi + } + + ############################## tools_sign ############################## 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 +# 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-3.124-ml-kem-alias-fix.patch b/nss-3.124-ml-kem-alias-fix.patch new file mode 100644 index 0000000..3b1e1ca --- /dev/null +++ b/nss-3.124-ml-kem-alias-fix.patch @@ -0,0 +1,80 @@ +# HG changeset patch +# User Robert Relyea +# Date 1780962091 25200 +# Mon Jun 08 16:41:31 2026 -0700 +# Branch NSS_3_124_BRANCH +# Node ID 7748a8ddfa510458e76ff41e840f78f5af55795a +# Parent 5f6c91f6171020eea4ce9eb5bc353370d30c8df0 +nss-3.124-ml-kem-alias-fix.patch + +diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c +--- a/cmd/lib/secutil.c ++++ b/cmd/lib/secutil.c +@@ -4303,16 +4303,18 @@ static const struct SSLNamedGroupString + #ifndef NSS_DISABLE_KYBER + { NAME_AND_LEN("xyber76800"), ssl_grp_kem_xyber768d00 }, + #endif + { NAME_AND_LEN("x25519mlkem768"), ssl_grp_kem_mlkem768x25519 }, + { NAME_AND_LEN("secp256r1mlkem768"), ssl_grp_kem_secp256r1mlkem768 }, + { NAME_AND_LEN("secp384r1mlkem1024"), ssl_grp_kem_secp384r1mlkem1024 }, + // keep for compatibility + { NAME_AND_LEN("mlkem768x25519"), ssl_grp_kem_mlkem768x25519 }, ++ { NAME_AND_LEN("mlkem768secp256r1"), ssl_grp_kem_secp256r1mlkem768 }, ++ { NAME_AND_LEN("mlkem1024secp384r1"), ssl_grp_kem_secp384r1mlkem1024 }, + }; + + static const size_t sslNamedGroupStringLen = PR_ARRAY_SIZE(sslNamedGroupStringArray); + + static SSLNamedGroup + groupNameToNamedGroup(char *name) + { + int len = PL_strlen(name); +diff --git a/lib/pk11wrap/pk11pars.c b/lib/pk11wrap/pk11pars.c +--- a/lib/pk11wrap/pk11pars.c ++++ b/lib/pk11wrap/pk11pars.c +@@ -255,16 +255,20 @@ static const oidValDef curveOptList[] = + { CIPHER_NAME("X25519MLKEM768"), SEC_OID_MLKEM768X25519, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("SECP384R1MLKEM1024"), SEC_OID_SECP384R1MLKEM1024, + NSS_USE_ALG_IN_SSL_KX }, + { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519, + NSS_USE_ALG_IN_SSL_KX }, ++ { CIPHER_NAME("MLKEM768SECP256R1"), SEC_OID_SECP256R1MLKEM768, ++ NSS_USE_ALG_IN_SSL_KX }, ++ { CIPHER_NAME("MLKEM1024SECP384R1"), SEC_OID_SECP384R1MLKEM1024, ++ NSS_USE_ALG_IN_SSL_KX }, + /* ANSI X9.62 named elliptic curves (characteristic two field) */ + { CIPHER_NAME("C2PNB163V1"), SEC_OID_ANSIX962_EC_C2PNB163V1, + NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, + { CIPHER_NAME("C2PNB163V2"), SEC_OID_ANSIX962_EC_C2PNB163V2, + NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, + { CIPHER_NAME("C2PNB163V3"), SEC_OID_ANSIX962_EC_C2PNB163V3, + NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE }, + { CIPHER_NAME("C2PNB176V1"), SEC_OID_ANSIX962_EC_C2PNB176V1, +@@ -467,21 +471,21 @@ static const oidValDef signOptList[] = { + NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE }, + { CIPHER_NAME("RSA-PSS"), SEC_OID_PKCS1_RSA_PSS_SIGNATURE, + NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE }, + { CIPHER_NAME("ECDSA"), SEC_OID_ANSIX962_EC_PUBLIC_KEY, + NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE }, + { CIPHER_NAME("ED25519"), SEC_OID_ED25519_PUBLIC_KEY, + NSS_USE_ALG_IN_SIGNATURE }, + { CIPHER_NAME("ML-DSA-44"), SEC_OID_ML_DSA_44, +- NSS_USE_ALG_IN_SIGNATURE }, ++ NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE }, + { CIPHER_NAME("ML-DSA-65"), SEC_OID_ML_DSA_65, +- NSS_USE_ALG_IN_SIGNATURE }, ++ NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE }, + { CIPHER_NAME("ML-DSA-87"), SEC_OID_ML_DSA_87, +- NSS_USE_ALG_IN_SIGNATURE }, ++ NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE }, + }; + + typedef struct { + const oidValDef *list; + PRUint32 entries; + const char *description; + PRBool allowEmpty; + } algListsDef; diff --git a/nss-3.124-no-p12-smime-policy.patch b/nss-3.124-no-p12-smime-policy.patch new file mode 100644 index 0000000..d050b02 --- /dev/null +++ b/nss-3.124-no-p12-smime-policy.patch @@ -0,0 +1,160 @@ +# HG changeset patch +# User Robert Relyea +# Date 1781048663 25200 +# Tue Jun 09 16:44:23 2026 -0700 +# Branch NSS_3_124_BRANCH +# Node ID f11e37ce2019be68e879875d774c770cf0a4c94a +# Parent a1ec20318f4fa9feeb4be2bc7339d573b4d78e27 +nss-3.124-no-p12-smime-policy.patch + +diff --git a/lib/pkcs12/p12plcy.c b/lib/pkcs12/p12plcy.c +--- a/lib/pkcs12/p12plcy.c ++++ b/lib/pkcs12/p12plcy.c +@@ -32,27 +32,31 @@ static pkcs12SuiteMap pkcs12SuiteMaps[] + { SEC_OID_UNKNOWN, 0, PKCS12_NULL, PR_FALSE, PR_FALSE }, + { SEC_OID_UNKNOWN, 0, 0L, PR_FALSE, PR_FALSE } + }; + + /* determine if algid is an algorithm which is allowed */ + static PRBool + sec_PKCS12Allowed(SECOidTag alg, PRUint32 needed) + { ++#ifdef notdef + PRUint32 policy; + SECStatus rv; + + rv = NSS_GetAlgorithmPolicy(alg, &policy); + if (rv != SECSuccess) { + return PR_FALSE; + } + if ((policy & needed) == needed) { + return PR_TRUE; + } + return PR_FALSE; ++#else ++ return PR_TRUE; ++#endif + } + + PRBool + SEC_PKCS12CipherAllowed(SECOidTag pbeAlg, SECOidTag hmacAlg) + { + SECOidTag cipherAlg = SEC_PKCS5GetCryptoFromAlgTag(pbeAlg); + SECOidTag hashAlg = SEC_PKCS5GetHashFromAlgTag(pbeAlg); + if (cipherAlg == SEC_OID_UNKNOWN) { +diff --git a/lib/smime/smimeutil.c b/lib/smime/smimeutil.c +--- a/lib/smime/smimeutil.c ++++ b/lib/smime/smimeutil.c +@@ -197,16 +197,17 @@ smime_get_policy_tag_from_key_length(SEC + return SEC_OID_UNKNOWN; + } + return algtag; + } + + PRBool + smime_allowed_by_policy(SECOidTag algtag, PRUint32 neededPolicy) + { ++#ifdef notdef + PRUint32 policyFlags; + + /* some S/MIME algs map to the same underlying KEA mechanism, + * collaps them here */ + if ((neededPolicy & (NSS_USE_ALG_IN_SMIME_KX | NSS_USE_ALG_IN_SMIME_KX_LEGACY)) != 0) { + CK_MECHANISM_TYPE mechType = PK11_AlgtagToMechanism(algtag); + switch (mechType) { + case CKM_ECDH1_DERIVE: +@@ -216,16 +217,17 @@ smime_allowed_by_policy(SECOidTag algtag + } + } + + if ((NSS_GetAlgorithmPolicy(algtag, &policyFlags) == SECFailure) || + ((policyFlags & neededPolicy) != neededPolicy)) { + PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); + return PR_FALSE; + } ++#endif + return PR_TRUE; + } + + /* + * We'll need this for the fake policy oids for RC2, but the + * rest of these should be moved to pk11wrap for generic + * algtag to key size values. We already need this for + * sec_pkcs5v2_key_length_by oid. +@@ -480,28 +482,34 @@ smime_init_once(void *arg) + return PR_FAILURE; + } + algorithm_list_lock = PR_NewLock(); + if (algorithm_list_lock == NULL) { + *error = PORT_GetError(); + return PR_FAILURE; + } + ++#ifdef notdef + /* At initialization time, we need to set up the defaults. We first + * look to see if the system or application has set up certain algorithms + * by policy. If they have set up values by policy we'll only allow those + * algorithms. We'll then look to see if any algorithms are enabled by + * the application. */ + rv = NSS_GetAlgorithmPolicyAll(NSS_USE_ALG_IN_SMIME_LEGACY, + NSS_USE_ALG_IN_SMIME_LEGACY, + &tags, &tagCount); + if (tags) { + PORT_Free(tags); + tags = NULL; + } ++#else ++ /* just initialize the old maps */ ++ rv = SECSuccess; ++ tagCount = 0; ++#endif + if ((rv != SECSuccess) || (tagCount == 0)) { + /* No algorithms have been enabled by policy (either by the system + * or by the application, we then will use the traditional default + * algorithms from the policy map */ + for (i = smime_legacy_map_count - 1; i >= 0; i--) { + SECOidTag policytag = smime_legacy_map[i].policytag; + /* this enables the algorithm by policy. We need this or + * the policy code will reject attempts to use it */ +diff --git a/tests/smime/smime.sh b/tests/smime/smime.sh +--- a/tests/smime/smime.sh ++++ b/tests/smime/smime.sh +@@ -898,13 +898,13 @@ smime_cleanup() + } + + ################## main ################################################# + + smime_init + smime_main + smime_data_tb + smime_p7 +-if using_sql ; then +- smime_policy +-fi ++#if using_sql ; then ++# smime_policy ++#fi + smime_cleanup + +diff --git a/tests/tools/tools.sh b/tests/tools/tools.sh +--- a/tests/tools/tools.sh ++++ b/tests/tools/tools.sh +@@ -614,17 +614,17 @@ tools_p12() + fi + tools_p12_export_with_none_ciphers + tools_p12_export_with_invalid_ciphers + tools_p12_import_old_files + tools_p12_import_pbmac1_samples + tools_p12_ml_kem_import + if using_sql; then + tools_p12_import_rsa_pss_private_key +- tools_p12_policy ++#tools_p12_policy + fi + } + + ############################## tools_sign ############################## + # local shell function pk12util uses a hardcoded tmp file, if this exists + # and is owned by another user we don't get reasonable errormessages + ######################################################################## + check_tmpfile() diff --git a/nss.spec b/nss.spec index 659175c..4706d8c 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 1 +%global baserelease 2 %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 @@ -170,6 +170,7 @@ Patch36: nss-3.101-skip-ocsp-if-not-connected.patch Patch37: nss-3.124-revert-libpkix-default.patch # build crmf for now Patch38: nss-3.124-enable-crmf.patch +Patch39: nss-3.124-no-p12-smime-policy.patch Patch40: nss-3.90-dh-test-update.patch Patch41: nss-3.124-ppc_no_init.patch @@ -179,7 +180,7 @@ Patch43: nss-3.124-tools-test-fix.patch #in process upstream Patch50: nss-3.124-fips-key-import-fix.patch -Patch51: nss-3.124-fix-ed-key-storage.patch +Patch51: nss-3.124-el9-fix-ed-key-storage.patch Patch52: nss-3.124-indicators-prf.patch Patch53: nss-3.124-annocheck.fix.patch Patch54: nss-3.124-disable-kyber-test.patch @@ -187,11 +188,16 @@ Patch54: nss-3.124-disable-kyber-test.patch Patch60: nss-3.118-ml-dsa-leancrypto.patch Patch61: nss-3.118-ml-dsa-tls.patch Patch62: nss-3.124-prefer-all-hybrid.patch -Patch65: nss-3.124-ml-dsa-test-for-sign-verify-pkcs12.patch +Patch65: nss-3.124-el9-ml-dsa-test-for-sign-verify-pkcs12.patch Patch66: nss-3.124-ml-dsa-tls-test.patch Patch67: nss-3.118-ml-dsa-unittests.patch Patch68: nss-3.123-fix-mldsa-import-regeneration.patch +# rebase fixes +Patch70: nss-3.124-add-ml-kem-key-size-mech-info.patch +Patch71: nss-3.124-fix-pub-key-import-encapsulate.patch +Patch72: nss-3.124-ml-kem-alias-fix.patch + Patch100: nspr-config-pc.patch Patch101: nspr-gcc-atomics.patch # https://bugzilla.mozilla.org/show_bug.cgi?id=1769293 @@ -1197,6 +1203,16 @@ update-crypto-policies &> /dev/null || : %changelog +* Tue Jun 9 2026 Bob Relyea - 3.124.0-2 +- rebase fixes +- restore rhel-9 dropping of pkcs12 and smime policy +- restore mlkem aliases +- add mlkem key lengths to the mechanism info +- fix crash if you try to encapsulate with an unimported + public key +- restore distrusted certs to certdata.txt even though we + never reference them to make tests happy. + * Tue Jun 2 2026 Bob Relyea - 3.124.0-1 - rebase to upstream NSS 3.124 - backport ml-dsa support that is not upstream yet.