TLS Encrypted ClientHello(ECH) を BoringSSLで試してみます。
なお、現時点ではBoringSSLはdraft 10版の ECH 対応です。
TLS Encrypted ClientHello(ECH) について
TLSの通信のうち、クライアントからサーバに送信されるSNI(Server Name Indication)は、通信先のホスト名が記載されます。
これは平文で送信されるため、通信の観測者はどのドメインと通信しているか分かります。これを秘匿するために Encrypted SNI (ESNI)という仕様が議論されています。
今は、TLS Encrypted ClientHello(ECH)という形で標準化が進められており、Firefoxなどが既に対応しています。
例えばこのECHを使うと、クライアントは「public.example.com」と「private.example.org」をサーバに送りますが、private.example.orgの情報は暗号化されて送れます。CDNやマネージドロードバランサが対応し、外に見えるSNIはCloudflareやクラウドベンダーのドメインとなれば、見えるSNIから暗号化されたSNIを観測者が推測するのも難しくなるでしょう。

古いですがもう少し詳しくは昔書いた通り。
asnokaze.hatenablog.com
実装を触ってみる
すでに幾つかの実装があり、相互接続性のテストを行っております。
https://github.com/tlswg/draft-ietf-tls-esni/wiki/Implementations
今回はBoringSSLで通信の様子を見ていきます。
ビルドする
説明に基づいてビルドします
https://boringssl.googlesource.com/boringssl/+/HEAD/BUILDING.md
ECH設定の生成
generate-ech で ech_config_listを生成します。今回は public-nameとしてpublic.example.comを指定します。
$ ./build/tool/bssl generate-ech -out-ech-config-list ech_config_list.data \ -out-ech-config ech_config.data \ -out-private-key ech.key \ -public-name public.example.com \ -config-id 0
この ech_configにはHpkePublicKeyやpublic_nameが格納されます。
一般的に、クライアントはこのech_configはDNS HTTPS レコードを介して取得します。(DNSの通信はDoHなどで暗号化しておけば、通信の観測者はどのドメインのHTTPSレコードを取得している事もわかりません)
通信してみる
サーバを起動しておく
$ ./build/tool/bssl server -accept 4430 \
-ech-key ech.key \
-ech-config ech_config.data クライアント側でつなぐ
$ ./build/tool/bssl client -connect localhost:4430 \
-ech-config-list ech_config_list.data \
-server-name private.example.org
Connecting to 127.0.0.1:4430
Connected.
Version: TLSv1.3
Resumed session: no
Cipher: TLS_AES_128_GCM_SHA256
ECDHE curve: X25519
Signature algorithm: ecdsa_secp256r1_sha256
Secure renegotiation: yes
Extended master secret: yes
Next protocol negotiated:
ALPN protocol:
OCSP staple: no
SCT list: no
Early data: no
Encrypted ClientHello: yes
Cert subject: C = US, O = BoringSSL
Cert issuer: C = US, O = BoringSSLサーバ側の出力
$ ./build/tool/bssl server -accept 4430 \
-ech-key ech.key \
-ech-config ech_config.data
Connected.
Version: TLSv1.3
Resumed session: no
Cipher: TLS_AES_128_GCM_SHA256
ECDHE curve: X25519
Secure renegotiation: yes
Extended master secret: yes
Next protocol negotiated:
ALPN protocol:
Client sent SNI: private.example.org
Early data: no
Encrypted ClientHello: yesサーバ側からするとEncrypted ClientHelloがyesになっている。また、クライアントが送った本来のSNI private.example.org が認識できています。
また、crypto.cloudflare.com がECHに対応していますが、HTTPS DNSレコードからECH Config listを取得すれば、同様にEncrypted ClientHelloが通信できました。
パケットキャプチャしてみる
上記で行った通信をパケットキャプチャしてみます。
経路上の観測者としては、ESNIは「public.example.com」しかみえません。但し、暗号化されている Enclipted Clienthelloが格納されている encrypted_client_hello 拡張 (65034 == 0xFE0A (ECH Draft-10)) がついている事が分かります。
