- What it is: NIST finalized ML-KEM (key encapsulation) and ML-DSA (signatures) in 2024 as the first post-quantum TLS primitives ready for production. Migrating to them requires hybrid negotiation, staged rollouts, and a separate certificate migration track.
- Why it matters: Harvest-now, decrypt-later attacks are already in practice. Adversaries capturing today’s TLS traffic can decrypt it retroactively once a cryptographically relevant quantum computer exists. Classical key exchange is the first thing to replace.
- The gotcha: Certificate signature migration is harder than key exchange, and most teams discover this too late. ML-DSA certificate chains are larger, dual issuance is not yet automated, and HSM firmware support trails software by months.
Who this is for: security engineers and platform engineers running TLS at scale who need to start a post-quantum migration in 2026. You should be comfortable with nginx or a comparable TLS termination layer, have some familiarity with OpenSSL configuration, and understand the difference between key exchange and authentication in the TLS handshake. You do not need a deep cryptography background, but you do need to care about the handshake.
The traffic you recorded last year is already a liability
Somewhere in a storage bucket there is a pcap of your production TLS traffic from three years ago. At the time it was unreadable without your private keys. Now, a well-resourced adversary is keeping a copy of ciphertext from TLS sessions they cannot yet decrypt. The bet they are making is that a cryptographically relevant quantum computer will exist in time to make decryption worthwhile. The session was ephemeral. The ciphertext is not.
This attack pattern is called “harvest now, decrypt later,” and it is already happening at scale. The threat is not academic. Nation-state actors and well-funded groups have the storage and the motivation. The break may be five years out or fifteen, but the data being collected today sets the outer boundary of your exposure.
The good news is that NIST closed the standardization gap in August 2024. FIPS 203 (ML-KEM, formerly Kyber), FIPS 204 (ML-DSA, formerly Dilithium), and FIPS 205 (SLH-DSA, formerly SPHINCS+) are final standards. The ecosystem has had time to implement them: OpenSSL 3.5 ships ML-KEM support, BoringSSL has it, and the major CDNs have offered hybrid PQC in preview configurations. The question is no longer whether to migrate. It is how to do it without breaking compatibility or production stability.
This article is a playbook for teams starting that migration now. It follows the safe order: inventory, hybrid key exchange, performance validation, and then certificate signature migration. Each step has real configuration examples and non-obvious failure modes.
Migration mechanics
The TLS handshake has two distinct cryptographic operations that need separate migration tracks. Understanding the separation is the prerequisite for planning.
Key exchange establishes the shared secret that encrypts the session. In TLS 1.3, this is a Diffie-Hellman operation, currently X25519 in most deployments. The quantum vulnerability here is that a future adversary with access to the ciphertext and a quantum computer could break the classical key exchange retroactively and recover the session secret. This is the harvest-now, decrypt-later exposure.
Authentication uses certificates and digital signatures to prove the server is who it claims to be. Certificates carry the server’s public key and a CA signature. The signature algorithm today is almost always ECDSA or RSA. Quantum computers threaten these too, but the attack requires the adversary to be online, actively intercepting the handshake, with a quantum computer ready. That threat window is further out than key exchange.
The migration order follows from this. Key exchange first, because that is the live exposure. Certificate signatures second, because the tooling is less mature and the urgency is lower.
Figure 1 shows the two tracks and their sequencing.
flowchart TD
A[Inventory TLS surface] --> B[Enable hybrid key exchange]
B --> C[Validate performance in staging]
C --> D[Promote to production]
D --> E[Certificate migration track]
E --> F[Dual-stack issuance]
F --> G[Deprecate classical-only path]
style A fill:#f0f0f0
style G fill:#d4edda
Figure 1. The two-track PQC migration. Key exchange (top half) runs first because it addresses harvest-now, decrypt-later; certificate signature migration (bottom half) can proceed in parallel once the key exchange track is stable. The goal state is G, where classical-only clients are explicitly unsupported.
The hybrid approach bridges the gap between “deployed today” and “fully PQC.” In a hybrid handshake, the client and server perform both a classical key exchange (X25519) and a post-quantum key exchange (ML-KEM-768), and the session secret is derived from both shared secrets combined. A classical break is insufficient to compromise the session because the ML-KEM shared secret contributes to the key derivation. A quantum break on the ML-KEM side is also insufficient because X25519 is still there. The hybrid is strictly stronger than either alone.
The IETF group name for this combination is X25519MLKEM768, and it is supported in OpenSSL 3.5 and BoringSSL as of early 2025.
Worked example: enabling hybrid key exchange
The examples below use nginx backed by OpenSSL 3.5. The same group name works in Go’s crypto/tls when the standard library adds ML-KEM support, and in BoringSSL-backed servers. The ssl_ecdh_curve directive takes a colon-separated list; order signals preference. X25519MLKEM768 first means hybrid is preferred; X25519 as a fallback ensures older clients that do not support the group still negotiate a classical handshake. On OpenSSL 3.x you can also set groups via ssl_conf_command Groups X25519MLKEM768:X25519;, which is the modern alternative to ssl_ecdh_curve and works with any OpenSSL 3.x provider that exposes the group.
# nginx.conf (TLS 1.3 block)
server {
listen 443 ssl;
ssl_protocols TLSv1.3;
# Prefer hybrid PQC; fall back to classical for older clients
ssl_ecdh_curve X25519MLKEM768:X25519;
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
ssl_session_timeout 1d;
ssl_session_tickets off;
}
To verify that a client is actually negotiating X25519MLKEM768, use testssl.sh with the --groups flag or inspect the ClientHello with Wireshark. The supported_groups extension should list X25519MLKEM768 when a PQC-capable client connects. You can also probe with openssl s_client:
# Verify hybrid negotiation from a PQC-capable client
openssl s_client \
-connect your.endpoint:443 \
-groups X25519MLKEM768:X25519 \
-tls1_3 \
2>&1 | grep -E "Server Temp Key|group"
If the server and client both support X25519MLKEM768, the output should show the hybrid group in the negotiated key exchange. If it falls back to X25519, the server config is not exposing the hybrid group or the OpenSSL version does not include ML-KEM.
For services behind a managed CDN, Cloudflare and AWS CloudFront have offered hybrid PQC in preview configurations. Enabling it at the CDN edge does not require touching your origin TLS stack, which makes the CDN path the lowest-friction first step for teams that do not directly manage TLS termination.
Figure 2 shows how the hybrid handshake fits into the TLS 1.3 flow.
sequenceDiagram
participant C as Client
participant S as Server
C->>S: ClientHello (supported_groups: X25519MLKEM768, X25519)
S->>C: ServerHello (selected: X25519MLKEM768)
Note over C,S: Both parties run X25519 + ML-KEM-768 key exchange
S->>C: {EncryptedExtensions, Certificate, CertificateVerify, Finished}
C->>S: {Finished}
Note over C,S: Session key = KDF(X25519_secret || ML-KEM_secret)
Figure 2. Hybrid TLS 1.3 handshake using X25519MLKEM768. The key to notice is that both X25519 and ML-KEM key exchange happen in the same ClientHello/ServerHello exchange, with the session key derived from both shared secrets, so a break of either algorithm alone is insufficient.
The hard part: handshake overhead and when it matters
ML-KEM has a larger handshake footprint than X25519. The ML-KEM-768 public key is 1,184 bytes and the ciphertext is 1,088 bytes. Together they add roughly 1.5 KB to the handshake compared to the 32-byte X25519 public key. This matters in specific situations and is negligible in others.
Where it matters: high-QPS endpoints with no session resumption, mobile clients on constrained networks (especially those where TCP initial congestion windows are small), and any service where fresh handshakes dominate the traffic pattern, such as short-lived API calls with per-request connection setup.
Where it does not matter: services with session resumption enabled (TLS session tickets or session IDs) carry PQC overhead only on the initial handshake, not on resumptions. L7 load balancers that terminate TLS and pool connections to the origin do the PQC work once per client connection, not per upstream request.
Before promoting any PQC config to production, measure handshake latency at p95 and p99 under realistic load in a staging environment. The right comparison is not average latency, it is tail latency under concurrency, because PQC key generation is slightly more CPU-intensive than X25519 and the effect shows up in the tail under load, not the median.
If you see a meaningful increase in tail latency for fresh handshakes, the first compensating controls to reach for are longer session lifetimes, TLS session tickets if you are not already using them, and connection pooling at the client. These reduce the fraction of requests that pay the full handshake cost. Do not assume the overhead is prohibitive before measuring. Benchmarks published by the OpenSSL project and academic evaluations consistently show ML-KEM-768 is fast enough for general web traffic, but your specific service topology is what determines actual impact.
Certificate signature migration
Key exchange migration and certificate signature migration share the same goal but have different tooling maturity. As of May 2026, the key exchange side is production-ready in mainstream TLS stacks. The certificate side is still catching up.
The leading candidates for post-quantum certificate signatures are ML-DSA-44 and ML-DSA-65 from FIPS 204. The challenge is that ML-DSA signatures and public keys are significantly larger than ECDSA equivalents. An ML-DSA-65 signature is around 3,309 bytes; an ECDSA P-256 signature is 64 bytes. Certificate chains carrying ML-DSA signatures can exceed the TCP initial congestion window, which causes extra round trips on fresh connections and can break TLS stacks that apply strict limits on handshake size.
The practical approach for 2026 is dual certificate stacks. Serve classical ECDSA certificates to clients that have not signaled PQC support, and serve ML-DSA certificates to clients that advertise PQC signature algorithm support via the TLS signature_algorithms extension. nginx and most commercial load balancers do not yet support dual certificate selection based on the signature algorithms extension natively, so this typically requires an intermediary or a custom TLS termination layer that can inspect the ClientHello before selecting a certificate.
# Check what signature algorithms a client advertises
# (using openssl s_server on a test listener)
openssl s_server \
-accept 4433 \
-cert server-ecdsa.crt \
-key server-ecdsa.key \
-tls1_3 \
-msg 2>&1 | grep -A 5 "signature_algorithms"
Most ACME clients and CA integrations do not yet automate dual issuance. Expect to manage dual certificate issuance with scripting or a certificate management platform that has added explicit PQC support. HashiCorp Vault’s PKI secrets engine and Smallstep step-ca are two open-source options that have begun adding PQC certificate support; verify the current state of their ML-DSA support against your target version before committing to either.
HSM support is the other constraint. If your private keys live in a hardware security module, check your HSM vendor’s roadmap for ML-KEM and ML-DSA firmware support. HSM firmware updates for PQC support commonly lag software library support by several months to over a year. Migrating certificate keys while the HSM cannot generate ML-DSA keys means either keeping classical keys in the HSM longer than desired or temporarily moving key material to software, both of which involve tradeoffs your security policy needs to explicitly address.
Integration and day-to-day
Figure 3 shows the operational picture once hybrid key exchange is live, including the monitoring signals worth watching.
flowchart LR
Clients["Clients\n(PQC-capable + legacy)"] --> LB["TLS termination\n(nginx / CDN)"]
LB --> Origin["Origin services"]
LB --> Metrics["Metrics pipeline"]
Metrics --> Alert["Alerts:\n- Handshake error rate\n- p99 TLS latency\n- PQC negotiation ratio"]
Alert --> Eng["On-call engineer"]
style Alert fill:#fff3cd
Figure 3. Operational monitoring for a hybrid PQC deployment. The PQC negotiation ratio tells you what fraction of clients are using X25519MLKEM768 versus falling back to X25519. Tracking it over time shows you when the ecosystem has shifted enough to consider deprecating the classical fallback.
The metric worth adding to your TLS observability is the negotiation ratio: what fraction of handshakes are using X25519MLKEM768 versus falling back to X25519. nginx does not expose this directly, but you can extract it from access logs by logging $ssl_curve (or the equivalent for your TLS stack) and aggregating in your metrics pipeline. Watching this ratio over time tells you when the client ecosystem has shifted enough that deprecating the classical fallback becomes reasonable.
Handshake error rate and p99 TLS latency should be on your standard runbook for any TLS configuration change, including the hybrid group addition. Set a baseline before the change and alert on regression relative to that baseline, not relative to an absolute threshold. The absolute threshold for “acceptable TLS latency” varies too much by service topology to be useful as a general rule.
On the certificate side, once dual issuance is running, add a check to your certificate rotation automation that validates both the ECDSA and ML-DSA chains on each renewal. Dual issuance doubles the surface area for rotation failures.
Related work
Pure PQC without a classical hybrid is technically possible with OpenSSL 3.5 using ssl_ecdh_curve MLKEM768; without X25519. Do not do this yet. A client that does not support MLKEM768 cannot fall back gracefully, and the browser ecosystem has not reached the point where you can safely assume PQC support universally. The hybrid is specifically designed for the current transition window. Pure PQC is the eventual steady state, not the 2026 step.
WireGuard and IPsec are seeing parallel PQC efforts. The IETF has active work on post-quantum key exchange for IKEv2 (the Internet Key Exchange protocol used by IPsec). If you run VPNs alongside TLS services, those need their own migration track, separate from what is described here. WireGuard does not natively support PQC key exchange as of May 2026; community projects like wireguard-pqc exist but are not production-ready for most use cases.
Signal Protocol has already completed a PQC key exchange migration, shipping PQXDH (Post-Quantum Extended Diffie-Hellman) in 2023. The Signal implementation is a useful reference for how a high-volume messaging system handled the transition. Their published design documents describe the tradeoffs between key exchange performance and forward secrecy that apply to any harvest-now, decrypt-later defense.
CNSA 2.0 (Commercial National Security Algorithm Suite 2.0) from NSA specifies ML-KEM and ML-DSA as mandatory for national security systems by 2030. If your systems handle classified data or work with the US government, CNSA 2.0 timelines may be binding. For commercial systems, the NIST FIPS standards are the operative reference.
Where it breaks
Clients that do not support TLS 1.3. ML-KEM is a TLS 1.3 primitive. Any client still negotiating TLS 1.2 will fall back to classical key exchange regardless of your server configuration. Before deprecating classical key exchange, audit your TLS version distribution. Older mobile clients, embedded devices, and some enterprise proxies are common sources of TLS 1.2 traffic that persists longer than teams expect.
HSM firmware gaps. If your HSM does not support ML-KEM or ML-DSA, you cannot complete the migration without either a firmware update or a change in your key management architecture. HSM vendor timelines vary, and enterprise HSM firmware qualification processes can take months even after the vendor ships an update. Audit your HSM estate early and open the vendor conversation before you need the firmware to be ready.
Intermediate CAs and certificate chain validation. A server certificate signed by an ML-DSA intermediate CA requires the client’s certificate validation stack to support ML-DSA signature verification. Browser and OS root store updates for PQC trust anchors are still rolling out as of May 2026. A self-signed ML-DSA certificate or an ML-DSA certificate from a CA that is not yet in trust stores will fail validation on most clients. For internal services with controlled PKI this is manageable; for public-facing services, wait for broader trust store support before serving ML-DSA certificates to general-purpose browsers.
Proxies and middleboxes that inspect TLS. Corporate proxies, DLP appliances, and network inspection tools that do TLS interception need to support the PQC groups and signature algorithms to re-encrypt traffic correctly. A middlebox that does not support ML-KEM will either fail the handshake or silently downgrade to a classical group. Inventory your network path for TLS-intercepting middleboxes before assuming a hybrid handshake reaches the client intact.
Performance on constrained hardware. ML-KEM key generation is faster than RSA key generation but slightly slower than X25519 on some embedded or constrained processors. If you run TLS on IoT devices, edge compute nodes with limited CPU, or anything that is not a standard server or mobile device, benchmark ML-KEM performance on that specific hardware. The overhead is often acceptable but is not uniform across architectures.
Metric incompleteness for negotiation tracking. Most TLS termination layers do not expose PQC-specific metrics out of the box. You may need to parse access logs or add custom instrumentation to track the negotiation ratio, hybrid error rates, or per-group handshake latency. Without this visibility, you are flying blind on how the migration is progressing and whether the fallback to classical is being triggered at unexpected rates.
Further reading
The NIST PQC project page [1] is the authoritative source for FIPS 203, 204, and 205 and their associated documentation. The IETF TLS working group drafts on hybrid key exchange [2] describe the protocol-level design of X25519MLKEM768. OpenSSL’s provider documentation [3] covers how ML-KEM is exposed via the provider API in OpenSSL 3.x. The testssl.sh project [4] is the most practical tool for validating what your server actually negotiates. For the certificate migration side, the IETF LAMPS working group [5] is where ML-DSA certificate profiles are being standardized. The Signal PQXDH design document [6] is the clearest published account of a production PQC key exchange migration from a high-volume system. NSA’s CNSA 2.0 guidance [7] covers timelines and algorithm requirements for national security systems. The Cloudflare research blog post on post-quantum TLS deployment [8] is a useful practitioner account of the handshake overhead tradeoffs at CDN scale. For the underlying ML-KEM specification, read the FIPS 203 document directly [9] rather than secondary summaries. The IETF RFC on TLS 1.3 [10] (RFC 8446) is the baseline for understanding what the hybrid extension adds and where it fits in the handshake. The OQS (Open Quantum Safe) project [11] maintains liboqs and integrations with OpenSSL and other stacks for experimentation. For HSM considerations, the PKCS#11 PQC draft extensions [12] describe the evolving standard for how PQC operations will be exposed through the standard HSM interface.
Written with AI assistance, editorially reviewed.
References
[1] NIST, “Post-Quantum Cryptography Standardization.” https://csrc.nist.gov/projects/post-quantum-cryptography
[2] D. Stebila, S. Fluhrer, S. Gueron, “Hybrid key exchange in TLS 1.3.” IETF Draft. https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/
[3] OpenSSL Project, “OpenSSL 3.x Provider Documentation.” https://www.openssl.org/docs/man3.0/man7/provider.html
[4] testssl.sh project, “Testing TLS/SSL encryption.” https://testssl.sh/
[5] IETF LAMPS Working Group, “Internet PKI and ML-DSA.” https://datatracker.ietf.org/wg/lamps/documents/
[6] Signal Messenger, “The PQXDH Key Agreement Protocol.” https://signal.org/docs/specifications/pqxdh/
[7] NSA, “Commercial National Security Algorithm Suite 2.0.” https://media.defense.gov/2022/Sep/07/2003071834/-1/-1/0/CSA_CNSA_2.0ALGORITHMS.PDF
[8] Cloudflare Research, “Post-quantum TLS is now generally available.” https://blog.cloudflare.com/tag/post-quantum/
[9] NIST, “FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard.” https://csrc.nist.gov/pubs/fips/203/final
[10] E. Rescorla, “The Transport Layer Security (TLS) Protocol Version 1.3.” RFC 8446, August 2018. https://www.rfc-editor.org/rfc/rfc8446
[11] Open Quantum Safe Project, “liboqs and OQS-OpenSSL.” https://openquantumsafe.org/
[12] OASIS PKCS#11 Technical Committee, “PKCS #11 Specification.” https://www.oasis-open.org/committees/pkcs11/