import java.io.DataInputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; /** * How big is the TLS ClientHello this JDK sends? * *
A plain TCP server accepts the connection, reads the first TLS record header (5 bytes: type, * version, 2-byte length) and then the record body, and reports the length. The client handshake * never completes, and does not need to. Post-quantum key shares are large: this is the number that * decides whether a hello still fits in one network packet. Explained in docs/04-post-quantum-tls.md. */ public class ClientHelloSize { public static void main(String[] args) throws Exception { try (ServerSocket listener = new ServerSocket(0, 1, InetAddress.getLoopbackAddress())) { Thread client = new Thread(() -> { try (SSLSocket s = (SSLSocket) SSLSocketFactory.getDefault() .createSocket(InetAddress.getLoopbackAddress(), listener.getLocalPort())) { s.setSoTimeout(1_000); s.startHandshake(); // will time out: nobody answers } catch (Exception expected) { // the server side closes without replying } }); client.start(); try (Socket raw = listener.accept()) { DataInputStream in = new DataInputStream(raw.getInputStream()); int type = in.readUnsignedByte(); int version = in.readUnsignedShort(); int length = in.readUnsignedShort(); byte[] body = new byte[length]; in.readFully(body); System.out.printf("java.version = %s%n", System.getProperty("java.version")); System.out.printf("record type = 0x%02x (0x16 = handshake)%n", type); System.out.printf("ClientHello record = %d bytes (+5 byte record header)%n", length); System.out.printf("fits one TCP segment = %s (1460-byte MSS on a 1500-byte MTU)%n", length + 5 <= 1460 ? "yes" : "NO"); } client.join(); } } }