JDK-8349164 : Switch to latest ML-DSA private key encoding
  • Type: CSR
  • Component: security-libs
  • Sub-Component: java.security
  • Priority: P2
  • Status: Draft
  • Resolution: Unresolved
  • Submitted: 2025-01-31
  • Updated: 2025-05-15
Related Reports
CSR :  
Description
Summary
-------

Update the ML-DSA private key encoding to align with Section 6 of draft-ietf-lamps-dilithium-certificates-8. Specifically, the `privateKey` field in `OneAsymmetricKey` will follow the DER-encoded CHOICE structure as defined: it must contain one of the three permitted alternatives described in the draft.

Problem
-------

When ML-DSA was initially implemented in OpenJDK, earlier versions of draft-ietf-lamps-dilithium-certificates stated that "A fully populated ML-DSA private key consists of 6 parameters. The size necessary to hold all private key elements is 32+32+32+32*[(k+l)*ceiling(log(2*eta+1))+13*k] bytes", this matches the private key defined in NIST FIPS 204 — specifically, the private key part of the return value from the ML-DSA.KeyGen function, as defined in Section 5.1 of FIPS 204.

In the final revision of the draft, the private key format has been formally defined as a DER-encoded ASN.1 CHOICE. For ML-DSA-44, for example:

    ML-DSA-44-PrivateKey ::= CHOICE {
        seed [0] OCTET STRING (SIZE (32)),
        expandedKey OCTET STRING (SIZE (2560)),
        both SEQUENCE {
            seed OCTET STRING (SIZE (32)),
            expandedKey OCTET STRING (SIZE (2560))
        }
    }

Similar structures are defined for ML-DSA-65 and ML-DSA-87.

Our current implementation corresponds to the second choice, `expandedKey OCTET STRING`. To comply with the updated specification, we must update our implementation to support the other two choices as well.

Solution
--------

Update the ML-DSA private key encoding to support the new CHOICE structure. A new security or system property will control which of the three CHOICE options is used by the JDK.

When `KeyPairGenerator::generateKey` or `KeyFactory::translateKey` is invoked, the returned ML-DSA private key will be encoded using the selected format.

Note: If `KeyFactory::translateKey` is used to convert a key that lacks a seed into a format that includes the seed, the operation will fail and an `InvalidKeyException` will be thrown.

Specification
-------------

A new security property, `jdk.mldsa.pkcs8.encoding`, is introduced to control the encoding format of ML-DSA private keys in PKCS #8.

The following entry is added to the `java.security` file:

	#
	# The privateKey field for newly created ML-DSA private keys in PKCS #8
	#
	# The draft-ietf-lamps-dilithium-certificates specification defines three formats
	# for an ML-DSA private key: a 32-byte seed, an expanded private key,
	# or a sequence containing both.
	#
	# Valid values for this property are "seed", "expandedKey", and "both"
	# (case-insensitive). The default is "seed".
	#
	# This property determines the encoding format used when a new keypair is
	# generated using a KeyPairGenerator, as well as the output of the translateKey
	# method on an existing key using a KeyFactory.
	#
	# If a system property of the same name is also specified, it supersedes the
	# security property value defined here.
	#
	# Note: This property is currently used by the SUN provider in the JDK
	# Reference implementation. It is not guaranteed to be supported by other
	# SE implementations.
	#
	#jdk.mldsa.pkcs8.encoding = seed
Comments
Moving to Provisional, not Approved. [~mullan], please review this request. Is there somewhere in the documentation where the format should be specified?
05-02-2025

Moving to Approved.
31-01-2025