haskell-tls / hs-tls

TLS/SSL implementation in haskell
Other
402 stars 87 forks source link

feature request: TLS Encrypted Client Hello #358

Open bjin opened 5 years ago

bjin commented 5 years ago

I understand that this is still a work-in-progress draft extension, and subject to future changes. But considering Firefox and Cloudflare had support of this extension for months now, it doesn't hurt to open an issue early, especially since this extension also involves DNS (I myself was mostly interested in a server side implementation though).

The draft can be found at https://tools.ietf.org/html/draft-ietf-tls-esni and https://github.com/tlswg/draft-ietf-tls-esni.

ocheron commented 4 years ago

I put an (incomplete) implementation of draft-ietf-tls-esni-04 in branch ocheron:encrypted-sni. Unfortunately not many implementations exist with that version yet. The handshake logic with the retry scenario is a bit complex so better wait for the final draft (and more implementations) before resuming this.

ocheron commented 4 years ago

The RFC draft moved to a more complex design called ECHO. This encrypts the entire ClientHello message, to address more privacy issues.

The new design relies on HPKE encryption, a combination of ECIES and AEAD with HKDF capabilities. This allows cryptographic binding during HRR.

The encrypted ClientHello is wrapped as an extension in an outer ClientHello not having the true SNI, and the outer ClientHello is not used when ECHO negotiation is successful.

My branch now implements draft -06 but I've left the most difficult part out: trial record decryption based on 2 possible TLS transcripts (since we have now 2 possible ClientHellos). For now I signal the server status "ECHO accepted/rejected" in ServerHello extensions instead of EncryptedExtensions. The client is able to know which ClientHello the server uses before needing to deprotect TLS records.

kazu-yamamoto commented 4 years ago

@ocheron I don't know this is relating to your issue but I write it up for record.

TLS 1.3 draft 18 defines SH differently from that of version 1.2. This means that clients have to use two kinds of parsers for SH. This was tricky because the original parser is purely functional. I defined HelloSwitch and the original parser throws the SwitchTLS13 constructor so that the caller can call the parser for TLS 1.3 SH:

https://github.com/kazu-yamamoto/hs-tls/blob/tls13-old/core/Network/TLS/Handshake/Client.hs#L180

Just FYI.

ocheron commented 4 years ago

Yes here it's tricky too. Giving it more thought, I finally drafted a solution. It should be clean but a bit complex.

When deprotecting records, an IO Bool is available to decide if a new decryption attempt should be made. The handshake code configures it with the necessary actions to recompute and update the handshake traffic keys from an alternative transcript. Some code is also needed so the client can track the multiple transcripts that the server may select.

In case of HelloRetryRequest there are four possible combinations with inner/outer in the two ClientHello messages. Combinations (ClientHelloInner1, ClientHelloInner2) and (ClientHelloOuter1, ClientHelloOuter2) are more likely than the other two.

ocheron commented 4 years ago

Draft -07 renamed this to ECH (Encrypted Client Hello) and improved many details. I experimented with QUIC client/server having ECH too: https://github.com/ocheron/quic/tree/ech The weaker thread model made integration a bit more complex than I expected. Or maybe I overestimate the risks.

gufm23 commented 1 year ago

Any chances to implement the ECH extension?

kazu-yamamoto commented 1 year ago

It's in my todo list but it would take time.