Cloudflare has been working on a standard to encrypt the TLS connection at all levels. We will dig as to what stuff is still unencrypted, how this poses the threat and the solution ClientHello
Pre-requisites
Before diving into the protocol, it is imperative to understand the historical context of this protocol
Existing TLS implementations contain a couple of parameters/extensions that are sent unencrypted and are used before the handshaking process. These are Server Name Identification(SNI) and Application-Layer Protocol Negotiation (ALPN)
While establishing a TLS connection between client and server, these parameters (SNI and ALPN) are not encrypted. It is after these 2 params are exchanged, that the client and server have enough security information (certificates, cryptographic keys .etc.) to initiate a Secure Connection
SNI
So what is SNI?
It is sent by the client indicating which hostname it wants to connect to before starting the TCP handshaking process
Since the ISPs can see which hostname the client wants to connect,it allows them to block websites easily.
ALPN
This provides information on what application-level protocol (HTTP version) should be used once the TLS connection has been established.
Having unencrypted ALPN is an attack vector that can be used to downgrade HTTP version and thus negate all security improvements for every HTTP version upgrade.
Since SNI and ALPN are considered metadata and can contain some sensitive information that is unencrypted, there has been a push to make this also encrypted. But this poses a chicken and egg problem, which is how can the client and server exchange encryption key before the handshaking process when the handshaking process itself is used for the same purpose?
This concept of encrypting before handshake was not considered in earlier TLS versions. But after the Snowden leak and the uproar on global surveillance with only using metadata information, IETF started considering ways to encrypt this information as well.
TLS Prerequisite
A prerequisite for any TLS connection is the TCP handshake. As it is a topic in itself, you can view it here. In simple terms, it does these things
Acknowledge both parties participating in TLS
Very each other
Establish cryptographic algorithms they will use to securely connect and exchange information with each other.
Specify which TLS version to use (depending on what is supported by each party)
Authenticate server via Server’s public key and CA’s signature
Basic TLS
The above is the initial SYN/ACK between client and server
After that, there is a ClientHello and ServerHello (refer to the below diagram)
ClientHello: Cipher Suite, TLS version client supports, client random, SNI and ALN info
ServerHello: Server’s Sl certificate (with CA who issued it), server’s cipher suite, server random
The rest of the steps can be viewed in the Cloudflare blog.
Existing TLS implementations contain a couple of parameters/extensions that are sent unencrypted and are used before the handshaking process. These are Server Name Identification(SNI) and Application-Layer Protocol Negotiation (ALPN)
It is after these 2 params are exchanged, that the client and server have enough security information (certificates, cryptographic keys etc.) to initiate a Secure Connection
SNI
So what is SNI?
It is sent by the client indicating which hostname it wants to connect to before starting the TCP handshaking process
Since the ISPs can see which hostname the server wants to connect, it allows them to block websites easily.
ALPN
This provides information on what application-level protocol (HTTP version) should be used once the TLS connection has been established.
Having unencrypted ALPN is an attack vector that can be used to downgrade HTTP version and thus negate all security improvements for every HTTP version upgrade.
Since SNI and ALPN are considered metadata and can contain some sensitive information that is unencrypted, there has been a push to make this also encrypted. But this poses a chicken and egg problem, how can the client and server exchange the encryption key before the handshaking process when the handshaking process itself is used for the same purpose?
This concept of encrypting before handshake was not considered in earlier TLS versions. But after the Snowden leak and the uproar on global surveillance with only using metadata information, IETF started considering ways to encrypt this information as well.
ESNI
ESNI was the first version of encrypting SNI. It evolved to what we have today which is ClientHello
ESNI issues
For key distribution, ESNI used DNS. And this keyboard distribution plain-text base-64 encoded for the ESNI Public key which would raise serious flags.
$ dig _esni.crypto.dance TXT +short
"/wGuNThxACQAHQAgXzyda0XSJRQWzDG7lk/r01r1ZQy+MdNxKg/mAqSnt0EAAhMBAQQAAAAAX67XsAAAAABftsCwAAA="
This negates the whole security aspect of SNT as plain-text DNS is easily traceable by ISP. One innovation that helped mitigate this was DNS-over-HTTPS (DoH).
Final puzzle Piece: ECH
What ECH as the final draft proposes is to divide ClientHello, into 2 parts:
- ClientHelloOuter: This contains information that is not sensitive such as what cipher suite is used, TLS version and outer SNI. This outer-SNI can show CDN-type hostnames which would be common for most sites using CDN for improving edge performance.
- ClientHelloInner: This would include inner-SNI which would have an actual server name. This would be encrypted by a public key provided by Cloudflare. This could mean Cloudflare to be a point of vulnerability as they can decrypt by the private key that they possess.
ECH uses Hybrid Public Key Encryption (HPKE) for exchanging keys.
Reference: C Structs used in ECH
opaque HpkePublicKey;
uint16 HpkeKemId; // Defined in <https://www.ietf.org/archive/id/draft-irtf-cfrg-hpke-05.txt>
uint16 HpkeKdfId; // Defined in <https://www.ietf.org/archive/id/draft-irtf-cfrg-hpke-05.txt>
uint16 HpkeAeadId; // Defined in <https://www.ietf.org/archive/id/draft-irtf-cfrg-hpke-05.txt>
struct {
HpkeKdfId kdf_id;
HpkeAeadId aead_id;
} ECHCipherSuite;
struct {
opaque public_name; // Entity trusted to update encryption keys
HpkePublicKey public_key; // Public key to encrypt `ClientHelloInner`
HpkeKemId kem_id; // Identifying public key
ECHCipherSuite cipher_suites; // Cipher suite for encrypting `ClientHelloInner`
uint16 maximum_name_length;
Extension extensions; //
} ECHConfigContents;
struct {
uint16 version; // Version of ECH for which this config is used
uint16 length; // Length of next field (in bytes)
select (ECHConfig.version) {
// ECHConfigContents string
case 0xfe08: ECHConfigContents contents;
}
} ECHConfig;
ECHConfig ECHConfigs;
ECH in the real world
Setting up a flag in your browser
Check if your browser has ECH enabled using this link
(Chrome, can be achieved by enabling chrome://flags
under encrypted-client-hello
)
- Before enabling ECH
- After enabling ECH
No free lunch
Well this helps with securing exchanging metadata before TLS handshake, there are still some concerns/flaws:
Issues for corporate networks to implement firewall rules
OpenSSL open issue for 5 years Github Link
There is still not an official RFC number attached (despite Google bringing this to the browser and Cloudflare releasing their last puzzle piece to the privacy link.)
References
RFCs
Encrypted Client Hello / ESNI Draft: https://datatracker.ietf.org/doc/draft-ietf-tls-esni/
DNS over HTTPS: https://datatracker.ietf.org/doc/html/rfc8484
Cloudflare blogs
YouTube talks