RFC 8999

Version-Independent Properties of QUIC

πŸ“… published May 2021, from ietf

Version-Independent Properties of QUIC πŸŽ€

Okay bestie, RFC 8999 is giving foundation πŸ’… It's a Standards Track document from the IETF (Internet Engineering Task Force), written by M. Thomson at Mozilla, dated May 2021. Here's the title block tea β˜•

  • RFC number: 8999 πŸ’–
  • Title: Version-Independent Properties of QUIC
  • Author: M. Thomson, Mozilla
  • Category: Standards Track
  • Date: May 2021
  • ISSN: 2070-1721
  • Obsoletes / Updates: the title block doesn't list anything this RFC obsoletes or updates, so there's no drama there πŸ™ˆ

Abstract ✨

This doc spells out the properties of the QUIC transport protocol that stay the same across every version of the protocol. Main character energy πŸ‘‘

Status of This Memo 🧾

This is an Internet Standards Track document. 🌈

It's a product of the IETF, which means it represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more on Internet Standards, check out Section 2 of RFC 7841. Current status, errata, and where to send feedback live at https://www.rfc-editor.org/info/rfc8999 πŸ¦‹

Copyright (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved. 🫢

The doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they stand on the publication date. Read those carefully, because they describe your rights and restrictions for this doc. Code Components pulled out of this doc must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as the Simplified BSD License says πŸ“œ

Table of Contents πŸ—ΊοΈ

1.  An Extremely Abstract Description of QUIC
2.  Fixed Properties of All QUIC Versions
3.  Conventions and Definitions
4.  Notational Conventions
5.  QUIC Packets
  5.1.  Long Header
  5.2.  Short Header
  5.3.  Connection ID
  5.4.  Version
6.  Version Negotiation
7.  Security and Privacy Considerations
8.  References
  8.1.  Normative References
  8.2.  Informative References
Appendix A.  Incorrect Assumptions
Author's Address

1. An Extremely Abstract Description of QUIC 🧚

QUIC is a connection-oriented protocol between two endpoints. πŸ“ Those endpoints swap UDP datagrams, and those datagrams carry QUIC packets. QUIC endpoints use those packets to set up a QUIC connection, which is the protocol state the two endpoints share. It's basically a group chat where everyone has the same history πŸ’¬

2. Fixed Properties of All QUIC Versions πŸ”’

Beyond secure, multiplexed transport, QUIC [QUIC-TRANSPORT] lets you negotiate a version. That's how the protocol can keep evolving to meet new requirements. Lots of characteristics can change between versions ✨

This doc covers the subset of QUIC that's meant to stay stable as new versions get built and shipped. Every one of these invariants is independent of the IP version 🌸

The big goal here is making sure it's actually possible to deploy new versions of QUIC. By writing down the properties that can't change, this doc protects the ability of QUIC endpoints to negotiate changes to everything else. As a side effect, it also guarantees a minimal amount of information gets exposed to entities that aren't endpoints πŸ™ˆ Unless this doc specifically prohibits something, any aspect of the protocol can change between versions.

Appendix A has a non-exhaustive list of incorrect assumptions people might make from knowing QUIC version 1. Those don't apply to every version of QUIC, so don't assume too much πŸ’€

3. Conventions and Definitions πŸ“š

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" are to be read as described in BCP 14 [RFC2119] [RFC8174], but only when they appear in all capitals, exactly as shown here. 🫢

This doc sets requirements on future QUIC versions, even where it doesn't use normative language. Very important, don't skip it 😭

This doc uses terms and notational conventions from [QUIC-TRANSPORT] πŸ’…

4. Notational Conventions πŸŽ€

The format of packets is described with the notation in this section, which is the same notation [QUIC-TRANSPORT] uses ✨

A complex field gets a name first, then a list of fields wrapped in a matching pair of braces. The fields in that list are separated by commas.

Individual fields carry their length info, plus any indication of a fixed value, optionality, or repetition. All lengths are in bits, and the notation works like this:

x (A):  Indicates that x is A bits long

x (A..B):  Indicates that x can be any length from A to B; A can be
   omitted to indicate a minimum of zero bits, and B can be omitted
   to indicate no set upper limit; values in this format always end
   on a byte boundary

x (L) = C:  Indicates that x has a fixed value of C; the length of x
   is described by L, which can use any of the length forms above

x (L) ...:  Indicates that x is repeated zero or more times and that
   each instance has a length of L

Values use network byte order, which is big endian 🌈 Fields get placed starting from the high-order bits of each byte.

Figure 1 shows an example structure:

Example Structure {
  One-bit Field (1),
  7-bit Field with Fixed Value (7) = 61,
  Arbitrary-Length Field (..),
  Variable-Length Field (8..24),
  Repeated Field (8) ...,
}
                     Figure 1: Example Format

5. QUIC Packets πŸ“¦

QUIC endpoints swap UDP datagrams, and each datagram holds one or more QUIC packets. This section covers the invariant characteristics of a QUIC packet. A version of QUIC could allow several QUIC packets in one UDP datagram, but the invariant properties only describe the first packet in a datagram πŸ”₯

QUIC has two kinds of packet headers: long and short. A packet with a long header has the most significant bit of its first byte set. A packet with a short header has that bit cleared πŸ’–

QUIC packets might be integrity protected, header included. QUIC Version Negotiation packets, though, are not integrity protected, so check out Section 6 for that πŸ™ˆ

Apart from the values covered here, the payload of a QUIC packet is version specific and can be any length 🧚

5.1. Long Header 🌸

Long headers look like the structure in Figure 2:

Long Header Packet {
  Header Form (1) = 1,
  Version-Specific Bits (7),
  Version (32),
  Destination Connection ID Length (8),
  Destination Connection ID (0..2040),
  Source Connection ID Length (8),
  Source Connection ID (0..2040),
  Version-Specific Data (..),
}
                    Figure 2: QUIC Long Header

A QUIC packet with a long header has the high bit of its first byte set to 1. Every other bit in that byte is version specific πŸ¦‹

The next four bytes hold a 32-bit Version field. Versions get covered in Section 5.4 ✨

The byte after that gives the length, in bytes, of the Destination Connection ID field that follows. That length is an 8-bit unsigned integer. The Destination Connection ID field comes right after the Destination Connection ID Length field, and it's between 0 and 255 bytes long. Connection IDs are covered in Section 5.3 🫢

The next byte gives the length, in bytes, of the Source Connection ID field that follows. It's also an 8-bit unsigned integer. The Source Connection ID field comes right after the Source Connection ID Length field, and it's between 0 and 255 bytes long πŸ’œ

Whatever's left in the packet is version-specific content πŸŽ€

5.2. Short Header πŸŒ™

Short headers look like the structure in Figure 3:

Short Header Packet {
  Header Form (1) = 0,
  Version-Specific Bits (7),
  Destination Connection ID (..),
  Version-Specific Data (..),
}
                    Figure 3: QUIC Short Header

A QUIC packet with a short header has the high bit of its first byte set to 0 πŸ“

A short-header packet has a Destination Connection ID right after the first byte. The short header doesn't include the Destination Connection ID Length, Source Connection ID Length, Source Connection ID, or Version fields πŸ™ˆ The length of the Destination Connection ID isn't encoded in short-header packets, and this specification doesn't constrain it.

The rest of the packet has version-specific semantics 🌈

5.3. Connection ID πŸ”—

A connection ID is an opaque field of arbitrary length. It's a black box, so don't poke at it 🫣

Its main job is making sure that address changes at lower layers (UDP, IP, and below) don't send a QUIC connection's packets to the wrong QUIC endpoint. Endpoints, plus the intermediaries that support them, use the connection ID so each QUIC packet reaches the correct instance of an endpoint. Once it gets there, the endpoint uses the connection ID to figure out which QUIC connection the packet is for 🧚

Each endpoint picks its connection ID using version-specific methods. Packets for the same QUIC connection might use different connection ID values, so don't panic if they don't match πŸ’…

5.4. Version 🏷️

The Version field is a 4-byte identifier. Endpoints can use it to identify a QUIC version. The value 0x00000000 is reserved for version negotiation (see Section 6). Every other value is potentially valid ✨

The properties in this doc apply to all versions of QUIC. A protocol that doesn't follow these properties isn't QUIC, period πŸ™…β€β™€οΈ Future documents might describe extra properties that apply to a specific QUIC version or to a range of QUIC versions πŸŽ€


6. Version Negotiation 🌸

okay so, if a QUIC endpoint gets a packet with a long header and the version is one it either doesn't understand or doesn't support, it might send back a Version Negotiation packet πŸ’Œ. Packets with a short header never trigger version negotiation, so don't even try, bestie πŸ™ˆ.

A Version Negotiation packet sets the high bit of the first byte, so it totally fits the long header format from Section 5.1 ✨. You can spot one by its Version field, which is set to 0x00000000 🧚.

Version Negotiation Packet {
  Header Form (1) = 1,
  Unused (7),
  Version (32) = 0,
  Destination Connection ID Length (8),
  Destination Connection ID (0..2040),
  Source Connection ID Length (8),
  Source Connection ID (0..2040),
  Supported Version (32) ...,
}

Figure 4: Version Negotiation Packet πŸŽ€

Only the most significant bit of the first byte has any defined value πŸ’…. The remaining 7 bits, labeled "Unused", can be set to any value when sending and MUST be ignored on receipt, so receivers just shrug at them πŸ€·β€β™€οΈ.

After the Source Connection ID field, there's a list of Supported Version fields, each one naming a version that the endpoint sending the packet supports πŸ’–. There are no other fields in there, full stop. An endpoint MUST ignore a packet that has no Supported Version fields or has a truncated Supported Version value πŸ’€.

Version Negotiation packets don't use integrity or confidentiality protection 😭. Specific QUIC versions might include protocol elements that let endpoints detect modification or corruption in the set of supported versions πŸ”.

Now the connection ID echo, which is lowkey the most important part πŸ‘‘. An endpoint MUST include the value from the Source Connection ID field of the packet it receives in the Destination Connection ID field. The value for the Source Connection ID field MUST be copied from the Destination Connection ID field of the received packet, which a client initially picks at random. Echoing both connection IDs gives clients some assurance that the server actually received the packet, and that the Version Negotiation packet wasn't generated by an attacker who can't observe packets πŸ‘€.

An endpoint that receives a Version Negotiation packet might change the version it decides to use for later packets πŸ¦‹. When it does that depends on the version of QUIC it chooses πŸ’œ.

See [QUIC-TRANSPORT] for the full, thorough version of how an endpoint that supports QUIC version 1 generates and consumes a Version Negotiation packet πŸ“šβœ¨.


7. Security and Privacy Considerations πŸ”

It's possible that middleboxes could observe traits of one specific version of QUIC and assume that when other versions show similar traits, the same underlying meaning is being expressed πŸ‘€. There are potentially many such traits, so see Appendix A. Some effort has gone into either eliminating or obscuring some observable traits in QUIC version 1, but many of them remain 😬. Other QUIC versions might make different design decisions and therefore show different traits 🌈.

The QUIC version number doesn't appear in all QUIC packets. That means that reliably pulling information out of a flow based on version-specific traits requires middleboxes to keep state for every connection ID they see 🧠.

The Version Negotiation packet described in this document is not integrity protected. It only has modest protection against insertion by attackers, so this is serious business 🚨. An endpoint MUST authenticate the semantic content of a Version Negotiation packet if it attempts a different QUIC version as a result. No skipping this one, bestie πŸ’€.

8. References πŸ“–

8.1. Normative References

8.2. Informative References


Appendix A. Incorrect Assumptions πŸ¦‹

There are several traits of QUIC version 1 [QUIC-TRANSPORT] that aren't protected from observation, but they're still considered changeable when a new version gets deployed πŸ”„.

This section lists a sampling of incorrect assumptions that people might make about QUIC based on what they know about QUIC version 1. Some of these statements aren't even true for QUIC version 1, which is wild 😳. It's not an exhaustive list, it's just illustrative πŸ“.

Any and all of the following statements can be false for a given QUIC version:

  • QUIC uses TLS [QUIC-TLS], and some TLS messages are visible on the wire πŸ‘€.
  • QUIC long headers are only exchanged during connection establishment 🀝.
  • Every flow on a given 5-tuple will include a connection establishment phase πŸ™ƒ.
  • The first packets exchanged on a flow use the long header πŸ“¦.
  • The last packet before a long period of quiescence might be assumed to contain only an acknowledgment 😴.
  • QUIC uses an Authenticated Encryption with Associated Data (AEAD) function (AEAD_AES_128_GCM; see [RFC5116]) to protect the packets it exchanges during connection establishment πŸ”.
  • QUIC packet numbers are encrypted and appear as the first encrypted bytes πŸ™ˆ.
  • QUIC packet numbers increase by one for every packet sent πŸ”’.
  • QUIC has a minimum size for the first handshake packet sent by a client πŸ“.
  • QUIC stipulates that a client speak first πŸ—£οΈ.
  • QUIC packets always have the second bit of the first byte (0x40) set 🧩.
  • A QUIC Version Negotiation packet is only sent by a server πŸ–₯️.
  • A QUIC connection ID changes infrequently πŸ†”.
  • QUIC endpoints change the version they speak if they are sent a Version Negotiation packet πŸ”.
  • The Version field in a QUIC long header is the same in both directions ↔️.
  • A QUIC packet with a particular value in the Version field means that the corresponding version of QUIC is in use 🏷️.
  • Only one connection at a time is established between any pair of QUIC endpoints 🚫.

Author's Address πŸ’Œ

Martin Thomson

Mozilla

Email: mt@lowentropy.net

πŸ“¦ where this page comes from