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)) がついている事が分かります。