Draft: draft-ietf-quic-version-negotiation

Commentary: 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 . 
 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 would n'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 should n'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 
 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 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 . 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 : comment on 
 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 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 ) , 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 do n't understand the scenario you have in mind here . How would the conversion from X to Y fail ? This seems like it should nt ' happen and should just cause connection failure . 
 Looking at , it says : 
 OK , well I have n't reviewed but that sounds wrong to me . 
 You 're right that was an oversight . In , I 've replaced : with : 
 The primary versions available to us to test this new version negotiation process are  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 do n'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 . how do you feel about closing this issue ? 
 Sure , good ahead . 
 Related to 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 was n'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 . 
 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 can not 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 would n'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 does n'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 ca n'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 , 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 , 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 is n't desirable long - term , because we do n'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 does n'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 should n'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 on 2019 - 11 - 04 ) 
 from 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 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 wo n'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 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 ) 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 ? 
 what is " Server Handshake Version Information " ? I do n'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 on 2019 - 11 - 04 : 
 Comment from 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 on 2019 - 11 - 12 ) 
 Copy of the conversation from the original issue : Can you say more about " mapping " ? I do n't believe that appears in this document , so I 'd like to make sure we are on the same page . 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 ? 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 does n'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 do n'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 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 would n'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 ?
QUIC does not provide a complete version negotiation mechanism but
instead only provides a way for the server to indicate that the
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
negotiated version share a compatible Initial format, the negotiation
can take place without incurring an extra round trip.
QUIC does not provide a complete version negotiation mechanism but
instead only provides a way for the server to indicate that the
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
negotiated version share a compatible first flight format, the
negotiation can take place without incurring an extra round trip.
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.
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.
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.
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.
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
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
this Initial in response to a Version Negotiation packet, the
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
the client has not received a Version Negotiation packet on this
connection, this field SHALL be 0.
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.
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.
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.
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.
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.
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.
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
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
this first flight in response to a Version Negotiation packet, the
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
the client has not received a Version Negotiation packet on this
connection, this field SHALL be 0.
A variable-length integer specifying the number of Compatible
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.
The version that the server chose to use for the connection.  This
field SHALL be equal to the value of the Version field in the long
header that carries this transport parameter.
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
included in the Supported Version list.
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
negotiation (see the Versions section of QUIC), and MUST be ignored
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
version from that list.
A variable-length integer specifying the number of Compatible
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.
The version that the server chose to use for the connection.  This
field MUST be equal to the value of the Version field in the long
header that carries this data.
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
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.
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
negotiation (see the Versions section of QUIC), and MUST be ignored
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
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
Version Negotiation packets.
Servers MUST validate that the client's "Currently Attempted Version"
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
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
enforcing its presence in Received Negotiation Versions.  Once all
servers have been upgraded, the second step is to start enforcing
that the new version is present in Received Negotiation Versions.
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.
The server's Supported Version list allows it to communicate the full
list of versions it supports to the client.  In the case where
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
version that is more preferable that the one initially attempted by
default, the client SHOULD cache that information and attempt the
preferred version in subsequent connections.
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
Version Negotiation packets on that connection.
Servers MUST validate that the client's "Currently Attempted Version"
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
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
enforcing its presence in "Received Negotiation Versions".  Once all
servers have been upgraded, the second step is to start enforcing
that the new version is present in "Received Negotiation Versions".
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.
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".
The server's "Supported Version" list allows it to communicate the
full list of versions it supports to the client.  In the case where
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
version that is more preferable that the one initially attempted by
default, the client SHOULD cache that information and attempt the
preferred version in subsequent connections.
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.
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.
The presence of the Attempted Version and Negotiated Version fields
mitigates an attacker's ability to forge packets by altering the
version.
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.
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).
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).
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.
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.
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.
The presence of the "Attempted Version" and "Negotiated Version"
fields mitigates an attacker's ability to forge packets by altering
the version.