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

Rework Key Update #2237

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
141 changes: 96 additions & 45 deletions draft-ietf-quic-tls.md
Expand Up @@ -1101,40 +1101,58 @@ anticipation of receiving a ClientHello.
# Key Update

Once the 1-RTT keys are established and the short header is in use, it is
possible to update the keys used to protect packets. The Key Phase bits in the
short header are used to indicate whether key updates have occurred. The
Key Phase is initially set to 0 and then incremented with each key update.
possible to update the keys used to protect packets. The Key Update field in the
short header are used to indicate when key updates are permitted and when they
Copy link
Contributor

Choose a reason for hiding this comment

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

s/are/is/

have occurred.

The Key Phase allows a recipient to detect a change in keying material
The the low bit of the Key Update field (0x04) is the Key Phase bit. The Key
Copy link
Member

Choose a reason for hiding this comment

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

"The the"

Phase is used to indicate which packet protection keys are in use. The Key
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe better: "which packet protection key was used to protect this packet."

Phase bit is initially set to 0 for the first set of 1-RTT packets. The Key
Phase is toggled to signal each key update.

The Key Phase bit allows a recipient to detect a change in keying material
without needing to receive the first packet that triggered the change. An
endpoint that notices a changed Key Phase bit can update keys and decrypt the
packet that contains the changed bit.
endpoint that notices a changed Key Phase updates keys and decrypts the packet
that contains the changed value.


The high bit of the Key Update field (0x08) is the Key Update Permitted bit.
Endpoints set this value to 0 until they successfully process a packet with keys
Copy link

Choose a reason for hiding this comment

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

As written, this seems to imply that Endpoints must set the value to 1 when they successfully process a packet. I agree with Ian that there will be cases where this is set to 0 and never changed (e.g. when the expected flow size is short). Perhaps this would work instead:

"The high bit of the Key Update field (0x08) is the Key Update Permitted bit. Endpoints may set this value to 0 for any reason, forbidding Key Updates. Endpoint MUST NOT set this value to 1 until they successfully process a packet the largest received packet number with keys from the same key phase as they are using. They MAY set it to 1 to indicate key update is permitted at any time after that."

from the same key phase as they are using to send. An endpoint MUST NOT
initiate a key update until it receives a packet with the Key Update Permitted
bit set.

Only packets that increase the largest received packet number are used to
trigger key updates or changes in the Key Update Permitted bit.

This mechanism replaces the TLS KeyUpdate message. Endpoints MUST NOT send a
TLS KeyUpdate message. Endpoints MUST treat the receipt of a TLS KeyUpdate
message as a connection error of type 0x10a, equivalent to a fatal TLS alert of
unexpected_message (see {{tls-errors}}).

This process ensures that once the handshake is complete, packets with the same
Key Phase will have the same packet protection keys, unless there are multiple
key updates in short succession and significant packet reordering.
{{ex-key-update}} shows a key update process, with keys used identified with @M
and @N. Values in brackets [] indicate the value of Key Update bits.

~~~
Initiating Peer Responding Peer

@M QUIC Frames
New Keys -> @N
@N QUIC Frames
@M [10] QUIC Packets
. Update to @N
@N [01] QUIC Packets
-------->
QUIC Frames @M
New Keys -> @N
QUIC Frames @N
QUIC Packets [10] @M
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this line here? The responding peer should update the keys immediately when receiving the first @n packet.

Update to @N .
QUIC Packets [11] @N
<--------
. Key Update Permitted
@N [11] QUIC Packets
-------->
Key Update Permitted .
~~~
{: #ex-key-update title="Key Update"}


## Initiating a Key Update
## Initiating a Key Update {#key-update-initiate}

Endpoints maintain separate read and write secrets for packet protection. An
endpoint initiates a key update by updating its packet protection write secret
Expand All @@ -1144,54 +1162,78 @@ uses the KDF function provided by TLS with a label of "quic ku". The
corresponding key and IV are created from that secret as defined in
{{protection-keys}}. The header protection key is not updated.

The endpoint uses the key and IV to protect all subsequent packets, and
increments the value of the Key Phase bits modulo 4 in the short packet header
to signal the change of keys.
The endpoint uses the key and IV to protect all subsequent packets, clears the
Key Update Permitted bit, and toggles the value of the low Key Phase bit.
Copy link
Contributor

Choose a reason for hiding this comment

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

This sentence reads better if you turn it around and insert an "updated": "The endpoint clears the Key Update Permitted bit, and toggles the value of the low Key Phase bit, and uses the updated key and IV to protect all subsequent packets."


An endpoint MUST NOT initiate more than one key update at a time. A new key
cannot be used until the endpoint has received an indication that its peer is
using the same key phase.
cannot be used until the endpoint has successfully processed a packet with a
Copy link
Contributor

Choose a reason for hiding this comment

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

Better: A subsequent key update can only be performed once the endpoint...

matching Key Phase and the Key Update Permitted bit set. Together, these
indicate that the key update was received and acted on.

Once an endpoint has received and successfully processed packets with the same
Key Phase value, this indicates that the peer has also updated keys. The
endpoint can then set the Key Update Permitted bit to 1 on packets it
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer stronger language here. Ideally, a MUST (although we'd have to rearrange the text a bit to allow deferring this until the old keys are discarded).

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I struggled with this too. I want people to enable key updates, but the fact is that we can't really enforce it. If we didn't want to allow peers to minimize the number of active keys, you could allow endpoints to punish them if they acknowledged a packet with a matching key phase in a packet that didn't include the Key Update Permitted bit. I will try to work in a SHOULD somehow.

subsequently sends. An endpoint MUST NOT set Key Update Permitted to 1 on
packets it sends unless it has successfully processed packets with a matching
Key Phase. An endpoint MAY defer setting Key Update Permitted to 1 until it has
discarded old keys, see {{key-update-old-keys}}.

Using Key Update Permitted in this manner guarantees at least one round trip
between updates, preventing multiple updates that could result in endpoints
being unable to process any packets.

An endpoint that receives a packet protected with old keys that includes an
acknowledgement for a packet protected with newer keys MAY treat that as a
connection error of type PROTOCOL_VIOLATION.
connection error of type KEY_UDPATE_ERROR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I assume that "processed a packet" means "received, successfully decrypted, and processed the content of the frames." But I have to guess. Encrypting and sending is a form of processing too. The term first occurs in section 8.1, and it is a bit puzzling there too. I would suggest adding a formal definition in "1.2. Terms and Definitions ".

Copy link
Contributor

Choose a reason for hiding this comment

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

A lot of that text is going to be specified again in the following paragraphs. Do we need a paraphrase here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Initial to Handshake, and Handshake to 1-RTT. Are these special cases of Key Update?

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've added a note about the handshake to clear that up. Logically, they are the same, but there is nothing to be gained by delaying the signal, or by requiring that the signal be used before a key change can be made.


## Responding to a Key Update

A receiving endpoint detects an update when the Key Phase is one greater than
what it is expecting. The endpoint creates a new read secret and the
corresponding read key and IV using the same process as its peer.

A packet with a Key Phase other than the expected or next value MUST be
discarded. However, endpoints MUST NOT generate a timing side-channel signal
that might indicate that this specific field was invalid (see
{{header-protect-analysis}}).
An endpoint that sets Key Update Permitted to 1 on packets it sends is willing
to accept key updates. If a packet is received with a Key Phase that differs
from the value the endpoint expects, the endpoint creates a new packet
protection secret for reading and the corresponding key and IV. The endpoint
uses the same key derivation process as its peer uses to generate keys for
receiving.

If the packet can be decrypted and authenticated using the updated key and IV,
then the keys the endpoint uses for packet protection (the write secret) are
also updated using the same KDF and label as for the read secret. The next
packet sent by the endpoint MUST use the new packet protection keys.
If the packet protection is successfully removed using the updated key and IV,
then the keys the endpoint initiates a key update in response, as described in
{{key-update-initiate}}. However, as packets with a matching Key Phase have
been received, the Key Update Permitted bit MAY be set to 1 on the next packet
it sends.

Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't that a restatement of the lines 1167-1169? Why do we have the same text twice, with slightly different phrasing, "processed" vs. "packet protection is successfully removed" ?

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 difference intended. I've tried to even this out.

An endpoint does not always need to send packets when it detects that its peer
has updated keys. The next packet that it sends will simply use the new keys.
If an endpoint detects a second update before it has sent any packets with
updated keys, it indicates that its peer has updated keys twice without awaiting
a reciprocal update. An endpoint MUST treat consecutive key updates as a fatal
error and abort the connection.
a reciprocal update. An endpoint MUST treat consecutive key updates as a
connection error of type KEY_UDPATE_ERROR.


## Using Old Keys {#key-update-old-keys}

If the most recent packet sent by the endpoint contained a Key Update Permitted
bit set to 0, a Key Phase other than the value expected indicates that the
packet was protected with old keys. If those old keys are available, then they
can be used to remove packet protection.

Copy link
Contributor

Choose a reason for hiding this comment

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

"key updates that use the Key Phase bit". That's a weird way to put it. Maybe a reference to the ladder diagram in the transport spec?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe "after the handshake is complete," assuming that's now a defined term?

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've tried very hard to separate key update as a concept from the key changes that happen during the handshake. So I'll remove the 'that use the Key Phase bit' part.

Old keys might be used to remove protection from packets that were are reordered
in the network. However, it is never valid for old keys to be used to protect
packets with packets that have higher packet numbers than packets that were
protected with newer keys. An endpoint that successfully removes protection
with old keys when newer keys were used for packets with lower packet numbers
MUST treat this as a connection error of type KEY_UPDATE_ERROR.

An endpoint SHOULD retain old read keys for a period of no more than three times
the Probe Timeout (PTO, see {{QUIC-RECOVERY}}). After this period, old read
keys and their corresponding secrets SHOULD be discarded. Retaining keys allows
endpoints to process packets that were sent with old keys and delayed in the
network. Packets with higher packet numbers always use the updated keys and
MUST NOT be decrypted with old keys.
keys and their corresponding secrets SHOULD be discarded. An endpoint MAY keep
the Key Update Permitted bit set to 0 until it discards old read keys to limit
Copy link
Member

Choose a reason for hiding this comment

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

How about explicitly stating "until it discards the 0-RTT key or the previous 1-RTT read key" here, to be clear that we can have the Key Update Permitted bit set to zero until the 0-RTT key is discarded when 0-RTT is used.

the number of keys it maintains.

A packet that triggers a key update could arrive after successfully processing a
packet with a higher packet number. This is only possible if there is a key
compromise and an attack, or if the peer is incorrectly reverting to use of old
keys. Because the latter cannot be differentiated from an attack, an endpoint
MUST immediately terminate the connection if it detects this condition.
Endpoints MUST NOT generate a timing side-channel signal that might indicate
that the Key Update field was invalid (see {{header-protect-analysis}}).
Endpoints can use dummy packet protection keys in place of discarded keys when
key updates are not permitted.


## Key Update Frequency
Expand All @@ -1200,6 +1242,12 @@ In deciding when to update keys, endpoints MUST NOT exceed the limits for use of
specific keys, as described in Section 5.5 of {{!TLS13}}.


## Key Update Error Code {#key-update-error}

The KEY_UPDATE_ERROR error code (0xD) is used to signal errors related to key
updates.


# Security of Initial Messages

Initial packets are not protected with a secret key, so they are subject to
Expand Down Expand Up @@ -1425,6 +1473,9 @@ values in the following registries:
Recommended column is to be marked Yes. The TLS 1.3 Column is to include CH
and EE.

* QUIC Error Codes Registry {{QUIC-TRANSPORT}} - IANA is to register the
KEY_UPDATE_ERROR (0xD), as described in {{key-update-error}}.


--- back

Expand Down
90 changes: 21 additions & 69 deletions draft-ietf-quic-transport.md
Expand Up @@ -3471,65 +3471,18 @@ See {{QUIC-INVARIANTS}} for details on how packets from different versions of
QUIC are interpreted.

The interpretation of the fields and the payload are specific to a version and
packet type. Type-specific semantics for this version are described in the
following sections.

The end of the packet is determined by the Length field. The Length field
covers both the Packet Number and Payload fields, both of which are
confidentiality protected and initially of unknown length. The length of the
Payload field is learned once header protection is removed. The Length field
enables packet coalescing ({{packet-coalesce}}).


## Short Header Packet {#short-header}

~~~~~
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+
|0|1|S|R| K | P |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Connection ID (0..144) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Packet Number (8/16/24/32) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Protected Payload (*) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~~~~~
{: #fig-short-header title="Short Header Packet Format"}

The short header can be used after the version and 1-RTT keys are negotiated.
Packets that use the short header contain the following fields:

Header Form:

: The most significant bit (0x80) of byte 0 is set to 0 for the short header.

Fixed Bit:

: The next bit (0x40) of byte 0 is set to 1. Packets containing a zero value
for this bit are not valid packets in this version and MUST be discarded.

Spin Bit (S):

: The sixth bit (0x20) of byte 0 is the Latency Spin Bit, set as described in
{{!SPIN=I-D.ietf-quic-spin-exp}}.
packet type. While type-specific semantics for this version are described in
the following sections, several long-header packets in this version of QUIC
contain these additional fields:

Reserved Bit (R):
Copy link
Contributor

Choose a reason for hiding this comment

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

It's still two bits.


: The next bit (0x10) of byte 0 is reserved. This bit is protected using header
protection (see Section 5.4 of {{QUIC-TLS}}). The value included prior to
protection MUST be set to 0. An endpoint MUST treat receipt of a packet that
has a non-zero value for this bit after removing protection as a connection
error of type PROTOCOL_VIOLATION.

Key Phase (K):

: The next two bits (those with a mask of 0x0c) of byte 0 indicate the key
phase, which allows a recipient of a packet to identify the packet protection
keys that are used to protect the packet. See {{QUIC-TLS}} for details.
These bits are protected using header protection (see Section 5.4 of
{{QUIC-TLS}}).
: Two bits (those with a mask of 0x0c) of byte 0 are reserved across multiple
packet types. These bits are protected using header protection (see Section
5.4 of {{QUIC-TLS}}). The value included prior to protection MUST be set to 0.
An endpoint MUST treat receipt of a packet that has a non-zero value for these
bits after removing protection as a connection error of type
PROTOCOL_VIOLATION.

Packet Number Length (P):

Expand Down Expand Up @@ -3945,7 +3898,7 @@ short packet header.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+
|0|1|S|R|R|K|P P|
|0|1|S|R|K K|P P|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated change.

| Destination Connection ID (0..144) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Expand Down Expand Up @@ -3973,21 +3926,20 @@ Spin Bit (S):
: The sixth bit (0x20) of byte 0 is the Latency Spin Bit, set as described in
{{!SPIN=I-D.ietf-quic-spin-exp}}.

Reserved Bits (R):
Reserved Bit (R):

: The next two bits (those with a mask of 0x18) of byte 0 are reserved. These
bits are protected using header protection (see Section 5.4 of
{{QUIC-TLS}}). The value included prior to protection MUST be set to 0. An
endpoint MUST treat receipt of a packet that has a non-zero value for these
bits after removing protection as a connection error of type
PROTOCOL_VIOLATION.
: The next bit (0x10) of byte 0 is reserved. This bit is protected using header
protection (see Section 5.4 of {{QUIC-TLS}}). The value included prior to
protection MUST be set to 0. An endpoint MUST treat receipt of a packet that
has a non-zero value for these bits after removing protection as a connection
error of type PROTOCOL_VIOLATION.

Key Phase (K):
Key Update (K):

: The next bit (0x04) of byte 0 indicates the key phase, which allows a
recipient of a packet to identify the packet protection keys that are used to
protect the packet. See {{QUIC-TLS}} for details. This bit is protected
using header protection (see Section 5.4 of {{QUIC-TLS}}).
: The next two bits (0x0c) of byte 0 are used to control key updates. These
bits are used by the recipient of a packet to identify the keys that are used
to protect the packet. See {{QUIC-TLS}} for details. These bits are
protected using header protection (see Section 5.4 of {{QUIC-TLS}}).

Packet Number Length (P):

Expand Down