http://docker:8083Self-signed root of trust with ML-DSA-65. 10-year validity. Foundation of the PQC PKI hierarchy.
ML-DSA-65Signed by Root CA. Issues end-entity certificates. 5-year validity. Keeps root key offline.
ML-DSA-65Server/client certificates signed by Intermediate CA. 1-year validity. For TLS, mTLS, code signing.
ML-DSA-65Dual ECDSA P-384 + ML-DSA-65 certificates for backward compatibility during PQC migration.
ECDSA + ML-DSA-65This service demonstrates a full PQC PKI hierarchy — the same patterns you'll implement using the Qudo JNI provider in your own certificate infrastructure.
Key generation: provider.generateKeyPair("ML-DSA-65")
Self-signed cert: provider.createSelfSignedCert(privKey, subject, days)
CSR + signing: provider.createCSR(privKey, subject) then provider.signCSR(csr, caKey, caCert, days)
Root CA → Intermediate CA → End-Entity certificates. Hybrid certificates (ECDSA + PQC) for backward compatibility.
/api/ca/create-root
Create a PQC Root CA
/api/ca/create-intermediate
Create Intermediate CA (signed by Root)
/api/ca/issue-cert
Issue end-entity certificate
/api/ca/create-hybrid
Create hybrid certificate (ECDSA + PQC)
/api/ca/chain
View all issued certificates
/api/ca/health
Service health + supported algorithms
Migrate your PKI from classical RSA/ECDSA to post-quantum ML-DSA-65 certificates. Use this playground to try PQC certificate operations, then use the Qudo JNI provider in your own PKI infrastructure.
A standard PKI hierarchy with quantum-safe certificates:
Root CA (ML-DSA-65, self-signed, 10-year validity)
|
+-- Intermediate CA (ML-DSA-65, signed by Root, 5-year validity)
|
+-- Server Cert (ML-DSA-65, signed by Intermediate, 1-year validity)
+-- Client Cert (ML-DSA-65, signed by Intermediate, 1-year validity)
+-- Code Signing Cert (ML-DSA-65, signed by Intermediate, 1-year validity)
The hierarchy, trust chain, and X.509 format are identical to classical PKI. Only the signature algorithm inside the certificate changes from RSA/ECDSA to ML-DSA-65.
Issue both ECDSA and ML-DSA-65 certificates for the same subject during migration. Clients use whichever they support.
Replace your classical RSA/ECDSA certificate generation with the Qudo JNI provider. The PKI hierarchy pattern stays the same.
import com.qudo.crypto.QudoCrypto;
import com.qudo.crypto.QudoKeyPair;
QudoCrypto provider = QudoCrypto.create();
// ============================================================
// 1. Create Root CA (self-signed, 10-year validity)
// ============================================================
QudoKeyPair rootKeys = provider.generateKeyPair("ML-DSA-65");
byte[] rootCert = provider.createSelfSignedCert(
rootKeys.getPrivateKeyPem(),
"/CN=My Organization Root CA/O=My Org/C=US", 3650);
// Store rootKeys.getPrivateKeyPem() OFFLINE (HSM)
// Distribute rootCert as trust anchor
// ============================================================
// 2. Create Intermediate CA (signed by Root, 5-year validity)
// ============================================================
QudoKeyPair intermediateKeys = provider.generateKeyPair("ML-DSA-65");
byte[] intermediateCSR = provider.createCSR(
intermediateKeys.getPrivateKeyPem(),
"/CN=My Intermediate CA/O=My Org/OU=PKI/C=US");
byte[] intermediateCert = provider.signCSR(
intermediateCSR, rootKeys.getPrivateKeyPem(), rootCert, 1825);
// ============================================================
// 3. Issue End-Entity Certificate (1-year validity)
// ============================================================
QudoKeyPair serverKeys = provider.generateKeyPair("ML-DSA-65");
byte[] serverCSR = provider.createCSR(
serverKeys.getPrivateKeyPem(),
"/CN=api.example.com/O=My Org/C=US");
byte[] serverCert = provider.signCSR(
serverCSR, intermediateKeys.getPrivateKeyPem(), intermediateCert, 365);
// ============================================================
// 4. Verify the chain (openssl CLI)
// ============================================================
// cat intermediate.crt root-ca.crt > ca-chain.crt
// openssl verify -CAfile ca-chain.crt server.crt
// Expected: server.crt: OK
// openssl x509 -in server.crt -noout -text | grep "Signature Algorithm"
// Shows: Signature Algorithm: ML-DSA-65
provider.close();
# RSA Root CA openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 openssl req -new -x509 -key root.key -sha256 ... # ECDSA Intermediate openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 openssl req -new -key intermediate.key ...
# ML-DSA-65 Root CA openssl genpkey -algorithm ML-DSA-65 openssl req -new -x509 -key root.key ... # ML-DSA-65 Intermediate (same commands) openssl genpkey -algorithm ML-DSA-65 openssl req -new -key intermediate.key ...
| Component | Changes? | Details |
|---|---|---|
| X.509 format | No | Same ASN.1 structure, same extensions, same chain model |
| Key algorithm | Yes | RSA/ECDSA → ML-DSA-65 (one flag change in openssl genpkey) |
| Signature algorithm | Yes | SHA256withRSA/ECDSA → ML-DSA-65 (automatic from key type) |
| Certificate size | Yes | ~10KB for ML-DSA-65 vs ~1-2KB for RSA/ECDSA (public key is larger) |
| Chain validation | No | Same openssl verify command, same trust model |
| OCSP / CRL | No | Same revocation mechanisms |
| OpenSSL commands | Minimal | Replace -algorithm RSA with -algorithm ML-DSA-65 |
| Operation | ML-DSA-65 | RSA-4096 | ECDSA P-384 |
|---|---|---|---|
| Key generation | ~55ms | ~500ms | ~5ms |
| Certificate signing | ~120ms | ~50ms | ~5ms |
| Certificate verification | ~40ms | ~1ms | ~2ms |
| Certificate size | ~10KB | ~2KB | ~1KB |
| Public key size | ~2.7KB | ~512B | ~91B |
A: The server (NGINX, Apache) must be built with OpenSSL 3.6+ and the Qudo Cryptographic Module. Standard NGINX with older OpenSSL will reject ML-DSA-65 certificates. During migration, use hybrid mode — serve ECDSA certs to classical clients and ML-DSA-65 certs to PQC-capable clients.
A: Browser support for PQC certificates is still emerging. Chrome and Firefox support PQC key exchange (X25519MLKEM768) but not PQC certificates for server authentication yet. Use ECDSA certificates for TLS server auth and ML-DSA-65 for code signing, internal mTLS, and non-browser use cases.
A: Not immediately. Start with new certificates — issue ML-DSA-65 certs for new services. Existing certificates can remain ECDSA until they expire. Prioritize code signing and internal mTLS certificates where you control both endpoints.
A: The hybrid endpoint creates two separate certificates — one ECDSA P-384 and one ML-DSA-65 — for the same subject. The server presents the appropriate certificate based on what the client supports. This isn't a composite certificate; it's dual-stack PKI.
A: For most use cases, no. TLS handshakes transmit the full chain (~30KB for a 3-cert chain) which adds ~1 RTT. With TLS session resumption, this cost is paid only once. For constrained environments (IoT with limited bandwidth), consider ML-DSA-44 which produces smaller certs.
Analyze any endpoint's cryptographic configuration. Enter a host:port to scan its TLS setup and identify what's quantum-safe vs what needs migration.