TLS Encrypted Client Hello の暗号化(ECH)に関するメモ

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が送られる。そんなイメージである。

f:id:ASnoKaze:20200409024404p:plain

それぞれが同居しているShared Modeと、分離しているSplit Modeの2つの構成です。

public.example.comの部分が、大手検索会社や大手CDN会社のドメイン名になり、多くのサイトの前段となれば、パプリックなドメインとプライベートなドメインを紐付けることは困難となる。

ECHO

Draft 6から、ECHOという仕組みになりました。これは、ClientHelloをまるごと暗号化する仕組みです。これによってALPNなどの領域も暗号化されるようになります。このClientHelloの暗号化は、暗号化したClientHello(ClientHelloInner)を含むClientHello(ClientHelloOuter)で送る形で転送されます。

f:id:ASnoKaze:20200409020447p:plain

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