Subject: KEYS_READY

From: Martin Thomson <[email-masked]>
Date: Wed, 13 Feb 2019 12:45:55 +1100

https://github.com/quicwg/base-drafts/pull/2237 has been updated to include the discussed new frame.

This allows us to remove the implicit-ish acknowledgment of Initial packets, fix the problem Marten identified with discarding Handshake keys, and the problem Kazuho found with multiple and simultaneous key updates.

There were two designs that were valid here, and I want to ensure that people think about the choice:

The one I chose to write up uses a design like ACK.  The keys used to protect the packet determine how the frame is interpreted.  That is, KEYS_READY in a packet implies that the corresponding keys are in use.  The cost here is that you have to purge any potential retransmissions of KEYS_READY when you update keys or you risk creating a false signal.

The alternative involves more explicit signaling, and requires us to label each set of keys unambiguously.  For that we could borrow the DTLS epoch convention, though that is inconveniently out of phase with the Key Phase we use; not a major issue, but a little hard to reason about.  This doesn't have a retransmission problem, but in addition to the need to document the counting system, we would need to decide whether a mismatch between frame and packet is OK, or something that can produce a connection error.

Obviously, I have a preference for the former, but if people feel differently, this is a good place to register your reasons.

Editorial concerns should be directed toward the pull request.

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 13 Feb 2019 14:55:22 +0900

Hi, Martin

Thank you for writing the PR. My comments inline.

2019年2月13日(水) 10:46 Martin Thomson <[email-masked]>:
> The alternative involves more explicit signaling, and requires us to label each set of keys unambiguously.

My weak preference goes to burning a bit in the first byte (we have
reserved bits in all the necessary packet types) due to the
exceptional retransmission rule that we would have for the frame, but
I'm not sure how much I care.

> For that we could borrow the DTLS epoch convention, though that is inconveniently out of phase with the Key Phase we use; not a major issue, but a little hard to reason about.  This doesn't have a retransmission problem, but in addition to the need to document the counting system, we would need to decide whether a mismatch between frame and packet is OK, or something that can produce a connection error.
>

-- 
Kazuho Oku

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Wed, 13 Feb 2019 00:36:11 -0800

Thanks for pointing out the second alternative, although reluctantly.

I think the first option with anonymous KEY_READY has a problem with
idempotency as well as tying state to retransmission logic. This means that
naive retransmission of packet content in a new packet number is no longer
valid, and likewise, naive processing of a frame that passes authentication
is also no longer possible. That is a strong principle break and I don’t
think the minor simplicity of a label-less KEY_READY frame can justify that
(even if one ought no do such naive transmission).

You could state that the KEY_PHASE bit is the lower bit the key counter
which increments by one on each key update, starting at 0 or 1.
Then, a KEY_READY with a future count is a PROTOCOL_VIOLATION and an old
count is ignored. The key phase or the packet protection of the packet
containing the KEY_READY frame is of no significance.

I also suspect that the alternatively two-bit proposal might have a problem
with idempotency, but I think it sorts itself by failing packet protection.

The text mentions that the updated key depends on the current traffic key
with reference to TLS 1.3. From reading this naively, it sounds like
forward secrecy is lost, which I am sure it is not.

Finally, this is just a high level view. I find the overall text hard to
understand, notably because it is not crystal clear whether the two
endpoints update their transmission keys in sync with the ready keys, or if
the (currently implicity) key phase counters can count independently.

That said, I like the idea of an explicit READY frame, and i probably would
also like and explicit handshake ready frame, if it isn’t effectively the
same thing, and if it is, perhaps formalise that.

Mikkel

On 13 February 2019 at 06.55.57, Kazuho Oku ([email-masked]) wrote:

Hi, Martin

2019年2月13日(水) 10:46 Martin Thomson <[email-masked]>:
> This allows us to remove the implicit-ish acknowledgment of Initial
packets, fix the problem Marten identified with discarding Handshake keys,
and the problem Kazuho found with multiple and simultaneous key updates.
> The one I chose to write up uses a design like ACK. The keys used to
protect the packet determine how the frame is interpreted. That is,
KEYS_READY in a packet implies that the corresponding keys are in use. The
cost here is that you have to purge any potential retransmissions of
KEYS_READY when you update keys or you risk creating a false signal.

> For that we could borrow the DTLS epoch convention, though that is
inconveniently out of phase with the Key Phase we use; not a major issue,
but a little hard to reason about. This doesn't have a retransmission
problem, but in addition to the need to document the counting system, we
would need to decide whether a mismatch between frame and packet is OK, or
something that can produce a connection error.
>
> Obviously, I have a preference for the former, but if people feel
differently, this is a good place to register your reasons.

-- 
Kazuho Oku

---

From: Marten Seemann <[email-masked]>
Date: Wed, 13 Feb 2019 20:59:37 +0800

I went through a few key update scenarios under different packet loss
patterns, and I have to admit that I found the KEY_READY frame surprisingly
difficult to reason about. The problem seems to be that we're replacing
what is in reality a contiguous state (it is permitted to update the keys)
with a one-time signal, which has to be retransmitted (taking care to
either block further key updates until this frame has been acknowledged, or
canceling the retransmission when performing another key update). The
reason we decided to create an explicit signal instead of consulting the
loss recovery state, was that we wanted to avoid a tight coupling between
the loss recovery and the key management. I have the impression that we're
now just trading one tight coupling for a slightly different one.

I agree with Kazuho that using a bit in the first byte seems to capture the
update logic we're looking for better. There's no need to retransmit any
information, since the bit is set on every subsequent packet.

On Wed, Feb 13, 2019 at 4:36 PM Mikkel Fahnøe Jørgensen <[email-masked]>
wrote:

> I also suspect that the alternatively two-bit proposal might have a
> problem with idempotency, but I think it sorts itself by failing packet
> protection.
>
> That said, I like the idea of an explicit READY frame, and i probably
> would also like and explicit handshake ready frame, if it isn’t effectively
> the same thing, and if it is, perhaps formalise that.
>
> Mikkel
>

---

From: Ian Swett <[email-masked]>
Date: Wed, 13 Feb 2019 10:03:19 -0500

I'm happy with the approach you outline here and wrote up in the PR, but I
did find the PR a bit confusing, partially because it's based on an
existing PR that's gone through a lot of revisions.

I don't think tying transmission of this to an encryption level will be
overly complex, because since it's only a single byte, I might just put it
in every ack-eliciting packet until it's no longer necessary and not use
the standard retransmission logic.

I'd rather not burn another bit in the first byte for this.

On Wed, Feb 13, 2019 at 8:00 AM Marten Seemann <[email-masked]>
wrote:

> I agree with Kazuho that using a bit in the first byte seems to capture
> the update logic we're looking for better. There's no need to retransmit
> any information, since the bit is set on every subsequent packet.
>
>
>
> On Wed, Feb 13, 2019 at 4:36 PM Mikkel Fahnøe Jørgensen <
> [email-masked]> wrote:
>

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 14 Feb 2019 00:26:51 +0900

2019年2月14日(木) 0:03 Ian Swett <[email-masked]>:
>
> I'm happy with the approach you outline here and wrote up in the PR, but I did find the PR a bit confusing, partially because it's based on an existing PR that's gone through a lot of revisions.
>
> I don't think tying transmission of this to an encryption level will be overly complex, because since it's only a single byte, I might just put it in every ack-eliciting packet until it's no longer necessary and not use the standard retransmission logic.

I tend to agree, because to me it the same as having a variable length
packet header that, when being extended by one byte, indicates that
the next key is ready. Though it seems a bit flexible.

OTOH, I think it's interesting to discuss if the KEY_READY frame is
ack-eliciting. My understanding is that per the current PR it is,
because the list of non-ack-eliciting frames has not changed.

I can see arguments for having the frame defined as ACK-eliciting,
because it encourages endpoints to retire old keys soon. If we think
that to be a good property, I think that might be an argument for
using a frame (because calling a header bit ACK-eliciting would be
strange).

> On Wed, Feb 13, 2019 at 8:00 AM Marten Seemann <[email-masked]> wrote:
>>
>> I went through a few key update scenarios under different packet loss patterns, and I have to admit that I found the KEY_READY frame surprisingly difficult to reason about. The problem seems to be that we're replacing what is in reality a contiguous state (it is permitted to update the keys) with a one-time signal, which has to be retransmitted (taking care to either block further key updates until this frame has been acknowledged, or canceling the retransmission when performing another key update). The reason we decided to create an explicit signal instead of consulting the loss recovery state, was that we wanted to avoid a tight coupling between the loss recovery and the key management. I have the impression that we're now just trading one tight coupling for a slightly different one.
>>
>> I agree with Kazuho that using a bit in the first byte seems to capture the update logic we're looking for better. There's no need to retransmit any information, since the bit is set on every subsequent packet.
>>
>>
>>
>> On Wed, Feb 13, 2019 at 4:36 PM Mikkel Fahnøe Jørgensen <[email-masked]> wrote:
>>>
>>> I think the first option with anonymous KEY_READY has a problem with idempotency as well as tying state to retransmission logic. This means that naive retransmission of packet content in a new packet number is no longer valid, and likewise, naive processing of a frame that passes authentication is also no longer possible. That is a strong principle break and I don’t think the minor simplicity of a label-less KEY_READY frame can justify that (even if one ought no do such naive transmission).
>>>
>>> You could state that the KEY_PHASE bit is the lower bit the key counter which increments by one on each key update, starting at 0 or 1.
>>> Then, a KEY_READY with a future count is a PROTOCOL_VIOLATION and an old count is ignored. The key phase or the packet protection of the packet containing the KEY_READY frame is of no significance.
>>>
>>> I also suspect that the alternatively two-bit proposal might have a problem with idempotency, but I think it sorts itself by failing packet protection.
>>>
>>> The text mentions that the updated key depends on the current traffic key with reference to TLS 1.3. From reading this naively, it sounds like forward secrecy is lost, which I am sure it is not.
>>>
>>> Finally, this is just a high level view. I find the overall text hard to understand, notably because it is not crystal clear whether the two endpoints update their transmission keys in sync with the ready keys, or if the (currently implicity) key phase counters can count independently.
>>>
>>> That said, I like the idea of an explicit READY frame, and i probably would also like and explicit handshake ready frame, if it isn’t effectively the same thing, and if it is, perhaps formalise that.
>>>
>>> Mikkel
>>>

-- 
Kazuho Oku

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Wed, 13 Feb 2019 07:29:28 -0800

It cannot not be ACK-eliciting, otherwise a lost packet could mean that no
new key updates would be possible.

On 13 February 2019 at 16.27.02, Kazuho Oku ([email-masked]) wrote:

2019年2月14日(木) 0:03 Ian Swett <[email-masked]>:
>
> I'm happy with the approach you outline here and wrote up in the PR, but
I did find the PR a bit confusing, partially because it's based on an
existing PR that's gone through a lot of revisions.

>>> Then, a KEY_READY with a future count is a PROTOCOL_VIOLATION and an
old count is ignored. The key phase or the packet protection of the packet
containing the KEY_READY frame is of no significance.
>>>
>>> The text mentions that the updated key depends on the current traffic
key with reference to TLS 1.3. From reading this naively, it sounds like
forward secrecy is lost, which I am sure it is not.
>>>
>>> Finally, this is just a high level view. I find the overall text hard
to understand, notably because it is not crystal clear whether the two
endpoints update their transmission keys in sync with the ready keys, or if
the (currently implicity) key phase counters can count independently.

-- 
Kazuho Oku

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 14 Feb 2019 00:48:51 +0900

2019/02/14 0:29、Mikkel Fahnøe Jørgensen <[email-masked]>のメール:

> It cannot not be ACK-eliciting, otherwise a lost packet could mean that no new key updates would be possible.

IIUC key updates are rare, and therefore the frame can be non-ack-eliciting. FWIW, the current design does not elicit an ACK in response to key update.

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Wed, 13 Feb 2019 07:55:32 -0800

The point is that under the rules set by the PR, it is not possible to
update keys before a KEYS_ACTIVE / KEYS_READY frame has been received. If
such a frame is sent, but lost, there is not path to update keys again.
This goes wrong after a (long) while, when the current key is exchausted.
It does not matter that updates are rare.

On 13 February 2019 at 16.48.57, Kazuho Oku ([email-masked]) wrote:

IIUC key updates are rare, and therefore the frame can be
non-ack-eliciting. FWIW, the current design does not elicit an ACK in
response to key update.

--
Kazuho Oku

---

From: Christian Huitema <[email-masked]>
Date: Wed, 13 Feb 2019 08:18:53 -1000

> On Feb 13, 2019, at 5:55 AM, Mikkel Fahnøe Jørgensen <[email-masked]> wrote:
> 
> The point is that under the rules set by the PR, it is not possible to update keys before a KEYS_ACTIVE / KEYS_READY frame has been received. If such a frame is sent, but lost, there is not path to update keys again. This goes wrong after a (long) while, when the current key is exchausted.

The more I look at it, the more I think that key update / key ready should be treated in much the same way as path challenge / path response. Something like: I just updated my key, can you receive it (challenge); yes, you can see I am using your new key (response). This resolves the debate with ack-or-not (not), and also whether the mechanism can be used to delay update ad infinitum (cannot).

If we use the existing path challenge mechanism, we need to add a restriction that responses must be sent in the same epoch. Or we can invent a new one.

-- Christian Huitema

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Wed, 13 Feb 2019 10:32:45 -0800

On 13 February 2019 at 19.20.18, Christian Huitema ([email-masked])
wrote:

The more I look at it, the more I think that key update / key ready should
be treated in much the same way as path challenge / path response.

In a sense, it is a new path if a path in one direction is the 3-tuple:
<ip, port, key>

There isn’t strictly a need to separate the concepts.

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 14 Feb 2019 07:03:23 +0900

> It does not matter that updates are rare.

I am not sure if that ever happens.

The only way to exhaust the key without sending a packet that contain
an ACK-eliciting frame is for both endpoints to continue sending
packets that just contain non-ACK-eliciting frames, which are ACK,
PADDING (and in this case KEY_READY).

However, you would never send ACKs in response to ACKs. You would not
be sending the other non-ACK-eliciting frames if there is nothing
other to send.

-- 
Kazuho Oku

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 14 Feb 2019 07:09:45 +0900

2019年2月14日(木) 3:20 Christian Huitema <[email-masked]>:
> The more I look at it, the more I think that key update / key ready should be treated in much the same way as path challenge / path response.

I am not sure if I like that alternative, primary because it does not
seem right as a way to drop Initial, 0-RTT, Handshake keys. We are
trying to address two issues at once; how to drop those keys in lower
epochs, and how to do key update correctly.

The proposed approach of using a frame (or a header bit) to let each
side unilaterally declare that it's done with the keys gives us a
consistent pattern for switching between the keys.

> Something like: I just updated my key, can you receive it (challenge); yes, you can see I am using your new key (response). This resolves the debate with ack-or-not (not), and also whether the mechanism can be used to delay update ad infinitum (cannot).
>

-- 
Kazuho Oku

---

From: Martin Thomson <[email-masked]>
Date: Thu, 14 Feb 2019 13:12:42 +1100

> (even if one ought no do such naive transmission).

I don't see this is a strong break with principle.  Like ACKs, KEYS_ACTIVE/KEYS_READY is tightly bound to the associated logic.  With ACK, it's packet receipt, here it's the keys you use for protecting/un-protecting packets.  In processing a KEYS_ACTIVE frame, you check what the most recent keys you have for reading and writing.  If they are the same, then you set the "can key update" flag on.  If the read keys are ahead of the write keys, then you have an error.  It doesn't require an active connection to the packet protection logic other than that.

> forward secrecy is lost, which I am sure it is not.

This isn't relevant to this discussion, but I encourage you to read draft-irtf-cfrg-re-keying which goes through the various trade-offs of rekeying designs.  TLS 1.3 has text on this also, and QUIC shares that design.
 
> the (currently implicity) key phase counters can count independently.

If you have more specific comments (the one about read keys is a good one), I'll take those on the PR.
 
> same thing, and if it is, perhaps formalise that.

We're working on that as the next step.

---

From: Martin Thomson <[email-masked]>
Date: Thu, 14 Feb 2019 13:33:26 +1100

A few different responses...

> information, since the bit is set on every subsequent packet.

I was OK with that PR, and while we might go back and forth on the merits of using a bit vs. a frame, the consensus in Tokyo was that the frame was superior.  Also, this solves more problems.

On Thu, Feb 14, 2019, at 02:48, Kazuho Oku wrote:
> IIUC key updates are rare, and therefore the frame can be non-ack-
> eliciting. FWIW, the current design does not elicit an ACK in response 
> to key update.

I used the opposite logic.  Key updates are rare and therefore eliciting an acknowledgment does not cost much.  It's one packet per update.  The interesting thing there is that you guarantee that KEYS_ACTIVE frame is sent, so maybe the text about not sending it until you have something to send is not needed.

> epochs, and how to do key update correctly.

The test we are looking for is whether a peer can read packets with a particular key.  You can test easily if they can write packets with a key because you receive a packet protected with that key.

PATH_CHALLENGE/PATH_RESPONSE have baggage, so I don't want to use those.  A new challenge/response could work, but it doesn't offer much over a simple assertion (which is what the proposed frame is).  If the assertion is wrong, then the consequence is a broken connection, so there isn't much incentive to get this wrong.  PATH_CHALLENGE/PATH_RESPONSE contain a field that protects against lying, because there are scenarios in which lying provides advantage (that is, the "DoS this IP please" case).

---

From: Christian Huitema <[email-masked]>
Date: Wed, 13 Feb 2019 17:47:39 -1000

> PATH_CHALLENGE/PATH_RESPONSE have baggage, so I don't want to use those.  A new challenge/response could work, but it doesn't offer much over a simple assertion (which is what the proposed frame is…

Yes, I can see the logic behind that. I like the challenge/response
because it has a clean state machine behind hit: send a challenge,
expect a response, if the response does not come, repeat the challenge,
if it still does not come, give up the path. The combination of the
phase change and the KEY ACTIVE frame is not so clean. The phase change
plays the same role as the challenge and the frame plays the same role
as the response, but there is no way to repeat the challenge if the
response is not received: the peer has to wait for the diligence and
good will of the other peer.

Of course, if the KEY ACTIVE frame requires an acknowledgement, it
should arrive eventually. But what if it doesn't? What if the peer did
not send it, or did not correctly retransmit it? Should the endpoint
just abort the connection if some number of RTO pass after the phase
change, and the KEY ACTIVE frame has not been received yet? Does the
behavior change if some traffic encrypted with the new phase has been
acknowledged?

-- Christian Huitema

---

From: Martin Thomson <[email-masked]>
Date: Thu, 14 Feb 2019 15:11:50 +1100

> behavior change if some traffic encrypted with the new phase has been

I'm happy leaving this to implementation discretion.  There is no clear rule that say when you can treat the absence of the frame as an error, partly because your view of PTO is different than that of your peer.

Maybe we can say that if you want to update and can't, you close the connection.  That's the usual advice anyway.

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 14 Feb 2019 13:22:31 +0900

TL;DR I think that the issue with the PR is that it not only tries to
address issue but it changes existing mechanism. It might make sense
to consider just fixing the issues. Proposal below.

I think there are two concerns regarding the PR.

The PR changes how Initial keys are retired. Instead of relying on the
delivery of Handshake packets, it relies on the delivery of
KEYS_ACTIVE frames. However, we do not require KEY_ACTIVE frames to be
included in every Handshake packet being sent. There is a risk that
Initial keys might not get dropped as early as they are now. The other
issue is that an endpoint might never receive a Handshake packet that
carries a KEY_ACTIVE frame. This happens packet loss occurs. To
accommodate that, the PR states that the delivery of KEY_ACTIVE frame
in either a Handshake or a 1-RTT packet signals the disposal of the
Initial packet. That's workable, but I think it shows the problem with
the approach.

KEY_ACTIVE frame does not name the key that is activated. That is
causing the strange retransmission rules for the frame. The right
approach seems to suggest endpoints to incorporate the frame in every
ACK-eliciting packet it sends. This is a logic we have not had so far,
and it could be difficult for certain implementations that do not know
what it is sending when it starts to build a packet.

Considering these two issues, I think it might be worth discussing the
following straw-man:

* Do not touch how Initial keys are dropped. Use the new frame just to
indicate the completion of the handshake and the retirement of the
previous generation of 1-RTT keys.
* Include the 1-RTT key generation number in the frame, so that
ordinary retransmission logic can be used. Note also that the
retransmission rule does not need to be aggressive, because we do not
use the frame for dropping Initial keys.

When the handshake is complete, both endpoints send
KEYS_ACTIVE(generation=0). That indicates the peer that the peer can
drop the Handshake keys, and also that the endpoint is ready to
receive a key update.

Completion of key update works exactly the same way. When key update
is complete, both endpoints send
KEY_ACTIVE(generation=previous_generation), indicating that the peer
can drop the 1-RTT keys, and that the endpoint is ready to receive
another key update.

Regarding the validation of the generation number, I think we can call it a MAY.

-- 
Kazuho Oku

---

From: Jana Iyengar <[email-masked]>
Date: Wed, 13 Feb 2019 20:24:25 -0800

On Wed, Feb 13, 2019 at 8:12 PM Martin Thomson <[email-masked]> wrote:

> I'm happy leaving this to implementation discretion.  There is no clear
> rule that say when you can treat the absence of the frame as an error,
> partly because your view of PTO is different than that of your peer.
>
> Maybe we can say that if you want to update and can't, you close the
> connection.  That's the usual advice anyway.
>

(I've left this comment on the PR as well, but seeing that this discussion
is happening here as well, echoing it here)
If the peer hasn't acked the previous KEYS_ACTIVE, it may not have seen it
yet. It is possible that it simultaneously did a key update and sent a
KEYS_ACTIVE however. Under this condition, the endpoint wouldn't be able to
update its keys again, since the peer may close the connection, right?

---

From: Jana Iyengar <[email-masked]>
Date: Wed, 13 Feb 2019 20:29:51 -0800

> can drop the 1-RTT keys, and that the endpoint is ready to receive

This is a good simplification, I think.  I'll note that you still cannot
update keys again until you've received an ACK for the previous KEYS_ACTIVE.

> Regarding the validation of the generation number, I think we can call it

What validation?

- jana

> > I was OK with that PR, and while we might go back and forth on the
> merits of using a bit vs. a frame, the consensus in Tokyo was that the
> frame was superior.  Also, this solves more problems.
> >
> > I used the opposite logic.  Key updates are rare and therefore eliciting
> an acknowledgment does not cost much.  It's one packet per update.  The
> interesting thing there is that you guarantee that KEYS_ACTIVE frame is
> sent, so maybe the text about not sending it until you have something to
> send is not needed.
> >
> > > > The more I look at it, the more I think that key update / key ready
> should be treated in much the same way as path challenge / path response.
> > >
> > The test we are looking for is whether a peer can read packets with a
> particular key.  You can test easily if they can write packets with a key
> because you receive a packet protected with that key.
> >
> > PATH_CHALLENGE/PATH_RESPONSE have baggage, so I don't want to use
> those.  A new challenge/response could work, but it doesn't offer much over
> a simple assertion (which is what the proposed frame is).  If the assertion
> is wrong, then the consequence is a broken connection, so there isn't much
> incentive to get this wrong.  PATH_CHALLENGE/PATH_RESPONSE contain a field
> that protects against lying, because there are scenarios in which lying
> provides advantage (that is, the "DoS this IP please" case).
> >
>
>
> --
> Kazuho Oku
>
>

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 14 Feb 2019 13:40:31 +0900

2019年2月14日(木) 13:30 Jana Iyengar <[email-masked]>:
> This is a good simplification, I think.  I'll note that you still cannot update keys again until you've received an ACK for the previous KEYS_ACTIVE.

We can require that, however it might be simpler to state that
receiving a KEY_ACTIVE frame from the peer allows an endpoint to
execute a key update.

>> Regarding the validation of the generation number, I think we can call it a MAY.

In the straw-man, KEY_ACTIVE frame carries the generation number of
the 1-RTT key.

The value can be anything equal to or less than the current generation
number, because the delivery of the frame can be severely delayed
(this is the norm for QUIC frames used to communicate a monotonously
increasing number; e.g., MAX_STREAMS).

However, an endpoint should never receive a KEY_ACTIVE frame
containing a generation number that is greater than the generation it
has ever used. Endpoints might want to police that. That's the
validation I'm referring to.

-- 
Kazuho Oku

---

From: Martin Thomson <[email-masked]>
Date: Thu, 14 Feb 2019 16:05:33 +1100

> update its keys again, since the peer may close the connection, right?

This is not a problem, but it requires thinking the process through.

An endpoint can only initiate a key update if it has received KEYS_ACTIVE.  It can only send KEYS_ACTIVE if it has received a key update (and is either responding, or initiated that).

Take the example where an ACK is lost, so a key update occurs when one peer is retransmitting KEYS_ACTIVE:

C: Update to Key Phase 1.
S: Update to Key Phase 1.  Send KEYS_ACTIVE.
C: Send packet containing ACK for the server packet containing KEYS_ACTIVE, plus KEYS_ACTIVE.  That packet is lost.
C: Update to Key Phase 0.
S: Update to Key Phase 0. Send KEYS_ACTIVE.

The server might believe that its KEYS_ACTIVE hasn't been acknowledged, but it has to be prepared for a key update as soon as it sends the frame.

If there is a simultanous update it looks like this:

C: Update to Key Phase 1.
S: Update to Key Phase 1.  (Concurrent with previous.)
C: Receive packet with KP1.  Send KEYS_ACTIVE.  Lost.
S: Receive packet with KP1.  Send KEYS_ACTIVE.

At this point, both peers are fine, they are on the same keys, and a key update can be triggered by the client.  The server can't update until the client repairs the lost KEYS_ACTIVE frame.  This continues:

C: Update to Key Phase 0.
S: Receive KP0.  Update to Key Phase 0.  Send KEYS_ACTIVE.

As you can see, the client stops sending when it updates again, but that's OK.

It's also safe if the KEYS_ACTIVE frames get through, but acknowledgments for them don't.

---

From: Marten Seemann <[email-masked]>
Date: Thu, 14 Feb 2019 13:27:27 +0800

> I was OK with that PR, and while we might go back and forth on the merits
of using a bit vs. a frame, the consensus in Tokyo was that the frame was
superior.  Also, this solves more problems.

In my understanding, the consensus in Tokyo was based on the assumption
that the bit and the frame were basically signaling the same thing - at
least I wasn’t aware of the additional retransmission logic necessary, and
I would’ve opposed this solution if I had known.

> The PR changes how Initial keys are retired. Instead of relying on the delivery
of Handshake packets, it relies on the delivery of KEYS_ACTIVE frames.
However, we do not require KEY_ACTIVE frames to be included in every
Handshake packet being sent.

This is again the problem of a discrete vs. a continuous signal. Using
another bit in the first byte solves this problem.
After the handshake completes, we want the peer to advance from handshake
mode to normal mode in the loss recovery logic, since in handshake mode we
don’t have PTOs. The only way to achieve this using the KEYS_ACTIVE frame
is to include it in multiple (all packets for one RTT?) after the handshake
completes.

That being said, adding a generation number as Kazuho suggested seems to be
the second best solution, since it at least removes the necessity to
implement separate retransmission rules.

On Thu, Feb 14, 2019 at 13:05 Martin Thomson <[email-masked]> wrote:

> An endpoint can only initiate a key update if it has received
> KEYS_ACTIVE.  It can only send KEYS_ACTIVE if it has received a key update
> (and is either responding, or initiated that).
>
> C: Send packet containing ACK for the server packet containing
> KEYS_ACTIVE, plus KEYS_ACTIVE.  That packet is lost.
> The server might believe that its KEYS_ACTIVE hasn't been acknowledged,
> but it has to be prepared for a key update as soon as it sends the frame.
>
> At this point, both peers are fine, they are on the same keys, and a key
> update can be triggered by the client.  The server can't update until the
> client repairs the lost KEYS_ACTIVE frame.  This continues:
>

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Thu, 14 Feb 2019 05:42:31 +0000

Why do keys need to be in sync?
Disregarding handshake, if each peer has a separate key index counter, at change in phase bit ought to be sufficient.

The endpoints can have vastly different consumption rates.

With sync keys the peer can prevent you from updating while uou can update after ca 3 PTO in the async design. Neither design can force the peer to update.

________________________________
Fra: QUIC <[email-masked]> på vegne af Marten Seemann <[email-masked]>
Sendt: torsdag, februar 14, 2019 6:27 AM
Til: Martin Thomson
Cc: Jana Iyengar; QUIC WG
Emne: Re: KEYS_READY

> I was OK with that PR, and while we might go back and forth on the merits of using a bit vs. a frame, the consensus in Tokyo was that the frame was superior.  Also, this solves more problems.

In my understanding, the consensus in Tokyo was based on the assumption that the bit and the frame were basically signaling the same thing - at least I wasn’t aware of the additional retransmission logic necessary, and I would’ve opposed this solution if I had known.

> The PR changes how Initial keys are retired. Instead of relying on the delivery of Handshake packets, it relies on the delivery of KEYS_ACTIVE frames. However, we do not require KEY_ACTIVE frames to be included in every Handshake packet being sent.

This is again the problem of a discrete vs. a continuous signal. Using another bit in the first byte solves this problem.
After the handshake completes, we want the peer to advance from handshake mode to normal mode in the loss recovery logic, since in handshake mode we don’t have PTOs. The only way to achieve this using the KEYS_ACTIVE frame is to include it in multiple (all packets for one RTT?) after the handshake completes.

That being said, adding a generation number as Kazuho suggested seems to be the second best solution, since it at least removes the necessity to implement separate retransmission rules.

On Thu, Feb 14, 2019 at 13:05 Martin Thomson <[email-masked]<mailto:[email-masked]>> wrote:

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Thu, 14 Feb 2019 05:44:00 +0000

I guess because ACK?

________________________________
Fra: Mikkel Fahnøe Jørgensen <[email-masked]>
Sendt: torsdag, februar 14, 2019 6:42 AM
Til: Marten Seemann; Martin Thomson
Cc: Jana Iyengar; QUIC WG
Emne: Re: KEYS_READY

---

From: David Schinazi <[email-masked]>
Date: Thu, 14 Feb 2019 09:57:02 -0800

I don't think the proposed PR matches what we discussed in Tokyo, and it
seems less robust than what we discussed.

In Tokyo we had discussed a RETIRE_KEYS frame with the following properties:
1) You send RETIRE_KEYS when both (a) you have sent everything you wanted
with those keys AND (b) that has been ACKed
    In particular, the client sends a 1RTT packet with
RETIRE_KEYS(Handshake) when the server ACKs the packet containing the
crypto frame with the ClientFinished
2) You can discard keys (and congestion control state if applicable) when
you've both sent and received RETIRE_KEYS

The proposal in PR#2237 does not have these properties, because it focuses
on the new keys being ready instead of focusing on when an endpoint is done
sending with previous keys.
In order to avoid the client infinitely retransmitting ClientFinished
issue, PR#2237 has the server delay its 1-RTT KEYS_READY until it believes
the handshake is complete.
It would be more robust to have the endpoint who is sending decide when it
is done sending, instead of having the peer assume it knows.

David

On Wed, Feb 13, 2019 at 9:44 PM Mikkel Fahnøe Jørgensen <[email-masked]>
wrote:

> I guess because ACK?
>
>
> ------------------------------
> *Fra:* Mikkel Fahnøe Jørgensen <[email-masked]>
> *Sendt:* torsdag, februar 14, 2019 6:42 AM
> *Til:* Marten Seemann; Martin Thomson
> *Cc:* Jana Iyengar; QUIC WG
> *Emne:* Re: KEYS_READY
>
> Disregarding handshake, if each peer has a separate key index counter, at
> change in phase bit ought to be sufficient.
>
> With sync keys the peer can prevent you from updating while uou can update
> after ca 3 PTO in the async design. Neither design can force the peer to
> update.
>
>
> ------------------------------
> *Fra:* QUIC <[email-masked]> på vegne af Marten Seemann <
> [email-masked]>
> *Sendt:* torsdag, februar 14, 2019 6:27 AM
> *Til:* Martin Thomson
> *Cc:* Jana Iyengar; QUIC WG
> *Emne:* Re: KEYS_READY
>
> That being said, adding a generation number as Kazuho suggested seems to
> be the second best solution, since it at least removes the necessity to

---

From: Ryan Hamilton <[email-masked]>
Date: Thu, 14 Feb 2019 12:34:13 -0800

> is done sending, instead of having the peer assume it knows.

I completely agree with this. The usage of RETIRE_KEYS, as outlined here
and in summaries of the discussion in Tokyo that I read, seems simple and
clear.

---

From: Mike Bishop <[email-masked]>
Date: Thu, 14 Feb 2019 20:38:49 +0000

The question is whether the same mechanism can/should be used for post-handshake key updates or if two separate mechanisms are needed.  They’re very similar problems, but it seems as if the requirements are slightly different.

From: QUIC <[email-masked]> On Behalf Of Ryan Hamilton
Sent: Thursday, February 14, 2019 12:34 PM
To: David Schinazi <[email-masked]>
Cc: Marten Seemann <[email-masked]>; Jana Iyengar <[email-masked]>; Mikkel Fahnøe Jørgensen <[email-masked]>; QUIC WG <[email-masked]>; Martin Thomson <[email-masked]>
Subject: Re: KEYS_READY

On Thu, Feb 14, 2019 at 9:57 AM David Schinazi <[email-masked]<mailto:[email-masked]>> wrote:
I don't think the proposed PR matches what we discussed in Tokyo, and it seems less robust than what we discussed.

In Tokyo we had discussed a RETIRE_KEYS frame with the following properties:
1) You send RETIRE_KEYS when both (a) you have sent everything you wanted with those keys AND (b) that has been ACKed
    In particular, the client sends a 1RTT packet with RETIRE_KEYS(Handshake) when the server ACKs the packet containing the crypto frame with the ClientFinished
2) You can discard keys (and congestion control state if applicable) when you've both sent and received RETIRE_KEYS

The proposal in PR#2237 does not have these properties, because it focuses on the new keys being ready instead of focusing on when an endpoint is done sending with previous keys.
In order to avoid the client infinitely retransmitting ClientFinished issue, PR#2237 has the server delay its 1-RTT KEYS_READY until it believes the handshake is complete.
It would be more robust to have the endpoint who is sending decide when it is done sending, instead of having the peer assume it knows.

I completely agree with this. The usage of RETIRE_KEYS, as outlined here and in summaries of the discussion in Tokyo that I read, seems simple and clear.

---

From: David Schinazi <[email-masked]>
Date: Thu, 14 Feb 2019 12:42:19 -0800

I think RETIRE_KEYS solves both problems. I don't think KEYS_READY does.

On Thu, Feb 14, 2019 at 12:38 PM Mike Bishop <[email-masked]> wrote:

> The question is whether the same mechanism can/should be used for
> post-handshake key updates or if two separate mechanisms are needed.
> They’re very similar problems, but it seems as if the requirements are
> slightly different.
>
>
>
> *From:* QUIC <[email-masked]> *On Behalf Of * Ryan Hamilton
> *Sent:* Thursday, February 14, 2019 12:34 PM
> *To:* David Schinazi <[email-masked]>
> *Cc:* Marten Seemann <[email-masked]>; Jana Iyengar <
> [email-masked]>; Mikkel Fahnøe Jørgensen <[email-masked]>; QUIC
> WG <[email-masked]>; Martin Thomson <[email-masked]>
> *Subject:* Re: KEYS_READY
>
>
>

---

From: "Martin Thomson" <[email-masked]>
Date: Thu, 14 Feb 2019 16:02:50 -0500

Please explain how the two differ, because I'm not seeing a difference.

On Fri, Feb 15, 2019, at 07:42, David Schinazi wrote:
> > The question is whether the same mechanism can/should be used for post-handshake key updates or if two separate mechanisms are needed. They’re very similar problems, but it seems as if the requirements are slightly different.____
> 
> >  
> > __ __
> 
> >  
> >  *Cc:* Marten Seemann <[email-masked]>; Jana Iyengar <[email-masked]>; Mikkel Fahnøe Jørgensen <[email-masked]>; QUIC WG <[email-masked]>; Martin Thomson <[email-masked]>
> >  *Subject:* Re: KEYS_READY____
> 
> >  
> > __ __
> 
> >  
> >  
> >  
> >  
> > On Thu, Feb 14, 2019 at 9:57 AM David Schinazi <[email-masked]> wrote:____
> 
> >  
> >  
> >  
> >   
> >>  
> >> I don't think the proposed PR matches what we discussed in Tokyo, and it seems less robust than what we discussed.____
> 
> >>  
> >>  
> >> __ __
> 
> >>  
> >>  
> >> In Tokyo we had discussed a RETIRE_KEYS frame with the following properties:____
> 
> >>  
> >>  
> >>  
> >> 1) You send RETIRE_KEYS when both (a) you have sent everything you wanted with those keys AND (b) that has been ACKed____
> 
> >>  
> >>  
> >>  
> >>  In particular, the client sends a 1RTT packet with RETIRE_KEYS(Handshake) when the server ACKs the packet containing the crypto frame with the ClientFinished____
> 
> >>  
> >>  
> >>  
> >> 2) You can discard keys (and congestion control state if applicable) when you've both sent and received RETIRE_KEYS____
> 
> >>  
> >>  
> >>  
> >> __ __
> 
> >>  
> >>  
> >>  
> >> The proposal in PR#2237 does not have these properties, because it focuses on the new keys being ready instead of focusing on when an endpoint is done sending with previous keys.____
> 
> >>  
> >>  
> >>  
> >> In order to avoid the client infinitely retransmitting ClientFinished issue, PR#2237 has the server delay its 1-RTT KEYS_READY until it believes the handshake is complete.____
> 
> >>  
> >>  
> >>  
> >> It would be more robust to have the endpoint who is sending decide when it is done sending, instead of having the peer assume it knows.____
> 
> >>  
> >>  
> >>  
> >>   
> >  
> > __ __
> 
> >  
> >  
> >  
> > I completely agree with this. The usage of RETIRE_KEYS, as outlined here and in summaries of the discussion in Tokyo that I read, seems simple and clear.____
> 
> >  
> >  
> >  
> >  
> >  
> >  
>

---

From: David Schinazi <[email-masked]>
Date: Thu, 14 Feb 2019 14:01:54 -0800

> Please explain how the two differ, because I'm not seeing a difference.

Here's the difference between them as I understand it:

I'd initially assumed KEYS_READY meant that the keys were installed -
meaning that you send KEYS_READY when your keys are installed. But not
quite! The server does not send KEYS_READY when the 1-RTT keys are
installed, it sends it when it believes the handshake is done. So now you
have a notion of keys being ready that is impacted by parts of the protocol
further away.

RETIRE_KEYS just means that you're done sending with a set of keys - so you
send it when you have received ACKs for everything you cared about sending
with those keys. I find that a lot more easier to reason about.

---

From: "Martin Thomson" <[email-masked]>
Date: Thu, 14 Feb 2019 17:30:30 -0500

On Fri, Feb 15, 2019, at 09:02, David Schinazi wrote:
> installed, it sends it when it believes the handshake is done. So now 
> you have a notion of keys being ready that is impacted by parts of the 
> protocol further away.
> 
> RETIRE_KEYS just means that you're done sending with a set of keys - so 
> you send it when you have received ACKs for everything you cared about 
> sending with those keys. I find that a lot more easier to reason about.

Take another look at the PR and see if you can spot the difference.  You will find that maybe you are just arguing for a name change here.

---

From: David Schinazi <[email-masked]>
Date: Thu, 14 Feb 2019 14:47:01 -0800

Hi Martin, I've read the PR (in its latest version) and the comments in my
previous email still hold.
The text I object to from the PR is the following:

    A KEYS_ACTIVE frame sent in 1-RTT packets indicates that Handshake keys
are no
    longer needed.  A client MUST send this frame in its first 1-RTT
packet, and a
    server MUST send this frame in the first packet it sends after
completing the
    handshake.  A server might send 1-RTT packets prior to this; a server
MUST NOT
    process 1-RTT packets until the cryptographic handshake is complete.

This means that the server sends KEYS_ACTIVE(1-RTT) not when the 1-RTT keys
are active,
but instead when the handshake finishes, which is when the server has
received the client finished.
Those are two different moments in time.

My proposal is to have the client decide when it is done with the handshake
keys by having the client
delay sending RETIRE_KEYS(Handshake) instead of the server delaying sending
KEYS_ACTIVE(1-RTT).

David

On Thu, Feb 14, 2019 at 2:30 PM Martin Thomson <[email-masked]> wrote:

> Take another look at the PR and see if you can spot the difference.  You
> will find that maybe you are just arguing for a name change here.
>

---

From: "Martin Thomson" <[email-masked]>
Date: Thu, 14 Feb 2019 18:45:56 -0500

On Fri, Feb 15, 2019, at 09:47, David Schinazi wrote:
> This means that the server sends KEYS_ACTIVE(1-RTT) not when the 1-RTT 
> keys are active,

Yes, because the keys aren't active when the server starts sending 1-RTT packets.  They are only active when the server starts reading 1-RTT.  The server can't activate its 1-RTT reading keys until the handshake is complete.

That's why I chose to name this KEYS_ACTIVE(this), not RETIRE_KEYS(prev), but I don't really mind what it is called.

 > My proposal is to have the client decide when it is done with the 
> handshake keys by having the client
> delay sending RETIRE_KEYS(Handshake) instead of the server delaying 
> sending KEYS_ACTIVE(1-RTT).

This requires that the client send more Handshake packets.  And it adds a lot of delay because the client has to wait until all its packets are acknowledged.  We previously agreed that any such signal from the server is more direct and effective.

---

From: David Schinazi <[email-masked]>
Date: Thu, 14 Feb 2019 16:17:47 -0800

On Thu, Feb 14, 2019 at 3:45 PM Martin Thomson <[email-masked]> wrote:

> Yes, because the keys aren't active when the server starts sending 1-RTT
> packets.  They are only active when the server starts reading 1-RTT.  The
> server can't activate its 1-RTT reading keys until the handshake is
> complete.
>

Ah, thanks. Looking at it this way it makes sense to me - we may want to
make the text clearer in case I'm not the only one who was confused.

> That's why I chose to name this KEYS_ACTIVE(this), not RETIRE_KEYS(prev),
> but I don't really mind what it is called.
>

I don't feel strongly about names either as long as they make sense - and
now KEYS_ACTIVE also makes sense to me - so either name is fine by me.

> This requires that the client send more Handshake packets.  And it adds a
> lot of delay because the client has to wait until all its packets are
> acknowledged.  We previously agreed that any such signal from the server is
> more direct and effective.
>

I don't think it means more handshake packets. And it's still a direct
signal between endpoints. The only difference is that the client-to-server
RETIRE_KEYS message is delayed by one RTT compared to its KEYS_ACTIVE
message so the server will wait one RTT before throwing away handshake
keys. But it has the advantage of not requiring any implicit ACKs. So the
tradeoff we're facing is between allowing the server to throw away keys
sooner at the cost of making implicit decisions. This implicitness means
KEYS_ACTIVE does not allow the client to be able to send anything in
Handshake after the ClientFinished. I'm worried that might prevent protocol
changes down the road.

I'm still in favor of paying the one RTT before key deletion to make the
protocol more explicit.

---

From: Kazuho Oku <[email-masked]>
Date: Fri, 15 Feb 2019 10:51:43 +0900

2019年2月15日(金) 9:18 David Schinazi <[email-masked]>:
> Ah, thanks. Looking at it this way it makes sense to me - we may want to make the text clearer in case I'm not the only one who was confused.
>
>>
> I don't feel strongly about names either as long as they make sense - and now KEYS_ACTIVE also makes sense to me - so either name is fine by me.
>
>>
> I don't think it means more handshake packets. And it's still a direct signal between endpoints. The only difference is that the client-to-server RETIRE_KEYS message is delayed by one RTT compared to its KEYS_ACTIVE message so the server will wait one RTT before throwing away handshake keys. But it has the advantage of not requiring any implicit ACKs. So the tradeoff we're facing is between allowing the server to throw away keys sooner at the cost of making implicit decisions. This implicitness means KEYS_ACTIVE does not allow the client to be able to send anything in Handshake after the ClientFinished. I'm worried that might prevent protocol changes down the road.
>
> I'm still in favor of paying the one RTT before key deletion to make the protocol more explicit.

I share the same view.

Admittedly, it means that then the frame would no longer be useful for
dropping the Initial keys, assuming that we want to drop them ASAP as
we do now.

But even with that downside, I think it makes sense to delay when the
handshake and each generation of 1-RTT keys are dropped. After all, we
can argue that the requirement for when to drop the Initial keys is
exceptional due to security concerns.

Hence something like
https://mailarchive.ietf.org/arch/msg/quic/NNOzxNWldmfiUN9avCdiQMNVXMw.

-- 
Kazuho Oku

---

From: David Schinazi <[email-masked]>
Date: Thu, 28 Feb 2019 16:30:22 -0800

Since this conversation has quieted down for two weeks, I went ahead and
wrote up the RETIRE_KEYS proposal:
https://github.com/quicwg/base-drafts/pull/2492

I believe this is simpler to reason about than the KEYS_ACTIVE proposal and
safer as it makes less assumptions about the handshake protocol.

Please let me know what you think, and I believe we should keep the
discussion here instead of on the PR.

David

On Thu, Feb 14, 2019 at 5:51 PM Kazuho Oku <[email-masked]> wrote:

> >> Yes, because the keys aren't active when the server starts sending
> 1-RTT packets.  They are only active when the server starts reading 1-RTT.
> The server can't activate its 1-RTT reading keys until the handshake is
> complete.
> >
> >
> >> That's why I chose to name this KEYS_ACTIVE(this), not
> RETIRE_KEYS(prev), but I don't really mind what it is called.
> >
> >
> > I don't feel strongly about names either as long as they make sense -
> and now KEYS_ACTIVE also makes sense to me - so either name is fine by me.
> >
> >>
> >> This requires that the client send more Handshake packets.  And it adds
> a lot of delay because the client has to wait until all its packets are

---

From: "Martin Thomson" <[email-masked]>
Date: Thu, 28 Feb 2019 22:37:25 -0500

I don't get it.  This is the same proposal.  With fewer editorial changes, perhaps.

On Fri, Mar 1, 2019, at 11:30, David Schinazi wrote:
> Since this conversation has quieted down for two weeks, I went ahead 
> and wrote up the RETIRE_KEYS proposal:
> I believe this is simpler to reason about than the KEYS_ACTIVE proposal 
> and safer as it makes less assumptions about the handshake protocol.
>

---

From: Nick Harper <[email-masked]>
Date: Thu, 28 Feb 2019 21:21:11 -0800

There is one difference between the RETIRE_KEYS and KEYS_ACTIVE PRs
(besides the name of the new frame):

With RETIRE_KEYS, the client doesn't send it until the Client Finished has
been ACKed. With KEYS_ACTIVE, the client MUST send it in its first 1-RTT
packet, while the server MUST NOT process that 1-RTT packet until it has
received the Client Finished.

Even though they do basically the same thing, I think it's much easier to
understand the logic in the RETIRE_KEYS PR. The logic for RETIRE_KEYS is "I
send RETIRE_KEYS when I don't need to send or receive anything more at the
previous encryption level." After re-reading the KEYS_ACTIVE PR, I don't
see a similar underlying principle for when it's sent, just a set of rules
to follow.

On Thu, Feb 28, 2019 at 7:37 PM Martin Thomson <[email-masked]> wrote:

> > >  > Ah, thanks. Looking at it this way it makes sense to me - we may
> want to make the text clearer in case I'm not the only one who was confused.
> > >  >
> > >  >>
> > >  > I don't feel strongly about names either as long as they make sense
> - and now KEYS_ACTIVE also makes sense to me - so either name is fine by me.
> > >  >
> > >  >>
> > >  >> This requires that the client send more Handshake packets. And it
> adds a lot of delay because the client has to wait until all its packets
> are acknowledged. We previously agreed that any such signal from the server
> is more direct and effective.
> > >  >
> > >  >
> > >  > I don't think it means more handshake packets. And it's still a
> direct signal between endpoints. The only difference is that the
> client-to-server RETIRE_KEYS message is delayed by one RTT compared to its
> KEYS_ACTIVE message so the server will wait one RTT before throwing away
> handshake keys. But it has the advantage of not requiring any implicit
> ACKs. So the tradeoff we're facing is between allowing the server to throw
> away keys sooner at the cost of making implicit decisions. This
> implicitness means KEYS_ACTIVE does not allow the client to be able to send
> anything in Handshake after the ClientFinished. I'm worried that might
> prevent protocol changes down the road.
> > >  >

---

From: "Martin Thomson" <[email-masked]>
Date: Fri, 01 Mar 2019 01:15:33 -0500

I see.  That's not clear.  It might have helped to explain that in the email announcing the proposal, because the PR contains errors that are quite confusing.  The PR never really defines what "done with keys" means either.

If that is the only difference then we can talk about the implications of driving state based on ACK frames, which we've not done in the past.  Leaving the ugly exception for Initial aside, I suspect that this is much harder to implement, because you have to track where data was first sent in order to send the frame at the right time.  That's easy enough for CRYPTO frames, which are basically all you have during the handshake, but in order to implement it for key updates you need visibility into which packets are still outstanding.  That requires a new type of access to the loss recovery module.

I see quite a few omissions and mistakes in the PR.  For instance, this doesn't address the concerns about retransmissions of the frame across key updates.  It also shows the server sending the frame in Handshake packets before it could have received ACKs.  Hence my confusion.

On Fri, Mar 1, 2019, at 16:21, Nick Harper wrote:
> With RETIRE_KEYS, the client doesn't send it until the Client Finished 
> has been ACKed. With KEYS_ACTIVE, the client MUST send it in its first 
> 1-RTT packet, while the server MUST NOT process that 1-RTT packet until 
> it has received the Client Finished.
> 
> Even though they do basically the same thing, I think it's much easier 
> to understand the logic in the RETIRE_KEYS PR. The logic for 
> RETIRE_KEYS is "I send RETIRE_KEYS when I don't need to send or receive 
> anything more at the previous encryption level." After re-reading the 
> KEYS_ACTIVE PR, I don't see a similar underlying principle for when 
> it's sent, just a set of rules to follow.
>