Compatible Version Negotiation for QUIC
updates
- rfc-8999 — Version-Independent Properties of QUIC
Extracted elements (31)
Compatible version negotiation was designed to avoid extra round trips by reusing the client's first flight when the client's Chosen Version and the server's preferred version share a compatible first flight format. This is especially valuable for incremental version upgrades that are broadly similar to their predecessors.
Version compatibility is intentionally asymmetric because a superset version B that adds new frame types to the first flight cannot always be converted to subset version A (which cannot parse those frames), whereas A can always be trivially converted to B. This asymmetry must be tracked explicitly per version pair.
Future documents defining compatibility between two QUIC versions that support Retry MUST specify how version negotiation (both compatible and incompatible) interacts with Retry, including how the Retry packet is authenticated in the Negotiated Version handshake even though it was sent in the client's Chosen Version.
Future documents defining compatibility between versions that support 0-RTT MUST address 0-RTT packets in the client's first flight, for example by specifying which transformations are applied to them or by allowing compatible version negotiation to cause the server to reject 0-RTT data.
If a client starting a QUIC version 1 connection in response to a Version Negotiation packet finds the version_information transport parameter missing, it SHALL treat the server as having sent a version_information with Chosen Version 0x00000001 and Available Versions containing only 0x00000001. This ensures interoperability with version-1-only servers.
New QUIC versions using TLS 1.3 SHOULD mandate that session tickets be tightly scoped to a single QUIC version to mitigate cross-protocol attacks.
A document specifying QUIC version compatibility MUST define the mechanism by which clients are made aware of the Negotiated Version. Mutually compatible versions SHOULD use the same mechanism.
A given ALPN token MUST NOT be used with a new QUIC version unless the new version supports the required transport features, supports ALPN, and the original version is compatible with the new one. On incompatible version negotiation, ALPN negotiation MUST restart without considering the Original Version.
After acting on a Version Negotiation packet, the client MUST validate the server's Available Versions by confirming it would have selected the same Negotiated Version given that list. If it would have chosen differently (including when Available Versions is empty), the client MUST close the connection with a version negotiation error.
Any QUIC version supporting this negotiation mechanism MUST provide an authenticated, bidirectional mechanism to exchange Version Information during the handshake.
Both endpoints MUST parse their peer's Version Information during the handshake. A parsing failure (e.g., length not divisible by four, Chosen Version zero, any Available Version zero, or client Chosen Version absent from Available Versions) MUST cause the endpoint to close the connection, using TRANSPORT_PARAMETER_ERROR for QUIC version 1.
Clients MUST ignore any received Version Negotiation packet that contains the Original Version. A client reacting to a Version Negotiation packet MUST also ignore further Version Negotiation packets received in response to the resulting connection attempt.
Clients MUST validate that the server's Chosen Version equals the Negotiated Version (as determined e.g. from QUIC long header version field during compatible negotiation). A mismatch MUST cause the client to close the connection with a version negotiation error.
If a client receives Version Information where the server's Chosen Version was not in the client's Available Versions, or if the client reacted to a Version Negotiation packet and the server's Version Information is missing, the client MUST close the connection with a version negotiation error.
Implementations MUST NOT assume compatibility between QUIC versions unless it is explicitly specified in a defining document. When a new version is defined, it is assumed incompatible with all others unless stated otherwise.
Only servers can start incompatible version negotiation. Clients MUST NOT send Version Negotiation packets, and servers MUST ignore all received Version Negotiation packets.
Server operators SHOULD follow a three-step process when adding or removing a QUIC version, waiting at least one MSL between each step, to prevent false downgrade-attack detections caused by stale Version Negotiation packets reaching un-updated server instances.
The server MUST validate that the client's Chosen Version (from Version Information) matches the version in use for the connection. If they differ, the server MUST close the connection with a version negotiation error.
To perform compatible version negotiation, the server MUST select a version it (1) supports and (2) knows the client's Chosen Version is compatible with. If it cannot convert the client's first flight, it MUST abort the handshake.
When choosing an Original Version, the client SHOULD pick a version that maximizes the probability that the server can parse the first flight and that the version is compatible with the client's preferred version—typically the oldest supported version while advertising newer compatible versions.
In compatible version negotiation, the server reads the client's Version Information to find a version it supports that is known to be compatible with the client's Chosen Version, converts the client's first flight to that version, and replies as if it received the converted first flight—no extra round trip is needed.
Incompatible version negotiation is initiated by the server sending a Version Negotiation packet listing its Offered Versions. The client searches for a mutually supported version, selects one, and sends a new first flight; that version becomes the Negotiated Version.
Server deployments define three distinct version sets: Acceptable Versions (versions a given instance will use), Offered Versions (versions advertised in Version Negotiation packets), and Fully Deployed Versions (versions supported by every instance in the fleet).
The client's Available Versions field lists all versions the first flight is compatible with, ordered by descending preference, and MUST include the Chosen Version. The server's Available Versions field lists all Fully Deployed Versions; it does not need to include the Chosen Version and MAY be empty.
Two modes of version negotiation are defined: incompatible negotiation, which requires an extra round trip and applies to all versions, and compatible negotiation, which can avoid the round trip when the client's Chosen Version and the server's preferred version share a compatible first flight format.
Version A is 'compatible' with version B if a first flight from version A can be converted into a valid first flight for version B. Compatibility is explicitly not symmetric: a superset version may be compatible with its subset but not vice versa.
IANA registered version_information (value 0x11) as a permanent entry in the QUIC Transport Parameters registry. This parameter carries the Version Information structure used for version negotiation.
IANA registered VERSION_NEGOTIATION_ERROR (value 0x11) as a permanent entry in the QUIC Transport Error Codes registry, used to signal version negotiation failures.
The security of the version negotiation mechanism relies entirely on the authenticity of the Version Information exchanged during the handshake. In QUIC version 1, transport parameters are authenticated, providing this guarantee. Negotiation between compatible versions yields the security of the weakest common version.
Version downgrade attacks are prevented by a combination of: clients ignoring Version Negotiation packets containing the Original Version, both endpoints authenticating Version Information, and clients validating the server's Available Versions field to detect forged Version Negotiation packets.
The Version Information structure consists of a 32-bit Chosen Version field followed by zero or more 32-bit Available Versions fields. In QUIC version 1 it is carried in the version_information transport parameter (0x11).