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

Early CONNECTION_CLOSE fixes #3440

Merged
merged 16 commits into from Mar 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
105 changes: 57 additions & 48 deletions draft-ietf-quic-tls.md
Expand Up @@ -316,48 +316,49 @@ same keys even if TLS has already updated to newer keys.

One important difference between TLS records (used with TCP) and QUIC CRYPTO
frames is that in QUIC multiple frames may appear in the same QUIC packet as
long as they are associated with the same encryption level. For instance, an
implementation might bundle a Handshake message and an ACK for some Handshake
data into the same packet.
long as they are associated with the same packet number space. For instance,
an endpoint can bundle a Handshake message and an ACK for some Handshake data
into the same packet.

Some frames are prohibited in different encryption levels, others cannot be
sent. The rules here generalize those of TLS, in that frames associated with
establishing the connection can usually appear at any encryption level, whereas
those associated with transferring data can only appear in the 0-RTT and 1-RTT
encryption levels:
Some frames are prohibited in different packet number spaces. The rules here
generalize those of TLS, in that frames associated with establishing the
connection can usually appear in packets in any packet number space, whereas
those associated with transferring data can only appear in the application
data packet number space:

- PADDING and PING frames MAY appear in packets of any encryption level.
- PADDING, PING, and CRYPTO frames MAY appear in any packet number space.

- CRYPTO frames and CONNECTION_CLOSE frames signaling errors at the QUIC layer
(type 0x1c) MAY appear in packets of any encryption level except 0-RTT.
- CONNECTION_CLOSE frames signaling errors at the QUIC layer (type 0x1c) MAY
appear in any packet number space. CONNECTION_CLOSE frames signaling
application errors (type 0x1d) MUST only appear in the application data packet
number space.
Copy link
Member

Choose a reason for hiding this comment

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

"application data packet number space"


- CONNECTION_CLOSE frames signaling application errors (type 0x1d) MUST only be
sent in packets at the 1-RTT encryption level.
- ACK frames MAY appear in any packet number space, but can only acknowledge
packets which appeared in that packet number space. However, as noted below,
0-RTT packets cannot contain ACK frames.

- ACK frames MAY appear in packets of any encryption level other than 0-RTT, but
can only acknowledge packets which appeared in that packet number space.
- All other frame types MUST only be sent in the application data packet number
space.

- All other frame types MUST only be sent in the 0-RTT and 1-RTT levels.

Note that it is not possible to send the following frames in 0-RTT for various
reasons: ACK, CRYPTO, HANDSHAKE_DONE, NEW_TOKEN, PATH_RESPONSE, and
RETIRE_CONNECTION_ID.
Note that it is not possible to send the following frames in 0-RTT packets for
various reasons: ACK, CRYPTO, HANDSHAKE_DONE, NEW_TOKEN, PATH_RESPONSE, and
RETIRE_CONNECTION_ID. A server MAY treat receipt of these frames in 0-RTT
packets as a connection error of type PROTOCOL_VIOLATION.

Because packets could be reordered on the wire, QUIC uses the packet type to
indicate which level a given packet was encrypted under, as shown in
{{packet-types-levels}}. When multiple packets of different encryption levels
need to be sent, endpoints SHOULD use coalesced packets to send them in the same
UDP datagram.

| Packet Type | Encryption Level | PN Space |
|:--------------------|:-----------------|:----------|
| Initial | Initial secrets | Initial |
| 0-RTT Protected | 0-RTT | 0/1-RTT |
| Handshake | Handshake | Handshake |
| Retry | N/A | N/A |
| Version Negotiation | N/A | N/A |
| Short Header | 1-RTT | 0/1-RTT |
{: #packet-types-levels title="Encryption Levels by Packet Type"}
indicate which keys were used to protect a given packet, as shown in
{{packet-types-keys}}. When packets of different types need to be sent,
endpoints SHOULD use coalesced packets to send them in the same UDP datagram.

| Packet Type | Encryption Keys | PN Space |
|:--------------------|:----------------|:-----------------|
| Initial | Initial secrets | Initial |
| 0-RTT Protected | 0-RTT | Application data |
| Handshake | Handshake | Handshake |
| Retry | Retry | N/A |
| Version Negotiation | N/A | N/A |
| Short Header | 1-RTT | Application data |
{: #packet-types-keys title="Encryption Keys by Packet Type"}

Section 17 of {{QUIC-TRANSPORT}} shows how packets at the various encryption
levels fit into the handshake process.
Expand Down Expand Up @@ -415,12 +416,20 @@ A QUIC client starts TLS by requesting TLS handshake bytes from TLS. The client
acquires handshake bytes before sending its first packet. A QUIC server starts
the process by providing TLS with the client's handshake bytes.

At any time, the TLS stack at an endpoint will have a current sending encryption
level and receiving encryption level. Each encryption level is associated with a
different flow of bytes, which is reliably transmitted to the peer in CRYPTO
frames. When TLS provides handshake bytes to be sent, they are appended to the
current flow and any packet that includes the CRYPTO frame is protected using
keys from the corresponding encryption level.
At any time, the TLS stack at an endpoint will have a current sending
encryption level and receiving encryption level. Encryption levels determine
the packet type and keys that are used for protecting data.

Each encryption level is associated with a different sequence of bytes, which is
reliably transmitted to the peer in CRYPTO frames. When TLS provides handshake
bytes to be sent, they are appended to the current flow. Any packet that
includes the CRYPTO frame is protected using keys from the corresponding
encryption level. Four encryption levels are used, producing keys for Initial,
0-RTT, Handshake, and 1-RTT packets. CRYPTO frames are carried in just three of
these levels, omitting the 0-RTT level. These four levels correspond to three
packet number spaces: Initial and Handshake encrypted packets use their own
separate spaces; 0-RTT and 1-RTT packets use the application data packet number
space.

QUIC takes the unprotected content of TLS handshake records as the content of
CRYPTO frames. TLS record protection is not used by QUIC. QUIC assembles
Expand Down Expand Up @@ -700,13 +709,13 @@ requirements for determining whether to accept or reject early data.

## HelloRetryRequest

In TLS over TCP, the HelloRetryRequest feature (see Section 4.1.4 of {{!TLS13}})
can be used to correct a client's incorrect KeyShare extension as well as for a
stateless round-trip check. From the perspective of QUIC, this just looks like
additional messages carried in the Initial encryption level. Although it is in
principle possible to use this feature for address verification in QUIC, QUIC
implementations SHOULD instead use the Retry feature (see Section 8.1 of
{{QUIC-TRANSPORT}}). HelloRetryRequest is still used to request key shares.
In TLS over TCP, the HelloRetryRequest feature (see Section 4.1.4 of
{{!TLS13}}) can be used to correct a client's incorrect KeyShare extension as
well as for a stateless round-trip check. From the perspective of QUIC, this
just looks like additional messages carried in Initial packets. Although it is
in principle possible to use this feature for address verification in QUIC,
QUIC implementations SHOULD instead use the Retry feature (see Section 8.1 of
{{QUIC-TRANSPORT}}). HelloRetryRequest is still used to request key shares.


## TLS Errors
Expand All @@ -717,7 +726,7 @@ Section 6 of {{!TLS13}}.
A TLS alert is turned into a QUIC connection error by converting the one-byte
alert description into a QUIC error code. The alert description is added to
0x100 to produce a QUIC error code from the range reserved for CRYPTO_ERROR.
The resulting value is sent in a QUIC CONNECTION_CLOSE frame.
The resulting value is sent in a QUIC CONNECTION_CLOSE frame of type 0x1c.

The alert level of all TLS alerts is "fatal"; a TLS stack MUST NOT generate
alerts at the "warning" level.
Expand Down
101 changes: 61 additions & 40 deletions draft-ietf-quic-transport.md
Expand Up @@ -1364,12 +1364,11 @@ by the frames that are typically contained in those packets. So, for instance
the first packet is of type Initial, with packet number 0, and contains a CRYPTO
frame carrying the ClientHello.

Note that multiple QUIC packets -- even of different encryption levels -- may be
Note that multiple QUIC packets -- even of different packet types -- can be
Copy link
Contributor

Choose a reason for hiding this comment

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

Take-it-or-leave-it suggestion: It seems useful to say here that different encryption levels can be coalesced. Perhaps retain this old text here?

coalesced into a single UDP datagram (see {{packet-coalesce}}), and so this
handshake may consist of as few as 4 UDP datagrams, or any number more. For
instance, the server's first flight contains packets from the Initial encryption
level (obfuscation), the Handshake level, and "0.5-RTT data" from the server at
the 1-RTT encryption level.
instance, the server's first flight contains Initial packets,
Handshake packets, and "0.5-RTT data" in 1-RTT packets with a short header.

~~~~
Client Server
Expand All @@ -1390,9 +1389,9 @@ Handshake[0]: CRYPTO[FIN], ACK[0]
{: #tls-1rtt-handshake title="Example 1-RTT Handshake"}

{{tls-0rtt-handshake}} shows an example of a connection with a 0-RTT handshake
and a single packet of 0-RTT data. Note that as described in {{packet-numbers}},
the server acknowledges 0-RTT data at the 1-RTT encryption level, and the
client sends 1-RTT packets in the same packet number space.
and a single packet of 0-RTT data. Note that as described in
{{packet-numbers}}, the server acknowledges 0-RTT data in 1-RTT packets, and
the client sends 1-RTT packets in the same packet number space.

~~~~
Client Server
Expand Down Expand Up @@ -2496,17 +2495,35 @@ level of packet protection to avoid the packet being discarded. After the
handshake is confirmed (see Section 4.1.2 of {{QUIC-TLS}}), an endpoint MUST
send any CONNECTION_CLOSE frames in a 1-RTT packet. However, prior to
confirming the handshake, it is possible that more advanced packet protection
keys are not available to the peer, so the frame MAY be replicated in a packet
that uses a lower packet protection level.
keys are not available to the peer, so another CONNECTION_CLOSE frame MAY be
sent in a packet that uses a lower packet protection level. More specifically:

* A client will always know whether the server has Handshake keys (see
{{discard-initial}}), but it is possible that a server does not know whether
the client has Handshake keys. Under these circumstances, a server SHOULD
send a CONNECTION_CLOSE frame in both Handshake and Initial packets to ensure
that at least one of them is processable by the client.

* A client that sends CONNECTION_CLOSE in a 0-RTT packet cannot be assured of
the server has accepted 0-RTT and so sending a CONNECTION_CLOSE frame in an
Initial packet makes it more likely that the server can receive the close
signal, even if the application error code might not be received.

* Prior to confirming the handshake, a peer might be unable to process 1-RTT
packets, so an endpoint SHOULD send CONNECTION_CLOSE in both Handshake and
1-RTT packets. A server SHOULD also send CONNECTION_CLOSE in an Initial
packet.
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we simplify these 3 points by just saying:
An endpoint SHOULD send a CONNECTION_CLOSE in all encryption levels that it possesses keys for.


Sending a CONNECTION_CLOSE of type 0x1d in an Initial or Handshake packet could
expose application state or be used to alter application state. A
CONNECTION_CLOSE of type 0x1d MUST be replaced by a CONNECTION_CLOSE of type
0x1c when sending the frame in Initial or Handshake packets. Otherwise,
information about the application state might be revealed. Endpoints MUST clear
the value of the Reason Phrase field and SHOULD use the APPLICATION_ERROR code
when converting to a CONNECTION_CLOSE of type 0x1c.

A client will always know whether the server has Handshake keys (see
{{discard-initial}}), but it is possible that a server does not know whether the
client has Handshake keys. Under these circumstances, a server SHOULD send a
CONNECTION_CLOSE frame in both Handshake and Initial packets to ensure that at
least one of them is processable by the client. Similarly, a peer might be
unable to read 1-RTT packets, so an endpoint SHOULD send CONNECTION_CLOSE in
Handshake and 1-RTT packets prior to confirming the handshake. These packets
can be coalesced into a single UDP datagram; see {{packet-coalesce}}.
CONNECTION_CLOSE frames sent in multiple packet types can be coalesced into a
single UDP datagram; see {{packet-coalesce}}.


## Stateless Reset {#stateless-reset}
Expand Down Expand Up @@ -2841,11 +2858,10 @@ successfully authenticated.

All other packets are protected with keys derived from the cryptographic
handshake. The type of the packet from the long header or key phase from the
short header are used to identify which encryption level - and therefore the
keys - that are used. Packets protected with 0-RTT and 1-RTT keys are expected
to have confidentiality and data origin authentication; the cryptographic
handshake ensures that only the communicating endpoints receive the
corresponding keys.
short header are used to identify which encryption keys are used. Packets
protected with 0-RTT and 1-RTT keys are expected to have confidentiality and
data origin authentication; the cryptographic handshake ensures that only the
communicating endpoints receive the corresponding keys.

The packet number field contains a packet number, which has additional
confidentiality protection that is applied after packet protection is applied
Expand All @@ -2870,10 +2886,11 @@ construct PMTU probes (see {{pmtu-probes-src-cid}}). Receivers MUST be able to
process coalesced packets.

Coalescing packets in order of increasing encryption levels (Initial, 0-RTT,
Handshake, 1-RTT) makes it more likely the receiver will be able to process all
the packets in a single pass. A packet with a short header does not include a
length, so it can only be the last packet included in a UDP datagram. An
endpoint SHOULD NOT coalesce multiple packets at the same encryption level.
Handshake, 1-RTT; see Section 4.1.4 of {{QUIC-TLS}}) makes it more likely the
receiver will be able to process all the packets in a single pass. A packet
with a short header does not include a length, so it can only be the last
packet included in a UDP datagram. An endpoint SHOULD NOT coalesce multiple
packets at the same encryption level.

Senders MUST NOT coalesce QUIC packets for different connections into a single
UDP datagram. Receivers SHOULD ignore any subsequent packets with a different
Expand Down Expand Up @@ -3014,13 +3031,13 @@ frames are explained in more detail in {{frame-formats}}.
| 0x19 | RETIRE_CONNECTION_ID | {{frame-retire-connection-id}} | __01 |
| 0x1a | PATH_CHALLENGE | {{frame-path-challenge}} | __01 |
| 0x1b | PATH_RESPONSE | {{frame-path-response}} | __01 |
| 0x1c - 0x1d | CONNECTION_CLOSE | {{frame-connection-close}} | IH_1* |
| 0x1c - 0x1d | CONNECTION_CLOSE | {{frame-connection-close}} | ih01 |
| 0x1e | HANDSHAKE_DONE | {{frame-handshake-done}} | ___1 |
{: #frame-types title="Frame Types"}

The "Packets" column in {{frame-types}} does not form part of the IANA registry
(see {{iana-frames}}). This column lists the types of packets that each
frame type can appear in, indicated by the following characters:
frame type could appear in, indicated by the following characters:

I:

Expand All @@ -3038,11 +3055,10 @@ H:

: 1-RTT ({{short-header}})

*:
ih:

: A CONNECTION_CLOSE frame of type 0x1c can appear in Initial, Handshake, and
1-RTT packets, whereas a CONNECTION_CLOSE of type 0x1d can only appear in a
1-RTT packet.
: A CONNECTION_CLOSE frame of type 0x1d cannot appear in Initial or Handshake
packets.

Section 4 of {{QUIC-TLS}} provides more detail about these restrictions. Note
that all frames can appear in 1-RTT packets.
Expand Down Expand Up @@ -3290,7 +3306,7 @@ containing that information is acknowledged.
* Data sent in CRYPTO frames is retransmitted according to the rules in
{{QUIC-RECOVERY}}, until all data has been acknowledged. Data in CRYPTO
frames for Initial and Handshake packets is discarded when keys for the
corresponding encryption level are discarded.
corresponding packet number space are discarded.

* Application data sent in STREAM frames is retransmitted in new STREAM frames
unless the endpoint has sent a RESET_STREAM for that stream. Once an endpoint
Expand Down Expand Up @@ -4214,9 +4230,9 @@ PADDING, or ACK frames. Handshake packets MAY contain CONNECTION_CLOSE frames.
Endpoints MUST treat receipt of Handshake packets with other frames as a
connection error.

Like Initial packets (see {{discard-initial}}), data in CRYPTO frames at the
Handshake encryption level is discarded - and no longer retransmitted - when
Handshake protection keys are discarded.
Like Initial packets (see {{discard-initial}}), data in CRYPTO frames for
Handshake packets is discarded - and no longer retransmitted - when Handshake
protection keys are discarded.

### Retry Packet {#packet-retry}

Expand Down Expand Up @@ -5680,10 +5696,10 @@ Reason Phrase:
This SHOULD be a UTF-8 encoded string {{!RFC3629}}.

The application-specific variant of CONNECTION_CLOSE (type 0x1d) can only be
sent using an 1-RTT packet ({{QUIC-TLS}}, Section 4). When an application
wishes to abandon a connection during the handshake, an endpoint can send a
CONNECTION_CLOSE frame (type 0x1c) with an error code of 0x15a ("user_canceled"
alert; see {{?TLS13}}) in an Initial or a Handshake packet.
sent using 0-RTT or 1-RTT packets ({{QUIC-TLS}}, Section 4). When an
Copy link
Member

Choose a reason for hiding this comment

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

Good to know that the sentence here forbids CONNECTION_CLOSE (0x1d) being used in Handshake packets. Maybe it's the case that we changed here, but not the other places (that I have pointed out).

Copy link
Member Author

Choose a reason for hiding this comment

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

Well that was a mistake, but now I don't have to fix it :)

application wishes to abandon a connection during the handshake, an endpoint
can send a CONNECTION_CLOSE frame (type 0x1c) with an error code of
APPLICATION_ERROR in an Initial or a Handshake packet.


## HANDSHAKE_DONE frame {#frame-handshake-done}
Expand Down Expand Up @@ -5789,6 +5805,10 @@ PROTOCOL_VIOLATION (0xA):
INVALID_TOKEN (0xB):
: A server received a Retry Token in a client Initial that is invalid.

APPLICATION_ERROR (0xC):

: The application or application protocol caused the connection to be closed.

CRYPTO_BUFFER_EXCEEDED (0xD):

: An endpoint has received more data in CRYPTO frames than it can buffer.
Expand Down Expand Up @@ -6575,6 +6595,7 @@ The initial contents of this registry are shown in {{iana-error-table}}.
| 0x9 | CONNECTION_ID_LIMIT_ERROR | Too many connection IDs received | {{error-codes}} |
| 0xA | PROTOCOL_VIOLATION | Generic protocol violation | {{error-codes}} |
| 0xB | INVALID_TOKEN | Invalid Token Received | {{error-codes}} |
| 0xC | APPLICATION_ERROR | Application error | {{error-codes}} |
| 0xD | CRYPTO_BUFFER_EXCEEDED | CRYPTO data buffer overflowed | {{error-codes}} |
{: #iana-error-table title="Initial QUIC Transport Error Codes Entries"}

Expand Down