Draft: draft-ietf-quic-version-negotiation

Commentary: I 'm not sure that this is the right angle . Instead , I would suggest that we simply say that VN ca n't be used to negotiate pre - v1 versions of QUIC , which seems to achieve the same objective . 
 It 's true that you could avoid using any sort of version negotiation signaling to select a version that does n't support this extension ( with the exception of version 1 ) . That still leaves a client that supports a new version and version 1 without protection when it has to validate the response from a server that only supports version 1 . This change addresses the problem by saying that if you do n't support this mechanism properly , then you must only support version 1 . We could also say that Version Negotiation packets can not be used to select draft versions of QUIC , but I do n't think that makes any real difference . 
 I do n't think I 'm following you here . If the client supports version N 1 and 1 and the server only supports 1 , then what are you trying to protect against ? You can only negotiate 1 . 
 If the client supports this specification , it is required to fail to connect in that case because the transport parameter is absent . That 's what this change is addressing . 
  , well that 's a matter of interop , not protection . So , I agree some special casing is needed , but I do n't think this is necessarily it . I would just say that if the parameter is not present , then you can still negotiate v1 , rather than trying to pretend it sent a parameter it did n't . 
 Same net effect . Sounds like that comes down to editorial preference . 
 , I just realized that this is n't completely true . The formulation with says something more : it says that you do n't support any other version . That might be important for those cases where you might have other incompatible versions available . 
 Yes , and I 'm proposing we do n't address that case , because future versions should use this mechanism and we just want to get rid of past versions . 
 But would it be reasonable to require that - if you implement a new version - you implement this extension for version 1 ? 
 Yes , I think we should require that . 
 This change is consistent with that decision : if a server implements an incompatible version X , then it will be required to send , which will allow the client to confirm that it would not have chosen X over 1 . That provides the client with protection against a downgrade to version 1 from X. If you merely allow the client to negotiate version X , then that client gets no downgrade protection in that case . 
 As above , I propose to merely forbid negotiating any older version at all via this mechanism . 
 to clarify your position : in the scenario where the client supports version 1 , version 2 , and this extension the client supports only version 1 and not this extension the client starts with v2 server replies with a VN packet that only contains v1 client restarts with v1 but does n't get version_information from the server Are you suggesting that in this scenario the client should fail the handshake ? 
 No . I believe this should succeed . What I believe should fail is that the client supports V2 , V1 , and some old ( preV1 ) draft version , and server only supports that draft version and they use this extension to negotiate that . 
 This PR is trying to which is not the same issue which pointed out . To fix issue , we need another rule : this version negotiation mechanism must not be used for pre - v1 draft versions . 
 in this scenario did the server send the version_information transport parameter ? 
 Does n't matter . I think we should actively forbid negotiation of pre - V1 versions , regardless of whether they implement this mechanism or not . 
 I think that 's outside the purview of this draft . Google 's going to keep using Google QUIC and h3 - 29 until our aggregated data shows it 's safe to remove support for those versions - we 're not going to treat those versions different from QUICv1 until then . 
 It 's not even remotely outside of the purview of this draft . For example , RFC 8996 forbids negotiating TLS 1.0 . As for what Google chooses to do or not to do , as is often said , there are no protocol police . But that does n't really have that much to do with whether the IETF should endorse removing these versions . Regardless , I do n't really see what the issue is here : presumably the problem is old clients , who will not be implementing this draft in any case , so you can simply accept them as a server , but not do VN for them . 
 I 'm failing to understand how your proposal is an alternative to this PR . Consider the scenario I mentioned in - in the current version of the draft , that scenario fails whereas with this PR that scenario succeeds . Since that scenario only involves QUICv1 and QUICv2 , how are pre - QUICv1 versions relevant ? 
 I 'll write something up in more detail . 
 Gentle ping . 
 I have implemented this PR feature in my client and confirmed that the backward compatibility is maintained . 
 Would you write up ? 
 I do n't see why this is a special case for QUICv1 . It should apply to all single - version servers . I thought our position was that any multiple - version endpoint needs to support the VN draft . If a server was e.g. v2 only for some silly reason , it could omit the TP with no risk of downgrade . The client should interpret lack of the TP as a single - version server , whether it 's v1 or not . The alternative is to make the  mandatory for all non - v1 servers . I could edit the v2 draft accordingly if that 's the consensus . 
 " it could omit the TP with no risk of downgrade " is not correct . You can have an attack where the client thinks it 's speaking one version and the server is thinking it 's speaking another version because an attacker is rewriting packets as they flow by . This ca n't happen with v1 vs v2 because we changed the TLS HKDF labels but it 's a risk in general . Keeping the Chosen Version in the transport parameters avoids this attack and simplifies security analysis 
 Does n't that collapse once the Version field is properly authenticated ? And anyway 9001 says we SHOULD roll new labels for each version , FWIW 
 The Version field is not authenticated if it 's not in the TLS transcript . That does n't apply to non - TLS versions 
 Suppose that a client supports QUIC v1 , v2 and the new negotiation while a server supports RFC 9000 only . The following normal scenario succeeds because the client does not receive a VN packet so the client does not have to check : However , the following scenario , I think , fails : The client sent CC because is missing . The latter is the common method to test the version negotiation of RFC 9000 . Are we giving up this method ? 
 It looks like the key flaw here is in dealing with servers that do n't understand this extension . I think that we fix that by treating absence of versioninformation as being equivalent to " versioninformation = 1 , { 1 } " or " versioninformation = 1 , { } " ( which is functionally equivalent ) . That is , of course , in tension with this text in : ... so far so good . That part probably needs to be revised . 
 With the current spec , " versioninformation = 1 , { } " from a client is not allowed . So for simplicity , " versioninformation = 1 , { } " from a server should not be allowed , either . Only the form of " version_information = 1 , { 1 } " should be allowed . 
 I agree with the premise , the scenario where the client starts with a grease version , waits for VN then tries with a version from the VN packet does n't work with this extension . But that scenario was never specifically allowed in RFC 9000 , it 's just something a few implementations picked up along the way . I 'd suggest either doing nothing , or having an appendix that mentions this version greasing technique . I 'd rather not treat a missing parameter as something present , because that opens up a class of downgrade attacks against servers that do n't support this extension . 
 Conceptually , this comes down to one question : if the server does n't support this extension , should the client fail open or fail closed . I 'd argue fail closed because it has better security and this scenario wo n't happen in practice . 
 I do n't have a strong opinion . I just want to have a clear spec . Let 's consider another scenario . Suppose that a server supports RFC 9000 only and does not allow  . If I understand correctly , the following would happen without the greasing version : Does this scenario change your opinion ? 
 The specification for  states that if you receive VN you MUST close the connection . If you support  and the VN draft , then you try again but require the presence of version_information and fail the handshake if it 's missing . This scenario is n't ambiguous . We need to fail the handshake in this scenario because otherwise we 're exposing the client to version downgrade attacks . 
 OK . I would like to add an appendix which describe the four scenarios in 
 That 's reasonable . Can you send a PR with the appendix you have in mind please ? 
 I will . 
 What about if you support version 2 and version 1 ? Version 2 will say that you need to support this draft . But if the server does n't support version 2 , then do you also need to fail on the basis that you are now executing version 1 logic ? That seems like it is the wrong answer . Sure , most sensible clients will attempt version 1 and offer a compatible upgrade to version 2 , but that does n't mean we should n't consider the converse . 
 I see two solutions here : the client to not do that - we already have text in the " Client Choice of Original Version " section but we could expand on it open ( in other words , do n't fail the handshake if version_negotiation is missing ) Do you have opinions on which is best ? ( or if you see other solutions ) 
 In this case , we have special information : if the server only supports version 1 ( let 's not drag pre - RFC9000 draft versions into this ) , then the absence of the extension might be used to confirm that . That only works for version 1 , but it seems OK to me to accept that as a positive signal ( as opposed to the absence of one ) . 
 What about a server that supports QUICv1 and Google QUIC versions Q050 and Q043 ? Or some other future non - IETF versions ? In other words , what change to the draft do you have in mind ? We could special - case QUICv1 but I 'm not sure what it 'd get us . 
 My suggestion is that we say that a client that negotiates QUIC version 1 can assume that the server ONLY supports QUIC version 1 for the purposes of validation . That is , in the absence of the extension and if QUIC version 1 is in use , the client may assume that the extension is present with a value of ( to use Kazu 's notation ) . That privileges QUIC version 1 as the version of QUIC that we defined prior to this , but I do n't think we can extend this sort of compatibility to other protocols without risking the exact sort of downgrades we 're trying to avoid . Sadly , that means that Q050 and Q043 are not protected in the same way . Implementations of other QUIC versions could add support for this extension though . 
 That sounds reasonable to me . If we rely on the following two assumptions : 1 is preferred over earlier versions ( such as 0xff00001d or Q050 ) that are created after QUICv1 will use this draft then we 're guaranteed that a downgrade attack against a QUICv1+Q050 server is n't possible , while still allowing VN to servers that only support QUICv1 .
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.  This document specifies
version negotiation using VN packets, which adds an extra round trip
to connection establishment if needed.
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 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 Version Negotiation
packet can be part of a mechanism to allow two QUIC implementations
to negotiate between two totally disjoint versions of QUIC.  This
document specifies version negotiation using Version Negotiation
packets, which adds an extra round trip to connection establishment
if needed.
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
fields; see Section 6 of INV.
Upon receiving the Version Negotiation 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 version information (see vers-info)
required to ensure that version negotiation was genuine, i.e. that no
attacker injected packets in order to influence the version
negotiation process, see downgrade.
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.  Note that the conversion of the first flight can
be lossy: some data such as QUIC version 1 0-RTT packets could be
ignored during conversion and retransmitted later.
When a client creates a QUIC connection, its goal is to use an
application layer protocol.  Therefore, when considering which
versions are compatible, clients will only consider versions that
support one of the intended application layer protocols.  For
example, if the client's first flight advertises multiple Application
Layer Protocol Negotiation (ALPN) ALPN tokens and multiple compatible
versions, the server needs to ensure that the ALPN token that it
selects can run over the QUIC version that it selects.
Note also that the client can disable compatible version negotiation
by only including the Chosen Version in the Other Versions field of
the Version Information Transport Parameter.
Clients will ignore a Version Negotiation packet if it contains the
original version attempted by the client.  The client also ignores a
Version Negotiation that contains incorrect connection ID fields; see
Section 6 of INV.
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 version information (see 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.
During the handshake, endpoints will exchange Version Information,
which consists of a chosen version and a list of other versions.  Any
version of QUIC that supports this mechanism MUST provide a mechanism
to exchange Version Information in both directions during the
handshake, such that this data is authenticated.
When sent by a server, the Other Versions field lists all the
Fully-Deployed Versions of this server deployment, see server-
fleet.  Note that the version in the Chosen Version field is not
necessarily included in this list, because the server operator
could be in the process of removing support for this version.  For
the same reason, the Other Versions field MAY be empty.
Both endpoints MUST parse their peer's Version Information during the
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 Other Version equal to zero, it MUST
treat it as a parsing failure.
If the client received and acted on a Version Negotiation packet, the
client MUST validate the server's Other Versions field.  The Other
Versions field is validated by confirming that the client would have
attempted the same version with knowledge of the versions the server
supports.  That is, the client would have selected the same version
if it received a Version Negotiation packet that listed the versions
in the server's Other Versions field, plus the negotiated version.
If the client would have selected a different version, the client
MUST close the connection with a version negotiation error.  In
particular, if the client reacted to a Version Negotiation packet and
the server's Other Versions field is empty, the client MUST close the
connection with a version negotiation error.  These connection
closures prevent an attacker from being able to use forged Version
Negotiation packets to force a version downgrade.
After the process of version negotiation in this document completes,
the version in use for the connection is the version that the server
sent in the Chosen Version field of its Version Information.  That
remains true even if other versions were used in the Version field of
long headers at any point in the lifetime of the connection.  In
particular, since during compatible version negotiation the client is
made aware of the negotiated version by the QUIC long header version
(see compat-vn), clients MUST validate that the server's Chosen
Version is equal to the negotiated version; if they do not match, the
client MUST close the connection with a version negotiation error.
This prevents an attacker's ability to influence version negotiation
by forging the Version long header field.
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.
QUIC version 1 defines multiple features which are not documented in
the QUIC invariants.  Since at the time of writing QUIC version 1 is
widely deployed, this section discusses considerations for future
versions to help with compatibility with QUIC version 1.
QUIC version 1 uses TLS 1.3, which supports session resumption by
sending session tickets in one connection that can be used in a later
connection; see Section 2.2 of TLS.  New versions that also use TLS
1.3 SHOULD mandate that their session tickets are rightly scoped to
one version of QUIC; i.e., require that clients not use them across
version and that servers validate this client requirement.
Because QUIC version 1 was the only IETF Standards Track version of
QUIC published before this document, it is handled specially as
follows: if a client is starting a QUIC version 1 connection in
response to a received Version Negotiation packet, and the
version_information transport parameter is missing from the server's
transport parameters, then the client SHALL proceed as if the
server's transport parameters contained a version_information
transport parameter with a Chosen Version set to 0x00000001 and an
Other Version list containing exactly one version set to 0x00000001.
This allows version negotiation to work with servers that only
support QUIC version 1.  Note that implementations which wish to use
version negotiation to negotiate versions other than QUIC version 1
will need to implement this draft.