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 all 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
212 changes: 153 additions & 59 deletions draft-ietf-quic-tls.md
Expand Up @@ -1097,78 +1097,169 @@ TLS ClientHello. The server MAY retain these packets for later decryption in
anticipation of receiving a ClientHello.


# Key Update
# Key Update {#key-update}

Once the 1-RTT keys are established and the short header is in use, it is
possible to update the keys. The KEY_PHASE bit in the short header is used to
indicate whether key updates have occurred. The KEY_PHASE bit is initially set
to 0 and then inverted with each key update.
Once the 1-RTT keys are established and confirmed through the use of the
KEYS_ACTIVE frame, it is possible to update the keys used to protect packets.

The KEY_PHASE bit allows a recipient to detect a change in keying material
without necessarily 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.
The Key Phase bit indicates which packet protection keys are used to protect the
packet. The Key Phase bit is initially set to 0 for the first set of 1-RTT
packets and toggled to signal each subsequent 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 updates keys and decrypts the
packet that contains the changed value.

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}}).

An endpoint MUST NOT initiate more than one key update at a time. A new key
cannot be used until the endpoint has received and successfully decrypted a
packet with a matching KEY_PHASE.

A receiving endpoint detects an update when the KEY_PHASE bit does not match
what it is expecting. It creates a new secret (see Section 7.2 of {{!TLS13}})
and the corresponding read key and IV using the KDF function provided by TLS.
The header protection key is not updated.

If the packet can be decrypted and authenticated using the updated key and IV,
then the keys the endpoint uses for packet protection are also updated. The
next packet sent by the endpoint will then use the new keys.

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.

An endpoint SHOULD retain old keys for a period of no more than three times the
Probe Timeout (PTO, see {{QUIC-RECOVERY}}). After this period, old keys and
their corresponding secrets SHOULD be discarded. Retaining keys allow 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.

This 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 a short time frame 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 Phase bit.

~~~
Initiating Peer Responding Peer

@M QUIC Frames
New Keys -> @N
@N QUIC Frames
@M [0] QUIC Packets
KEYS_ACTIVE
-------->
QUIC Frames @M
New Keys -> @N
QUIC Frames @N
QUIC Packets [0] @M
KEYS_ACTIVE
<--------
... Update to @N
@N [1] QUIC Packets
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a bit confusing. The KEYS_ACTIVE sent above are for @m, right? If so, shouldn't the endpoint send a KEYS_ACTIVE for @n as soon as it updates to the new keys (on line 1133)?

Copy link
Member Author

Choose a reason for hiding this comment

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

During a key update, the initiator doesn't update until it receives a packet in the new keys. If we sent the frame in the first packet we'd get the simultaneous update problem.

That makes me a little more receptive to the idea that @kazuho suggests on the mailing list, but not much more. Having special rules for Handshake isn't a huge burden.

p.s., I'm sure that github users @M and @N get pinged all the time.

Copy link
Contributor

Choose a reason for hiding this comment

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

Poor Matt Mullenweg.... 😁

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

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.

## 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
and using that to protect new packets. The endpoint creates a new write secret
from the existing write secret as performed in Section 7.2 of {{!TLS13}}. This
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 toggles the value of the Key Phase bit and uses the updated key and
IV to protect all subsequent packets.

An endpoint MUST NOT initiate a key update prior to having received and
successfully processed a KEYS_ACTIVE frame contained in a packet from the
current key phase. This ensures that keys are available to both peers before
another can be initiated.

Note:

: Changes in keys from Initial to Handshake and from Handshake to 1-RTT don't
use this key update process. Key changes during the handshake do not need to
wait for a KEYS_ACTIVE frame, they are driven solely by changes in the TLS
handshake. The KEYS_ACTIVE frame is used to allow Initial and Handshake keys
to be discarded when they are no longer needed and - in the case of the first
1-RTT key phase - to enable the first key update.

The endpoint that initiates a key update also updates the keys that it uses for
receiving packets. These keys will be needed to process packets the peer sends
after updating. An endpoint needs to retain old keys so that packets sent by
the peer prior to receiving the key update can be processed. Once an endpoint
has successfully processed a packet using the new keys, it MUST send a
KEYS_ACTIVE frame, though endpoints MAY defer sending the frame (see
{{key-update-old-keys}}).

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

An endpoint that sends a KEYS_ACTIVE frame can accept further key updates. A
key update can happen even without seeing a KEYS_ACTIVE frame from the peer. If
a packet is received with a key phase that differs from the value the endpoint
used to protect the last packet it sent, the endpoint creates a new packet
protection secret for reading and the corresponding key and IV. An endpoint
uses the same key derivation process as its peer uses to generate keys for
receiving.

If the packet is successfully processed using the updated key and IV, then the
keys the endpoint initiates a key update in response, as described in
{{key-update-initiate}}. An endpoint that responds to a key update MUST send a
KEYS_ACTIVE frame to indicate that it is both sending and receiving with updated
keys, though it MAY defer sending the frame (see {{key-update-old-keys}}).

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 use the new keys and include
the KEYS_ACTIVE frame. If an endpoint detects a second update before it has
sent any packets with updated keys or a KEYS_ACTIVE frame, it indicates that its
peer has updated keys twice without awaiting a reciprocal update. An endpoint
MUST treat consecutive key updates as a connection error of type
KEY_UPDATE_ERROR.

Endpoints responding to an apparent key update MUST NOT generate a timing
side-channel signal that might indicate that the Key Phase bit was invalid (see
{{header-protect-analysis}}). Endpoints can use dummy packet protection keys in
place of discarded keys when key updates are not permitted; using dummy keys
Copy link
Contributor

Choose a reason for hiding this comment

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

If this were to happen, wouldn't the connection be closed with a KEY_UPDATE_ERROR? Is there much value in the timing signal at this point?

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 packets can be injected.

will generate no variation in the timing signal produced by attempting to remove
packet protection, but all packets with an invalid Key Phase bit will be
rejected.

An endpoint might not receive an acknowledgment for the packet that contains a
KEYS_ACTIVE before receiving another key update.


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

During a key update, packets protected with older keys might arrive if they were
delayed by the network. If those old keys are available, then they can be used
to remove packet protection.

An endpoint always sends packets that are protected with the newest keys. Keys
used for protecting packets that an endpoint sends can be discarded immediately
after newer keys are available.

After a key update, an endpoint MAY delay sending the KEYS_ACTIVE frame by up to
three times the Probe Timeout (PTO, see {{QUIC-RECOVERY}}) to minimize the
number of active keys it maintains. During this time, an endpoint can use old
keys to process delayed packets rather than enabling a new key update. This
only applies to key updates; endpoints MUST NOT defer sending of KEYS_ACTIVE
during and immediately after the handshake.

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.

Even if old keys are available, those keys MUST NOT be used to protect 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 current PTO. After this period, old read keys and their corresponding
secrets SHOULD be discarded.

An endpoint that receives an acknowledgement for a packet protected with new
keys in a packet protected with older keys MAY treat that as a connection error
of type KEY_UPDATE_ERROR.


## Key Update Frequency

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 @@ -1394,15 +1485,15 @@ authenticated using packet protection; the entire packet header is part of the
authenticated additional data. Protected fields that are falsified or modified
can only be detected once the packet protection is removed.

An attacker could guess values for packet numbers and have an endpoint confirm
guesses through timing side channels. Similarly, guesses for the packet number
length can be trialed and exposed. If the recipient of a packet discards
packets with duplicate packet numbers without attempting to remove packet
protection they could reveal through timing side-channels that the packet number
matches a received packet. For authentication to be free from side-channels,
the entire process of header protection removal, packet number recovery, and
packet protection removal MUST be applied together without timing and other
side-channels.
An attacker could guess values for packet numbers or key phase and have an
endpoint confirm guesses through timing side channels. Similarly, guesses for
the packet number length can be trialed and exposed. If the recipient of a
packet discards packets with duplicate packet numbers without attempting to
remove packet protection they could reveal through timing side-channels that the
packet number matches a received packet. For authentication to be free from
side-channels, the entire process of header protection removal, packet number
recovery, and packet protection removal MUST be applied together without timing
and other side-channels.

For the sending of packets, construction and protection of packet payloads and
packet numbers MUST be free from side-channels that would reveal the packet
Expand Down Expand Up @@ -1441,6 +1532,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