Skip to content

no-mlkem

TLS 1.3 works, but the server doesn’t negotiate ML-KEM. Either its TLS library is too old to have it, or the group list in its config leaves it out.

This was 61.3% of the non-post-quantum origins in the study: 2,108 of 3,439.

  • The classical TLS 1.3 hello (probe 1) gets a ServerHello.
  • Offered only an X25519MLKEM768 key share (probe 2), the server asks the client to retry with a classical group, usually X25519.
  • It doesn’t steer clients to NIST curves. That would be pinned-nist.
  1. Upgrade the TLS library. Hybrid PQ (X25519MLKEM768) ships in OpenSSL 3.5+, current BoringSSL and AWS-LC, Go 1.24+, and rustls with aws-lc-rs.
  2. If the groups are set by hand, put X25519MLKEM768 first:
# nginx, on OpenSSL 3.5+
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1;
// Go 1.24+: the default includes X25519MLKEM768
cfg.CurvePreferences = nil

pqdoctor prints the version for the stack it detects. Every server’s lines are on Fixes by server. If you can’t upgrade, there’s the Cloudflare Tunnel fallback.

The fix lab ran real servers with this fault. pqdoctor reported each one not post-quantum, and the fix it printed made each one post-quantum:

Server Fix applied After
OpenSSL 3.5, groups X25519:P-256 ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1 PQ
Node, ecdhCurve set to X25519 ecdhCurve: 'X25519MLKEM768:X25519:P-256' PQ
Go without ML-KEM (GODEBUG=tlsmlkem=0, pre-1.24 behaviour) Go 1.24+ defaults (CurvePreferences = nil) PQ
Go with CurvePreferences X25519, P-256 Remove CurvePreferences PQ
SMTP, IMAP STARTTLS with pinned groups The Postfix / Dovecot group list PQ

Server software named in the Server header for no-mlkem origins: unknown 1,030, nginx 600, apache 225, aws 151, envoy 30. The header is often missing, so “unknown” is large.

Terminal window
openssl s_client -connect example.com:443 -servername example.com -groups X25519MLKEM768 </dev/null 2>&1 | grep -i 'group'