How Chromium Negotiates Post-Quantum Keys in TLS 1.3

This article provides a technical overview of how the Chromium web browser negotiates post-quantum key encapsulation mechanisms (KEMs) during a TLS 1.3 handshake. It covers Chromium's implementation of a hybrid cryptographic approach via its BoringSSL library, the specific extension data transmitted in the client and server hello messages, how the classical and post-quantum shared secrets are combined, and how the browser seamlessly falls back to classical cryptography when communicating with legacy servers.

The Hybrid Cryptographic Approach

Chromium does not rely solely on post-quantum algorithms for securing TLS 1.3 connections. Instead, it uses a hybrid key exchange mechanism that pairs a classical elliptic curve algorithm (X25519) with a NIST-standardized post-quantum lattice-based KEM (ML-KEM-768, formerly known as Kyber-768).

This hybrid approach ensures that the connection remains secure as long as at least one of the two algorithms remains unbroken. It protects data transmitted today against future "harvest now, decrypt later" attacks by quantum computers, without sacrificing the proven security of existing elliptic curve cryptography.

Step 1: The ClientHello Message

The negotiation begins when Chromium initiates a TLS 1.3 handshake by sending a ClientHello message to the server. To negotiate the post-quantum hybrid key exchange, Chromium populates two specific TLS extensions:

  1. supported_groups Extension: Chromium lists the cryptographic groups it supports in order of preference. It places the hybrid identifier (such as X25519MLKEM768 using code point 0x11EC, or the earlier draft X25519Kyber768Draft00 using code point 0x6399) at the top of the list, followed by classical groups like standard X25519 (0x001D) and secp256r1.
  2. key_share Extension: TLS 1.3 optimizes handshake speed by having the client guess which algorithms the server supports and sending the corresponding public keys immediately. Chromium generates and sends two key shares in the initial ClientHello: the hybrid public key (which consists of a 32-byte X25519 public key concatenated with a 1,184-byte ML-KEM-768 public key) and a standalone 32-byte X25519 public key.

By sending both key shares upfront, Chromium avoids an extra network round-trip if the server does not support the post-quantum hybrid algorithm.

Step 2: Server Processing and Fallback

When the server receives the ClientHello, it evaluates the supported_groups and key_share extensions. There are two primary outcomes:

  • Post-Quantum Negotiation Succeeds: If the server supports the hybrid KEM, it selects the hybrid code point. The server generates its own ephemeral X25519 key pair to compute the classical shared secret. Simultaneously, it uses the client's ML-KEM-768 public key to encapsulate a randomly generated post-quantum shared secret, producing a ciphertext. The server responds with a ServerHello message containing a key_share extension that holds its 32-byte X25519 public key concatenated with the 1,088-byte ML-KEM-768 ciphertext.
  • Fallback to Classical Cryptography: If the server does not recognize the hybrid code point, standard TLS 1.3 protocol rules dictate that the server simply ignore the unknown identifier. The server moves down the client's preference list, sees the classical X25519 group, and uses the standalone X25519 key share that Chromium already provided in the ClientHello. The handshake completes using classical cryptography without any connection failures or delays.

Step 3: Secret Combination and Key Derivation

When the post-quantum negotiation succeeds and Chromium receives the ServerHello, it extracts the server's hybrid key_share data and splits it into its two components: the classical public key and the post-quantum ciphertext.

Chromium's BoringSSL library then performs two mathematical operations:

  1. It executes a standard Diffie-Hellman operation using its private X25519 key and the server's public X25519 key, yielding a 32-byte classical shared secret.
  2. It decapsulates the server's ML-KEM-768 ciphertext using its private ML-KEM-768 key, yielding a 32-byte post-quantum shared secret.

Chromium concatenates these two outputs together to form a single 64-byte combined shared secret. This 64-byte value is then fed directly into the standard TLS 1.3 HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as the key exchange input. From this point onward, the rest of the TLS 1.3 handshake—including certificate verification and the generation of symmetric encryption keys (such as AES-GCM or ChaCha20-Poly1305) for bulk data transfer—proceeds identically to a standard TLS 1.3 connection.