From 42f55df78007dab2d02faf837eebed5e864d17ee Mon Sep 17 00:00:00 2001 From: EKR Date: Tue, 22 May 2018 18:08:58 -0700 Subject: [PATCH 01/31] Output of Stream 0 Design Team. See: https://docs.google.com/document/d/1fRsJqPinJl8N3b-bflDRV6auojfJLkxddT93j6SwHY8/edit for design rationale. --- draft-ietf-quic-recovery.md | 199 +++-- draft-ietf-quic-tls.md | 1431 +++++++++++----------------------- draft-ietf-quic-transport.md | 715 ++++++++++------- 3 files changed, 1034 insertions(+), 1311 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index 3310014d28..212b784e8a 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -89,12 +89,16 @@ when, and only when, they appear in all capitals, as shown here. # Design of the QUIC Transmission Machinery -All transmissions in QUIC are sent with a packet-level header, which includes a -packet sequence number (referred to below as a packet number). These packet -numbers never repeat in the lifetime of a connection, and are monotonically -increasing, which prevents ambiguity. This fundamental design decision -obviates the need for disambiguating between transmissions and -retransmissions and eliminates significant complexity from QUIC's +All transmissions in QUIC are sent with a packet-level header, which indicates +an encryption level and includes a packet sequence number +(referred to below as a packet number). The encryption level indicates the +packet number space, as described in {{QUIC-TRANSPORT}}. Packet +numbers never repeat within a packet number space for the lifetime of a +connection. Packet numbers monotonically increase within a space, +preventing ambiguity. + +This design obviates the need for disambiguating between transmissions +and retransmissions and eliminates significant complexity from QUIC's interpretation of TCP loss detection mechanisms. Every packet may contain several frames. We outline the frames that are @@ -107,7 +111,7 @@ important to the loss detection and congestion control machinery below. * Retransmittable packets are those that contain at least one retransmittable frame. -* Crypto handshake data is sent on stream 0, and uses the reliability +* Crypto handshake data is sent in CRYPTO_HS frames, and uses the reliability machinery of QUIC underneath. * ACK frames contain acknowledgment information. ACK frames contain one or more @@ -120,6 +124,17 @@ algorithms here that parallel well-known TCP ones. Protocol differences between QUIC and TCP however contribute to algorithmic differences. We briefly describe these protocol differences below. +### Separate Packet Number Spaces + +QUIC uses separate packet number spaces for each encryption level, except that +0-RTT and all generations of 1-RTT keys use the same packet number space. +Separating the spaces allows the recovery mechanisms to work without special +cases to avoid spuriously retransmitting un-processable packets. +Separate packet number spaces do not imply separate paths. Consequently, +a sender need not split congestion control actions across packet number spaces. +The optimizations described in {{optimizations}} help a sender co-ordinate +loss detection across packet number spaces. + ### Monotonically Increasing Packet Numbers TCP conflates transmission sequence number at the sender with delivery sequence @@ -130,15 +145,15 @@ number for transmissions, and any data that is to be delivered to the receiving application(s) is sent in one or more streams, with delivery order determined by stream offsets encoded within STREAM frames. -QUIC's packet number is strictly increasing, and directly encodes transmission -order. A higher QUIC packet number signifies that the packet was sent later, -and a lower QUIC packet number signifies that the packet was sent earlier. When -a packet containing frames is deemed lost, QUIC rebundles necessary frames in a -new packet with a new packet number, removing ambiguity about which packet is -acknowledged when an ACK is received. Consequently, more accurate RTT -measurements can be made, spurious retransmissions are trivially detected, and -mechanisms such as Fast Retransmit can be applied universally, based only on -packet number. +QUIC's packet number is strictly increasing within a packet number space, +and directly encodes transmission order. A higher QUIC packet number signifies +that the packet was sent later, and a lower QUIC packet number signifies that +the packet was sent earlier. When a packet containing frames is deemed lost, +QUIC rebundles necessary frames in a new packet with a new packet number, +removing ambiguity about which packet is acknowledged when an ACK is received. +Consequently, more accurate RTT measurements can be made, spurious +retransmissions are trivially detected, and mechanisms such as Fast Retransmit +can be applied universally, based only on packet number. This design point significantly simplifies loss detection mechanisms for QUIC. Most TCP mechanisms implicitly attempt to infer transmission ordering based on @@ -259,17 +274,18 @@ prone to spurious retransmissions due to its reduced reordering resilence without the alarm. This observation led Linux TCP implementers to implement an alarm for TCP as well, and this document incorporates this advancement. - ## Timer-based Detection Timer-based loss detection implements a handshake retransmission timer that is optimized for QUIC as well as the spirit of TCP's Tail Loss Probe and Retransmission Timeout mechanisms. -### Handshake Timeout +### Crypto Handshake Timeout -Handshake packets, which contain STREAM frames for stream 0, are critical to -QUIC transport and crypto negotiation, so a separate alarm is used for them. +Data in CRYPTO_HS frames is critical to QUIC transport and crypto negotiation, +so a more aggressive timeout is used to retransmit it. Below, the word +handshake packet is used to refer to packets containing CRYPTO_HS frames, +not packets with the specific long header packet type Handshake. The initial handshake timeout SHOULD be set to twice the initial RTT. @@ -280,23 +296,26 @@ connection's final smoothed RTT value as the resumed connection's initial RTT. If no previous RTT is available, or if the network changes, the initial RTT SHOULD be set to 100ms. -When a handshake packet is sent, the sender SHOULD set an alarm for the -handshake timeout period. +When CRYPTO_HS frames are sent, the sender SHOULD set an alarm for the handshake +timeout period. -When the alarm fires, the sender MUST retransmit all unacknowledged handshake -data, by calling RetransmitAllUnackedHandshakeData(). On each consecutive -firing of the handshake alarm, the sender SHOULD double the handshake timeout -and set an alarm for this period. +When the alarm fires, the sender MUST retransmit all unacknowledged CRYPTO_HS +data by calling RetransmitAllUnackedHandshakeData(). On each +consecutive firing of the handshake alarm without receiving an +acknowledgement for a new packet, the sender SHOULD double the handshake +timeout and set an alarm for this period. When an acknowledgement is received for a handshake packet, the new RTT is computed and the alarm SHOULD be set for twice the newly computed smoothed RTT. -Handshake data may be cancelled by handshake state transitions. In particular, -all non-protected data SHOULD no longer be transmitted once packet protection -is available. +#### Retry + +A RETRY packet causes the content of the client's Initial packet to be +immediately retransmitted along with the token present in the RETRY. -(TODO: Work this section some more. Add text on client vs. server, and on -stateless retry.) +The RETRY indicates that the Initial was received but not processed. +It MUST NOT be treated as an acknowledgment for the Initial, +but it MAY be used for an RTT measurement. ### Tail Loss Probe {#tlp} @@ -398,8 +417,82 @@ A packet sent on an RTO alarm MUST NOT be blocked by the sender's congestion controller. A sender MUST however count these bytes as additional bytes in flight, since this packet adds network load without establishing packet loss. +## Multiple Packet Number Space Optimizations {#optimizations} + +There are cases where one may be able to gain recovery information from +acknowledgements of packets in another packet number space, but they rely +on complex assumptions about the peer’s processing and acknowledgement +algorithms. Even those are unable to quickly recover from cases such as +losing the client's Initial, but receiving the 0-RTT packets. Below are +three different optimizations in increasing complexity that minimize +handshake latency. + +### EMPTY_ACK frames + +The EMPTY_ACK frame indicates a packet for the connection was received, +but it could not be processed, because the decryption keys are not yet +available. EMPTY_ACK enables faster recovery of lost Initial +and Handshake packets when the only other outstanding packets are +undecryptable. + +The receiver SHOULD send an EMPTY_ACK frame soon (e.g., 1ms) after +undecryptable packets are received, even if those received packets are +not buffered for later decryption. The small delay allows for cases when +0-RTT packets are reordered in front of the Initial, which is not uncommon +on networks that prioritize small packets. The receiver should limit the +number of EMPTY_ACK frames sent to one per packet number space per RTT. +If no RTT is known, only one per encryption level should be sent. + +When an EMPTY_ACK frame is received, a sender should immediately +retransmit the missing handshake packet(s) as though the handshake timer +fired and re-arm the handshake timer when the handshake packets are sent. +If the missing handshake data was timer retransmitted after the packets +that triggered the empty ack, then the empty ack should be ignored. + +An EMPTY_ACK frame does not acknowledge a new packet, and in cases +when multiple packets are outstanding, the RTT signal is ambiguous, +so it should not be used like an RTT signal from a newly acknowledged +packet. It MAY change the connection’s default RTT if no RTT measurements +have been taken. + +### Coalesced Packets + +Despite loss recovery being separate for different packet number spaces, +the ability to send a coalesced packet enables faster recovery with small, +and sometimes no overhead. The acknowledgement of a coalesced packet +allows QUIC recovery to use early retransmit to determine if any prior +packets in that space were lost without waiting for timeouts. + +This optimization is particularly useful when: + + * Sending the client’s Initial, which must be padded to a full + sized packet, so the datagram typically has extra space to retransmit + some outstanding 0-RTT data. + * The clients sends 1-RTT data soon after the final TLS flight + (containing the client Finished) and can proactively retransmit the + final client flight with one or more 1-RTT packets. + +### Implicit Acknowledgements + +Handshake data may be cancelled when packets at a higher encryption +level are processed, as this demonstrates the peer has received the +handshake data at the prior encryption level. + +In particular: + + * Processing data in a Handshake packet indicates the Initial + packet(s) have been delivered. + * A Server processing 1-RTT packets indicates all CRYPTO_HS data in + Handshake packets has been delivered. + * Processing 0-RTT packets does not indicate the peer has received + any handshake data. + ## Generating Acknowledgements +An ACK frame acknowledges packets from only one packet number space. +Received packets from each packet number space should be stored +separately while multiple spaces have outstanding data. + QUIC SHOULD delay sending acknowledgements in response to packets, but MUST NOT excessively delay acknowledgements of packets containing non-ack frames. Specifically, implementaions MUST attempt to @@ -422,6 +515,14 @@ sending any ACK frames in response. In this case they can determine whether an immediate or delayed acknowledgement should be generated after processing incoming packets. +### Crypto Handshake Data + +In order to quickly complete the handshake and avoid spurious +retransmissions due to handshake alarm timeouts, acknowledging packets +containing CRYPTO_HS frames should use a very short ack delay, such as 1ms. +ACK frames may be sent immediately when the crypto stack indicates all +data for that encryption level has been received. + ### ACK Ranges When an ACK frame is sent, one or more ranges of acknowledged packets are @@ -514,7 +615,7 @@ time_of_last_sent_retransmittable_packet: : The time the most recent retransmittable packet was sent. time_of_last_sent_handshake_packet: -: The time the most recent packet containing handshake data was sent. +: The time the most recent packet containing a CRYPTO_HS frame was sent. largest_sent_packet: : The packet number of the most recently sent packet. @@ -559,6 +660,8 @@ sent_packets: was sent, a boolean indicating whether the packet is ack only, and a bytes field indicating the packet's size. sent_packets is ordered by packet number, and packets remain in sent_packets until acknowledged or lost. + A sent_packets data structure is maintained per packet number space, and ack + processing only applies to a single space. ### Initialization @@ -627,9 +730,18 @@ Pseudocode for OnPacketSent follows: When an ack is received, it may acknowledge 0 or more packets. +When an EMPTY_ACK frame is received, it does not acknowledge +any packets, but it may cause handshake data to be retransmitted. + Pseudocode for OnAckReceived and UpdateRtt follow: ~~~ + OnEmptyAckReceived(): + // TODO: This is incorrect for the Initial/Handshake + if (time_of_last_sent_handshake_packet < + time_of_last_sent_retransmittable_packet): + RetransmitAllHandshakeData(); + OnAckReceived(ack): largest_acked_packet = ack.largest_acked // If the largest acked is newly acked, update the RTT. @@ -711,7 +823,7 @@ closed once a reject is sent, so no timer is set to retransmit the reject. Version negotiation packets are always stateless, and MUST be sent once per handshake packet that uses an unsupported QUIC version, and MAY be sent in -response to 0RTT packets. +response to 0-RTT packets. #### Tail Loss Probe and Retransmission Alarm @@ -807,18 +919,11 @@ Pseudocode for OnLossDetectionAlarm follows: ### Detecting Lost Packets -Packets in QUIC are only considered lost once a larger packet number is -acknowledged. DetectLostPackets is called every time an ack is received. -If the loss detection alarm fires and the loss_time is set, the previous -largest acked packet is supplied. - -#### Handshake Packets - -The receiver MUST close the connection with an error of type OPTIMISTIC_ACK -when receiving an unprotected packet that acks protected packets. -The receiver MUST trust protected acks for unprotected packets, however. Aside -from this, loss detection for handshake packets when an ack is processed is -identical to other packets. +Packets in QUIC are only considered lost once a larger packet number in +the same packet number space is acknowledged. DetectLostPackets is called +every time an ack is received and operates on the sent_packets for that +packet number space. If the loss detection alarm fires and the loss_time +is set, the previous largest acked packet is supplied. #### Pseudocode @@ -1084,6 +1189,10 @@ This document has no IANA actions. Yet. > **RFC Editor's Note:** Please remove this section prior to > publication of a final version of this document. +## Since draft-ietf-quic-recovery-11 + +- Text on multiple packet number spaces and relevant optimizations. + ## Since draft-ietf-quic-recovery-10 - Improved text on ack generation (#1139, #1159) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index bf7dbae3ad..328b6488e2 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -122,10 +122,8 @@ connections between the same client and server, the client can often send application data immediately, that is, using a zero round trip setup. -This document describes how the standardized TLS 1.3 acts a security -component of QUIC. The same design could work for TLS 1.2, though few of the -benefits QUIC provides would be realized due to the handshake latency in -versions of TLS prior to 1.3. +This document describes how the standardized TLS 1.3 acts as a security +component of QUIC. # Notational Conventions @@ -139,66 +137,6 @@ This document uses the terminology established in {{QUIC-TRANSPORT}}. For brevity, the acronym TLS is used to refer to TLS 1.3. -TLS terminology is used when referring to parts of TLS. Though TLS assumes a -continuous stream of octets, it divides that stream into *records*. Most -relevant to QUIC are the records that contain TLS *handshake messages*, which -are discrete messages that are used for key agreement, authentication and -parameter negotiation. Ordinarily, TLS records can also contain *application -data*, though in the QUIC usage there is no use of TLS application data. - - -# Protocol Overview - -QUIC {{QUIC-TRANSPORT}} assumes responsibility for the confidentiality and -integrity protection of packets. For this it uses keys derived from a TLS 1.3 -connection {{!TLS13}}; QUIC also relies on TLS 1.3 for authentication and -negotiation of parameters that are critical to security and performance. - -Rather than a strict layering, these two protocols are co-dependent: QUIC uses -the TLS handshake; TLS uses the reliability and ordered delivery provided by -QUIC streams. - -This document defines how QUIC interacts with TLS. This includes a description -of how TLS is used, how keying material is derived from TLS, and the application -of that keying material to protect QUIC packets. {{schematic}} shows the basic -interactions between TLS and QUIC, with the QUIC packet protection being called -out specially. - -~~~ -+------------+ +------------+ -| |------ Handshake ------>| | -| |<-- Validate Address ---| | -| |-- OK/Error/Validate -->| | -| |<----- Handshake -------| | -| QUIC |------ Validate ------->| TLS | -| | | | -| |<------ 0-RTT OK -------| | -| |<------ 1-RTT OK -------| | -| |<--- Handshake Done ----| | -+------------+ +------------+ - | ^ ^ | - | Protect | Protected | | - v | Packet | | -+------------+ / / -| QUIC | / / -| Packet |-------- Get Secret -------' / -| Protection |<-------- Secret -----------' -+------------+ -~~~ -{: #schematic title="QUIC and TLS Interactions"} - -The initial state of a QUIC connection has packets exchanged without any form of -protection. In this state, QUIC is limited to using stream 0 and associated -packets. Stream 0 is reserved for a TLS connection. This is a complete TLS -connection as it would appear when layered over TCP; the only difference is that -QUIC provides the reliability and ordering that would otherwise be provided by -TCP. - -At certain points during the TLS handshake, keying material is exported from the -TLS connection for use by QUIC. This keying material is used to derive packet -protection keys. Details on how and when keys are derived and used are included -in {{packet-protection}}. - ## TLS Overview @@ -206,9 +144,24 @@ TLS provides two endpoints with a way to establish a means of communication over an untrusted medium (that is, the Internet) that ensures that messages they exchange cannot be observed, modified, or forged. -TLS features can be separated into two basic functions: an authenticated key -exchange and record protection. QUIC primarily uses the authenticated key -exchange provided by TLS but provides its own packet protection. +Internally, TLS is a layered protocol, with the structure shown below: + +~~~~ ++--------------+--------------+--------------+ +| Handshake | Alerts | Application | +| Layer | | Data | +| | | | ++--------------+--------------+--------------+ +| | +| Record Layer | +| | ++--------------------------------------------+ +~~~~ + +Each upper layer (handshake, alerts, and application data) is carried as +a series of typed TLS records. Records are individually cryptographically +protected and then transmitted over a reliable transport (typically TCP) +which provides sequencing and guaranteed delivery. The TLS authenticated key exchange occurs between two entities: client and server. The client initiates the exchange and the server responds. If the key @@ -225,9 +178,6 @@ learn and authenticate an identity for the client. TLS supports X.509 The TLS key exchange is resistent to tampering by attackers and it produces shared secrets that cannot be controlled by either participating peer. - -## TLS Handshake - TLS 1.3 provides two basic handshake modes of interest to QUIC: * A full 1-RTT handshake in which the client is able to send application data @@ -255,142 +205,206 @@ A simplified TLS 1.3 handshake with 0-RTT application data is shown in {Finished} --------> [Application Data] <-------> [Application Data] + + () Indicates messages protected by early data (0-RTT) keys + {} Indicates messages protected using handshake keys + [] Indicates messages protected using application data + (1-RTT) keys ~~~ {: #tls-full title="TLS Handshake with 0-RTT"} -This 0-RTT handshake is only possible if the client and server have previously +Data is protected using a number of encryption levels: + +- Plaintext +- Early Data (0-RTT) Keys +- Handshake Keys +- Application Data (1-RTT) Keys + +Application data may appear only in the early data and application +data levels. Handshake and Alert messages may appear in any level. + +The 0-RTT handshake is only possible if the client and server have previously communicated. In the 1-RTT handshake, the client is unable to send protected application data until it has received all of the handshake messages sent by the server. -Two additional variations on this basic handshake exchange are relevant to this -document: - * The server can respond to a ClientHello with a HelloRetryRequest, which adds - an additional round trip prior to the basic exchange. This is needed if the - server wishes to request a different key exchange key from the client. - HelloRetryRequest is also used to verify that the client is correctly able to - receive packets on the address it claims to have (see {{QUIC-TRANSPORT}}). +# Protocol Overview - * A pre-shared key mode can be used for subsequent handshakes to reduce the - number of public key operations. This is the basis for 0-RTT data, even if - the remainder of the connection is protected by a new Diffie-Hellman - exchange. +QUIC {{QUIC-TRANSPORT}} assumes responsibility for the confidentiality and +integrity protection of packets. For this it uses keys derived from a TLS 1.3 +handshake {{!TLS13}}, but instead of carrying TLS records over QUIC +(as with TCP), TLS Handshake and Alert messages are carried directly +over QUIC transport, which takes over the responsibilities of the TLS +record layer, as shown below. + +~~~~ + ++--------------+--------------+ +-------------+ +| TLS | TLS | | QUIC | +| Handshake | Alerts | | Applications| +| | | | (h2q, etc.) | ++--------------+--------------+-+-------------+ +| | +| QUIC Transport | +| (streams, reliability, congestion, etc.) | +| | ++---------------------------------------------+ +| | +| QUIC Packet Protection | +| | ++---------------------------------------------+ +~~~~ + + +QUIC also relies on TLS 1.3 for authentication and +negotiation of parameters that are critical to security and performance. +Rather than a strict layering, these two protocols are co-dependent: QUIC uses +the TLS handshake; TLS uses the reliability and ordered delivery provided by +QUIC streams. -# TLS Usage +At a high level, there are two main interactions between the TLS and QUIC +components: -QUIC reserves stream 0 for a TLS connection. Stream 0 contains a complete TLS -connection, which includes the TLS record layer. Other than the definition of a -QUIC-specific extension (see {{quic_parameters}}), TLS is unmodified for this -use. This means that TLS will apply confidentiality and integrity protection to -its records. In particular, TLS record protection is what provides -confidentiality protection for the TLS handshake messages sent by the server. +* The TLS component sends and receives messages via the QUIC component, with + QUIC providing a reliable stream abstraction to TLS. -QUIC permits a client to send frames on streams starting from the first packet. -The initial packet from a client contains a stream frame for stream 0 that -contains the first TLS handshake messages from the client. This allows the TLS -handshake to start with the first packet that a client sends. +* The TLS component provides a series of updates to the QUIC + component, including (a) new packet protection keys to install (b) + state changes such as handshake completion, the server certificate, + etc. -QUIC packets are protected using a scheme that is specific to QUIC, see -{{packet-protection}}. Keys are exported from the TLS connection when they -become available using a TLS exporter (see Section 7.5 of {{!TLS13}} and -{{key-expansion}}). After keys are exported from TLS, QUIC manages its own key -schedule. +{{schematic}} shows these interactions in more detail, with the QUIC +packet protection being called out specially. + +~~~ ++------------+ +------------+ +| |<- Handshake Messages ->| | +| |<---- 0-RTT Keys -------| | +| |<--- Handshake Keys-----| | +| QUIC |<---- 1-RTT Keys -------| TLS | +| |<--- Handshake Done ----| | ++------------+ +------------+ + | ^ + | Protect | Protected + v | Packet ++------------+ +| QUIC | +| Packet | +| Protection | ++------------+ +~~~ +{: #schematic title="QUIC and TLS Interactions"} + +Unlike TLS over TCP, QUIC applications which want to send data do not +send it through TLS "application_data" records. Rather, they send it +as QUIC STREAM frames which are then carried in QUIC packets. + + +# Carrying TLS Messages {#carrying-tls} + +QUIC carries TLS handshake data in CRYPTO_HS frames, each of which +consists of a contiguous block of handshake data (identified by an +offset and length). Those frames are packaged into QUIC packets +and encrypted under the current TLS encryption level. +As with TLS over TCP, once TLS handshake data has +been delivered to QUIC, it is QUIC's responsibility to deliver it +reliably. Each chunk of data is associated with the then-current TLS +sending keys, and if QUIC needs to retransmit that data, it MUST use +the same keys even if TLS has already updated to newer keys. + +One important difference between TLS 1.3 records (used with TCP) +and QUIC CRYPTO_HS frames is that in QUIC multiple frames may appear +in the same QUIC packet as long as they are associated with the +same encryption level. For instance, an implementation might +bundle a Handshake message and an ACK for some Handshake +data into the same packet. + +In general, the rules for which data can appear in packets of which +encryption level are the same in QUIC as in TLS over TCP: + +- CRYPTO_HS frames MAY appear in packets of any encryption level. +- CONNECTION_CLOSE and CRYPTO_CLOSE MAY appear in packets of any + encryption level other than 0-RTT. +- PADDING and PING frames MAY appear in packets of any encryption level. +- ACK frames MAY appear in packets of any encryption level, but + MUST only acknowledge packets which appeared in that encryption + level. +- STREAM frames MUST ONLY appear in the 0-RTT and 1-RTT levels. +- All other frame types MUST only appear at the 1-RTT levels. + +Because packets may be reordered on the wire, QUIC uses the packet +type to indicate which level a given packet was encrypted +under [TODO: Table needed here?]. When multiple packets of +different encryption levels need to be sent, endpoints SHOULD use +compound packets to send them in the same UDP datagram. ## Handshake and Setup Sequence The integration of QUIC with a TLS handshake is shown in more detail in -{{quic-tls-handshake}}. QUIC `STREAM` frames on stream 0 carry the TLS -handshake. QUIC performs loss recovery {{QUIC-RECOVERY}} for this stream and -ensures that TLS handshake messages are delivered in the correct order. +{{quic-tls-handshake}}. ~~~ - Client Server +Client Server -@H QUIC STREAM Frame(s) <0>: - ClientHello - + QUIC Extension - --------> - 0-RTT Key => @0 - -@0 QUIC STREAM Frame(s) : - Replayable QUIC Frames - --------> - - QUIC STREAM Frame <0>: @H - ServerHello - {TLS Handshake Messages} - <-------- - 1-RTT Key => @1 - - QUIC Frames @1 - <-------- -@H QUIC STREAM Frame(s) <0>: - (EndOfEarlyData) - {Finished} - --------> - -@1 QUIC Frames <-------> QUIC Frames @1 -~~~ -{: #quic-tls-handshake title="QUIC over TLS Handshake"} + ---------> -In {{quic-tls-handshake}}, symbols mean: +(STREAM[0-RTTData]) ---------> -* "<" and ">" enclose stream numbers. + <--------- -* "@" indicates the keys that are used for protecting the QUIC packet (H = - handshake, using keys from the well-known cleartext packet secret; - 0 = 0-RTT keys; 1 = 1-RTT keys). + <--------- {CRYPTO_HS[ + EncryptedExtensions, + Certificate, + CertificateVerify, + Finished]} -* "(" and ")" enclose messages that are protected with TLS 0-RTT handshake or - application keys. + <--------- {STREAM[0.5-RTT Data]) +{ACK, + CRYPTO_HS[Finished]} ---------> -* "{" and "}" enclose messages that are protected by the TLS Handshake keys. +[Any frames] <--------> [Any frames] -If 0-RTT is not attempted, then the client does not send packets protected by -the 0-RTT key (@0). In that case, the only key transition on the client is from -handshake packets (@H) to 1-RTT protection (@1), which happens after it sends -its final set of TLS handshake messages. +~~~ +{: #quic-tls-handshake title="QUIC Handshake"} + +In {{quic-tls-handshake}}, symbols mean: + +* "<" and ">" enclose packets protected with Initial keys {{initial-secrets}}. -Note: two different types of packet are used during the handshake by both client -and server. The Initial packet carries a TLS ClientHello message; the remainder -of the TLS handshake is carried in Handshake packets. The Retry packet carries -a TLS HelloRetryRequest, if it is needed, and Handshake packets carry the -remainder of the server handshake. +* "(" and ")" enclose packets that are protected with 0-RTT handshake or + application keys. -The server sends TLS handshake messages without protection (@H). The server -transitions from no protection (@H) to full 1-RTT protection (@1) after it sends -the last of its handshake messages. +* "{" and "}" enclose packets that are protected by the Handshake keys. -Some TLS handshake messages are protected by the TLS handshake record -protection. These keys are not exported from the TLS connection for use in -QUIC. QUIC packets from the server are sent in the clear until the final -transition to 1-RTT keys. +* "[" and "]" enclose packets that are protected by the Application keys. -The client transitions from handshake (@H) to 0-RTT keys (@0) when sending 0-RTT -data, and subsequently to to 1-RTT keys (@1) after its second flight of TLS -handshake messages. This creates the potential for unprotected packets to be -received by a server in close proximity to packets that are protected with 1-RTT -keys. +* CRYPTO_HS[...], STREAM[...] and ACK indicate QUIC frames. -More information on key transitions is included in {{hs-protection}}. +If 0-RTT is not attempted, then the client does not send packets protected by +the 0-RTT key. ## Interface to TLS -As shown in {{schematic}}, the interface from QUIC to TLS consists of four -primary functions: Handshake, Source Address Validation, Key Ready Events, and -Secret Export. +As shown in {{schematic}}, the interface from QUIC to TLS consists of three +primary functions: + +- Sending and receiving handshake messages +- Rekeying (both in and out) +- Handshake state updates Additional functions might be needed to configure TLS. -### Handshake Interface +### Sending and Receiving Handshake Messages In order to drive the handshake, TLS depends on being able to send and receive -handshake messages on stream 0. There are two basic functions on this +handshake messages. There are two basic functions on this interface: one where QUIC requests handshake messages and one where QUIC provides handshake packets. @@ -399,18 +413,34 @@ Before starting the handshake QUIC provides TLS with the transport parameters A QUIC client starts TLS by requesting TLS handshake octets from TLS. The client acquires handshake octets before sending its first packet. - -A QUIC server starts the process by providing TLS with stream 0 octets. - -Each time that an endpoint receives data on stream 0, it delivers the octets to -TLS if it is able. Each time that TLS is provided with new data, new handshake -octets are requested from TLS. TLS might not provide any octets if the -handshake messages it has received are incomplete or it has no data to send. - -At the server, when TLS provides handshake octets, it also needs to indicate -whether the octets contain a HelloRetryRequest. A HelloRetryRequest MUST always -be sent in a Retry packet, so the QUIC server needs to know whether the octets -are a HelloRetryRequest. +A QUIC server starts the process by providing TLS with the client's +handshake octets. + +At any given time, an endpoint will have a current sending encryption +level and receiving encryption level. Each encryption level is +associated with a different flow of bytes, which is reliably +transmitted to the peer in CRYPTO_HS frames. When TLS provides handshake +octets to be sent, they are appended to the current flow and +will eventually be transmitted under the then-current key. + +When an endpoint receives a packet containing a CRYPTO_HS frame from +the network, it proceeds as follows: + +- If the packet was in the current receiving encryption level, sequence + the data into the input flow as usual. As with STREAM frames, + the offset is used to find the proper location in the data sequence. + If the result of this process is that new data is available, then + it is delivered to TLS. + +- If the packet is from a previously installed encryption level, it + MUST not contain data which extends past the end of previously + received data in that flow. [TODO(ekr): Double check that this + can't happen]. Implementations MUST treat any violations of this + requirement as a connection error of type PROTOCOL_VIOLATION. + +Each time that TLS is provided with new data, new handshake octets are +requested from TLS. TLS might not provide any octets if the handshake +messages it has received are incomplete or it has no data to send. Once the TLS handshake is complete, this is indicated to QUIC along with any final handshake octets that TLS needs to send. TLS also provides QUIC with the @@ -423,8 +453,8 @@ data is that the server might wish to provide additional or updated session tickets to a client. When the handshake is complete, QUIC only needs to provide TLS with any data -that arrives on stream 0. In the same way that is done during the handshake, -new data is requested from TLS after providing received data. +that arrives in CRYPTO_HS streams. In the same way that is done during the +handshake, new data is requested from TLS after providing received data. Important: @@ -440,102 +470,63 @@ Important: STREAM frame that carries the Finished message in multiple packets. This enables immediate server processing for those packets. +### Encryption Level Changes -### Source Address Validation - -During the processing of the TLS ClientHello, TLS requests that the transport -make a decision about whether to request source address validation from the -client. - -An initial TLS ClientHello that resumes a session includes an address validation -token in the session ticket; this includes all attempts at 0-RTT. If the client -does not attempt session resumption, no token will be present. While processing -the initial ClientHello, TLS provides QUIC with any token that is present. In -response, QUIC provides one of three responses: - -* proceed with the connection, - -* ask for client address validation, or - -* abort the connection. - -If QUIC requests source address validation, it also provides a new address -validation token. TLS includes that along with any information it requires in -the cookie extension of a TLS HelloRetryRequest message. In the other cases, -the connection either proceeds or terminates with a handshake error. - -The client echoes the cookie extension in a second ClientHello. A ClientHello -that contains a valid cookie extension will always be in response to a -HelloRetryRequest. If address validation was requested by QUIC, then this will -include an address validation token. TLS makes a second address validation -request of QUIC, including the value extracted from the cookie extension. In -response to this request, QUIC cannot ask for client address validation, it can -only abort or permit the connection attempt to proceed. - -QUIC can provide a new address validation token for use in session resumption at -any time after the handshake is complete. Each time a new token is provided TLS -generates a NewSessionTicket message, with the token included in the ticket. - -See {{client-address-validation}} for more details on client address validation. - - -### Key Ready Events - -TLS provides QUIC with signals when 0-RTT and 1-RTT keys are ready for use. +At each change of encryption level in either direction, TLS signals +QUIC, providing the new level and the encryption keys. These events are not asynchronous, they always occur immediately after TLS is provided with new handshake octets, or after TLS produces handshake octets. -When TLS completed its handshake, 1-RTT keys can be provided to QUIC. On both -client and server, this occurs after sending the TLS Finished message. - -This ordering means that there could be frames that carry TLS handshake messages -ready to send at the same time that application data is available. An -implementation MUST ensure that TLS handshake messages are always sent in -packets protected with handshake keys (see {{handshake-secrets}}). Separate -packets are required for data that needs protection from 1-RTT keys. - If 0-RTT is possible, it is ready after the client sends a TLS ClientHello message or the server receives that message. After providing a QUIC client with -the first handshake octets, the TLS stack might signal that 0-RTT keys are -ready. On the server, after receiving handshake octets that contain a +the first handshake octets, the TLS stack might signal the change to the +the 0-RTT keys. On the server, after receiving handshake octets that contain a ClientHello message, a TLS server might signal that 0-RTT keys are available. -1-RTT keys are used for packets in both directions. 0-RTT keys are only -used to protect packets sent by the client. +Note that although TLS only uses one encryption level at a time, QUIC +may use more than one level. For instance, after sending its Finished +message (using a CRYPTO_HS frame in Handshake encryption) may send STREAM +data (in 1-RTT encryption). However, if the Finished is lost, the client +would have to retransmit the Finished, in which case it would use +Handshake encryption. -### Secret Export - -Details how secrets are exported from TLS are included in {{key-expansion}}. - ### TLS Interface Summary {{exchange-summary}} summarizes the exchange between QUIC and TLS for both -client and server. +client and server. Each arrow is tagged with the encryption level used for +that transmission. ~~~ Client Server Get Handshake -0-RTT Key Ready - --- send/receive ---> + Initial ------------> +Rekey tx to 0-RTT Keys + 0-RTT --------------> + Handshake Received + Get Handshake + <------------ Initial + Rekey rx to 0-RTT keys Handshake Received - 0-RTT Key Ready + Rekey rx to Handshake keys Get Handshake - 1-RTT Keys Ready - <--- send/receive --- + <----------- Handshake + Rekey tx to 1-RTT keys +Handshake Received +Rekey rx to Handshake keys Handshake Received Get Handshake Handshake Complete -1-RTT Keys Ready - --- send/receive ---> +Rekey tx to 1-RTT keys + Handshake ----------> Handshake Received + Rekey rx to 1-RTT keys Get Handshake Handshake Complete - <--- send/receive --- + <--------------- 1-RTT Handshake Received -Get Handshake ~~~ {: #exchange-summary title="Interaction Summary between QUIC and TLS"} @@ -598,64 +589,9 @@ A server MUST NOT use post-handshake client authentication (see Section 4.6.2 of {{!TLS13}}). -## Rejecting 0-RTT - -A server rejects 0-RTT by rejecting 0-RTT at the TLS layer. This results in -early exporter keys being unavailable, thereby preventing the use of 0-RTT for -QUIC. - -A client that attempts 0-RTT MUST also consider 0-RTT to be rejected if it -receives a Retry or Version Negotiation packet. - -When 0-RTT is rejected, all connection characteristics that the client assumed -might be incorrect. This includes the choice of application protocol, transport -parameters, and any application configuration. The client therefore MUST reset -the state of all streams, including application state bound to those streams. - - -## TLS Errors - -Errors in the TLS connection SHOULD be signaled using TLS alerts on stream 0. A -failure in the handshake MUST be treated as a QUIC connection error of type -TLS_HANDSHAKE_FAILED. Once the handshake is complete, an error in the TLS -connection that causes a TLS alert to be sent or received MUST be treated as a -QUIC connection error of type TLS_FATAL_ALERT_GENERATED or -TLS_FATAL_ALERT_RECEIVED respectively. - - -# QUIC Packet Protection {#packet-protection} - -QUIC packet protection provides authenticated encryption of packets. This -provides confidentiality and integrity protection for the content of packets -(see {{aead}}). Packet protection uses keys that are exported from the TLS -connection (see {{key-expansion}}). - -Different keys are used for QUIC packet protection and TLS record protection. -TLS handshake messages are protected solely with TLS record protection, -but post-handshake messages are redundantly protected with -both the QUIC packet protection and the TLS record protection. These messages -are limited in number, and so the additional overhead is small. - - -## Installing New Keys {#new-key} - -As TLS reports the availability of keying material, the packet protection keys -and initialization vectors (IVs) are updated (see {{key-expansion}}). The -selection of AEAD function is also updated to match the AEAD negotiated by TLS. - -For packets other than any handshake packets (see {{hs-protection}}), once a -change of keys has been made, packets with higher packet numbers MUST be sent -with the new keying material. The KEY_PHASE bit on these packets is inverted -each time new keys are installed to signal the use of the new keys to the -recipient (see {{key-phases}} for details). - -An endpoint retransmits stream data in a new packet. New packets have new -packet numbers and use the latest packet protection keys. This simplifies key -management when there are key updates (see {{key-update}}). - - ## Enabling 0-RTT {#enable-0rtt} +[TODO(ekr@rtfm.com): I'm not sure that this is correct any more.] In order to be usable for 0-RTT, TLS MUST provide a NewSessionTicket message that contains the "max_early_data" extension with the value 0xffffffff; the amount of data which the client can send in 0-RTT is controlled by the @@ -667,73 +603,85 @@ Early data within the TLS connection MUST NOT be used. As it is for other TLS application data, a server MUST treat receiving early data on the TLS connection as a connection error of type PROTOCOL_VIOLATION. +## Rejecting 0-RTT -## QUIC Key Expansion {#key-expansion} +A server rejects 0-RTT by rejecting 0-RTT at the TLS layer. This results in +early exporter keys being unavailable, thereby preventing the use of 0-RTT for +QUIC. -QUIC uses a system of packet protection secrets, keys and IVs that are modelled -on the system used in TLS {{!TLS13}}. The secrets that QUIC uses -as the basis of its key schedule are obtained using TLS exporters (see Section -7.5 of {{!TLS13}}). +A client that attempts 0-RTT MUST also consider 0-RTT to be rejected if it +receives a Version Negotiation packet. +When 0-RTT is rejected, all connection characteristics that the client assumed +might be incorrect. This includes the choice of application protocol, transport +parameters, and any application configuration. The client therefore MUST reset +the state of all streams, including application state bound to those streams. -### QHKDF-Expand +## HelloRetryRequest -QUIC uses the Hash-based Key Derivation Function (HKDF) {{!HKDF=RFC5869}} with -the same hash function negotiated by TLS for key derivation. For example, if -TLS is using the TLS_AES_128_GCM_SHA256, the SHA-256 hash function is used. +In TLS over TCP, the HelloRetryRequest feature ({{TLS13}; Section +4.1.4) can be used to correct a client's incorrect KeyShare extension +as well as for a stateless round trip check. From the perspective of +QUIC, this just looks like additional messages carried in the Initial +encryption level. Although it is in principle possible to use this +feature for address verification in QUIC, QUIC implementations SHOULD +instead use the Retry feature ({{QUIC-TRANSPORT}}; Section 4.4.2)). -Most key derivations in this document use the QHKDF-Expand function, which uses -the HKDF expand function and is modelled on the HKDF-Expand-Label function from -TLS 1.3 (see Section 7.1 of {{!TLS13}}). QHKDF-Expand differs from -HKDF-Expand-Label in that it uses a different base label and omits the Context -argument. -~~~ -QHKDF-Expand(Secret, Label, Length) = - HKDF-Expand(Secret, QhkdfExpandInfo, Length) -~~~ +## TLS Errors -The HKDF-Expand function used by QHKDF-Expand uses the PRF hash function -negotiated by TLS, except for handshake secrets and keys derived from them (see -{{handshake-secrets}}). +If TLS experiences an error, it MUST generate an appropriate alert +as defined in {{TLS13}}; Section 6) and then provide it to QUIC, +which sends the alert in a CRYPTO_CLOSE frame. All such alerts are +"fatal". -Where the `info` parameter of HKDF-Expand is an encoded `QhkdfExpandInfo` -structure: -~~~ -struct { - uint16 length = Length; - opaque label<6..255> = "QUIC " + Label; -} QhkdfExpandInfo; -~~~ +# QUIC Packet Protection {#packet-protection} + +As with TLS over TCP, QUIC encrypts packets with keys derived from the TLS +handshake, using the AEAD algorithm negotiated by TLS. + + +## QUIC Packet Encryption Keys {#encryption-keys} + +QUIC derives packet encryption keys in the same way as TLS 1.3: +Each encryption level/direction pair has a secret value, which +is then used to derive the traffic keys using as described +in {{TLS13}}; Section 7.3. -For example, assuming a hash function with a 32 octet output, derivation for a -client packet protection key would use HKDF-Expand with an `info` parameter of -0x00200851554943206b6579. +The keys for the Initial encryption level are computed based on +the client's first Destination Connection Id, as described in +{{initial-secrets}}. +The keys for the remaining encryption level are computed in the same +fashion as the corresponding TLS keys (see {{TLS13}}; Section 7), +except that the label for HKDF-Expand-Label uses the prefix "quic " +rather than "tls 13". The purpose of this change is to provide key +separation between TLS and QUIC, so that TLS stacks can avoid +exposing TLS record protection keys. -### Handshake Secrets {#handshake-secrets} +### Initial Secrets {#initial-secrets} -Packets that carry the TLS handshake (Initial, Retry, and Handshake) are -protected with a secret derived from the Destination Connection ID field from -the client's Initial packet. Specifically: +Initial packets are protected with +a secret derived from the Destination Connection ID field from the client's +Initial packet. Specifically: ~~~ -handshake_salt = 0x9c108f98520a5c5c32968e950e8a2c5fe06d6c38 -handshake_secret = - HKDF-Extract(handshake_salt, client_dst_connection_id) - -client_handshake_secret = - QHKDF-Expand(handshake_secret, "client hs", Hash.length) -server_handshake_secret = - QHKDF-Expand(handshake_secret, "server hs", Hash.length) +initial_salt = 0x9c108f98520a5c5c32968e950e8a2c5fe06d6c38 +initial_secret = + HKDF-Extract(initial_salt, client_dst_connection_id) + +client_initial_secret = + HKDF-Expand-Label(initial_secret, "client in", Hash.length) +server_initial_secret = + HKDF-Expand-Label(initial_secret, "server in", Hash.length) ~~~ The hash function for HKDF when deriving handshake secrets and keys is SHA-256 -{{!SHA=DOI.10.6028/NIST.FIPS.180-4}}. The connection ID used with QHKDF-Expand -is the connection ID chosen by the client. +{{!SHA=DOI.10.6028/NIST.FIPS.180-4}}. The connection ID used with +HKDF-Expand-Label is the connection ID chosen by the client. -The handshake salt is a 20 octet sequence shown in the figure in hexadecimal +initial_salt is a 20 octet sequence shown in the figure in hexadecimal notation. Future versions of QUIC SHOULD generate a new salt value, thus ensuring that the keys are different for each version of QUIC. This prevents a middlebox that only recognizes one version of QUIC from seeing or modifying the @@ -743,121 +691,11 @@ Note: : The Destination Connection ID is of arbitrary length, and it could be zero length if the server sends a Retry packet with a zero-length Source Connection - ID field. In this case, the handshake keys provide no assurance to the client + ID field. In this case, the initial keys provide no assurance to the client that the server received its packet; the client has to rely on the exchange that included the Retry packet for that property. -### 0-RTT Secret {#zero-rtt-secrets} - -0-RTT keys are those keys that are used in resumed connections prior to the -completion of the TLS handshake. Data sent using 0-RTT keys might be replayed -and so has some restrictions on its use, see {{using-early-data}}. 0-RTT keys -are used after sending or receiving a ClientHello. - -The secret is exported from TLS using the exporter label "EXPORTER-QUIC 0rtt" -and an empty context. The size of the secret MUST be the size of the hash -output for the PRF hash function negotiated by TLS. This uses the TLS -early_exporter_secret. The QUIC 0-RTT secret is only used for protection of -packets sent by the client. - -~~~ -client_0rtt_secret = - TLS-Early-Exporter("EXPORTER-QUIC 0rtt", "", Hash.length) -~~~ - - -### 1-RTT Secrets {#one-rtt-secrets} - -1-RTT keys are used by both client and server after the TLS handshake completes. -There are two secrets used at any time: one is used to derive packet protection -keys for packets sent by the client, the other for packet protection keys on -packets sent by the server. - -The initial client packet protection secret is exported from TLS using the -exporter label "EXPORTER-QUIC client 1rtt"; the initial server packet protection -secret uses the exporter label "EXPORTER-QUIC server 1rtt". Both exporters use -an empty context. The size of the secret MUST be the size of the hash output -for the PRF hash function negotiated by TLS. - -~~~ -client_pp_secret<0> = - TLS-Exporter("EXPORTER-QUIC client 1rtt", "", Hash.length) -server_pp_secret<0> = - TLS-Exporter("EXPORTER-QUIC server 1rtt", "", Hash.length) -~~~ - -These secrets are used to derive the initial client and server packet protection -keys. - - -### Updating 1-RTT Secrets - -After a key update (see {{key-update}}), the 1-RTT secrets are updated using -QHKDF-Expand. Updated secrets are derived from the existing packet protection -secret. A Label parameter of "client 1rtt" is used for the client secret and -"server 1rtt" for the server. The Length is the same as the native output of -the PRF hash function. - -~~~ -client_pp_secret = - QHKDF-Expand(client_pp_secret, "client 1rtt", Hash.length) -server_pp_secret = - QHKDF-Expand(server_pp_secret, "server 1rtt", Hash.length) -~~~ - -This allows for a succession of new secrets to be created as needed. - -### Packet Protection Keys - -The complete key expansion uses a similar process for key expansion to that -defined in Section 7.3 of {{!TLS13}}, using QHKDF-Expand in place of -HKDF-Expand-Label. QUIC uses the AEAD function negotiated by TLS. - -The packet protection key and IV used to protect the 0-RTT packets sent by a -client are derived from the QUIC 0-RTT secret. The packet protection keys and -IVs for 1-RTT packets sent by the client and server are derived from the current -generation of client and server 1-RTT secrets (client_pp_secret\ and -server_pp_secret\) respectively. - -The length of the QHKDF-Expand output is determined by the requirements of the -AEAD function selected by TLS. The key length is the AEAD key size. As defined -in Section 5.3 of {{!TLS13}}, the IV length is the larger of 8 or N_MIN (see -Section 4 of {{!AEAD=RFC5116}}; all ciphersuites defined in {{!TLS13}} have -N_MIN set to 12). - -The size of the packet number protection key is determined by the packet number -protection algorithm, see {{pn-encrypt}}. - -For any secret S, the AEAD key uses a label of "key", the IV uses a label of -"iv", packet number encryption uses a label of "pn": - -~~~ -key = QHKDF-Expand(S, "key", key_length) -iv = QHKDF-Expand(S, "iv", iv_length) -pn_key = QHKDF-Expand(S, "pn", pn_key_length) -~~~ - -Separate keys are derived for packet protection by clients and servers. Each -endpoint uses the packet protection key of its peer to remove packet protection. -For example, client packet protection keys and IVs - which are also used by the -server to remove the protection added by a client - for AEAD_AES_128_GCM are -derived from 1-RTT secrets as follows: - -~~~ -client_pp_key = QHKDF-Expand(client_pp_secret, "key", 16) -client_pp_iv = QHKDF-Expand(client_pp_secret, "iv", 12) -client_pp_pn = QHKDF-Expand(client_pp_secret, "pn", 16) -~~~ - -The QUIC packet protection initially starts with keying material derived from -handshake keys. For a client, when the TLS state machine reports that the -ClientHello has been sent, 0-RTT keys can be generated and installed for -writing, if 0-RTT is available. Finally, the TLS state machine reports -completion of the handshake and 1-RTT keys can be generated and installed for -writing. - - ## QUIC AEAD Usage {#aead} The Authentication Encryption with Associated Data (AEAD) {{!AEAD}} function @@ -873,7 +711,7 @@ from the packet number. All QUIC packets other than Version Negotiation and Stateless Reset packets are protected with an AEAD algorithm {{!AEAD}}. Prior to establishing a shared secret, packets are protected with AEAD_AES_128_GCM and a key derived from the -client's connection ID (see {{handshake-secrets}}). This provides protection +client's connection ID (see {{initial-secrets}}). This provides protection against off-path attackers and robustness against QUIC version unaware middleboxes, but not against on-path attackers. @@ -881,18 +719,12 @@ All ciphersuites currently defined for TLS 1.3 - and therefore QUIC - have a 16-byte authentication tag and produce an output 16 bytes larger than their input. -Once TLS has provided a key, the contents of regular QUIC packets immediately -after any TLS messages have been sent are protected by the AEAD selected by TLS. - -The key, K, is either the client packet protection key (client_pp_key\) or -the server packet protection key (server_pp_key\), derived as defined in -{{key-expansion}}. - -The nonce, N, is formed by combining the packet protection IV (either -client_pp_iv\ or server_pp_iv\) with the packet number. The 64 bits -of the reconstructed QUIC packet number in network byte order is left-padded -with zeros to the size of the IV. The exclusive OR of the padded packet number -and the IV forms the AEAD nonce. +The key and iv for the packet are computed as described in {{encryption-keys}}. +The nonce, N, is formed by combining the packet protection IV with the +packet number. The 64 bits of the reconstructed QUIC packet number in +network byte order is left-padded with zeros to the size of the IV. +The exclusive OR of the padded packet number and the IV forms the AEAD +nonce. The associated data, A, for the AEAD is the contents of the QUIC header, starting from the flags octet in either the short or long header. @@ -902,34 +734,11 @@ the header, as described in {{QUIC-TRANSPORT}}. The output ciphertext, C, of the AEAD is transmitted in place of P. - -## Packet Numbers {#packet-number} - -QUIC has a single, contiguous packet number space. In comparison, TLS -restarts its sequence number each time that record protection keys are -changed. The sequence number restart in TLS ensures that a compromise of the -current traffic keys does not allow an attacker to truncate the data that is -sent after a key update by sending additional packets under the old key -(causing new packets to be discarded). - -QUIC does not assume a reliable transport and is required to handle attacks -where packets are dropped in other ways. QUIC is therefore not affected by this -form of truncation. - -The QUIC packet number is not reset and it is not permitted to go higher than -its maximum value of 2^62-1. This establishes a hard limit on the number of -packets that can be sent. - Some AEAD functions have limits for how many packets can be encrypted under the same key and IV (see for example {{AEBounds}}). This might be lower than the packet number limit. An endpoint MUST initiate a key update ({{key-update}}) prior to exceeding any limit set for the AEAD that is in use. -TLS maintains a separate sequence number that is used for record protection on -the connection that is hosted on stream 0. This sequence number is not visible -to QUIC. - - ## Packet Number Protection {#pn-encrypt} QUIC packet numbers are protected using a key that is derived from the current @@ -981,7 +790,7 @@ progressively decrypt the packet number. Before a TLS ciphersuite can be used with QUIC, a packet protection algorithm MUST be specifed for the AEAD used with that ciphersuite. This document defines algorithms for AEAD_AES_128_GCM, AEAD_AES_128_CCM, AEAD_AES_256_GCM, -AEAD_AES_256_CCM (all AES AEADs are defined in {{!RFC5116}}), and +AEAD_AES_256_CCM (all AES AEADs are defined in {{!AEAD=RFC5116}}), and AEAD_CHACHA20_POLY1305 ({{!CHACHA=RFC7539}}). @@ -1024,12 +833,13 @@ encrypted_pn = ChaCha20(pn_key, counter, nonce, packet_number) ## Receiving Protected Packets -Once an endpoint successfully receives a packet with a given packet number, it -MUST discard all packets with higher packet numbers if they cannot be -successfully unprotected with either the same key, or - if there is a key update -- the next packet protection key (see {{key-update}}). Similarly, a packet that -appears to trigger a key update, but cannot be unprotected successfully MUST be -discarded. +Once an endpoint successfully receives a packet with a given packet +number, it MUST discard all packets in the same packet number space +with higher packet numbers if they cannot be successfully unprotected +with either the same key, or - if there is a key update - the next +packet protection key (see {{key-update}}). Similarly, a packet that +appears to trigger a key update, but cannot be unprotected +successfully MUST be discarded. Failure to unprotect a packet does not necessarily indicate the existence of a protocol error in a peer or an attack. The truncated packet number encoding @@ -1037,131 +847,76 @@ used in QUIC can cause packet numbers to be decoded incorrectly if they are delayed significantly. -# Key Phases - -As TLS reports the availability of 0-RTT and 1-RTT keys, new keying material can -be exported from TLS and used for QUIC packet protection. At each transition -during the handshake a new secret is exported from TLS and packet protection -keys are derived from that secret. - -Every time that a new set of keys is used for protecting outbound packets, the -KEY_PHASE bit in the public flags is toggled. 0-RTT protected packets use the -QUIC long header, they do not use the KEY_PHASE bit to select the correct keys -(see {{first-keys}}). - -Once the connection is fully enabled, the KEY_PHASE bit allows a recipient to -detect a change in keying material without necessarily needing to receive the -first packet that triggered the change. An endpoint that notices a changed -KEY_PHASE bit can update keys and decrypt the packet that contains the changed -bit, see {{key-update}}. - -The KEY_PHASE bit is included as the 0x20 bit of the QUIC short header. - -Transitions between keys during the handshake are complicated by the need to -ensure that TLS handshake messages are sent with the correct packet protection. - - -## Packet Protection for the TLS Handshake {#hs-protection} - -The initial exchange of packets that carry the TLS handshake are AEAD-protected -using the handshake secrets generated as described in {{handshake-secrets}}. -All TLS handshake messages up to the TLS Finished message sent by either -endpoint use packets protected with handshake keys. - -Any TLS handshake messages that are sent after completing the TLS handshake do -not need special packet protection rules. Packets containing these messages use -the packet protection keys that are current at the time of sending (or -retransmission). - -Like the client, a server MUST send retransmissions of its unprotected handshake -messages or acknowledgments for unprotected handshake messages sent by the -client in packets protected with handshake keys. - - -### Initial Key Transitions {#first-keys} - -Once the TLS handshake is complete, keying material is exported from TLS and -used to protect QUIC packets. - -Packets protected with 1-RTT keys initially have a KEY_PHASE bit set to 0. This -bit inverts with each subsequent key update (see {{key-update}}). - -If the client sends 0-RTT data, it uses the 0-RTT packet type. The packet that -contains the TLS EndOfEarlyData and Finished messages are sent in packets -protected with handshake keys. +## Use of 0-RTT Keys {#using-early-data} -Using distinct packet types during the handshake for handshake messages, 0-RTT -data, and 1-RTT data ensures that the server is able to distinguish between the -different keys used to remove packet protection. All of these packets can -arrive concurrently at a server. +If 0-RTT keys are available (see {{enable-0rtt}}), the lack of replay protection +means that restrictions on their use are necessary to avoid replay attacks on +the protocol. -A server might choose to retain 0-RTT packets that arrive before a TLS -ClientHello. The server can then use those packets once the ClientHello -arrives. However, the potential for denial of service from buffering 0-RTT -packets is significant. These packets cannot be authenticated and so might be -employed by an attacker to exhaust server resources. Limiting the number of -packets that are saved might be necessary. +A client MUST only use 0-RTT keys to protect data that is idempotent. A client +MAY wish to apply additional restrictions on what data it sends prior to the +completion of the TLS handshake. A client otherwise treats 0-RTT keys as +equivalent to 1-RTT keys, except that ACKs for that data MUST only be sent with +1-RTT keys. -The server transitions to using 1-RTT keys after sending its first flight of TLS -handshake messages, ending in the Finished. -From this point, the server protects all packets with 1-RTT -keys. Future packets are therefore protected with 1-RTT keys. Initially, these -are marked with a KEY_PHASE of 0. +A client that receives an indication that its 0-RTT data has been accepted by a +server can send 0-RTT data until it receives all of the server's handshake +messages. A client SHOULD stop sending 0-RTT data if it receives an indication +that 0-RTT data has been rejected. +A server MUST NOT use 0-RTT keys to protect packets. -### Retransmission and Acknowledgment of Unprotected Packets +: 0-RTT data can be acknowledged by the server as it receives it, but any + packets containing acknowledgments of 0-RTT data cannot have packet protection + removed by the client until the TLS handshake is complete. The 1-RTT keys + necessary to remove packet protection cannot be derived until the client + receives all server handshake messages. -TLS handshake messages from both client and server are critical to the key -exchange. The contents of these messages determine the keys used to protect -later messages. If these handshake messages are included in packets that are -protected with these keys, they will be indecipherable to the recipient. -Even though newer keys could be available when retransmitting, retransmissions -of these handshake messages MUST be sent in packets protected with handshake -keys. An endpoint MUST generate ACK frames for these messages and send them in -packets protected with handshake keys. +## Receiving Out-of-Order Protected Frames {#pre-hs-protected} -A HelloRetryRequest handshake message might be used to reject an initial -ClientHello. A HelloRetryRequest handshake message is sent in a Retry packet; -any second ClientHello that is sent in response uses a Initial packet type. -These packets are only protected with a predictable key (see -{{handshake-secrets}}). This is natural, because no shared secret will be -available when these messages need to be sent. Upon receipt of a -HelloRetryRequest, a client SHOULD cease any transmission of 0-RTT data; 0-RTT -data will only be discarded by any server that sends a HelloRetryRequest. +Due to reordering and loss, protected packets might be received by an endpoint +before the final TLS handshake messages are received. A client will be unable +to decrypt 1-RTT packets from the server, whereas a server will be able to +decrypt 1-RTT packets from the client. However, +a server MUST NOT process data from incoming 1-RTT protected packets +before verifying either the client Finished message or - in the case that the +server has chosen to use a pre-shared key - the pre-shared key binder (see +Section 4.2.8 of {{!TLS13}}). Verifying these values provides the server with +an assurance that the ClientHello has not been modified. +Packets protected with 1-RTT keys MAY be stored and later decrypted and used +once the handshake is complete. -The packet type ensures that protected packets are clearly distinguished from -unprotected packets. Loss or reordering might cause unprotected packets to -arrive once 1-RTT keys are in use, unprotected packets are easily distinguished -from 1-RTT packets using the packet type. +A server could receive packets protected with 0-RTT keys prior to receiving a +TLS ClientHello. The server MAY retain these packets for later decryption in +anticipation of receiving a ClientHello. -Once 1-RTT keys are available to an endpoint, it no longer needs the TLS -handshake messages that are carried in unprotected packets. However, a server -might need to retransmit its TLS handshake messages in response to receiving an -unprotected packet that contains ACK frames. A server MUST process ACK frames -in unprotected packets until the TLS handshake is reported as complete, or it -receives an ACK frame in a protected packet that acknowledges all of its -handshake messages. +Receiving and verifying the TLS Finished message is critical in +ensuring the integrity of the TLS handshake. A server MUST NOT use +1-RTT protected packets from the client prior to verifying the client +Finished message if its response depends on client authentication. -To limit the number of key phases that could be active, an endpoint MUST NOT -initiate a key update while there are any unacknowledged handshake messages, see -{{key-update}}. +# Key Update -## Key Update {#key-update} +Once the 1-RTT keys are established and the short header is in use, it +is possible to update the keys, for instance because of limits on AEAD +encryption. The KEY_PHASE bit in the short header is used to indicate +whether key updates have occurred. The KEY_PHASE bit is initially set +to 0 and then inverted with each key update {{key-update}}. -Once the TLS handshake is complete, the KEY_PHASE bit allows for refreshes of -keying material by either peer. Endpoints start using updated keys immediately -without additional signaling; the change in the KEY_PHASE bit indicates that a -new key is in use. +The KEY_PHASE bit allows a recipient to detect a change in keying +material without necessarily needing to receive the first packet that +triggered the change. An endpoint that notices a changed KEY_PHASE +bit can update keys and decrypt the packet that contains the changed +bit, see {{key-update}}. An endpoint MUST NOT initiate more than one key update at a time. A new key cannot be used until the endpoint has received and successfully decrypted a -packet with a matching KEY_PHASE. Note that when 0-RTT is attempted the value -of the KEY_PHASE bit will be different on packets sent by either peer. +packet with a matching KEY_PHASE. A receiving endpoint detects an update when the KEY_PHASE bit doesn't match what -it is expecting. It creates a new secret (see {{key-expansion}}) and the +it is expecting. It creates a new secret (see {{TLS13}}; Section 7.2) and the corresponding read key and IV. If the packet can be decrypted and authenticated using these values, then the keys it uses for packet protection are also updated. The next packet sent by the endpoint will then use the new keys. @@ -1202,341 +957,28 @@ key updates in a short time frame succession and significant packet reordering. ~~~ {: #ex-key-update title="Key Update"} -As shown in {{quic-tls-handshake}} and {{ex-key-update}}, there is never a -situation where there are more than two different sets of keying material that -might be received by a peer. Once both sending and receiving keys have been -updated, the peers immediately begin to use them. - -A server cannot initiate a key update until it has received the client's -Finished message. Otherwise, packets protected by the updated keys could be -confused for retransmissions of handshake messages. A client cannot initiate a -key update until all of its handshake messages have been acknowledged by the -server. - A packet that triggers a key update could arrive after successfully processing a packet with a higher packet number. This is only possible if there is a key compromise and an attack, or if the peer is incorrectly reverting to use of old keys. Because the latter cannot be differentiated from an attack, an endpoint MUST immediately terminate the connection if it detects this condition. +# Security of Initial Messages -# Client Address Validation {#client-address-validation} - -Two tools are provided by TLS to enable validation of client source addresses at -a server: the cookie in the HelloRetryRequest message, and the ticket in the -NewSessionTicket message. - - -## HelloRetryRequest Address Validation - -The cookie extension in the TLS HelloRetryRequest message allows a server to -perform source address validation during the handshake. - -When QUIC requests address validation during the processing of the first -ClientHello, the token it provides is included in the cookie extension of a -HelloRetryRequest. As long as the cookie cannot be successfully guessed by a -client, the server can be assured that the client received the HelloRetryRequest -if it includes the value in a second ClientHello. - -An initial ClientHello never includes a cookie extension. Thus, if a server -constructs a cookie that contains all the information necessary to reconstruct -state, it can discard local state after sending a HelloRetryRequest. Presence -of a valid cookie in a ClientHello indicates that the ClientHello is a second -attempt from the client. - -An address validation token can be extracted from a second ClientHello and -passed to the transport for further validation. If that validation fails, the -server MUST fail the TLS handshake and send an illegal_parameter alert. - -Combining address validation with the other uses of HelloRetryRequest ensures -that there are fewer ways in which an additional round-trip can be added to the -handshake. In particular, this makes it possible to combine a request for -address validation with a request for a different client key share. - -If TLS needs to send a HelloRetryRequest for other reasons, it needs to ensure -that it can correctly identify the reason that the HelloRetryRequest was -generated. During the processing of a second ClientHello, TLS does not need to -consult the transport protocol regarding address validation if address -validation was not requested originally. In such cases, the cookie extension -could either be absent or it could indicate that an address validation token is -not present. - +Because the Initial messages are not securely encrypted, they are subject +to potential tampering by an attacker. Some forms of tampering -- such +as modifying the TLS messages themselves -- are detectable, but some +-- such as modifying ACKs -- are not. To give a concrete example, +an on-path attacker could modify the ACK to make it appear that +a packet had not been received or to create a false impression of +the state of the connection (e.g., by modifying the ACK Delay). +Implementations SHOULD use caution in relying on any data which +is contained in Initial packets that is not otherwise authenticated. -### Stateless Address Validation - -A server can use the cookie extension to store all state necessary to continue -the connection. This allows a server to avoid committing state for clients that -have unvalidated source addresses. - -For instance, a server could use a statically-configured key to encrypt the -information that it requires and include that information in the cookie. In -addition to address validation information, a server that uses encryption also -needs to be able recover the hash of the ClientHello and its length, plus any -information it needs in order to reconstruct the HelloRetryRequest. - - -### Sending HelloRetryRequest - -A server does not need to maintain state for the connection when sending a -HelloRetryRequest message. This might be necessary to avoid creating a denial -of service exposure for the server. However, this means that information about -the transport will be lost at the server. This includes the stream offset of -stream 0, the packet number that the server selects, and any opportunity to -measure round trip time. - -A server MUST send a TLS HelloRetryRequest in a Retry packet. Using a Retry -packet causes the client to reset stream offsets. It also avoids the need for -the server select an initial packet number, which would need to be remembered so -that subsequent packets could be correctly numbered. - -A HelloRetryRequest message MUST NOT be split between multiple Retry packets. -This means that HelloRetryRequest is subject to the same size constraints as a -ClientHello (see {{clienthello-size}}). - -A client might send multiple Initial packets in response to loss. If a server -sends a Retry packet in response to an Initial packet, it does not have to -generate the same Retry packet each time. Variations in Retry packet, if used -by a client, could lead to multiple connections derived from the same -ClientHello. Reuse of the client nonce is not supported by TLS and could lead -to security vulnerabilities. Clients that receive multiple Retry packets MUST -use only one and discard the remainder. - - -## NewSessionTicket Address Validation - -The ticket in the TLS NewSessionTicket message allows a server to provide a -client with a similar sort of token. When a client resumes a TLS connection - -whether or not 0-RTT is attempted - it includes the ticket in the handshake -message. As with the HelloRetryRequest cookie, the server includes the address -validation token in the ticket. TLS provides the token it extracts from the -session ticket to the transport when it asks whether source address validation -is needed. - -If both a HelloRetryRequest cookie and a session ticket are present in the -ClientHello, only the token from the cookie is passed to the transport. The -presence of a cookie indicates that this is a second ClientHello - the token -from the session ticket will have been provided to the transport when it -appeared in the first ClientHello. - -A server can send a NewSessionTicket message at any time. This allows it to -update the state - and the address validation token - that is included in the -ticket. This might be done to refresh the ticket or token, or it might be -generated in response to changes in the state of the connection. QUIC can -request that a NewSessionTicket be sent by providing a new address validation -token. - -A server that intends to support 0-RTT SHOULD provide an address validation -token immediately after completing the TLS handshake. - - -## Address Validation Token Integrity {#validation-token-integrity} - -TLS MUST provide integrity protection for address validation token unless the -transport guarantees integrity protection by other means. For a -NewSessionTicket that includes confidential information - such as the resumption -secret - including the token under authenticated encryption ensures that the -token gains both confidentiality and integrity protection without duplicating -the overheads of that protection. - - -# Pre-handshake QUIC Messages {#pre-hs} - -Implementations MUST NOT exchange data on any stream other than stream 0 without -packet protection. QUIC requires the use of several types of frame for managing -loss detection and recovery during this phase. In addition, it might be useful -to use the data acquired during the exchange of unauthenticated messages for -congestion control. - -This section generally only applies to TLS handshake messages from both peers -and acknowledgments of the packets carrying those messages. In many cases, the -need for servers to provide acknowledgments is minimal, since the messages that -clients send are small and implicitly acknowledged by the server's responses. - -The actions that a peer takes as a result of receiving an unauthenticated packet -needs to be limited. In particular, state established by these packets cannot -be retained once record protection commences. - -There are several approaches possible for dealing with unauthenticated packets -prior to handshake completion: - -* discard and ignore them -* use them, but reset any state that is established once the handshake completes -* use them and authenticate them afterwards; failing the handshake if they can't - be authenticated -* save them and use them when they can be properly authenticated -* treat them as a fatal error - -Different strategies are appropriate for different types of data. This document -proposes that all strategies are possible depending on the type of message. - -* Transport parameters are made usable and authenticated as part of the TLS - handshake (see {{quic_parameters}}). - -* Most unprotected messages are treated as fatal errors when received except for - the small number necessary to permit the handshake to complete (see - {{pre-hs-unprotected}}). - -* Protected packets can either be discarded or saved and later used (see - {{pre-hs-protected}}). - - -## Unprotected Packets Prior to Handshake Completion {#pre-hs-unprotected} - -This section describes the handling of messages that are sent and received prior -to the completion of the TLS handshake. - -Sending and receiving unprotected messages is hazardous. Unless expressly -permitted, receipt of an unprotected message of any kind MUST be treated as a -fatal error. - - -### STREAM Frames - -`STREAM` frames for stream 0 are permitted. These carry the TLS handshake -messages. Once 1-RTT keys are available, unprotected `STREAM` frames on stream -0 can be ignored. - -Receiving unprotected `STREAM` frames for other streams MUST be treated as a -fatal error. - - -### ACK Frames - -`ACK` frames are permitted prior to the handshake being complete. Information -learned from `ACK` frames cannot be entirely relied upon, since an attacker is -able to inject these packets. Timing and packet retransmission information from -`ACK` frames is critical to the functioning of the protocol, but these frames -might be spoofed or altered. - -Endpoints MUST NOT use an `ACK` frame in an unprotected packet to acknowledge -packets that were protected by 0-RTT or 1-RTT keys. An endpoint MUST treat -receipt of an `ACK` frame in an unprotected packet that claims to acknowledge -protected packets as a connection error of type OPTIMISTIC_ACK. An endpoint -that can read protected data is always able to send protected data. - -Note: - -: 0-RTT data can be acknowledged by the server as it receives it, but any - packets containing acknowledgments of 0-RTT data cannot have packet protection - removed by the client until the TLS handshake is complete. The 1-RTT keys - necessary to remove packet protection cannot be derived until the client - receives all server handshake messages. - -An endpoint SHOULD use data from `ACK` frames carried in unprotected packets or -packets protected with 0-RTT keys only during the initial handshake. All `ACK` -frames contained in unprotected packets that are received after successful -receipt of a packet protected with 1-RTT keys MUST be discarded. An endpoint -SHOULD therefore include acknowledgments for unprotected and any packets -protected with 0-RTT keys until it sees an acknowledgment for a packet that is -both protected with 1-RTT keys and contains an `ACK` frame. - - -### Updates to Data and Stream Limits - -`MAX_DATA`, `MAX_STREAM_DATA`, `BLOCKED`, `STREAM_BLOCKED`, and `MAX_STREAM_ID` -frames MUST NOT be sent unprotected. - -Though data is exchanged on stream 0, the initial flow control window on that -stream is sufficiently large to allow the TLS handshake to complete. This -limits the maximum size of the TLS handshake and would prevent a server or -client from using an abnormally large certificate chain. - -Stream 0 is exempt from the connection-level flow control window. - -Consequently, there is no need to signal being blocked on flow control. - -Similarly, there is no need to increase the number of allowed streams until the -handshake completes. - - -### Handshake Failures - -The `CONNECTION_CLOSE` frame MAY be sent by either endpoint in a Handshake -packet. This allows an endpoint to signal a fatal error with connection -establishment. A `STREAM` frame carrying a TLS alert MAY be included in the -same packet. - - -### Address Verification - -In order to perform source-address verification before the handshake is -complete, `PATH_CHALLENGE` and `PATH_RESPONSE` frames MAY be exchanged -unprotected. - - -### Denial of Service with Unprotected Packets - -Accepting unprotected - specifically unauthenticated - packets presents a denial -of service risk to endpoints. An attacker that is able to inject unprotected -packets can cause a recipient to drop even protected packets with a matching -packet number. The spurious packet shadows the genuine packet, causing the -genuine packet to be ignored as redundant. - -Once the TLS handshake is complete, both peers MUST ignore unprotected packets. -From that point onward, unprotected messages can be safely dropped. - -Since only TLS handshake packets and acknowledgments are sent in the clear, an -attacker is able to force implementations to rely on retransmission for packets -that are lost or shadowed. Thus, an attacker that intends to deny service to an -endpoint has to drop or shadow protected packets in order to ensure that their -victim continues to accept unprotected packets. The ability to shadow packets -means that an attacker does not need to be on path. - -In addition to causing valid packets to be dropped, an attacker can generate -packets with an intent of causing the recipient to expend processing resources. -See {{useless}} for a discussion of these risks. - -To avoid receiving TLS packets that contain no useful data, a TLS implementation -MUST reject empty TLS handshake records and any record that is not permitted by -the TLS state machine. Any TLS application data or alerts that are received -prior to the end of the handshake MUST be treated as a connection error of type -PROTOCOL_VIOLATION. - - -## Use of 0-RTT Keys {#using-early-data} - -If 0-RTT keys are available (see {{enable-0rtt}}), the lack of replay protection -means that restrictions on their use are necessary to avoid replay attacks on -the protocol. - -A client MUST only use 0-RTT keys to protect data that is idempotent. A client -MAY wish to apply additional restrictions on what data it sends prior to the -completion of the TLS handshake. A client otherwise treats 0-RTT keys as -equivalent to 1-RTT keys. - -A client that receives an indication that its 0-RTT data has been accepted by a -server can send 0-RTT data until it receives all of the server's handshake -messages. A client SHOULD stop sending 0-RTT data if it receives an indication -that 0-RTT data has been rejected. - -A server MUST NOT use 0-RTT keys to protect packets. - -If a server rejects 0-RTT, then the TLS stream will not include any TLS records -protected with 0-RTT keys. - - -## Receiving Out-of-Order Protected Frames {#pre-hs-protected} - -Due to reordering and loss, protected packets might be received by an endpoint -before the final TLS handshake messages are received. A client will be unable -to decrypt 1-RTT packets from the server, whereas a server will be able to -decrypt 1-RTT packets from the client. - -Packets protected with 1-RTT keys MAY be stored and later decrypted and used -once the handshake is complete. A server MUST NOT use 1-RTT protected packets -before verifying either the client Finished message or - in the case that the -server has chosen to use a pre-shared key - the pre-shared key binder (see -Section 4.2.8 of {{!TLS13}}). Verifying these values provides the server with -an assurance that the ClientHello has not been modified. - -A server could receive packets protected with 0-RTT keys prior to receiving a -TLS ClientHello. The server MAY retain these packets for later decryption in -anticipation of receiving a ClientHello. - -Receiving and verifying the TLS Finished message is critical in ensuring the -integrity of the TLS handshake. A server MUST NOT use protected packets from -the client prior to verifying the client Finished message if its response -depends on client authentication. +It is also possible for the attacker to tamper with data that +is carried in Handshake packets, but because that tampering +requires modifying TLS handshake messages, that tampering will be +detected as soon as the TLS handshake completes. # QUIC-Specific Additions to the TLS Handshake @@ -1592,6 +1034,52 @@ version of QUIC defined in {{QUIC-TRANSPORT}} is used. The quic_transport_parameters extension is carried in the ClientHello and the EncryptedExtensions messages during the handshake. +While the transport parameters are technically available prior to the +completion of the handshake, they cannot be fully trusted until the handshake +completes, and reliance on them should be minimized. +However, any tampering with the parameters will be detected +when the handshake completes. + + +## QUIC Max Crypto Data Extension {#max_crypto_data} + +When QUIC provides TLS messages via the CRYPTO_HS frame, one TLS +message may be fragmented across different packets. TLS +implementations may choose to limit the data they buffer before the +handshake is completed and close the connection on receiving too much +data. + +To communicate the maximum amount of data that TLS will allow to be sent in +CRYPTO_HS frames, TLS MAY use the `max_crypto_data` extension, defined as +follows: + +~~~ + enum { + max_crypto_data(27), (65535) + } ExtensionType; + + struct { + uint32 max_crypto_data; + } MaxCryptoData; +~~~ + +max_crypto_data: + +: The maximum number of bytes that can be sent in CRYPTO_HS frames + +The `extension_data` field of the extension contains the MaxCryptoData +structure. + +Implementations SHOULD send this extension. Receivers do not need to +process this extension. If a receiver does process this extension and +will not be able to fit its handshake into the limit, it SHOULD +terminate the connection with a TODO error. If an implementation sends +this extension and received more than max_crypto_data bytes from its +peer, it SHOULD terminate the connection with a TODO error. The +purpose of this extension is to provide a facility to debug issues +during the handshake and also allow future extensibility of the +protocol to larger message sizes. + # Security Considerations @@ -1608,14 +1096,13 @@ A small ClientHello that results in a large block of handshake messages from a server can be used in packet reflection attacks to amplify the traffic generated by an attacker. -Certificate caching {{?RFC7924}} can reduce the size of the server's handshake -messages significantly. - -QUIC requires that the packet containing a ClientHello be padded to a minimum -size. A server is less likely to generate a packet reflection attack if the -data it sends is a small multiple of this size. A server SHOULD use a -HelloRetryRequest if the size of the handshake messages it sends is likely to -significantly exceed the size of the packet containing the ClientHello. +QUIC includes three defenses against this attack. First, the packet +containing a ClientHello be padded to a minimum size. Second, if +responding to an unverified source address, the server is forbidden to +send more than three packets in its first flight ({{QUIC-TRANSPORT}}; +Section 4.4.3). Finally, because ACKs of Handshake packets +are authenticated, a blind attacker cannot forge them +Put together, these defenses limit the level of amplification. ## Peer Denial of Service {#useless} @@ -1631,13 +1118,6 @@ QUIC prohibits the sending of empty `STREAM` frames unless they are marked with the FIN bit. This prevents `STREAM` frames from being sent that only waste effort. -TLS records SHOULD always contain at least one octet of a handshake messages or -alert. Records containing only padding are permitted during the handshake, but -an excessive number might be used to generate unnecessary work. Once the TLS -handshake is complete, endpoints MUST NOT send TLS application data records. -Receiving TLS application data MUST be treated as a connection error of type -PROTOCOL_VIOLATION. - While there are legitimate uses for some redundant packets, implementations SHOULD track redundant packets and treat excessive volumes of any non-productive packets as indicative of an attack. @@ -1693,50 +1173,18 @@ packet numbers MUST be free from side-channels that would reveal the packet number or its encoded size. -# Error Codes {#errors} - -This section defines error codes from the error code space used in -{{QUIC-TRANSPORT}}. - -The following error codes are defined when TLS is used for the crypto handshake: - -TLS_HANDSHAKE_FAILED (0x201): -: The TLS handshake failed. - -TLS_FATAL_ALERT_GENERATED (0x202): -: A TLS fatal alert was sent, causing the TLS connection to end prematurely. - -TLS_FATAL_ALERT_RECEIVED (0x203): -: A TLS fatal alert was received, causing the TLS connection to end prematurely. - - # IANA Considerations This document does not create any new IANA registries, but it registers the values in the following registries: -* QUIC Transport Error Codes Registry {{QUIC-TRANSPORT}} - IANA is to register - the three error codes found in {{errors}}, these are summarized in - {{iana-errors}}. - * TLS ExtensionsType Registry {{!TLS-REGISTRIES=I-D.ietf-tls-iana-registry-updates}} - IANA is to register - the quic_transport_parameters extension found in {{quic_parameters}}. - The Recommended column is to be marked Yes. The TLS 1.3 Column is to include - CH and EE. - -* TLS Exporter Label Registry {{!TLS-REGISTRIES}} - IANA is requested to - register "EXPORTER-QUIC 0rtt" from {{zero-rtt-secrets}}; "EXPORTER-QUIC client - 1rtt" and "EXPORTER-QUIC server 1-RTT" from {{one-rtt-secrets}}. The DTLS - column is to be marked No. The Recommended column is to be marked Yes. - -| Value | Error | Description | Specification | -|:------|:--------------------------|:----------------------|:--------------| -| 0x201 | TLS_HANDSHAKE_FAILED | TLS handshake failure | {{errors}} | -| 0x202 | TLS_FATAL_ALERT_GENERATED | Sent TLS alert | {{errors}} | -| 0x203 | TLS_FATAL_ALERT_RECEIVED | Receives TLS alert | {{errors}} | -{: #iana-errors title="QUIC Transport Error Codes for TLS"} - + the quic_transport_parameters extension found in {{quic_parameters}} as well + as the max_crypto_data extension found in {{max_crypto_data}} + Assigning 26 and 27 to the extensions respectively would be greatly + appreciated. The Recommended column is to be marked Yes. The TLS 1.3 Column + is to include CH and EE. --- back @@ -1748,6 +1196,15 @@ values in the following registries: Issue and pull request numbers are listed with a leading octothorp. +## Since draft-ietf-quic-tls-12 + +- Big restructure to align with the "QUIC record layer for TLS" proposal. +- Remove source address validation from TLS in favor of Retry. + +## Since draft-ietf-quic-tls-11 + +- Encrypted packet numbers. + ## Since draft-ietf-quic-tls-10 - No significant changes. diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index b743a024e6..10fdbef9fb 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -536,66 +536,140 @@ process. Once version negotiation is complete, the cryptographic handshake is used to agree on cryptographic keys. The cryptographic handshake is carried in Initial -({{packet-initial}}), Retry ({{packet-retry}}) and Handshake -({{packet-handshake}}) packets. +({{packet-initial}}) and Handshake ({{packet-handshake}}) packets. All these packets use the long header and contain the current QUIC version in the version field. -In order to prevent tampering by version-unaware middleboxes, handshake packets -are protected with a connection- and version-specific key, as described in -{{QUIC-TLS}}. This protection does not provide confidentiality or integrity -against on-path attackers, but provides some level of protection against -off-path attackers. +In order to prevent tampering by version-unaware middleboxes, Initial +packets are protected with a connection- and version-specific keys +(Initial keys) as described in {{QUIC-TLS}}. This protection does not +provide confidentiality or integrity against on-path attackers, but +provides some level of protection against off-path attackers. ### Initial Packet {#packet-initial} The Initial packet uses long headers with a type value of 0x7F. It carries the -first cryptographic handshake message sent by the client. +first CRYPTO_HS frames sent by the client as well as the +cryptographic messages sent by the server to perform key exchange. The Initial +packet is protected by Initial keys as described in {{QUIC-TLS}}. -If the client has not previously received a Retry packet from the server, it -populates the Destination Connection ID field with a randomly selected value. -This MUST be at least 8 octets in length. Until a packet is received from the -server, the client MUST use the same random value unless it also changes the -Source Connection ID (which effectively starts a new connection attempt). The -randomized Destination Connection ID is used to determine packet protection -keys. +The Initial packet has two additional header fields that follow the normal Long +Header. -If the client received a Retry packet and is sending a second Initial packet, -then it sets the Destination Connection ID to the value from the Source -Connection ID in the Retry packet. Changing Destination Connection ID also -results in a change to the keys used to protect the Initial packet. +~~~ + 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 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Token Length (i) ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Token (*) ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +~~~ + +Token Length: + +: A variable-length integer specifying the length of the Token field, in bytes. +It may be zero if no token is present. The server MUST send a zero-length +token. + +Token: + +: An optional token blob previously received in either a Retry packet or +NEW_TOKEN frame. + +When an an Initial packet is sent by a client which has not previously received +a Retry packet from the server, it populates the Destination Connection ID field +with a randomly selected value. This MUST be at least 8 octets in length. Until +a packet is received from the server, the client MUST use the same random value +unless it also changes the Source Connection ID (which effectively starts a new +connection attempt). The randomized Destination Connection ID is used to +determine packet protection keys. The client populates the Source Connection ID field with a value of its choosing and sets the SCIL field to match. -The first Initial packet that is sent by a client contains a packet number of 0. -All subsequent packets contain a packet number that is incremented by at least -one, see ({{packet-numbers}}). +If the client has a suitable token available from a previous connection, +it SHOULD populate the Token field. + +A server sends its first Initial packet in response to a client Initial. A +server may send multiple Initial packets. The cryptographic key exchange could +require multiple round trips or retransmissions of this data. + +The Destination Connection ID field in the server's Initial packet +contains a connection ID that is chosen by the recipient of the packet +(i.e., the client); the Source Connection ID includes the connection +ID that the sender of the packet wishes to use (see +{{connection-id}}). + +On first receiving the server Initial packet the client uses the Source +Connection ID supplied by the server as the Destination Connection ID for +subsequent packets. + +If the client received a Retry packet from the server and sends an +Initial packet in response, then it sets the Destination Connection ID to +the value from the Source Connection ID in the Retry packet. Changing +Destination Connection ID also results in a change to the keys used to +protect the Initial packet. It also sets the Token field to the +token provided in the Retry. -The payload of an Initial packet conveys a STREAM frame (or frames) for stream -0 containing a cryptographic handshake message. The stream in this packet -always starts at an offset of 0 (see {{stateless-retry}}) and the complete -cryptographic handshake message MUST fit in a single packet (see {{handshake}}). +The first Initial packet contains a packet number of 0. Each packet sent after +the Initial packet is associated with a packet number space and its packet +number increases monotonically in that space (see {{packet-numbers}}). + +The payload of an Initial packet conveys a CRYPTO_HS frame (or frames) +containing a cryptographic handshake message. The first CRYPTO_HS frame +send always begins at an offset of 0 (see {{handshake}}). The client's complete +first message MUST fit in a single packet (see {{handshake}}). Note that if +the server sends a HelloRetryRequest, the client will send a second Initial +packet with a CRYPTO_HS frame starting immediately after the first one. The payload of a UDP datagram carrying the Initial packet MUST be expanded to at least 1200 octets (see {{packetization}}), by adding PADDING frames to the Initial packet and/or by combining the Initial packet with a 0-RTT packet (see {{packet-coalesce}}). -The client uses the Initial packet type for any packet that contains an initial -cryptographic handshake message. This includes all cases where a new packet -containing the initial cryptographic message needs to be created, this includes -the packets sent after receiving a Version Negotiation ({{packet-version}}) or -Retry packet ({{packet-retry}}). +The client and server use the Initial packet type for any packet that contains +an initial cryptographic handshake message. This includes all cases where a new +packet containing the initial cryptographic message needs to be created, this +includes the packets sent after receiving a Version Negotiation +({{packet-version}}) or Retry packet ({{packet-retry}}). + +When a server receives an Initial packet with an address validation token, it +should attempt to validate it. If the token is invalid then it should be +ignored. If the validation succeeds, the server should then allow the +handshake to proceed (see {{stateless-retry}}). ### Retry Packet {#packet-retry} -A Retry packet uses long headers with a type value of 0x7E. It carries -cryptographic handshake messages and acknowledgments. It is used by a server -that wishes to perform a stateless retry (see {{stateless-retry}}). +A Retry packet uses long headers with a type value of 0x7E. It carries an +address validation token created by the server. It is used by a server that +wishes to perform a stateless retry (see {{stateless-retry}}). + +~~~ + 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 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| DCIL(8) | Original Destination Connection ID (*) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Retry Token (*) ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +~~~ + +A Retry packet is not encrypted at all. Instead, the payload of a +Retry packet contains two values in the clear. + +Original Destination Connection ID: + +: The Destination Connection ID from the Initial packet that this +Retry is in response to. The length of this field is given in DCIL. + +Retry Token: + +: An opaque token that the server can use to validate the client's +address. The server populates the Destination Connection ID with the connection ID that the client included in the Source Connection ID of the Initial packet. This @@ -611,28 +685,17 @@ it creates a "cheat" where the client assumes a value. That's a problem, so I'm tempted to suggest that this include any value less than 2^30 so that normal processing works - and can be properly exercised.]] -A Retry packet is never explicitly acknowledged in an ACK frame -by a client. Receiving another Initial packet implicitly acknowledges a Retry -packet. +A Retry packet is never explicitly acknowledged in an ACK frame by a client. -After receiving a Retry packet, the client uses a new -Initial packet containing the next cryptographic handshake message. The client -retains the state of its cryptographic handshake, but discards all transport -state. The Initial packet that is generated in response to a Retry packet -includes STREAM frames on stream 0 that start again at an offset of 0. +A server MUST only send a Retry in response to a client Initial packet. -Continuing the cryptographic handshake is necessary to ensure that an attacker -cannot force a downgrade of any cryptographic parameters. In addition to -continuing the cryptographic handshake, the client MUST remember the results of -any version negotiation that occurred (see {{version-negotiation}}). The client -MAY also retain any observed RTT or congestion state that it has accumulated for -the flow, but other transport state MUST be discarded. +If the Original Destination Connection ID field does not match the +Destination Connection ID from the Initial packet it sent, clients MUST +discard the packet. This prevents an off-path attacker from injecting +a Retry packet with a bogus new Source Connection ID. -The payload of the Retry packet contains at least two frames. It MUST include a -STREAM frame on stream 0 with offset 0 containing the server's cryptographic -stateless retry material. It MUST also include an ACK frame to acknowledge the -client's Initial packet. It MAY additionally include PADDING frames. The next -STREAM frame sent by the server will also start at stream offset 0. +Otherwise, the client SHOULD respond with a new Initial +packet with the Token field set to the token received in the Retry packet. ### Handshake Packet {#packet-handshake} @@ -652,24 +715,18 @@ includes the connection ID that the sender of the packet wishes to use (see {{connection-id}}). The first Handshake packet sent by a server contains a packet number of 0. -Packet numbers are incremented normally for other Handshake packets. +Handshake packets are their own packet number space. Packet numbers are +incremented normally for other Handshake packets. -Servers MUST NOT send more than three Handshake packets without receiving a -packet from a verified source address. Source addresses can be verified -through an address validation token, receipt of the final cryptographic message -from the client, or by receiving a valid PATH_RESPONSE frame from the client. +Servers MUST NOT send more than three packets including Initial and Handshake +packets without receiving a packet from a verified source address. Source +addresses can be verified through an address validation token +(delivered via a Retry packet or a NEW_TOKEN frame) or by receiving +any message from the client encrypted using the Handshake keys. -If the server expects to generate more than three Handshake packets in response -to an Initial packet, it SHOULD include a PATH_CHALLENGE frame in each Handshake -packet that it sends. After receiving at least one valid PATH_RESPONSE frame, -the server can send its remaining Handshake packets. Servers can instead perform -address validation using a Retry packet; this requires less state on the server, -but could involve additional computational effort depending on implementation -choices. - -The payload of this packet contains STREAM frames and could contain PADDING, -ACK, PATH_CHALLENGE, or PATH_RESPONSE frames. Handshake packets MAY contain -CONNECTION_CLOSE frames if the handshake is unsuccessful. +The payload of this packet contains CRYPTO_HS frames and could contain PADDING, +or ACK frames. Handshake packets MAY contain +CRYPTO_CLOSE or CONNECTION_CLOSE frames if the handshake is unsuccessful. ## Protected Packets {#packet-protected} @@ -678,7 +735,8 @@ All QUIC packets use packet protection. Packets that are protected with the static handshake keys or the 0-RTT keys are sent with long headers; all packets protected with 1-RTT keys are sent with short headers. The different packet types explicitly indicate the encryption level and therefore the keys that are -used to remove packet protection. +used to remove packet protection. 0-RTT and 1-RTT protected packets share a +single packet number space. Packets protected with handshake keys only use packet protection to ensure that the sender of the packet is on the network path. This packet protection is not @@ -694,7 +752,7 @@ Packets protected with 0-RTT keys use a type value of 0x7C. The connection ID fields for a 0-RTT packet MUST match the values used in the Initial packet ({{packet-initial}}). -The client can send 0-RTT packets after receiving a Handshake packet +The client can send 0-RTT packets after receiving an Initial or Handshake packet ({{packet-handshake}}), if that packet does not complete the handshake. Even if the client receives a different connection ID in the Handshake packet, it MUST continue to use the same Destination Connection ID for 0-RTT packets, see @@ -761,7 +819,7 @@ During the handshake, an endpoint might receive multiple packets with the long header, and thus be given multiple opportunities to update the Destination Connection ID it sends. A client MUST only change the value it sends in the Destination Connection ID in response to the first packet of each type it -receives from the server (Retry or Handshake); a server MUST set its value based +receives from the server (Retry or Initial); a server MUST set its value based on the Initial packet. Any additional changes are not permitted; if subsequent packets of those types include a different Source Connection ID, they MUST be discarded. This avoids problems that might arise from stateless processing of @@ -792,15 +850,36 @@ response to connection migration ({{migration}}). NEW_CONNECTION_ID frames The packet number is an integer in the range 0 to 2^62-1. The value is used in determining the cryptographic nonce for packet encryption. Each endpoint -maintains a separate packet number for sending and receiving. The packet number -for sending MUST start at zero for the first packet sent and MUST increase by at -least one after sending a packet. +maintains a separate packet number for sending and receiving. + +Packet numbers are divided into 3 spaces in QUIC: + +- Initial space: All Initial packets {{packet-initial}} are in this space. +- Handshake space: All Handshake packets {{packet-handshake}} are in this space. +- Application data space: All 0-RTT and 1-RTT encrypted packets + {{packet-protected}} are in this space. + +As descibed in {{QUIC-TLS}}, each packet type uses different encryption keys. -A QUIC endpoint MUST NOT reuse a packet number within the same connection (that -is, under the same cryptographic keys). If the packet number for sending -reaches 2^62 - 1, the sender MUST close the connection without sending a -CONNECTION_CLOSE frame or any further packets; an endpoint MAY send a Stateless -Reset ({{stateless-reset}}) in response to further packets that it receives. +Conceptually, a packet number space is the encryption context in which a packet +can be processed and ACKed. Initial packets can only be sent with +Initial encryption keys and ACKed in packets which are also Initial packets. +Similarly Handshake packets can only be sent and acked in Handshake packets. + +This enforces cryptographic separation between the data sent in the +different packet sequence number spaces. As a result, each packet number space +starts at packet number 0. Subsequent packets sent in the +same packet number space MUST increase the packet number by at least one. + +0-RTT and 1-RTT data exist in the same packet number space to make loss recovery +algorithms easier to implement between the two packet types. + +A QUIC endpoint MUST NOT reuse a packet number within the same packet number +space in one connection (that is, under the same cryptographic keys). If the +packet number for sending reaches 2^62 - 1, the sender MUST close the connection +without sending a CONNECTION_CLOSE frame or any further packets; an endpoint MAY +send a Stateless Reset ({{stateless-reset}}) in response to further packets that +it receives. In the QUIC long and short packet headers, the number of bits required to represent the packet number are reduced by including only a variable number of @@ -916,6 +995,10 @@ explained in more detail as they are referenced later in the document. | 0x0e | PATH_CHALLENGE | {{frame-path-challenge}} | | 0x0f | PATH_RESPONSE | {{frame-path-response}} | | 0x10 - 0x17 | STREAM | {{frame-stream}} | +| 0x18 | CRYPTO_HS | {{frame-crypto}} | +| 0x19 | EMPTY_ACK | {{frame-empty-ack}} | +| 0x20 | CRYPTO_CLOSE | {{frame-crypto-close}} | +| 0x21 | NEW_TOKEN | {{frame-new-token}} | {: #frame-types title="Frame Types"} All QUIC frames are idempotent. That is, a valid frame does not cause @@ -989,9 +1072,9 @@ Packets with a supported version, or no version field, are matched to a connection as described in {{packet-handling}}. If not matched, the server continues below. -If the packet is an Initial packet fully conforming with the -specification, the server proceeds with the handshake ({{handshake}}). -This commits the server to the version that the client selected. +If the packet is an Initial packet fully conforming with the specification, the +server proceeds with the handshake ({{handshake}}). This commits the server to +the version that the client selected. If a server isn't currently accepting any new connections, it SHOULD send a Handshake packet containing a CONNECTION_CLOSE frame with error code @@ -1084,14 +1167,16 @@ solicit a list of supported versions from a server. ## Cryptographic and Transport Handshake {#handshake} -QUIC relies on a combined cryptographic and transport handshake to minimize -connection establishment latency. QUIC allocates stream 0 for the cryptographic -handshake. Version 0x00000001 of QUIC uses TLS 1.3 as described in -{{QUIC-TLS}}; a different QUIC version number could indicate that a different +QUIC relies on a combined cryptographic and transport handshake to +minimize connection establishment latency. QUIC uses the CRYPTO_HS +frame {frame-crypto} to transmit the cryptographic handshake. Version +0x00000001 of QUIC uses TLS 1.3 as described in {{QUIC-TLS}}; a +different QUIC version number could indicate that a different cryptographic handshake protocol is in use. -QUIC provides this stream with reliable, ordered delivery of data. In return, -the cryptographic handshake provides QUIC with: +QUIC provides the cryptographic handshake with reliable, ordered +delivery of data via the CRYPTO_HS frame. In return, the +cryptographic handshake provides QUIC with: * authenticated key exchange, where @@ -1118,19 +1203,26 @@ the cryptographic handshake provides QUIC with: client can receive packets that are addressed with the transport address that is claimed by the client (see {{address-validation}}) -The initial cryptographic handshake message MUST be sent in a single packet. -Any second attempt that is triggered by address validation MUST also be sent -within a single packet. This avoids having to reassemble a message from -multiple packets. Reassembling messages requires that a server maintain state -prior to establishing a connection, exposing the server to a denial of service -risk. +The CRYPTO_HS frame provides an offset and a length. QUIC functions +as the record encryption layer for the cryptographic protocol. + +The initial CRYPTO_HS frame MUST be sent in a single packet. Any +second attempt that is triggered by address validation MUST also be +sent within a single packet. This avoids having to reassemble a +message from multiple packets. Reassembling messages requires that a +server maintain state prior to establishing a connection, exposing the +server to a denial of service risk. \[\[TODO: Reword this with retry +proposal.]] The first client packet of the cryptographic handshake protocol MUST fit within a 1232 octet QUIC packet payload. This includes overheads that reduce the space available to the cryptographic handshake protocol. -Details of how TLS is integrated with QUIC is provided in more detail in -{{QUIC-TLS}}. +The CRYPTO_HS frame can be sent in different packet number spaces. +CRYPTO_HS frames in each packet number space carry a separate sequence +of handshake data starting from an offset of 0. + +Details of how TLS is integrated with QUIC are provided in {{QUIC-TLS}}. ## Transport Parameters @@ -1240,13 +1332,11 @@ initial_max_bidi_streams (0x0002): maximum number of application-owned bidirectional streams the peer may initiate, encoded as an unsigned 16-bit integer. If this parameter is absent or zero, application-owned bidirectional streams cannot be created until a - MAX_STREAM_ID frame is sent. Note that a value of 0 does not prevent the - cryptographic handshake stream (that is, stream 0) from being used. Setting - this parameter is equivalent to sending a MAX_STREAM_ID - ({{frame-max-stream-id}}) immediately after completing the handshake - containing the corresponding Stream ID. For example, a value of 0x05 would be - equivalent to receiving a MAX_STREAM_ID containing 20 when received by a - client or 17 when received by a server. + MAX_STREAM_ID frame is sent. Setting this parameter is equivalent to sending + a MAX_STREAM_ID ({{frame-max-stream-id}}) immediately after completing the + handshake containing the corresponding Stream ID. For example, a value of 0x05 + would be equivalent to receiving a MAX_STREAM_ID containing 16 when received + by a client or 17 when received by a server. initial_max_uni_streams (0x0008): @@ -1274,8 +1364,8 @@ ack_delay_exponent (0x0007): : An 8-bit unsigned integer value indicating an exponent used to decode the ACK Delay field in the ACK frame, see {{frame-ack}}. If this value is absent, a default value of 3 is assumed (indicating a multiplier of 8). The default - value is also used for ACK frames that are sent in Initial, Handshake, and - Retry packets. Values above 20 are invalid. + value is also used for ACK frames that are sent in Initial and Handshake + packets. Values above 20 are invalid. A server MAY include the following transport parameters: @@ -1415,17 +1505,10 @@ A server can process an initial cryptographic handshake messages from a client without committing any state. This allows a server to perform address validation ({{address-validation}}), or to defer connection establishment costs. -A server that generates a response to an initial packet without retaining +A server that generates a response to an Initial packet without retaining connection state MUST use the Retry packet ({{packet-retry}}). This packet -causes a client to reset its transport state and to continue the connection -attempt with new connection state while maintaining the state of the -cryptographic handshake. - -A server MUST NOT send multiple Retry packets in response to a client handshake -packet. Thus, any cryptographic handshake message that is sent MUST fit within -a single packet. - -In TLS, the Retry packet type is used to carry the HelloRetryRequest message. +causes a client to restart the connection attempt and includes the token in the +new Initial packet ({{packet-initial}}) to prove source address ownership. ## Proof of Source Address Ownership {#address-validation} @@ -1459,8 +1542,7 @@ To send additional data prior to completing the cryptographic handshake, the server then needs to validate that the client owns the address that it claims. Source address validation is therefore performed during the establishment of a -connection. TLS provides the tools that support the feature, but basic -validation is performed by the core transport protocol. +connection, by the core transport protocol. A different type of source address validation is performed after a connection migration, see {{migrate-validate}}. @@ -1468,59 +1550,60 @@ migration, see {{migrate-validate}}. ### Client Address Validation Procedure -QUIC uses token-based address validation. Any time the server wishes to -validate a client address, it provides the client with a token. As long as the -token cannot be easily guessed (see {{token-integrity}}), if the client is able -to return that token, it proves to the server that it received the token. - -During the processing of the cryptographic handshake messages from a client, TLS -will request that QUIC make a decision about whether to proceed based on the -information it has. TLS will provide QUIC with any token that was provided by -the client. For an initial packet, QUIC can decide to abort the connection, -allow it to proceed, or request address validation. - -If QUIC decides to request address validation, it provides the cryptographic -handshake with a token. The contents of this token are consumed by the server -that generates the token, so there is no need for a single well-defined format. -A token could include information about the claimed client address (IP and -port), a timestamp, and any other supplementary information the server will need -to validate the token in the future. - -The cryptographic handshake is responsible for enacting validation by sending -the address validation token to the client. A legitimate client will include a -copy of the token when it attempts to continue the handshake. The cryptographic -handshake extracts the token then asks QUIC a second time whether the token is -acceptable. In response, QUIC can either abort the connection or permit it to -proceed. +QUIC uses token-based address validation. Any time the server wishes +to validate a client address, it provides the client with a token. As +long as the token's authenticity can be checked (see +{{token-integrity}}) and the client is able to return that token, it +proves to the server that it received the token. + +If QUIC decides to request address validation for the current +handshake, it encodes the token in a Retry packet. The contents of +this token are consumed by the server that generates the token, so +there is no need for a single well-defined format. A token could +include information about the claimed client address (IP and port), a +timestamp, and any other supplementary information the server will +need to validate the token in the future. + +The Retry packet is sent to the client and a legitimate client will +respond with an Initial packet containing the token from the Retry packet +when it continues the handshake. In response to receiving the token, a +QUIC server can either abort the connection or permit it to proceed. A connection MAY be accepted without address validation - or with only limited validation - but a server SHOULD limit the data it sends toward an unvalidated address. Successful completion of the cryptographic handshake implicitly provides proof that the client has received packets from the server. +The client should allow for additional Retry packets being sent in response to +Initial packets sent containing a token. There are several situations in which +the server might not be able to use the previously generated token to validate +the client's address and must send a new Retry. A reasonable limit to the number +of tries the client allows for, before giving up, is 3. That is, the should +echo the address validation token from a new Retry packet up to 3 times. After +that, the client may give up on the connection attempt. -### Address Validation on Session Resumption + +### Address Validation for Future Connections A server MAY provide clients with an address validation token during one connection that can be used on a subsequent connection. Address validation is especially important with 0-RTT because a server potentially sends a significant amount of data to a client in response to 0-RTT data. -A different type of token is needed when resuming. Unlike the token that is -created during a handshake, there might be some time between when the token is -created and when the token is subsequently used. Thus, a resumption token -SHOULD include an expiration time. It is also unlikely that the client port -number is the same on two different connections; validating the port is +The server uses the NEW_TOKEN frame {{frame-new-token}} to provide the client +with an address validation token that can be used to validate future 0-RTT +connections. The client may then use this token to validate future 0-RTT +connections by including it in the Initial packet's header. The client MUST +NOT use the token provided in a RETRY for future connections. + +Unlike the token that is created for a Retry packet, there might be some time +between when the token is created and when the token is subsequently used. +Thus, a resumption token SHOULD include an expiration time. The server may +include either an explicit expiration time or an issued timestamp and +dynamically calculate the expiration time. It is also unlikely that the client +port number is the same on two different connections; validating the port is therefore unlikely to be successful. -This token can be provided to the cryptographic handshake immediately after -establishing a connection. QUIC might also generate an updated token if -significant time passes or the client address changes for any reason (see -{{migration}}). The cryptographic handshake is responsible for -providing the client with the token. In TLS the token is included in the ticket -that is used for resumption and 0-RTT, which is carried in a NewSessionTicket -message. - ### Address Validation Token Integrity {#token-integrity} @@ -1535,15 +1618,6 @@ integrity protection, malicious clients could generate or guess values for tokens that would be accepted by the server. Only the server requires access to the integrity protection key for tokens. -In TLS the address validation token is often bundled with the information that -TLS requires, such as the resumption secret. In this case, adding integrity -protection can be delegated to the cryptographic handshake protocol, avoiding -redundant protection. If integrity protection is delegated to the cryptographic -handshake, an integrity failure will result in immediate cryptographic handshake -failure. If integrity protection is performed by QUIC and the integrity check -fails, QUIC MUST abort the connection with a PROTOCOL_VIOLATION error code. - - ## Path Validation {#migrate-validate} Path validation is used by an endpoint to verify reachability of a peer over a @@ -1958,7 +2032,7 @@ These states SHOULD persist for three times the current Retransmission Timeout An endpoint enters a closing period after initiating an immediate close ({{immediate-close}}). While closing, an endpoint MUST NOT send packets unless -they contain a CONNECTION_CLOSE or APPLICATION_CLOSE frame (see +they contain a CONNECTION_CLOSE, CRYPTO_CLOSE, or APPLICATION_CLOSE frame (see {{immediate-close}} for details). In the closing state, only a packet containing a closing frame can be sent. An @@ -2023,10 +2097,10 @@ before the packet is received. ### Immediate Close -An endpoint sends a closing frame, either CONNECTION_CLOSE or APPLICATION_CLOSE, -to terminate the connection immediately. Either closing frame causes all -streams to immediately become closed; open streams can be assumed to be -implicitly reset. +An endpoint sends a closing frame, (CONNECTION_CLOSE, CRYPTO_CLOSE or +APPLICATION_CLOSE) to terminate the connection immediately. Any +closing frame causes all streams to immediately become closed; open +streams can be assumed to be implicitly reset. After sending a closing frame, endpoints immediately enter the closing state. During the closing period, an endpoint that sends a closing frame SHOULD respond @@ -2143,7 +2217,8 @@ Reset Token. A stateless reset is not appropriate for signaling error conditions. An endpoint that wishes to communicate a fatal connection error MUST use a -CONNECTION_CLOSE or APPLICATION_CLOSE frame if it has sufficient state to do so. +CONNECTION_CLOSE, CRYPTO_CLOSE, or APPLICATION_CLOSE frame if it has +sufficient state to do so. This stateless reset design is specific to QUIC version 1. An endpoint that supports multiple versions of QUIC needs to generate a stateless reset that will @@ -2377,13 +2452,12 @@ Maximum Data: : A variable-length integer indicating the maximum amount of data that can be sent on the entire connection, in units of octets. -All data sent in STREAM frames counts toward this limit, with the exception of -data on stream 0. The sum of the largest received offsets on all streams - -including streams in terminal states, but excluding stream 0 - MUST NOT exceed -the value advertised by a receiver. An endpoint MUST terminate a connection -with a QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA error if it receives more data -than the maximum data value that it has sent, unless this is a result of a -change in the initial limits (see {{zerortt-parameters}}). +All data sent in STREAM frames counts toward this limit. The sum of the largest +received offsets on all streams - including streams in terminal states - MUST +NOT exceed the value advertised by a receiver. An endpoint MUST terminate a +connection with a QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA error if it receives +more data than the maximum data value that it has sent, unless this is a result +of a change in the initial limits (see {{zerortt-parameters}}). ## MAX_STREAM_DATA Frame {#frame-max-stream-data} @@ -2676,6 +2750,12 @@ QUIC acknowledgements are irrevocable. Once acknowledged, a packet remains acknowledged, even if it does not appear in a future ACK frame. This is unlike TCP SACKs ({{?RFC2018}}). +It is expected that a sender will reuse the same packet number across different +packet number spaces. ACK frames only acknowledge the packet numbers that were +transmitted by the sender in the same packet number space of the packet that the +ACK was received in. This is an important property to allow for separation +between the different packet number spaces. + A client MUST NOT acknowledge Retry packets. Retry packets include the packet number from the Initial packet it responds to. Version Negotiation packets cannot be acknowledged because they do not contain a packet number. Rather than @@ -2839,6 +2919,9 @@ is only sending ACK frames will only receive acknowledgements for its packets if the sender includes them in packets with non-ACK frames. A sender SHOULD bundle ACK frames with other frames when possible. +Implementations must be aware of the packet number space of the packet being +transmitted and only acknowledge packets from that space. + To limit receiver state or the size of ACK frames, a receiver MAY limit the number of ACK blocks it sends. A receiver can do this even without receiving acknowledgment of its ACK frames, with the knowledge this could cause the sender @@ -2849,15 +2932,11 @@ received packets in preference to packets received in the past. ### ACK Frames and Packet Protection -ACK frames that acknowledge protected packets MUST be carried in a packet that -has an equivalent or greater level of packet protection. - -Packets that are protected with 1-RTT keys MUST be acknowledged in packets that -are also protected with 1-RTT keys. +ACK frames MUST only be carried in a packet that has the same packet number +space as the packet being ACKed (see {{packet-protected}}). -A packet that is not protected and claims to acknowledge a packet number that -was sent with packet protection is not valid. An unprotected packet that -carries acknowledgments for protected packets MUST be discarded in its entirety. +For instance, packets that are protected with 1-RTT keys MUST be acknowledged in +packets that are also protected with 1-RTT keys. Packets that a client sends with 0-RTT packet protection MUST be acknowledged by the server in packets protected by 1-RTT keys. This can mean that the client is @@ -2865,27 +2944,8 @@ unable to use these acknowledgments if the server cryptographic handshake messages are delayed or lost. Note that the same limitation applies to other data sent by the server protected by the 1-RTT keys. -Unprotected packets, such as those that carry the initial cryptographic -handshake messages, MAY be acknowledged in unprotected packets. Unprotected -packets are vulnerable to falsification or modification. Unprotected packets -can be acknowledged along with protected packets in a protected packet. - -An endpoint SHOULD acknowledge packets containing cryptographic handshake -messages in the next unprotected packet that it sends, unless it is able to -acknowledge those packets in later packets protected by 1-RTT keys. At the -completion of the cryptographic handshake, both peers send unprotected packets -containing cryptographic handshake messages followed by packets protected by -1-RTT keys. An endpoint SHOULD acknowledge the unprotected packets that complete -the cryptographic handshake in a protected packet, because its peer is -guaranteed to have access to 1-RTT packet protection keys. - -For instance, a server acknowledges a TLS ClientHello in the packet that carries -the TLS ServerHello; similarly, a client can acknowledge a TLS HelloRetryRequest -in the packet containing a second TLS ClientHello. The complete set of server -handshake messages (TLS ServerHello through to Finished) might be acknowledged -by a client in protected packets, because it is certain that the server is able -to decipher the packet. - +Implementations SHOULD aggressively ACK packets containing CRYPTO_HS frames. +See {{QUIC-RECOVERY}}, Section 3.5.1. ## PATH_CHALLENGE Frame {#frame-path-challenge} @@ -2929,6 +2989,34 @@ PATH_CHALLENGE frame previously sent by the endpoint, the endpoint MAY generate a connection error of type UNSOLICITED_PATH_RESPONSE. +## NEW_TOKEN frame {#frame-new-token} + +An server sends a NEW_TOKEN frame (type=0x21) to provide the client a token to +send in a the header of an Initial packet for a future 0-RTT connection. + +The NEW_TOKEN frame is as follows: + +~~~ + 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 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Token Length (i) ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Token (*) ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +~~~ + +The fields of a NEW_TOKEN frame are as follows: + +Token Length: + +: A variable-length integer specifying the length of the token in bytes. + +Token: + +: An opaque blob that the client may use with a future Initial packet. + + ## STREAM Frames {#frame-stream} STREAM frames implicitly create a stream and carry stream data. The STREAM @@ -3016,6 +3104,77 @@ advised to bundle as few streams as necessary in outgoing packets without losing transmission efficiency to underfilled packets. +## CRYPTO_HS Frame {#frame-crypto} + +The CRYPTO_HS frame (type=0x18) is used to transmit cryptographic handshake +messages. It can be sent in all packet types. The CRYPTO_HS frame offers the +cryptographic protocol an in-order stream of bytes. + +A CRYPTO_HS frame is shown below. + +~~~ + 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 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| [Offset (i)] ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| [Length (i)] ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Crypto Data (*) ... ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +~~~ +{: #crypto-format title="CRYPTO_HS Frame Format"} + +The CRYPTO_HS frame contains the following fields: + +Offset: + +: A variable-length integer specifying the byte offset in the stream for the + data in this CRYPTO_HS frame. + +Length: + +: A variable-length integer specifying the length of the Crypto Data field in + this CRYPTO_HS frame. + +Crypto Data: + +: The cryptographic message data. + +There is a separate flow of cryptographic handshake data in each +encryption level, each of which starts at an offset of 0. This implies +that each encryption level is treated as a separate CRYPTO_HS stream +of data. + +Unlike STREAM frames, which include a Stream ID indicating to which +stream the data belongs, the CRYPTO_HS frame carries data for a single +stream per encryption level. The stream does not have an explicit +end, so CRYPTO_HS frames do not have a FIN bit. + + +## EMPTY_ACK Frame {#frame-empty-ack} + +The EMPTY_ACK frame (type=0x19) is used to transmit loss recovery information +during the cryptographic handshake before keys are established. The EMPTY_ACK +frame is used to assist loss recovery, see {{QUIC-RECOVERY}} by indicating that +the receiver received a packet it was not able to decrypt and hence cannot send +a real ACK. + +An EMPTY_ACK frame has no content. That is, an EMPTY_ACK frame consists of the +single octet that identifies the frame as an EMPTY_ACK frame. + +## CRYPTO_CLOSE Frame {#frame-crypto-close} + +The CRYPTO_CLOSE frame (type=0x20) is used to indicate connection failures +caused by the crypto handshake. It uses the same format as the +CONNECTION_CLOSE frame ({{frame-connection-close}}), except that the +error codes are specific to the crypto protocol in use. For TLS 1.3, +the error code is simply the TLS alert number. + +Other than the error code space, the format and semantics of the +CRYPTO_CLOSE frame are identical to the CONNECTION_CLOSE frame. + + # Packetization and Reliability {#packetization} A sender bundles one or more frames in a QUIC packet (see {{frames}}). @@ -3064,6 +3223,10 @@ been lost. In general, information is sent again when a packet containing that information is determined to be lost and sending ceases when a packet containing that information is acknowledged. +* Data sent in CRYPTO_HS frames are retransmitted according to the rules in + {{QUIC-RECOVERY}}, until either all data has been ACKed or the crypto state + machine implictly knows that the peer received the data. + * Application data sent in STREAM frames is retransmitted in new STREAM frames unless the endpoint has sent a RST_STREAM for that stream. Once an endpoint sends a RST_STREAM frame, no further STREAM frames are needed. @@ -3082,9 +3245,9 @@ containing that information is acknowledged. STOP_SENDING frame, is sent until the receive stream enters either a "Data Recvd" or "Reset Recvd" state, see {{solicited-state-transitions}}. -* Connection close signals, including those that use CONNECTION_CLOSE and - APPLICATION_CLOSE frames, are not sent again when packet loss is detected, but - as described in {{termination}}. +* Connection close signals, including those that use CONNECTION_CLOSE, + CRYPTO_CLOSE, and APPLICATION_CLOSE frames, are not sent again when + packet loss is detected, but as described in {{termination}}. * The current connection maximum data is sent in MAX_DATA frames. An updated value is sent in a MAX_DATA frame if the packet containing the most recently @@ -3299,8 +3462,7 @@ The two type bits from a Stream ID therefore identify streams as summarized in | 0x3 | Server-Initiated, Unidirectional | {: #stream-id-types title="Stream ID Types"} -Stream ID 0 (0x0) is a client-initiated, bidirectional stream that is used for -the cryptographic handshake. Stream 0 MUST NOT be used for application data. +The first bi-directional stream opened by the client is stream 0. A QUIC endpoint MUST NOT reuse a Stream ID. Streams can be used in any order. Streams that are used out of order result in opening all lower-numbered streams @@ -3664,14 +3826,7 @@ change if it is sent multiple times; an endpoint MAY treat receipt of a changed octet as a connection error of type PROTOCOL_VIOLATION. An endpoint MUST NOT send data on any stream without ensuring that it is within -the data limits set by its peer. The cryptographic handshake stream, Stream 0, -is exempt from the connection-level data limits established by MAX_DATA. Data on -stream 0 other than the initial cryptographic handshake message is still subject -to stream-level data limits and MAX_STREAM_DATA. This message is exempt from -flow control because it needs to be sent in a single packet regardless of the -server's flow control state. This rule applies even for 0-RTT handshakes where -the remembered value of MAX_STREAM_DATA would not permit sending a full initial -cryptographic handshake message. +the data limits set by its peer. Flow control is described in detail in {{flow-control}}, and congestion control is described in the companion document {{QUIC-RECOVERY}}. @@ -3706,10 +3861,10 @@ the protocol functions efficiently. That is, prioritizing frames other than STREAM frames ensures that loss recovery, congestion control, and flow control operate effectively. -Stream 0 MUST be prioritized over other streams prior to the completion of the -cryptographic handshake. This includes the retransmission of the second flight -of client handshake messages, that is, the TLS Finished and any client -authentication messages. +CRYPTO_HS frames SHOULD be prioritized over other streams prior to the +completion of the cryptographic handshake. This includes the +retransmission of the second flight of client handshake messages, that +is, the TLS Finished and any client authentication messages. STREAM data in frames determined to be lost SHOULD be retransmitted before sending new data, unless application priorities indicate otherwise. @@ -3733,9 +3888,9 @@ Stream flow control, which prevents a single stream from consuming the entire receive buffer for a connection. A data receiver sends MAX_STREAM_DATA or MAX_DATA frames to the sender -to advertise additional credit. MAX_STREAM_DATA frames send the maximum -absolute byte offset of a stream, while MAX_DATA sends the maximum sum -of the absolute byte offsets of all streams other than stream 0. +to advertise additional credit. MAX_STREAM_DATA frames send the +maximum absolute byte offset of a stream, while MAX_DATA sends the +maximum sum of the absolute byte offsets of all streams. A receiver MAY advertise a larger offset at any point by sending MAX_DATA or MAX_STREAM_DATA frames. A receiver MUST NOT renege on an advertisement; that @@ -3761,11 +3916,11 @@ the sender receives an update before running out of flow control credit, even if one of the packets is lost. Connection flow control is a limit to the total bytes of stream data sent in -STREAM frames on all streams except stream 0. A receiver advertises credit for -a connection by sending a MAX_DATA frame. A receiver maintains a cumulative sum -of bytes received on all contributing streams, which are used to check for flow -control violations. A receiver might use a sum of bytes consumed on all -contributing streams to determine the maximum data limit to be advertised. +STREAM frames on all streams. A receiver advertises credit for a connection by +sending a MAX_DATA frame. A receiver maintains a cumulative sum of bytes +received on all contributing streams, which are used to check for flow control +violations. A receiver might use a sum of bytes consumed on all contributing +streams to determine the maximum data limit to be advertised. ## Edge Cases and Other Considerations @@ -3819,22 +3974,6 @@ it increases data limits based on a round-trip time estimate and the rate at which the receiving application consumes data, similar to common TCP implementations. -### Handshake Exemption - -During the initial handshake, an endpoint could need to send a larger message on -stream 0 than would ordinarily be permitted by the peer's initial stream flow -control window. Since MAX_STREAM_DATA frames are not permitted in these early -packets, the peer cannot provide additional flow control window in order to -complete the handshake. - -Endpoints MAY exceed the flow control limits on stream 0 prior to the completion -of the cryptographic handshake. (That is, in Initial, Retry, and Handshake -packets.) However, once the handshake is complete, endpoints MUST NOT send -additional data beyond the peer's permitted offset. If the amount of data sent -during the handshake exceeds the peer's maximum offset, the endpoint cannot send -additional data on stream 0 until the peer has sent a MAX_STREAM_DATA frame -indicating a larger maximum offset. - ## Stream Limit Increment As with flow control, this document leaves when and how many streams to make @@ -3893,6 +4032,14 @@ errors is not mandatory, but only because requiring that an endpoint generate these errors also means that the endpoint needs to maintain the final offset state for closed streams, which could mean a significant state commitment. +## Flow control of CRYPTO_HS data {#flow-control-crypto} + +Data sent in CRYPTO_HS frames is not flow controlled in the same way as STREAM +frames. QUIC relies on the cryptographic protocol implementation to avoid +excessive buffering of data, see {{QUIC-TLS}}. The implementation SHOULD +provide an interface to QUIC to tell it about its buffering limits so that there +is no excessive buffering at multiple layers. + # Error Handling @@ -3905,40 +4052,45 @@ The most appropriate error code ({{error-codes}}) SHOULD be included in the frame that signals the error. Where this specification identifies error conditions, it also identifies the error code that is used. -A stateless reset ({{stateless-reset}}) is not suitable for any error that can -be signaled with a CONNECTION_CLOSE, APPLICATION_CLOSE, or RST_STREAM frame. A -stateless reset MUST NOT be used by an endpoint that has the state necessary to -send a frame on the connection. +A stateless reset ({{stateless-reset}}) is not suitable for any error +that can be signaled with a CONNECTION_CLOSE, CRYPTO_CLOSE, +APPLICATION_CLOSE, or RST_STREAM frame. A stateless reset MUST NOT be +used by an endpoint that has the state necessary to send a frame on +the connection. ## Connection Errors -Errors that result in the connection being unusable, such as an obvious -violation of protocol semantics or corruption of state that affects an entire -connection, MUST be signaled using a CONNECTION_CLOSE or APPLICATION_CLOSE frame -({{frame-connection-close}}, {{frame-application-close}}). An endpoint MAY close -the connection in this manner even if the error only affects a single stream. - -Application protocols can signal application-specific protocol errors using the -APPLICATION_CLOSE frame. Errors that are specific to the transport, including -all those described in this document, are carried in a CONNECTION_CLOSE frame. -Other than the type of error code they carry, these frames are identical in -format and semantics. - -A CONNECTION_CLOSE or APPLICATION_CLOSE frame could be sent in a packet that is -lost. An endpoint SHOULD be prepared to retransmit a packet containing either -frame type if it receives more packets on a terminated connection. Limiting the -number of retransmissions and the time over which this final packet is sent +Errors that result in the connection being unusable, such as an +obvious violation of protocol semantics or corruption of state that +affects an entire connection, MUST be signaled using a +CONNECTION_CLOSE, CRYPTO_CLOSE, or APPLICATION_CLOSE frame +({{frame-connection-close}}, {{frame-crypto-close}}, +{{frame-application-close}}). An endpoint MAY close the connection in +this manner even if the error only affects a single stream. + +Application protocols can signal application-specific protocol errors +using the APPLICATION_CLOSE frame. Errors that are specific to the +transport, including all those described in this document, are carried +in a CONNECTION_CLOSE frame. Other than the type of error code they +carry, these frames are identical in format and semantics. + +A CONNECTION_CLOSE, CRYPTO_CLOSE, or APPLICATION_CLOSE frame could be +sent in a packet that is lost. An endpoint SHOULD be prepared to +retransmit a packet containing either frame type if it receives more +packets on a terminated connection. Limiting the number of +retransmissions and the time over which this final packet is sent limits the effort expended on terminated connections. -An endpoint that chooses not to retransmit packets containing CONNECTION_CLOSE -or APPLICATION_CLOSE risks a peer missing the first such packet. The only -mechanism available to an endpoint that continues to receive data for a -terminated connection is to use the stateless reset process -({{stateless-reset}}). +An endpoint that chooses not to retransmit packets containing +CONNECTION_CLOSE, CRYPTO_CLOSE, or APPLICATION_CLOSE risks a peer +missing the first such packet. The only mechanism available to an +endpoint that continues to receive data for a terminated connection is +to use the stateless reset process ({{stateless-reset}}). -An endpoint that receives an invalid CONNECTION_CLOSE or APPLICATION_CLOSE frame -MUST NOT signal the existence of the error to its peer. +An endpoint that receives an invalid CONNECTION_CLOSE, CRYPTO_CLOSE, +or APPLICATION_CLOSE frame MUST NOT signal the existence of the error +to its peer. ## Stream Errors @@ -3948,10 +4100,6 @@ connection in a recoverable state, the endpoint can send a RST_STREAM frame ({{frame-rst-stream}}) with an appropriate error code to terminate just the affected stream. -Stream 0 is critical to the functioning of the entire connection. If stream 0 -is closed with either a RST_STREAM or STREAM frame bearing the FIN flag, an -endpoint MUST generate a connection error of type PROTOCOL_VIOLATION. - Other than STOPPING ({{solicited-state-transitions}}), RST_STREAM MUST be instigated by the application and MUST carry an application error code. Resetting a stream without knowledge of the application protocol could cause the @@ -4313,6 +4461,15 @@ the range from 0xFE00 to 0xFFFF. Issue and pull request numbers are listed with a leading octothorp. +## Since draft-ietf-quic-transport-12 + +- Enable server to transition connections to a preferred address (#560,#1251). +- No more stream 0. +- EMPTY_ACK, CRYPTO_HS, and CRYPTO_CLOSE frames +- Move stateless retry to the QUIC layer. +- Added token fields to Initial packet header. +- Added NEW_TOKEN frame. + ## Since draft-ietf-quic-transport-11 - Enable server to transition connections to a preferred address (#560, #1251) From cab82952ab67bd994da0da4160af42f2e95a9850 Mon Sep 17 00:00:00 2001 From: EKR Date: Tue, 22 May 2018 18:17:22 -0700 Subject: [PATCH 02/31] Fix changelog --- draft-ietf-quic-recovery.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index 212b784e8a..01540667c2 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -1189,6 +1189,10 @@ This document has no IANA actions. Yet. > **RFC Editor's Note:** Please remove this section prior to > publication of a final version of this document. +## Since draft-ietf-quic-recovery-12 + +- Updated to match the design team proposal. + ## Since draft-ietf-quic-recovery-11 - Text on multiple packet number spaces and relevant optimizations. From 984ecc86d259d76d8498f3b4990bb5cfdc10c448 Mon Sep 17 00:00:00 2001 From: EKR Date: Tue, 22 May 2018 19:11:17 -0700 Subject: [PATCH 03/31] Fix whitespace --- draft-ietf-quic-transport.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 10fdbef9fb..9e61c446f1 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -3826,7 +3826,7 @@ change if it is sent multiple times; an endpoint MAY treat receipt of a changed octet as a connection error of type PROTOCOL_VIOLATION. An endpoint MUST NOT send data on any stream without ensuring that it is within -the data limits set by its peer. +the data limits set by its peer. Flow control is described in detail in {{flow-control}}, and congestion control is described in the companion document {{QUIC-RECOVERY}}. From 36899e50d963d6d7aa427168d45311f444014bdf Mon Sep 17 00:00:00 2001 From: EKR Date: Tue, 22 May 2018 20:12:46 -0700 Subject: [PATCH 04/31] Offset and length fields in CRYPTO_HS are not optional --- draft-ietf-quic-transport.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 9e61c446f1..0b010ecda3 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -3116,9 +3116,9 @@ A CRYPTO_HS frame is shown below. 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| [Offset (i)] ... +| Offset (i) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| [Length (i)] ... +| Length (i) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Crypto Data (*) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ From f8f172f52889036ddbc697165393194a28073b0d Mon Sep 17 00:00:00 2001 From: ianswett Date: Wed, 6 Jun 2018 12:15:49 -0400 Subject: [PATCH 05/31] Remove EMPTY_ACK --- draft-ietf-quic-recovery.md | 61 +++++-------------------------------- 1 file changed, 7 insertions(+), 54 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index 01540667c2..75210bbf11 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -132,7 +132,7 @@ Separating the spaces allows the recovery mechanisms to work without special cases to avoid spuriously retransmitting un-processable packets. Separate packet number spaces do not imply separate paths. Consequently, a sender need not split congestion control actions across packet number spaces. -The optimizations described in {{optimizations}} help a sender co-ordinate +The optimizations described in {{optimizations}} help a sender optimize loss detection across packet number spaces. ### Monotonically Increasing Packet Numbers @@ -423,37 +423,8 @@ There are cases where one may be able to gain recovery information from acknowledgements of packets in another packet number space, but they rely on complex assumptions about the peer’s processing and acknowledgement algorithms. Even those are unable to quickly recover from cases such as -losing the client's Initial, but receiving the 0-RTT packets. Below are -three different optimizations in increasing complexity that minimize -handshake latency. - -### EMPTY_ACK frames - -The EMPTY_ACK frame indicates a packet for the connection was received, -but it could not be processed, because the decryption keys are not yet -available. EMPTY_ACK enables faster recovery of lost Initial -and Handshake packets when the only other outstanding packets are -undecryptable. - -The receiver SHOULD send an EMPTY_ACK frame soon (e.g., 1ms) after -undecryptable packets are received, even if those received packets are -not buffered for later decryption. The small delay allows for cases when -0-RTT packets are reordered in front of the Initial, which is not uncommon -on networks that prioritize small packets. The receiver should limit the -number of EMPTY_ACK frames sent to one per packet number space per RTT. -If no RTT is known, only one per encryption level should be sent. - -When an EMPTY_ACK frame is received, a sender should immediately -retransmit the missing handshake packet(s) as though the handshake timer -fired and re-arm the handshake timer when the handshake packets are sent. -If the missing handshake data was timer retransmitted after the packets -that triggered the empty ack, then the empty ack should be ignored. - -An EMPTY_ACK frame does not acknowledge a new packet, and in cases -when multiple packets are outstanding, the RTT signal is ambiguous, -so it should not be used like an RTT signal from a newly acknowledged -packet. It MAY change the connection’s default RTT if no RTT measurements -have been taken. +losing the client's Initial, but receiving the 0-RTT packets. Below is +an optimization using coalesced packets and implicit acknowledgements. ### Coalesced Packets @@ -472,20 +443,11 @@ This optimization is particularly useful when: (containing the client Finished) and can proactively retransmit the final client flight with one or more 1-RTT packets. -### Implicit Acknowledgements +### Implicit Acknowledgements of Initial -Handshake data may be cancelled when packets at a higher encryption -level are processed, as this demonstrates the peer has received the -handshake data at the prior encryption level. - -In particular: - - * Processing data in a Handshake packet indicates the Initial - packet(s) have been delivered. - * A Server processing 1-RTT packets indicates all CRYPTO_HS data in - Handshake packets has been delivered. - * Processing 0-RTT packets does not indicate the peer has received - any handshake data. +Initial data may be cancelled when packets at the Handshake level +are received and processed, because that indicates all packets at +Initial encryption have been received and processed by the peer. ## Generating Acknowledgements @@ -730,18 +692,9 @@ Pseudocode for OnPacketSent follows: When an ack is received, it may acknowledge 0 or more packets. -When an EMPTY_ACK frame is received, it does not acknowledge -any packets, but it may cause handshake data to be retransmitted. - Pseudocode for OnAckReceived and UpdateRtt follow: ~~~ - OnEmptyAckReceived(): - // TODO: This is incorrect for the Initial/Handshake - if (time_of_last_sent_handshake_packet < - time_of_last_sent_retransmittable_packet): - RetransmitAllHandshakeData(); - OnAckReceived(ack): largest_acked_packet = ack.largest_acked // If the largest acked is newly acked, update the RTT. From 70b26e8c3ae6b30acbcb9b915eac98e6757d2a5d Mon Sep 17 00:00:00 2001 From: EKR Date: Wed, 6 Jun 2018 09:16:28 -0700 Subject: [PATCH 06/31] Incorporate the comments from PR#1377 --- draft-ietf-quic-recovery.md | 20 +++++++++++--------- draft-ietf-quic-tls.md | 15 ++++++++++++--- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index 75210bbf11..f3e8bf04a5 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -145,15 +145,17 @@ number for transmissions, and any data that is to be delivered to the receiving application(s) is sent in one or more streams, with delivery order determined by stream offsets encoded within STREAM frames. -QUIC's packet number is strictly increasing within a packet number space, -and directly encodes transmission order. A higher QUIC packet number signifies -that the packet was sent later, and a lower QUIC packet number signifies that -the packet was sent earlier. When a packet containing frames is deemed lost, -QUIC rebundles necessary frames in a new packet with a new packet number, -removing ambiguity about which packet is acknowledged when an ACK is received. -Consequently, more accurate RTT measurements can be made, spurious -retransmissions are trivially detected, and mechanisms such as Fast Retransmit -can be applied universally, based only on packet number. +QUIC's packet number is strictly increasing within a packet number +space, and directly encodes transmission order. A higher QUIC packet +number signifies that the packet was sent later, and a lower QUIC +packet number signifies that the packet was sent earlier. When a +packet containing frames is deemed lost, QUIC rebundles the +retransmittable data in a new packet with a new packet number, +removing ambiguity about which packet is acknowledged when an ACK is +received. Consequently, more accurate RTT measurements can be made, +spurious retransmissions are trivially detected, and mechanisms such +as Fast Retransmit can be applied universally, based only on packet +number. This design point significantly simplifies loss detection mechanisms for QUIC. Most TCP mechanisms implicitly attempt to infer transmission ordering based on diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 328b6488e2..622347ba57 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -336,10 +336,18 @@ encryption level are the same in QUIC as in TLS over TCP: Because packets may be reordered on the wire, QUIC uses the packet type to indicate which level a given packet was encrypted -under [TODO: Table needed here?]. When multiple packets of +under, as shown in {{packet-types-levels}}. When multiple packets of different encryption levels need to be sent, endpoints SHOULD use -compound packets to send them in the same UDP datagram. +coalesced packets to send them in the same UDP datagram. +| Packet Type | Encryption Level | +|:----------------|:-----------------| +| Initial | Obfuscation | +| 0-RTT Protected | 0-RTT | +| Handshake | Handshake | +| Retry | N/A | +| Short Header | 1-RTT | +{: #packet-types-levels title="Encryption Levels by Packet Type"} ## Handshake and Setup Sequence @@ -347,6 +355,7 @@ The integration of QUIC with a TLS handshake is shown in more detail in {{quic-tls-handshake}}. ~~~ +[TODO(ekr@rtfm.com): replace this diagram per the meeting today.] Client Server Date: Wed, 6 Jun 2018 12:19:48 -0400 Subject: [PATCH 07/31] Remove EMPTY_ACK --- draft-ietf-quic-transport.md | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 0b010ecda3..b228bae4f7 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -996,9 +996,8 @@ explained in more detail as they are referenced later in the document. | 0x0f | PATH_RESPONSE | {{frame-path-response}} | | 0x10 - 0x17 | STREAM | {{frame-stream}} | | 0x18 | CRYPTO_HS | {{frame-crypto}} | -| 0x19 | EMPTY_ACK | {{frame-empty-ack}} | -| 0x20 | CRYPTO_CLOSE | {{frame-crypto-close}} | -| 0x21 | NEW_TOKEN | {{frame-new-token}} | +| 0x19 | CRYPTO_CLOSE | {{frame-crypto-close}} | +| 0x20 | NEW_TOKEN | {{frame-new-token}} | {: #frame-types title="Frame Types"} All QUIC frames are idempotent. That is, a valid frame does not cause @@ -3152,17 +3151,6 @@ stream per encryption level. The stream does not have an explicit end, so CRYPTO_HS frames do not have a FIN bit. -## EMPTY_ACK Frame {#frame-empty-ack} - -The EMPTY_ACK frame (type=0x19) is used to transmit loss recovery information -during the cryptographic handshake before keys are established. The EMPTY_ACK -frame is used to assist loss recovery, see {{QUIC-RECOVERY}} by indicating that -the receiver received a packet it was not able to decrypt and hence cannot send -a real ACK. - -An EMPTY_ACK frame has no content. That is, an EMPTY_ACK frame consists of the -single octet that identifies the frame as an EMPTY_ACK frame. - ## CRYPTO_CLOSE Frame {#frame-crypto-close} The CRYPTO_CLOSE frame (type=0x20) is used to indicate connection failures @@ -4465,7 +4453,7 @@ Issue and pull request numbers are listed with a leading octothorp. - Enable server to transition connections to a preferred address (#560,#1251). - No more stream 0. -- EMPTY_ACK, CRYPTO_HS, and CRYPTO_CLOSE frames +- CRYPTO_HS, and CRYPTO_CLOSE frames - Move stateless retry to the QUIC layer. - Added token fields to Initial packet header. - Added NEW_TOKEN frame. From aa1b6834af8b327ef0ef761b9daede3447504deb Mon Sep 17 00:00:00 2001 From: ianswett Date: Wed, 6 Jun 2018 12:29:46 -0400 Subject: [PATCH 08/31] Update draft-ietf-quic-transport.md --- draft-ietf-quic-transport.md | 1 + 1 file changed, 1 insertion(+) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index b228bae4f7..e82ddd2f49 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -1529,6 +1529,7 @@ handshake packet is padded to at least 1200 octets. This allows a server to send a similar amount of data without risking causing an amplification attack toward an unproven remote address. +TODO(ekr): Receipt of Hanshake is now confirmation of the peer's address/etc A server eventually confirms that a client has received its messages when the cryptographic handshake successfully completes. This might be insufficient, either because the server wishes to avoid the computational cost of completing From 927cf128a760708657f3d7ea76ba0495ed60af49 Mon Sep 17 00:00:00 2001 From: EKR Date: Thu, 7 Jun 2018 02:35:51 -0700 Subject: [PATCH 09/31] Add the TLS diagrams --- draft-ietf-quic-transport.md | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index e82ddd2f49..5ffac3e5b9 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -1223,6 +1223,64 @@ of handshake data starting from an offset of 0. Details of how TLS is integrated with QUIC are provided in {{QUIC-TLS}}. +{{tls-1rtt-handshake}} provides an overview of the 1-RTT handshake. +Each line shows a QUIC packet with the packet type and packet +number shown first, followed by the contents. So, for instance +the first packet is of type Initial, with packet number 0, and +contains a CRYPTO_HS frame carrying the ClientHello. + +Note that multiple QUIC packets may be coalesced into a single +UDP datagram (see {{packet-coalesce}}, and so this handshake +may consist of anywhere from 4 to 9 UDP datagrams. Moreover, +each UDP datagram may consist of multiple packets of different +encryption levels. For instance, the server's first flight +contains packets from the Initial encryption level +(obfuscation), the Handshake level, and "0.5-RTT data" +from the server at the 1-RTT encryption level. + +~~~~ +Client Server + +Initial[0]: CRYPTO_HS[CH] -> + + Initial[0]: CRYPTO_HS[SH] ACK[0] + Handshake[0]: CRYPTO_HS[EE, CERT, CV, FIN] + <- 1-RTT[0]: STREAM[0, "..."] + +Initial[1]: ACK[0] +Handshake[0]: CRYPTO_HS[FIN], ACK[0] +1-RTT[0]: STREAM[0, "..."], ACK[0] -> + + 1-RTT[1]: STREAM[55, "..."], ACK[0] + <- Handshake[1]: ACK[0] +~~~~ +{: #tls-1rtt-handshake title="Example 1-RTT Handshake"} + + +{{tls-0rtt-handshake}} shows an example of a connection with a +0-RTT handshake and a single packet of 0-RTT data. Note that +as described in {{packet-numbers}}, the server ACKs the +0-RTT data at the 1-RTT encryption level, and the client's +sequence numbers at the 1-RTT encryption level continue +to increment from it's 0-RTT packets. + +~~~~ +Client Server + +Initial[0]: CRYPTO_HS[CH] +0-RTT[0]: STREAM[0, "..."] -> + + Initial[0]: CRYPTO_HS[SH] ACK[0] + Handshake[0] CRYPTO_HS[EE, CERT, CV, FIN] + <- 1-RTT[0]: STREAM[0, "..."] ACK[0] + +Initial[1]: ACK[0] +0-RTT[1]: CRYPTO_HS[EOED] +Handshake[0]: CRYPTO_HS[FIN], ACK[0] +1-RTT[2]: STREAM[0, "..."], ACK[0] -> +~~~~ +{: #tls-0rtt-handshake title="Example 1-RTT Handshake"} + ## Transport Parameters From 74300a1be6e84f5deec8dcb513bc370433e1dca3 Mon Sep 17 00:00:00 2001 From: EKR Date: Thu, 7 Jun 2018 02:58:23 -0700 Subject: [PATCH 10/31] Redact diagram from the TLS doc --- draft-ietf-quic-tls.md | 50 ++---------------------------------------- 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 622347ba57..8ad2be1265 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -349,54 +349,8 @@ coalesced packets to send them in the same UDP datagram. | Short Header | 1-RTT | {: #packet-types-levels title="Encryption Levels by Packet Type"} -## Handshake and Setup Sequence - -The integration of QUIC with a TLS handshake is shown in more detail in -{{quic-tls-handshake}}. - -~~~ -[TODO(ekr@rtfm.com): replace this diagram per the meeting today.] -Client Server - - ---------> - -(STREAM[0-RTTData]) ---------> - - <--------- - - <--------- {CRYPTO_HS[ - EncryptedExtensions, - Certificate, - CertificateVerify, - Finished]} - - <--------- {STREAM[0.5-RTT Data]) -{ACK, - CRYPTO_HS[Finished]} ---------> - -[Any frames] <--------> [Any frames] - -~~~ -{: #quic-tls-handshake title="QUIC Handshake"} - -In {{quic-tls-handshake}}, symbols mean: - -* "<" and ">" enclose packets protected with Initial keys {{initial-secrets}}. - -* "(" and ")" enclose packets that are protected with 0-RTT handshake or - application keys. - -* "{" and "}" enclose packets that are protected by the Handshake keys. - -* "[" and "]" enclose packets that are protected by the Application keys. - -* CRYPTO_HS[...], STREAM[...] and ACK indicate QUIC frames. - -If 0-RTT is not attempted, then the client does not send packets protected by -the 0-RTT key. - +{{QUIC-TRANSPORT}}; Section 6.3 shows how packets at the various encryption +levels fit into the handshake process. ## Interface to TLS From 04fd3213c3873c7f8593a16115b36061421251a3 Mon Sep 17 00:00:00 2001 From: EKR Date: Thu, 7 Jun 2018 04:52:07 -0700 Subject: [PATCH 11/31] Ian Swett's comments --- draft-ietf-quic-transport.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 5ffac3e5b9..237ad5c687 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -1221,7 +1221,10 @@ The CRYPTO_HS frame can be sent in different packet number spaces. CRYPTO_HS frames in each packet number space carry a separate sequence of handshake data starting from an offset of 0. -Details of how TLS is integrated with QUIC are provided in {{QUIC-TLS}}. +## Example Handshake Flows + +Details of how TLS is integrated with QUIC are provided in {{QUIC-TLS}}, +but we provide some examples here. {{tls-1rtt-handshake}} provides an overview of the 1-RTT handshake. Each line shows a QUIC packet with the packet type and packet @@ -1229,14 +1232,13 @@ number shown first, followed by the contents. So, for instance the first packet is of type Initial, with packet number 0, and contains a CRYPTO_HS frame carrying the ClientHello. -Note that multiple QUIC packets may be coalesced into a single -UDP datagram (see {{packet-coalesce}}, and so this handshake -may consist of anywhere from 4 to 9 UDP datagrams. Moreover, -each UDP datagram may consist of multiple packets of different -encryption levels. For instance, the server's first flight -contains packets from the Initial encryption level -(obfuscation), the Handshake level, and "0.5-RTT data" -from the server at the 1-RTT encryption level. +Note that multiple QUIC packets -- even of different encryption levels +-- may be coalesced into a single UDP datagram (see +{{packet-coalesce}}, and so this handshake may consist of anywhere +from 4 to 9 UDP datagrams. For instance, the server's first flight +contains packets from the Initial encryption level (obfuscation), the +Handshake level, and "0.5-RTT data" from the server at the 1-RTT +encryption level. ~~~~ Client Server From bf9c62cb42534d90efc7aae65e16c31b793a75b6 Mon Sep 17 00:00:00 2001 From: EKR Date: Thu, 7 Jun 2018 05:16:19 -0700 Subject: [PATCH 12/31] server-initiated streams start from 1 --- draft-ietf-quic-transport.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 237ad5c687..cb121464c5 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -1247,7 +1247,7 @@ Initial[0]: CRYPTO_HS[CH] -> Initial[0]: CRYPTO_HS[SH] ACK[0] Handshake[0]: CRYPTO_HS[EE, CERT, CV, FIN] - <- 1-RTT[0]: STREAM[0, "..."] + <- 1-RTT[0]: STREAM[1, "..."] Initial[1]: ACK[0] Handshake[0]: CRYPTO_HS[FIN], ACK[0] @@ -1274,7 +1274,7 @@ Initial[0]: CRYPTO_HS[CH] Initial[0]: CRYPTO_HS[SH] ACK[0] Handshake[0] CRYPTO_HS[EE, CERT, CV, FIN] - <- 1-RTT[0]: STREAM[0, "..."] ACK[0] + <- 1-RTT[0]: STREAM[1, "..."] ACK[0] Initial[1]: ACK[0] 0-RTT[1]: CRYPTO_HS[EOED] From 77155f9f535fddf86c88bd18db0cce32edb66555 Mon Sep 17 00:00:00 2001 From: EKR Date: Fri, 8 Jun 2018 12:12:18 -0700 Subject: [PATCH 13/31] Remove last TODO --- draft-ietf-quic-tls.md | 48 +++--------------------------------- draft-ietf-quic-transport.md | 10 +++----- 2 files changed, 6 insertions(+), 52 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 8ad2be1265..1b8a19f70d 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -397,9 +397,9 @@ the network, it proceeds as follows: - If the packet is from a previously installed encryption level, it MUST not contain data which extends past the end of previously - received data in that flow. [TODO(ekr): Double check that this - can't happen]. Implementations MUST treat any violations of this - requirement as a connection error of type PROTOCOL_VIOLATION. + received data in that flow. Implementations MUST treat any + violations of this requirement as a connection error of type + PROTOCOL_VIOLATION. Each time that TLS is provided with new data, new handshake octets are requested from TLS. TLS might not provide any octets if the handshake @@ -554,7 +554,6 @@ A server MUST NOT use post-handshake client authentication (see Section 4.6.2 of ## Enabling 0-RTT {#enable-0rtt} -[TODO(ekr@rtfm.com): I'm not sure that this is correct any more.] In order to be usable for 0-RTT, TLS MUST provide a NewSessionTicket message that contains the "max_early_data" extension with the value 0xffffffff; the amount of data which the client can send in 0-RTT is controlled by the @@ -1003,47 +1002,6 @@ completes, and reliance on them should be minimized. However, any tampering with the parameters will be detected when the handshake completes. - -## QUIC Max Crypto Data Extension {#max_crypto_data} - -When QUIC provides TLS messages via the CRYPTO_HS frame, one TLS -message may be fragmented across different packets. TLS -implementations may choose to limit the data they buffer before the -handshake is completed and close the connection on receiving too much -data. - -To communicate the maximum amount of data that TLS will allow to be sent in -CRYPTO_HS frames, TLS MAY use the `max_crypto_data` extension, defined as -follows: - -~~~ - enum { - max_crypto_data(27), (65535) - } ExtensionType; - - struct { - uint32 max_crypto_data; - } MaxCryptoData; -~~~ - -max_crypto_data: - -: The maximum number of bytes that can be sent in CRYPTO_HS frames - -The `extension_data` field of the extension contains the MaxCryptoData -structure. - -Implementations SHOULD send this extension. Receivers do not need to -process this extension. If a receiver does process this extension and -will not be able to fit its handshake into the limit, it SHOULD -terminate the connection with a TODO error. If an implementation sends -this extension and received more than max_crypto_data bytes from its -peer, it SHOULD terminate the connection with a TODO error. The -purpose of this extension is to provide a facility to debug issues -during the handshake and also allow future extensibility of the -protocol to larger message sizes. - - # Security Considerations There are likely to be some real clangers here eventually, but the current set diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index cb121464c5..320ad38a0b 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -1207,11 +1207,8 @@ as the record encryption layer for the cryptographic protocol. The initial CRYPTO_HS frame MUST be sent in a single packet. Any second attempt that is triggered by address validation MUST also be -sent within a single packet. This avoids having to reassemble a -message from multiple packets. Reassembling messages requires that a -server maintain state prior to establishing a connection, exposing the -server to a denial of service risk. \[\[TODO: Reword this with retry -proposal.]] +sent within a single packet. This avoids having to reassemble a +message from multiple packets. The first client packet of the cryptographic handshake protocol MUST fit within a 1232 octet QUIC packet payload. This includes overheads that reduce the space @@ -1589,9 +1586,8 @@ handshake packet is padded to at least 1200 octets. This allows a server to send a similar amount of data without risking causing an amplification attack toward an unproven remote address. -TODO(ekr): Receipt of Hanshake is now confirmation of the peer's address/etc A server eventually confirms that a client has received its messages when the -cryptographic handshake successfully completes. This might be insufficient, +first Handshake-level message is received. This might be insufficient, either because the server wishes to avoid the computational cost of completing the handshake, or it might be that the size of the packets that are sent during the handshake is too large. This is especially important for 0-RTT, where the From 779b3a007bae19afeed9bd32d8f3bc58640f67d2 Mon Sep 17 00:00:00 2001 From: EKR Date: Fri, 15 Jun 2018 07:42:06 -0700 Subject: [PATCH 14/31] Minor editorial --- draft-ietf-quic-recovery.md | 2 +- draft-ietf-quic-transport.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index f3e8bf04a5..6b1d2d81e9 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -90,7 +90,7 @@ when, and only when, they appear in all capitals, as shown here. # Design of the QUIC Transmission Machinery All transmissions in QUIC are sent with a packet-level header, which indicates -an encryption level and includes a packet sequence number +the encryption level and includes a packet sequence number (referred to below as a packet number). The encryption level indicates the packet number space, as described in {{QUIC-TRANSPORT}}. Packet numbers never repeat within a packet number space for the lifetime of a diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 320ad38a0b..4a09ef03ce 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -3935,7 +3935,7 @@ receive buffer for a connection. A data receiver sends MAX_STREAM_DATA or MAX_DATA frames to the sender to advertise additional credit. MAX_STREAM_DATA frames send the maximum absolute byte offset of a stream, while MAX_DATA sends the -maximum sum of the absolute byte offsets of all streams. +maximum of the sum of the absolute byte offsets of all streams. A receiver MAY advertise a larger offset at any point by sending MAX_DATA or MAX_STREAM_DATA frames. A receiver MUST NOT renege on an advertisement; that From d3b055a6e9afc403a9b0cb2862f09880938b5eb7 Mon Sep 17 00:00:00 2001 From: EKR Date: Fri, 15 Jun 2018 07:43:04 -0700 Subject: [PATCH 15/31] Remove the advice on how to use coalesced packets for recovery. This may be re-added in a future PR, but isn't part of the minimal set for the stream 0 DT. --- draft-ietf-quic-recovery.md | 50 ------------------------------------- 1 file changed, 50 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index 6b1d2d81e9..d536c72640 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -428,56 +428,6 @@ algorithms. Even those are unable to quickly recover from cases such as losing the client's Initial, but receiving the 0-RTT packets. Below is an optimization using coalesced packets and implicit acknowledgements. -### Coalesced Packets - -Despite loss recovery being separate for different packet number spaces, -the ability to send a coalesced packet enables faster recovery with small, -and sometimes no overhead. The acknowledgement of a coalesced packet -allows QUIC recovery to use early retransmit to determine if any prior -packets in that space were lost without waiting for timeouts. - -This optimization is particularly useful when: - - * Sending the client’s Initial, which must be padded to a full - sized packet, so the datagram typically has extra space to retransmit - some outstanding 0-RTT data. - * The clients sends 1-RTT data soon after the final TLS flight - (containing the client Finished) and can proactively retransmit the - final client flight with one or more 1-RTT packets. - -### Implicit Acknowledgements of Initial - -Initial data may be cancelled when packets at the Handshake level -are received and processed, because that indicates all packets at -Initial encryption have been received and processed by the peer. - -## Generating Acknowledgements - -An ACK frame acknowledges packets from only one packet number space. -Received packets from each packet number space should be stored -separately while multiple spaces have outstanding data. - -QUIC SHOULD delay sending acknowledgements in response to packets, -but MUST NOT excessively delay acknowledgements of packets containing -non-ack frames. Specifically, implementaions MUST attempt to -enforce a maximum ack delay to avoid causing the peer spurious -timeouts. The default maximum ack delay in QUIC is 25ms. - -An acknowledgement MAY be sent for every second full-sized packet, -as TCP does {{?RFC5681}}, or may be sent less frequently, as long as -the delay does not exceed the maximum ack delay. QUIC recovery algorithms -do not assume the peer generates an acknowledgement immediately when -receiving a second full-sized packet. - -Out-of-order packets SHOULD be acknowledged more quickly, in order -to accelerate loss recovery. The receiver SHOULD send an immediate ACK -when it receives a new packet which is not one greater than the -largest received packet number. - -As an optimization, a receiver MAY process multiple packets before -sending any ACK frames in response. In this case they can determine -whether an immediate or delayed acknowledgement should be generated -after processing incoming packets. ### Crypto Handshake Data From 48c9b9fde954d6a8b3a52e5ee7006fffd0c8a6ca Mon Sep 17 00:00:00 2001 From: EKR Date: Fri, 15 Jun 2018 07:47:51 -0700 Subject: [PATCH 16/31] Self-review, ready to submit --- draft-ietf-quic-tls.md | 8 ++++---- draft-ietf-quic-transport.md | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 1b8a19f70d..0cd1651d98 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -235,7 +235,7 @@ QUIC {{QUIC-TRANSPORT}} assumes responsibility for the confidentiality and integrity protection of packets. For this it uses keys derived from a TLS 1.3 handshake {{!TLS13}}, but instead of carrying TLS records over QUIC (as with TCP), TLS Handshake and Alert messages are carried directly -over QUIC transport, which takes over the responsibilities of the TLS +over the QUIC transport, which takes over the responsibilities of the TLS record layer, as shown below. ~~~~ @@ -305,8 +305,8 @@ as QUIC STREAM frames which are then carried in QUIC packets. # Carrying TLS Messages {#carrying-tls} QUIC carries TLS handshake data in CRYPTO_HS frames, each of which -consists of a contiguous block of handshake data (identified by an -offset and length). Those frames are packaged into QUIC packets +consists of a contiguous block of handshake data identified by an +offset and length. Those frames are packaged into QUIC packets and encrypted under the current TLS encryption level. As with TLS over TCP, once TLS handshake data has been delivered to QUIC, it is QUIC's responsibility to deliver it @@ -342,7 +342,7 @@ coalesced packets to send them in the same UDP datagram. | Packet Type | Encryption Level | |:----------------|:-----------------| -| Initial | Obfuscation | +| Initial | Initial secrets | | 0-RTT Protected | 0-RTT | | Handshake | Handshake | | Retry | N/A | diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 4a09ef03ce..15abc559c4 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -1261,7 +1261,7 @@ Handshake[0]: CRYPTO_HS[FIN], ACK[0] as described in {{packet-numbers}}, the server ACKs the 0-RTT data at the 1-RTT encryption level, and the client's sequence numbers at the 1-RTT encryption level continue -to increment from it's 0-RTT packets. +to increment from its 0-RTT packets. ~~~~ Client Server @@ -1630,13 +1630,14 @@ validation - but a server SHOULD limit the data it sends toward an unvalidated address. Successful completion of the cryptographic handshake implicitly provides proof that the client has received packets from the server. -The client should allow for additional Retry packets being sent in response to -Initial packets sent containing a token. There are several situations in which -the server might not be able to use the previously generated token to validate -the client's address and must send a new Retry. A reasonable limit to the number -of tries the client allows for, before giving up, is 3. That is, the should -echo the address validation token from a new Retry packet up to 3 times. After -that, the client may give up on the connection attempt. +The client should allow for additional Retry packets being sent in +response to Initial packets sent containing a token. There are several +situations in which the server might not be able to use the previously +generated token to validate the client's address and must send a new +Retry. A reasonable limit to the number of tries the client allows +for, before giving up, is 3. That is, the client SHOULD echo the +address validation token from a new Retry packet up to 3 times. After +that, it MAY give up on the connection attempt. ### Address Validation for Future Connections @@ -2988,11 +2989,10 @@ received packets in preference to packets received in the past. ### ACK Frames and Packet Protection -ACK frames MUST only be carried in a packet that has the same packet number -space as the packet being ACKed (see {{packet-protected}}). - -For instance, packets that are protected with 1-RTT keys MUST be acknowledged in -packets that are also protected with 1-RTT keys. +ACK frames MUST only be carried in a packet that has the same packet +number space as the packet being ACKed (see {{packet-protected}}). For +instance, packets that are protected with 1-RTT keys MUST be +acknowledged in packets that are also protected with 1-RTT keys. Packets that a client sends with 0-RTT packet protection MUST be acknowledged by the server in packets protected by 1-RTT keys. This can mean that the client is @@ -3214,7 +3214,7 @@ The CRYPTO_CLOSE frame (type=0x20) is used to indicate connection failures caused by the crypto handshake. It uses the same format as the CONNECTION_CLOSE frame ({{frame-connection-close}}), except that the error codes are specific to the crypto protocol in use. For TLS 1.3, -the error code is simply the TLS alert number. +the error code is simply the one-byte TLS alert number. Other than the error code space, the format and semantics of the CRYPTO_CLOSE frame are identical to the CONNECTION_CLOSE frame. From 396c318dabd73952ee44b4bf1826aa28ebd19d8b Mon Sep 17 00:00:00 2001 From: EKR Date: Fri, 15 Jun 2018 08:39:04 -0700 Subject: [PATCH 17/31] Some more cleanup --- draft-ietf-quic-transport.md | 85 +++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 15abc559c4..ad7947a7aa 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -579,6 +579,26 @@ Token: : An optional token blob previously received in either a Retry packet or NEW_TOKEN frame. +The client and server use the Initial packet type for any packet that contains +an initial cryptographic handshake message. This includes all cases where a new +packet containing the initial cryptographic message needs to be created, this +includes the packets sent after receiving a Version Negotiation +({{packet-version}}) or Retry packet ({{packet-retry}}). + +A server sends its first Initial packet in response to a client Initial. A +server may send multiple Initial packets. The cryptographic key exchange could +require multiple round trips or retransmissions of this data. + +The payload of an Initial packet conveys a CRYPTO_HS frame (or frames) +containing a cryptographic handshake message. The first CRYPTO_HS frame +send always begins at an offset of 0 (see {{handshake}}). The client's complete +first message MUST fit in a single packet (see {{handshake}}). Note that if +the server sends a HelloRetryRequest, the client will send a second Initial +packet with a CRYPTO_HS frame starting immediately after the first one. + + +#### Connection IDs + When an an Initial packet is sent by a client which has not previously received a Retry packet from the server, it populates the Destination Connection ID field with a randomly selected value. This MUST be at least 8 octets in length. Until @@ -590,22 +610,23 @@ determine packet protection keys. The client populates the Source Connection ID field with a value of its choosing and sets the SCIL field to match. -If the client has a suitable token available from a previous connection, -it SHOULD populate the Token field. - -A server sends its first Initial packet in response to a client Initial. A -server may send multiple Initial packets. The cryptographic key exchange could -require multiple round trips or retransmissions of this data. - The Destination Connection ID field in the server's Initial packet contains a connection ID that is chosen by the recipient of the packet (i.e., the client); the Source Connection ID includes the connection ID that the sender of the packet wishes to use (see -{{connection-id}}). +{{connection-id}}). The server MUST use consistent Source Connection +IDs during the handshake. + +On first receiving an Initial or Retry packet from the server, the +client uses the Source Connection ID supplied by the server as the +Destination Connection ID for subsequent packets. The client MUST +discard any subsequent packets it receives with different +Source Connection IDs. -On first receiving the server Initial packet the client uses the Source -Connection ID supplied by the server as the Destination Connection ID for -subsequent packets. +#### Tokens + +If the client has a suitable token available from a previous connection, +it SHOULD populate the Token field. If the client received a Retry packet from the server and sends an Initial packet in response, then it sets the Destination Connection ID to @@ -614,38 +635,38 @@ Destination Connection ID also results in a change to the keys used to protect the Initial packet. It also sets the Token field to the token provided in the Retry. +When a server receives an Initial packet with an address validation +token, it SHOULD attempt to validate it. If the token is invalid then +the server SHOULD proceed as if the client did not have a validated +address, including potentially sending a Retry. If the validation +succeeds, the server SHOULD then allow the handshake to proceed (see +{{stateless-retry}}). + +Note: The rationale for treating the client as unvalidated rather +than discarding the packet is that the client might have received +the token in a previous connection using the NEW_TOKEN message, +and if the server has lost state, it might be unable to validate +the token at all, leading to connection failure if the packet +is discarded. + +#### Packet Numbers + The first Initial packet contains a packet number of 0. Each packet sent after the Initial packet is associated with a packet number space and its packet number increases monotonically in that space (see {{packet-numbers}}). -The payload of an Initial packet conveys a CRYPTO_HS frame (or frames) -containing a cryptographic handshake message. The first CRYPTO_HS frame -send always begins at an offset of 0 (see {{handshake}}). The client's complete -first message MUST fit in a single packet (see {{handshake}}). Note that if -the server sends a HelloRetryRequest, the client will send a second Initial -packet with a CRYPTO_HS frame starting immediately after the first one. +#### Minimum Packet Size The payload of a UDP datagram carrying the Initial packet MUST be expanded to at least 1200 octets (see {{packetization}}), by adding PADDING frames to the Initial packet and/or by combining the Initial packet with a 0-RTT packet (see {{packet-coalesce}}). -The client and server use the Initial packet type for any packet that contains -an initial cryptographic handshake message. This includes all cases where a new -packet containing the initial cryptographic message needs to be created, this -includes the packets sent after receiving a Version Negotiation -({{packet-version}}) or Retry packet ({{packet-retry}}). - -When a server receives an Initial packet with an address validation token, it -should attempt to validate it. If the token is invalid then it should be -ignored. If the validation succeeds, the server should then allow the -handshake to proceed (see {{stateless-retry}}). - ### Retry Packet {#packet-retry} -A Retry packet uses long headers with a type value of 0x7E. It carries an -address validation token created by the server. It is used by a server that +A Retry packet uses long headers with a type value of 0x7E. It carries an +address validation token created by the server. It is used by a server that wishes to perform a stateless retry (see {{stateless-retry}}). ~~~ @@ -661,6 +682,10 @@ wishes to perform a stateless retry (see {{stateless-retry}}). A Retry packet is not encrypted at all. Instead, the payload of a Retry packet contains two values in the clear. +DCIL: + +: The length of the Original Destination Connection ID. + Original Destination Connection ID: : The Destination Connection ID from the Initial packet that this From 777114ac355c7a4b15dabd67122ca21c164e2e17 Mon Sep 17 00:00:00 2001 From: EKR Date: Fri, 15 Jun 2018 08:47:11 -0700 Subject: [PATCH 18/31] Fix compile errors --- draft-ietf-quic-tls.md | 6 ++---- draft-ietf-quic-transport.md | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 0cd1651d98..8730377af7 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -1101,10 +1101,8 @@ values in the following registries: * TLS ExtensionsType Registry {{!TLS-REGISTRIES=I-D.ietf-tls-iana-registry-updates}} - IANA is to register - the quic_transport_parameters extension found in {{quic_parameters}} as well - as the max_crypto_data extension found in {{max_crypto_data}} - Assigning 26 and 27 to the extensions respectively would be greatly - appreciated. The Recommended column is to be marked Yes. The TLS 1.3 Column + the quic_transport_parameters extension found in {{quic_parameters}}. + The Recommended column is to be marked Yes. The TLS 1.3 Column is to include CH and EE. diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index ad7947a7aa..e6c53490e5 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -649,7 +649,7 @@ and if the server has lost state, it might be unable to validate the token at all, leading to connection failure if the packet is discarded. -#### Packet Numbers +#### Starting Packet Numbers The first Initial packet contains a packet number of 0. Each packet sent after the Initial packet is associated with a packet number space and its packet From a4ad49b42d9c6e7f86b1127cc4291f70d5fbe835 Mon Sep 17 00:00:00 2001 From: ianswett Date: Mon, 18 Jun 2018 16:24:50 -0400 Subject: [PATCH 19/31] Restore Generating Acknowledgements --- draft-ietf-quic-recovery.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index d536c72640..a4ec23cf24 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -437,6 +437,30 @@ containing CRYPTO_HS frames should use a very short ack delay, such as 1ms. ACK frames may be sent immediately when the crypto stack indicates all data for that encryption level has been received. +## Generating Acknowledgements + +QUIC SHOULD delay sending acknowledgements in response to packets, +but MUST NOT excessively delay acknowledgements of packets containing +non-ack frames. Specifically, implementaions MUST attempt to +enforce a maximum ack delay to avoid causing the peer spurious +timeouts. The default maximum ack delay in QUIC is 25ms. + +An acknowledgement MAY be sent for every second full-sized packet, +as TCP does {{?RFC5681}}, or may be sent less frequently, as long as +the delay does not exceed the maximum ack delay. QUIC recovery algorithms +do not assume the peer generates an acknowledgement immediately when +receiving a second full-sized packet. + +Out-of-order packets SHOULD be acknowledged more quickly, in order +to accelerate loss recovery. The receiver SHOULD send an immediate ACK +when it receives a new packet which is not one greater than the +largest received packet number. + +As an optimization, a receiver MAY process multiple packets before +sending any ACK frames in response. In this case they can determine +whether an immediate or delayed acknowledgement should be generated +after processing incoming packets. + ### ACK Ranges When an ACK frame is sent, one or more ranges of acknowledged packets are From 6b363007d1875ffb02cf6f0c9006696c72a2cd0b Mon Sep 17 00:00:00 2001 From: ianswett Date: Tue, 19 Jun 2018 08:55:01 -0400 Subject: [PATCH 20/31] Mike's comments --- draft-ietf-quic-recovery.md | 46 ++++++++++++++----------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index a4ec23cf24..69a06a3923 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -145,17 +145,15 @@ number for transmissions, and any data that is to be delivered to the receiving application(s) is sent in one or more streams, with delivery order determined by stream offsets encoded within STREAM frames. -QUIC's packet number is strictly increasing within a packet number -space, and directly encodes transmission order. A higher QUIC packet -number signifies that the packet was sent later, and a lower QUIC -packet number signifies that the packet was sent earlier. When a -packet containing frames is deemed lost, QUIC rebundles the -retransmittable data in a new packet with a new packet number, -removing ambiguity about which packet is acknowledged when an ACK is -received. Consequently, more accurate RTT measurements can be made, -spurious retransmissions are trivially detected, and mechanisms such -as Fast Retransmit can be applied universally, based only on packet -number. +QUIC's packet number is strictly increasing, and directly encodes transmission +order. A higher QUIC packet number signifies that the packet was sent later, +and a lower QUIC packet number signifies that the packet was sent earlier. When +a packet containing frames is deemed lost, QUIC rebundles necessary frames in a +new packet with a new packet number, removing ambiguity about which packet is +acknowledged when an ACK is received. Consequently, more accurate RTT +measurements can be made, spurious retransmissions are trivially detected, and +mechanisms such as Fast Retransmit can be applied universally, based only on +packet number. This design point significantly simplifies loss detection mechanisms for QUIC. Most TCP mechanisms implicitly attempt to infer transmission ordering based on @@ -419,24 +417,6 @@ A packet sent on an RTO alarm MUST NOT be blocked by the sender's congestion controller. A sender MUST however count these bytes as additional bytes in flight, since this packet adds network load without establishing packet loss. -## Multiple Packet Number Space Optimizations {#optimizations} - -There are cases where one may be able to gain recovery information from -acknowledgements of packets in another packet number space, but they rely -on complex assumptions about the peer’s processing and acknowledgement -algorithms. Even those are unable to quickly recover from cases such as -losing the client's Initial, but receiving the 0-RTT packets. Below is -an optimization using coalesced packets and implicit acknowledgements. - - -### Crypto Handshake Data - -In order to quickly complete the handshake and avoid spurious -retransmissions due to handshake alarm timeouts, acknowledging packets -containing CRYPTO_HS frames should use a very short ack delay, such as 1ms. -ACK frames may be sent immediately when the crypto stack indicates all -data for that encryption level has been received. - ## Generating Acknowledgements QUIC SHOULD delay sending acknowledgements in response to packets, @@ -461,6 +441,14 @@ sending any ACK frames in response. In this case they can determine whether an immediate or delayed acknowledgement should be generated after processing incoming packets. +### Crypto Handshake Data + +In order to quickly complete the handshake and avoid spurious +retransmissions due to handshake alarm timeouts, handshake packets +should use a very short ack delay, such as 1ms. ACK frames may be +sent immediately when the crypto stack indicates all data for that +encryption level has been received. + ### ACK Ranges When an ACK frame is sent, one or more ranges of acknowledged packets are From 4065266b5a01d982ec01050305247d342e8cdff7 Mon Sep 17 00:00:00 2001 From: ianswett Date: Tue, 19 Jun 2018 09:02:15 -0400 Subject: [PATCH 21/31] Fix retry and remove optimizations --- draft-ietf-quic-recovery.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index 69a06a3923..d559a9b3bd 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -132,8 +132,6 @@ Separating the spaces allows the recovery mechanisms to work without special cases to avoid spuriously retransmitting un-processable packets. Separate packet number spaces do not imply separate paths. Consequently, a sender need not split congestion control actions across packet number spaces. -The optimizations described in {{optimizations}} help a sender optimize -loss detection across packet number spaces. ### Monotonically Increasing Packet Numbers @@ -310,10 +308,10 @@ computed and the alarm SHOULD be set for twice the newly computed smoothed RTT. #### Retry -A RETRY packet causes the content of the client's Initial packet to be -immediately retransmitted along with the token present in the RETRY. +A Retry packet causes the content of the client's Initial packet to be +immediately retransmitted along with the token present in the Retry. -The RETRY indicates that the Initial was received but not processed. +The Retry indicates that the Initial was received but not processed. It MUST NOT be treated as an acknowledgment for the Initial, but it MAY be used for an RTT measurement. @@ -1108,11 +1106,12 @@ This document has no IANA actions. Yet. ## Since draft-ietf-quic-recovery-12 -- Updated to match the design team proposal. +- Updated to match the Stream0 design team proposal. +- Text on multiple packet number spaces. ## Since draft-ietf-quic-recovery-11 -- Text on multiple packet number spaces and relevant optimizations. +No significant changes. ## Since draft-ietf-quic-recovery-10 From d814642dec0176287f81ac2b0391aa7d541850c8 Mon Sep 17 00:00:00 2001 From: ianswett Date: Wed, 20 Jun 2018 17:54:45 -0400 Subject: [PATCH 22/31] Martin's comments --- draft-ietf-quic-recovery.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index d559a9b3bd..18e76e4390 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -126,12 +126,12 @@ these protocol differences below. ### Separate Packet Number Spaces -QUIC uses separate packet number spaces for each encryption level, except that +QUIC uses separate packet number spaces for each encryption level, except 0-RTT and all generations of 1-RTT keys use the same packet number space. -Separating the spaces allows the recovery mechanisms to work without special -cases to avoid spuriously retransmitting un-processable packets. -Separate packet number spaces do not imply separate paths. Consequently, -a sender need not split congestion control actions across packet number spaces. +Separate packet number spaces ensures that acknowledgement of packets sent +with one level of encryption doesn't cause spurious retransmission of packets +sent with a different encryption level. Congestion control and RTT measurement +are unified across packet number spaces. ### Monotonically Increasing Packet Numbers @@ -294,14 +294,16 @@ connection's final smoothed RTT value as the resumed connection's initial RTT. If no previous RTT is available, or if the network changes, the initial RTT SHOULD be set to 100ms. -When CRYPTO_HS frames are sent, the sender SHOULD set an alarm for the handshake -timeout period. +When CRYPTO_HS frames are sent, the sender SHOULD set an alarm for the +handshake timeout period. When the alarm fires, the sender MUST retransmit +all unacknowledged CRYPTO_HS data by calling +RetransmitAllUnackedHandshakeData(). On each consecutive firing of the +handshake alarm without receiving an acknowledgement for a new packet, +the sender SHOULD double the handshake timeout and set an alarm for this +period. -When the alarm fires, the sender MUST retransmit all unacknowledged CRYPTO_HS -data by calling RetransmitAllUnackedHandshakeData(). On each -consecutive firing of the handshake alarm without receiving an -acknowledgement for a new packet, the sender SHOULD double the handshake -timeout and set an alarm for this period. +When CRYPTO_HS frames are outstanding, the TLP and RTO timers are not active +unless the CRYPTO_HS frames were sent at 1RTT encryption. When an acknowledgement is received for a handshake packet, the new RTT is computed and the alarm SHOULD be set for twice the newly computed smoothed RTT. @@ -443,7 +445,7 @@ after processing incoming packets. In order to quickly complete the handshake and avoid spurious retransmissions due to handshake alarm timeouts, handshake packets -should use a very short ack delay, such as 1ms. ACK frames may be +SHOULD use a very short ack delay, such as 1ms. ACK frames MAY be sent immediately when the crypto stack indicates all data for that encryption level has been received. @@ -584,7 +586,7 @@ sent_packets: was sent, a boolean indicating whether the packet is ack only, and a bytes field indicating the packet's size. sent_packets is ordered by packet number, and packets remain in sent_packets until acknowledged or lost. - A sent_packets data structure is maintained per packet number space, and ack + A sent_packets data structure is maintained per packet number space, and ACK processing only applies to a single space. ### Initialization From da0d8ecff5905d4321db902c2df6a51846791fec Mon Sep 17 00:00:00 2001 From: ianswett Date: Wed, 20 Jun 2018 21:22:53 -0400 Subject: [PATCH 23/31] Ensures that --- draft-ietf-quic-recovery.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/draft-ietf-quic-recovery.md b/draft-ietf-quic-recovery.md index 18e76e4390..0d7bd267bc 100644 --- a/draft-ietf-quic-recovery.md +++ b/draft-ietf-quic-recovery.md @@ -128,8 +128,8 @@ these protocol differences below. QUIC uses separate packet number spaces for each encryption level, except 0-RTT and all generations of 1-RTT keys use the same packet number space. -Separate packet number spaces ensures that acknowledgement of packets sent -with one level of encryption doesn't cause spurious retransmission of packets +Separate packet number spaces ensures acknowledgement of packets sent +with one level of encryption will not cause spurious retransmission of packets sent with a different encryption level. Congestion control and RTT measurement are unified across packet number spaces. From daea8615f43545e42fda486d92b5ac6c4218e760 Mon Sep 17 00:00:00 2001 From: EKR Date: Thu, 21 Jun 2018 13:59:56 -0700 Subject: [PATCH 24/31] Address MT's comments on TLS --- draft-ietf-quic-tls.md | 131 +++++++++++++++++++---------------- draft-ietf-quic-transport.md | 8 ++- 2 files changed, 76 insertions(+), 63 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 8730377af7..c72ec08378 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -321,35 +321,39 @@ same encryption level. For instance, an implementation might bundle a Handshake message and an ACK for some Handshake data into the same packet. -In general, the rules for which data can appear in packets of which -encryption level are the same in QUIC as in TLS over TCP: +Each encryption level has a specific list of frames which may appear +in it. The rules here generalize those of TLS, in that frames +associated with establishing the connection can usually appear at any +encryption level, whereas those associated with transferring data can +only appear in the 0-RTT and 1-RTT encryption levels - CRYPTO_HS frames MAY appear in packets of any encryption level. - CONNECTION_CLOSE and CRYPTO_CLOSE MAY appear in packets of any encryption level other than 0-RTT. - PADDING and PING frames MAY appear in packets of any encryption level. - ACK frames MAY appear in packets of any encryption level, but - MUST only acknowledge packets which appeared in that encryption + can only acknowledge packets which appeared in that encryption level. - STREAM frames MUST ONLY appear in the 0-RTT and 1-RTT levels. - All other frame types MUST only appear at the 1-RTT levels. -Because packets may be reordered on the wire, QUIC uses the packet +Because packets could be reordered on the wire, QUIC uses the packet type to indicate which level a given packet was encrypted under, as shown in {{packet-types-levels}}. When multiple packets of different encryption levels need to be sent, endpoints SHOULD use coalesced packets to send them in the same UDP datagram. -| Packet Type | Encryption Level | -|:----------------|:-----------------| -| Initial | Initial secrets | -| 0-RTT Protected | 0-RTT | -| Handshake | Handshake | -| Retry | N/A | -| Short Header | 1-RTT | +| Packet Type | Encryption Level | PN Space | +|:----------------|:-----------------|:----------| +| Initial | Initial secrets | Initial | +| 0-RTT Protected | 0-RTT | 0/1-RTT | +| Handshake | Handshake | Handshake | +| Retry | N/A | N/A | +| Short Header | 1-RTT | 0/1-RTT | + {: #packet-types-levels title="Encryption Levels by Packet Type"} -{{QUIC-TRANSPORT}}; Section 6.3 shows how packets at the various encryption +{{QUIC-TRANSPORT}}, Section 6.3 shows how packets at the various encryption levels fit into the handshake process. ## Interface to TLS @@ -358,7 +362,7 @@ As shown in {{schematic}}, the interface from QUIC to TLS consists of three primary functions: - Sending and receiving handshake messages -- Rekeying (both in and out) +- Rekeying (both transmit and receive) - Handshake state updates Additional functions might be needed to configure TLS. @@ -366,10 +370,10 @@ Additional functions might be needed to configure TLS. ### Sending and Receiving Handshake Messages -In order to drive the handshake, TLS depends on being able to send and receive -handshake messages. There are two basic functions on this -interface: one where QUIC requests handshake messages and one where QUIC -provides handshake packets. +In order to drive the handshake, TLS depends on being able to send and +receive handshake messages. There are two basic functions on this +interface: one where QUIC requests handshake messages and one where +QUIC provides handshake packets. Before starting the handshake QUIC provides TLS with the transport parameters (see {{quic_parameters}}) that it wishes to carry. @@ -393,7 +397,7 @@ the network, it proceeds as follows: the data into the input flow as usual. As with STREAM frames, the offset is used to find the proper location in the data sequence. If the result of this process is that new data is available, then - it is delivered to TLS. + it is delivered to TLS in order. - If the packet is from a previously installed encryption level, it MUST not contain data which extends past the end of previously @@ -567,11 +571,8 @@ as a connection error of type PROTOCOL_VIOLATION. ## Rejecting 0-RTT -A server rejects 0-RTT by rejecting 0-RTT at the TLS layer. This results in -early exporter keys being unavailable, thereby preventing the use of 0-RTT for -QUIC. - -A client that attempts 0-RTT MUST also consider 0-RTT to be rejected if it +A server rejects 0-RTT by rejecting 0-RTT at the TLS layer. This also prevents +QUIC from sending 0-RTT data. A client that attempts 0-RTT MUST also consider 0-RTT to be rejected if it receives a Version Negotiation packet. When 0-RTT is rejected, all connection characteristics that the client assumed @@ -583,11 +584,12 @@ the state of all streams, including application state bound to those streams. In TLS over TCP, the HelloRetryRequest feature ({{TLS13}; Section 4.1.4) can be used to correct a client's incorrect KeyShare extension -as well as for a stateless round trip check. From the perspective of +as well as for a stateless round-trip check. From the perspective of QUIC, this just looks like additional messages carried in the Initial encryption level. Although it is in principle possible to use this feature for address verification in QUIC, QUIC implementations SHOULD instead use the Retry feature ({{QUIC-TRANSPORT}}; Section 4.4.2)). +HelloRetryRequest is still used for incorrect key shares. ## TLS Errors @@ -595,7 +597,7 @@ instead use the Retry feature ({{QUIC-TRANSPORT}}; Section 4.4.2)). If TLS experiences an error, it MUST generate an appropriate alert as defined in {{TLS13}}; Section 6) and then provide it to QUIC, which sends the alert in a CRYPTO_CLOSE frame. All such alerts are -"fatal". +"fatal" (see {{TLS13}}, Section 6.2. # QUIC Packet Protection {#packet-protection} @@ -609,16 +611,16 @@ handshake, using the AEAD algorithm negotiated by TLS. QUIC derives packet encryption keys in the same way as TLS 1.3: Each encryption level/direction pair has a secret value, which is then used to derive the traffic keys using as described -in {{TLS13}}; Section 7.3. +in {{TLS13}}, Section 7.3. The keys for the Initial encryption level are computed based on -the client's first Destination Connection Id, as described in -{{initial-secrets}}. +the client's initial Destination Connection ID, as described in +{{initial-secrets}}. The keys for the remaining encryption level are computed in the same fashion as the corresponding TLS keys (see {{TLS13}}; Section 7), except that the label for HKDF-Expand-Label uses the prefix "quic " -rather than "tls 13". The purpose of this change is to provide key +rather than "tls13". The purpose of this change is to provide key separation between TLS and QUIC, so that TLS stacks can avoid exposing TLS record protection keys. @@ -626,7 +628,7 @@ exposing TLS record protection keys. Initial packets are protected with a secret derived from the Destination Connection ID field from the client's -Initial packet. Specifically: +first Initial packet of the connection. Specifically: ~~~ initial_salt = 0x9c108f98520a5c5c32968e950e8a2c5fe06d6c38 @@ -639,9 +641,13 @@ server_initial_secret = HKDF-Expand-Label(initial_secret, "server in", Hash.length) ~~~ +Note that if the server sends a Retry, the client's Initial will +correspond to a new connection and thus use the server provided +Destination Connection ID. + The hash function for HKDF when deriving handshake secrets and keys is SHA-256 {{!SHA=DOI.10.6028/NIST.FIPS.180-4}}. The connection ID used with -HKDF-Expand-Label is the connection ID chosen by the client. +HKDF-Expand-Label is the initial Destination Connection ID. initial_salt is a 20 octet sequence shown in the figure in hexadecimal notation. Future versions of QUIC SHOULD generate a new salt value, thus @@ -653,7 +659,7 @@ Note: : The Destination Connection ID is of arbitrary length, and it could be zero length if the server sends a Retry packet with a zero-length Source Connection - ID field. In this case, the initial keys provide no assurance to the client + ID field. In this case, the Initial keys provide no assurance to the client that the server received its packet; the client has to rely on the exchange that included the Retry packet for that property. @@ -670,21 +676,23 @@ QUIC packets are protected prior to applying packet number encryption (A). When removing packet protection, an endpoint first removes the protection from the packet number. -All QUIC packets other than Version Negotiation and Stateless Reset packets are -protected with an AEAD algorithm {{!AEAD}}. Prior to establishing a shared -secret, packets are protected with AEAD_AES_128_GCM and a key derived from the -client's connection ID (see {{initial-secrets}}). This provides protection -against off-path attackers and robustness against QUIC version unaware -middleboxes, but not against on-path attackers. +All QUIC packets other than Version Negotiation and Stateless Reset +packets are protected with an AEAD algorithm {{!AEAD}}. Prior to +establishing a shared secret, packets are protected with +AEAD_AES_128_GCM and a key derived from the from the destination +connection ID in the client's first Initial packet (see +{{initial-secrets}}). This provides protection against off-path +attackers and robustness against QUIC version unaware middleboxes, but +not against on-path attackers. All ciphersuites currently defined for TLS 1.3 - and therefore QUIC - have a 16-byte authentication tag and produce an output 16 bytes larger than their input. -The key and iv for the packet are computed as described in {{encryption-keys}}. +The key and IV for the packet are computed as described in {{encryption-keys}}. The nonce, N, is formed by combining the packet protection IV with the packet number. The 64 bits of the reconstructed QUIC packet number in -network byte order is left-padded with zeros to the size of the IV. +network byte order are left-padded with zeros to the size of the IV. The exclusive OR of the padded packet number and the IV forms the AEAD nonce. @@ -818,15 +826,19 @@ the protocol. A client MUST only use 0-RTT keys to protect data that is idempotent. A client MAY wish to apply additional restrictions on what data it sends prior to the completion of the TLS handshake. A client otherwise treats 0-RTT keys as -equivalent to 1-RTT keys, except that ACKs for that data MUST only be sent with -1-RTT keys. +equivalent to 1-RTT keys, except that it MUST NOT send ACKs with 0-RTT keys. A client that receives an indication that its 0-RTT data has been accepted by a server can send 0-RTT data until it receives all of the server's handshake messages. A client SHOULD stop sending 0-RTT data if it receives an indication that 0-RTT data has been rejected. -A server MUST NOT use 0-RTT keys to protect packets. +A server MUST NOT use 0-RTT keys to protect packets; it uses 1-RTT +keys to protect acknowledgements of 0-RTT packets. Clients MUST NOT +attempt to decrypt 0-RTT packets it receives and instead MUST discard +them. + +Note: : 0-RTT data can be acknowledged by the server as it receives it, but any packets containing acknowledgments of 0-RTT data cannot have packet protection @@ -853,19 +865,15 @@ A server could receive packets protected with 0-RTT keys prior to receiving a TLS ClientHello. The server MAY retain these packets for later decryption in anticipation of receiving a ClientHello. -Receiving and verifying the TLS Finished message is critical in -ensuring the integrity of the TLS handshake. A server MUST NOT use -1-RTT protected packets from the client prior to verifying the client -Finished message if its response depends on client authentication. # Key Update Once the 1-RTT keys are established and the short header is in use, it -is possible to update the keys, for instance because of limits on AEAD -encryption. The KEY_PHASE bit in the short header is used to indicate -whether key updates have occurred. The KEY_PHASE bit is initially set -to 0 and then inverted with each key update {{key-update}}. +is possible to update the keys. The KEY_PHASE bit in the short header +is used to indicate whether key updates have occurred. The KEY_PHASE +bit is initially set to 0 and then inverted with each key update +{{key-update}}. The KEY_PHASE bit allows a recipient to detect a change in keying material without necessarily needing to receive the first packet that @@ -939,8 +947,8 @@ is contained in Initial packets that is not otherwise authenticated. It is also possible for the attacker to tamper with data that is carried in Handshake packets, but because that tampering -requires modifying TLS handshake messages, that tampering will be -detected as soon as the TLS handshake completes. +requires modifying TLS handshake messages, that tampering will +cause the TLS handshake to fail. # QUIC-Specific Additions to the TLS Handshake @@ -997,10 +1005,11 @@ The quic_transport_parameters extension is carried in the ClientHello and the EncryptedExtensions messages during the handshake. While the transport parameters are technically available prior to the -completion of the handshake, they cannot be fully trusted until the handshake -completes, and reliance on them should be minimized. -However, any tampering with the parameters will be detected -when the handshake completes. +completion of the handshake, they cannot be fully trusted until the +handshake completes, and reliance on them should be minimized. +However, any tampering with the parameters will cause the handshake to +fail. + # Security Considerations @@ -1018,11 +1027,11 @@ server can be used in packet reflection attacks to amplify the traffic generated by an attacker. QUIC includes three defenses against this attack. First, the packet -containing a ClientHello be padded to a minimum size. Second, if +containing a ClientHello MUST be padded to a minimum size. Second, if responding to an unverified source address, the server is forbidden to -send more than three packets in its first flight ({{QUIC-TRANSPORT}}; -Section 4.4.3). Finally, because ACKs of Handshake packets -are authenticated, a blind attacker cannot forge them +send more than three UDP datagrams in its first flight ({{QUIC-TRANSPORT}}; +Section 4.4.3). Finally, because acknowledgements of Handshake packets +are authenticated, a blind attacker cannot forge them. Put together, these defenses limit the level of amplification. diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index e6c53490e5..53a34f9e9e 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -360,7 +360,7 @@ The following packet types are defined: | Type | Name | Section | |:-----|:------------------------------|:----------------------------| | 0x7F | Initial | {{packet-initial}} | -| 0x7E | Retry | {{packet-retry}} | +| 0x7E | Retry | {{packet-retry}} | | 0x7D | Handshake | {{packet-handshake}} | | 0x7C | 0-RTT Protected | {{packet-protected}} | {: #long-packet-types title="Long Header Packet Types"} @@ -800,7 +800,10 @@ sequence of frames, as described in {{frames}}. A sender can coalesce multiple QUIC packets (typically a Cryptographic Handshake packet and a Protected packet) into one UDP datagram. This can reduce the number of UDP datagrams needed to send application data during the handshake and -immediately afterwards. +immediately afterwards. It is not necessary for senders to coalesce +packets -- though failing to do so will require sending a significantly +larger number of packets during the handshake -- but receivers MUST +be able to process coalesced packets. Senders SHOULD coalesce packets in order of increasing encryption levels (Initial, Handshake, 0-RTT, 1-RTT), as this makes it more likely the receiver @@ -813,6 +816,7 @@ IDs into a single UDP datagram. Receivers SHOULD ignore any subsequent packets with a different Destination Connection ID than the first packet in the datagram. + Every QUIC packet that is coalesced into a single UDP datagram is separate and complete. Though the values of some fields in the packet header might be redundant, no fields are omitted. The receiver of coalesced QUIC packets MUST From 3aea50db51a14f2b42ed8aea7dbeeea72c6321b4 Mon Sep 17 00:00:00 2001 From: EKR Date: Thu, 21 Jun 2018 19:04:30 -0700 Subject: [PATCH 25/31] MT/Bishop comments on transport --- draft-ietf-quic-transport.md | 209 +++++++++++++++++++---------------- 1 file changed, 113 insertions(+), 96 deletions(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 53a34f9e9e..4d87b8cd6e 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -542,7 +542,7 @@ All these packets use the long header and contain the current QUIC version in the version field. In order to prevent tampering by version-unaware middleboxes, Initial -packets are protected with a connection- and version-specific keys +packets are protected with connection- and version-specific keys (Initial keys) as described in {{QUIC-TLS}}. This protection does not provide confidentiality or integrity against on-path attackers, but provides some level of protection against off-path attackers. @@ -550,10 +550,11 @@ provides some level of protection against off-path attackers. ### Initial Packet {#packet-initial} -The Initial packet uses long headers with a type value of 0x7F. It carries the -first CRYPTO_HS frames sent by the client as well as the -cryptographic messages sent by the server to perform key exchange. The Initial -packet is protected by Initial keys as described in {{QUIC-TLS}}. +The Initial packet uses long headers with a type value of 0x7F. It +carries the first CRYPTO_HS frames sent by the client as well as the +cryptographic messages sent by the server to perform key exchange, and +may carry ACKs in either direction. The Initial packet is protected by +Initial keys as described in {{QUIC-TLS}}. The Initial packet has two additional header fields that follow the normal Long Header. @@ -562,7 +563,7 @@ 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Token Length (i) ... +| Token Length (i) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Token (*) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -571,41 +572,43 @@ Header. Token Length: : A variable-length integer specifying the length of the Token field, in bytes. -It may be zero if no token is present. The server MUST send a zero-length -token. +It may be zero if no token is present. Initial packets sent by the server +MUST in include a zero-length token. Token: : An optional token blob previously received in either a Retry packet or NEW_TOKEN frame. -The client and server use the Initial packet type for any packet that contains -an initial cryptographic handshake message. This includes all cases where a new -packet containing the initial cryptographic message needs to be created, this -includes the packets sent after receiving a Version Negotiation +The client and server use the Initial packet type for any packet that +contains an initial cryptographic handshake message. In addition to +the first packet(s), This includes all cases where a new packet +containing the initial cryptographic message needs to be created, such +as the packets sent after receiving a Version Negotiation ({{packet-version}}) or Retry packet ({{packet-retry}}). A server sends its first Initial packet in response to a client Initial. A server may send multiple Initial packets. The cryptographic key exchange could require multiple round trips or retransmissions of this data. -The payload of an Initial packet conveys a CRYPTO_HS frame (or frames) -containing a cryptographic handshake message. The first CRYPTO_HS frame -send always begins at an offset of 0 (see {{handshake}}). The client's complete -first message MUST fit in a single packet (see {{handshake}}). Note that if -the server sends a HelloRetryRequest, the client will send a second Initial -packet with a CRYPTO_HS frame starting immediately after the first one. - +The payload of an Initial packet includes a CRYPTO_HS frame (or +frames), containing a cryptographic handshake message, ACK frames, or +both. The first CRYPTO_HS frame sent always begins at an offset of 0 +(see {{handshake}}). The client's complete first message MUST fit in a +single packet (see {{handshake}}). Note that if the server sends a +HelloRetryRequest, the client will send a second Initial packet with a +CRYPTO_HS frame with an offset starting at the end of the CRYPTO_HS +stream in the first Initial. #### Connection IDs -When an an Initial packet is sent by a client which has not previously received -a Retry packet from the server, it populates the Destination Connection ID field -with a randomly selected value. This MUST be at least 8 octets in length. Until -a packet is received from the server, the client MUST use the same random value -unless it also changes the Source Connection ID (which effectively starts a new -connection attempt). The randomized Destination Connection ID is used to -determine packet protection keys. +When an Initial packet is sent by a client which has not previously +received a Retry packet from the server, it populates the Destination +Connection ID field with an unpredictable value. This MUST be at +least 8 octets in length. Until a packet is received from the server, +the client MUST use the same value unless it abandons the connection +attempt and starts a new one. The initial Destination Connection ID is +used to determine packet protection keys. The client populates the Source Connection ID field with a value of its choosing and sets the SCIL field to match. @@ -619,9 +622,9 @@ IDs during the handshake. On first receiving an Initial or Retry packet from the server, the client uses the Source Connection ID supplied by the server as the -Destination Connection ID for subsequent packets. The client MUST -discard any subsequent packets it receives with different -Source Connection IDs. +Destination Connection ID for subsequent packets. Once a client has +received an Initial packet from the server, it MUST discard any packet +it receives with a different Source Connection ID. #### Tokens @@ -642,7 +645,9 @@ address, including potentially sending a Retry. If the validation succeeds, the server SHOULD then allow the handshake to proceed (see {{stateless-retry}}). -Note: The rationale for treating the client as unvalidated rather +Note: + +: The rationale for treating the client as unvalidated rather than discarding the packet is that the client might have received the token in a previous connection using the NEW_TOKEN message, and if the server has lost state, it might be unable to validate @@ -673,16 +678,16 @@ wishes to perform a stateless retry (see {{stateless-retry}}). 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| DCIL(8) | Original Destination Connection ID (*) | +| ODCIL(8 | Original Destination Connection ID (*) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Retry Token (*) +| Retry Token (*) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~~~ A Retry packet is not encrypted at all. Instead, the payload of a Retry packet contains two values in the clear. -DCIL: +ODCIL: : The length of the Original Destination Connection ID. @@ -715,9 +720,9 @@ A Retry packet is never explicitly acknowledged in an ACK frame by a client. A server MUST only send a Retry in response to a client Initial packet. If the Original Destination Connection ID field does not match the -Destination Connection ID from the Initial packet it sent, clients MUST -discard the packet. This prevents an off-path attacker from injecting -a Retry packet with a bogus new Source Connection ID. +Destination Connection ID from most recent the Initial packet it sent, +clients MUST discard the packet. This prevents an off-path attacker +from injecting a Retry packet with a bogus new Source Connection ID. Otherwise, the client SHOULD respond with a new Initial packet with the Token field set to the token received in the Retry packet. @@ -743,7 +748,7 @@ The first Handshake packet sent by a server contains a packet number of 0. Handshake packets are their own packet number space. Packet numbers are incremented normally for other Handshake packets. -Servers MUST NOT send more than three packets including Initial and Handshake +Servers MUST NOT send more than three datagrams including Initial and Handshake packets without receiving a packet from a verified source address. Source addresses can be verified through an address validation token (delivered via a Retry packet or a NEW_TOKEN frame) or by receiving @@ -777,10 +782,11 @@ Packets protected with 0-RTT keys use a type value of 0x7C. The connection ID fields for a 0-RTT packet MUST match the values used in the Initial packet ({{packet-initial}}). -The client can send 0-RTT packets after receiving an Initial or Handshake packet -({{packet-handshake}}), if that packet does not complete the handshake. Even if -the client receives a different connection ID in the Handshake packet, it MUST -continue to use the same Destination Connection ID for 0-RTT packets, see +The client can send 0-RTT packets after receiving an Initial +{{packet-initial}} or Handshake ({{packet-handshake}}) packet, if that +packet does not complete the handshake. Even if the client receives a +different connection ID in the Handshake packet, it MUST continue to +use the same Destination Connection ID for 0-RTT packets, see {{connection-id}}. The version field for protected packets is the current QUIC version. @@ -888,15 +894,16 @@ Packet numbers are divided into 3 spaces in QUIC: - Application data space: All 0-RTT and 1-RTT encrypted packets {{packet-protected}} are in this space. -As descibed in {{QUIC-TLS}}, each packet type uses different encryption keys. +As described in {{QUIC-TLS}}, each packet type uses different encryption keys. -Conceptually, a packet number space is the encryption context in which a packet -can be processed and ACKed. Initial packets can only be sent with -Initial encryption keys and ACKed in packets which are also Initial packets. -Similarly Handshake packets can only be sent and acked in Handshake packets. +Conceptually, a packet number space is the encryption context in which +a packet can be processed and ACKed. Initial packets can only be sent +with Initial encryption keys and ACKed in packets which are also +Initial packets. Similarly, Handshake packets can only be sent and +acknowledged in Handshake packets. This enforces cryptographic separation between the data sent in the -different packet sequence number spaces. As a result, each packet number space +different packet sequence number spaces. Each packet number space starts at packet number 0. Subsequent packets sent in the same packet number space MUST increase the packet number by at least one. @@ -1197,14 +1204,15 @@ solicit a list of supported versions from a server. QUIC relies on a combined cryptographic and transport handshake to minimize connection establishment latency. QUIC uses the CRYPTO_HS -frame {frame-crypto} to transmit the cryptographic handshake. Version +frame {{frame-crypto}} to transmit the cryptographic handshake. Version 0x00000001 of QUIC uses TLS 1.3 as described in {{QUIC-TLS}}; a different QUIC version number could indicate that a different cryptographic handshake protocol is in use. -QUIC provides the cryptographic handshake with reliable, ordered -delivery of data via the CRYPTO_HS frame. In return, the -cryptographic handshake provides QUIC with: +QUIC provides reliable, ordered delivery of the cryptographic +handshake data. QUIC packet protection ensures confidentiality and +integrity protection that meets the requirements of the cryptographic +handshake protocol: * authenticated key exchange, where @@ -1231,9 +1239,6 @@ cryptographic handshake provides QUIC with: client can receive packets that are addressed with the transport address that is claimed by the client (see {{address-validation}}) -The CRYPTO_HS frame provides an offset and a length. QUIC functions -as the record encryption layer for the cryptographic protocol. - The initial CRYPTO_HS frame MUST be sent in a single packet. Any second attempt that is triggered by address validation MUST also be sent within a single packet. This avoids having to reassemble a @@ -1250,7 +1255,7 @@ of handshake data starting from an offset of 0. ## Example Handshake Flows Details of how TLS is integrated with QUIC are provided in {{QUIC-TLS}}, -but we provide some examples here. +but some examples are provided here. {{tls-1rtt-handshake}} provides an overview of the 1-RTT handshake. Each line shows a QUIC packet with the packet type and packet @@ -1260,11 +1265,11 @@ contains a CRYPTO_HS frame carrying the ClientHello. Note that multiple QUIC packets -- even of different encryption levels -- may be coalesced into a single UDP datagram (see -{{packet-coalesce}}, and so this handshake may consist of anywhere -from 4 to 9 UDP datagrams. For instance, the server's first flight -contains packets from the Initial encryption level (obfuscation), the -Handshake level, and "0.5-RTT data" from the server at the 1-RTT -encryption level. +{{packet-coalesce}}, and so this handshake may consist of as few as 4 +UDP datagrams, or any number more. For instance, the server's first +flight contains packets from the Initial encryption level +(obfuscation), the Handshake level, and "0.5-RTT data" from the server +at the 1-RTT encryption level. ~~~~ Client Server @@ -1305,7 +1310,10 @@ Initial[0]: CRYPTO_HS[CH] Initial[1]: ACK[0] 0-RTT[1]: CRYPTO_HS[EOED] Handshake[0]: CRYPTO_HS[FIN], ACK[0] -1-RTT[2]: STREAM[0, "..."], ACK[0] -> +1-RTT[2]: STREAM[0, "..."] ACK[0] -> + + 1-RTT[1]: STREAM[55, "..."], ACK[1,2] + <- Handshake[1]: ACK[0] ~~~~ {: #tls-0rtt-handshake title="Example 1-RTT Handshake"} @@ -1626,8 +1634,8 @@ request - in response to the data carried in the early data from the client. To send additional data prior to completing the cryptographic handshake, the server then needs to validate that the client owns the address that it claims. -Source address validation is therefore performed during the establishment of a -connection, by the core transport protocol. +Source address validation is therefore performed by the core transport +protocol during the establishment of a connection. A different type of source address validation is performed after a connection migration, see {{migrate-validate}}. @@ -1641,18 +1649,19 @@ long as the token's authenticity can be checked (see {{token-integrity}}) and the client is able to return that token, it proves to the server that it received the token. -If QUIC decides to request address validation for the current -handshake, it encodes the token in a Retry packet. The contents of -this token are consumed by the server that generates the token, so -there is no need for a single well-defined format. A token could -include information about the claimed client address (IP and port), a -timestamp, and any other supplementary information the server will -need to validate the token in the future. +Upon receiving the client's Initial packet, the server can request +address validation by sending a Retry packet containing a token. This +token is repeated in the client's next Initial packet. Because the +token is consumed by the server that generates it, there is no need +for a single well-defined format. A token could include information +about the claimed client address (IP and port), a timestamp, and any +other supplementary information the server will need to validate the +token in the future. The Retry packet is sent to the client and a legitimate client will respond with an Initial packet containing the token from the Retry packet when it continues the handshake. In response to receiving the token, a -QUIC server can either abort the connection or permit it to proceed. +server can either abort the connection or permit it to proceed. A connection MAY be accepted without address validation - or with only limited validation - but a server SHOULD limit the data it sends toward an unvalidated @@ -1664,7 +1673,7 @@ response to Initial packets sent containing a token. There are several situations in which the server might not be able to use the previously generated token to validate the client's address and must send a new Retry. A reasonable limit to the number of tries the client allows -for, before giving up, is 3. That is, the client SHOULD echo the +for, before giving up, is 3. That is, the client MUST echo the address validation token from a new Retry packet up to 3 times. After that, it MAY give up on the connection attempt. @@ -1676,15 +1685,16 @@ connection that can be used on a subsequent connection. Address validation is especially important with 0-RTT because a server potentially sends a significant amount of data to a client in response to 0-RTT data. -The server uses the NEW_TOKEN frame {{frame-new-token}} to provide the client -with an address validation token that can be used to validate future 0-RTT -connections. The client may then use this token to validate future 0-RTT -connections by including it in the Initial packet's header. The client MUST -NOT use the token provided in a RETRY for future connections. +The server uses the NEW_TOKEN frame {{frame-new-token}} to provide the +client with an address validation token that can be used to validate +future connections. The client may then use this token to validate +future connections by including it in the Initial packet's header. +The client MUST NOT use the token provided in a Retry for future +connections. Unlike the token that is created for a Retry packet, there might be some time between when the token is created and when the token is subsequently used. -Thus, a resumption token SHOULD include an expiration time. The server may +Thus, a resumption token SHOULD include an expiration time. The server MAY include either an explicit expiration time or an issued timestamp and dynamically calculate the expiration time. It is also unlikely that the client port number is the same on two different connections; validating the port is @@ -2839,8 +2849,7 @@ TCP SACKs ({{?RFC2018}}). It is expected that a sender will reuse the same packet number across different packet number spaces. ACK frames only acknowledge the packet numbers that were transmitted by the sender in the same packet number space of the packet that the -ACK was received in. This is an important property to allow for separation -between the different packet number spaces. +ACK was received in. A client MUST NOT acknowledge Retry packets. Retry packets include the packet number from the Initial packet it responds to. Version Negotiation packets @@ -3005,8 +3014,9 @@ is only sending ACK frames will only receive acknowledgements for its packets if the sender includes them in packets with non-ACK frames. A sender SHOULD bundle ACK frames with other frames when possible. -Implementations must be aware of the packet number space of the packet being -transmitted and only acknowledge packets from that space. +Endpoints can only acknowledge packets sent in a particular packet +number space by sending ACK frames in packets from the same packet +number space. To limit receiver state or the size of ACK frames, a receiver MAY limit the number of ACK blocks it sends. A receiver can do this even without receiving @@ -3029,8 +3039,8 @@ unable to use these acknowledgments if the server cryptographic handshake messages are delayed or lost. Note that the same limitation applies to other data sent by the server protected by the 1-RTT keys. -Implementations SHOULD aggressively ACK packets containing CRYPTO_HS frames. -See {{QUIC-RECOVERY}}, Section 3.5.1. +Endpoints SHOULD send acknowledgments for packets containing CRYPTO_HS +frames with a reduced delay; see Section 3.5.1 of {{RECOVERY}}. ## PATH_CHALLENGE Frame {#frame-path-challenge} @@ -3076,8 +3086,8 @@ a connection error of type UNSOLICITED_PATH_RESPONSE. ## NEW_TOKEN frame {#frame-new-token} -An server sends a NEW_TOKEN frame (type=0x21) to provide the client a token to -send in a the header of an Initial packet for a future 0-RTT connection. +A server sends a NEW_TOKEN frame (type=0x21) to provide the client a token to +send in a the header of an Initial packet for a future connection. The NEW_TOKEN frame is as follows: @@ -3085,7 +3095,7 @@ The NEW_TOKEN frame is as follows: 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Token Length (i) ... +| Token Length (i) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Token (*) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -3191,9 +3201,13 @@ transmission efficiency to underfilled packets. ## CRYPTO_HS Frame {#frame-crypto} -The CRYPTO_HS frame (type=0x18) is used to transmit cryptographic handshake -messages. It can be sent in all packet types. The CRYPTO_HS frame offers the -cryptographic protocol an in-order stream of bytes. +The CRYPTO_HS frame (type=0x18) is used to transmit cryptographic +handshake messages. It can be sent in all packet types. The CRYPTO_HS +frame offers the cryptographic protocol an in-order stream of bytes. +CRYPTO_HS frames are functionally identical to STREAM frames, except +that they do not bear a stream identifier; they are not flow +controlled; and they do not carry markers for optional offset, +optional, length, and the end of the stream. A CRYPTO_HS frame is shown below. @@ -3243,7 +3257,9 @@ The CRYPTO_CLOSE frame (type=0x20) is used to indicate connection failures caused by the crypto handshake. It uses the same format as the CONNECTION_CLOSE frame ({{frame-connection-close}}), except that the error codes are specific to the crypto protocol in use. For TLS 1.3, -the error code is simply the one-byte TLS alert number. +the error code is simply the one-byte TLS alert number left-padded +with zeroes. + Other than the error code space, the format and semantics of the CRYPTO_CLOSE frame are identical to the CONNECTION_CLOSE frame. @@ -3297,9 +3313,10 @@ been lost. In general, information is sent again when a packet containing that information is determined to be lost and sending ceases when a packet containing that information is acknowledged. -* Data sent in CRYPTO_HS frames are retransmitted according to the rules in - {{QUIC-RECOVERY}}, until either all data has been ACKed or the crypto state - machine implictly knows that the peer received the data. +* Data sent in CRYPTO_HS frames are retransmitted according to the + rules in {{QUIC-RECOVERY}}, until either all data has been + acknowledged or the crypto state machine implictly knows that the + peer received the data. * Application data sent in STREAM frames is retransmitted in new STREAM frames unless the endpoint has sent a RST_STREAM for that stream. Once an endpoint @@ -4112,7 +4129,7 @@ Data sent in CRYPTO_HS frames is not flow controlled in the same way as STREAM frames. QUIC relies on the cryptographic protocol implementation to avoid excessive buffering of data, see {{QUIC-TLS}}. The implementation SHOULD provide an interface to QUIC to tell it about its buffering limits so that there -is no excessive buffering at multiple layers. +is not excessive buffering at multiple layers. # Error Handling @@ -4538,7 +4555,7 @@ Issue and pull request numbers are listed with a leading octothorp. ## Since draft-ietf-quic-transport-12 - Enable server to transition connections to a preferred address (#560,#1251). -- No more stream 0. +- Moved the cryptographic handshake off stream 0 and into CRYPTO_HS frames. - CRYPTO_HS, and CRYPTO_CLOSE frames - Move stateless retry to the QUIC layer. - Added token fields to Initial packet header. From bd5f9ff36dd1fc11a14f8fccd7ff144482ed356f Mon Sep 17 00:00:00 2001 From: EKR Date: Fri, 22 Jun 2018 06:19:53 -0700 Subject: [PATCH 26/31] Ian's comments --- draft-ietf-quic-tls.md | 10 +++++----- draft-ietf-quic-transport.md | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index c72ec08378..b8ebc9d462 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -331,9 +331,9 @@ only appear in the 0-RTT and 1-RTT encryption levels - CONNECTION_CLOSE and CRYPTO_CLOSE MAY appear in packets of any encryption level other than 0-RTT. - PADDING and PING frames MAY appear in packets of any encryption level. -- ACK frames MAY appear in packets of any encryption level, but - can only acknowledge packets which appeared in that encryption - level. +- ACK frames MAY appear in packets of any encryption level other than + 0-RTT, but can only acknowledge packets which appeared in that + encryption level. - STREAM frames MUST ONLY appear in the 0-RTT and 1-RTT levels. - All other frame types MUST only appear at the 1-RTT levels. @@ -676,10 +676,10 @@ QUIC packets are protected prior to applying packet number encryption (A). When removing packet protection, an endpoint first removes the protection from the packet number. -All QUIC packets other than Version Negotiation and Stateless Reset +All QUIC packets other than Version Negotiation and Retry packets are protected with an AEAD algorithm {{!AEAD}}. Prior to establishing a shared secret, packets are protected with -AEAD_AES_128_GCM and a key derived from the from the destination +AEAD_AES_128_GCM and a key derived from the destination connection ID in the client's first Initial packet (see {{initial-secrets}}). This provides protection against off-path attackers and robustness against QUIC version unaware middleboxes, but diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 4d87b8cd6e..8ba75cf9fe 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -551,10 +551,10 @@ provides some level of protection against off-path attackers. ### Initial Packet {#packet-initial} The Initial packet uses long headers with a type value of 0x7F. It -carries the first CRYPTO_HS frames sent by the client as well as the -cryptographic messages sent by the server to perform key exchange, and -may carry ACKs in either direction. The Initial packet is protected by -Initial keys as described in {{QUIC-TLS}}. +carries the first CRYPTO_HS frames sent by the client and server to +perform key exchange, and may carry ACKs in either direction. The +Initial packet is protected by Initial keys as described in +{{QUIC-TLS}}. The Initial packet has two additional header fields that follow the normal Long Header. @@ -582,7 +582,7 @@ NEW_TOKEN frame. The client and server use the Initial packet type for any packet that contains an initial cryptographic handshake message. In addition to -the first packet(s), This includes all cases where a new packet +the first packet(s). This includes all cases where a new packet containing the initial cryptographic message needs to be created, such as the packets sent after receiving a Version Negotiation ({{packet-version}}) or Retry packet ({{packet-retry}}). @@ -592,7 +592,7 @@ server may send multiple Initial packets. The cryptographic key exchange could require multiple round trips or retransmissions of this data. The payload of an Initial packet includes a CRYPTO_HS frame (or -frames), containing a cryptographic handshake message, ACK frames, or +frames) containing a cryptographic handshake message, ACK frames, or both. The first CRYPTO_HS frame sent always begins at an offset of 0 (see {{handshake}}). The client's complete first message MUST fit in a single packet (see {{handshake}}). Note that if the server sends a @@ -608,7 +608,7 @@ Connection ID field with an unpredictable value. This MUST be at least 8 octets in length. Until a packet is received from the server, the client MUST use the same value unless it abandons the connection attempt and starts a new one. The initial Destination Connection ID is -used to determine packet protection keys. +used to determine packet protection keys for Initial packets. The client populates the Source Connection ID field with a value of its choosing and sets the SCIL field to match. @@ -807,8 +807,8 @@ A sender can coalesce multiple QUIC packets (typically a Cryptographic Handshake packet and a Protected packet) into one UDP datagram. This can reduce the number of UDP datagrams needed to send application data during the handshake and immediately afterwards. It is not necessary for senders to coalesce -packets -- though failing to do so will require sending a significantly -larger number of packets during the handshake -- but receivers MUST +packets, though failing to do so will require sending a significantly +larger number of datagrams during the handshake. Receivers MUST be able to process coalesced packets. Senders SHOULD coalesce packets in order of increasing encryption levels @@ -3207,7 +3207,7 @@ frame offers the cryptographic protocol an in-order stream of bytes. CRYPTO_HS frames are functionally identical to STREAM frames, except that they do not bear a stream identifier; they are not flow controlled; and they do not carry markers for optional offset, -optional, length, and the end of the stream. +optional length, and the end of the stream. A CRYPTO_HS frame is shown below. From 7a780dbed8eed8ed9584db89215bd752dbf86c7a Mon Sep 17 00:00:00 2001 From: Mike Bishop Date: Fri, 22 Jun 2018 15:36:22 -0700 Subject: [PATCH 27/31] Fix build breaks --- draft-ietf-quic-tls.md | 7 +++---- draft-ietf-quic-transport.md | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index b8ebc9d462..1e5a27de8d 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -350,7 +350,6 @@ coalesced packets to send them in the same UDP datagram. | Handshake | Handshake | Handshake | | Retry | N/A | N/A | | Short Header | 1-RTT | 0/1-RTT | - {: #packet-types-levels title="Encryption Levels by Packet Type"} {{QUIC-TRANSPORT}}, Section 6.3 shows how packets at the various encryption @@ -572,8 +571,8 @@ as a connection error of type PROTOCOL_VIOLATION. ## Rejecting 0-RTT A server rejects 0-RTT by rejecting 0-RTT at the TLS layer. This also prevents -QUIC from sending 0-RTT data. A client that attempts 0-RTT MUST also consider 0-RTT to be rejected if it -receives a Version Negotiation packet. +QUIC from sending 0-RTT data. A client that attempts 0-RTT MUST also consider +0-RTT to be rejected if it receives a Version Negotiation packet. When 0-RTT is rejected, all connection characteristics that the client assumed might be incorrect. This includes the choice of application protocol, transport @@ -615,7 +614,7 @@ in {{TLS13}}, Section 7.3. The keys for the Initial encryption level are computed based on the client's initial Destination Connection ID, as described in -{{initial-secrets}}. +{{initial-secrets}}. The keys for the remaining encryption level are computed in the same fashion as the corresponding TLS keys (see {{TLS13}}; Section 7), diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 8ba75cf9fe..7a7d3b470f 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -360,7 +360,7 @@ The following packet types are defined: | Type | Name | Section | |:-----|:------------------------------|:----------------------------| | 0x7F | Initial | {{packet-initial}} | -| 0x7E | Retry | {{packet-retry}} | +| 0x7E | Retry | {{packet-retry}} | | 0x7D | Handshake | {{packet-handshake}} | | 0x7C | 0-RTT Protected | {{packet-protected}} | {: #long-packet-types title="Long Header Packet Types"} @@ -572,8 +572,8 @@ Header. Token Length: : A variable-length integer specifying the length of the Token field, in bytes. -It may be zero if no token is present. Initial packets sent by the server -MUST in include a zero-length token. + It may be zero if no token is present. Initial packets sent by the server + MUST in include a zero-length token. Token: @@ -2849,7 +2849,7 @@ TCP SACKs ({{?RFC2018}}). It is expected that a sender will reuse the same packet number across different packet number spaces. ACK frames only acknowledge the packet numbers that were transmitted by the sender in the same packet number space of the packet that the -ACK was received in. +ACK was received in. A client MUST NOT acknowledge Retry packets. Retry packets include the packet number from the Initial packet it responds to. Version Negotiation packets @@ -3040,7 +3040,7 @@ messages are delayed or lost. Note that the same limitation applies to other data sent by the server protected by the 1-RTT keys. Endpoints SHOULD send acknowledgments for packets containing CRYPTO_HS -frames with a reduced delay; see Section 3.5.1 of {{RECOVERY}}. +frames with a reduced delay; see Section 3.5.1 of {{QUIC-RECOVERY}}. ## PATH_CHALLENGE Frame {#frame-path-challenge} From 4db556887313b51de0139bb7c6c7be33614c4ddb Mon Sep 17 00:00:00 2001 From: Mike Bishop Date: Fri, 22 Jun 2018 15:53:25 -0700 Subject: [PATCH 28/31] Extra word --- draft-ietf-quic-transport.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-ietf-quic-transport.md b/draft-ietf-quic-transport.md index 7a7d3b470f..8c08896a6a 100644 --- a/draft-ietf-quic-transport.md +++ b/draft-ietf-quic-transport.md @@ -573,7 +573,7 @@ Token Length: : A variable-length integer specifying the length of the Token field, in bytes. It may be zero if no token is present. Initial packets sent by the server - MUST in include a zero-length token. + MUST include a zero-length token. Token: From 8d57711c819307c44cec8db2964a2a80c8f87ab9 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Mon, 25 Jun 2018 11:45:19 +1000 Subject: [PATCH 29/31] remove "the the" --- draft-ietf-quic-tls.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 1e5a27de8d..2dd3679756 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -445,8 +445,8 @@ provided with new handshake octets, or after TLS produces handshake octets. If 0-RTT is possible, it is ready after the client sends a TLS ClientHello message or the server receives that message. After providing a QUIC client with -the first handshake octets, the TLS stack might signal the change to the -the 0-RTT keys. On the server, after receiving handshake octets that contain a +the first handshake octets, the TLS stack might signal the change to +0-RTT keys. On the server, after receiving handshake octets that contain a ClientHello message, a TLS server might signal that 0-RTT keys are available. Note that although TLS only uses one encryption level at a time, QUIC From a2aabfe9e6feec0eaab59af0f4a0c212190b4474 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Mon, 25 Jun 2018 11:58:12 +1000 Subject: [PATCH 30/31] More errors around delivering to TLS out of order --- draft-ietf-quic-tls.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 2dd3679756..714d39a5b9 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -310,9 +310,10 @@ offset and length. Those frames are packaged into QUIC packets and encrypted under the current TLS encryption level. As with TLS over TCP, once TLS handshake data has been delivered to QUIC, it is QUIC's responsibility to deliver it -reliably. Each chunk of data is associated with the then-current TLS -sending keys, and if QUIC needs to retransmit that data, it MUST use -the same keys even if TLS has already updated to newer keys. +reliably. Each chunk of data that is produced by TLS is associated +with the set of keys that TLS is currently using. If QUIC needs to +retransmit that data, it MUST use the same keys even if TLS has already +updated to newer keys. One important difference between TLS 1.3 records (used with TCP) and QUIC CRYPTO_HS frames is that in QUIC multiple frames may appear @@ -382,27 +383,35 @@ TLS. The client acquires handshake octets before sending its first packet. A QUIC server starts the process by providing TLS with the client's handshake octets. -At any given time, an endpoint will have a current sending encryption -level and receiving encryption level. Each encryption level is +At any given time, the TLS stack at an endpoint will have a current sending +encryption level and receiving encryption level. Each encryption level is associated with a different flow of bytes, which is reliably transmitted to the peer in CRYPTO_HS frames. When TLS provides handshake -octets to be sent, they are appended to the current flow and -will eventually be transmitted under the then-current key. +octets to be sent, they are appended to the current flow and any packet +that includes the CRYPTO_HS frame is protected using keys from the +corresponding encryption level. When an endpoint receives a QUIC packet containing a CRYPTO_HS frame from the network, it proceeds as follows: -- If the packet was in the current receiving encryption level, sequence +- If the packet was in the TLS receiving encryption level, sequence the data into the input flow as usual. As with STREAM frames, the offset is used to find the proper location in the data sequence. If the result of this process is that new data is available, then it is delivered to TLS in order. - + - If the packet is from a previously installed encryption level, it MUST not contain data which extends past the end of previously received data in that flow. Implementations MUST treat any violations of this requirement as a connection error of type PROTOCOL_VIOLATION. + +- If the packet is from a new encryption level, it is saved for later + processing by TLS. Once TLS moves to receiving from this encryption + level, saved data can be provided. When providing data from any new + encryption level to TLS, if there is data from a previous encryption + level that TLS has not consumed, this MUST be treated as a connection + error of type PROTOCOL_VIOLATION. Each time that TLS is provided with new data, new handshake octets are requested from TLS. TLS might not provide any octets if the handshake From 2473966033d8f2d75a37113e723d05be42b20f38 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Mon, 25 Jun 2018 12:02:05 +1000 Subject: [PATCH 31/31] The online editor is terrible --- draft-ietf-quic-tls.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 714d39a5b9..39e51eee12 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -399,13 +399,13 @@ the network, it proceeds as follows: the offset is used to find the proper location in the data sequence. If the result of this process is that new data is available, then it is delivered to TLS in order. - + - If the packet is from a previously installed encryption level, it MUST not contain data which extends past the end of previously received data in that flow. Implementations MUST treat any violations of this requirement as a connection error of type PROTOCOL_VIOLATION. - + - If the packet is from a new encryption level, it is saved for later processing by TLS. Once TLS moves to receiving from this encryption level, saved data can be provided. When providing data from any new