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.
This commit is contained in:
Robert Relyea 2026-06-09 20:44:50 -07:00
parent 7a379da5b1
commit ed6f9c6a95
7 changed files with 2011 additions and 3 deletions

View File

@ -0,0 +1,60 @@
# HG changeset patch
# User Robert Relyea <rrelyea@redhat.com>
# 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;

View File

@ -0,0 +1,821 @@
# HG changeset patch
# User Robert Relyea <rrelyea@redhat.com>
# 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, &paramSet, &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,
&paramSet);
if (crv != CKR_OK) {
crv = sftk_GetULongAttribute(object, CKA_NSS_PARAMETER_SET,
&paramSet);
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 ##############################

View File

@ -0,0 +1,654 @@
# HG changeset patch
# User Robert Relyea <rrelyea@redhat.com>
# 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 = &paramSet;
+ 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, &paramSet, &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 <<CERTSCRIPT
+5
+6
+9
+n
+y
+-1
+n
+5
+6
+7
+9
+n
+CERTSCRIPT
+ if [ "$RET" -ne 0 ]; then
+ echo "return value is $RET"
+ Exit 6 "Fatal - failed to create ML-DSA ($PARAM_SET) CA cert"
+ fi
+
+ ################# Exporting ML-DSA Root Cert ###############################
+ #
+ CU_ACTION="Exporting ML-DSA ($PARAM_SET) Root Cert"
+ certu -L -n $NICKNAME -r -d ${LPROFILE} -o ${NICKNAME}.ca.cert
+ if [ "$RET" -ne 0 ]; then
+ Exit 7 "Fatal - failed to export $PARAM_SET root cert"
+ fi
+}
################################ cert_rsa_pss_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 RSA-PSS version of cert_CA.
##########################################################################
cert_rsa_pss_CA()
{
@@ -1194,17 +1265,17 @@ cert_stresscerts()
}
############################## cert_fips #####################################
# local shell function to create certificates for FIPS tests
##############################################################################
cert_fips()
{
CERTFAILED=0
- echo "$SCRIPTNAME: Creating FIPS 140 DSA Certificates =============="
+ echo "$SCRIPTNAME: Creating FIPS 140 Certificates =============="
cert_init_cert "${FIPSDIR}" "FIPS PUB 140 Test Certificate" 1000 "${D_FIPS}"
CU_ACTION="Initializing ${CERTNAME}'s Cert DB"
certu -N -d "${PROFILEDIR}" -f "${R_FIPSPWFILE}" 2>&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 ##############################

View File

@ -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));

View File

@ -0,0 +1,80 @@
# HG changeset patch
# User Robert Relyea <rrelyea@redhat.com>
# 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;

View File

@ -0,0 +1,160 @@
# HG changeset patch
# User Robert Relyea <rrelyea@redhat.com>
# 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()

View File

@ -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 <rrelyea@redhat.com> - 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 <rrelyea@redhat.com> - 3.124.0-1
- rebase to upstream NSS 3.124
- backport ml-dsa support that is not upstream yet.