-
Notifications
You must be signed in to change notification settings - Fork 158
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
Special-case the hash for CH1 when HRR is used. This allows the #901
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1450,6 +1450,7 @@ processed and transmitted as specified by the current active connection state. | |
client_key_exchange_RESERVED(16), | ||
finished(20), | ||
key_update(24), | ||
message_hash(254), | ||
(255) | ||
} HandshakeType; | ||
|
||
|
@@ -1986,8 +1987,8 @@ Cookies serve two primary purposes: | |
|
||
- Allowing the server to offload state to the client, thus allowing it to send | ||
a HelloRetryRequest without storing any state. The server does this by | ||
storing the serialized hash state in the cookie (protected | ||
with some suitable integrity algorithm). | ||
storing the hash of the ClientHello in the HelloRetryRequest cookie | ||
(protected with some suitable integrity algorithm). | ||
|
||
When sending a HelloRetryRequest, the server MAY provide a "cookie" extension to the | ||
client (this is an exception to the usual rule that the only extensions that | ||
|
@@ -2621,7 +2622,7 @@ The PSK binder value forms a binding between a PSK and the current | |
handshake, as well as between the handshake in which the PSK was | ||
generated (if via a NewSessionTicket message) and the handshake where | ||
it was used. Each entry in the binders list is computed as an HMAC | ||
over the portion of the ClientHello (including the handshake header) | ||
over a transcript hash (see {{the-transcript-hash}}) containing a partial ClientHello | ||
up to and including the PreSharedKeyExtension.identities field. That | ||
is, it includes all of the ClientHello but not the binders list | ||
itself. The length fields for the message (including the overall | ||
|
@@ -2639,14 +2640,19 @@ and HelloRetryRequest are included in the transcript along with the | |
new ClientHello. For instance, if the client sends ClientHello1, its | ||
binder will be computed over: | ||
|
||
ClientHello1[truncated] | ||
Transcript-Hash(ClientHello1[truncated]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to explicitly call out that because this is a partial ClientHello1, it doesn't need to be turned into the special message_hash form. |
||
|
||
If the server responds with HelloRetryRequest, and the client then sends | ||
ClientHello2, its binder will be computed over: | ||
|
||
ClientHello1 + HelloRetryRequest + ClientHello2[truncated] | ||
Transcript-Hash(ClientHello1, | ||
HelloRetryRequest, | ||
ClientHello2[truncated]) | ||
|
||
The full ClientHello is included in all other handshake hash computations. | ||
Note that in the first flight, ClientHello1[truncated] is hashed directly, | ||
but in the second flight, it is hashed and then reinjected as a | ||
"handshake_hash" message, as described in {{the-transcript-hash}}. | ||
|
||
#### Processing Order | ||
|
||
|
@@ -2855,7 +2861,8 @@ The computations for the Authentication messages all uniformly | |
take the following inputs: | ||
|
||
- The certificate and signing key to be used. | ||
- A Handshake Context based on the transcript of the handshake messages | ||
- A Handshake Context consisting of the set of messages to be | ||
included in the transcript hash. | ||
- A base key to be used to compute a MAC key. | ||
|
||
Based on these inputs, the messages then contain: | ||
|
@@ -2866,19 +2873,13 @@ supporting certificates in the chain. Note that certificate-based | |
client authentication is not available in the 0-RTT case. | ||
|
||
CertificateVerify | ||
: A signature over the value Hash(Handshake Context + Certificate) | ||
: A signature over the value Transcript-Hash(Handshake Context, Certificate) | ||
|
||
Finished | ||
: A MAC over the value Hash(Handshake Context + Certificate + CertificateVerify) | ||
: A MAC over the value Transcript-Hash(Handshake Context, Certificate, CertificateVerify) | ||
using a MAC key derived from the base key. | ||
{:br} | ||
|
||
Because the CertificateVerify signs the Handshake Context + | ||
Certificate and the Finished MACs the Handshake Context + Certificate | ||
+ CertificateVerify, this is mostly equivalent to keeping a running hash | ||
of the handshake messages (exactly so in the pure 1-RTT cases). Note, | ||
however, that subsequent post-handshake authentications do not include | ||
each other, just the messages through the end of the main handshake. | ||
|
||
The following table defines the Handshake Context and MAC Base Key | ||
for each scenario: | ||
|
@@ -2889,9 +2890,37 @@ for each scenario: | |
| Client | ClientHello ... ServerFinished | client_handshake_traffic_secret | | ||
| Post-Handshake | ClientHello ... ClientFinished + CertificateRequest | client_traffic_secret_N | | ||
|
||
In all cases, the handshake context is formed by concatenating the | ||
indicated handshake messages, including the handshake message type | ||
and length fields, but not including record layer headers. | ||
|
||
### The Transcript Hash | ||
|
||
Many of the cryptographic computations in TLS make use of a transcript | ||
hash. This value is computed by hashing the concatenation of | ||
each included handshake message, including the handshake | ||
message header carrying the handshake message type and length fields, | ||
but not including record layer headers. I.e., | ||
|
||
Transcript-Hash(M1, M2, ... MN) = Hash(M1 || M2 ... MN) | ||
|
||
As an exception to this general rule, when the server responds to a | ||
ClientHello with a HelloRetryRequest, the value of ClientHello1 is | ||
replaced with a special synthetic handshake message of handshake | ||
type "message_hash" containing Hash(ClientHello1). I.e., | ||
|
||
Transcript-Hash(ClientHello1, HelloRetryRequest, ... MN) = | ||
Hash(message_hash || // Handshake Type | ||
00 00 Hash.length || // Handshake message length | ||
Hash(ClientHello1) || // Hash of ClientHello1 | ||
HelloRetryRequest ... MN) | ||
|
||
The reason for this construction is to allow the server to do a | ||
stateless HelloRetryRequest by storing just the hash of ClientHello1 | ||
in the cookie, rather than requiring it to export the entire intermediate | ||
hash state (see {{cookie}}). | ||
|
||
In general, implementations can implement the transcript by keeping a | ||
running transcript hash value based on the negotiated hash. Note, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [This is not entirely true for the client due to the PSK binder issue, but we can defer that.] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "in general" covers a lot of sins |
||
however, that subsequent post-handshake authentications do not include | ||
each other, just the messages through the end of the main handshake. | ||
|
||
### Certificate | ||
|
||
|
@@ -3111,7 +3140,7 @@ signature is a digital signature using that algorithm. The content | |
to be signed is the hash output as described in | ||
{{authentication-messages}} namely: | ||
|
||
Hash(Handshake Context + Certificate) | ||
Transcript-Hash(Handshake Context, Certificate) | ||
|
||
The digital signature is then computed over the concatenation of: | ||
|
||
|
@@ -3132,7 +3161,7 @@ and for a client signature is "TLS 1.3, client | |
CertificateVerify". It is used to provide separation between signatures | ||
made in different contexts, helping against potential cross-protocol attacks. | ||
|
||
For example, if Hash(Handshake Context + Certificate) was 32 bytes of | ||
For example, if the transcript hash was 32 bytes of | ||
01 (this length would make sense for SHA-256), the content covered by | ||
the digital signature for a server CertificateVerify would be: | ||
|
||
|
@@ -3227,9 +3256,9 @@ Structure of this message: | |
The verify_data value is computed as follows: | ||
|
||
verify_data = | ||
HMAC(finished_key, Hash(Handshake Context + | ||
Certificate* + | ||
CertificateVerify*)) | ||
HMAC(finished_key, | ||
Transcript-Hash(Handshake Context, | ||
Certificate*, CertificateVerify*)) | ||
|
||
* Only included if present. | ||
|
||
|
@@ -4045,7 +4074,7 @@ defined below: | |
|
||
Derive-Secret(Secret, Label, Messages) = | ||
HKDF-Expand-Label(Secret, Label, | ||
Hash(Messages), Hash.length) | ||
Transcript-Hash(Messages), Hash.length) | ||
~~~~ | ||
|
||
The Hash function and the HKDF hash are the cipher suite hash algorithm. | ||
|
@@ -4381,7 +4410,7 @@ and their allocation policies are below: | |
Standards Action {{RFC5226}}. IANA \[SHALL update/has updated] this registry | ||
to rename item 4 from "NewSessionTicket" to "new_session_ticket" | ||
and to add the "hello_retry_request", "encrypted_extensions", | ||
"end_of_early_data", and "key_update" values. | ||
"end_of_early_data", "key_update", and "handshake_hash" values. | ||
|
||
This document also uses a registry originally created in {{RFC4366}}. IANA has | ||
updated it to reference this document. The registry and its allocation policy | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an IANA section that needs updating?