Formats of the post-quantum parts
graph TD
CERT["Hybrid certificate"]
TBS["TBSCertificate with three noncritical extensions"]
SPKI["subjectAltPublicKeyInfo: the subject's ML-DSA key"]
ALG["altSignatureAlgorithm: ML-DSA parameter set"]
VAL["altSignatureValue: the issuer's ML-DSA signature"]
SIG["Classical signature: RSA or ECDSA over the entire TBSCertificate"]
CERT --> TBS
CERT --> SIG
TBS --> SPKI
TBS --> ALG
TBS --> VALFigure: A hybrid certificate is an ordinary X.509 certificate. The post-quantum part sits in three noncritical extensions, which the classical signature also covers.
The library stores every post-quantum (PQ) part so that software without PQ support can still read and verify the data. Where a standard defines a format, the library follows it. Where no standard exists yet, the library uses provisional identifiers; this page lists those cases.
Key features
- Hybrid certificates and CRLs with alternative signatures as defined in ITU-T X.509 (10/2019).
- Pure ML-DSA certificates as defined in RFC 9881.
- Composite ML-DSA for raw signatures, following the IETF draft draft-ietf-lamps-pq-composite-sigs.
- CMS encryption for ML-KEM as defined in RFC 9629 (KEMRecipientInfo).
- PFX files as defined in RFC 7292, with the ML-DSA key in a key bag of its own.
- Provisional: PQ signatures in CMS and XML, and hybrid encryption with
EncryptHybrid.
Core concepts
Hybrid certificates and CRLs
A hybrid certificate carries three noncritical extensions from ITU-T X.509 (10/2019):
| Extension | OID | Content |
|---|---|---|
| subjectAltPublicKeyInfo | 2.5.29.72 | the subject's ML-DSA key |
| altSignatureAlgorithm | 2.5.29.73 | the ML-DSA parameter set of the additional signature |
| altSignatureValue | 2.5.29.74 | the issuer's ML-DSA signature |
The ML-DSA signature covers the TBSCertificate without the altSignatureValue extension. The classical
signature covers the entire TBSCertificate, including all three extensions. A classical verifier skips
unknown noncritical extensions and validates the certificate like any other. CRLs from X509CrlBuilder
carry their additional signature the same way.
Pure ML-DSA certificates
Certificates in PostQuantum mode carry the ML-DSA key as a standard SubjectPublicKeyInfo and are signed
with ML-DSA, as RFC 9881 specifies. The library supports the parameter sets ML-DSA-44, ML-DSA-65, and
ML-DSA-87. Which of them create data without an exemption is governed by the
Post-quantum algorithm policy.
Composite ML-DSA
Raw signatures in Hybrid mode are composite ML-DSA signatures as defined in the IETF draft
draft-ietf-lamps-pq-composite-sigs (revision 19): an ML-DSA signature followed by the RSA or ECDSA
signature. The draft defines fixed pairs, and the library supports these. The Hash algorithm column lists
the value that you pass to SignData and VerifyData:
| ML-DSA | Classical part | Hash algorithm |
|---|---|---|
| ML-DSA-44 | RSA-2048, PSS or PKCS#1 v1.5 | SHA-256 |
| ML-DSA-44 | ECDSA P-256 | SHA-256 |
| ML-DSA-65 | RSA-3072, PSS or PKCS#1 v1.5 | SHA-256 |
| ML-DSA-65 | RSA-4096, PSS or PKCS#1 v1.5 | SHA-384 |
| ML-DSA-65 | ECDSA P-256 | SHA-256 |
| ML-DSA-65 | ECDSA P-384 | SHA-384 |
| ML-DSA-65 | ECDSA brainpoolP256r1 | SHA-256 |
| ML-DSA-87 | ECDSA P-384 | SHA-384 |
| ML-DSA-87 | ECDSA brainpoolP384r1 | SHA-384 |
| ML-DSA-87 | RSA-3072, PSS | SHA-256 |
| ML-DSA-87 | RSA-4096, PSS | SHA-384 |
| ML-DSA-87 | ECDSA P-521 | SHA-512 |
The library rejects any other pair, such as ML-DSA-65 with RSA-2048, with a CryptographicException. The
pairs with ML-DSA-44 sign only with the ReducedParameterSets exemption; you can verify them without it.
Ed25519 and Ed448 aren't supported, because .NET 8 doesn't provide EdDSA.
CMS encryption
KemEnvelopedCms writes CMS EnvelopedData (RFC 5652) with KEMRecipientInfo (RFC 9629). For ML-KEM, the
format matches what OpenSSL 3.6 writes. For composite ML-KEM, it follows the IETF draft
draft-ietf-lamps-cms-composite-kem. RSA recipients of the same message get a KeyTransRecipientInfo with
RSAES-OAEP.
The .NET EnvelopedCms class can't decode a message that contains a KEMRecipientInfo, not even for an RSA
recipient of the same message. Open mixed messages with KemEnvelopedCms instead.
PFX files
ExportPfx writes a PKCS#12 file as defined in RFC 7292. The ML-DSA key sits in an additional encrypted
key bag next to the classical key, and the same localKeyId links it to the certificate. ML-KEM and composite
ML-KEM keys are stored in the file the same way. Other programs read the certificate and the classical key
as usual and skip the additional bag. For how the file is encrypted, see
Keys and key storage.
Provisional formats
No standard assigns identifiers for the following cases yet, so the library uses provisional identifiers. Only peers that use this library verify the PQ part; classical verifiers still read the data.
| Case | Location | Provisional identifier |
|---|---|---|
| PQ signature in CMS | unsigned attribute of the SignerInfo | 1.3.6.1.4.1.99999.3.1 |
| Announcement of the PQ signature in CMS | signed attribute of the SignerInfo | 1.3.6.1.4.1.99999.3.2 |
ML-DSA in XML, PostQuantum mode | SignatureMethod | urn:oid:2.16.840.1.101.3.4.3.17 through .19 |
ML-DSA in XML, Hybrid mode | AltSignatureValue element in a ds:Object | namespace urn:x-wkl:xmldsig-pq |
EncryptHybrid, HybridEncryptedData, PqCrypto | proprietary binary format | – |
The classical signature protects the announcement in CMS. If someone strips the PQ signature, a verifier that uses this library detects the downgrade and rejects the message.
Limitations
- Provisional identifiers aren't registered. A future standard will assign different identifiers. Use PQ signatures in CMS and XML only between apps that use this library, and don't rely on these identifiers alone when you archive signed documents for the long term.
- Drafts aren't standards. Composite ML-DSA and composite ML-KEM follow specific revisions of IETF drafts. A peer that implements a different revision can reject such signatures and messages.
- Proprietary binary format only between your own apps.
EncryptHybridandPqCryptoaren't suitable for exchanging data with third-party software. For that, useKemEnvelopedCms.