tlswg / tls13-spec

TLS 1.3 Specification
562 stars 158 forks source link

Ilari ] #543

Closed ekr closed 7 years ago

ekr commented 8 years ago

Copying here so they don't get lost.

On Mon, Jul 11, 2016 at 12:08:00PM -0700, Eric Rescorla wrote:

Folks,

I've just submitted draft-ietf-tls-tls13-14.txt and it should show up on the draft repository shortly. In the meantime you can find the editor's copy in the usual location at:

As usual, comments welcome. -Ekr

Did a readthrough, here's a bunch of comments (didn't check the issues list):


Zero-RTT Data

[[OPEN ISSUE: Should it be possible to combine 0-RTT with the server authenticating via a signature https://github.com/tlswg/tls13-spec/issues/443]]

One should note that it is not clear what sort of continuity properties should be provoded:

The last choice obviously limits lifetime of derived PSK to the parent certificate.

Also, extension matching is quite different between those three (and the last two are rather different from the current rules, tuned for 0-RTT only being used with PSK.

Numbers

Note that in some cases (e.g., DH parameters) it is necessary to represent integers as opaque vectors. In such cases, they are represented as unsigned integers (i.e., additional leading zero octets are not used even if the most significant bit is set).

Well, I think the DH parameters are gone, but DH public keys are still there, and those AFAIK are padded with zeroes.

Client Hello

When this message will be sent:

When a client first connects to a server, it is required to send the ClientHello as its first message. The client will also send a ClientHello when the server has responded to its ClientHello with a ServerHello that selects cryptographic parameters that don't match the client's "key_share" extension. In that case, the client MUST send the same ClientHello (without modification) except:

Should the "ServerHello" be "HelloRetryRequest"?

  • Including a new KeyShareEntry as the lowest priority share (i.e., appended to the list of shares in the "key_share" extension).
  • Removing the EarlyDataIndication {{early-data-indication}} extension if one was present. Early data is not permitted after HelloRetryRequest.

Also, adding cookie extension if that was present in HRR?

BTW, with the early_data context and cross-connection cookies gone, I have figured out how to delta-compress the first client_hello and its rejection against to-be-sent second client hello plus connection parameters server selected into 6 bytes(!) of space (not including return-reachability check or MAC).

Server Hello

cipher_suite : The single cipher suite selected by the server from the list in ClientHello.cipher_suites. For resumed sessions, this field is the value from the state of the session being resumed. [[TODO: interaction with PSK.]]

Isn't this the true ciphersuite used on this connection, "resumption" or not? Otherwise you can get into all sorts of crazy situations that WILL be sources of implementation bugs.

The idea that it isn't true ciphersuite brings me bad flashbacks about TLS 1.2 ticket "maybe resume" craziness (except this would be even worse).

extensions : A list of extensions. Note that only extensions offered by the client can appear in the server's list. In TLS 1.3, as opposed to previous versions of TLS, the server's extensions are split between the ServerHello and the EncryptedExtensions {{encrypted-extensions}} message. The ServerHello MUST only include extensions which are required to establish the cryptographic context. Currently the only such extensions are "key_share", "pre_shared_key", and "early_data". Clients MUST check the ServerHello for the presence of any forbidden extensions and if any are found MUST terminate the handshake with a "illegal_parameter" alert. In prior versions of TLS, the extensions field could be omitted entirely if not needed, similar to ClientHello. As of TLS 1.3, all clients and servers will send at least one extension (at least "key_share" or "pre_shared_key").

Hasn't early_data just moved to EncryptedExtensions?

Hello Retry Request

selected_group : The mutually supported group the server intends to negotiate and is requesting a retried ClientHello/KeyShare for. {:br }

What is written into this field if server selects pure-PSK ciphersuite and then decides to reject the ClientHello? Or connections that use pure-PSK just plain can't be rejected for any reason (including IP address verification in DTLS?)

[[NOTE: cipher_suite may disappear. https://github.com/tlswg/tls13-spec/issues/528]]

Currently assuming pure-PSK rejections are possible, cipher_suite is needed to tell if the next group field contains anything sane or not...

The server SHOULD send only the extensions necessary for the client to generate a correct ClientHello pair (currently no such extensions exist). As with ServerHello, a HelloRetryRequest MUST NOT contain any extensions that were not first offered by the client in its ClientHello.

What about cookie? IIRC, it is allowed to be in HRR even without being in CH...

Upon receipt of a HelloRetryRequest, the client MUST first verify that the selected_group field corresponds to a group which was provided in the "supported_groups" extension in the original ClientHello. It MUST then verify that the selected_group field does not correspond to a group which was provided in the "key_share" extension in the original ClientHello. If either of these checks fails, then the client MUST abort the handshake with a fatal "handshake_failure" alert. Clients SHOULD also abort with "handshake_failure" in response to any second HelloRetryRequest which was sent in the same connection (i.e., where the ClientHello was itself in response to a HelloRetryRequest).

Otherwise, the client MUST send a ClientHello with an updated KeyShare extension to the server. The client MUST append a new KeyShareEntry for the group indicated in the selected_group field to the groups in its original KeyShare.

Again, rejections with cookie aren't spurious, and the cookie needs to be added.

Hello Extensions

An extension type MUST NOT appear in the ServerHello or HelloRetryRequest unless the same extension type appeared in the corresponding ClientHello. If a client receives an extension type in ServerHello or HelloRetryRequest that it did not request in the associated ClientHello, it MUST abort the handshake with an "unsupported_extension" fatal alert.

Cookie in HRR might not follow that....

In general, the specification of each extension type needs to describe the effect of the extension both during full handshake and session resumption. Most current TLS extensions are relevant only when a session is initiated: when an older session is resumed, the server does not process these extensions in ClientHello, and does not include them in ServerHello. However, some extensions may specify different behavior during session resumption. [[TODO: update this and the previous paragraph to cover PSK-based resumption.]]

I would say that it is a bad idea for any extension to do anything special with "resumption" without very good reasons.

In fact, the only non-connection-control extension that is relevant for PSK I know is server_name.

Now, ALPN (connection-control by definition!) behaves specially with early_data for darn good reasons (the ALP is locked).

This is made worse by the fact that what consistutes "resumption" is not clearly defined (the ALPN rules are related to early_data, not choosing PSK #0!).

Signature Algorithms

  • In TLS 1.2, the extension contained hash/signature pairs. The pairs are encoded in two octets, so SignatureScheme values have been allocated to align with TLS 1.2's encoding. Some legacy pairs are left unallocated. These algorithms are deprecated as of TLS 1.3. They MUST NOT be offered or negotiated by any implementation. In particular, MD5 {{SLOTH}} and SHA-224 MUST NOT be used.
  • ecdsa_secp256r1_sha256, etc., align with TLS 1.2's ECDSA hash/signature pairs. However, the old semantics did not constrain the signing curve.

Also, for interoperability, any legal TLS 1.3 meaning of these algorithms must be extended to apply to TLS 1.2, even for TLS 1.2 ClientHello. Anything else would be pointless trap.

This impiles that RSA PSS and EdDSA work in TLS 1.2 and also how those work.

Also, even if meaning of the ECDSA codepoints changed, those would not break that rule, since new definition is strict subset of old.

Negotiated Groups

As of TLS 1.3, servers are permitted to send the "supported_groups" extension to the client. If the server has a group it prefers to the ones in the "key_share" extension but is still willing to accept the ClientHello, it SHOULD send "supported_groups" to update the client's view of its preferences. Clients MUST NOT act upon any information found in "supported_groups" prior to successful completion of the handshake, but MAY use the information learned from a successfully completed handshake to change what groups they offer to a server in subsequent connections.

Are those supposed to be filtered to be subset of ones client advertised or not? E.g. if client didn't indicate support for x448, can the server still send x448?

Key Share

If this extension is not provided in a ServerHello or ClientHello, and the peer is offering (EC)DHE cipher suites, then the endpoint MUST close the connection with a fatal "missing_extension" alert. (see {{mti-extensions}})

Doesn't seem to consistent with the other descriptions of this and pre_shared_key (those are just "MUST NOT select covered ciphersuite if missing"). Of course, in practice, it might be more this (at least that's how I would implement it)...

[[TODO: Recommendation about what the client offers. Presumably which integer DH groups and which curves.]]

Bit crazy algorithm: If you haven't heard of this server before, pick smallest you support, if you have, pick the one it selected the last time.

Pre-Shared Key Extension

Note that although 0-RTT data is encrypted with the first PSK identity, the server MAY fall back to 1-RTT and select a different PSK identity if multiple identities are offered.

The temporal ordering in messages is actually selecting different PSK and then rejecting 0-RTT.

Early Data Indication

obfuscated_ticket_age : The time since the client learned about the server configuration that it is using, in milliseconds. This value is added modulo 2^32 to with the "ticket_age_add" value that was included with the ticket, see {{NewSessionTicket}}. This addition prevents passive observers from correlating sessions unless tickets are reused. Note: because ticket lifetimes are restricted to a week, 32 bits is enough to represent any plausible age, even in milliseconds.

And the addition also prevents correlating session with its parent, even in case of reuse (this was the reason for switching to addition from XOR).

A server MUST validate that the ticket_age is within a small tolerance of the time since the ticket was issued (see {{replay-time}}).

Good luck with that...

Also, requirement that the server MUST proceed with the handshake and reject 0-RTT if that validation fails would be good here...

0-RTT messages sent in the first flight have the same content types as their corresponding messages sent in other flights (handshake, application_data, and alert respectively) but are protected under different keys. After all the 0-RTT application data messages (if any) have been sent, an "end_of_early_data" alert of type "warning" is sent to indicate the end of the flight. 0-RTT MUST always be followed by an "end_of_early_data" alert.

This does not talk about if end_of_early_data alert is encrypted or not (obviously encrypted one won't work if server rejected 0-RTT, unless server trial-decrypts).

If any of these checks fail, the server MUST NOT respond with the extension and must discard all the remaining first flight data (thus falling back to 1-RTT). If the client attempts a 0-RTT handshake but the server rejects it, it will generally not have the 0-RTT record protection keys and must instead trial decrypt each record with the 1-RTT handshake keys until it finds one that decrypts properly, and then pick up the handshake from that point.

Oh, still trial decryption... Got it.

Processing Order

Clients are permitted to "stream" 0-RTT data until they receive the server's Finished, only then sending the "end_of_early_data" alert. In order to avoid deadlock, when accepting "early_data", servers MUST process the client's Finished and then immediately send the ServerHello, rather than waiting for the client's "end_of_early_data" alert.

I think there was some proposal to dump the Finished. Would simplify implementation. In TLS, there is at least one appdata record with its MAC to be deprotected. That's not true in DTLS.

However, even in DTLS, any wrong keys almost certainly cause handshake to immediately blow up as handshake keys won't match up...

Replay Properties {#replay-time}

There are several potential sources of error that make an exact measurement of time difficult. Variations in client and server clocks are likely to be minimal, outside of gross time corrections. Network propagation delays are most likely causes of a mismatch in legitimate values for elapsed time. Both the NewSessionTicket and ClientHello messages might be retransmitted and therefore delayed, which might be hidden by TCP.

I don't think variations in clocks are minimal...

I wonder what 95% timeskew interval per day is...

(Oh, and have fun with leap seconds!)

Encrypted Extensions

The same extension types MUST NOT appear in both the ServerHello and EncryptedExtensions. If the same extension appears in both locations, the client MUST rely only on the value in the EncryptedExtensions block. All server-sent extensions other than those explicitly listed in {{server-hello}} or designated in the IANA registry MUST only appear in EncryptedExtensions. Extensions which are designated to appear in ServerHello MUST NOT appear in EncryptedExtensions. Clients MUST check EncryptedExtensions for the presence of any forbidden extensions and if any are found MUST terminate the handshake with an "illegal_parameter" alert.

This seems inconsistent. In implementation, I would write explicit disjoint whitelists of extensions for both (and non-whitelisted one is a fatal error). Explicit whitelisting is safe even on client side, since the extensions are bounded by client-supported ones.

Certificate Request

  • The Extended Key Usage extension in a certificate matches the request when all key purpose OIDs present in the request are also found in the Extended Key Usage certificate extension. The special anyExtendedKeyUsage OID MUST NOT be used in the request.

How are multiple OIDs represented? Multiple EKU OID/value pairs?

Server Certificate Selection

  • The "server_name" and "trusted_ca_keys" extensions {{RFC6066}} are used to guide certificate selection. As servers MAY require the presence of the "server_name" extension, clients SHOULD send this extension, when applicable.

I think the certificate should be REQUIRED to match (as in, not be inconsistent with it) server_name, even if not ACK'd.

Certificate Verify

If sent by a server, the signature algorithm MUST be one offered in the client's "signature_algorithms" extension unless no valid certificate chain can be produced without unsupported algorithms (see {{signature-algorithms}}). Note that there is a possibility for inconsistencies here. For instance, the client might offer an ECDHE_ECDSA cipher suite but omit any ECDSA and EdDSA values from its "signature_algorithms" extension. In order to negotiate correctly, the server MUST check any candidate cipher suites against the "signature_algorithms" extension before selecting them. This is somewhat inelegant but is a compromise designed to minimize changes to the original cipher suite design.

The exception on not having valid value can not work at all. With certificates, even if the EE cert is signed with unknown algorithm, there is a small chance things will work. In contrast, there is absolutely no chance of success if either endpoint tries ot use this fallback.

Note: When used with non-certificate-based handshakes (e.g., PSK), the client's signature does not cover the server's certificate directly, although it does cover the server's Finished message, which transitively includes the server's certificate when the PSK derives from a certificate-authenticated handshake. {{PSK-FINISHED}} describes a concrete attack on this mode if the Finished is omitted from the signature. It is unsafe to use certificate-based client authentication when the client might potentially share the same PSK/key-id pair with two different endpoints. In order to ensure this, implementations MUST NOT mix certificate-based client authentication with pure PSK modes (i.e., those where the PSK was not derived from a previous non-PSK handshake).

Does this apply to in-handshake or post-handshake auth? I thought in-handshake auth with PSK is not possible.

If it is intended to be possible, that's certainly going to be surprising to implementers, and there are probably going to be multiple implementations that outright choke if one tries to send CertificateRequest in (DHE-)PSK mode

Record Payload Protection

length : The length (in bytes) of the following TLSCiphertext.fragment, which is the sum of the lengths of the content and the padding, plus one for the inner content type. The length MUST NOT exceed 2^14 + 256. An endpoint that receives a record that exceeds this length MUST generate a fatal "record_overflow" alert.

Later the document seems to imply that the limit for for content+type+ padding is in fact 16385 bytes.

Per-Record Nonce {#nonce}

Sequence numbers do not wrap. If a TLS implementation would need to wrap a sequence number, it MUST either rekey ({{key-update}}) or terminate the connection.

Maybe add requirement that record with sequence number of 2^64-1 MUST be either fatal alert or KeyUpdate.

Limits on Key Usage

For AES-GCM, up to 2^24.5 full-size records may be encrypted on a given connection while keeping a safety margin of approximately 2^-57 for Authenticated Encryption (AE) security. For ChaCha20/Poly1305, the record sequence number will wrap before the safety limit is reached.

I would expand that 2^24.5 to some rough number ("about 24 million"?).

And also "will wrap" -> "would wrap". Because such wrapping can't happen (even if endpoint delays KeyUpdate to RSN 2^64-1).

Key Schedule

If a given secret is not available, then the 0-value consisting of a string of Hash.length zeroes is used. Note that this does not mean skipping rounds, so if PSK is not in use Early Secret will still be HKDF-Extract(0, 0).

This might cause fun with future key exchange types...

IANA Considerations

Extension Recommended TLS 1.3
max_fragment_length [RFC6066] Yes Encrypted

I think this needs to be in ServerHello on server-side, given how low- level it is.

| user_mapping [RFC4681] | Yes | Encrypted | | client_authz [RFC5878] | No | Encrypted | | server_authz [RFC5878] | No | Encrypted |

These darn things use Supplemental Data messages, would need to define where the data goes. And one can't stick it to extension for user_mapping and client_authz, because those are sent by the client, not the server.

| cookie [[this document]] | Yes | Encrypted/HelloRetryRequest |

Isn't that "Client/HelloRetryRequest"? I don't think EncryptedExtensions can have Cookie...

  • TLS SignatureScheme Registry: Values with the first byte in the range 0-254 (decimal) are assigned via Specification Required {{RFC2434}}. Values with the first byte 255 (decimal) are reserved for Private Use {{RFC2434}}. This registry SHALL have a "Recommended" column. The registry [shall be/ has been] initially populated with the values described in {{signature-algorithms}}. The following values SHALL be marked as "Recommended": ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, rsa_pss_sha256, rsa_pss_sha384, rsa_pss_sha512, ed25519.

Should the two registeries shadowed by this closed?

Cipher Suites

Note: The values listed for ECDHE and ChaCha/Poly are preliminary but are being or will be used for interop testing and therefore are likely to be assigned.

Isn't the RFC already published, so the codepoints are stable?

Random Number Generation and Seeding

To estimate the amount of seed material being produced, add the number of bits of unpredictable information in each seed byte. For example, keystroke timing values taken from a PC compatible 18.2 Hz timer provide 1 or 2 secure bits each, even though the total size of the counter value is 16 bits or more. Seeding a 128-bit PRNG would thus require approximately 100 such timer values.

This seems really obsolete. The timers have not been 18.2Hz for years, and applications running on operating systems damn better use OS services for random numbers, given that anything else is fraught with peril.

Implementation Pitfalls

  • Have you ensured that all support for SSL, RC4, EXPORT ciphers, and MD5 (via the "signature_algorithm" extension) is completely removed from all possible configurations that support TLS 1.3 or later, and that attempts to use these obsolete capabilities fail correctly? (see {{backward-compatibility}})

Better to just nuke the code entierely for all versions.

"Disabled" code has nasty tendency of coming back to life.

  • Do you handle TLS extensions in ClientHello correctly, including unknown extensions or omitting the extensions field completely?

The extensions field can't be omitted in TLS 1.3. And I would consider TLS 1.2 client implementations that send such messages as quite pathological.

Cryptographic details:

  • What countermeasures do you use to prevent timing attacks against RSA signing operations {{TIMING}}?

Also, ECDSA signing operations do have problems with timing attacks.

  • When verifying RSA signatures, do you accept both NULL and missing parameters? Do you verify that the RSA padding doesn't have additional data after the hash value? {{FI06}}

Also, the lengths need to be correct (not verifying this leads to an attack). Best just to treat first length bytes >0x82 or >0x83 as malformed. There is no way to send legimate message with first length byte >0x83 in TLS.

Overview of Security Properties {#security-analysis}

[[TODO: This section is still a WIP and needs a bunch more work.]]

A complete security analysis of TLS is outside the scope of this document. In this section, we provide an informal description the desired properties as well as references to more detailed work in the research literature which provides more formal definitions.

We cover properties of the handshake separately from those of the record layer.

I think properties of the exporter should be covered as well:

(The TLS 1.2 exporter without EMS failed the middle requirement, creating security issues in applications that assumed the data was connection-unique.


-Ilari

Dave Garrett 10:52 PM (6 hours ago)

to tls, Ilari, me Just replying to a few points.

On Tuesday, July 12, 2016 12:16:24 am Ilari Liusvaara wrote:

Hello Retry Request

selected_group : The mutually supported group the server intends to negotiate and is requesting a retried ClientHello/KeyShare for. {:br }

What is written into this field if server selects pure-PSK ciphersuite and then decides to reject the ClientHello? Or connections that use pure-PSK just plain can't be rejected for any reason (including IP address verification in DTLS?)

The HelloRetryRequest message is not applicable to pure-PSK, which does not use the KeyShare extension at all. PSK has its own separate extension. ((EC)DHE-PSK uses both together)

The purpose of HelloRetryRequest is to allow for clients to not send full keys for every single algorithm they support, yet allow the server to still pick from that entire list if it needs to. PSK has no equivalent system; pre-shared keys are first-flight or bust. If an (EC)DHE-PSK suite is selected, and a valid PSK identity is selected, the server can use HelloRetryRequest to reject a group in favor of another supported by the client, but it can't reject the suite or identity in this manner. The response to no acceptable PSK identity is either to negotiate another suite or to abort with a fatal alert.

See draft 14 section 4.2.5: https://tools.ietf.org/html/draft-ietf-tls-tls13-14#section-4.2.5

Cipher Suites

Note: The values listed for ECDHE and ChaCha/Poly are preliminary but are being or will be used for interop testing and therefore are likely to be assigned.

Isn't the RFC already published, so the codepoints are stable?

xiaoyinl fixed the second one of those notes, but that was merged after the checkpoint for draft 14. I'll fix this one to just note for ECDHE PSK AES.

Implementation Pitfalls

  • Have you ensured that all support for SSL, RC4, EXPORT ciphers, and MD5 (via the "signature_algorithm" extension) is completely removed from all possible configurations that support TLS 1.3 or later, and that attempts to use these obsolete capabilities fail correctly? (see {{backward-compatibility}})

Better to just nuke the code entierely for all versions.

"Disabled" code has nasty tendency of coming back to life.

Emphatically agreed, however I worded it this way to be slightly more general. If I said that all that code should be universally gutted, I'd risk more people ignoring it due to the severe status quo bias that is very common. In lieu of modernizing fully and dropping it completely, having these old features disabled via the same compile-time option that enables building of TLS 1.3 would be acceptable, IMO (though, more trouble than it should be worth, and still not ideal at all). Bikeshedding better wordings in this section would not be unwelcome, if you think anything here can be made better.

  • Do you handle TLS extensions in ClientHello correctly, including unknown extensions or omitting the extensions field completely?

The extensions field can't be omitted in TLS 1.3. And I would consider TLS 1.2 client implementations that send such messages as quite pathological.

Implementations should be expected to handle pathological cases gracefully, even if only to recognize and reject. ;)

Ilari Liusvaara 2:00 AM (3 hours ago)

to Dave, tls, me On Tue, Jul 12, 2016 at 01:52:57AM -0400, Dave Garrett wrote:

Just replying to a few points.

On Tuesday, July 12, 2016 12:16:24 am Ilari Liusvaara wrote:

Hello Retry Request

selected_group : The mutually supported group the server intends to negotiate and is requesting a retried ClientHello/KeyShare for. {:br }

What is written into this field if server selects pure-PSK ciphersuite and then decides to reject the ClientHello? Or connections that use pure-PSK just plain can't be rejected for any reason (including IP address verification in DTLS?)

The HelloRetryRequest message is not applicable to pure-PSK, which does not use the KeyShare extension at all. PSK has its own separate extension. ((EC)DHE-PSK uses both together)

Yes, rejection because of group mismatch can't occur. However, I don't see any requirement not to reject pure-PSK for cookie check (might be feasible, if the computational and network load is determined "small enough").

Cipher Suites

Note: The values listed for ECDHE and ChaCha/Poly are preliminary but are being or will be used for interop testing and therefore are likely to be assigned.

Isn't the RFC already published, so the codepoints are stable?

xiaoyinl fixed the second one of those notes, but that was merged after the checkpoint for draft 14. I'll fix this one to just note for ECDHE PSK AES.

IIRC, there was merged patch that changed the reference, but not the text. Just checked, seems to still be there in Editor's Copy.

ekr commented 8 years ago

@ilaril I think I have dealt with most of these.

ilaril commented 8 years ago

On Sat, Sep 03, 2016 at 12:49:39PM -0700, ekr wrote:

@ilaril I think I have dealt with most of these.

  • You say "Later the document seems to imply that the limit for for content+type+ padding is in fact 16385 bytes." If you point out where I will fix it.

Probably just me misreading the 255 byte limit for expansion from protection and the 16384+1+255 formula for the 16384+256 byte limit.

Also, what's the protected limit if max_fragment_length is in effect? 256 bytes above the plaintext limit (so e.g. 768 bytes for 512 byte plaintext limit)?

  • I don't think max_fragment_length should go in ServerHello because the client doesn't need it to interpret messages from the server.

Actually, probably OK to keep it until EE if included at all because the strictest limit one can apply is 512 octets, and the maximum size of ServerHello is (there is protection change afterwards, so one can't combine the mesage):

This is 56 bytes, plus key share data, leaving at least 456 bytes for the key share. Now, the only DHFs that exceed that are FFDH4k, FFDH6k and FFDH8k (and possible PQ exchanges).

And any device that is puny enough to want 512-byte fragments is very unlikely to support any of those.

  • If you want to provide a PR about RSA in S 8.5 that would be useful.

The first length byte thing?

Actually, that's a special case of doing RSA PKCS#1 v1.5 (CA certs) verification by doing RSA op and then decoding the result, instead of the proper way, which is to do RSA op, encode the expected result and then compare.

-Ilari

ekr commented 7 years ago

Closing this as Ilari did a new review. @ilaril please let me know if there's anything that got missed.