Skip to content

Instantly share code, notes, and snippets.

@janaiyengar
Last active February 15, 2017 07:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janaiyengar/b05acb3af17d6e938d25befc69c11eae to your computer and use it in GitHub Desktop.
Save janaiyengar/b05acb3af17d6e938d25befc69c11eae to your computer and use it in GitHub Desktop.

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.

Long-Form Headers

 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.

Short Form Header

 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)
@martinthomson
Copy link

Let me articulate the requirements:

  1. we need to be able to identify all the types of packets
  2. we need to be able to identify which of the keys we use
  3. we need to be able to tell client from server for cleartext packets
  4. most packets need to be small
  5. the protocol needs to keep working

@janaiyengar
Copy link
Author

Yup, those are exactly what I worked with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment