Issue pure ML-DSA certificates
You need a certification authority and certificates that use ML-DSA only, for example in a closed environment where every party verifies ML-DSA.
Solution overview
| Element | Purpose |
|---|---|
PostQuantumConfig.Exemptions | with PurePostQuantum, allows PostQuantum mode |
MLDsaKey.Generate | generates an ML-DSA key pair with the ML-DSA-65 or ML-DSA-87 parameter set; ML-DSA-44 only with ReducedParameterSets |
MLDsaX509SignatureGenerator.CreateCertificateRequest | creates a CertificateRequest for an ML-DSA key |
CreateSelfSigned, Create with CryptoMode.PostQuantum | issue the certificate as defined in RFC 9881 |
X509Chain.Build with CryptoMode.PostQuantum | validates the chain |
AttachPrivateMLDsaKey | associates an issued certificate with its private key |
X509CertificateBuilder | the same path for .NET Framework 4.6.2, which doesn't have CertificateRequest |
Implementation
BSI TR-02102-1 recommends PQ signatures only in combination with a classical signature. That's why
PostQuantum mode requires an exemption, which you set once when your app starts:
PostQuantumConfig.Exemptions |= PostQuantumExemptions.PurePostQuantum;
Root certificate:
var now = DateTimeOffset.UtcNow; using var rootKey = MLDsaKey.Generate(MLDsaParameterSet.MLDsa65); var rootRequest = new MLDsaX509SignatureGenerator(rootKey) .CreateCertificateRequest("CN=Contoso PQ Root CA"); rootRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true)); rootRequest.CertificateExtensions.Add( new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign, true)); using var root = rootRequest.CreateSelfSigned(now, now.AddYears(10), CryptoMode.PostQuantum);
A signer certificate issued by the root certificate, followed by chain validation:
using var signerKey = MLDsaKey.Generate(MLDsaParameterSet.MLDsa65); var signerRequest = new MLDsaX509SignatureGenerator(signerKey) .CreateCertificateRequest("CN=signer.example.com"); signerRequest.CertificateExtensions.Add( new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, true)); using var signer = signerRequest.Create( root, now, now.AddYears(1), RandomNumberGenerator.GetBytes(16), CryptoMode.PostQuantum); signer.AttachPrivateMLDsaKey(signerKey); using var chain = new X509Chain(); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; chain.ChainPolicy.CustomTrustStore.Add(root); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; Console.WriteLine(chain.Build(signer, CryptoMode.PostQuantum));
On .NET Framework 4.6.2, issue the certificate with X509CertificateBuilder:
var builder = new X509CertificateBuilder( new X500DistinguishedName("CN=signer.example.com"), signerKey); using var selfSigned = builder.CreateSelfSigned(now, now.AddYears(1), CryptoMode.PostQuantum);
Remarks
- Associate the private key. A certificate issued with
Createonly knows the public key from the request.GetPrivateMLDsaKeyreturnsnullfor it until you callAttachPrivateMLDsaKey. Only then can the certificate sign, issue, or be exported as a PFX file. HasPrivateKeystaysfalse. The .NET property only knows classical keys. To check whether an ML-DSA key is present, callGetPrivateMLDsaKey.- Without
CryptoMode, .NET applies.rootRequest.CreateSelfSigned(notBefore, notAfter)without the argument binds to the .NET method. That method doesn't know the ML-DSA key and throws anInvalidOperationException. - The exemption also applies to verification. Without
PurePostQuantum, every operation inPostQuantummode throws aCryptographicException, includingX509Chain.Build. Every operation raises thePolicyDeviationevent; see Post-quantum algorithm policy. - Only verifiers that support ML-DSA. Software that doesn't know ML-DSA can't validate these certificates. For the transition, use hybrid certificates as shown in Create your first hybrid certificate chain.
Related topics
en/wiki/pqcrypt/lib/how-to/issue-ml-dsa-certificates.txt · Last modified: by Wolfgang van der Stille