Change:
Fixes issue .
I know we have consensus and are ready to merge this PR, but... have we considered what error code the server shall use? Implementing this, the easiest for me is INVALID_TOKEN. Is that the obvious intent here?
INVALIDTOKEN seems wrong to me. Why not PROTOCOLVIOLATION?
(I first raised this issue on the .)_ There is the following in the transport draft: We should allow the server to abort the connection the the client violates this . The server can do so by including the packet number into the Retry token and comparing against it when the client sends packets that carry the token.
I think that this might as well run through the design process. It's borderline, because this is about enforcement of an existing MUST, which you might argue comes with an implicit MAY enforce, but we do need to agree on the requirement level. Note that this isn't completely trivial to implement. If a servers responds to packet 1 with Retry, it has to ignore packet 0 if it arrives with no token (or a NEW_TOKEN token). That's already a requirement, but a poor implementation of this requirement will fail, likely with low enough probability that the error won't be detected, especially when it is hidden by Alt-Svc.
I agree this isn't trivial to enforce. Which is why I favor "If you detect this, you SHOULD close the connection.", rather than any recommendation on detecting a violation.
Aside from it not being trivial to enforce, I am not sure how much I like the idea of enforcing correctness for Initial packets. And that is because injection of Initial packets is the way for middleboxes to disrupt the connection. IIRC, we have allowed endpoints to ignore suspicious Initial packets, and I tend to think that we do not need to suggest that an endpoint can (IMO needlessly) strict.
How would the server know to ignore packet 0 in a Stateless Retry? I believe it would respond with another Retry packet instead.
If it's not trivial, it's verging on trivial. The "right" way to enforce this, as Dmitri notes, is to include the client's packet number in the Retry token. Upon receipt of any token, if it is a retry token, the server checks whether the containing packet number is less than or equal to that stored in the token. If it's not a retry token, no check is needed. This is completely stateless, so if packets get reordered, nothing breaks. As to the point of modifying Initial packets, that's true. An attacker that can modify packets can always cause the handshake to fail; this is just another way. To use this for disruption by injecting a packet, the attacker has to observe the client's Initial, the server's Retry packet, and then fabricate an Initial with a lower packet number. Not a high bar, but an attacker that can observe the packets in both directions and inject packets can break things in many other ways, too. I'm comfortable with MAY enforce (which I think is already implicit in a MUST NOT) at least, if people think one more integer encoded in the token is too high a bar for a stronger recommendation.
I'm also fine with MAY. Honestly, I'm also fine with can. I agree with Mike's comments that there are so many ways to interrupt the handshake at this stage, this is just another one, and likely not the easiest by far.
I agree that it is unlikely that servers detecting this behavior would help MITM attackers. My concern was mostly about principles regarding what we write down in spec. That said, I would not oppose to using a MAY here. It is already implied by the MUST NOT on the client-side, so to me it is an editorial change.
Based on the discussion of the issue during consensus call, I'd like to mark this as within 24 hours. And have someone create a spin-off issue for a general-sense review of use of MAYs, if they believe there is a strong need for it. (see URL).
As pointed out by NAME on the mailing list, adds little value to the spec. Every MUST can be enforced by aborting the connection. I'm not convinced that adding a "The peer MAY abort the connection if this MUST is violated" after every MUST increases the clarity of the spec.
As with NAME my preference here is for parsimony (I would feel different if there were a SHOULD). However, I'm not going to go to the mat as long as we add a statement somewhere that you are generally permitted to respond to every MUST violation by closing the connection; if we do that this text is just superfluous.
As stated in URL, detecting MUST violations for Handshake and ApplicationData packets is fine because they are protected by the secrets, but not necessarily for unprotected information. Therefore, it makes sense to have a MAY here. My limited experience tells me that we have different customs between WGs. I tend to believe that document produced by TLS WG assume that a MUST implies "peer MAY detect." And that's fine because TLS does not care about attacks against the underlying transport, and hence any violation is considered as misbehavior of the peer. In contrast, MUST in the recovery draft is not enforceable at all. HTTP is in a middle ground, HTTP/2 has many MAY detect rules for misbehaving peers. That might be due to the history of HTTP being a very lax protocol. I know that the differences are confusing, but I think they all have reasons, and am perfectly fine with keeping status-quo.
NAME Do we have any MUST in the (QUIC) spec for which it's forbidden (i.e. the peer MUST NOT) to enforce it? I don't think so.
In my opinion, instead of a piecemeal solution as suggested here, it would make more sense to add a general statement like the following:
That seems to be the core of the issue that people are suggesting we open.
NAME One example that I can immediately recall is the handling of Version Negotiation packet. An endpoint (including client) is forbidden to respond to a Version Negotiation packet with a Version Negotiation packet, but the server is forbidden to recognize Version Negotiation packets (i.e. we have "MUST discard"). Re writing down the principles, my +1 goes to opening a new issue.
In the interest of not getting tied up on this, I'm declaring consensus to merge the PR. I ask one of the folks in favour of taking a broad brush look, to open an issue to continue that discussion and track any proposals that get made to do so. Hello, In a couple of threads on Slack, Lars reminded me of an interesting MUST NOT in the transport draft: " A client MUST NOT reset the packet number for any packet number space " after processing a Retry packet; Section 17.2.3 contains more " information on this. This made me wonder whether the server should check that the client indeed did not reset the packet number. This is possible to do by including the packet number into the Retry token and then comparing this value with the number of the packet that carries the token back. I could not find such SHOULD in the draft. Should it be included? E.g. "The server SHOULD abort the connection if it detects that packet numbers were reset upon Retry." Dmitri.

Discussion:
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 <del> protect different content. </del> <ins> protect different content.  A server MAY abort the connection if it detects that the client reset the packet number. </ins> A server acknowledges the use of a Retry packet for a connection using the retry_source_connection_id transport parameter; see