-
Notifications
You must be signed in to change notification settings - Fork 160
Middlebox changes2 hrr #1091
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
Middlebox changes2 hrr #1091
Conversation
CipherSuite cipher_suite; | ||
uint8 legacy_compression_method = 0; | ||
Extension extensions<6..2^16-1>; | ||
} ServerHello; | ||
|
||
version |
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.
nit: legacy_version
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.
Yea, I don't really like it either to have two version fields.
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.
Me neither, but it's that or an insecure version fallback. Aesthetics and cleanliness are valuable, but not at the cost of security.
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.
But the same problem may repeat with future middleboxes.
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.
Future middleboxes should understand TLSv1.3... If they don't, then it's the manufacturers' fault.
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.
We have a few local middleboxes to test with. The setup is nowhere near exhaustive (the variance on these things is huge), but it did allow us to iterate on this locally with a number of designs before testing a few out into the wild. This PR came out of what we've learned from all those experiments.
Variants that didn't fix the ServerHello version didn't even survive the local pass. :-(
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.
So do you know why these individual middleboxes did it?
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.
Also consider that most users know or can find out if they are using middleboxes or not, so an "insecure version fallback" is not the only alternative.
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.
Mostly the only way to know is to measure, and that's just a network attacker.
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.
And is getting into an arms race with middleboxes really a good idea?
@@ -3924,7 +3979,7 @@ by an encrypted body, which itself contains a type and optional padding. | |||
|
|||
struct { | |||
ContentType opaque_type = 23; /* application_data */ | |||
ProtocolVersion legacy_record_version = 0x0301; /* TLS v1.x */ | |||
ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */ |
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.
I'm assuming this was changed to 0x0303 so that middleboxes which view the ClientHello and ServerHello and assume TLS 1.2 was negotiated can verify that the TLSCiphertext.record_version is 0x0303 as expected.
Is it worth adding language either here or in #middlebox explaining why the 0x0301 (in TLSPlaintext) and 0x0303 values were chosen?
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 it worth adding language ...
Probably.
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.
It's not 0x0301 for plaintext and 0x0303 for ciphertext. That wouldn't get through the middleboxes anyway. It's 0x0301 for ClientHello (a long-standing quirk from TLS 1.1) and 0x0303 for everything else. And yeah, you're right that it's to match TLS 1.2.
|
||
- The server sends a dummy change_cipher_spec record immediately | ||
after its first handshake message. This may either be after a | ||
ServerHello or a HelloRetryRequest. |
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.
I thought these were being combined?
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.
I opted to treat it as a separate message for simplicity.
|
||
- The client always provides a non-empty session ID in the ClientHello. | ||
|
||
- If not offering early data, the client sends a dummy |
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.
what does "dummy" mean here? It's a term not used anywhere else in the draft.
Does the CCS has to be always sent? If not, what the other side is supposed to do when it doesn't receive it? What if it receives it at different time? What if it receives multiple CCS messages one after another?
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.
The receiver ignores all CCS records during the handshake, without any care as to where they do or don't appear. It's in the record layer section.
This is based on implementor feedback. Our initial prototype had the receiver enforce the CCS positions, but the handshake/CCS synchronization on the read side is a bit of a mess in TLS 1.2. There was a desire from some folks to not complicate their TLS 1.3 state machined with this. Discarding them at the record layer, on the other hand, is straightforward. (Additionally, it allows any implementation to unilaterally disable compatibility mode if it is deployed somewhere these middlebox issues are less common.)
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.
Perhaps specify that a "dummy CCS record" is one consisting of a single 0x01
byte.
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.
I meant that "dummy" is obvious to us, in this discussion, in the context of this PR. Not necessarily to somebody reading the spec in 5 years.
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.
I don't think dummy is confusing here.
draft-ietf-tls-tls13.md
Outdated
condition prior to attempting to deprotect the record. An | ||
implementation which receives any other change_cipher_spec value or | ||
which receives a protected change_cipher_spec record MUST abort the | ||
handshake with an "illegal_parameter" alert. After the handshake is |
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.
"unexpected_message" seems more appropriate
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.
Agreed.
draft-ietf-tls-tls13.md
Outdated
@@ -1653,7 +1653,7 @@ processed and transmitted as specified by the current active connection state. | |||
hello_verify_request_RESERVED(3), | |||
new_session_ticket(4), | |||
end_of_early_data(5), | |||
hello_retry_request(6), | |||
hello_retry_request_RESERVED(6), |
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.
nit: trailing space
"supported_versions" extension ({{supported-versions}}), | ||
and the legacy_version field MUST | ||
be set to 0x0303, which is the version number for TLS 1.2. | ||
(See {{backward-compatibility}} for details about backward compatibility.) |
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.
Should anything be said about the order of the SV extension relative to other extensions? The definition of extensions might change between versions.
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.
Down at line 2050 we (now?) have:
+Upon receipt of a HelloRetryRequest, the client MUST perform the
+checks specified in {{server-hello}} and then process the
+extensions, starting with determining the version using
+"supported_versions". Clients MUST abort the handshake with
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.
No, I don't think we need to order it. You just make two passes.
draft-ietf-tls-tls13.md
Outdated
this field is echoed even if the client's value corresponded to | ||
a cached pre-TLS 1.3 session which the server has chosen not | ||
to resume. A client which receives a legacy_session_id field | ||
which does not match what it sent in the ClientHello |
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.
nit: s/which/that/
: The contents of the client's legacy_session_id field. Note that | ||
this field is echoed even if the client's value corresponded to | ||
a cached pre-TLS 1.3 session which the server has chosen not | ||
to resume. A client which receives a legacy_session_id field |
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.
We should consider saying something about how the TLS 1.3-aware client must do the version check before the resumption check, in case some existing TLS 1.2 code does a resumption/sesion-id check early in processing and would be confused about what protocol is in use.
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.
Done.
In TLS 1.3, the TLS server indicates its version using the | ||
"supported_versions" extension ({{supported-versions}}), | ||
and the legacy_version field MUST | ||
be set to 0x0303, which is the version number for TLS 1.2. |
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.
Do we want to specify a client alert to send when receiving some other value?
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.
+1. In case legacy_version
is not set to 0x0303 and supported_versions
is present, the connection should fail with illegal_parameter
though it probably should be placed in the legacy_version
description to mirror how Client Hello is described
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.
Actually, we should ignore it to match how we handle ClientHello.legacy_version
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.
And that's what the text already says.
draft-ietf-tls-tls13.md
Outdated
cipher_suite | ||
: The single cipher suite selected by the server from the list in | ||
ClientHello.cipher_suites. A client which receives a cipher suite | ||
that was not offered MUST abort the handshake with an "illegal_parameter" | ||
alert. | ||
|
||
legacy_compression_method | ||
: A single byte of value 0. |
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.
What should a client do if it receives something else?
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.
illegal_parameter
seems like a correct choice
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.
Yes, but we don't need to say it here because illegal_parameter's definitions says o.
ProtocolVersion versions<2..254>; | ||
|
||
case server_hello: | ||
ProtocolVersion selected_version; |
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.
There is probably some editorial (?) work to be done where we still talk about HRR all over the place (in the extensions table), etc., but there is no longer a hello_retry_request message type for the actual protocol elements.
draft-ietf-tls-tls13.md
Outdated
in previous versions of TLS. | ||
A server which negotiates TLS 1.3 MUST respond by sending a | ||
"supported_versions" extension containing the selected version value | ||
(0x0304). It MUST set the ServerHello.version field to 0x0303 (TLS |
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.
legacy_version
draft-ietf-tls-tls13.md
Outdated
which receives a protected change_cipher_spec record MUST abort the | ||
handshake with an "illegal_parameter" alert. After the handshake is | ||
complete, change_cipher_spec MUST be treated as an unexpected record | ||
type. |
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.
I wonder how much more complicated implementations will have to be to reject CCS post-handshake (as opposed to ignoring it always).
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.
Not very it seems.
@@ -3924,7 +3979,7 @@ by an encrypted body, which itself contains a type and optional padding. | |||
|
|||
struct { | |||
ContentType opaque_type = 23; /* application_data */ | |||
ProtocolVersion legacy_record_version = 0x0301; /* TLS v1.x */ | |||
ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */ |
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 it worth adding language ...
Probably.
struct { | ||
ProtocolVersion server_version; | ||
CipherSuite cipher_suite; | ||
Extension extensions<2..2^16-1>; |
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.
One detail I noticed as I was sorting out some of our tests: at one point we had text which disallowed no-op HelloRetryRequests. When HRR got moved to extensions, this turned into just a rule that the extensions block is non-empty. (That plus no unsolicited extensions did the trick.)
This is gone now, but it actually wouldn't have sufficed anyway because every HRR has a supported_versions extension now. So we probably need to go back to explicit text here somewhere.
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.
This is on line 2053.
|
||
- If not offering early data, the client sends a dummy | ||
change_cipher_spec record immediately before its second flight. This | ||
may either be before its second ClientHello or before its encrypted |
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.
A somewhat irksome consequence of this: if you do completely stateless HRR, you need to skip the CCS before parsing your "first" (actually second) ClientHello and picking the version.
(Then again, we only need this over TCP which is stateful...)
draft-ietf-tls-tls13.md
Outdated
HelloRetryRequest and send a second updated ClientHello. The | ||
HelloRetryRequest extensions defined in this specification are: | ||
|
||
- supported_versions (see {{supported_versions}}) |
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.
Reference must be {{supported-versions}}
or the build fails.
No description provided.