2020/07/19 追記
最新版では仕様名が encrypting the entire ClientHello (ECHO)から、TLS Encrypted Client Hello(ECH) に変更されました
広域盗聴行為(RFC7258)への対策として、通信の暗号化が行われています。
TLS1.3からは、サーバ側証明書は暗号化されるようになり、観測者が得られる情報はIPアドレスやSNIから得られるホスト名などになりました。
このSNIの情報も暗号化するために、さまざな議論が行われました。その中で出てきた提案として「Encrypted Server Name Indication for TLS 1.3」という提案仕様があります。
この仕様はすでに、TLS WGでWG Draftとなっており第6版まで出てます。版が進む中で幾つかの変更があり、HTTPSSVCレコードの利用や、encrypting the entire ClientHello (ECHO)といった仕組みなどが入っています。
簡単に現在のDraftをつまみ食いする。
なお、HTTPSSVCについては以前書いたとおり。こちらは、Chromeなどで対応が進んでいる。
HTTPSで接続するための追加情報を格納するHTTPSSVCレコード - ASnoKaze blog
構成
本仕様では、以下の2種類の構成が考えられている。
それぞれドメイン名として、経路上からはSNIとしてpublic.example.comが設定されているように見える。 暗号化されたSNIとしてprivate.example.orgが送られる。そんなイメージである。
それぞれが同居しているShared Modeと、分離しているSplit Modeの2つの構成です。
public.example.comの部分が、大手検索会社や大手CDN会社のドメイン名になり、多くのサイトの前段となれば、パプリックなドメインとプライベートなドメインを紐付けることは困難となる。
ECHO
Draft 6から、ECHOという仕組みになりました。これは、ClientHelloをまるごと暗号化する仕組みです。これによってALPNなどの領域も暗号化されるようになります。このClientHelloの暗号化は、暗号化したClientHello(ClientHelloInner)を含むClientHello(ClientHelloOuter)で送る形で転送されます。
ClientHelloOuterはちゃんとしたClientHelloですが、TLS拡張としてencrypted_client_hello拡張を持ちます。
encrypted_client_hello拡張には、暗号化されたClientHello及びそれを復号するの必要な情報が格納されています。
サーバは、ClientHelloInnerを復号し受理するか、もしくはClientHelloOuterを使用できます。サーバによってClientHelloOuterが選択され処理された場合、ClientHelloOuterに対するサーバ証明書がクライアントに送信されます、後述のpublic_nameとしてvalidな証明書か検証する必要があります。
暗号化
ClientHelloの暗号化方法についても簡単に触れます。
クライアントがClientHelloを暗号化するために、ECHOConfigというメタ情報を使用します。このECHOConfigは任意の方法でクライアントに伝えられますが、例えばDNSのHTTPSSVCレコードを用いる事が言及されています。複数のECHOConfigをクライアントに渡し、使用できる設定が使用されます。
struct { opaque public_name<1..2^16-1>; HpkePublicKey public_key; HkpeKemId kem_id; CipherSuite cipher_suites<2..2^16-2>; uint16 maximum_name_length; Extension extensions<0..2^16-1>; } ECHOConfigContents; struct { uint16 version; uint16 length; select (ECHOConfig.version) { case 0xff03: ECHOConfigContents; } } ECHOConfig;
ECHOConfigは、version, length, およびECHOConfigContentsからなります。versionは0xff03が使用されます。ECHOConfigContentsに実際に暗号化するための鍵とサイファースイートなどが入っています。
暗号化に関しては、HPKEとあるようにIETFのCFRGで議論されている「Hybrid Public Key Encryption」という仕組みが用いられている。
ということで、ECHOConfigからゴニョゴニョされて暗号化されたClientHelloが導出される。。。
pkR = HPKE.KEM.Unmarshal(ECHOConfig.public_key) enc, context = SetupBaseS(pkR, "tls13-echo") echo_nonce = context.Export("tls13-echo-nonce", 16) echo_hrr_key = context.Export("tls13-echo-hrr-key", 16)
encrypted_ch = context.Seal("", ClientHelloInner)
その他
ちょっと調べきれてないトピックとして、以下がある。引き続きお勉強します
- ClientHelloInnerが持つecho_nonce拡張
- HelloRetryRequest
- HPKE