Encrypted client hello doesn't help with privacy

ArcHound1 pts0 comments

Encrypted Client Hello: A Big Tech Privacy Fix

- Miloslav Homer

Miloslav Homer

About

Archive

Encrypted Client Hello: A Big Tech Privacy Fix

• Where Are The Keys? See RFC9848

• SVCB DNS Records

• HTTPS DNS Records

• Encrypted Client Hello - RFC9849

• Client Hello in TLS Handshake

• Inner/Outer Client Hello Extension

• Using ECH In Practice

• What About The Small Webs?

• The Corporate Internet

• Privacy Is Hard

• Did ECH Achieve The Stated Goals? Yes, but

Encrypted Client Hello: A Big Tech Privacy Fix

It does sound like a contradiction, doesn't it?

Miloslav Homer

#ECH

#IETF

#Privacy

#RFC

#TLS

2026-04-08

Much of the traffic on the web is now encrypted thanks to SSL/TLS (https). This prevents attackers from seeing the contents of your traffic. But they can still see which domains you are connecting to, and that might be a problem still.<br>DNS-over-TLS (RFC7858) aimed to solve this, encrypting the domain names you’re requesting. Sadly, the SNI extension of client hello still leaks the domain name 1.<br>Obviously, we have to encrypt the client hello. And finally, since March 3rd 2026, we have a newly-released standard to achieve this - RFC9849 named TLS Encrypted Client Hello (ECH for short). Here's a summary flow:

A diagram of the full flow for ECH. We'll go over each part in due time.

While ECH definitely achieves the stated goals, I think these goals are not universal and should be re-examined. Specifically, you MUST (see RFC2119) use and trust a proxy provider (think Cloudflare) for ECH to be effective. Moreover, there are known cases when governments blocked ECH completely. I'd like to see a solution that works in more general cases. I know it's hard.<br>Dependency on a 3rd party for internet standards is a new one. That's not the internet I know and love. While Encrypted Client Hello brings improvements to a very hard problem, we should strive for standards that everyone can benefit from.

Here comes the nerdy part, where we dig deep and pick apart the encrypted client hello mechanisms to see how exactly this works.<br>Please do not attempt to play a drinking game when you take a shot each time you see a RFC document reference. Especially beware of footnotes and external links.

Where Are The Keys? See RFC9848

The original ECH RFC9849 doesn’t specify how the client gets the key to actually encrypt the client hello. As an example, it points to RFC9848 with the support of Service binding over DNS RFC9460. Note that this is only a recommendation - clients can have ECH configs pre-configured or they might use a different mechanism.

SVCB DNS Records

DNS-over-TLS was here first (RFC7858), using the SVCB records. Generally speaking, they point subdomains to subdomains and give additional parameters in the meantime. They are not easy to come by, here’s one I found from google:

$ dig _dns.dns.google SVCB @8.8.8.8 +short<br>2 dns.google. alpn="h2,h3" key7="/dns-query{?dns}"<br>1 dns.google. alpn="dot"

ALPN or Application Layer Protocol Negotiation (see RFC7301) is basically a hint on the DNS level on what protocol the client is using. See a list of known ALPNs, managed by IANA. Here, h2 is HTTP/2 (RFC9113), h3 is HTTP/3 (RFC9114) and dot is DNS-over-TLS (RFC7858).<br>So this basically says, if you’d like to use http to get DNS data, use this endpoint like so. Of course, you have to 2 use the DNS binary format as specified in RFC1035. Here’s a PoC in action:

$ curl 'https://8.8.8.8/dns-query?dns=nbcBIAABAAAAAAABBGJsb2cNbWlsb3NsYXZob21lcgJjegAAAQABAAApBNAAAAAAAAwACgAIlq49rJd1ruo' --output - 2>/dev/null | xxd

00000000: 9db7 81a0 0001 0001 0000 0001 0462 6c6f .............blo<br>00000010: 670d 6d69 6c6f 736c 6176 686f 6d65 7202 g.miloslavhomer.<br>00000020: 637a 0000 0100 01c0 0c00 0100 0100 0002 cz..............<br>00000030: 5800 04a4 446b 1b00 0029 0200 0000 0000 X...Dk...)......<br>00000040: 0000

$ dig blog.miloslavhomer.cz A +short

164.68.107.27

$ dig blog.miloslavhomer.cz A +short | tr '.' ' ' | xargs printf '%02X'

A4446B1B

The IP starts at offset 0x33 or 51.<br>I’m slightly sad that they didn’t mention the much more natural JSON endpoint, but I guess the format doesn’t allow for sufficient API description. Here’s an example:

$ curl 'https://8.8.8.8/resolve?name=blog.miloslavhomer.cz&type=A' | jq

"Status": 0,<br>"TC": false,<br>"RD": true,<br>"RA": true,<br>"AD": true,<br>"CD": false,<br>"Question": [<br>"name": "blog.miloslavhomer.cz.",<br>"type": 1<br>],<br>"Answer": [<br>"name": "blog.miloslavhomer.cz.",<br>"type": 1,<br>"TTL": 600,<br>"data": "164.68.107.27"<br>],<br>"Comment": "Response from 185.71.159.12."

HTTPS DNS Records

Similar in intent, different in target we have the HTTPS record. It’s not exactly easy to find sites that have this enabled properly. After a lot of digging (ba-dum-ts), I’ve found this random Firefox bug that showcases the setup for static.certitudes.org:

$ dig static.certitudes.org HTTPS +short

1...

client hello bull encrypted https privacy

Related Articles