From e7f4707d3864a2e63e7d68dd81be85d99dca4134 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Fri, 8 Dec 2017 14:29:42 +1100 Subject: [PATCH 1/3] Update key schedule This changes the labels that we use in key derivations to be shorter. That is in line with similar changes TLS made, so that the number of iterations of the underlying hash function are reduced slightly. QUIC will still run SHA-256 like a bitcoin rig, but this should help some. I've chosen to define the function we use rather than reuse the TLS 1.3 function. It's still the same function, but it now uses a different root label. That should help avoid collisions if QUIC and TLS diverge (though that would be unlikely). The main benefit is in reducing the label length. This also corrects the error in the example. --- draft-ietf-quic-tls.md | 85 ++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 48 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 6ff17f7c0f..ea9ebe0f63 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -656,13 +656,9 @@ client's Initial packet. Specifically: client_connection_id) client_handshake_secret = - HKDF-Expand-Label(handshake_secret, - "QUIC client handshake secret", - "", Hash.length) + QHKDF-Expand(handshake_secret, "client hs", Hash.length) server_handshake_secret = - HKDF-Expand-Label(handshake_secret, - "QUIC server handshake secret", - "", Hash.length) + QHKDF-Expand(handshake_secret, "server hs", Hash.length) ~~~ The HKDF for the handshake secrets and keys derived from them uses the SHA-256 @@ -690,8 +686,7 @@ packets sent by the client. ~~~ client_0rtt_secret - = TLS-Exporter("EXPORTER-QUIC 0-RTT Secret" - "", Hash.length) + = TLS-Exporter("EXPORTER-QUIC 0rtt", "", Hash.length) ~~~ @@ -709,59 +704,54 @@ Both exporters use an empty context. The size of the secret MUST be the size of the hash output for the PRF hash function negotiated by TLS. ~~~ - client_pp_secret_0 - = TLS-Exporter("EXPORTER-QUIC client 1-RTT Secret" - "", Hash.length) - server_pp_secret_0 - = TLS-Exporter("EXPORTER-QUIC server 1-RTT Secret" - "", Hash.length) + client_pp_secret_0 = + TLS-Exporter("EXPORTER-QUIC client 1rtt", "", Hash.length) + server_pp_secret_0 = + TLS-Exporter("EXPORTER-QUIC server 1rtt", "", Hash.length) ~~~ These secrets are used to derive the initial client and server packet protection keys. After a key update (see {{key-update}}), these secrets are updated using the -HKDF-Expand-Label function defined in Section 7.1 of {{!TLS13}}. -HKDF-Expand-Label uses the PRF hash function negotiated by TLS. The replacement -secret is derived using the existing Secret, a Label of "QUIC client 1-RTT -Secret" for the client and "QUIC server 1-RTT Secret" for the server, an empty -HashValue, and the same output Length as the hash function selected by TLS for -its PRF. +QHKDF-Expand function. The QHKDF-Expand function is similar in definition to +HKDF-Expand-Label defined in Section 7.1 of {{!TLS13}}, but it has a different +base label and omits the hash argument. QHKDF-Expand uses the PRF hash function +negotiated by TLS. The replacement secret is derived using the existing Secret, +a Label of "client 1rtt" for the client and "server 1rtt" for the server, and +the same output Length as the PRF hash function selected by TLS. ~~~ - client_pp_secret_ - = HKDF-Expand-Label(client_pp_secret_, - "QUIC client 1-RTT Secret", - "", Hash.length) - server_pp_secret_ - = HKDF-Expand-Label(server_pp_secret_, - "QUIC server 1-RTT Secret", - "", Hash.length) + client_pp_secret_ = + QHKDF-Expand(client_pp_secret_, "client 1rtt", Hash.length) + server_pp_secret_ = + QHKDF-Expand(server_pp_secret_, "server 1rtt", Hash.length) ~~~ This allows for a succession of new secrets to be created as needed. -HKDF-Expand-Label uses HKDF-Expand {{!RFC5869}} with a specially formatted info -parameter, as shown: +HKDF-Expand-Label uses HKDF-Expand {{!RFC5869}} as shown: ~~~ - HKDF-Expand-Label(Secret, Label, HashValue, Length) = - HKDF-Expand(Secret, HkdfLabel, Length) + QHKDF-Expand(Secret, Label, Length) = + HKDF-Expand(Secret, QuicHkdfLabel, Length) +~~~ - Where HkdfLabel is specified as: +Where the info parameter, QuicHkdfLabel, is specified as: +~~~ struct { uint16 length = Length; - opaque label<10..255> = "tls13 " + Label; - uint8 hashLength; // Always 0 - } HkdfLabel; + opaque label<6..255> = "QUIC " + Label; + uint8 hashLength = 0; + } QuicHkdfLabel; ~~~ For example, the client packet protection secret uses an info parameter of: ~~~ info = (HashLen / 256) || (HashLen % 256) || 0x1f || - "tls13 QUIC client 1-RTT secret" || 0x00 + "QUIC client 1rtt" || 0x00 ~~~ @@ -784,8 +774,8 @@ The key length is the AEAD key size. As defined in Section 5.3 of 12). For any secret S, the corresponding key and IV are derived as shown below: ~~~ - key = HKDF-Expand-Label(S, "key", "", key_length) - iv = HKDF-Expand-Label(S, "iv", "", iv_length) + key = QHKDF-Expand(S, "key", key_length) + iv = QHKDF-Expand(S, "iv", iv_length) ~~~ The QUIC record protection initially starts without keying material. When the @@ -812,15 +802,15 @@ attackers. Once TLS has provided a key, the contents of regular QUIC packets immediately after any TLS messages have been sent are protected by the AEAD selected by TLS. -The key, K, is either the client packet protection key (client_pp_key_n) or the -server packet protection key (server_pp_key_n), derived as defined in +The key, K, is either the client packet protection key (client_pp_key_\) or +the server packet protection key (server_pp_key_\), derived as defined in {{key-expansion}}. The nonce, N, is formed by combining the packet protection IV (either -client_pp_iv_n or server_pp_iv_n) with the packet number. The 64 bits of the -reconstructed QUIC packet number in network byte order is left-padded with zeros -to the size of the IV. The exclusive OR of the padded packet number and the IV -forms the AEAD nonce. +client_pp_iv_\ or server_pp_iv_\) with the packet number. The 64 bits +of the reconstructed QUIC packet number in network byte order is left-padded +with zeros to the size of the IV. The exclusive OR of the padded packet number +and the IV forms the AEAD nonce. The associated data, A, for the AEAD is the contents of the QUIC header, starting from the flags octet in either the short or long header. @@ -878,9 +868,8 @@ Section 7.5.1.1 of {{QUIC-TRANSPORT}} also requires a secret to compute packet number gaps on connection ID transitions. That secret is computed as: ~~~ - packet_number_secret - = TLS-Exporter("EXPORTER-QUIC Packet Number Secret" - "", Hash.length) + packet_number_secret = + TLS-Exporter("EXPORTER-QUIC packet number", "", Hash.length) ~~~ # Key Phases From 7ebcc7a710b574616112f961406e75fb846c131e Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Fri, 8 Dec 2017 15:52:18 +1100 Subject: [PATCH 2/3] A few consistency fixes --- draft-ietf-quic-tls.md | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index ea9ebe0f63..5c2c05bb77 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -678,9 +678,9 @@ completion of the TLS handshake. Data sent using 0-RTT keys might be replayed and so has some restrictions on its use, see {{using-early-data}}. 0-RTT keys are used after sending or receiving a ClientHello. -The secret is exported from TLS using the exporter label "EXPORTER-QUIC 0-RTT -Secret" and an empty context. The size of the secret MUST be the size of the -hash output for the PRF hash function negotiated by TLS. This uses the TLS +The secret is exported from TLS using the exporter label "EXPORTER-QUIC 0rtt" +and an empty context. The size of the secret MUST be the size of the hash +output for the PRF hash function negotiated by TLS. This uses the TLS early_exporter_secret. The QUIC 0-RTT secret is only used for protection of packets sent by the client. @@ -698,10 +698,10 @@ keys for packets sent by the client, the other for packet protection keys on packets sent by the server. The initial client packet protection secret is exported from TLS using the -exporter label "EXPORTER-QUIC client 1-RTT Secret"; the initial server packet -protection secret uses the exporter label "EXPORTER-QUIC server 1-RTT Secret". -Both exporters use an empty context. The size of the secret MUST be the size of -the hash output for the PRF hash function negotiated by TLS. +exporter label "EXPORTER-QUIC client 1rtt"; the initial server packet protection +secret uses the exporter label "EXPORTER-QUIC server 1rtt". Both exporters use +an empty context. The size of the secret MUST be the size of the hash output +for the PRF hash function negotiated by TLS. ~~~ client_pp_secret_0 = @@ -758,20 +758,21 @@ For example, the client packet protection secret uses an info parameter of: ### Packet Protection Key and IV The complete key expansion uses an identical process for key expansion as -defined in Section 7.3 of {{!TLS13}}, using different values for -the input secret. QUIC uses the AEAD function negotiated by TLS. +defined in Section 7.3 of {{!TLS13}}, using different values for the input +secret and labels. QUIC uses the AEAD function negotiated by TLS. The packet protection key and IV used to protect the 0-RTT packets sent by a client are derived from the QUIC 0-RTT secret. The packet protection keys and IVs for 1-RTT packets sent by the client and server are derived from the current -generation of client_pp_secret and server_pp_secret respectively. The length of -the output is determined by the requirements of the AEAD function selected by -TLS. All ciphersuites currently used for QUIC have a 16-byte authentication -tag and produce an ouput 16 bytes larger than their input. -The key length is the AEAD key size. As defined in Section 5.3 of -{{!TLS13}}, the IV length is the larger of 8 or N_MIN (see Section -4 of {{!AEAD=RFC5116}}; all ciphersuites defined in {{?TLS13}} have N_MIN set to -12). For any secret S, the corresponding key and IV are derived as shown below: +generation of client and server 1-RTT secrets (client_pp_secret_\ and +server_pp_secret_\) respectively. The length of the output is determined by +the requirements of the AEAD function selected by TLS. All ciphersuites +currently used for QUIC have a 16-byte authentication tag and produce an ouput +16 bytes larger than their input. The key length is the AEAD key size. As +defined in Section 5.3 of {{!TLS13}}, the IV length is the larger of 8 or N_MIN +(see Section 4 of {{!AEAD=RFC5116}}; all ciphersuites defined in {{?TLS13}} have +N_MIN set to 12). For any secret S, the corresponding key and IV are derived as +shown below: ~~~ key = QHKDF-Expand(S, "key", key_length) From a5d5f94f7ae51e6c522a6ea3d91897caf9366d9d Mon Sep 17 00:00:00 2001 From: Sean Turner Date: Tue, 12 Dec 2017 18:27:01 -0500 Subject: [PATCH 3/3] Update draft-ietf-quic-tls.md --- draft-ietf-quic-tls.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-ietf-quic-tls.md b/draft-ietf-quic-tls.md index 5c2c05bb77..d2cdb7b27a 100644 --- a/draft-ietf-quic-tls.md +++ b/draft-ietf-quic-tls.md @@ -770,7 +770,7 @@ the requirements of the AEAD function selected by TLS. All ciphersuites currently used for QUIC have a 16-byte authentication tag and produce an ouput 16 bytes larger than their input. The key length is the AEAD key size. As defined in Section 5.3 of {{!TLS13}}, the IV length is the larger of 8 or N_MIN -(see Section 4 of {{!AEAD=RFC5116}}; all ciphersuites defined in {{?TLS13}} have +(see Section 4 of {{!AEAD=RFC5116}}; all ciphersuites defined in {{!TLS13}} have N_MIN set to 12). For any secret S, the corresponding key and IV are derived as shown below: