Proposal Details
I propose adding support to crypto/x509 for parsing and marshaling ML-KEM public and private keys according to RFC 9935.
Go already provides crypto/mlkem, whose key types expose byte encodings for public keys and seed-based private keys. crypto/x509 already provides APIs for marshaling and parsing PKIX public keys and PKCS#8 private keys. Adding ML-KEM support there allows crypto/mlkem keys to use the standard RFC 9935 encodings without requiring applications to implement their own ASN.1 wrappers.
This would extend the following existing key encoding APIs:
crypto/x509/x509.go
crypto/x509/pkcs8.go
This proposal is limited to key encoding and decoding. It does not propose adding ML-KEM as a certificate signature algorithm, does not add TLS certificate authentication support, and does not add general ML-KEM certificate semantics.
Background
RFC 9935 specifies the X.509/PKIX algorithm identifiers and key encodings for ML-KEM. The relevant OIDs are:
- ML-KEM-768:
2.16.840.1.101.3.4.4.2
- ML-KEM-1024:
2.16.840.1.101.3.4.4.3
RFC 9935 also defines ML-KEM-512, but this proposal does not include it because crypto/mlkem does not currently expose ML-KEM-512.
Proposed Changes
Extend x509.MarshalPKIXPublicKey to accept:
*mlkem.EncapsulationKey768
*mlkem.EncapsulationKey1024
Extend x509.ParsePKIXPublicKey to return:
*mlkem.EncapsulationKey768
*mlkem.EncapsulationKey1024
when the SubjectPublicKeyInfo algorithm identifier contains the corresponding RFC 9935 ML-KEM OID.
Extend x509.MarshalPKCS8PrivateKey to accept:
*mlkem.DecapsulationKey768
*mlkem.DecapsulationKey1024
Extend x509.ParsePKCS8PrivateKey to return:
*mlkem.DecapsulationKey768
*mlkem.DecapsulationKey1024
when the PrivateKeyInfo private key algorithm identifier contains the corresponding RFC 9935 ML-KEM OID.
Encoding Details
The AlgorithmIdentifier parameters for ML-KEM keys must be absent, as required by RFC 9935. Encodings that include parameters, including ASN.1 NULL parameters, should be rejected.
For public keys, the SubjectPublicKeyInfo.subjectPublicKey value is the raw ML-KEM public key bytes. Expected public key sizes are 1184 bytes for ML-KEM-768 and 1568 bytes for ML-KEM-1024.
For private keys, this proposal supports only the RFC 9935 seed private-key format. This aligns with the Bytes representation of the existing crypto/mlkem decapsulation key types:
ML-KEM-PrivateKey ::= CHOICE {
seed [0] OCTET STRING (SIZE (64))
}
Open Questions
- Should
ParsePKCS8PrivateKey accept the RFC 9935 expanded private-key forms for interoperability, or should Go initially support only seed private keys?
/cc @golang/security
Proposal Details
I propose adding support to
crypto/x509for parsing and marshaling ML-KEM public and private keys according to RFC 9935.Go already provides
crypto/mlkem, whose key types expose byte encodings for public keys and seed-based private keys.crypto/x509already provides APIs for marshaling and parsing PKIX public keys and PKCS#8 private keys. Adding ML-KEM support there allowscrypto/mlkemkeys to use the standard RFC 9935 encodings without requiring applications to implement their own ASN.1 wrappers.This would extend the following existing key encoding APIs:
crypto/x509/x509.gocrypto/x509/pkcs8.goThis proposal is limited to key encoding and decoding. It does not propose adding ML-KEM as a certificate signature algorithm, does not add TLS certificate authentication support, and does not add general ML-KEM certificate semantics.
Background
RFC 9935 specifies the X.509/PKIX algorithm identifiers and key encodings for ML-KEM. The relevant OIDs are:
2.16.840.1.101.3.4.4.22.16.840.1.101.3.4.4.3RFC 9935 also defines ML-KEM-512, but this proposal does not include it because
crypto/mlkemdoes not currently expose ML-KEM-512.Proposed Changes
Extend
x509.MarshalPKIXPublicKeyto accept:*mlkem.EncapsulationKey768*mlkem.EncapsulationKey1024Extend
x509.ParsePKIXPublicKeyto return:*mlkem.EncapsulationKey768*mlkem.EncapsulationKey1024when the
SubjectPublicKeyInfoalgorithm identifier contains the corresponding RFC 9935 ML-KEM OID.Extend
x509.MarshalPKCS8PrivateKeyto accept:*mlkem.DecapsulationKey768*mlkem.DecapsulationKey1024Extend
x509.ParsePKCS8PrivateKeyto return:*mlkem.DecapsulationKey768*mlkem.DecapsulationKey1024when the
PrivateKeyInfoprivate key algorithm identifier contains the corresponding RFC 9935 ML-KEM OID.Encoding Details
The
AlgorithmIdentifierparameters for ML-KEM keys must be absent, as required by RFC 9935. Encodings that include parameters, including ASN.1NULLparameters, should be rejected.For public keys, the
SubjectPublicKeyInfo.subjectPublicKeyvalue is the raw ML-KEM public key bytes. Expected public key sizes are 1184 bytes for ML-KEM-768 and 1568 bytes for ML-KEM-1024.For private keys, this proposal supports only the RFC 9935 seed private-key format. This aligns with the Bytes representation of the existing
crypto/mlkemdecapsulation key types:Open Questions
ParsePKCS8PrivateKeyaccept the RFC 9935 expanded private-key forms for interoperability, or should Go initially support only seed private keys?/cc @golang/security