QUIC packet headers can be separated into long form and short form headers. Long form headers are used for version negotiation, connection establishment, and public reset packets. Short form headers are version-specific, and are used for 1-RTT packets, minimizing their header size.
While all packets are identified using the same Type octet, headers are separated into the two categories for two reasons: (i) short form headers are only used after version negotiation and establishment of 1-RTT keys, and (ii) editorial convenience.
This formulation eschews specific bits indicating the presence of various fields in favor of an octet indicating one of 256 packet types. Of these 256 types, this version defines and uses only 18: 6 with long-form headers for the initial phase of the connection, and 12 with short-form headers for after the version negotiation and 1-RTT keys are established.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+
| Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Connection ID +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Packet Number / Proof |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
These long-form headers are used for anything that doesn't have 1-RTT packet protection and prior to the completion of version negotiation. Once both conditions are met, a sender may switch to sending short-form headers. While inefficient, long headers may also be used for 1-RTT packets. The long form allows for special packets, such as the version negotiation and the public reset packets to be represented in this uniform fixed-length packet format.
- Octet 0: Packet Type
- 39: Version Negotiation packet
- 3a: Public Reset packet
- 3d: 0-RTT packet
- 3e: Server cleartext packet
- 3f: Client cleartext packet
- 1c: 1-RTT packet with version field, connection ID, and 2-byte packet number
The remainder of the packet layout is the same regardless of type, the difference being what rules for how to fill the values out and their semantics.
A client cleartext packet (type = 0x3c) then contains:
- Octets 1-8: connection ID (initially randomly chosen)
- Octets 9-12: version
- Octets 13-16: packet number (low 4 octets, starts at a random 31-bit value)
- Octets 17+: payload
The client MUST choose a random value and use it as the Connection ID until the server replies with a server-selected connection ID. The client's connection ID would have no semantic value, though they might serve to provide proof that the server received the packet via echoing, see below.
A server cleartext packet (type = 0x3e) contains:
- Octets 1-8: connection ID (server-selected value)
- Octets 9-12: version (echoed)
- Octets 13-16: packet number (low 4 octets, random 31-bit initial value)
- Octets 17+: payload
Both 0-RTT and 1-RTT packets with long-form headers contain:
- Octets 1-8: connection ID (server-selected value)
- Octets 9-12: version
- Octets 13-16: packet number (low 4 octets)
- Octets 17+: payload
A version negotiation packet contains:
- Octets 1-8: connection ID (server-selected value, may be used in a subsequent connection to reach the same server)
- Octets 9-12: version (echoed)
- Octets 13-16: proof (first 4 octets of client-selected connection ID)
- Octets 17+: payload = version list
A public reset packet is sent when the server has no state for a received packet. A server may therefore have to respond to either a long-form or a short-form packet. A public reset packet contains:
- Octets 1-8: connection ID (server-selected value)
- Octets 9-12: version
- Octets 13-16: proof (octets 1-5 of received packet)
Echoing details from the packet in both version negotiation and public reset provides return routeability (#244), while maintaining a consistent header shape for all packets.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+
| Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Connection ID (optional) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Packet Number (1/2/4) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The short form header is used after the version and 1-RTT keys are negotiated. The short form header is defined to be specific to a version. In this version, bit 0 of the first octet (i.e., 0x80) is used as the key phase bit, resulting in the following packet types.
- Octet 0: Packet Type
- 04 and 84: 1-RTT packet (packet number size = 1)
- 14 and 94: 1-RTT packet (packet number size = 2)
- 34 and b4: 1-RTT packet (packet number size = 4)
- 0c and 8c: 1-RTT packet with Connection ID (packet number size = 1)
- 1c and 9c: 1-RTT packet with Connection ID (packet number size = 2)
- 3c and bc: 1-RTT packet with Connection ID (packet number size = 4)
Let me articulate the requirements: