Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatible version upgrade #1901

Closed
wants to merge 30 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4dc5e0d
Compatible version upgrade
martinthomson Oct 24, 2018
7483395
There are only two things, which means no list
martinthomson Oct 24, 2018
f997b10
Marten's editorial suggestions
martinthomson Oct 24, 2018
f12becd
Thwart downgrade attacks between incompatible versions
martinthomson Oct 25, 2018
4235f75
unplural
nibanks Oct 25, 2018
0e0df73
article
nibanks Oct 25, 2018
48ae25f
joiner
nibanks Oct 25, 2018
87bcb71
Nick's suggestions
martinthomson Oct 25, 2018
847445b
No common versions means fail
martinthomson Oct 25, 2018
7533873
Move some text up to get the flow right
martinthomson Oct 25, 2018
2b02ccd
Split into supported and unsupported
martinthomson Oct 26, 2018
34b19da
The packet definitely always changes
martinthomson Oct 26, 2018
a2c5c6a
Moar words about what it means for a version to be supported by a client
martinthomson Oct 26, 2018
0de8a0c
Cleanup, don't create conflicting requirements
martinthomson Oct 26, 2018
8ffb306
discard, not ignore
igorlord Oct 29, 2018
67a815e
Fix the RETIRE_CONNECTION_ID frame type again
martinthomson Oct 24, 2018
4edf5b3
Don't recommend stateless reset
martinthomson Oct 25, 2018
4417e03
Add missing sections to document structure
martinthomson Oct 25, 2018
8f69ad1
Forward reference ECN verification
martinthomson Oct 25, 2018
7c4b04d
Take suggestion
martinthomson Oct 25, 2018
270243e
Use octets rather than bytes throughout
martinthomson Oct 25, 2018
0143d41
Use octets for units; size for packet sizes
martinthomson Oct 25, 2018
bbf55a5
Use bytes instead of octets throughout
martinthomson Oct 25, 2018
a4f4c9f
Reflow
martinthomson Oct 25, 2018
9d50417
Update draft-ietf-quic-recovery.md
ianswett Oct 28, 2018
3f330f6
clarify
ianswett Oct 28, 2018
f0b5080
unhypenate - the name of my new startup
martinthomson Oct 28, 2018
4578287
rewrap
martinthomson Oct 28, 2018
aa3ddc1
Reflow
martinthomson Oct 29, 2018
d59f429
Merge branch 'master' into vn-mkII
martinthomson Oct 29, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 96 additions & 48 deletions draft-ietf-quic-transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -1169,23 +1169,29 @@ Connection ID fields in a packet that the client sent. If this check fails, the
packet MUST be discarded.

Once the Version Negotiation packet is determined to be valid, the client then
selects an acceptable protocol version from the list provided by the server.
The client then attempts to create a connection using that version. Though the
content of the Initial packet the client sends might not change in response to
version negotiation, a client MUST increase the packet number it uses on every
packet it sends. Packets MUST continue to use long headers ({{long-header}})
and MUST include the new negotiated protocol version.
selects an acceptable protocol version from the list provided by the server. The
client MUST choose the version that it most prefers from those supported by the
server. The server will abort the connection attempt if the client chooses in a
manner inconsistent from the preference order included with the client transport
parameters (see {{version-validation}}).

The client then attempts to create a connection using the version it selects.
Though the content of the Initial packet the client sends might not change in
response to version negotiation, a client MUST increase the packet number it
uses on every packet it sends. Packets MUST continue to use long headers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this saying that even if the client creates an entirely new connection state it needs to increase the packet number still? I assume that wasn't intended. Perhaps Though the content of the Initial packet the client sends might not change in response to version negotiation, a client MUST increase the packet number it uses on every packet it sends. should be changed to something like If the content of the Initial packet the client sends does not change in response to version negotiation, a client MUST increase the packet number it uses on every packet it sends.?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take the suggestion, which is better than what we have. In practice, the packet will probably change - it's a different version of the protocol after all.

({{long-header}}) and MUST include the new negotiated protocol version.

The client MUST use the long header format and include its selected version on
all packets until it has 1-RTT keys and it has received a packet from the server
which is not a Version Negotiation packet.

A client MUST NOT change the version it uses unless it is in response to a
Version Negotiation packet from the server. Once a client receives a packet
from the server which is not a Version Negotiation packet, it MUST discard other
Version Negotiation packets on the same connection. Similarly, a client MUST
ignore a Version Negotiation packet if it has already received and acted on a
Version Negotiation packet.
Version Negotiation packet from the server, or if the server picks a different,
but compatible version (see {{version-upgrade}}). Once a client receives a
packet from the server which is not a Version Negotiation packet, it MUST
discard other Version Negotiation packets on the same connection. Similarly, a
client MUST ignore a Version Negotiation packet if it has already received and
acted on a Version Negotiation packet.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not theoretically possible that a client (that supports A,B,C) sends version A, and the server supports version {B, C} and responds with a version negotiation packet. THEN the server is updated to support only {C}. The client responds to the VN with B, and then gets a new VN in response, and would want to then try C? It's a pretty crappy experience and extremely small edge case, but I think possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly the type of edge case I had in mind when talking about #504 (now quicwg/ops-drafts#28).

I don't think that we can fix that here, though this compatible version upgrade will make that a lot easier: if B and C are compatible, you can retain enough support for B that you can upgrade from B to C. It's not perfect, because you still have to send Version Negotiation in response to B if the client doesn't support C, but it could get you further in an incremental roll-back scenario.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in that case the client should abort and possibly make a completely new connection attempt a limited number of times. Otherwise you can get into a loop between two round robin load balanced servers where you never terminate version negotiation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client is not allowed to respond to version {C} because it is only allow to handle one VN packet (which is important to avoid loops). But as I wrote, a client could make a new connection attempt which amounts to the same thing, so stricly speaking the connection would fail on timeout as the second VN packet is ignored.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally speaking, a server cluster will indicate a common subset of versions that it supports in VN.

When adding support for a new version, each of the server start accepting the new version when found in Initial. After that completes, the next would be to modify each server to start indicating the use of the new version in VN.

In case of removing the support for an old version, we will remove that version from the VN list, then stop accepting Initial with that version.


A client MUST ignore a Version Negotiation packet that lists the client's chosen
version.
Expand All @@ -1197,9 +1203,8 @@ as a result, see {{retry-0rtt-pn}}.
The format of the packet that a client sends might be different in the new
version. In this case, the client generates a new packet that conforms to the
selected version. Though different versions might convey information about
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't we requiring the client to always regenerate a packet, now that unsupported_versions change from an empty list to a non-empty list when receiving a VN?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I missed that one. I squashed the other text, but missed that one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah! It's a gift to proof-readers 👍

versions differently, a client MUST NOT change either the list of versions it
claims to support. Similarly, a client MUST NOT change what it reports as the
version it first attempted to use.
versions differently, a client MUST send both its first attempted version and
the list of versions it claims to support in preference order.

Version negotiation packets have no cryptographic protection. Keeping
version-related information consistent between versions is critical for
Expand All @@ -1210,15 +1215,18 @@ validation of the choice of version (see {{version-validation}}).

The first packet sent by a client uses a QUIC version selected by the client.
In this version of QUIC, this packet also includes transport parameters. Those
transport parameters include a list of QUIC versions the client supports.
transport parameters includes the version the client first attempts to use, plus
martinthomson marked this conversation as resolved.
Show resolved Hide resolved
a list of QUIC versions the client supports in the order that the client prefers
them.

A server that understands the version selected by the client can extract the
list of QUIC versions and select an alternative version from the list of
supported versions. A server MAY choose a compatible version from that list and
continue the handshake with that version. The server sends its first packet as
though it was continuing with the version it selects.
supported versions. A server MAY choose version from that list that is
martinthomson marked this conversation as resolved.
Show resolved Hide resolved
compatible with the version selected by the client and continue the handshake
with that version. The server sends its first packet as though it was
continuing with the version it selects.

A QUIC version is compatible with this version if the cryptographic handshake
A QUIC version is compatible with another version if the cryptographic handshake
message sent in the first packet can be used in both versions. A compatible
version is also able to identify and acknowledge the first packet sent by the
client in some fashion. Other QUIC versions might have different constraints in
Expand All @@ -1235,6 +1243,10 @@ A server MUST NOT send a Version Negotiation packet if it prefers a version that
is not compatible with the version the client initially chose; a server has to
allow the client to choose between versions that are not compatible.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need some text what a client is supposed to do when it receives a VNP that includes a compatible version to the one it initially selected?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Because the server might not support every compatible version. If the client offers A, where B is compatible, the server can still send Version Negotiation in response with B because it doesn't understand A.


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the client wants to use a specific other version if possible, but it does not want to do it in-flight within the current connection, for example to keep the client simple? It cannot omit that version from TP because then the current version will continue. It cannot include that version in TP because then it might get in-flight version change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s the use case for this? I don’t really see the point of “keeping the client simple” here, this is not one of the complex areas of the protocol.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you implement each version as a separate binary or in a separate process. You could send on the that other version instead and hope the best, but that could result in many unnecessary version negotations if that version is not (yet) widely supported.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you were to implement each version in a different process, then this would not work, yes. Unless you wanted to complicate the hand-off from a simple exec quic-vY --disable-vn to something more like exec quic-vY --handoff=<translated packet+necessary keys>. The consequence is that you probably want to have compatible versions handled by the same instance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have some text that says what to do if the server's supported list doesn't overlap at all with the client's? Should it still send a VN, even though it knows the client won't be able to continue the connection? I didn't see any text talking about that case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's caught by the generic version negotiation text. But I note that we don't have that. #1917.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you wrote this, new text appeared requiring a connection abort if a VN with no overlap is received. If the server has implicit knowledge about what the client supports it doesn't change anything - either it goes forward with a compatible version or it sends a VN packet.

A client MUST abort the connection attempt with a VERSION_NEGOTIATION_ERROR if
the server chooses a compatible version upgrade to the version that the client
first attempted.


## Using Reserved Versions

Expand Down Expand Up @@ -1438,12 +1450,12 @@ available. Each endpoint validates the value provided by its peer. Successful
validation of transport parameters MUST be completed before a connection is
considered successfully established.

A client also includes a list of supported versions along with its transport
parameters. Transport parameters are carried in the first packet the client
sends. Sending the list of supported versions enables upgrades between
compatible versions, as described in {{version-upgrade}}. These parameters also
enable validation of version negotiation by the server (see
{{version-validation}}).
A client also includes information about the QUIC versions it supports along
with its transport parameters. Transport parameters are carried in the first
packet the client sends. Sending a list of supported versions enables upgrades
between compatible versions, as described in {{version-upgrade}}. These
parameters are used by a server to validate the outcome of version negotiation
(see {{version-validation}}).

A transport parameter MUST appear at most once in a given transport parameters
extension. An endpoint MUST treat receipt of duplicate transport parameters as
Expand Down Expand Up @@ -1510,30 +1522,55 @@ version downgrade are possible. In the first, an attacker replaces the QUIC
version in the Initial packet. In the second, a fake Version Negotiation packet
is sent by an attacker.

To protect against these attacks, the transport parameters includes the complete
list of versions that a client is willing to use, with the version it used for
sending the first packet in the first entry. Including this information in the
cryptographic handshake provides it with integrity protection, and allows the
server to detect version downgrade attacks.
To protect against these attacks, the transport parameters includes both the
original version the client uses with its first packet, a complete list of
martinthomson marked this conversation as resolved.
Show resolved Hide resolved
versions that a client is willing to use in preference order. Including this
information in the cryptographic handshake provides it with integrity
protection, and allows the server to detect version downgrade attacks.

The client MUST include the first QUIC version it attempts to use in the
original_version field of its transport parameters. A server MUST abort the
connection attempt with a VERSION_NEGOTIATION_ERROR if it supports the version
in the original_version field and that version does not match the version of the
Initial packet from the client.

The client MUST include the versions it claims to support in preference order in
the supported_versions field of its transport parameters. A server MUST abort
the connection attempt with a VERSION_NEGOTIATION_ERROR if the Initial packet
from the client contains a version that is less preferred by the client than any
version it supports, unless that version also matches the original_version
field.

<!-- Editor's note: should I include this algorithm?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I find it useful.

if original_version == current_version:
return OK # No version negotiation, great.
for v in supported_versions:
if v == current_version:
return OK # Version negotiation, but all good.
if server_supports(v):
return BAD # Downgrade attack attempt thwarted!
return BAD # Client claims it doesn't support this version!
-->

The client MUST include the first QUIC version it attempts to use as the first
entry of the supported_versions list in the transport parameters. A server MUST
close the connection attempt with a VERSION_NEGOTIATION_ERROR if it supports the
first entry in the list it receives and that version does not match the version
of the QUIC packet. The server MAY choose to upgrade to a compatible version,
as defined in {{version-upgrade}}.
After validating the version parameters from the client, a server MAY choose to
upgrade to a compatible version, as defined in {{version-upgrade}}, even if that
version is less preferred by the client.

Different QUIC versions might define transport parameters, or their equivalent,
using a different format. However, the version field in the QUIC packet header
is authenticated using transport parameters. The position and the format of the
version fields in transport parameters therefore MUST either be identical across
different QUIC versions, or be unambiguously different to ensure no confusion
about their interpretation. One way that a new format could be introduced is to
define a TLS extension with a different codepoint.
using a different format. However, the negotiated version is validated using
these parameters, so they require that equivalent information is conveyed.

If a new version uses transport parameters with a similar encoding, the position
and the format of the version fields in transport parameters MUST either be
identical across different QUIC versions, or be unambiguously different to
ensure no confusion about their interpretation. If the same sequence of octets
could be interpreted differently based on the assumed version, this might be
exploited to attack version negotiation. One way that a new format could be
introduced is to define a TLS extension with a different codepoint.

Transport parameters for QUIC versions that are compatible with this QUIC
version MUST provide transport parameters definitions that retain both a list of
versions the client supports, as well as the one that it first attempts to use.
version MUST provide transport parameters definitions that retain equivalents
for the original_version and supported_versions fields.


# Address Validation
Expand Down Expand Up @@ -3836,6 +3873,7 @@ language from Section 3 of {{!TLS13=RFC8446}}.
struct {
select (Handshake.msg_type) {
case client_hello:
QuicVersion original_version;
QuicVersion supported_versions<4..2^8-4>;
};
TransportParameter parameters<0..2^16-1>;
Expand All @@ -3854,14 +3892,24 @@ language from Section 3 of {{!TLS13=RFC8446}}.
The `extension_data` field of the quic_transport_parameters extension defined in
{{QUIC-TLS}} contains a TransportParameters value.

A client includes a list of its supported versions in its transport parameters.
This supports validation of the negotiated versions as defined in
{{version-validation}}.

QUIC encodes transport parameters into a sequence of octets, which are then
included in the cryptographic handshake.


## Version Validation Fields

A client includes the QUIC version it first attempts to connect with in the
original_version field of its transport parameters.

The supported_versions field is a list of the versions the client supports.
This list MUST be ordered starting with the version the client most prefers and
ending with the least-prefered version. This supports validation of the
negotiated versions as defined in {{version-validation}}.

Though different QUIC versions might express these values differently, a client
MUST not change these values in response to Version Negotiation.


## Transport Parameter Definitions {#transport-parameter-definitions}

<!-- TODO: reorganize this section -->
Expand Down