21.12.1. The QUIC handshake incorporates the TLS 1.3 handshake and enjoys the <del> cryptographic properties described in Appendix E.1 of TLS13. </del>  <del> In addition to those properties, the handshake is intended to provide some defense against DoS attacks on the handshake, as described below. </del>  21.12.1.1.

We don't ever really say that QUIC depends on TLS providing the properties that we claim TLS provides. So it's worth pointing that exposure. This is more so because some of the properties we claim are dependent on these properties.
(Cleaned up duplicate instances of the same comment.)
As per comment URL I'll note that there is MITM protection in QUIC, but it is not immediate which is roughly why we have the concept of handshake confirmed.
The options for triage are close it, mark as editorial, or mark as design. This has a needs-discussion, and I'm seeing a lack of any discussion. So you might see where my thought process is going... NAME this relates to your PR on the QUIC threat model. Are you willing to provide some comment that helps us triage the issue?
I think that we can take this as editorial, as it merely requires that we capture already agreed principles (we don't protect against an adversary who can inject packets). NAME assistance would be useful, but I can produce text if nothing is forthcoming.
I can always provide comments, no guarantees on how much they'll help triage IIRC, this is an issue filed from a comment on the threat model PR that was several-months merged to potentially increase the scope of what that covered. I think that the original threat model that NAME and I put together, covering the handshake and migration respectively, is intended to be the start of that section -- as additional items are discovered that could use coverage there to help clarify QUIC's stance on whatever issue, they should totally be added. I agree with NAME that adding such items seem editorial, as they aren't introducing any new requirements and are only capturing current realities as specified elsewhere. (Of course, as that text is written, it seems logical that putting it all in words next to each other may highlight issues, and if the WG decides that we don't like how the current spec results in a particular security stance, we can open a design issue to change normative text elsewhere.) So, I'd probably consider this editorial, and ask NAME to potentially contribute some text or clarify what he's looking to have covered by the original comment -- once that's clear, happy to help get a PR up if needed (or NAME text is always good too!).
Since this concerns the handshake, I'm not too confident in contributing text but I'd be happy to review and discuss. I believe it is correct that the issue is covered in existing text elsewhere but as NAME says, it makes sense to cover it in one place. The risk is that the reader is not aware how important it is to reach a certain point in the connection before trusting data, and especially to those seeking to create derived versions. From various discussions I'm not sure the importance is broadly understood. Additionally, I'm not entirely convinced that the current text fully captures the problem - not that we necessarily can - for example various stateless transmissions / redirects / token issues - might assume a level of privacy that doesn't exist in all cases, thus requiring stronger integrity elsewhere such as in CIDs, tokens etc..
Thanks folks. It seems we have a path forward, so I'm removing the needs-discussion label. The editorial process will naturally generate some back and forth but that is the same for all editorial issues.

21.12.1. The QUIC handshake incorporates the TLS 1.3 handshake and enjoys the  <ins> cryptographic properties described in Appendix E.1 of TLS13.  Many of the security properties of QUIC depend on the TLS handshake providing these properties.  Any attack on the TLS handshake could affect QUIC. </ins>  <ins> Any attack on the TLS handshake that compromises the secrecy or uniqueness of session keys affects other security guarantees provided by QUIC that depends on these keys.  For instance, migration (migration) depends on the efficacy of confidentiality protections, both for the negotiation of keys using the TLS handshake and for QUIC packet protection, to avoid linkability across network paths. An attack on the integrity of the TLS handshake might allow an attacker to affect the selection of application protocol or QUIC version. In addition to the properties provided by TLS, the QUIC handshake provides some defense against DoS attacks on the handshake. </ins> 21.12.1.1.


packets being encrypted with per-version keys and the Handshake and later packets being encrypted with keys derived from the TLS key exchange.  Further, parameter negotiation is folded into the TLS <del> transcript and thus provides the same security guarantees as ordinary TLS negotiation.  Thus, an attacker can observe the client's transport parameters (as long as it knows the version-specific salt) </del>  but cannot observe the server's transport parameters and cannot influence parameter negotiation.

packets being encrypted with per-version keys and the Handshake and later packets being encrypted with keys derived from the TLS key exchange.  Further, parameter negotiation is folded into the TLS  <ins> transcript and thus provides the same integrity guarantees as ordinary TLS negotiation.  An attacker can observe the client's transport parameters (as long as it knows the version-specific keys) </ins> but cannot observe the server's transport parameters and cannot influence parameter negotiation.


6.2.3. <del> Stream types of the format "0x1f * N + 0x21" for integer values of N are reserved to exercise the requirement that unknown types be ignored.  These streams have no semantics, and can be sent when application-layer padding is desired.  They MAY also be sent on </del>  connections where no data is currently being transferred.  Endpoints MUST NOT consider these streams to have any meaning upon receipt.

Clarify reserved values for stream types, settings identifiers, frame types, and error codes. 0x1f N + 0x21 for the value of N = -1 is 0x02. Literal interpretation of the current text includes this as a reserved value. The parenthetical examples given in Section 11.2 make it clear that this was not the intention, rendering this PR editorial. The main motivation of this PR is not that the current text is inconsistent, but that parenthetical examples from 11.2 are necessary to correctly interpret the definitions in sections 6.2.3, 7.2.4.1, 7.2.8, and 8.1. Alternative wordings could be: "0x1f N + 0x21 for N = 0, 1, 2, ..." "0x1f N + 0x02 for positive integer values of N" "0x1f N + 0x02 for N = 1, 2, 3, ..." "0x21, 0x21 + 0x1f, 0x21 + 2 * 0x1f, ..." "a value of at least 0x21 with a remainder of 0x02 modulo 0x1f" "a value of at least 0x21 that is congruent to 0x21 modulo 0x1f" none of which is better than what this PR proposes.

6.2.3.  <ins> Stream types of the format "0x1f * N + 0x21" for non-negative integer values of N are reserved to exercise the requirement that unknown types be ignored.  These streams have no semantics, and can be sent when application-layer padding is desired.  They MAY also be sent on </ins> connections where no data is currently being transferred.  Endpoints MUST NOT consider these streams to have any meaning upon receipt.


The default value is unlimited.  See header-formatting for usage. <del> Setting identifiers of the format "0x1f * N + 0x21" for integer values of N are reserved to exercise the requirement that unknown identifiers be ignored.  Such settings have no defined meaning. Endpoints SHOULD include at least one such setting in their SETTINGS frame.  Endpoints MUST NOT consider such settings to have any meaning upon receipt. </del>  Because the setting has no defined meaning, the value of the setting can be any value the implementation selects.

The default value is unlimited.  See header-formatting for usage.  <ins> Setting identifiers of the format "0x1f * N + 0x21" for non-negative integer values of N are reserved to exercise the requirement that unknown identifiers be ignored.  Such settings have no defined meaning.  Endpoints SHOULD include at least one such setting in their SETTINGS frame.  Endpoints MUST NOT consider such settings to have any meaning upon receipt. </ins> Because the setting has no defined meaning, the value of the setting can be any value the implementation selects.


7.2.8. <del> Frame types of the format "0x1f * N + 0x21" for integer values of N are reserved to exercise the requirement that unknown types be ignored (extensions).  These frames have no semantics, and can be sent on any open stream when application-layer padding is desired. They MAY also be sent on connections where no data is currently being transferred.  Endpoints MUST NOT consider these frames to have any meaning upon receipt. </del>  The payload and length of the frames are selected in any manner the implementation chooses.

7.2.8.  <ins> Frame types of the format "0x1f * N + 0x21" for non-negative integer values of N are reserved to exercise the requirement that unknown types be ignored (extensions).  These frames have no semantics, and can be sent on any open stream when application-layer padding is desired.  They MAY also be sent on connections where no data is currently being transferred.  Endpoints MUST NOT consider these frames to have any meaning upon receipt. </ins> The payload and length of the frames are selected in any manner the implementation chooses.


The requested operation cannot be served over HTTP/3.  The peer should retry over HTTP/1.1. <del> Error codes of the format "0x1f * N + 0x21" for integer values of N are reserved to exercise the requirement that unknown error codes be treated as equivalent to H3_NO_ERROR (extensions).  Implementations SHOULD select an error code from this space with some probability when they would have sent H3_NO_ERROR. </del>  9.

The requested operation cannot be served over HTTP/3.  The peer should retry over HTTP/1.1.  <ins> Error codes of the format "0x1f * N + 0x21" for non-negative integer values of N are reserved to exercise the requirement that unknown error codes be treated as equivalent to H3_NO_ERROR (extensions). Implementations SHOULD select an error code from this space with some probability when they would have sent H3_NO_ERROR. </ins> 9.


The entries in iana-frame-table are registered by this document. <del> Additionally, each code of the format "0x1f * N + 0x21" for integer values of N (that is, "0x21", "0x40", ..., through </del>  "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. 11.2.2.

The entries in iana-frame-table are registered by this document.  <ins> Additionally, each code of the format "0x1f * N + 0x21" for non- negative integer values of N (that is, "0x21", "0x40", ..., through </ins> "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. 11.2.2.


The entries in iana-setting-table are registered by this document. <del> Additionally, each code of the format "0x1f * N + 0x21" for integer values of N (that is, "0x21", "0x40", ..., through </del>  "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. 11.2.3.

The entries in iana-setting-table are registered by this document.  <ins> Additionally, each code of the format "0x1f * N + 0x21" for non- negative integer values of N (that is, "0x21", "0x40", ..., through </ins> "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. 11.2.3.


The entries in the iana-error-table are registered by this document. <del> Additionally, each code of the format "0x1f * N + 0x21" for integer values of N (that is, "0x21", "0x40", ..., through </del>  "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. 11.2.4.

The entries in the iana-error-table are registered by this document.  <ins> Additionally, each code of the format "0x1f * N + 0x21" for non- negative integer values of N (that is, "0x21", "0x40", ..., through </ins> "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. 11.2.4.


The entries in the following table are registered by this document. <del> Additionally, each code of the format "0x1f * N + 0x21" for integer values of N (that is, "0x21", "0x40", ..., through </del>  "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. 12.  References

The entries in the following table are registered by this document.  <ins> Additionally, each code of the format "0x1f * N + 0x21" for non- negative integer values of N (that is, "0x21", "0x40", ..., through </ins> "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. 12.  References


If TLS experiences an error, it generates an appropriate alert as defined in Section 6 of TLS13. <del> A TLS alert is turned into a QUIC connection error by converting the one-byte alert description into a QUIC error code.  The alert </del>  description is added to 0x100 to produce a QUIC error code from the range reserved for CRYPTO_ERROR.  The resulting value is sent in a QUIC CONNECTION_CLOSE frame of type 0x1c.

This defines a limit on the number of packets that can fail authentication before you have to use new keys. There is a big hole here in that AES-CCM (that is, the AEAD based on CBC-MAC) is currently permitted, but we have no analysis to support either the confidentiality limits in TLS 1.3 or the integrity limits in this document. It is probably OK, but that is not the standard we apply here. So this might have to remain open until we get some sort of resolution on that issue. My initial opinion is to cut CCM from the draft until/unless an analysis is produced.
In the interest of transparency, I have added one more commit here. When I did the same for DTLS, ekr observed that if you have updated, you might safely stop trying to accept packets with the old keys rather than killing the connection. That results in loss for any packets that genuinely did want to use the exhausted keys, but that is probably less disruptive than having the connection drop. Of course, you can't always update, so closure is still likely necessary in some cases.
For what it's worth, Martin, Felix, and I put together a document which might help users do this themselves: URL
NAME Could you use that to come up with 2^16 limits and put them in the doc? I’m really wary of letting implementors roll their own
Sure! Can you please file an issue with that request? Noting anything else you'd like spelled out in detail would be helpful, too.
tl;dr We need to recommend limits on the number of failed decryptions. At one of the side discussions concentrated on the quality of the analysis of the and the applicability of that analysis to QUIC. Felix Günther, along with Marc Fischlin, Christian Janson, and Kenny Paterson have done a little analysis, based on and the we used to set limits in TLS. There are two relevant limits in this analysis: The confidentiality bound, which is usually expressed in terms of advantage an attacker gains in being able to break confidentiality of records/packets as they get more data from valid packets. For instance, in AES-GCM, the analysis shows that after seeing 2^24.5 packets (almost 24 million) the attacker has a 2^-60 better chance than pure chance of winning the IND-CPA game. The forgery bound, which is again expressed as an probably of an attacker successfully creating a forged record/packet. Thanks to the analysis done previously, we know that AES-GCM and ChaCha20+Poly1305 have a forgery chance of 2^-57 after 2^60 and 2^36 forgery attempts respectively. The current text just points to TLS 1.3, which recommends the use of key updates to protect confidentiality. But TLS has a forgery tolerance of 0: a single failed forgery attempt causes the connection to break. QUIC (and DTLS) allow for multiple forgeries to be ignored, so we need to factor that in. As discussed in if we want to maintain security, we need to consider both confidentiality and integrity. For that we need two independent limits: The number of packets that are successfully encrypted and decrypted. The number of packets that are unsuccessfully decrypted. We have the former already. The latter is what this issue tracks. Once the limit is at risk of being exceeded, updating keys will force the attacker to start over. Based on Felix's recommendation I am going to suggest that we limit forgery attempts to 2^36. I have confirmed this with a close reading of the paper and concur. There is a significant difference here between AES-GCM and ChaCha20+Poly1305 but we believe that setting a single limit is the best approach. I will create a pull request to document this approach shortly. We could split the recommendation and allow a larger limit for AES-GCM, but I don't believe that 2^36 (~68 billion) is a significant barrier. For reference, if you were able to saturate a 10Gbps link with 50 byte IP packets that contained plausible QUIC packets, and the recipient didn't treat this as DoS traffic, it would take 5 minutes. If we assume that are more likely representative of potential packet rates, then the limit goes up to 10s of hours. I would point out that that volume of unproductive traffic is probably a good reason to use something other than a key update to deal with the sender. A reminder that the underlying analysis assumes that packets are all 2^14 in size, which is the record size in TLS. This is ~10 times larger than typical MTU on the Internet and many QUIC packets might be smaller than that, so - at least for AES-GCM - recommending a 2^36 limit is more conservative than necessary. However, if we were to allow for different limits, we'd have to address the question of packet size, as a 2^16 byte packet will be used by some deployments. For ChaCha20+Poly1305, the only value that matters is the number of packets, so we avoid that question. Quoting from Felix's email for reference (with permission):
NAME Can I request that you review this analysis for correctness? I know that you had reservations about the claims here.
Another (simplier?) option could be to just update keys much more often. I've done performance tests with msquic on the effect of updating the key ~once per round trip. There was no noticeable effect on performance. In fact, more often than not, the key update perf tests happen to perform slightly better (within noise tolerance) than without key update. I'm not suggesting we advocate once a round trip or anything near that; more like every 2^20 packets (or 2^30 bytes?) sent or received (including failed decryptions). As I understand it, this is an ultra conservative number as far as protecting from any kind of attacks, and should be free as far as any performance impact on the connection. This also has the added benefit of exercising the key update scenario more often, which should hopefully improve interoperability of the feature.
I support a change like this, but I am not qualified to say what the thresholds should be. There certainly isn't a reason to push it to very high limits. This change would not break interoperability, so it's a good one. Banning CCM might break interoperability for someone, but I'm not too concerned, particularly if we can update all the browsers to not offer it. A somewhat bigger concern is the lack of key update support in a lot of implementations: I read 9 of 15 servers as supporting it.
(Tentative) good news on CCM: Kenny identified a security analysis paper and it seems relatively simple to go from that to numbers. I am not personally concerned about support for key update. 9/15 isn't 15, but that doesn't bother me. It turns out to be a little fiddly to implement, so if people decide to drop connections that hit these limits instead, the effect isn't that bad. Of course, if you want to follow Nick's suggestion, that works too (I remember Dan Bernstein seriously suggesting a cipher that updated every record, back when I first proposed this scheme for TLS).
If we're looking for a new bound to initiate a key update, there's precedent in the SSH RFC to rekey after every 1 GB of data transferred. See
I should point out that my "9 of 15" figure is based on the interop matrix, where the client initiates an early update and the server responds. That is a different thing than a server initiating an update when required by the spec, which fewer than 9 servers might do.
Based on by Jonsson, I have calculated the bounds on the number of forgeries and encryptions for CCM. The numbers aren't great, but that probably doesn't matter much for the purposes to which CCM is generally put. (I'm using the notation from the here because that is easier to type than some of what is being used in other papers. For reference, q is the number of genuine encryptions, l is the length of each in 16 byte blocks, v is the number of forgeries, n is the key length in bits, t is the tag length in bits.) Jonsson puts the advantage an attacker has over a generic PRF at . If we assume the same numbers in the AEBounds paper for record/packet size, (this is for consistency, most QUIC packets will be much smaller, in the order of 2^7, but we might also go as high as 2^12; this being dictated by the MTU). For AES, . To keep the advantage an attacker has to 2^-60 (to match the analysis in TLS), we therefore need to keep q to below 2^24.5. Somewhat unsurprisingly, that matches the numbers we have for AES-GCM. Jonsson puts the advantage for an attacker over a generic PRF at . As the first term is negligible even for large v (up to 2^64), we consider the second term alone and aim for a bound on the advantage of 2^-57 to match the analysis for other ciphers. That leaves us with . As q is already established to be 2^24.5, we can say that v should be limited to 2^25 (or if you want to be precise). (As a side note, for t=64, as in AEADAES128CCM8, the first term becomes relevant and our security bound limits the number of forgeries to 2^7, which is probably a bit limiting in practice. That's good justification for not enabling AEADAES128CCM_8 by default; though different applications might use a different target bound than 2^-57.) I'm an not a cryptographer. These papers all read like chicken-chicken-chicken. My calculations are not infallible either.
The shape of the bound seems plausible but I'll start a thread with the cryptographers to check everything
I reproduced Martin's analysis of CCM based on of the bounds by . (Myself not being an expert in producing such bounds, I found the second-level confirmation by Rogaway to be helpful.) I essentially agree with the numbers, except that --when following the same metric as the -- the advantage over an ideal PRP (instead of PRF) should be considered. This simply means losing a 1/2 factor in the bound: Confidentiality bound: yields an advantage of . I'd hence say it's fine to keep TLS 1.3's recommendation on sending max. full-sized records. Integrity bound: , hence yields an advantage of (matching the other analyses). Most importantly, I concur with Martin that AEADAES128CCM8 would need either much lower bounds or a different risk assessment: applying the same limit of would bring the advantage incurred through the bound up to . Would it still be the best approach to define the same anti-forgery limit across all cipher suites, even if this means going down to ? Of course, I'm happy to discuss more with NAME !
Thanks for checking this NAME I was a little concerned about the PRP/PRF split, so I'm glad to have you correct me. I ultimately went with per-AEAD recommendations, and a lower limit for CCM. That's mainly to establish some sort of uniformity around 2^-60 and 2^-57. Even if those are basically arbitrary choices, at least they are defensible (I think!) and using them uniformly establishes the right expectations about what the standard is. I'm comfortable with specifying different limits for each AEAD in specifications. In practice, however, I expect that a far lower tolerance for forgery attempts. Assuming that these numbers work out, a review of the pull request would be greatly appreciated. If there are other relevant papers, I'm always happy to pull those in as well.
I realize that I didn't respond to NAME That advice applies to the limits that TLS specifies already; this issue is primarily about responding to forgeries. That said, 1G is pretty good advice. However what we've seen from this analysis that 1G results in a lower safety margin than TLS aims for. But it's close enough that if the AEAD is as good as the set we have here, you are probably OK. However, this does depend a lot on the specific AEAD. I'd be uncomfortable using so simple a guide in the general case.
NAME points out an error in my calculation. I had based my calculations on direct mapping of in the CCM analysis to in our calculations. That is, was the number of blocks in the message. But the analysis by Jonsson defines this as: ! The definition of Beta is the CCM function, so this function really reduces to 2 times the length of the message (in blocks), plus 1 (to account for the additional encryption). We can ignore the extra 1 as that is absorbed by the tag length. I'm updating the numbers in the PR. The result is another halving of the number of packets. NAME NAME it's pretty clear that I'm out of my depth here, so your input would be highly valued.
Good catch, yes, the double passing over the message requires a factor 2 here. (The AD a may also be up to 3 blocks if I understand the header format correctly, but I guess that's negligible compared to the conservative 2^10 message size.)
Good point about the AD. The AD - at least for QUIC - is always sent, so that fits in the same space. We don't necessarily need to double count the tiny number of blocks, but as you say, counting that only once yields a negligible difference. If we had a large AD that wasn't also transmitted, that would be different.
Agreed. To be precise: if I'm not mistaken the AD isn't counted at all right now ( accounts for the max. payload blocks), but of course the difference is still negligible as long as the AD is small.
Thanks for the edits!

If TLS experiences an error, it generates an appropriate alert as defined in Section 6 of TLS13.  <ins> A TLS alert is converted into a QUIC connection error.  The alert </ins> description is added to 0x100 to produce a QUIC error code from the range reserved for CRYPTO_ERROR.  The resulting value is sent in a QUIC CONNECTION_CLOSE frame of type 0x1c.


The alert level of all TLS alerts is "fatal"; a TLS stack MUST NOT generate alerts at the "warning" level.  4.11. After QUIC moves to a new encryption level, packet protection keys

The alert level of all TLS alerts is "fatal"; a TLS stack MUST NOT generate alerts at the "warning" level. <ins> QUIC permits the use of a generic code in place of a specific error code; see Section 11 of QUIC-TRANSPORT.  For TLS alerts, this includes replacing any alert with a generic alert, such as handshake_failure (0x128 in QUIC).  Endpoints MAY use a generic error code to avoid possibly exposing confidential information. </ins> 4.11. After QUIC moves to a new encryption level, packet protection keys


Key updates MUST be initiated before usage limits on packet protection keys are exceeded.  For the cipher suites mentioned in <del> this document, the limits in Section 5.5 of TLS13 apply.  Other cipher suites MUST define usage limits in order to be used with QUIC. </del>  6.7.

Key updates MUST be initiated before usage limits on packet protection keys are exceeded.  For the cipher suites mentioned in  <ins> this document, the limits in Section 5.5 of TLS13 apply.  TLS13 does not specify a limit for AEAD_AES_128_CCM, but the analysis in ccm- bounds shows that a limit of 2^23 packets can be used to obtain the same confidentiality protection as the limits specified in TLS. The usage limits defined in TLS 1.3 exist for protection against attacks on confidentiality and apply to successful applications of AEAD protection.  The integrity protections in authenticated encryption also depend on limiting the number of attempts to forge packets.  TLS achieves this by closing connections after any record fails an authentication check.  In comparison, QUIC ignores any packet that cannot be authenticated, allowing multiple forgery attempts. Endpoints MUST count the number of received packets that fail authentication for each set of keys.  If the number of packets that fail authentication with the same key exceeds a limit that is specific to the AEAD in use, the endpoint MUST stop using those keys. Endpoints MUST initiate a key update before reaching this limit.  If a key update is not possible, the endpoint MUST immediately close the connection.  Applying a limit reduces the probability that an attacker is able to successfully forge a packet; see AEBounds and ROBUST. Due to the way that header protection protects the Key Phase, packets that are discarded are likely to have an even distribution of both Key Phase values.  This means that packets that fail authentication will often use the packet protection keys from the next key phase.  It is therefore necessary to also track the number of packets that fail authentication with the next set of packet protection keys.  To avoid exhaustion of both sets of keys, it might be necessary to initiate two key updates in succession. For AEAD_AES_128_GCM, AEAD_AES_256_GCM, and AEAD_CHACHA20_POLY1305, the limit on the number of packets that fail authentication is 2^36. Note that the analysis in AEBounds supports a higher limit for the AEAD_AES_128_GCM and AEAD_AES_256_GCM, but this specification recommends a lower limit.  For AEAD_AES_128_CCM, the limit on the number of packets that fail authentication is 2^23.5; see ccm-bounds. These limits were originally calculated using assumptions about the limits on TLS record size.  The maximum size of a TLS record is 2^14 bytes.  In comparison, QUIC packets can be up to 2^16 bytes.  However, it is expected that QUIC packets will generally be smaller than TLS records.  Where packets might be larger than 2^14 bytes in length, smaller limits might be needed. Any TLS cipher suite that is specified for use with QUIC MUST define limits on the use of the associated AEAD function that preserves margins for confidentiality and integrity.  That is, limits MUST be specified for the number of packets that can be authenticated and for the number packets that can fail authentication.  Providing a reference to any analysis upon which values are based - and any assumptions used in that analysis - allows limits to be adapted to varying usage conditions. </ins> 6.7.


protocol negotiation.  TLS uses Application Layer Protocol Negotiation (ALPN) ALPN to select an application protocol.  Unless another mechanism is used for agreeing on an application protocol, <del> endpoints MUST use ALPN for this purpose.  When using ALPN, endpoints MUST immediately close a connection (see Section 10.3 in QUIC- TRANSPORT) if an application protocol is not negotiated with a no_application_protocol TLS alert (QUIC error code 0x178, see tls- errors).  While ALPN only specifies that servers use this alert, QUIC clients MUST also use it to terminate a connection when ALPN negotiation fails. </del>  An application protocol MAY restrict the QUIC versions that it can operate over.  Servers MUST select an application protocol compatible

protocol negotiation.  TLS uses Application Layer Protocol Negotiation (ALPN) ALPN to select an application protocol.  Unless another mechanism is used for agreeing on an application protocol,  <ins> endpoints MUST use ALPN for this purpose. When using ALPN, endpoints MUST immediately close a connection (see Section 10.3 of QUIC-TRANSPORT) with a no_application_protocol TLS alert (QUIC error code 0x178; see tls-errors) if an application protocol is not negotiated.  While ALPN only specifies that servers use this alert, QUIC clients MUST use error 0x178 to terminate a connection when ALPN negotiation fails. </ins> An application protocol MAY restrict the QUIC versions that it can operate over.  Servers MUST select an application protocol compatible


Including transport parameters in the TLS handshake provides integrity protection for these values. <del> The "extension_data" field of the quic_transport_parameters extension </del>  contains a value that is defined by the version of QUIC that is in use.

Including transport parameters in the TLS handshake provides integrity protection for these values.  <ins> The extension_data field of the quic_transport_parameters extension </ins> contains a value that is defined by the version of QUIC that is in use.


output of AEAD_AES_128_GCM AEAD used with the following inputs: The secret key, K, is 128 bits equal to <del> 0x4d32ecdb2a2133c841e4043df27d4430. </del>  <del> The nonce, N, is 96 bits equal to 0x4d1611d05513a552c587d575. </del>  The plaintext, P, is empty.

Any chance we could also update the initial salt?
I was saving that for the final version, by popular demand. If you have a reason to change, then I can do that (I'll also want to update the keys for Retry in that case).
I agree with NAME Let's leave the salt update to the final version.
With Google's QUIC deployment, we're already experiencing version ossification due to middleboxes inspecting initial packets - some of our traffic is stuck on older versions of GoogleQUIC because of this. Changing the salts every time we change the version number will help remind everyone that this is not an ossified aspect of the protocol. The cost to implementors is pretty much zero. NAME out of curiosity, why the pushback?
What NAME says makes sense to me, so I would be in favor of shipping draft-29 with new salts.
I updated the salts and the test vectors in quic-go, and I can confirm that the values match.
The draft describes that a client SHOULD NOT reuse a token in different connections (URL). However, I miss the argument that the server SHOULD NOT construct the same token multiple times. This argument addresses the risks of client tracking via tokens if a deterministic approach is used to construct them.
Maybe ?
NAME do you mean already covers this?
Yes, my view is that and the corresponding mailing list thread (URL) covers this issue. They discuss about unlinkability between the tokens issued by a server.
NAME do you agree that this is (mostly) covered by ? If yes, can we close this issue and resolve it as part of ?
No, does not cover this particular point. makes the point that a network observer should not be able to derive information such as a timestamp from observed tokens. However, this issue says that the construction of the token should not be deterministic. To illustrate this problem, assume that the token is more or less the hash of the client's source address. Thus, the client receives upon repeat connections each time the same token, if its source address is identical. As a result, even if the client uses each token only a single time the corresponding connections established with these tokens can be correlated to each other by a network observer.
NAME could be modified to cover your issue? could you comment there?
NAME Ok, I will make proposals within to cover this issue.
NAME the automation failed here - this should not be moved to "Text Incorporated", it should just be closed As stated in URL, my understanding is that a token sent in a NEW_TOKEN frame SHOULD be encrypted. The only exception would be the case of the token carrying only an opaque and randomly-generated key identifier in a stateful design (i.e. a server using a key-value store to retain the information of previous connections). Otherwise, an observer can use the information contained in the token sent in an resuming connection, to correlate that connection to the previous connection that issued the token. For example, if a server includes the generation time of the token in plaintext, an observer can extract that information found in an Initial packet to nail down the connection that issued the token. While I think we might be call this an editorial issue, I think we should clarify this as a normative requirement (e.g., SHOULD). Hence bringing the discussion to the mailing list as well. Kazuho Oku

output of AEAD_AES_128_GCM AEAD used with the following inputs: The secret key, K, is 128 bits equal to  <ins> 0xccce187ed09a09d05728155a6cb96be1. </ins>  <ins> The nonce, N, is 96 bits equal to 0xe54930f97f2136f0530a8c1c. </ins> The plaintext, P, is empty.


The secret key and the nonce are values derived by calling HKDF- Expand-Label using <del> 0x656e61e336ae9417f7f0edd8d78d461e2aa7084aba7a14c1e9f726d55709169a as </del>  the secret, with labels being "quic key" and "quic iv" (protection- keys).

The secret key and the nonce are values derived by calling HKDF- Expand-Label using  <ins> 0x8b0d37eb8535022ebc8d76a207d80df22646ec06dc809642c30a8baa2baaff4c as </ins> the secret, with labels being "quic key" and "quic iv" (protection- keys).


The payload of an Initial packet includes a CRYPTO frame (or frames) containing a cryptographic handshake message, ACK frames, or both. <del> PING, PADDING, and CONNECTION_CLOSE frames are also permitted.  An endpoint that receives an Initial packet containing other frames can either discard the packet as spurious or treat it as a connection error. </del>  The first packet sent by a client always includes a CRYPTO frame that contains the start or all of the first cryptographic handshake

When we prohibited the use of application-layer CONNECTION_CLOSE in these packets, we should have updated the text in the description of the packets also.
I think the spec is ambiguous when it says in section 17.2: and: >Handshake packets MAY contain CONNECTIONCLOSE frames. But CONNECTIONCLOSE can mean 0x1c or 0x1d. Are both permitted during the handshake?
NAME In this case, the intent is to allow both. Unless explicitly specified, I would read the text to mean both types of CONNECTION_CLOSE frames.
Okay, if more people think that way, we can close with no action.
So on the surface, there is no inconsistency: the two sections permit CONNECTIONCLOSE. But the question about the different types of CONNECTIONCLOSE is more relevant than NAME response might imply. We currently require that CONNECTIONCLOSE of type 0x1d (application close) is not sent in Initial or Handshake packets. So that's a drafting error, and we might reasonably take this as an editorial issue. However, if the question is about what a reaction to receiving an application CONNECTIONCLOSE in one of those packets, we might consider a different posture. If you get an application CONNECTIONCLOSE in an Initial packet that is otherwise valid, you probably want to drop the connection. And you probably don't want to start sending CONNECTIONCLOSE in response every time, because that leads to madness. But this is a general problem: if you detect and error and that error keeps being repeated, it probably isn't a good idea to generate a CONNECTION_CLOSE in response to every infraction.
(removing my comment as NAME posted what needs to be said couple of seconds earlier).
I'm going to re-close the can of worms I half-opened in my earlier comment and take this as editorial. From memory, the larger question of how to deal with junk is something we've discussed several times. If anyone wants to take that up, I'm happy to do that, but let's at least correct the obvious error.
It does make sense that we only allow 0x1c during the handshake.
NAME : Apologies, I misspoke -- I was speaking to interpretation of text, rather than the actual question itself.

The payload of an Initial packet includes a CRYPTO frame (or frames) containing a cryptographic handshake message, ACK frames, or both.  <ins> PING, PADDING, and CONNECTION_CLOSE frames of type 0x1c are also permitted.  An endpoint that receives an Initial packet containing other frames can either discard the packet as spurious or treat it as a connection error. </ins> The first packet sent by a client always includes a CRYPTO frame that contains the start or all of the first cryptographic handshake


The payload of this packet contains CRYPTO frames and could contain PING, PADDING, or ACK frames.  Handshake packets MAY contain <del> CONNECTION_CLOSE frames.  Endpoints MUST treat receipt of Handshake packets with other frames as a connection error. </del>  Like Initial packets (see discard-initial), data in CRYPTO frames for Handshake packets is discarded - and no longer retransmitted - when

The payload of this packet contains CRYPTO frames and could contain PING, PADDING, or ACK frames.  Handshake packets MAY contain  <ins> CONNECTION_CLOSE frames of type 0x1c.  Endpoints MUST treat receipt of Handshake packets with other frames as a connection error. </ins> Like Initial packets (see discard-initial), data in CRYPTO frames for Handshake packets is discarded - and no longer retransmitted - when


Indicates that x is repeated zero or more times (and that each instance is length E)  fig-ex-format shows an example structure: 5.

Editorial NiTs when reviewing the invariant text. These NiTs address readability issues, and do not intend to change the meaning of the text.
Is there an associated issue?
Thanks Gorry, these are all quite helpful. 1) I understand the acronyms DCID and SCID, but these aren't really expanded on first use in sect 5.1. 2) There's mention of "the high bit", but there doesn't seem to be any statement of bit order saying. Is it worth declaring network byte/bit order earlier in section 4? This also clarifies the placement of fields within a byte, which was basically assumed knowledge otherwise. 3) Personally, I don't think: "The length of the Destination Connection ID is not specified" is a great choice of words. Surely, this needs to be specified somewhere for a protocol instance to use it? This reads better as something like: The length of the Destination Connection ID is not encoded in packets with a short header and is not constrained by this specification. 4) The brackets here seem to point to connection IDs in general, not the DCID "(see Section 5.3)". Is it worth writing that as "Connection IDs are described in Section 5", rather than use brackets? The same is true for versions. 5) In section 5.3: "the wrong endpoint" is taken as the wrong transport endpoint, but some of our IP and subIP colleagues would use the term endpoint for other uses, so one insertion of "transport" would perhaps help? 6) In the appendix A, this: "QUIC forbids acknowledgments of packets" - still has me wondering what is actually intended to be understood, because the list of bullets is not guarenteed ... : /The last packet before a long period of quiescence might be assumed to contain an acknowledgment (it should be assumed that QUIC could allow acknowledgments of packets that only contain ACK frames)/ I'm not sure what to say here I think the combination of not... forbids threw me off the meaning. Changes proposed in
Thanks for changing SCID/DCID to "Source Connection ID" and "Destination Connection ID", that seems like a good change.

Indicates that x is repeated zero or more times (and that each instance is length E) <ins> This document uses network byte order (that is, big endian) values. Fields are placed starting from the high-order bits of each byte. </ins> fig-ex-format shows an example structure: 5.


A QUIC packet with a long header has the high bit of the first byte set to 1.  All other bits in that byte are version specific. <del> The next four bytes include a 32-bit Version field (see version). </del>  The next byte contains the length in bytes of the Destination <del> Connection ID (see connection-id) field that follows it.  This length is encoded as an 8-bit unsigned integer.  The Destination Connection ID field follows the DCID Length field and is between 0 and 255 bytes in length. </del>  The next byte contains the length in bytes of the Source Connection ID field that follows it.  This length is encoded as a 8-bit unsigned <del> integer.  The Source Connection ID field follows the SCID Length field and is between 0 and 255 bytes in length. </del>  The remainder of the packet contains version-specific content.

A QUIC packet with a long header has the high bit of the first byte set to 1.  All other bits in that byte are version specific.  <ins> The next four bytes include a 32-bit Version field.  Versions are described in version. </ins> The next byte contains the length in bytes of the Destination  <ins> Connection ID field that follows it.  This length is encoded as an 8-bit unsigned integer.  The Destination Connection ID field follows the Destination Connection ID Length field and is between 0 and 255 bytes in length.  Connection IDs are described in connection-id. </ins> The next byte contains the length in bytes of the Source Connection ID field that follows it.  This length is encoded as a 8-bit unsigned  <ins> integer.  The Source Connection ID field follows the Source Connection ID Length field and is between 0 and 255 bytes in length. </ins> The remainder of the packet contains version-specific content.


A QUIC packet with a short header includes a Destination Connection ID immediately following the first byte.  The short header does not include the Connection ID Lengths, Source Connection ID, or Version <del> fields.  The length of the Destination Connection ID is not specified </del>  in packets with a short header and is not constrained by this specification.

A QUIC packet with a short header includes a Destination Connection ID immediately following the first byte.  The short header does not include the Connection ID Lengths, Source Connection ID, or Version  <ins> fields.  The length of the Destination Connection ID is not encoded </ins> in packets with a short header and is not constrained by this specification.


The primary function of a connection ID is to ensure that changes in addressing at lower protocol layers (UDP, IP, and below) don't cause <del> packets for a QUIC connection to be delivered to the wrong endpoint. The connection ID is used by endpoints and the intermediaries that support them to ensure that each QUIC packet can be delivered to the correct instance of an endpoint.  At the endpoint, the connection ID is used to identify which QUIC connection the packet is intended for. </del>  The connection ID is chosen by each endpoint using version-specific methods.  Packets for the same QUIC connection might use different

The primary function of a connection ID is to ensure that changes in addressing at lower protocol layers (UDP, IP, and below) don't cause  <ins> packets for a QUIC connection to be delivered to the wrong QUIC endpoint.  The connection ID is used by endpoints and the intermediaries that support them to ensure that each QUIC packet can be delivered to the correct instance of an endpoint.  At the endpoint, the connection ID is used to identify which QUIC connection the packet is intended for. </ins> The connection ID is chosen by each endpoint using version-specific methods.  Packets for the same QUIC connection might use different


Indicates that x is repeated zero or more times (and that each instance is length E)  By convention, individual fields reference a complex field by using the name of the complex field.

Indicates that x is repeated zero or more times (and that each instance is length E) <ins> This document uses network byte order (that is, big endian) values. Fields are placed starting from the high-order bits of each byte. </ins> By convention, individual fields reference a complex field by using the name of the complex field.


packet protection keys for Initial packets. The client populates the Source Connection ID field with a value of <del> its choosing and sets the SCID Length field to indicate the length. </del>  The first flight of 0-RTT packets use the same Destination Connection ID and Source Connection ID values as the client's first Initial

packet protection keys for Initial packets. The client populates the Source Connection ID field with a value of  <ins> its choosing and sets the Source Connection ID Length field to indicate the length. </ins> The first flight of 0-RTT packets use the same Destination Connection ID and Source Connection ID values as the client's first Initial


If a zero-length connection ID is selected, the corresponding transport parameter is included with a zero-length value. <del> fig-auth-cid shows the connection IDs that are used in a complete </del>  handshake.  The exchange of Initial packets is shown, plus the later exchange of 1-RTT packets that includes the connection ID established during the handshake.

If a zero-length connection ID is selected, the corresponding transport parameter is included with a zero-length value.  <ins> fig-auth-cid shows the connection IDs (with DCID=Destination Connection ID, SCID=Source Connection ID) that are used in a complete </ins> handshake.  The exchange of Initial packets is shown, plus the later exchange of 1-RTT packets that includes the connection ID established during the handshake.


SHOULD be able to read longer connection IDs from other QUIC versions in order to properly form a version negotiation packet. <del> The Destination Connection ID field follows the DCID Length field and is between 0 and 20 bytes in length. negotiating-connection- ids describes the use of this field in more detail. </del>  The byte following the Destination Connection ID contains the length in bytes of the Source Connection ID field that follows it.

SHOULD be able to read longer connection IDs from other QUIC versions in order to properly form a version negotiation packet.  <ins> The Destination Connection ID field follows the Destination Connection ID Length field and is between 0 and 20 bytes in length.  negotiating-connection-ids describes the use of this field in more detail. </ins> The byte following the Destination Connection ID contains the length in bytes of the Source Connection ID field that follows it.


IDs from other QUIC versions in order to properly form a version negotiation packet. <del> The Source Connection ID field follows the SCID Length field and is between 0 and 20 bytes in length. negotiating-connection-ids describes the use of this field in more detail. </del>  In this version of QUIC, the following packet types with the long header are defined:

IDs from other QUIC versions in order to properly form a version negotiation packet.  <ins> The Source Connection ID field follows the Source Connection ID Length field and is between 0 and 20 bytes in length. negotiating- connection-ids describes the use of this field in more detail. </ins> In this version of QUIC, the following packet types with the long header are defined:


The Initial packet contains a long header as well as the Length and Packet Number fields.  The first byte contains the Reserved and <del> Packet Number Length bits.  Between the SCID and Length fields, there are two additional fields specific to the Initial packet. </del>  A variable-length integer specifying the length of the Token field, in bytes.  This value is zero if no token is present.

The Initial packet contains a long header as well as the Length and Packet Number fields.  The first byte contains the Reserved and  <ins> Packet Number Length bits.  Between the Source Connection ID and Length fields, there are two additional fields specific to the Initial packet. </ins> A variable-length integer specifying the length of the Token field, in bytes.  This value is zero if no token is present.


transport parameter; see termination.  However, state in middleboxes might time out earlier than that.  Though REQ-5 in RFC4787 recommends a 2 minute timeout interval, experience shows that sending packets <del> every 15 to 30 seconds is necessary to prevent the majority of middleboxes from losing state for UDP flows. </del>  10.3.

Thanks to Lucas for finding the study. Note that I found at least one middlebox with a default timeout of 30s; that was not a home gateway included in this study.
says that "experience shows" you should send packets every 15-30 seconds, RFC4787 notwithstanding. Ideally, we would have a source that we could reference for this "experience."
Maybe see URL
I'm going to say that while the 15s floor is a good requirement, I don't want to cite RFC 8085 for this gem, which I think is straight-up misinformation: "NATs require a state timeout of 2 minutes or longer [RFC4787]." We do cite RFC 8085 elsewhere and that's fine, but the fact here is that the IETF has requested that NATs provide a state timeout of 2 minutes. That does not mean that they do.
I have seen anecdata as well that showing 30 seconds is an important threshold. I think the ref we now have is good.

transport parameter; see termination.  However, state in middleboxes might time out earlier than that.  Though REQ-5 in RFC4787 recommends a 2 minute timeout interval, experience shows that sending packets  <ins> every 30 seconds is necessary to prevent the majority of middleboxes from losing state for UDP flows GATEWAY. </ins> 10.3.


After a client receives a Retry packet, 0-RTT packets are likely to have been lost or discarded by the server.  A client SHOULD attempt to resend data in 0-RTT packets after it sends a new Initial packet. <del> A client MUST NOT reset the packet number it uses for 0-RTT packets, since the keys used to protect 0-RTT packets will not change as a result of responding to a Retry packet.  Sending packets with the same packet number in that case is likely to compromise the packet protection for all 0-RTT packets because the same key and nonce could be used to protect different content. </del>  A client only receives acknowledgments for its 0-RTT packets once the handshake is complete.  Consequently, a server might expect 0-RTT

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.

After a client receives a Retry packet, 0-RTT packets are likely to have been lost or discarded by the server.  A client SHOULD attempt to resend data in 0-RTT packets after it sends a new Initial packet.  <ins> New packet numbers MUST be used for any new packets that are sent; as described in retry-continue, reusing packet numbers could compromise packet protection. </ins> A client only receives acknowledgments for its 0-RTT packets once the handshake is complete.  Consequently, a server might expect 0-RTT


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>  A server acknowledges the use of a Retry packet for a connection using the retry_source_connection_id transport parameter; see

response to receiving a Retry. A client MUST NOT reset the packet number for any packet number space  <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


12.1. All QUIC packets except Version Negotiation packets use authenticated <del> encryption with additional data (AEAD) RFC5116 to provide </del>  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.

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.

12.1. All QUIC packets except Version Negotiation packets use authenticated  <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.


Authenticated and encrypted header and payload <del> QUIC uses UDP as a substrate to avoid requiring changes to legacy client operating systems and middleboxes.  QUIC authenticates all of its headers and encrypts most of the data it exchanges, including its signaling, to avoid incurring a dependency on middleboxes. </del>  1.1.

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!

Authenticated and encrypted header and payload  <ins> QUIC establishes a connection, which is a stateful interaction between a client and server.  The primary purpose of a connection is to support the structured exchange of data by an application protocol. Streams are means by which an application protocol exchanges information.  Streams are ordered sequences of bytes.  Two types of stream can be created: bidirectional streams, which allow both endpoints to send data; and unidirectional streams, which allow a single endpoint to send.  A credit-based scheme is used to limit stream creation and to bound the amount of data that can be sent. The QUIC handshake combines negotiation of cryptographic and transport parameters.  The handshake is structured to permit the exchange of application data as soon as possible.  This includes an option for clients to send data immediately (0-RTT), which might require prior communication to enable. QUIC connections are not strictly bound to a single network path. Connection migration uses connection identifiers to allow connections to transfer to a new network path. Frames are used in QUIC to communicate between endpoints.  One or more frames are assembled into packets.  QUIC authenticates all packets and encrypts as much as is practical.  QUIC packets are carried in UDP datagrams to better facilitate deployment in existing systems and networks. Once established, multiple options are provided for connection termination.  Applications can manage a graceful shutdown, endpoints can negotiate a timeout period, errors can cause immediate connection teardown, and a stateless mechanism provides for termination of connections after one endpoint has lost state. </ins> 1.1.


5. <del> QUIC's connection establishment combines version negotiation with the cryptographic and transport handshakes to reduce connection establishment latency, as described in handshake.  During connection establishment, each side validates the peer's address, as described in address-validation.  Once established, a connection may migrate to a different IP or port at either endpoint as described in migration. Finally, a connection may be terminated by either endpoint, as described in termination. </del>  5.1.

5.  <ins> A QUIC connection is shared state between a client and a server. Each connection starts with a handshake phase, during which the two endpoints establish a shared secret using the cryptographic handshake protocol QUIC-TLS and negotiate the application protocol.  The handshake (handshake) confirms that both endpoints are willing to communicate (validate-handshake) and establishes parameters for the connection (transport-parameters). An application protocol can use the connection during the handshake phase with some limitations.  0-RTT allows application data to be sent by a client before receiving a response from the server. However, 0-RTT provides no protection against replay attacks; see Section 9.2 of QUIC-TLS.  A server can also send application data to a client before it receives the final cryptographic handshake messages that allow it to confirm the identity and liveness of the client.  These capabilities allow an application protocol to offer the option of trading some security guarantees for reduced latency. The use of connection IDs (connection-id) allows connections to migrate to a new network path, both as a direct choice of an endpoint and when forced by a change in a middlebox.  migration describes mitigations for the security and privacy issues associated with migration. For connections that are no longer needed or desired, there are several ways for a client and server to terminate a connection (termination). </ins> 5.1.


5.3. <del> A QUIC connection is a stateful interaction between a client and server, the primary purpose of which is to support the exchange of data by an application protocol.  Streams (streams) are the primary means by which an application protocol exchanges information. Each connection starts with a handshake phase, during which client and server establish a shared secret using the cryptographic handshake protocol QUIC-TLS and negotiate the application protocol. The handshake (handshake) confirms that both endpoints are willing to communicate (validate-handshake) and establishes parameters for the connection (transport-parameters). An application protocol can also operate in a limited fashion during the handshake phase.  0-RTT allows application data to be sent by a client before receiving any response from the server.  However, 0-RTT lacks certain key security guarantees.  In particular, there is no protection against replay attacks in 0-RTT; see QUIC-TLS. Separately, a server can also send application data to a client before it receives the final cryptographic handshake messages that allow it to confirm the identity and liveness of the client.  These capabilities allow an application protocol to offer the option to trade some security guarantees for reduced latency. The use of connection IDs (connection-id) allows connections to migrate to a new network path, both as a direct choice of an endpoint and when forced by a change in a middlebox.  migration describes mitigations for the security and privacy issues associated with migration. For connections that are no longer needed or desired, there are several ways for a client and server to terminate a connection (termination). 5.4. </del> There are certain operations that an application MUST be able to perform when interacting with the QUIC transport.  This document does not specify an API, but any implementation of this version of QUIC

5.3.  There are certain operations that an application MUST be able to perform when interacting with the QUIC transport.  This document does not specify an API, but any implementation of this version of QUIC


ordered delivery of cryptographic handshake data start from zero in each packet number space.  Endpoints MUST explicitly negotiate an application protocol.  This avoids situations where there is a disagreement about the protocol that is in use.

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.


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>  To entities other than its intended recipient, a stateless reset will appear to be a packet with a short header.  For the stateless reset

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

A stateless reset uses an entire UDP datagram, starting with the first two bits of the packet header.  The remainder of the first byte  <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


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>  The recipient of this frame MUST generate a PATH_RESPONSE frame (frame-path-response) containing the same Data.

This 8-byte field contains arbitrary data.  <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.


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>  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

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

Any received 0-RTT data that the server responds to might be due to a replay attack.  <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


receiving a TLS ClientHello.  The server MAY retain these packets for later decryption in anticipation of receiving a ClientHello.  5.8. Retry packets (see the Retry Packet section of QUIC-TRANSPORT) carry

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


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>  5.2.1.

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

Invalid packets without packet protection, such as Initial, Retry, or Version Negotiation, MAY be discarded.  An endpoint MUST generate a  <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.


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>  A receiver SHOULD send an ACK frame after receiving at least two ack- eliciting packets.  This recommendation is general in nature and

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]."

On the other hand, reducing the frequency of packets that carry only acknowledgements reduces packet transmission and processing cost at  <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


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-

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.

constants-of-interest) for a new path, but the delay SHOULD NOT be considered an RTT sample.  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-


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>  In addition to sending data in the packet number space for which the timer expired, the sender SHOULD send ack-eliciting packets from

6.2.4. When a PTO timer expires, a sender MUST send at least one ack-  <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


5.2. <del> min_rtt is the minimum RTT observed for a given network path. min_rtt is set to the latest_rtt on the first RTT sample, and to the lesser of min_rtt and latest_rtt on subsequent samples.  In this document, min_rtt is used by loss detection to reject implausibly small rtt samples. </del>  An endpoint uses only locally observed times in computing the min_rtt and does not adjust for acknowledgment delays reported by the peer.

I believe this covers the discussion on the issue. It also introduces some MUSTs which should've always been there. I don't have a strong opinion on the use of RFC 2119 language here, and I'm happy to remove all of that language if folks think that's better. I would like not to bikeshed this, but I would also like to be on a beach right now, enjoying a lovely drink and watching the sunset.
NAME wrote the following in his WGLC review (): Splitting this off from as a potential design issue.
This seems like a reasonable thing to do.
I'd support a can or a MAY, as an example when you might reset min_rtt, but I don't think we need a SHOULD here.
minrtt is currently only used for filtering unexpectedly large ackdelay's reported by the peer. If the path RTT truly inflates then the peer will be able to report much larger ackdelay values and get a much lower RTT sample accepted. But I don't think this is a security problem in practice. The only other consideration is that in future QUIC implementations may reuse this computed value for other purposes like delay based congestion control. It's hard to make a judgement call on how important it is to reset minrtt. I guess I'd be happy with a SHOULD but I can live with a MAY.
Jana made a good argument that persistent congestion could be declared due to an overly small RTT, so resetting minrtt could avoid an endpoint repeatedly declaring persistent congestion. That being said, the RTT samples also need to be too low to spuriously declare persistent congestion, so this is increasingly sounding like an attack scenario, rather than having a poor estimate of minrtt. I think a SHOULD is Ok now, but I'd like to state the best rationale we have for why it's a SHOULD and neither a MUST or a MAY.
I think there's one tricky point in resetting the minrtt after handshake confirmation. That is that all the packets can be acked with delays. IIRC, one of the reasons we were happy with using minrtt for capping latestrtt is that Initial and Handshake packets do not have ackdelays. If we are to suggest that an endpoint MAY reset minrtt when persistent congestion is declared, I think we should consider the risk of not having good estimate of minrtt, as we would have during the handshake.
I don't see that as a risk here. min_rtt doesn't consider any discretionary delays.
NAME That's exactly the problem. will be inflated by , unless and until the peer sends an immediate acknowledgement. And until that happens, will as well.
I think that's OK. In practice, immediate ACKs do happen, and even at low rates, this should resolve to a "true" minimum. And if it doesn't, then you have worse performance than you might had otherwise. You have to have a pretty poor network (or a terrible ACK generation regime) for minrtt not to eventually resolve to a useful minimum. Explaining this risk is fine, but the endpoint that does this made the choice to throw out minrtt and that's just a consequence of that.
On one hand I agree that we can expect to see immediate ACKs, especially when HTTP/3 is used. At the same time, I am not sure if resetting minrtt when observing persistent congestion is better than other cases where we might reset minrtt, but that we do not currently mention. Change of IPTTL could be one of the examples in this regard (IIRC NAME pointed out that we do not use that value for detecting path changes). To summarize, I think talking about resetting minrtt might be fine, though I am not sure if that discussion should be tied to persistent congestion.
To give a specific example, one problem that I know with the current definition of minrtt is that it cannot detect and correct RTT estimate of a congested path. The sole purpose of minrtt is to discard excessive ack-delays being reported by the receiver. This works by capping the lower bound of adjustedrtt to minrtt. The problem here is that minrtt is a value that is typically collected when the path is almost idle. Once the path becomes congested, the true RTT becomes much greater than minrtt. For instance, if RTT-on-idle is 10ms and if RTT-on-congestion is 50ms, minrtt would be 10ms, and therefore cannot be used to correct RTT estimates when the peer reports an excessive ackdelay of, say 25ms. The RTT estimate would become 25ms in such case. I tend to think that this might be a bigger problem of the original issue, and therefore that we should state that an endpoint can periodically re-collect minrtt estimates, if we are to make a change to the current definition of minrtt.
Based on agreement on the resolution in , which introduces normative language, let's mark this design.
Seems fine. I'm not 100% on the strength of the recommendation to reset after persistent congestion, but it's sensible advice.The resetting of min RTT is also specified with LEDBAT or BBR, which differ from each other and from this proposed spec. This is a complex issue, because resetting min RTT in LEDBAT "because of congestion" is a variation of the latecomer advantage. But as long as the text applies only to RENO as specified here, then I am fine with it.I like the cautionary text. Just one suggestion but LGTM regardless. Thank you for working on this.

5.2.  <ins> min_rtt is the sender's estimate of the minimum RTT observed for a given network path.  In this document, min_rtt is used by loss detection to reject implausibly small rtt samples. min_rtt MUST be set to the latest_rtt on the first RTT sample. min_rtt MUST be set to the lesser of min_rtt and latest_rtt (latest- rtt) on all other samples. </ins> An endpoint uses only locally observed times in computing the min_rtt and does not adjust for acknowledgment delays reported by the peer.


The RTT for a network path may change over time.  If a path's actual RTT decreases, the min_rtt will adapt immediately on the first low <del> sample.  If the path's actual RTT increases, the min_rtt will not adapt to it, allowing future RTT samples that are smaller than the new RTT to be included in smoothed_rtt. </del>  5.3.

The RTT for a network path may change over time.  If a path's actual RTT decreases, the min_rtt will adapt immediately on the first low  <ins> sample.  If the path's actual RTT increases however, the min_rtt will not adapt to it, allowing future RTT samples that are smaller than the new RTT to be included in smoothed_rtt. Endpoints SHOULD set the min_rtt to the newest RTT sample after persistent congestion is established.  This is to allow a connection to reset its estimate of min_rtt and smoothed_rtt (smoothed-rtt) after a disruptive network event, and because it is possible that an increase in path delay resulted in persistent congestion being incorrectly declared. Endpoints MAY re-establish the min_rtt at other times in the connection, such as when traffic volume is low and an acknowledgement is received with a low acknowledgement delay.  Implementations SHOULD NOT refresh the min_rtt value too often, since the actual minimum RTT of the path is not frequently observable. </ins> 5.3.


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>  immediate-close. Endpoints MUST NOT exceed the limit set by their peer.  An endpoint

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.

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  <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


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>  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

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.

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  <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


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>  10.1.1.

An update to I read the 4091 text as implying that probes were sent upon a loss.

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  <ins> expire, and therefore multiple probes to be sent and lost, prior to idle timeout. </ins> 10.1.1.


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>  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

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.

MAX_STREAMS frames; see frame-max-streams.  Separate limits apply to unidirectional and bidirectional streams.  <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


Clients SHOULD send a CANCEL_PUSH frame upon receipt of a PUSH_PROMISE frame carrying a request that is not cacheable, is not known to be safe, that indicates the presence of a request body, or <del> for which it does not consider the server authoritative. </del>  Each pushed response is associated with one or more client requests. The push is associated with the request stream on which the

In the HTTP/3 draft 30, section 4.4 on Server Push says and then adds in 10.4 (URL) I don't think normative requirements belong in security considerations except in reference to that requirement elsewhere. Also, requirements in general should clearly state who is responsible for implementing them, whereas the latter requirement implies a client (maybe). And sending CANCEL_PUSH is kind of like the MUST NOT, but not really the same thing; it seems a bit weak in response given that the server just tried to poison the client. I think the server MUST is an interop requirement because the client MUST NOT is a critical security requirement. I think both should be described in Server Push and merely noted in the Security Considerations, since they are really important. Way more important than the spec reads now. My guess is that this is editorial, but is the kind of thing that should be fixed before IESG last call.
The reason it's only a SHOULD CANCEL_PUSH is that the server can't know with certainty for which origins the client considers it authoritative. The server only knows for which origins it believes that it's authoritative. So having received a push the client considers out-of-bounds, the client can't know for sure whether it's a poisoning attempt or simply a difference in view. Yes, I think this is editorial, since the core request is to relocate existing text without changing the normative requirements.

Clients SHOULD send a CANCEL_PUSH frame upon receipt of a PUSH_PROMISE frame carrying a request that is not cacheable, is not known to be safe, that indicates the presence of a request body, or  <ins> for which it does not consider the server authoritative.  Any corresponding responses MUST NOT be used or cached. </ins> Each pushed response is associated with one or more client requests. The push is associated with the request stream on which the


served out of cache, overriding the actual representation that the authoritative tenant provides. <del> Pushed responses for which an origin server is not authoritative (see connection-reuse) MUST NOT be used or cached. </del>  10.5.

served out of cache, overriding the actual representation that the authoritative tenant provides.  <ins> Clients are required to reject pushed responses for which an origin server is not authoritative; see server-push. </ins> 10.5.


21.6. <del> An adversarial sender might intentionally send fragments of stream data in an attempt to cause disproportionate receive buffer memory commitment and/or creation of a large and inefficient data structure. </del>  An adversarial receiver might intentionally not acknowledge packets containing stream data in an attempt to force the sender to store the

Proposal to clarify "stream fragmentation". Suggested by Issue .
I don’t understand what section 21.6 is about… the title seems to suggests it is about IP Fragmentation and Reassembly Attacks, but elsewhere the spec already prohibits IP Fragmentation in section 14? And I have seen no encouragement to do any form of network-layer fragmentation - so I don’t understand a security consideration in this topic. Is this therefiore some other thing? It may about something different where a sender originates data with “holes” of missing packet to try and exercise the server? or soemthing? What is this?
Hi NAME 21.6 is titled "Stream Fragmentation and Reassembly Attacks". It refers to streams, not IP packets. The attack involves sending stream frames with holes such as and some receivers might allocate the entire stream receive buffer between 0 and 10000001. I found the section pretty clear, but we should make it clear to everyone - could you perhaps suggest text that would make it clearer?
OK. I see. I can try a PR, if I can find words that avoid "fragment": Is this close enough to start: /An adversarial sender might intentionally omit to send portions of the stream data causing the receiver to commit resources for the omitted data, this could cause a disproportionate receive buffer memory commitment and/or creation of a large and inefficient data structure.
Do we really need to avoid the term "fragment"? It's not the only overloaded networking term in the spec. Perhaps adding a "Note that stream fragmentation is unrelated to IP fragmentation" could suffice?
I don't think this clarification is necessary. The context makes it clear what fragmentation this is, and talking about IP fragmentation only leads to confuse the reader. (I like the first part of your PR though, as I've noted on my review of it.)

21.6.  <ins> An adversarial sender might intentionally not send portions of the stream data, causing the receiver to commit resources for the unsent data.  This could cause a disproportionate receive buffer memory commitment and/or the creation of a large and inefficient data structure at the receiver. </ins> An adversarial receiver might intentionally not acknowledge packets containing stream data in an attempt to force the sender to store the


Using a value for "N" that is small, but at least 1 (for example, 1.25) ensures that variations in round-trip time do not result in <del> under-utilization of the congestion window.  Values of 'N' larger than 1 ultimately result in sending packets as acknowledgments are received rather than when timers fire, provided the congestion window is fully utilized and acknowledgments arrive at regular intervals. </del>  Practical considerations, such as packetization, scheduling delays, and computational efficiency, can cause a sender to deviate from this

N was introduced in to describe how a sender might pace at a rate that allows it to send a congestion window's worth of data in a period that is shorter than an RTT. This PR clarifies text that goes into unnecessary detail, trying to describe assumptions (the network is spreading the packets out, for example, resulting in an ack clock).
Can we make progress in this one?
Yes, I'm waiting for the design issues to get done before moving on the remaining editorial ones.
I think that has happened now :-)
Nudge

Using a value for "N" that is small, but at least 1 (for example, 1.25) ensures that variations in round-trip time do not result in  <ins> under-utilization of the congestion window. </ins> Practical considerations, such as packetization, scheduling delays, and computational efficiency, can cause a sender to deviate from this