version the client offered is unacceptable.  This document describes a version negotiation mechanism that allows a client and server to select a mutually supported version.  Optionally, if the original and <del> negotiated version share a compatible Initial format, the negotiation can take place without incurring an extra round trip. </del>  Discussion of this work is encouraged to happen on the QUIC IETF mailing list quic@ietf.org [1] or on the GitHub repository which 1. <del> QUIC QUIC does not provide a complete version negotiation (VN) mechanism; the VN packet only allows the server to indicate that the version the client offered is unacceptable, but doesn't allow the client to safely make use of that information to create a new connection with a mutually supported version.  With proper safety mechanisms in place, the VN packet can be part of a mechanism to allow two QUIC implementations to negotiate between two totally disjoint versions of QUIC, at the cost of an extra round trip. However, it is beneficial to avoid that cost whenever possible, especially given that most incremental versions are broadly similar to the the previous version. </del>  This specification describes a simple version negotiation mechanism which optionally leverages similarities between versions and can contains the draft: https://github.com/quicwg/version-negotiation/ [4]. <del> 2. </del>  The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here.  3. <del> The mechanism defined in this document is straightforward: the client maintains a list of QUIC versions it supports, ordered by preference. Its Initial packet is sent using the version that the server is most likely to support (in the absence of other information, this will often be the oldest version the client supports); that Initial packet then lists all compatible versions (compatible-versions) that the client supports in the Compatible Version fields of its transport parameters (fig-client-tp).  Note that the client's compatible version list always contains its currently attempted version. If the server supports one of the client's compatible versions, it selects a version it supports from the client's compatible version list.  It then responds with that version in all of its future packets (except for Retry, as below). If the server does not support any of the client's compatible versions, it sends a Version Negotiation packet listing all the versions it supports. If the server leverages compatible versions and responds with a different version from the client's currently attempted version, it MUST NOT select a version not offered by the client.  The client MUST validate that the version in the server's packets is one of the compatible versions that it offered and that it matches the negotiated version in the server's transport parameters. If the server sends a Retry, it MUST use the same version that the client provided in its Initial.  Version negotiation takes place after the retry cycle is over. In order for negotiation to complete successfully, the client's Initial packet (and initial CRYPTO frames) MUST be interpretable by the server.  This implies that servers must retain the ability to process the Initial packet from older versions as long as they are reasonably popular.  This is not generally an issue in practice as long as the overall structure of the protocol remains similar. </del>  4. <del> This document registers a new transport parameter, "version_negotiation".  The contents of this transport parameter depend on whether the client or server is sending it, and are shown below: </del>  The content of each field is described below: <del> The version that the client is using in this Initial.  This field MUST be equal to the value of the Version field in the long header that carries this transport parameter. </del>  <del> If the client is sending this Initial in response to a Version Negotiation packet, this field contains the version that the client used in the previous Initial packet that triggered the </del>  version negotiation packet.  If the client did not receive a Version Negotiation packet, this field SHALL be all-zeroes. A variable-length integer specifying the number of Received Negotiation Version fields following it.  If the client is sending <del> this Initial in response to a Version Negotiation packet, the </del>  subsequent versions SHALL include all the versions from that Version Negotiation packet in order, even if they are not supported by the client (even if the versions are reserved).  If connection, this field SHALL be 0. A variable-length integer specifying the number of Compatible <del> Version fields following it.  The client lists all versions compatible with Currently Attempted Version in the subsequent Compatible Version fields, ordered by descending preference.  Note that the version in the Currently Attempted Version field MUST be included in the Compatible Version list to allow the client to communicate the currently attempted version's preference. </del>  The content of each field is described below: The version that the server chose to use for the connection.  This <del> field SHALL be equal to the value of the Version field in the long header that carries this transport parameter. </del>  A variable-length integer specifying the number of Supported Version fields following it.  The server encodes all versions it supports in the subsequent list, ordered by descending preference. Note that the version in the Negotiated Version field MUST be <del> included in the Supported Version list. </del>  Clients MAY include versions following the pattern "0x?a?a?a?a" in <del> their Compatible Version list, and the server in their Supported Version list.  Those versions are reserved to exercise version </del>  negotiation (see the Versions section of QUIC), and MUST be ignored <del> when parsing these fields.  On the other hand, the Received Negotiation Version list MUST be identical to the received Version </del>  Negotiation packet, so clients MUST NOT add or remove reserved version from that list. Clients MUST ignore any received Version Negotiation packets that contain the version that they initially attempted.  Once a client has reacted to a Version Negotiation packet, it MUST drop all subsequent <del> Version Negotiation packets. </del>  Servers MUST validate that the client's "Currently Attempted Version" <del> matches the version in the long header that carried the transport parameter.  Similarly, clients MUST validate that the server's "Negotiated Version" matches the long header version.  If an endpoint's validation fails, it MUST close the connection with an error of type VERSION_NEGOTIATION_ERROR. When a server parses the client's "version_negotiation" transport parameter, if the "Received Negotiation Version Count" is not zero, the server MUST validate that it could have sent the Version Negotation packet described by the client in response to an Initial of version "Previously Attempted Version".  In particular, the server MUST ensure that there are no versions that it supports that are absent from the Received Negotiation Versions, and that the ordering matches the server's preference.  If this validation fails, the server MUST close the connection with an error of type VERSION_NEGOTIATION_ERROR.  This mitigates an attacker's ability to </del>  forge Version Negotiation packets to force a version downgrade. If a server operator is progressively deploying a new QUIC version throughout its fleet, it MAY perform a two-step process where it first progressively adds support for the new version, but without <del> enforcing its presence in Received Negotiation Versions.  Once all </del>  servers have been upgraded, the second step is to start enforcing <del> that the new version is present in Received Negotiation Versions. </del>  This opens connections to version downgrades during the upgrade window, since those could be due to clients communicating with both upgraded and non-upgraded servers.  6. <del> The server's Supported Version list allows it to communicate the full list of versions it supports to the client.  In the case where </del>  clients initially attempt connections with the oldest version they support, this allows them to be notified of more recent versions the server supports.  If the client notices that the server supports a 7. <del> Two versions of QUIC A and B are said to be "compatible" if a version A Initial can be used to negotiate version B and vice versa.  The most common scenario is a sequence of versions 1, 2, 3, etc. in which all the Initial packets have the same basic structure but might include specific extensions (especially inside the crypto handshake) that are only meaningful in some subset of versions and are ignored in others.  Note that it is not possible to add new frame types in Initial packets because QUIC frames do not use a self-describing encoding, so unrecognized frame types cannot be parsed or ignored (see the Extension Frames section of QUIC). When a new version of QUIC is defined, it is assumed to not be compatible with any other version unless otherwise specified. Implementations MUST NOT assume compatibility between version unless explicitly specified. </del>  8. <del> The crypto handshake is already required to guarantee agreement on the supported parameters, so negotiation between compatible versions will have the security of the weakest common version. </del>  The requirement that versions not be assumed compatible mitigates the possibility of cross-protocol attacks, but more analysis is still needed here. <del> The presence of the Attempted Version and Negotiated Version fields mitigates an attacker's ability to forge packets by altering the version. </del>  <del> 9. </del>  <del> If this document is approved, IANA shall assign the identifier 0x73DB for the "version_negotiation" transport parameter from the QUIC Transport Parameter Registry and the identifier 0x53F8 for "VERSION_NEGOTIATION_ERROR" from the QUIC Transport Error Codes registry. </del>  <del> 10.  References </del>  <del> 10.1.  URIs </del>  [1] mailto:quic@ietf.org

This PR rewrites most of the draft to make it more aligned with the fact that it's now a stand-alone document that is not directly tied to QUICv1.
NAME defining compatible is currently left to future documents. For example QUICv2 could define its compatibility with QUICv1, or it could decide to skip that and rely on a future document. We could theoretically use draft29 vs QUICv1 as an experiment, but I know we wouldn't implement it because that one is really tricky due to the transport parameter codepoint.
Do we explicitly state this? Should we (can we?) require future documents/versions to respect this process? Even if they're incompatible with other versions, should they reference and require usage of this extension? Would it even still be an extension or directly included? I do think it would be a good test case. It might be practically be useful as well, as v1 and -29 start being supported in parallel in the coming months. Perhaps a separate issue should be opened to track this though.
We explicitly say that versions are incompatible unless a future document says otherwise. We shouldn't require anything. This is just an extension, and we may replace it with a different extension some day. A separate issue sounds best, could you file it please?
Ok. Sounds good. opened.
Not necessarily. We could say that for version B, the long header could have either A or B. This basically requires reinterpreting LongHeader.Version as "format" or "minimum version to interpret" or something, but it's not inherently a problem.
Merged based on offline conversation with NAME
Looking at , how should the server respond if the Client Handshake Version Negotiation Information is malformed? For example, the QUIC version in the long header is different from the Current Attempted Version field in the transport parameter? Should the server continue with the Original Version in the long header (assuming it is supported), or attempt incompatible version negotiation? (related to )
If the Client Handshake Version Negotiation Information is malformed (too short to be parsed or something like that) or if it fails to validate (e.g. Current Attempted Version field differs from the long header's version) then the server MUST close the connection with VERSIONNEGOTIATIONERROR. I've added text to 's "Version Downgrade Prevention" section to make that explicit.
According to the principles we used in QUIC v1, I would've expected a TRANSPORTPARAMETERERROR if parsing fails and a VERSIONNEGOTIATIONERROR if validation fails.
My confusion comes from the line in Compatible Version Negotiation: It seems ambiguous whether this is referring only to the attempt to convert the received flight to a newer version, or whether it also includes the potential failures in parsing. NAME brings up a good point too.
I see. I've clarified that sentence to explicitly rule out parsing and validation failures. I also changed the error code.
Looks good to me! Thanks
Assume that both endpoints support compatible versions and , but the client prefers version over version , while the server prefers version over version . When the server receives a connection attempt using version , it will detect that the client also supports , and convert it to version . The connection therefore ends up with version . Is that what we want? One could argue that the version in use should be controlled by the client, not by the server. This could be easily achieved by only allowing the server to switch to version if the client expressed a preference for over .
Related: NAME comment on URL
Yes, I believe that having the server choose is the right answer. We already have experience with it in TLS where it works reasonably well. It's also hard to enforce the client chooses rule when the client speaks first and offers all its supported versions. The server can just pretend it only supports B and just speaks the A Initial format.
I agree with NAME letting the server choose whether to follow the client's preference or not seems simplest.
Let's assume both client and server support compatible versions and , and the server prefers over . The client now initiates a connection using version , for some reason though the conversion from to fails. As the draft is written now, the only way for the server to proceed here is to perform Incomptabile Version Negotiation, i.e. send a VN packet. While this rule makes the process deterministic (and might allow the client to verify the result of the version negotiation, see the open question in URL), it also costs a round trip. When the differences between and are small, a server might prefer to not bother with upgrading the version, and just establish a connection using . Should we allow that?
I don't understand the scenario you have in mind here. How would the conversion from X to Y fail? This seems like it shouldnt' happen and should just cause connection failure.
NAME Looking at , it says:
OK, well I haven't reviewed but that sounds wrong to me.
You're right NAME that was an oversight. In , I've replaced: with:
The primary versions available to us to test this new version negotiation process are draft-29 and upcoming v1 versions. It probably makes sense to define the compatibility rules for these so that we can test everything out.
My main concern is that these two versions are very hard to implement compatibility for, because of the TLS codepoint change. Because of that, I don't think Google would implement this. But if we have multiple implementors interested, then we should do it.
I agree it would be tricky. I'd have to double check our logic in MsQuic, but I think it would be easy enough on the server side, but definitely trickier on the client side.
Since RFC 9000 has been published, I think interest in draft-29 is declining. NAME how do you feel about closing this issue?
Sure, good ahead.
Related to URL Should the version negotiation transport parameter allow for (optionally) encoding transport parameters specific to each compatible version? This might improve the range of compatible versions in the future. For instance, if version 2 changed the meaning of one of the existing transport parameters such that it wasn't directly compatible with version 1's TPs, this would allow the versions themselves to still be considered compatible, because the client could just offer the v2 TPs along with the v1.
NAME I'm not sure I understand the problem that this solves. If there is a v2-only TP, the client can send it in v1 and rely on the fact that v1 servers ignore unknown TPs. Could you write up a specific example where this would be useful?
Any kind of breaking change to an existing transport parameter, where the new encoding format in v2 is incompatible with v1. For instance, say was changed to require two numbers, a v4 and v6 specific value. I know this is a contrived example, but if something like it happens in the future, the client cannot send a value for 'maxudppayloadsize` that generically works for both v1 and v2. Without this feature, v1 and v2 would have to be considered incompatible. Another example, would be a transport parameter that is explicitly disallowed to be sent by the client in v1, but then is allowed (required?) in v2. If it's not required, the client just wouldn't be able to take advantage of the feature tied to the TP, but if it goes from disallowed to required, then the versions become incompatible. For example .
This doesn't sound like the right solution. If we want to change the format of in v2, we can give it a new TP ID. That allows the two versions to be compatible. Similarly, if we want to switch a TP from disallowed to required, we can give it a new ID. Do you have any use-cases that can't be solved by changing the Transport Parameter IDs when changing a TP's meaning?
What about if any transport parameter goes from required in v1 to disallowed in v2?
As I mentioned in URL , in that scenario we'd give this TP a new ID in v2.
Yeah, I guess. You just never have a breaking change by constantly appending new transport parameters and ignoring old/deprecated ones. Then the client just sends the superset of all parameters for all versions. It just means you can never actually change the meaning of a transport parameter for with a particular numeric value. If folks are fine with that restriction for transport parameters, then I'm fine closing this issue. One thought though then, when connecting using version negotiation, the client might use the lowest compatible version number for the packet, but it should supply the highest compatible (superset) version of the transport parameters. Does the spec call this out already?
However, as noted in URL, we have created such a breaking change between draft versions and version 1. The TLS codepoint used for the transport parameters changed between versions. This needs to be addressed in the definition of being able to craft an appropriate Initial in the new version, because there are multiple paths one could choose: Require the client to include both TP extensions, so the server can respond only to the one used by the QUIC version it selects. This pair of versions might be either compatible or incompatible, depending on whether the client includes both TPs in its ClientHello. This solution isn't desirable long-term, because we don't want QUIC clients squatting on private-use space indefinitely. Require the server to modify the client's TLS message in well-defined ways as part of constructing an up-level Initial. If the client doesn't have a way to make those changes to an in-progress handshake and/or restart a handshake by inputting a ClientHello, it will fail. PSK binders could complicate this further; this would likely mean it's not possible to do some compatible version changes while doing 0-RTT. So while the contents of the TP shouldn't be breaking between versions, we have an existence proof of breaking changes in the means of carrying the transport parameters.
Consider the case of two difference QUIC versions which are roughly identical in terms of the crypto/handshake/packet layer. But imagine that these two versions, say, renumber streams or some other change which makes 0-RTT data look different. I would assume that such versions would not be "compatible" for the purposes of section 7? Or alternatively, they could be considered compatible, but the server MUST not process 0-RTT packets, and the client must "unwind" the 0-RTT state (un-open streams, etc)? (Issue copied from , by NAME on 2019-11-04)
from NAME on 2019-11-04: I agree, we should add text to discuss this, perhaps in a section of recommendations for writers of new versions. When deciding whether two versions are compatible, the cost of rewriting 0-RTT data from one version to the next should be taken into account.
from NAME on 2019-11-19: Interested in seeing where this goes.
It definitely should discuss 0-RTT. I suspect the same language could hold, in that for certain pairs of versions it might be possible to construct up-level 0-RTT packets from down-level 0-RTT packets and pretend that's what you received. However, I suspect that won't be true for all compatible version pairs; tolerating that would mean that you have versions which are Initial-compatible and versions which are I/0-compatible, and you'd have to define behavior between them. It might be simpler to say that if the server wants to change versions, it MUST reject Early Data.
While I recognize that it is an explicit design choice of this extension to move all the downgrade detection to the server, it seems unfortunate to prevent the client from detecting the downgrade and instead relying on the server to do so. (I could imagine that some server implementations are lazy/broken and might not perform this detection)? Alternatively, if the server delivered to the client a set of lists of versions that the server (or the server's peers) might have sent in VN packets, then the client could compare the actual VN packet it received with the elements in the set and detect the case where none of them match. Commonly the server would send one such list, but if it were participating in a staggered rollout, it could send both the "old" and "new" lists? (Issue copied from , by NAME on 2019-11-04)
The contains all versions supported by the server, so the client could easily perform that verification, taking care to: remove the current version from remove any greasing version both from and from the versions in the VN packet ignoring the ordering of versions (dependent on the outcome of URL) Open question: Should the client also check that the server actually performed a version upgrade, if there's a version supported by both endpoints with a higher preference than the currently selected version?
NAME what is "Server Handshake Version Information"? I don't see that string in this draft. Is it in a different doc?
Sorry, I was looking at , as I assumed that’s the direction this draft is moving in.
Oh, I see. Yes, I agree that fixes this issue.
Comment from NAME on 2019-11-04:
Comment from NAME on 2019-11-06 :
If there is a definition for a mapping from vM to vN, can a client assume that the server will understand that mapping? Or does the client have to accept an incompatible version negotiation from servers? It would be nice if compatible mappings could be developed separately from QUIC versions, which suggests that the server can decide whether to apply the mapping. (Issue copied from , by NAME on 2019-11-12)
Copy of the conversation from the original issue: NAME >Can you say more about "mapping"? I don't believe that appears in this document, so I'd like to make sure we are on the same page. NAME >Sorry, I was using my own model. If you can use an initial flight from A to negotiate B (i.e., there is a mapping from that flight in A to the equivalent in B), then can the client expect that the server will understand that the two are compatible? NAME NAME NAME NAME NAME NAME NAME bunch of unnecessary confusion
I believe clients always have to accept the incompatible-version path. If the client offers A and knows that a mapping from A to B exists, that doesn't mean the server possesses that mapping. From the server's point of view, if it only implements B, it's receiving a packet offering an unknown version. It will send a VN packet, and expect the client to retry with B. The only way around that is if the client also knows that the spec for B requires supporting a mapping from A. I don't think we can assume that's the general case, though it might happen in some cases.
In the common scenario where one has not deployed a new version to 100% of all potential endpoints all the time, the probability of a successful upgrade is p^n, where: p = probability of landing on server with a proposed version being accepted n = number of "nonsticky" round trips If the routing of the packets for an attempted session initiation/connection are routed to the same place, it becomes far more predictable. All of the above is a long way of saying that compatible is not the same as in-line / routed to the same place. Providing an in-line upgrade capability allows a reasonably understandable site deployment to do an upgrade without surprising weirdness. Without this, even with "compatible" upgrades, there will be some "fun" deployment issues in practice. (Issue copied from , by NAME on 2019-11-19)
Generally, looks to be a good rewrite. Thanks! Beyond the one small nit, I have a question about what document has the responsibility to describe/define what versions are compatible and how. This document by definition is an extension to the QUIC spec. The same may continue to be true for QUIC v2, right? If neither spec directly acknowledge this document, it seems they wouldn't specify how compatibility may work. If so, is it the responsibility of this extension to be updated with all known compatibility rules? Additionally, would/could we use -29 and v1 as test candidates for this process? Should we define the compatibility rules in this doc? Some notes: Section 3: “Version negotiation takes place after the retry cycle is over.” This is only possible for compatible versions; if the server does not support the version the client attempted, it obviously cannot send a Retry packet in that version, because Retry packets are version-specific. Section 3: “Servers must retain the ability to process the Initial packet from older versions….” No, it means that if the server wants to avoid a VN packet, it needs to be able to process the Initial packet from the version the client tried. Section 4: Rather than putting a count-prefixed list of versions, perhaps consider just embedding the VN packet payload? It’s equivalent, but easier to explain. Section 7: Clearly it is possible to possible to add new frame types to Initial packets in a future version, I think what you mean to say is that this is a change that would break compatibility between versions. As a general statement on the document, you assume throughout that all versions have packet types, contain packet types called Initial and Retry, and that Initial packets contain frames. The odds of those things being true across QUIC versions is likely high, but they’re not invariants, so you can’t assume them here. You need to state general principles, and then use concepts from QUICv1 as examples of the principle. For example, rather than discussing version compatibility in terms of Initial packets, you might want to say that versions A and B are “compatible” if the first flight of packets sent by the client in version A carries enough information for the server to generate the corresponding flight in version B, the server speaks version B, and is able to parse at least the first flight of version A. Also not discussed is the case where the server speaks version(s) which are compatible with what the client offered, but doesn’t speak the version the client offered, even enough to generate the response. With the right definition of “compatible,” this just falls into the “incompatible” path and works for the server, but you need to call out the fact that the client shouldn’t consider it an error if the server uses the incompatible path between versions that the client thinks are compatible. From: QUIC On Behalf Of David Schinazi Sent: Monday, November 4, 2019 3:30 PM To: QUIC Subject: QUIC Version Negotiation Extension Hi everyone, From the recent discussion on multiple PRs, it appears that there might be a need for downgrade-safe QUIC version negotiation, earlier than we expected. EKR and I updated our extension to hopefully suit these needs: URL Comments welcome here or on the GitHub (link in draft). Thanks, David
Hi David, I think that this is broadly the right mechanism. It would be good to validate it more thoroughly. The model and framing could use a little work. I struggled a little with the framing here because the split between incompatible and compatible versions is very important, but also unclear. The definition of "compatible" is left for Section 7, but it seems like it should be right up front. The framing I would choose puts the model up front. The model that you have have two layers that are applied progressively: incompatible version negotiation, where the server sends a Version Negotiation packet in response to a version it does not understand. compatible version negotiation, where the server can generate interpret a version X Initial packet and continue with version Y. Regarding the model, the definition of "compatible" needs work. I observe that you only need a mapping from "Initial"-equivalent packets in X to the same in Y - and maybe the ability to generate a Retry in version X (more below) - in order for this to work. That's where there is a clear functional mapping from a version X packets that initiate the connection to something that fills the same purpose in version Y. But the definition you have for "compatible" implies that the mapping is bijective, which I don't think is necessary. As the draft says, version Y might define (and allow) new frame types in its Initial-equivalent packet(s), but as long as those are either optional or can be synthesized from X, that's OK. It isn't necessary that every Y have a functional representation in X. We might not want to define a way to negotiate an older version from a newer one (or at least not for every case). The ability to generate a Retry stretches this definition a little. Can you explain why you can't generate a version Y Retry? I have an inkling, but it's not fully formed. It complicates the model more than I'd like to have it this way around.

version the client offered is unacceptable.  This document describes a version negotiation mechanism that allows a client and server to select a mutually supported version.  Optionally, if the original and  <ins> negotiated version share a compatible first flight format, the negotiation can take place without incurring an extra round trip. </ins> Discussion of this work is encouraged to happen on the QUIC IETF mailing list quic@ietf.org [1] or on the GitHub repository which 1.  <ins> The version-invariant properties of QUIC INV define a version negotiation (VN) packet but do not specify how an endpoint reacts when it receives one.  QUIC version 1 QUIC allows the server to use a VN packet to indicate that the version the client offered is unacceptable, but doesn't allow the client to safely make use of that information to create a new connection with a mutually supported version.  With proper safety mechanisms in place, the VN packet can be part of a mechanism to allow two QUIC implementations to negotiate between two totally disjoint versions of QUIC, at the cost of an extra round trip.  However, it is beneficial to avoid that cost whenever possible, especially given that most incremental versions are broadly similar to the the previous version. </ins> This specification describes a simple version negotiation mechanism which optionally leverages similarities between versions and can contains the draft: https://github.com/quicwg/version-negotiation/ [4].  <ins> 1.1. </ins> The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. <ins> 2. If A and B are two distinct versions of QUIC, A is said to be "compatible" with B if it is possible to take a first flight of packets from version A and convert it into a first flight of packets from version B.  As an example, if versions A and B are absolutely equal in their wire image and behavior during the handshake but differ after the handshake, then A is compatible with B and B is compatible with A. Version compatibility is not bijective: it is possible for version A to be compatible with version B and for B not to be compatible with A.  This could happen for example if version B is a strict superset of version A. Note that version compatibility does not mean that every single possible instance of a first flight will succeed in conversion to the other version.  A first flight using version A is said to be "compatible" with version B if two conditions are met: first that version A is compatible with version B, and second that the conversion of this first flight to version B is well-defined.  For example, if version B is equal to A in all aspects except it introduced a new frame in its first flight that version A cannot parse or even ignore, then B could still be compatible with A as conversions would succeed for connections where that frame is not used.  In this example, first flights using version B that carry this new frame would not be compatible with version A. When a new version of QUIC is defined, it is assumed to not be compatible with any other version unless otherwise specified. Similarly, no other version is compatible with the new version unless otherwise specified.  Implementations MUST NOT assume compatibility between versions unless explicitly specified. Note that both endpoints might disagree on whether two versions are compatible or not.  For example, two versions could have been defined concurrently and then specified as compatible in a third document much later - in that scenario one endpoint might be aware of the compatibility document while the other may not. </ins> 3.  <ins> This document specifies two means of performing version negotiation: one "incompatible" which requires a round trip and is applicable to all versions, and one "compatible" that allows saving the round trip but only applies when the versions are compatible. The client initiates a QUIC connection by sending a first flight of QUIC packets with a long header to the server INV.  We'll refer to the version of those packets as the "original version".  The client's first flight includes handshake version information (see hs-vers- info) which will be used to optionally enable compatible version negotation (see compat-vn), and to prevent version downgrade attacks (see downgrade). Upon receiving this first flight, the server verifies whether it knows how to parse first flights from the original version.  If it does not, then it starts incompatible version negotiation, see incompat-vn.  If the server can parse the first flight, it can either establish the connection using the original version, or it MAY attempt compatible version negotiation, see compat-vn. Note that it is possible for a server to have the ability to parse the first flight of a given version without fully supporting it, in the sense that it implements enough of the version's specification to parse first flight packets but not enough to fully establish a connection using that version. 3.1. QUIC connections are shared state between a client and a server INV. The compatible version negotiation mechanism defined in this document (see compat-vn) operates inside of a QUIC connection; i.e., the packets with the original version are part of the same connection as the packets with the negotiated version.  On the other hand, the incompatible version negotiation mechanism, which leverages QUIC Version Negotiation packets (see incompat-vn) conceptually operates across two QUIC connections: one before the Version Negotiation packet, and a distinct connection after. 3.2. The server starts incompatible version negotiation by sending a VN packet, listing all the versions that it does support. Upon receiving the VN packet, the client will search for a version it supports in the list provided by the server.  If it doesn't find one, it aborts the connection attempt.  Otherwise, it selects a mutually supported version and sends a new first flight with that version - we refer to this version as the "negotiated version". The new first flight will allow the endpoints to establish a connection using the negotiated version.  The handshake of the negotiated version will exchange handshake version information (see hs-vers-info) required to ensure that VN was genuine, i.e. that no attacker injected packets in order to influence the VN process, see downgrade. 3.3. When the server can parse the client's first flight using the original version, it can extract the client's handshake version information (see hs-vers-info).  This contains the list of versions that the client thinks its first flight is compatible with. If the server supports one of the client's compatible versions, and the server also believes that the original version is compatible with this version, then the server converts the client's first flight to that version and replies to the client as if it had received the converted first flight.  The version used by the server in its reply is refered to as the "negotiated version".  The server MUST NOT reply with a version that is not present in the client's compatible versions, unless it is the original version. If the server does not find a compatible version, it will use the original version if it supports it, and if it doesn't then the server will perform incompatible version negotiation instead, see incompat- vn. For the duration of the compatible version negotiation process, clients MUST use the same 5-tuple (source and destination IP addresses and UDP port numbers).  During that time, clients MUST also use the same Destination Connection ID, except if the server explicitly instructs the client to use a different Destination Connection ID (for example, a QUIC version 1 server can accomplish this by sending an INITIAL packet with a Source Connection ID that differed from the client's Destination Connection ID).  This allows load balancers to ensure that packets for a given connection are routed to the same server. </ins> 4.  <ins> During the handshake, endpoints will exchange handshake version information, which is a blob of data that is defined below.  In QUIC version 1, the handshake version information is transmitted using a new transport parameter, "version_negotiation".  The contents of handshake version information depend on whether the client or server is sending it, and are shown below (using the notation from the "Notational Conventions" section of QUIC): </ins> The content of each field is described below:  <ins> The version that the client is attempting to use.  This field MUST be equal to the value of the Version field in the long header that carries this data. </ins>  <ins> If the client is sending this first flight in response to a Version Negotiation packet, this field contains the version that the client used in the previous first flight that triggered the </ins> version negotiation packet.  If the client did not receive a Version Negotiation packet, this field SHALL be all-zeroes. A variable-length integer specifying the number of Received Negotiation Version fields following it.  If the client is sending  <ins> this first flight in response to a Version Negotiation packet, the </ins> subsequent versions SHALL include all the versions from that Version Negotiation packet in order, even if they are not supported by the client (even if the versions are reserved).  If connection, this field SHALL be 0. A variable-length integer specifying the number of Compatible  <ins> Version fields following it.  The client lists all versions that this first flight is compatible with in the subsequent Compatible Version fields, ordered by descending preference.  Note that the version in the Currently Attempted Version field MUST be included in the Compatible Version list to allow the client to communicate the currently attempted version's preference.  Note that this preference is only advisory, servers MAY choose to use their own preference instead. </ins> The content of each field is described below: The version that the server chose to use for the connection.  This  <ins> field MUST be equal to the value of the Version field in the long header that carries this data. </ins> A variable-length integer specifying the number of Supported Version fields following it.  The server encodes all versions it supports in the subsequent list, ordered by descending preference. Note that the version in the Negotiated Version field MUST be  <ins> included in the Supported Version list to allow the server to communicate the negotiated version's preference.  Note that this preference is only advisory, clients MAY choose to use their own preference instead. </ins> Clients MAY include versions following the pattern "0x?a?a?a?a" in  <ins> their "Compatible Version" list, and the server in their "Supported Version" list.  Those versions are reserved to exercise version </ins> negotiation (see the Versions section of QUIC), and MUST be ignored  <ins> when parsing these fields.  On the other hand, the "Received Negotiation Version" list MUST be identical to the received Version </ins> Negotiation packet, so clients MUST NOT add or remove reserved version from that list. Clients MUST ignore any received Version Negotiation packets that contain the version that they initially attempted.  Once a client has reacted to a Version Negotiation packet, it MUST drop all subsequent  <ins> Version Negotiation packets on that connection. </ins> Servers MUST validate that the client's "Currently Attempted Version"  <ins> matches the version in the long header that carried the handshake version information.  Similarly, clients MUST validate that the server's "Negotiated Version" matches the long header version.  If an endpoint's validation fails, it MUST close the connection.  If the connection was using QUIC version 1, it MUST be closed with a transport error of type "VERSION_NEGOTIATION_ERROR". When a server parses the client's handshake version information, if the "Received Negotiation Version Count" is not zero, the server MUST validate that it could have sent the Version Negotation packet described by the client in response to a first flight of version "Previously Attempted Version".  In particular, the server MUST ensure that there are no versions that it supports that are absent from the Received Negotiation Versions, and that the ordering matches the server's preference.  If this validation fails, the server MUST close the connection.  If the connection was using QUIC version 1, it MUST be closed with a transport error of type "VERSION_NEGOTIATION_ERROR".  This mitigates an attacker's ability to </ins> forge Version Negotiation packets to force a version downgrade. If a server operator is progressively deploying a new QUIC version throughout its fleet, it MAY perform a two-step process where it first progressively adds support for the new version, but without  <ins> enforcing its presence in "Received Negotiation Versions".  Once all </ins> servers have been upgraded, the second step is to start enforcing  <ins> that the new version is present in "Received Negotiation Versions". </ins> This opens connections to version downgrades during the upgrade window, since those could be due to clients communicating with both upgraded and non-upgraded servers. <ins> If an endpoint receives its peer's Handshake Version Information and fails to parse it (for example, if it is too short), then the endpoint MUST close the connection.  If the connection was using QUIC version 1, it MUST be closed with a transport error of type "TRANSPORT_PARAMETER_ERROR". </ins> 6.  <ins> The server's "Supported Version" list allows it to communicate the full list of versions it supports to the client.  In the case where </ins> clients initially attempt connections with the oldest version they support, this allows them to be notified of more recent versions the server supports.  If the client notices that the server supports a 7.  <ins> The client's first flight SHOULD be sent using the version that the server is most likely to support (in the absence of other information, this will often be the oldest version the client supports). </ins> 8.  <ins> QUIC version 1 features retry packets, which the server can send to validate the client's IP address before parsing the client's first flight.  This impacts compatible version negotiation because a server who wishes to send a retry packet before parsing the client's first flight won't have parsed the client's handshake version information yet.  If a future document wishes to define compatibility between two versions that support retry, that document MUST specify how version negotiation (both compatible and incompatible) interacts with retry during a handshake that requires both.  For example, that could be accomplished by having the server send a retry packet first and validating the client's IP address before starting version negotiation and deciding whether to use compatible version negotiation on that connection (in that scenario the retry packet would be sent using the original version). 9. QUIC version 1 allows sending data from the client to the server during the handshake, by using 0-RTT packets.  If a future document wishes to define compatibility between two versions that support 0-RTT, that document MUST address the scenario where there are 0-RTT packets in the client's first flight.  For example, this could be accomplished by defining which transformations are applied to 0-RTT packets.  Alternatively, that document could specify that compatible version negotiation causes 0-RTT data to be rejected by the server. 10. In order to facilitate the deployment of future versions of QUIC, designers of future versions SHOULD attempt to design their new version such that commonly deployed versions are compatible with it. For example, a successor to QUIC version 1 may wish to design its transport parameters in a way that does not preclude compatibility. Additionally, frames in QUIC version 1 do not use a self-describing encoding, so unrecognized frame types cannot be parsed or ignored (see the Extension Frames section of QUIC); this means that new versions that wish to be very similar to QUIC version 1 and compatible with it should avoid introducing new frames in initial packets. 11. The security of this version negotiation mechanism relies on the authenticity of the handshake version information exchanged during the handshake.  In QUIC version 1, transport parameters are authenticated ensuring the security of this mechanism.  Negotiation between compatible versions will have the security of the weakest common version. </ins> The requirement that versions not be assumed compatible mitigates the possibility of cross-protocol attacks, but more analysis is still needed here.  <ins> The presence of the "Attempted Version" and "Negotiated Version" fields mitigates an attacker's ability to forge packets by altering the version. </ins>  <ins> 12. 12.1. If this document is approved, IANA shall assign the following entry in the QUIC Transport Parameter Registry: 12.2. </ins>  <ins> If this document is approved, IANA shall assign the following entry in the QUIC Transport Error Codes Registry: </ins>  <ins> 13.  References </ins>  <ins> 13.1.  URIs </ins> [1] mailto:quic@ietf.org


1. <del> The version-invariant properties of QUIC INV define a Version Negotiation packet but do not specify how an endpoint reacts when it receives one.  QUIC version 1 QUIC allows the server to use a Version Negotiation packet to indicate that the version the client chose is unacceptable, but doesn't allow the client to safely make use of that information to create a new connection with a mutually supported version. </del>  With proper safety mechanisms in place, the Version Negotiation packet can be part of a mechanism to allow two QUIC implementations The client initiates a QUIC connection by choosing an initial version and sending a first flight of QUIC packets with a long header to the <del> server INV.  The client's first flight includes Version Information (see vers-info) which will be used to optionally enable compatible version negotation (see compat-vn), and to prevent version downgrade attacks (see downgrade). </del>  Upon receiving this first flight, the server verifies whether it knows how to parse first flights from the original version.  If it Clients will ignore a Version Negotiation packet if it contains the original version attempted by the client.  The client also ignores a Version Negotiation packet that contains incorrect connection ID <del> fields; see INV. </del>  Upon receiving the Version Negotiation packet, the client will search for a version it supports in the list provided by the server.  If it 2.4. <del> QUIC connections are shared state between a client and a server INV. The compatible version negotiation mechanism defined in this document (see compat-vn) is performed as part of a single QUIC connection; that is, the packets with the client's chosen version are part of the same connection as the packets with the negotiated version. </del>  In comparison, the incompatible version negotiation mechanism, which leverages QUIC Version Negotiation packets (see incompat-vn)

editorial nit: for consitency with RFC 9000, consider changing you reference name from [INV] -> [QUIC-INVARIANTS]

1.  <ins> The version-invariant properties of QUIC QUIC-INVARIANTS define a Version Negotiation packet but do not specify how an endpoint reacts when it receives one.  QUIC version 1 QUIC allows the server to use a Version Negotiation packet to indicate that the version the client chose is unacceptable, but doesn't allow the client to safely make use of that information to create a new connection with a mutually supported version. </ins> With proper safety mechanisms in place, the Version Negotiation packet can be part of a mechanism to allow two QUIC implementations The client initiates a QUIC connection by choosing an initial version and sending a first flight of QUIC packets with a long header to the  <ins> server QUIC-INVARIANTS.  The client's first flight includes Version Information (see vers-info) which will be used to optionally enable compatible version negotation (see compat-vn), and to prevent version downgrade attacks (see downgrade). </ins> Upon receiving this first flight, the server verifies whether it knows how to parse first flights from the original version.  If it Clients will ignore a Version Negotiation packet if it contains the original version attempted by the client.  The client also ignores a Version Negotiation packet that contains incorrect connection ID  <ins> fields; see QUIC-INVARIANTS. </ins> Upon receiving the Version Negotiation packet, the client will search for a version it supports in the list provided by the server.  If it 2.4.  <ins> QUIC connections are shared state between a client and a server QUIC- INVARIANTS.  The compatible version negotiation mechanism defined in this document (see compat-vn) is performed as part of a single QUIC connection; that is, the packets with the client's chosen version are part of the same connection as the packets with the negotiated version. </ins> In comparison, the incompatible version negotiation mechanism, which leverages QUIC Version Negotiation packets (see incompat-vn)


all versions, and one "compatible" that allows saving the round trip but only applies when the versions are compatible. <del> The client initiates a QUIC connection by choosing an initial version and sending a first flight of QUIC packets with a long header to the server QUIC-INVARIANTS.  The client's first flight includes Version Information (see vers-info) which will be used to optionally enable compatible version negotiation (see compat-vn), and to prevent </del>  version downgrade attacks (see downgrade). Upon receiving this first flight, the server verifies whether it to be compatible with version B and for B not to be compatible with A.  This could happen for example if version B is a strict superset of version A: if version A includes the concept of streams and STREAM <del> frames, and version B includes the concepts of streams and tubes along with STREAM and TUBE frames, then A would be compatible with B but B would not be compatible with A. </del>  Note that version compatibility does not mean that every single possible instance of a first flight will succeed in conversion to the

Instead of creating separate issues for each minor editorial comments I will put them all in this issue - I am not a fan of having normative language in the definitions. I feel those normative languages are out of context and hard to reason. It is the case for MSL definition. I would suggest that besides definition, we have some description where MSL is used and put the recommended value there. What is the difference between the initial version and original version ? if there is none why do we need to use two different call sign for the same thing? What is Tubes? we need to explain it. otherwise use other example.
I personally disagree. Mentioning the recommended value when defining the term makes it easier to understand and implement. Agreed, there was only one mention of "initial version" so I replaced that with original in It's a hypothetical example. That doesn't make it unhelpful.
:-) hmm, the example makes little sense if one does not understand the terms used in the example. If "Tube" is a hypothetical term here, then let's just mention that.
There was no reasoning, this was pulled out of a hat just like the original MSL from RFC 793. Can you send us a PR describing the reasoning you'd like to see added? Fair enough, I've added the word "hypothetical" to PR

all versions, and one "compatible" that allows saving the round trip but only applies when the versions are compatible.  <ins> The client initiates a QUIC connection by choosing an original version and sending a first flight of QUIC packets with a long header to the server QUIC-INVARIANTS.  The client's first flight includes Version Information (see vers-info) which will be used to optionally enable compatible version negotiation (see compat-vn), and to prevent </ins> version downgrade attacks (see downgrade). Upon receiving this first flight, the server verifies whether it to be compatible with version B and for B not to be compatible with A.  This could happen for example if version B is a strict superset of version A: if version A includes the concept of streams and STREAM  <ins> frames, and version B includes the concept of streams and the hypothetical concept of tubes along with STREAM and TUBE frames, then A would be compatible with B but B would not be compatible with A. </ins> Note that version compatibility does not mean that every single possible instance of a first flight will succeed in conversion to the


defined in QUIC) in Supported Version fields. Clients will ignore a Version Negotiation packet if it contains the <del> original version attempted by the client.  The client also ignores a Version Negotiation packet that contains incorrect connection ID fields; see QUIC-INVARIANTS. </del>  Upon receiving the Version Negotiation packet, the client will search for a version it supports in the list provided by the server.  If it

URL here, it feel lacking normative language. The current text gives feel like there are other options the client can do and these are examples. if that is true what are those other options? if the client behave differently than described here as there is no normative language will that not cause interoperability issues?
The normative language already exists in . That said, the QUIC-VN draft is written in terms of QUIC invariants so we should tweak this.
we should or we should not?
We should
takes care of this

defined in QUIC) in Supported Version fields. Clients will ignore a Version Negotiation packet if it contains the  <ins> original version attempted by the client; see downgrade.  The client also ignores a Version Negotiation packet that contains incorrect connection ID fields; see QUIC-INVARIANTS. </ins> Upon receiving the Version Negotiation packet, the client will search for a version it supports in the list provided by the server.  If it


compatible versions SHOULD use the same mechanism. Note that, after the first flight is converted to the negotiated <del> version, the handshake completes in the negotiated version.  The entire handshake (including the converted first flight) needs to conform to the rules of the negotiated version.  For instance, if the negotiated version requires that the 5-tuple remain stable for the entire handshake (as QUIC version 1 does), then this applies to the entire handshake, including the first flight. </del>  Note also that the client can disable compatible version negotiation by only including the Chosen Version in the Other Versions field of

thanks for the fix.
URL here it is not clear to me if we are talking about first flight or converted first flight. I am assuming the negotiated version is in the converted first flight. May be we can be more clear here.
In this particular case, it probably doesn't matter. I don't know if it would be possible to convert a flight so that it had a different address tuple. I guess maybe you could, so I would say that this applies to the converted flight. BTW, NAME I really appreciate the quoting of text, but when you quote the text, you can select a range of lines, which might be useful here. Click the first/last line, then hold shift and click the last/first line.
Ok then probably best to clear about this int he spec. by the way, thanks for the tip NAME
I'm sorry, what is unclear here?
NAME the inclusion of "including the first flight" in the last sentence is confusing. it says - "For instance, if the negotiated version requires that the 5-tuple remain stable for the entire handshake (as QUIC version 1 does), then this applies to the entire handshake, including the first flight." Actually now I think the whole thing is very hard to parse. what does it mean? So, the negotiated version comes second and how does the first flight comply with that? should it not be the case that if the first flight requires the 5-tuple to be stable the negotiated version must comply with that? or does it mean when the client receives the negotiated version it should not change the 5-tuple? I think this is what we want but that is not clear from the example text or entire paragraph. as MT, mentioned it might be possible to convert the flight to different address tuple. If we don't want that then we need to change this text - " The entire handshake (including the converted first flight) needs to conform to the rules of the negotiated version" to include normative MUST.
All this says is "any requirements from the negotiated version also apply to the first flight". So if the negotiated version required the addresses to be stable, if it detects that they changed then it fails the handshake. That's just a way of saying "follow the spec of the versions in use". I don't think that's needed. I'm fine with a future document defining conversion such that it changes the address tuple. There's no need to prevent that. Perhaps you could propose text that you find clearer?
I would simple suggest to make it clear in this document and rewrite - Also I would suggest to change the example to reflect what you said here -
This is unclear, who does this normative requirement apply to? Who is "it" in "it fails the handshake"? At this point, it's sounding like this issue is editorial about how best to phrase one paragraph. I propose we don't block IESG review on this editorial work.
The draft says - >The entire handshake (including the converted first flight) needs to conform to the rules of the negotiated version. it seems like it is then unclear who does this "needs" apply to? Then we have problem. the "it" is I suppose same as in your previous reply :-) it is editorial yes, but I am assuming if what is written is not clear to me I think it won't clear to others as well. Hence, I think it is worth clarifying. And I don't think this will block any longer than the consensus call we have now on update tag if we work on to improve the text. May be we should just say do we lose big if we drop the "including the first flight" part?
How about this:
This is much better, specially clear about the converted first flight. Thanks

compatible versions SHOULD use the same mechanism. Note that, after the first flight is converted to the negotiated  <ins> version, the handshake completes in the negotiated version.  If the negotiated version has requirements that apply during the handshake, those requirements apply to the entire handshake, including the converted first flight.  In particular, if the negotiated version mandates that endpoints perform validations on handshake packets, endpoints MUST also perform such validations on the converted first flight.  For instance, if the negotiated version requires that the 5-tuple remain stable for the entire handshake (as QUIC version 1 does), then both endpoints need to validate the 5-tuple of all handshake packets, including the converted first flight. </ins> Note also that the client can disable compatible version negotiation by only including the Chosen Version in the Other Versions field of


select a mutually supported version.  Optionally, if the client's chosen version and the negotiated version share a compatible first flight format, the negotiation can take place without incurring an <del> extra round trip. </del>  1.

This PR just updates the tag. Which I think is not adequate. The abstract should clearly mention that it is updating 8999 and the respective sections should say what it is updating.
The whole document updates Section 6 of RFC 8999. I think it's sufficient to state that in a stand-alone sentence in the abstract and introduction.
As per the IETF tradition, I've modified the abstract to mention that this document updates RFC 8999. There is no requirement to update the introduction or the rest of the text.
Please merge and update the datatracker version.
I would like to have a discussion to determine whether this specification should update RFC9000 or not. This version negotiation draft adds new functionality on top of RFC9000 using the version negotiation packet from RFC8999. The update tag might be seen as useful to let other aware of the added mechanism for version negotiation, also because it actually changes how section 6 of RFC9000 deals with QUIC versions, which mentions potential future work regarding the negotiation. On the other hand, this new mechanism is not really a must to implement to make things works for RFC9000and both mechanism can co-exists, hence falls into QUIC extension categories. It seems all about how we want the future QUIC versions to get deployed. I have checked with WG chairs and authors that we didn't really discussed this in the working group. I think having a discussion now would be useful to know where the WG stands on this and have an response ready for potential questions (from reviews) along the path of publication.
Speaking in capacity as individual and chair: I still find the commentary on use of the Updates tags in URL compelling. If I dare to summarise, the Updates tag is used inconsistently across the IETF. Any use of it is ambiguous and open to interpretation. I'd encourage people to familiarise themselves with some of the background and wider discussion, in order to avoid playing all of it out here. Trying to document or describe how the QUIC WG treats use of Updates is probably a futile activity, since its unlikely to be found by the target audience. Adding an Updates tag risks confusing people just as much as it might help some people. Absent a strong reason to provide an Updates tag, I don't think we should. And I don't class subjective opinions as a strong reason on their own.
I largely agree with Lucas, but I think that the change in behaviour with respect to Version Negotiation is significant enough to warrant an Updates tag in this case. I generally subscribe to the view that Amends is the only useful application of Updates, but this clearly fits into that interpretation. (It is also an instance of Extends, but I don't care about that.) I can see how you might argue that this new document only applies to people implementing versions of QUIC other than version 1, but that seems too much like sophistry. On balance though, given the importance of this feature, I think that a strong pointer is useful in this case.
I do not care whether this has an Update tag or not, because it has no impact whatsoever on implementations. I'll follow the WG consensus on this.
yes, getting the WG consensus is the target here. May be the chairs (NAME NAME ) should explicitly ping the WG about it now.
I agree with Lucas and Martin. "RFC X updates RFC Y" has been used with a lot of different meanings, such as: RFC X defines version N+1 of the EXAMPLE protocol, whose version N is defined in RFC Y RFC X reflects IETF consensus to change some parts of the specification of the EXAMPLE protocol defined in RFC Y RFC X specifies extensions to the EXAMPLE protocol using the extension mechanisms defined in RFC Y In my mid, the first case should be noted as "obsoletes", as in RFC 8446 (TPS 1.3) obsoletes RFC 5246 (TLS 1.2). The second case is properly noted as "updates". The third case does neither update not obsolete. This is certainly the interpretation that the WG has used so far: neither RFC 9287, greasing the Q bit, nor RFC9221, datagram frames, are marked as updating RFC 9000. The compatible version negotiation should also not be stated as updating RFC 9000. In any case, if the compatible version negotiation updates something, it is not RFC 9000 but RFC 8999, the QUIC invariants, which defines the basic version negotiation.
Agreed with NAME that this doesn't sound like an update to RFC 9000. The only reference to QUICv1 () doesn't require any updates to implementations of RFC 9000, just handling for newer versions. I could see an argument for marking it as an Update to RFC 8999, but I'm ambivalent about that.
I vote yes for the update: we want implementors of RFC 9000 to be aware of this later doc, even if they don't strictly need to be, and it seems to be within the scope of existing uses.
chair hat off: I am coming around to the idea that this doc should not update RFC 9000 and might update RFC 8999 (specifically because of URL). Whether we do add an updates tag is borderline. Adding a tag doesn't hurt either this draft or 8999, the confusion risk I mentioned earlier does not seem high after hearing others views. It might improve discoverability but I'm skeptical of the efficacy discovery via tags in practice; a link with no context seems like a pretty lame hint. I'd rather us have more detailed and expressive ways to communicate with implementers the "why" and broader context about things that they should consider - for example, adding resources on URL and the interop runner that nudge people to "Do the best thing". An updates tag doesn't prevent that though, so all good. Finally, adding an updates tag here risks us having to ask the question every time. I'm encouraged by the discussion here that we can logically reason why something like Datagram extension doesn't while version negotiation does. In summary, as an individual, I'm seeing what appears to be ambivalence to RFC 8999 but no objections
QUIC WG chairs have to update 8999 but not 9000. I've written this up as PR .
Let's merge the PR and cut a new release for Zahed to progress Hello all, To summarize the outcome, while the usage of the "Updates" tag across the IETF is generally not very consistent, the chairs believe that there is consensus for adding the "Updates" tag for RFC 8999, but not for RFC 9000, as the implications and precedent-setting of the latter are not as clear. Best, Matt Joras On behalf of the QUIC WG Chairs Lucas Pardue wrote:

select a mutually supported version.  Optionally, if the client's chosen version and the negotiated version share a compatible first flight format, the negotiation can take place without incurring an  <ins> extra round trip.  This document updates RFC 8999. </ins> 1.


Version Negotiation packet to indicate that the version the client chose is unacceptable, but doesn't allow the client to safely make use of that information to create a new connection with a mutually <del> supported version. </del>  With proper safety mechanisms in place, the Version Negotiation packet can be part of a mechanism to allow two QUIC implementations

Add a short text in the introduction section to define how this document updates RFC 8999.
Thanks for taking the time, Christian! I appreciate it.
We have agreed to mark this document as updating RFC 8999. Fine, but this lacks a bit of discipline. We should have a statement inside the text (not just the abstract) explaining in which way RFC 8999 is updated.
Can someone propose text here? Based on our discussion in , there is no agreement inside the IETF on what "updates" means so I'm not sure what text would be helpful for readers.
NAME see PR

Version Negotiation packet to indicate that the version the client chose is unacceptable, but doesn't allow the client to safely make use of that information to create a new connection with a mutually  <ins> supported version.  This document updates QUIC-INVARIANTS by defining version negotiation mechanisms that leverage the Version Negotiation packet. </ins> With proper safety mechanisms in place, the Version Negotiation packet can be part of a mechanism to allow two QUIC implementations


4.  Clients MUST ignore any received Version Negotiation packets that contain the version that they initially attempted.  A client that makes a connection attempt based on information received from a

This was raised during the
With my comment. Reviewer: Qin Wu Review result: Has Issues I have reviewed this document as part of the Operational directorate's ongoing effort to review all IETF documents being processed by the IESG. These comments were written with the intent of improving the operational aspects of the IETF drafts. Comments that are not addressed in last call may be included in AD reviews during the IESG review. Document editors and WG chairs should treat these comments just like any other last call comments. This document describes a version negotiation mechanism that allows a client and server to select a mutually supported version. The mechanism can be further broke down into incompatible Version Negotiation and compatible Version Negotiation. I believe this document is on the right track and but worth further polished with the following editorial comments. Major Issues: No Minor Issues: 1. Section 4 introduce verson downgrade term [Qin]What the version downgrade is? I feel confused, does it mean when I currently use new version, I should not fall back to the old version? Can you explain how version downgrade is different from version incompatible? It will be great to give a definition of version downgrade in the first place or provide an example to explain it? 2. Section 9 said: " The requirement that versions not be assumed compatible mitigates the possibility of cross-protocol attacks, but more analysis is still needed here." [Qin] It looks this paragraph is incomplete, what else analysis should we provide to make this paragraph complete? 3. Section 10 [Qin]: I am not clear why not request permanent allocation of a codepoint in the 0-63 range directly in this document. In my understanding, provisional codepoint can be requested without any dependent document? e.g., Each vendor can request IANA for Vendor specific range. Secondly, if replacing provisional codepoint with permanent allocation, requires make bis for this document, I don't think it is reasonable. Nits: 1. Section 2 said: " For instance, if the client initiates a connection with version A and the server starts incompatible version negotiation and the client then initiates a new connection with .... " [Qin]Can the client starts incompatible version negotiation? if not, I think we should call this out, e.g., using RFC2119 language. 2. Section 2, last paragraph [Qin] This paragraph is a little bit vague to me, how do we define not fully support? e.g., the server can interpret version A, B,C, but the server only fully implements version A,B, regarding version C, the server can read this version, but can not use this version, in other words, it is partially implemented, is my understanding correct? 3.Section 2.1 the new term "offered version" [Qin] Can you add one definition of offered versions in section 1.2, terminology section? To be honest, I still not clear how offered version is different from negotiated version? Also I suggest to add definitions of accepted version, deployed version as well in section 1.2? Too many terminologies, hard to track them in the first place. 4. Section 6 said: " it is possible for some application layer protocols to not be able to run over some of the offered compatible versions. " [Qin]I believe compatible versions is not pertaining to any application layer protocol, if yes, s/compatible versions/compatible QUIC versions 7.1 said: "For example, that could be accomplished by having the server send a Retry packet in the original version first thereby validating the client's IP address before" [Qin] Is Version first Version 1? If the answer is yes, please be consistent and keep using either of them instead of inter-exchange to use them. s/version first/version 1

4. <ins> A version downgrade is an attack where a malicious entity manages to make the QUIC endpoints negotiate a QUIC version different from the one they would have negotiated in the absence of the attack.  The mechanism described in this document is designed to prevent downgrade attacks. </ins> Clients MUST ignore any received Version Negotiation packets that contain the version that they initially attempted.  A client that makes a connection attempt based on information received from a


packets it receives in response to that connection attempt. Both endpoints MUST parse their peer's Version Information during the <del> handshake.  If parsing the Version Information failed (for example, if it is too short or if its length is not divisible by four), then the endpoint MUST close the connection; if the connection was using QUIC version 1, that connection closure MUST use a transport error of type TRANSPORT_PARAMETER_ERROR.  If an endpoint receives a Chosen Version equal to zero, or any Available Version equal to zero, it </del>  MUST treat it as a parsing failure. Every QUIC version that supports version negotiation MUST define a For QUIC version 1, version negotiation errors are signaled using a transport error of type VERSION_NEGOTIATION_ERROR; see iana-error.  If the Version Information was missing, the endpoints MAY complete the handshake.  However, if a client has reacted to a Version Negotiation packet and the Version Information was missing, the

NAME confirmed offline that he can live with this PR as-is, so I'm merging it
Currently at says future versions might allow the long header version to be different from the chosen version in the versioninfo transport parameter. But there's nothing about what to do until such a version exists which changes the semantics of the chosenversion. This is in the initial packet, before incompatible version negotiation, and before compatible version negotiation, has happened. Which error should the handshake be closed with? says that version info transport parameter parsing errors should use the transport parameter error.
Thinking about this some more, I think draft-ietf-quic-version-negotiation doesn't need to say anything more, as those details are specific to the compatibility version document. So I opened URL to discuss this there.
I'm a little confused because this document explains which errors should be used with QUIC v1 when closing the connection on failure to parse the transport parameter or invalid versions (i.e. 0). In the absence of another compatibility version document, shouldn't this document specify the error for QUIC v1? Or are you saying this is not an error in QUIC v1, but could be an error in, e.g., QUIC v2?
This only causes an error when there are two versions involved - and therefore that scenario should be covered by the document that defines compatibility between those two versions. Or do you have a scenario in mind where one version is QUICv1 and the other is unknown? I'm noticing that RFC 9000 doesn't say what you're supposed to do if you receive a packet from another version - I think the assumption is that you silently drop it because you don't know how to parse it.
Agreed that I should specify the v1/v2 case. But perhaps the VN draft should handle the behavior when the long header has a known version (certainly v1) and the Chosen Version is unknown? (I imagine that allowing this allows us to have a backdoor for version upgrade if the version field ossifies)
I would recommend that a server sends a VN packet in this case, and a client kills the connection -- there is no valid reason for the server to slip in a version the client didn't advertise.
Rereading what NAME originally wrote along with NAME comments, I think we can tighten up the validation requirements in this spec to prevent tampering. I've written it up as , please take a look. NAME I went with forcing a close instead of your suggestion, because this back door would weaken the protocol (allows tampering) without helping (if the long header ossifies we can use compatible VN as our backdoor).
I'm not sure compatible VN is sufficient. If someone writes a firewall that says "drop all Long Headers with version == 4" I don't see that compatible negotiation solves the problem -- all the long headers have to say v1 and the actual negotiation happens using TPs. Though I haven't fully thought this through, and certainly not any backdoor implications.
Note that the requirement is only for the client's first flight. So you work around that firewall by defining v1-to-v4 compatibility as always setting Version=1 in long headers
Yeah, I think that works.
WFM. David pointed out that this already defines "in use" and the change to "processes" is good.LGTM

packets it receives in response to that connection attempt. Both endpoints MUST parse their peer's Version Information during the  <ins> handshake.  If that leads to a parsing failure (for example, if it is too short or if its length is not divisible by four), then the endpoint MUST close the connection; if the connection was using QUIC version 1, that connection closure MUST use a transport error of type TRANSPORT_PARAMETER_ERROR.  If an endpoint receives a Chosen Version equal to zero, or any Available Version equal to zero, it MUST treat it as a parsing failure.  If a server receives a Version Information where the Chosen Version is not included in Available Versions, it </ins> MUST treat it as a parsing failure. Every QUIC version that supports version negotiation MUST define a For QUIC version 1, version negotiation errors are signaled using a transport error of type VERSION_NEGOTIATION_ERROR; see iana-error. <ins> When a server receives a client's first flight, the server will first establish which QUIC version is in use for this connection in order to properly parse the first flight.  For example, the server determines that QUIC version 1 is in use by observing that the Version field of the first Long Header packet it receives is set to 0x00000001.  When the server then processes the client's Version Information, the server MUST validate that the client's Chosen Version matches the version in use for the connection.  If the two differ, the server MUST close the connection with a version negotiation error.  For example, if a server receives the client's Version Information over QUIC version 1 (as indicated by the Version field of the Long Header packets that carried the transport parameters) and the client's Chosen Version is not set to 0x00000001, the server will close the connection with a version negotiation error. If a client receives a Version Information where the server's Chosen Version was not sent by the client as part of its Available Versions, the client MUST close the connection with a version negotiation error. </ins> If the Version Information was missing, the endpoints MAY complete the handshake.  However, if a client has reacted to a Version Negotiation packet and the Version Information was missing, the


QUIC connections are shared state between a client and a server INV. The compatible version negotiation mechanism defined in this document <del> (see compat-vn) operates inside of a QUIC connection; i.e., the packets with the original version are part of the same connection as the packets with the negotiated version.  On the other hand, the incompatible version negotiation mechanism, which leverages QUIC Version Negotiation packets (see incompat-vn) conceptually operates across two QUIC connections: one before the Version Negotiation packet, and a distinct connection after. </del>  4.2.

No real complaint with what existed before, but I thought that this might be clearer.
Approved with one nit

QUIC connections are shared state between a client and a server INV. The compatible version negotiation mechanism defined in this document  <ins> (see compat-vn) is performed as part of a single QUIC connection; that is, the packets with the original version are part of the same connection as the packets with the negotiated version. In comparison, the incompatible version negotiation mechanism, which leverages QUIC Version Negotiation packets (see incompat-vn) conceptually operates across two QUIC connections: the connection attempt prior to receiving the Version Negotiation packet is distinct from the connection with the incompatible version that follows. </ins> 4.2.


Clients MAY include versions following the pattern "0x?a?a?a?a" in their "Compatible Version" list, and the server in their "Supported Version" list.  Those versions are reserved to exercise version <del> negotiation (see the Versions section of QUIC), and MUST be ignored </del>  when parsing these fields.  On the other hand, the "Received Negotiation Version" list MUST be identical to the received Version Negotiation packet, so clients MUST NOT add or remove reserved

This construction directly undermines greasing by privileging the handling of greased versions. Please don't do this. As I alluded to in , this doesn't need to match the Version Negotiation packet/datagram contents. What is important here is that the list doesn't include a version that the client would have preferred to attempt over the current one. If you validate the server values that way, then you never have to worry about greased versions being different in the two different places. Indeed, you can have the server offer Version Negotiation packets that include more versions than they claim in their handshake (this being beneficial during the rollout of a fancy new version of the protocol).
Can you elaborate on how this undermines greasing? All we say is that you can add grease to version lists, but the Received Negotiation Version list needs to be transmitted as an opaque blob. We don't treat greased versions differently on receipt anywhere.
Well, the second MUST NOT pertains to something that I think should be removed. But you say "[reserved versions] MUST be ignored when parsing these fields". That tells implementations to train themselves to recognize greased versions. At that point, they are no longer treating these as versions that they just don't understand, but something special. The whole point of using an odd pattern was to ensure that this never happened.
Fair enough, if we replaced with: Would that be OK?
That's all I'm asking for. (Along with striking the echo of the VN packet, but we'll pursue that separately. The requirement there is reasonable if you assume that echoing the bits is necessary.)

Clients MAY include versions following the pattern "0x?a?a?a?a" in their "Compatible Version" list, and the server in their "Supported Version" list.  Those versions are reserved to exercise version  <ins> negotiation (see the Versions section of QUIC), and will be ignored </ins> when parsing these fields.  On the other hand, the "Received Negotiation Version" list MUST be identical to the received Version Negotiation packet, so clients MUST NOT add or remove reserved