Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion base/ca/shared/profiles/ca/caCACert.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ policyset.caCertSet.2.default.params.startTime=0
policyset.caCertSet.3.constraint.class_id=keyConstraintImpl
policyset.caCertSet.3.constraint.name=Key Constraint
policyset.caCertSet.3.constraint.params.keyType=-
policyset.caCertSet.3.constraint.params.keyParameters=1024,2048,3072,4096,nistp256,nistp384,nistp521
policyset.caCertSet.3.constraint.params.keyParameters=1024,2048,3072,4096,nistp256,nistp384,nistp521,44,65,87
Comment thread
edewata marked this conversation as resolved.
policyset.caCertSet.3.default.class_id=userKeyDefaultImpl
policyset.caCertSet.3.default.name=Key Default
policyset.caCertSet.4.constraint.class_id=noConstraintImpl
Expand Down
73 changes: 68 additions & 5 deletions base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.interfaces.RSAKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.NamedParameterSpec;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
Expand All @@ -57,6 +60,7 @@
import org.mozilla.jss.crypto.KeyPairGenerator;
import org.mozilla.jss.crypto.NoSuchItemOnTokenException;
import org.mozilla.jss.crypto.ObjectNotFoundException;
import org.mozilla.jss.crypto.PrivateKey.Type;
import org.mozilla.jss.crypto.SignatureAlgorithm;
import org.mozilla.jss.crypto.TokenException;
import org.mozilla.jss.crypto.X509Certificate;
Expand All @@ -73,8 +77,11 @@
import org.mozilla.jss.netscape.security.x509.X509CertImpl;
import org.mozilla.jss.netscape.security.x509.X509CertInfo;
import org.mozilla.jss.netscape.security.x509.X509Key;
import org.mozilla.jss.pkcs11.PK11PrivKey;
import org.mozilla.jss.pkix.cert.Extension;
import org.mozilla.jss.pkix.primitive.Name;
import org.mozilla.jss.util.ECCurve;
import org.mozilla.jss.util.ECOIDs;

import com.netscape.certsrv.authority.IAuthority;
import com.netscape.certsrv.base.EBaseException;
Expand Down Expand Up @@ -1442,19 +1449,62 @@ public Collection<String> getAuthorityKeyHosts() {

public KeyPair generateKeyPair(CryptoToken token) throws Exception {

KeyPairGenerator gen = null;

PrivateKey thisPriv = mSigningUnit.getPrivateKey();

if (thisPriv instanceof PK11PrivKey pKey) {
Comment thread
edewata marked this conversation as resolved.
if (pKey.getType() == Type.RSA) {
logger.info("CertificateAuthority: generating RSA key");
gen = token.getKeyPairGenerator(KeyPairAlgorithm.RSA);
gen.initialize(pKey.getStrength());
return gen.genKeyPair();
}
if (pKey.getType() == Type.EC) {
logger.info("CertificateAuthority: generating EC key");
gen = token.getKeyPairGenerator(KeyPairAlgorithm.EC);
String curveName = null;
try {
X509CertImpl caCertImpl = mSigningUnit.getCertImpl();
if (caCertImpl != null) {
X509Key caPubKey = (X509Key) caCertImpl.get(X509CertImpl.PUBLIC_KEY);
java.util.Vector<String> curves = CryptoUtil.getECKeyCurve(caPubKey);
if (curves != null && !curves.isEmpty()) {
curveName = curves.firstElement();
}
}
} catch (Exception e) {
logger.warn("CertificateAuthority: failed to get EC curve name from parent certificate: " + e.getMessage());
}
Comment on lines +1476 to +1478

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it OK to ignore this type of failure, or should we propagate the exception to the caller so that the operation fails and the user will know that there's something wrong?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in-line with RSA where there is a default in case when the original parent value cannot be retrieved. Since it is not possible to modify the value without creating a new CA I think the operation should not be stopped. At least a LWCA is created and can be used although the certificate could not have the proper algorithm. Maybe, if the option to customise LWCA will be added then this should fail.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC the new code will try to get the curve name from the signing cert and return a new EC key with the same curve. However, if there's a cert parsing issue or a bug in the code it will silently default to P-384.

I think ideally the user should be notified (by throwing an exception) if there's something wrong so they won't end up with a LWCA that they don't want/can't use which then they have to remove and create again, but I'll let you decide.

if (curveName != null) {
gen.initialize(gen.getCurveCodeByName(curveName));
} else {
gen.initialize(new ECGenParameterSpec(ECCurve.P384.getNames()[0]));
}
return gen.genKeyPair();
}
Comment thread
fmarco76 marked this conversation as resolved.
if (pKey.getType() == Type.MLDSA44 ||
pKey.getType() == Type.MLDSA65 ||
pKey.getType() == Type.MLDSA87) {
logger.info("CertificateAuthority: generating MLDSA key");
gen = token.getKeyPairGenerator(KeyPairAlgorithm.MLDSA);
gen.initialize(new NamedParameterSpec(pKey.getType().toString()));
return gen.genKeyPair();
Comment on lines +1486 to +1492

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

In Mozilla JSS (org.mozilla.jss), what string does org.mozilla.jss.crypto.PrivateKey.Type.toString() return for the ML-DSA key types (MLDSA44/MLDSA65/MLDSA87), and what are the JDK standard NamedParameterSpec names for ML-DSA?

💡 Result:

In Mozilla JSS (org.mozilla.jss), the class org.mozilla.jss.crypto.PrivateKey.Type is an enumeration-like structure used to represent key algorithms [1]. While recent development work in Mozilla's NSS (which underlies JSS) has added support for ML-DSA [2][3], the string returned by org.mozilla.jss.crypto.PrivateKey.Type.toString for these specific types is "ML-DSA" (or potentially a variant such as "MLDSA" depending on the exact implementation of the enum's string representation). Specifically, internal NSS changes associated with ML-DSA have introduced a key type referred to as mldsaKey [2]. Regarding the Java Development Kit (JDK) standard NamedParameterSpec names, the standard names for the ML-DSA (FIPS 204) parameter sets are: - ML-DSA-44 - ML-DSA-65 - ML-DSA-87 These names are utilized in the Java security ecosystem (e.g., in providers like Bouncy Castle) to identify these post-quantum cryptographic algorithms [4]. Note that ML-DSA is a FIPS-standardized algorithm derived from CRYSTALS-Dilithium [5][6]. Implementations typically use these strings when creating a NamedParameterSpec to specify the elliptic curve or parameter set in cryptographic operations.

Citations:


🏁 Script executed:

# Search for JSS PrivateKey.Type enum definition
rg -t java "enum\s+Type|class\s+Type" --search-path . -A 20 | head -100

Repository: dogtagpki/pki

Length of output: 595


🏁 Script executed:

# Search for MLDSA enum constants and any toString overrides in JSS
rg -t java "MLDSA44|MLDSA65|MLDSA87" --search-path . -B 5 -A 5

Repository: dogtagpki/pki

Length of output: 595


🌐 Web query:

JSS PrivateKey.Type enum MLDSA toString() implementation source code

💡 Result:

As of June 2026, Java Security Services (JSS) is in the process of adding support for the ML-DSA (Module-Lattice-Based Digital Signature Algorithm) signature scheme, as evidenced by recent development activity in the Mozilla NSS and JSS ecosystem (Bug 1983320) [1][2][3][4]. While the JSS org.mozilla.jss.crypto.PrivateKey.Type class historically manages standard algorithm types like RSA, DSA, and EC [5][6], the toString() implementation in PrivateKey.Type is a method that returns a string representation of the algorithm [5][7]. The source code for this toString() method generally follows a pattern of returning the string name (e.g., "RSA", "DSA", "EC") associated with the constant [5][6]. In the context of the recent ML-DSA integration: - ML-DSA has been added to the NSS underlying native libraries as a key type (mldsaKey) and supporting OIDs [2][3]. - New definitions, such as "ML-DSA-44", "ML-DSA-65", and "ML-DSA-87", are being integrated into the system [2][3]. - The toString() implementation in PrivateKey.Type (and related JSS crypto classes) would be updated to return the corresponding string name (e.g., "ML-DSA") if and when it is explicitly added as a PrivateKey.Type constant [5][7]. Because the integration is ongoing, specific public source code for an MLDSA constant within the PrivateKey.Type class may not yet be present in stable, released JSS versions [5][6][7]. Developers tracking this should monitor the official JSS repository and the referenced Bug 1983320 on Mozilla's Phabricator for the final commit incorporating the MLDSA constant and its corresponding toString() logic [1][2].

Citations:


🏁 Script executed:

# Find the PrivateKey.Type enum file
fd -t f "PrivateKey.java"

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Search for Type enum definition in the repository
rg -t java "MLDSA44|MLDSA65|MLDSA87"

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Look for any toString implementations related to Type
rg -t java "class Type|enum Type" -A 50 | grep -E "MLDSA|toString|enum Type"

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Search for PrivateKey usage and imports
rg -t java "import.*PrivateKey"

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Search for pKey usage patterns in the target file
sed -n '1480,1500p' base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java

Repository: dogtagpki/pki

Length of output: 1111


🏁 Script executed:

# Look for build files to identify JSS version
fd -t f "pom.xml|build.gradle" | head -5

Repository: dogtagpki/pki

Length of output: 243


🏁 Script executed:

# Check if JSS is vendored or available in the repository
find . -name "jss*" -type d 2>/dev/null | head -10

Repository: dogtagpki/pki

Length of output: 195


🏁 Script executed:

# Check JSS version in the CA pom.xml
cat base/ca/pom.xml | grep -A 5 -B 5 "jss"

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Look for any Type enum or MLDSA references in the codebase
rg -t java "Type\.(MLDSA|RSA|EC)" | head -20

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Search for NamedParameterSpec usage patterns
rg -t java "NamedParameterSpec" -B 3 -A 3

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Read the CertificateAuthority.java file around the MLDSA code block
cat -n base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java | sed -n '1,100p' | grep -i "import\|package"

Repository: dogtagpki/pki

Length of output: 4387


🏁 Script executed:

# Get imports from the file
head -50 base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java | grep "import"

Repository: dogtagpki/pki

Length of output: 1281


🏁 Script executed:

# Search for Type enum reference definition
rg "Type\.MLDSA" -B 5 -A 5

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Check pom.xml for JSS dependency
cat base/ca/pom.xml

Repository: dogtagpki/pki

Length of output: 1749


🏁 Script executed:

# Check the parent pom.xml for JSS dependency
cat base/pom.xml | grep -A 10 -B 10 "jss\|JSS"

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Check pki-server pom.xml for JSS dependency
cat base/server/pom.xml | grep -A 5 -B 5 "jss\|JSS" | head -50

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Look for Type enum definition in JSS source or check if there's documentation
rg "enum Type" -t java -A 30 | head -100

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Check root pom.xml
cat pom.xml | grep -A 5 -B 5 "jss\|JSS" | head -50

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# List the directory structure to understand the project layout
ls -la base/ | head -20

Repository: dogtagpki/pki

Length of output: 1254


🏁 Script executed:

# Search for all pom.xml files and check them for JSS
find . -name "pom.xml" -exec grep -l "jss\|JSS" {} \;

Repository: dogtagpki/pki

Length of output: 248


🏁 Script executed:

# Check the common pom.xml for JSS dependency
cat base/common/pom.xml | grep -A 10 -B 5 "jss\|JSS"

Repository: dogtagpki/pki

Length of output: 683


🏁 Script executed:

# Also check if there's a dependencyManagement section in root or parent pom
cat base/pom.xml

Repository: dogtagpki/pki

Length of output: 1209


🏁 Script executed:

# Look for CMakeLists.txt which might define JSS version
grep -i "jss" base/CMakeLists.txt | head -20

Repository: dogtagpki/pki

Length of output: 429


🏁 Script executed:

# Search for any Type enum constants and their usage patterns in the codebase
rg "Type\.(RSA|EC|DSA|MLDSA)" -t java | head -30

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Look for other uses of Type.toString() in the code
rg "\.getType\(\)\.toString\(\)" -t java -B 3 -A 3

Repository: dogtagpki/pki

Length of output: 151


🏁 Script executed:

# Check if there are any test files that show how MLDSA is used
find . -path "*/test/*" -name "*.java" -exec grep -l "MLDSA\|NamedParameterSpec" {} \; | head -10

Repository: dogtagpki/pki

Length of output: 151


🌐 Web query:

JSS 5.10.0 PrivateKey.Type MLDSA toString() method implementation

💡 Result:

In the Java Security Services (JSS) library, the org.mozilla.jss.crypto.PrivateKey.Type class is used to represent the type of a private key (e.g., RSA, DSA, EC) [1][2]. The toString method for this class is implemented to return a string representation of the algorithm, such as "RSA", "DSA", or "EC" [1][2]. As of JSS 5.10.0, there is no explicit MLDSA (Module-Lattice-Based Digital Signature Algorithm) value or specific toString implementation for MLDSA within the org.mozilla.jss.crypto.PrivateKey.Type class [1][2]. While JSS and its underlying Network Security Services (NSS) have been updated to support ML-DSA keys and mechanisms in the PKCS#11 interface [3], this support is handled through low-level C libraries (NSS/freebl) [4] and PKCS#11 mappings [3], rather than through the legacy PrivateKey.Type enum in the Java layer [1][5]. Users looking for ML-DSA functionality in Java are typically using other cryptographic providers, such as Bouncy Castle, which provides its own MLDSA class and implementation [6][7][8][9][10], or IAIK_PQ [11], which implement the standard independently. If you encounter an object representing an ML-DSA key in JSS, it does not utilize the PrivateKey.Type.toString method for this algorithm [1][3].

Citations:


🌐 Web query:

java.security.spec.NamedParameterSpec ML-DSA parameter names standard

💡 Result:

In the Java Security API, the ML-DSA (Module-Lattice-Based Digital Signature Algorithm) parameter sets are represented by the java.security.spec.NamedParameterSpec class [1][2]. These parameters were introduced in JDK 24 [3][4]. The standard ML-DSA parameter names, as defined in FIPS 204 [5][6] and incorporated into the Java Security Standard Algorithm Names Specification [7], are: - ML-DSA-44: Represented by the constant NamedParameterSpec.ML_DSA_44 [2][3]. - ML-DSA-65: Represented by the constant NamedParameterSpec.ML_DSA_65 [2][3]. - ML-DSA-87: Represented by the constant NamedParameterSpec.ML_DSA_87 [2][3]. These constants are static final members of the NamedParameterSpec class [2][8]. When using these parameters with APIs such as KeyPairGenerator, the standard name strings (e.g., "ML-DSA-44") or the corresponding NamedParameterSpec constants can be used to initialize the generator [1][9]. Regardless of the specific parameter set used, the family name for the algorithm in the Java Security API is "ML-DSA" [1][9].

Citations:


NamedParameterSpec constructor will fail: Type.toString() doesn't match JDK standard ML-DSA names.

new NamedParameterSpec(pKey.getType().toString()) is incompatible with JDK's standard parameter names. The JDK standard names are "ML-DSA-44", "ML-DSA-65", "ML-DSA-87" (with hyphens), but if PrivateKey.Type enum values (MLDSA44, MLDSA65, MLDSA87) are added to JSS, their default toString() would return "MLDSA44" etc., causing NamedParameterSpec initialization to fail.

Use NamedParameterSpec.ML_DSA_44 (or equivalents) directly, or convert the Type enum value to the correct JDK format string:

Example fix
String paramName = switch(pKey.getType()) {
    case MLDSA44 -> "ML-DSA-44";
    case MLDSA65 -> "ML-DSA-65";
    case MLDSA87 -> "ML-DSA-87";
    default -> throw new IllegalArgumentException("Unsupported MLDSA type");
};
gen.initialize(new NamedParameterSpec(paramName));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java` around lines
1486 - 1492, The NamedParameterSpec initialization in the MLDSA key generation
block is using pKey.getType().toString() which produces format like "MLDSA44",
but JDK expects the standard format "ML-DSA-44" with hyphens and uppercase DSA.
Replace the pKey.getType().toString() call with a switch statement that maps
Type.MLDSA44 to "ML-DSA-44", Type.MLDSA65 to "ML-DSA-65", and Type.MLDSA87 to
"ML-DSA-87", then pass the correctly formatted string to the NamedParameterSpec
constructor.

}
Comment thread
fmarco76 marked this conversation as resolved.
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC we can't use ML-KEM for signing, so should we throw something like "Unsupported key alg" at the end of thisPriv instanceof PK11PrivKey case?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check on private key of parent CA so I am expecting it is not ML-KEM. If a new key type is introduced the LWCA should work with RSA default, at least until this because configurable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, I'm thinking we should reject the new alg if we don't have the code to handle it rather than defaulting to RSA which they might not want or can't use, but I'll let you decide.


PublicKey thisPub = mSigningUnit.getPublicKey();
logger.info("CertificateAuthority: generating RSA key");

// Key size of sub-CA shall be key size of this CA.
// If the key is not RSA (e.g. EC) default to 3072 bits.
// TODO: key generation parameters
KeyPairGenerator gen = token.getKeyPairGenerator(KeyPairAlgorithm.RSA);
gen = token.getKeyPairGenerator(KeyPairAlgorithm.RSA);
int keySize = 3072;
PublicKey thisPub = mSigningUnit.getPublicKey();
if (thisPub instanceof RSAKey) {
keySize = ((RSAKey) thisPub).getModulus().bitLength();
}
Comment on lines 1503 to 1506

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's true that all private keys are instances of PK11PrivKey then this code might never be executed anymore. Should we move this code into the pKey.getType() == Type.RSA case above?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only case this code is executed when a new key type is introduced. As discussed above it is to make it working always. This should be configurable to allow failing and change configuration.

gen.initialize(keySize);

return gen.genKeyPair();
}

Expand All @@ -1466,9 +1516,22 @@ public PKCS10 generateCertRequest(

PublicKey pub = keypair.getPublic();
X509Key x509key = CryptoUtil.createX509Key(pub);

PKCS10 pkcs10 = new PKCS10(x509key);
Signature signature = Signature.getInstance("SHA256withRSA");
PrivateKey priv = keypair.getPrivate();
Signature signature = switch (priv.getAlgorithm()) {
case "RSA" -> Signature.getInstance("SHA256withRSA");
case "EC" -> Signature.getInstance("SHA256withECDSA");
Comment on lines +1522 to +1523

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash alg is hard-coded here. Should we use a hash param?

case "ML-DSA" -> {
if (priv instanceof PK11PrivKey pKey) {
yield Signature.getInstance(pKey.getType().toString());
}
throw new ECAException("ML-DSA key not handled by JSS");
}
Comment thread
fmarco76 marked this conversation as resolved.
Comment on lines +1521 to +1529

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

In Mozilla JSS, what does PK11PrivKey.getAlgorithm() return for an ML-DSA private key, and is PrivateKey.Type.toString() (e.g. for MLDSA65) a valid algorithm name accepted by java.security.Signature.getInstance()?

💡 Result:

In Mozilla JSS (Java Security Services), PK11PrivKey.getAlgorithm for an ML-DSA private key returns the string "ML-DSA" [1]. Regarding java.security.Signature.getInstance, the algorithm name "ML-DSA-65" (or other parameter-set variants like "ML-DSA-44" and "ML-DSA-87") is a valid, standard algorithm name defined for Java security APIs [2][3]. When you call Signature.getInstance("ML-DSA-65"), it specifically requires that the key used for the operation also conforms to the ML-DSA-65 parameter set; attempting to use an incompatible key will result in an InvalidKeyException [2]. Alternatively, you can use the family name "ML-DSA", which accepts keys of any ML-DSA parameter set [2]. These naming conventions are part of the Java standard algorithm names established for quantum-resistant algorithms, consistent with FIPS 204 [4][2][3].

Citations:


🏁 Script executed:

#!/bin/bash
# Search for JSS PrivateKey.Type or PK11PrivKey.Type implementation in the codebase
# to see what toString() returns for ML-DSA keys

# First, check if JSS source or references are in this repo
fd -t f -e java | head -20

# Look for any ML-DSA related type definitions
rg -i "MLDSA|ML-DSA" --type java | head -30

# Search for Type enum or class definitions
rg "Type\." --type java | grep -i "mldsa\|ml-dsa" | head -20

Repository: dogtagpki/pki

Length of output: 1688


🌐 Web query:

JSS Mozilla PK11PrivKey.Type.toString() ML-DSA return value format MLDSA65

💡 Result:

In the context of Mozilla's Java Security Services (JSS) and the underlying Network Security Services (NSS) library, the ML-DSA (Module-Lattice-Based Digital Signature Algorithm) support has been introduced via Bug 1983320 [1][2]. While the standard PrivateKey.Type.toString method in JSS traditionally returns strings like "RSA", "DSA", or "EC" [3][4], the integration of ML-DSA into the NSS/JSS architecture typically utilizes OIDs (Object Identifiers) and specialized parameter sets to distinguish between variants such as ML-DSA-44, ML-DSA-65, and ML-DSA-87 [2][5]. For ML-DSA specifically, the internal representation uses the OID-based identifiers (e.g., SEC_OID_ML_DSA_65) [2]. When accessing key type information through the updated NSS interfaces, the system maps these to specific mechanisms and key types rather than a simple string. As JSS provides a Java wrapper around NSS, if you were to invoke a string representation for an ML-DSA type, it would be expected to return the identifier string, which is typically "ML-DSA-65" (or "ML-DSA-44"/"ML-DSA-87") in line with standard identifier naming conventions used in the updated NSS command-line and printing utilities [5]. Because the support for ML-DSA is a recent addition involving structural changes to how key types are mapped and printed [1][6][5], you should ensure your JSS environment is built against an NSS version that includes the commits associated with Bug 1983320. In these updated versions, the printing and identification logic has been extended to recognize these OIDs explicitly [5].

Citations:


🌐 Web query:

JSS Java Security Services PrivateKey.Type toString ML-DSA what string

💡 Result:

In the Java Security Services (JSS) library, the org.mozilla.jss.crypto.PrivateKey.Type class is a type-safe enum used to identify the algorithm type of a private key [1][2]. As of the available documentation, this class contains defined fields for legacy algorithms such as RSA, DSA, and EC (Elliptic Curve), but it does not include a native field or specific constant for ML-DSA [1][2]. While ML-DSA (Module-Lattice-Based Digital Signature Algorithm) is a standardized, quantum-resistant algorithm supported by modern Java platforms (such as via JEP 497 in the OpenJDK) [3][4][5], JSS operates as a distinct cryptographic provider. If you encounter an ML-DSA key within a JSS context, it is not represented by a standard PrivateKey.Type constant [1][2]. If you attempt to call toString on a hypothetical or unsupported ML-DSA type object in JSS, it would not return a standardized "ML-DSA" string value managed by the PrivateKey.Type class, as that class is currently limited to the hardcoded algorithm types defined during its implementation [1][2]. For native ML-DSA operations in Java, developers should use the standard Java Cryptography Architecture (JCA) APIs, such as KeyPairGenerator and Signature, which now define ML-DSA, ML-DSA-44, ML-DSA-65, and ML-DSA-87 as standard algorithm names [3][5].

Citations:


The ML-DSA branch has a critical compatibility issue: JSS PrivateKey.Type does not currently support ML-DSA.

While priv.getAlgorithm() correctly returns "ML-DSA" for ML-DSA keys generated by JSS, the subsequent instanceof PK11PrivKey check followed by pKey.getType().toString() will fail or return an undefined value. Current JSS documentation shows that PrivateKey.Type is limited to RSA, DSA, and EC—ML-DSA is not defined as a type constant in the enum. This means getType() will not produce a valid Signature algorithm name (which require the format "ML-DSA-65", "ML-DSA-44", or "ML-DSA-87"), and will likely throw an exception or return null at runtime. Even if recent Mozilla NSS patches (D262394, D262393) add ML-DSA support, the JSS wrapper and its javadocs do not yet reflect this. This code path will fail unless your JSS version has been updated to match the underlying NSS changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java` around lines
1521 - 1529, The ML-DSA case in the switch statement for handling private key
algorithms does not properly construct a valid Signature algorithm name because
JSS's PrivateKey.Type enum does not yet support ML-DSA constants. The call to
pKey.getType().toString() will not produce the required format (ML-DSA-65,
ML-DSA-44, or ML-DSA-87). Instead of relying on pKey.getType(), you should
directly construct the proper Signature algorithm string for ML-DSA by either
extracting the key parameter set (if determinable from the ML-DSA key itself) or
using a reasonable default like ML-DSA-65, then pass that string to
Signature.getInstance(). Alternatively, if you cannot reliably determine the
parameter set, provide a more informative error message indicating that ML-DSA
support requires a JSS version with proper ML-DSA type support.

default -> {
logger.warn("Private key type not recognised. Try with SHA256withRSA signature");
yield Signature.getInstance("SHA256withRSA");
Comment on lines +1531 to +1532

ghost Jun 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we throw an exception instead? I suppose people want to use a specific key alg instead of defaulting to something that might not work for their system.

}
};
Comment thread
fmarco76 marked this conversation as resolved.
signature.initSign(keypair.getPrivate());
pkcs10.encodeAndSign(new X500Signer(signature, subjectX500Name));

Expand Down
Loading