TLS 1.2 vs TLS 1.3: Why the Version Actually Matters
TLS 1.3 wasn't just a performance improvement. The architectural change it made to key exchange is the reason ML-KEM can exist at all, and TLS 1.3 without ML-KEM still leaves you exposed. Both of those things are true at the same time.
At a Glance
key_share extension, a pluggable slot. Swap in any algorithm
both sides support without changing anything else.
key_share slot.
Three Things to Know
ML-KEM requires TLS 1.3. It uses the key_share extension
that only exists in TLS 1.3. If any hop in your traffic path enforces TLS 1.2 as a minimum,
ML-KEM can't negotiate, silently. No error, no fallback warning.
TLS 1.3 with X25519 (classical) is just as exposed to harvest now, decrypt later as TLS 1.2. The version protects you against classical attacks. ML-KEM is what closes the quantum gap.
When ML-KEM can't negotiate, sessions fall back to X25519 and everything works normally.
There's no log entry, no alert. The only way to confirm PQ is actually negotiating is to
run openssl s_client and check the output yourself.
| Configuration | Forward Secrecy | Quantum-Safe Key Exchange | HNDL Exposure |
|---|---|---|---|
| TLS 1.2 | Not guaranteed | No | Exposed |
| TLS 1.3 (X25519 only) | Yes, always | No | Exposed |
| TLS 1.3 + X25519MLKEM768 | Yes, always | Yes | Protected |
Why You Cannot Retrofit ML-KEM onto TLS 1.2
In TLS 1.2, the key exchange algorithm is fused into the cipher suite string. Take
ECDHE-RSA-AES128-GCM-SHA256 bundles the key exchange, authentication,
encryption, and MAC all together. Adding a new key exchange method means defining an
entirely new cipher suite, pushing it through a standards process, and waiting for
every server, browser, and library to adopt it. That was never going to happen for ML-KEM.
TLS 1.3 broke these apart. The key_share extension is a clean, dedicated slot.
Both sides advertise what they support, agree on an algorithm, and fill the slot with the
appropriate key material. The protocol doesn't care what the math underneath is.
Swap X25519 for X25519MLKEM768 and everything else stays the same. That pluggability
is what makes ML-KEM possible.
The Same Version, Different Quantum Posture
Testing with openssl s_client and advertising X25519MLKEM768
against two different CDN paths for the same domain shows the difference clearly.
One path through Cloudflare, one through F5 Distributed Cloud:
Through Cloudflare
Negotiated TLS1.3 group: X25519MLKEM768
Post-quantum key exchange confirmed. ML-KEM is on by default for TLS 1.3 zones.
Through F5 Distributed Cloud
Negotiated TLS1.3 group: x25519
TLS 1.3, but classical only. F5 Distributed Cloud doesn't yet support ML-KEM in its key_share handling.
Same domain. Same TLS version. Same cipher for data encryption. The only difference is one algorithm in one extension slot. That's the entire quantum gap.
Cloudflare TLS Settings: Two Controls, One Goal
In the Cloudflare dashboard under SSL/TLS โ Edge Certificates, there are two separate settings that both relate to TLS version. They look similar but control completely different things. Getting them confused is a common source of misconfiguration.
key_share extension โ no ML-KEM, regardless of any other setting.
TLS 1.2 is the floor and TLS 1.3 is available. Most modern browsers negotiate 1.3 and can use ML-KEM. Legacy systems fall back to 1.2. Those sessions are not quantum-safe. This is the right balance for most environments still running mixed clients.