# 4. Post-quantum hybrid key exchange in TLS 1.3 (JEP 527) Prev: [3. Compact headers](03-compact-headers.md) · Next: [5. Primitive patterns](05-primitive-patterns.md) JDK 27's default TLS 1.3 client offers the hybrid group **X25519MLKEM768** first: an ordinary X25519 exchange and an ML-KEM-768 key encapsulation combined, so a recorded session stays safe even if a large quantum computer later breaks X25519. ## Who negotiates what [`scripts/tls-pq.sh`](../scripts/tls-pq.sh) starts a loopback TLS server with [`TlsPeer`](../jep-tour/src/TlsPeer.java) on one JDK and connects with a client on the other, for all four pairings, with `-Djavax.net.debug=ssl:handshake` ([30](output/30-tls-groups-matrix.txt)). | Client | Server | Group selected | |---|---|---| | 26 | 26 | x25519 | | 27 | 27 | **X25519MLKEM768** | | 27 | 26 | x25519 (the 26 server does not know the hybrid group) | | 26 | 27 | x25519 (the 26 client never offered it) | Nothing fails when the peers disagree: the hybrid only happens when both ends are on 27 (or another stack that supports it). ## The catch: a bigger first packet [`ClientHelloSize`](../jep-tour/src/ClientHelloSize.java) captures the first TLS record ([31](output/31-tls-clienthello-size.txt)): | Client | ClientHello record | Fits one TCP segment (1460-byte MSS)? | |---|---|---| | JDK 26 | 417 bytes | yes | | JDK 27 | 1573 bytes | **no** | | JDK 27, `-Djdk.tls.namedGroups=x25519,secp256r1` | 408 bytes | yes | The ML-KEM public key alone is 1184 bytes, so the ClientHello no longer fits in one segment. Middleboxes that mishandle a ClientHello spanning segments are the known failure mode of large post-quantum ClientHellos; **that failure was not observed here** (loopback has no middleboxes). If you meet it, the opt-out is the system property above, and the client then behaves like 26 ([32](output/32-tls-opt-out.txt)). Prev: [3. Compact headers](03-compact-headers.md) · Next: [5. Primitive patterns](05-primitive-patterns.md)