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 3 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
164 changes: 71 additions & 93 deletions draft-ietf-quic-tls.md
Expand Up @@ -864,7 +864,7 @@ the Packet Number field. The four least-significant bits of the first byte are
protected for packets with long headers; the five least significant bits of the
first byte are protected for packets with short headers. For both header forms,
this covers the reserved bits and the Packet Number Length field; the Key Update
bits are also protected for packets with a short header.
bit is also protected for packets with a short header.
Copy link
Contributor

Choose a reason for hiding this comment

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

See comments in Key Update section. I would vote for keeping the Key Phase name.


The same header protection key is used for the duration of the connection, with
the value not changing after a key update (see {{key-update}}). This allows
Expand Down Expand Up @@ -1100,55 +1100,45 @@ anticipation of receiving a ClientHello.

# 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 used to protect packets. The Key Update field in the
short header is used to indicate when key updates are permitted and when they
have occurred.
Once the 1-RTT keys are established and confirmed through the use of the
KEYS_READY frame, it is possible to update the keys used to protect packets.
Copy link
Member

Choose a reason for hiding this comment

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

To me, the name KEYS_READY seems to indicate that the keys are about to be used, not that they are in use now. I think I'd prefer something like KEYS_ACTIVE or KEY_IN_USE. Just a personal preference though.


The low bit of the Key Update field (0x04) is the Key Phase bit. The key phase
is used to indicate 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. The
key phase is toggled to signal each key update.
The Key Phase bit is used to indicate which packet protection keys are used to
Copy link
Contributor

Choose a reason for hiding this comment

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

I am confused. Line 866 mentions a Key Update bit, and here we see a Key Phase bit. Is that the same bit, or do we now have 2 bits?

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The Key Phase bit is used to indicate which packet protection keys are used to
The Key Phase bit indicates which packet protection keys are being used to

protect the packet. The Key Phase bit is initially set to 0 for the first set
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
protect the packet. The Key Phase bit is initially set to 0 for the first set
protect the packet. The Key Phase bit is set to 0 for the first set

of 1-RTT packets. The Key Phase bit is toggled to signal each key update.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
of 1-RTT packets. The Key Phase bit is toggled to signal each key update.
of 1-RTT packets and toggled for each subsequent key.


The key phase 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 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. An
endpoint MUST NOT initiate a key update unless they have received a packet with
the current Key Phase and the Key Update Permitted bit set to 1. An endpoint
MAY keep this value set to 0, forbidding key updates. An endpoint MUST NOT set
this value to 1 until it successfully processes a packet with keys from the same
key phase. Once this bit is set it MUST NOT be cleared for packets in the same
key phase.

Only packets that increase the largest received packet number are used to
trigger key updates or changes in the Key Update Permitted bit.
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}}).

{{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.
and @N. Values in brackets \[] indicate the value of Key Phase bit.

~~~
Initiating Peer Responding Peer

@M [10] QUIC Packets
@M [0] QUIC Packets
KEYS_READY
-------->
QUIC Packets [10] @M
QUIC Packets [0] @M
KEYS_READY
<--------
... Update to @N
@N [01] QUIC Packets
@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 [11] @N
QUIC Packets [1] @N
KEYS_READY
<--------
@N [1] QUIC Packets
KEYS_READY
... Key Update Permitted
@N [11] QUIC Packets
-------->
Key Update Permitted ...
~~~
Expand All @@ -1165,87 +1155,75 @@ 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 clears the Key Update Permitted bit, and 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 more than one key update at a time. A subsequent
key update can only be performed after the endpoint has successfully processed a
packet with a matching key phase and the Key Update Permitted bit set.
Together, these indicate that the key update was received and acted on.
The endpoint toggles the value of the Key Phase bit, and uses the updated key
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The endpoint toggles the value of the Key Phase bit, and uses the updated key
The endpoint toggles the value of the Key Phase bit and uses the updated key

and IV to protect all subsequent packets.

Once an endpoint has received and successfully processed packets with the same
key phase, this indicates that the peer has also updated keys. The
endpoint can then set the Key Update Permitted bit to 1 on packets it
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}}.
An endpoint MUST NOT initiate a key update prior to having received a KEYS_READY
frame in a packet from the current key phase. A subsequent key update can only
be performed after the endpoint has successfully processed a KEYS_READY frame
from a packet with a matching key phase. This ensures that keys are available
to both peers before another can be initiated.

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 KEY_UDPATE_ERROR.
Once an endpoint has successfully processed a packet with the same key phase, it
Copy link
Contributor

Choose a reason for hiding this comment

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

"with the same key phase" as what?

can send a KEYS_READY frame. Endpoints MAY defer sending a KEYS_READY frame
after a key update (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 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.
An endpoint that sends a KEYS_READY frame can accept further key updates. A key
update can happen even without seeing a KEYS_READY frame from the peer. If a
packet is received with a key phase that differs from the value the endpoint
used to protect the packet containing its last KEYS_READY frame, the endpoint
creates a new packet protection secret for reading and the corresponding key and
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this always the case? If I was using 0, and now start using 1 and send KEYS_ACTIVE with 1, I will continue to receive packets with key phase 0. That doesn't mean I need to create a new secret, since I haven't discarded the previous secret yet, right?

IV. An endpoint uses the same key derivation process as its peer uses to
generate keys for receiving.

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 can be set to 1 on the next packet
it sends.
{{key-update-initiate}}. An endpoint that responds to a key update MUST send a
KEYS_READY 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 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
connection error of type KEY_UDPATE_ERROR.
has updated keys. The next packet that it sends use the new keys and include
the KEYS_READY frame. If an endpoint detects a second update before it has sent
any packets with updated keys or a KEYS_READY 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.
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're going to mention this last, it's probably worth expanding on this a bit. What behavior might generate such a side-channel? How are dummy keys used to emulate normal behavior in those cases?

Copy link
Member Author

Choose a reason for hiding this comment

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

Text added.



## 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.
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.

After a key update, an endpoint MAY delay sending the KEYS_READY 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 that use the Key Phase bit; endpoints MUST NOT defer
sending of KEYS_READY 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.

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.
Even if old keys are available, those keys MUST NOT be used to protect packets
with packets that have higher packet numbers than packets that were protected
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
with packets that have higher packet numbers than packets that were protected
that have higher packet numbers than packets that were protected

with newer keys. An endpoint that successfully removes protection with 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.

Would it make sense to mandate dropping write keys immediately, but permit retaining read keys?

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 don't want to mandate dropping keys so directly, but I will mention that it is possible. Note that there are cases during the handshake where write keys for different packet number spaces need to be kept. So this would be limited to key update.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why? It seems appropriate to close the connection here.

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.

An endpoint MAY keep the Key Update Permitted bit set to 0 until it discards old
read keys to limit the number of keys it maintains. An endpoint MAY also
prevent key update until it discards keys from the handshake, including any
0-RTT keys. An endpoint SHOULD set the Key Update Permitted bit when possible.

Once set, the Key Update Permitted bit MUST NOT be cleared for packets with the
same key phase. An endpoint MAY treat receipt of a packet with the Key Update
Permitted bit cleared as a connection error of type KEY_UPDATE_ERROR if the bit
was previously set on packets protected with the same keys.

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.
the current PTO. After this period, old read keys and their corresponding
secrets SHOULD be discarded.

An endpoint that receives a packet protected with old keys that includes an
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: "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 ..."

acknowledgement for a packet protected with newer keys MAY treat that as a
connection error of type KEY_UPDATE_ERROR.


## Key Update Frequency
Expand Down