Re: [quicwg/base-drafts] Rework Key Update (#2237)

Martin Thomson <notifications@github.com> Thu, 14 February 2019 05:40 UTC

Return-Path: <noreply@github.com>
X-Original-To: quic-issues@ietfa.amsl.com
Delivered-To: quic-issues@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 709AD130FE9 for <quic-issues@ietfa.amsl.com>; Wed, 13 Feb 2019 21:40:22 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -8.001
X-Spam-Level:
X-Spam-Status: No, score=-8.001 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=0.001, MAILING_LIST_MULTI=-1, RCVD_IN_DNSWL_HI=-5, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (1024-bit key) header.d=github.com
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OCw3ALXSLhDm for <quic-issues@ietfa.amsl.com>; Wed, 13 Feb 2019 21:40:19 -0800 (PST)
Received: from out-11.smtp.github.com (out-11.smtp.github.com [192.30.254.194]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 72F77130FE8 for <quic-issues@ietf.org>; Wed, 13 Feb 2019 21:40:19 -0800 (PST)
Date: Wed, 13 Feb 2019 21:40:18 -0800
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=github.com; s=pf2014; t=1550122818; bh=yBLLDpjaQDCErKw9DEHBj0bciJG7gxBXw40b1aziM38=; h=Date:From:Reply-To:To:Cc:In-Reply-To:References:Subject:List-ID: List-Archive:List-Post:List-Unsubscribe:From; b=fGtiKWpt8JxoupdXB9/p0FnKAfbYXcTcXXmXaL6rj+pXe0oKn/G+jXZ5oTNdlds0S oO2dwmWjihj7yEfbF6j9lWdP2R2+XAZ3iwjevOepj8oULLAYIoNx/gOexXldN3+zjY ndJ3wYxdxpyTQswefP/qF1W0calaVRnknf9RCJdg=
From: Martin Thomson <notifications@github.com>
Reply-To: quicwg/base-drafts <reply+0166e4ab0b426356575aa65a9fb40c097395dcc49bf36b1f92cf00000001187cc14292a169ce1770e975@reply.github.com>
To: quicwg/base-drafts <base-drafts@noreply.github.com>
Cc: Subscribed <subscribed@noreply.github.com>
Message-ID: <quicwg/base-drafts/pull/2237/review/203533711@github.com>
In-Reply-To: <quicwg/base-drafts/pull/2237@github.com>
References: <quicwg/base-drafts/pull/2237@github.com>
Subject: Re: [quicwg/base-drafts] Rework Key Update (#2237)
Mime-Version: 1.0
Content-Type: multipart/alternative; boundary="--==_mimepart_5c64ff428d725_42543fcaa9cd45c016599b"; charset="UTF-8"
Content-Transfer-Encoding: 7bit
Precedence: list
X-GitHub-Sender: martinthomson
X-GitHub-Recipient: quic-issues
X-GitHub-Reason: subscribed
X-Auto-Response-Suppress: All
X-GitHub-Recipient-Address: quic-issues@ietf.org
Archived-At: <https://mailarchive.ietf.org/arch/msg/quic-issues/x7i5RHwL7sYOC49V8F_Xe8Twm3c>
X-BeenThere: quic-issues@ietf.org
X-Mailman-Version: 2.1.29
List-Id: Notification list for GitHub issues related to the QUIC WG <quic-issues.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/quic-issues>, <mailto:quic-issues-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/quic-issues/>
List-Post: <mailto:quic-issues@ietf.org>
List-Help: <mailto:quic-issues-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/quic-issues>, <mailto:quic-issues-request@ietf.org?subject=subscribe>
X-List-Received-Date: Thu, 14 Feb 2019 05:40:22 -0000

martinthomson commented on this pull request.



> +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 a
+KEYS_ACTIVE 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_ACTIVE frame from a packet with a matching key phase.  This ensures that
+keys are available to both peers before another can be initiated.
+
+Once an endpoint has successfully processed a packet with the same key phase, it
+can send a KEYS_ACTIVE frame.  Endpoints MAY defer sending a KEYS_ACTIVE frame
+after a key update (see {{key-update-old-keys}}).
+

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 packet containing its last KEYS_ACTIVE frame, 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 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}}.  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}}).
+

No difference intended.  I've tried to even this out.

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

Text added.

> +place of discarded keys when key updates are not permitted.
+
+
+## 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.
+
+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 that use the Key Phase bit; endpoints MUST NOT defer
+sending of KEYS_ACTIVE during and immediately after the handshake.
+

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.

> +## 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.
+
+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 that use the Key Phase bit; endpoints MUST NOT defer
+sending of KEYS_ACTIVE during and immediately after the handshake.
+
+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
+with newer keys.  An endpoint that successfully removes protection with old keys

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.

> @@ -1259,15 +1259,13 @@ Client                                                  Server
 Initial[0]: CRYPTO[CH] ->
 
                                  Initial[0]: CRYPTO[SH] ACK[0]
-                       Handshake[0]: CRYPTO[EE, CERT, CV, FIN]
+           Handshake[0]: KEYS_ACTIVE, CRYPTO[EE, CERT, CV, FIN]
                                  <- 1-RTT[0]: STREAM[1, "..."]

Yes, this is the logic.  I had to tweak the description of the frame to account for that though...

>                        <--------
+... Update to @N
+@N [1] QUIC Packets

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.

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

No.  Because packets can be injected.

> @@ -2934,6 +2931,9 @@ containing that information is acknowledged.
 * PING and PADDING frames contain no information, so lost PING or PADDING frames
   do not require repair.
 
+* KEYS_ACTIVE frames are sent until acknowledged or until newer keys are used
+  for sending packets.

It is correct.

Interesting observation:  If your KEYS_ACTIVE got through and you don't see the ACK before your peer updates again, then you can just retransmit, but it's a different frame at that point.

That suggests that maybe you don't need to worry about stopping retransmission for KEYS_ACTIVE.  The sender can always update, and the sender of a packet with new keys containing KEYS_ACTIVE is always receptive to a key update.

Technically however, KEYS_ACTIVE sent in those circumstances has different semantics, so the text is correct as is.

> +both sent and received, older keys can be safely discarded.
+
+The KEYS_ACTIVE frame contains no additional fields.
+
+The packet that carries a KEYS_ACTIVE frame determines which keys are active and
+usable.  The keys with the same key phase as those used in the packet that
+carries the KEYS_ACTIVE frame are active.
+
+An endpoint MUST send a KEYS_ACTIVE packet in the first packet it sends using
+keys, but only if it is also able to receive packets that are protected using
+the corresponding keys.
+
+KEYS_ACTIVE frames are retransmitted when declared lost, however implementations
+need to take care not to retransmit lost KEYS_ACTIVE frames if they initiate a
+subsequent key update.  This can happen if an acknowledgment for a packet
+containing a KEYS_ACTIVE frame is lost.

Say I initiate an update.  I receive a KEYS_ACTIVE in an updated packet.

At this point, I am expected to start sending KEYS_ACTIVE.  But I can also initiate another key update.

If I initiate a key update, which I can do without sending any more packets, then I MUST NOT send a KEYS_ACTIVE in that packet, because that leaves me open to a double update from my peer.

> +
+KEYS_ACTIVE frames are retransmitted when declared lost, however implementations
+need to take care not to retransmit lost KEYS_ACTIVE frames if they initiate a
+subsequent key update.  This can happen if an acknowledgment for a packet
+containing a KEYS_ACTIVE frame is lost.
+
+Endpoints MUST NOT send KEYS_ACTIVE frames in Initial or 0-RTT packets.
+
+A KEYS_ACTIVE frame used during the handshake can be used to indicate the
+availability of Handshake keys by including it in a Handshake packet.  An
+endpoint sends this frame in its first Handshake packet.  Once received, an
+endpoint can discard Initial keys.
+
+A KEYS_ACTIVE frame used after the completion of the handshake in 1-RTT packets
+indicates that Handshake keys are no longer needed.  A client sends this frame
+in its first 1-RTT packet, and a server sends this frame in the first packet it

I'm going with MUST.

> +KEYS_ACTIVE frames are retransmitted when declared lost, however implementations
+need to take care not to retransmit lost KEYS_ACTIVE frames if they initiate a
+subsequent key update.  This can happen if an acknowledgment for a packet
+containing a KEYS_ACTIVE frame is lost.
+
+Endpoints MUST NOT send KEYS_ACTIVE frames in Initial or 0-RTT packets.
+
+A KEYS_ACTIVE frame used during the handshake can be used to indicate the
+availability of Handshake keys by including it in a Handshake packet.  An
+endpoint sends this frame in its first Handshake packet.  Once received, an
+endpoint can discard Initial keys.
+
+A KEYS_ACTIVE frame used after the completion of the handshake in 1-RTT packets
+indicates that Handshake keys are no longer needed.  A client sends this frame
+in its first 1-RTT packet, and a server sends this frame in the first packet it
+sends after completing the handshake.  A server might send 1-RTT keys prior to

Oops, I meant packets.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2237#discussion_r256660837