jiebi/CodeConvo huggingface dataset:
Code change:
This moves text from the section on 0-RTT to the section on continuing after Retry. Though 0-RTT is the only thing that is seriously affected in the current design, Initial packets might also be affected if we ever wanted to protect those with anything other than a static key.
says that after receiving a Retry, clients MUST NOT reset the packet number for any packet number space, and references 17.2.3 for more info. However, 17.2.3 only explains why this is the case for 0-RTT packets. We should either narrow the prohibition or expand the explanation.
Or maybe move the explanation that currently exists 17.2.3 to 17.2.5.3 and use it as an example (to avoid it being read as the only reason).
NAME does NAME editorial change address your issue?
Yes, this is fine.

Related discussion:
text: response to receiving a Retry. A client MUST NOT reset the packet number for any packet number space <del> after processing a Retry packet; packet-0rtt contains more information on this. </del> <ins> after processing a Retry packet.  In particular, 0-RTT packets contain confidential information that will most likely be retransmitted on receiving a Retry packet.  The keys used to protect these new 0-RTT packets will not change as a result of responding to a Retry packet.  However, the data sent in these packets could be different than what was sent earlier.  Sending these new packets with the same packet number is likely to compromise the packet protection for those packets because the same key and nonce could be used to protect different content. </ins> A server acknowledges the use of a Retry packet for a connection using the retry_source_connection_id transport parameter; see
Code change:
I'd always heard this as "Authenticated Encryption with Additional Data," so it was -tls that sounded funny. But looking at 5116, it's actually "Associated" data and -tls is correct. Fixing in -transport.
I read this as referring to Authenticated at first.

Related discussion:
text: 12.1. All QUIC packets except Version Negotiation packets use authenticated <del> encryption with additional data (AEAD) RFC5116 to provide </del> <ins> encryption with associated data (AEAD) RFC5116 to provide </ins> confidentiality and integrity protection.  Retry packets use AEAD to provide integrity protection.  Details of packet protection are found in QUIC-TLS; this section includes an overview of the process.
Code change:
This does a little shuffling to move some of the context-setting up. It then adds some more meat to the introductory section.
Thanks for the review Jana. I've taken most of this, with small tweaks only. Two things I didn't take: Interleaving explanation with references to sections sounded appealing, but it turns out to be both harder to read as the links break up the flow, and harder to scan for links (the structure section serves as an abbreviated and accessible ToC). I didn't move the connection piece below streams as I think that - at this level - talking about the connection is important context. I've moved the picture to the section, which didn't have that simple diagram (just some more complex ones), and I think benefits from it.
When I was reading quic-transport I found it very difficult to deal with the forward references. Streams are presented before connections, the overall state machine isn't introduced up front, packets come long after frames, and both are long before the wire formats are described. It might worth revisiting the section ordering.
At some point, transport was hugely restructured, and I believe many of those changes were good, but some didn't work out that well. I find streams coming before connections particularly odd.
The larger idea is "high-level concepts, then wire encoding" which I think makes sense. It puts the things that someone needs for a conceptual understanding of the protocol in one place, and the things that someone needs to implement the protocol elsewhere. Within the high-level concepts, I also find it strange that connections don't come before streams. However, the "connections" group also includes things that really don't deserve pride-of-place as the first couple things to be discussed, either.
I think that the main concept you need is that QUIC has a connection that is shared state between two endpoints. The later sections about connections go into more detail than you need to understand the stream sections. But I note that we don't properly provide that basic knowledge in our introductory parts, which are quite lean. Leanness is good, but we might have overdone it slightly in this regard.
Having worked my way through the spec, my suggested resolution to this is that Section 5.3 needs to be earlier, perhaps much earlier. At the least, it should open Section 5; some or all of it might belong in Section 1.
Thanks for working through this!

Related discussion:
text: ordered delivery of cryptographic handshake data start from zero in each packet number space. <ins> fig-hs shows a simplied handshake and the exchange of packets and frames that are used to advance the handshake.  Exchange of application data during the handshake is enabled where possible, shown with a '*'.  Once completed, endpoints are able to exchange application data. </ins> Endpoints MUST explicitly negotiate an application protocol.  This avoids situations where there is a disagreement about the protocol that is in use.
Code change:
I see a couple of places where we require that values have high entropy. For instance of the packet header. The remainder of the first byte and an arbitrary number of bytes following it that are set to unpredictable values. The last 16 bytes of the datagram contain a Stateless Reset Token. and to ensure that it is easier to receive the packet than it is to guess the value correctly. In general, this means that things contain sufficient entropy (so, for instance, you might have a value with some fixed values and some high entropy values). In any case, I think the first of these should be "indistinguishable from random" and the second should be "containing at least 64 bits worth of entropy"
LGTM

Related discussion:
text: A stateless reset uses an entire UDP datagram, starting with the first two bits of the packet header.  The remainder of the first byte <del> and an arbitrary number of bytes following it that are set to unpredictable values.  The last 16 bytes of the datagram contain a Stateless Reset Token. </del> <ins> and an arbitrary number of bytes following it that are set to values that SHOULD be indistinguishable from random.  The last 16 bytes of the datagram contain a Stateless Reset Token. </ins> To entities other than its intended recipient, a stateless reset will appear to be a packet with a short header.  For the stateless reset
Code change:
I see a couple of places where we require that values have high entropy. For instance of the packet header. The remainder of the first byte and an arbitrary number of bytes following it that are set to unpredictable values. The last 16 bytes of the datagram contain a Stateless Reset Token. and to ensure that it is easier to receive the packet than it is to guess the value correctly. In general, this means that things contain sufficient entropy (so, for instance, you might have a value with some fixed values and some high entropy values). In any case, I think the first of these should be "indistinguishable from random" and the second should be "containing at least 64 bits worth of entropy"
LGTM

Related discussion:
text: This 8-byte field contains arbitrary data. <del> A PATH_CHALLENGE frame containing 8 bytes that are hard to guess is sufficient to ensure that it is easier to receive the packet than it is to guess the value correctly. </del> <ins> Including 64 bits of entropy in a PATH_CHALLENGE frame ensures that it is easier to receive the packet than it is to guess the value correctly. </ins> The recipient of this frame MUST generate a PATH_RESPONSE frame (frame-path-response) containing the same Data.
Code change:
This was never explicit for the client as it is usually not possible. in a way that perhaps was not anticipated.
is complete. Consequently, a server might expect 0-RTT packets to start with a However, this is not necessarily strictly true, because you might have the ACKs in 0.5RTT. Now you might say that the TLS stack reports the handshake as complete as soon as it receives Finished but that's an implementation detail
I think that this is true. The server can send before then, but we require that the client not install 1-RTT keys until it considers the handshake complete.
That's not entirely true. It's the server that needs to hold back keys (namely, the 1-RTT read key) until the handshake completes. The client can use keys as soon as they become available.
I think NAME is correct in sense that the following three events happen at the same moment on the client side: handshake is declared complete TLS stack provides the 1-RTT read and write keys TLS stack provides ClientFinished
Martin is correct. There are two different forms of handshake completion: complete when 1rtt can be sent and received, confirmed when the peer is known to be complete. The client cannot receive 0rtt acks before installing 1rtt keys, hence before hanshake is complete.
a nit, but LGTM

Related discussion:
text: Any received 0-RTT data that the server responds to might be due to a replay attack. <del> Therefore, the server's use of 1-RTT keys MUST be limited to sending data before the handshake is complete.  A server MUST NOT process </del> <ins> Therefore, the server's use of 1-RTT keys before the handshake is complete is limited to sending data.  A server MUST NOT process </ins> incoming 1-RTT protected packets before the TLS handshake is complete.  Because sending acknowledgments indicates that all frames in a packet have been processed, a server cannot send acknowledgments
Code change:
This was never explicit for the client as it is usually not possible. in a way that perhaps was not anticipated.
is complete. Consequently, a server might expect 0-RTT packets to start with a However, this is not necessarily strictly true, because you might have the ACKs in 0.5RTT. Now you might say that the TLS stack reports the handshake as complete as soon as it receives Finished but that's an implementation detail
I think that this is true. The server can send before then, but we require that the client not install 1-RTT keys until it considers the handshake complete.
That's not entirely true. It's the server that needs to hold back keys (namely, the 1-RTT read key) until the handshake completes. The client can use keys as soon as they become available.
I think NAME is correct in sense that the following three events happen at the same moment on the client side: handshake is declared complete TLS stack provides the 1-RTT read and write keys TLS stack provides ClientFinished
Martin is correct. There are two different forms of handshake completion: complete when 1rtt can be sent and received, confirmed when the peer is known to be complete. The client cannot receive 0rtt acks before installing 1rtt keys, hence before hanshake is complete.
a nit, but LGTM

Related discussion:
text: receiving a TLS ClientHello.  The server MAY retain these packets for later decryption in anticipation of receiving a ClientHello. <ins> A client generally receives 1-RTT keys at the same time as the handshake completes.  Even if it has 1-RTT secrets, a client MUST NOT process incoming 1-RTT protected packets before the TLS handshake is complete. </ins> 5.8. Retry packets (see the Retry Packet section of QUIC-TRANSPORT) carry
Code change:
Those packets that are not authenticated can be discarded, but only if processing them has no permanent effect on existing state. This attempts to explain that.
S 5.2. says: Invalid packets without packet protection, such as Initial, Retry, or Version Negotiation, MAY be discarded. An endpoint MUST generate a connection error if it commits changes to state before discovering an error. I'm having trouble parsing this.
LGTM

Related discussion:
text: Invalid packets without packet protection, such as Initial, Retry, or Version Negotiation, MAY be discarded.  An endpoint MUST generate a <del> connection error if it commits changes to state before discovering an error. </del> <ins> connection error if processing of the contents of these packets prior to discovering an error resulted in changes to the state of a connection that cannot be reverted. </ins> 5.2.1.
Code change:
This is a small tweak of Gorry's suggestion.
Looks good to me.
I promised to raise an issue relating to this text: "It can also improve connection throughput on severely asymmetric links; see Section 3 of [RFC3449]." This partly addresss the case, but it does not yet note the implications of the return path traffic on congestion of the return path. I think this is a useful addition, because it helps alert the reader of the tradeoff ... which can be quite important for half-duplex/shared radio, etc where the spectrum consumed sending an ACK can even outweigh the cost of sending a data packet (because they use different design of PHY). I suggest: "It can improve connection throughput using severely asymmetric links and can also reduce the volume of acknowledgment traffic using return path capacity; see Section 3 of [RFC3449]."

Related discussion:
text: On the other hand, reducing the frequency of packets that carry only acknowledgements reduces packet transmission and processing cost at <del> both endpoints.  It can also improve connection throughput on severely asymmetric links; see Section 3 of RFC3449. </del> <ins> both endpoints.  It can improve connection throughput on severely asymmetric links and reduce the volume of acknowledgment traffic using return path capacity; see Section 3 of RFC3449. </ins> A receiver SHOULD send an ACK frame after receiving at least two ack- eliciting packets.  This recommendation is general in nature and
Code change:
PTO packets always have to be ACK-eliciting, not just during the handshake, per existing text: "When a PTO timer expires, a sender MUST send at least one ack-eliciting packet in the packet number space as a probe,..." Also removed an "unless" clause, because if there's nothing to send, you don't arm the PTO timer.

Related discussion:
text: constants-of-interest) for a new path, but the delay SHOULD NOT be considered an RTT sample. <del> Prior to handshake completion, when few to none RTT samples have been generated, it is possible that the probe timer expiration is due to an incorrect RTT estimate at the client.  To allow the client to improve its RTT estimate, the new packet that it sends MUST be ack- eliciting. </del> Initial packets and Handshake packets could be never acknowledged, but they are removed from bytes in flight when the Initial and Handshake keys are discarded, as described below in discarding-
Code change:
PTO packets always have to be ACK-eliciting, not just during the handshake, per existing text: "When a PTO timer expires, a sender MUST send at least one ack-eliciting packet in the packet number space as a probe,..." Also removed an "unless" clause, because if there's nothing to send, you don't arm the PTO timer.

Related discussion:
text: 6.2.4. When a PTO timer expires, a sender MUST send at least one ack- <del> eliciting packet in the packet number space as a probe, unless there is no data available to send.  An endpoint MAY send up to two full- sized datagrams containing ack-eliciting packets, to avoid an expensive consecutive PTO expiration due to a single lost datagram or transmit data from multiple packet number spaces.  All probe packets sent on a PTO MUST be ack-eliciting. </del> <ins> eliciting packet in the packet number space as a probe.  An endpoint MAY send up to two full-sized datagrams containing ack-eliciting packets, to avoid an expensive consecutive PTO expiration due to a single lost datagram or transmit data from multiple packet number spaces.  All probe packets sent on a PTO MUST be ack-eliciting. </ins> In addition to sending data in the packet number space for which the timer expired, the sender SHOULD send ack-eliciting packets from
Code change:
This is an error that can be detected in frame parsing without additional context.
Over on URL we had a discussion about whether a MAXSTREAMS frame with value exceeding 2^60 generates a FRAMEENCODING or a STREAMLIMIT error. Draft 29 Section 19.11 says: corresponding type that can be opened over the lifetime of the connection. This value cannot exceed 2^60, as it is not possible to encode stream IDs larger than 2^62-1. Receipt of a frame that permits opening of a stream larger than this limit MUST be treated as a FRAMEENCODINGERROR. but as NAME points out, Section 4.5 says with a value greater than 2^60, this would allow a maximum stream ID that cannot be expressed as a variable-length integer; see Section 16. If either is received, the connection MUST be closed immediately with a connection error of type STREAMLIMITERROR Meanwhile, for the STREAMSBLOCKED frame in Section 19.15 we have: I suspect both Vidhi and I are correct, bogus MAXSTREAMS can be treated as either STREAMLIMIT or FRAME_ENCODING. If so, its probably a minor editorial fix to state either/or in both the sections.
NAME suggested that it should only be a FRAMEENCODINGERROR, as it's invalid to send a MAX_STREAMS larger than 2^60 under any circumstance, regardless of connection state, and I agree that's the clearest application of our principles.
I agree that requiring the use of FRAMEENOCDINGERROR is fine. Even though we occasionally allow an endpoint to use multiple error codes when there is more than one way of checking the status (i.e. FLOWCONTROLERROR vs. FRAMEENCODINGERROR for STREAM frames), the check required in this particular case is purely unrelated to the connection state. Hence my +1.
I would be happy with a single error too. I'm not fussy about the actual code used as long as the spec is clear and consistent. That means that we'd need to reduce STREAMS_BLOCKED to one error code too, and potentially any other situation that allows either.
I'm going to drop . I agree with the comments suggesting that FRAMEENCODINGERROR is the right answer. Note that you might still receive a different error, as we permit endpoints that detect multiple errors to send any that it detects, and this case clearly justifies use of STREAMLIMITERROR.

Related discussion:
text: with a value greater than 2^60, this would allow a maximum stream ID that cannot be expressed as a variable-length integer; see integer- encoding.  If either is received, the connection MUST be closed <del> immediately with a connection error of type STREAM_LIMIT_ERROR; see </del> <ins> immediately with a connection error of type FRAME_ENCODING_ERROR; see </ins> immediate-close. Endpoints MUST NOT exceed the limit set by their peer.  An endpoint
Code change:
The original text here might be read to imply that a server can't send Retry if it receives an Initial that contains a token that came from NEW_TOKEN. That's wrong.

Related discussion:
text: address validation by sending a Retry packet (packet-retry) containing a token.  This token MUST be repeated by the client in all Initial packets it sends for that connection after it receives the <del> Retry packet.  In response to processing an Initial containing a token, a server can either abort the connection or permit it to proceed. </del> <ins> Retry packet. In response to processing an Initial containing a token that was provided in a Retry packet, a server cannot send another Retry packet; it can only refuse the connection or permit it to proceed. </ins> As long as it is not possible for an attacker to generate a valid token for its own address (see token-integrity) and the client is
Code change:
An update to I read the 4091 text as implying that probes were sent upon a loss.

Related discussion:
text: To avoid excessively small idle timeout periods, endpoints MUST increase the idle timeout period to be at least three times the current Probe Timeout (PTO).  This allows for multiple PTOs to <del> expire, and therefore multiple probes to be sent in the event of loss, prior to idle timeout. </del> <ins> expire, and therefore multiple probes to be sent and lost, prior to idle timeout. </ins> 10.1.1.
Code change:
I noticed this in the Transport Draft (ID-30): Is this intentional? Should an invalid transport parameter result in a frame encoding error?
I believe this aligns with our principles that a framing error which can be detected with no connection context is a FRAMEENCODINGERROR. Is there another error you'd suggest?
My concern is that transport parameter values have nothing to do with framing and using FRAMEENCODINGERROR is therefore misleading.
We only ever applied this principle to frames though, so I'm not sure we can use it as a precedent here. The name is indeed confusing, as it's FRAMEENCODINGERROR and not FRAMINGERROR or ENCODINGERROR.
I always rationalized this as "the encoded content of the CRYPTO frame is erroneous".
Well, if we've been through this before, I won't insist -- it's just something that jumped out at me.
That's even more confusing. The CRYPTO frame itself is totally fine. I'd be in favor of changing it to a TRANSPORTPARAMETERERROR.

Related discussion:
text: MAX_STREAMS frames; see frame-max-streams.  Separate limits apply to unidirectional and bidirectional streams. <del> If a max_streams transport parameter or MAX_STREAMS frame is received with a value greater than 2^60, this would allow a maximum stream ID that cannot be expressed as a variable-length integer; see integer- encoding.  If either is received, the connection MUST be closed immediately with a connection error of type FRAME_ENCODING_ERROR; see immediate-close. </del> <ins> If a max_streams transport parameter or a MAX_STREAMS frame is received with a value greater than 2^60, this would allow a maximum stream ID that cannot be expressed as a variable-length integer; see integer-encoding.  If either is received, the connection MUST be closed immediately with a connection error of type TRANSPORT_PARAMETER_ERROR if the offending value was received in a transport parameter or of type FRAME_ENCODING_ERROR if it was received in a frame; see immediate-close. </ins> Endpoints MUST NOT exceed the limit set by their peer.  An endpoint that receives a frame with a stream ID exceeding the limit it has