TLS Encrypted Client Hello用のSSLKEYLOGFILE拡張の提案仕様

TLS Encrypted Client Hello用のSSLKEYLOGFILE拡張として『SSLKEYLOGFILE Extension for ECH』という提案仕様が提出されています。

背景

提案仕様の説明の前に、簡単にSSLKEYLOGFILEとECHについて補足します。

SSLKEYLOGFILEについて

TLS通信を復号するためには鍵の情報が必要です。トラブルシュートやデバッグのために、多くのTLS実装では"SSLKEYLOGFILE形式"でシークレットをログとして出力できます。例えば、OpenSSLやChromeブラウザなどがオプションを指定することでSSLKEYLOGFILEファイルを出力します。

具体的にはこのように各種シークレットが16進数で表記されます。

# SSL/TLS secrets log file, generated by OpenSSL
SERVER_HANDSHAKE_TRAFFIC_SECRET 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 b48d1fdc6b10b6f4765456e8407649b25971f3384e63461bdacab59c2488cacb8bb7dcde0aa1e2c6ede9390b568624f4
EXPORTER_SECRET 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 b56d696bd2fc3ef533dea35a6f907586cbbd7d049fd027d9964d3b924435ea157bfc955a55ef1d6ea7d5012ea906dee3
SERVER_TRAFFIC_SECRET_0 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 4676aa104c6ac82822f4450c5a8d3990f70b64005bed05e50a9586e4cd2a6c0187fec0220a83ed21e69eb61fd9e9cfaf
CLIENT_HANDSHAKE_TRAFFIC_SECRET 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 6ef4d40e4103a2aa00c985a5287314048fdaddd781f7ee90a2b98513efef6fde04a00950721660ba9e5afb184fbafc70
CLIENT_TRAFFIC_SECRET_0 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 8408e4b76dfcb3850eea590c8be1a0fb42a5c63f85246b1b6b16661241670f19c0a511b3d683d5bafc650e89efc04890

また、WireSharkにSSLKEYLOGFILEを食わせることで、キャプチャした該当通信を復号することもできます。

SSLKEYLOGFILEは、現在『The SSLKEYLOGFILE Format for TLS』として標準化が進められています。

Encrypted Client Hello

TLSハンドシェイク中にクライアントから送信されるClientHelloは、暗号化されません。特にSNI拡張は通信先のドメインが記載されるため、通信の観測者に情報を与えてしまいます。

そこで、ClientHelloの暗号化『TLS Encrypted Client Hello』という仕様が提案されています。詳しい仕組みについては詳しい解説が幾つか公開されておりますので、そちらに譲ります。

blog.cloudflare.com

SSLKEYLOGFILE Extension for Encrypted Client Hello

SSLKEYLOGFILE Extension for ECH』では、SSLKEYLOGFILEに以下の情報を記載可能に拡張する。

  • ECH_SECRET: ECHで使われる、HPKE キー スケジュールで生成されるシークレット
  • ECH_CONFIG: ECH拡張に使用されたECHConfigの値 (16進数表記)

これらの情報によりEncrypted Client Helloが復号できるようになる。

DNSでTLSハンドシェイクの鍵交換を改善する、TLS Key Share Predictionについて

IETFGoogleの方々から提案されている『TLS Key Share Prediction』という提案仕様が、WG Adoptionされています。

これは、DNS HTTPS レコードを用いることでTLSハンドシェイクを改善することを目的とした提案仕様です。

TLSハンドシェイクのKey Shareについて

まず、Key Shareについて簡単に補足する

TLSハンドシェイクのClientHelloでは、鍵交換でサポートするnamed groups(名前付きグループ)をSupported groups拡張で送信します。合わせて、鍵交換に必要なパラメータをKey share拡張で送信します。Key Share拡張にはnamed groups事に必要なパラメータを送信します(サポートする全てのnamed groups分送る事は必須ではない)。

Chromeの例:

Key Share拡張には下記のようなトレードオフがあります。

  • 複数のnamed groupsのKeyShareEntryを送ると、その分 データ量が増える
  • 送ったKeyShareEntryにサーバが対応してないかった場合、HelloRetryRequestによって1RTT余計に時間がかかる。

そこでこのトレードオフを改善するために『TLS Key Share Prediction』が役に立ちます。

TLS Key Share Prediction

TLS Key Share Prediction』では、DNS HTTPSレコードにサーバが対応しているSupported groupsをユーザに通知することによって、クライアントはClientHelloで送信する必要があるKey Shareを知ることができます。

これにより、Key Share拡張におけるトレードオフは緩和され、必要なKeyShareEntryのみを送信することが出来るようになります。

(もしなんらかの理由により、HTTPSレコードと齟齬があったとしてもHelloRetryRequestを挟みますが、通信自体は問題なく継続できます)

HTTPSレコードのtls-supported-groupsパラメータ

この仕様では、HTTPSレコードにtls-supported-groupsを新しく定義し、そこにSupported groupsの値を書けるようにします

Cookieの改訂版仕様 rfc6265bis の変更点

Cookieの改訂版仕様 rfc6265bis について、その変更点をざっと眺めていく

はじめに

Cookieの仕様は『RFC 6265: HTTP State Management Mechanism』として標準化されています。

そのCookieの仕様の改訂版が『rfc6265bis』と呼ばれているもので、現在標準化作業が進められいています。"SameSite属性"や”Cookieプレフィックス”などが仕組みとして追加されているほか、仕様として曖昧だった部分が明確化されています。

これらの機能はすでにブラウザに実装されているため、今回の改訂で大きくCookieの仕組みが変わるということはありません。

そんなrfc6265bisの仕様だが、標準化作業を進めているIETF HTTPWGにおいて"Working Group Last Call"が呼びかけられました。この段階までくれば、機能追加などの大きな変更は入らないと思われます。

SameSite属性

新しく定義されたCookieの属性であり、リクエストが同じSiteの時のみCookieが送信されるように制限できる。

属性値として次の値が指定できる

  • Strict: same-site のときのみCookieが送信される
  • Lax: same-siteもしくは、トップレベルナビゲーションじのときにCookieが送信される
  • None: same-site及びcross-site の両方でCookieが送信される

今まで、一度セットしたCookieの属性をサーバ側から確認する方法はありませんでした。サーバ側からすると送られてきたCookieについて、預かり知らぬところで属性が変更されている可能性もあるわけです。

Cookieプレフィックスを付与することで、属性を保証できるようにします。

__Secureプレフィックス

Cookie名を"__Secure"から始めることで、Secure属性がついていることを保証します。
ブラウザはSecure属性のついてないCookieを拒否します。
(サーバ側からするとこのプレフィックス付くCookieが送られてきたら、Secure属性がついてると確信できる。)

ブラウザはこのCookieは拒否します。

Set-Cookie: __Secure-SID=12345; Domain=site.example
__Hostプレフィックス

Cookie名を"__Host"から始めることで、『Secure属性・Path属性==/・Domain属性無し 』であることを保証します。
ブラウザはそうではないCookieを拒否します

ブラウザは以下のようなCookieを拒否します

Set-Cookie: __Host-SID=12345
Set-Cookie: __Host-SID=12345; Secure
Set-Cookie: __Host-SID=12345; Domain=site.example
Set-Cookie: __Host-SID=12345; Domain=site.example; Path=/
Set-Cookie: __Host-SID=12345; Secure; Domain=site.example; Path=/

非セキュアなオリジンからの Secure属性の上書きを禁止

非セキュアなオリジン(例: スキームがhttp)から、secure属性がついたCookieを上書きを禁止。

例えば、パブリックなWiFi利用時に中間者攻撃にてhttp://~なURLへ誘導され、secure属性を消すような攻撃を不可能にします。

nameless cookieの許容

名前の無いCookie(nameless Cookie)は、RFC6265時点で拒否するよう指定されていますが、実際に使用されているケースが有るため、受け入れるように変更されました(ただし非推奨)。

例えば次のようなset-cookieヘッダがnameless Cookieの例になります。

set-cookie: =hoge
set-cookie: hoge

上記のように設定されたCookieは、リクエスト時に次のように付加されます

cookie: hoge


ただし、以下のような名前も値も無いset-cookieは無視されます

set-cookie: =

Cookie名、Cookie値の上限長の指定

Cookie名とCookie値の合計が4096バイトより大きい場合、ブラウザは保存処理時にそのエントリを無視する。
(以前はShouldだったが保存アルゴリズムに組み込まれた)

Expires属性の年が2桁の場合の処理の指定

Expires属性は通常 4桁で年が表記されますが、2桁も許可されています

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT

2桁の場合は、以下のように解釈するよう明示されました

  • 70~99の場合は1900年代を示す
  • 0~69の場合は2000年代を示す

Max-Age/Expires の上限

Max-Age/Expiresの上限を400日とした。

その他

その他にも細かい修正が幾つかある、rfc6265からの差分については提案仕様を参照してください。

  • Cookie2, Set-Cookie2のIANA登録を削除
  • 制御文字やタブ文字の拒否
  • ”Secureコネクション”かどうかはユーザエージェントによって判断され、localhostも含まれうる
  • Service Workerでの取り扱いの追加
今回入らなかった機能

Cookieに対する取り組みは幾つかありますが、今回の改訂には含まれていないものもあります。
幾つか紹介します

privacy.txt の提案仕様について

Webサイト利用者に関するプライバシーが重要視されるなか、プライバシーポリシーURLや各種オプトアウト用URLを提示できる『privacy.txt』の仕様がIETFに提出されている。

このprivacy.txtは、『robots.txt』『security.txt』『ads.txt』と同様に、ドメイン直下のPATH、もしくは/.well-knownのパスに配置される。

privacy.txtの中身

何が記述できるかについては『A File Format to Aid in Consumer Privacy Enforcement, Research, and Tools』仕様に書かれている

プライバシーポリシー情報

プライバシーポリシーに関するURLを提示できる

  • Privacy-policy: URL
    • プライバシーポリシーのURLを提示
  • Privacy-policy-text: URL
    • プライバシーポリシーのテキスト形式のURLを提示
各種アクション用URL情報

データ削除やオプトアウト用のURLを提示できる

  • Action-delete-account-and-data: mailto:EMAIL|URL
    • アカウントおよびデータを消すためのメール宛先・URL
  • Action-delete-personal-data: mailto:EMAIL|URL
    • 個人の情報を消すためのメール宛先・URL
  • Action-opt-out-sharing:mailto: EMAIL|URL
    • 三者との情報共有をオプトアウトするためのメール宛先・URL
  • Action-shared-list:mailto: EMAIL|URL
    • データが共有される第三者のリストを取得するメール宛先・URL
  • Action-opt-out-marketing: mailto:EMAIL|URL
Cookieに関する情報

プライバシー法で求められる、Cookieの情報を記述できるようにすることを目的とする

Cookie: FIELD#1,FIELD#2,...FIELD#7』という形式であり、各FIELD#1~7には次の情報が入る

( 必須Cookieかどうか取れるので、ポリシー見てブラウザがいい感じにやってくれたりするのだろうか... )

さいごに

今のところIETFで活発に議論されている様子はみられない、次のIETFミーティングでdispatchされるかもしれない

QUICにおける、明示的な輻輳シグナルを受け取る ECN対応

RFC 9000 QUICには、経路上のスイッチから明示的な輻輳シグナルを受け取る ECN (Explicit Congestion Notification) という機能に対応しています。

Googleではサーバ側はQUIC ECN対応がデプロイされており、Chromeでの実装も進められている事が報告されています。
mailarchive.ietf.org

概要

  • ECNに対応したネットワーク機器は、輻輳が起こると該当のパケットにおいて、IPヘッダのTOS fieldのCE(Congestion Experience)ビットをセットする
  • 受信したIPヘッダのCE(Congestion Experience)ビットがセットされている場合、パケットの送信者にフィードバックするため、QUICのACK-ECNでそれを通知する
  • ACK-ECNを受け取ったエンドポイントは輻輳が起こっている事を把握し、送信量を下げる
IPヘッダの CT, CE ビット

RFC2481において、IPヘッダのTOSフィールドをECN用に 2ビット使用します

  • 00: ECN非対応
  • 01, 10 : ECNに対応している事を示すのに使用します(それぞれECT1, ECT0と呼ばれる)
  • 11: CEと呼ばれ、 輻輳が起こっている事を示すのに使用します


QUICのACK ECN

QUICではACKフレームにECN Countsの情報を格納します。ECN情報を持つACKは、フレームタイプとして0x03を使用します。

ECN CountsとしてECT, CEの受信数をピアに通知します

Example

最初に述べた通り、Google, YoutubeではすでにECNに対応しているため、ACK ECNを送ってきます。WiresharkでQUICを復号すると次のようにみることが出来ます。

HTTP/3コネクション上でSSHを実行するSSH3プロトコル

IETFに『Secure shell over HTTP/3 connections』という提案仕様が提出されています。

これは、HTTP/3コネクション上でSSHを実行するプロトコルを定義しています。なお、"SSH3"という名称を仕様中で使用していますが、あくまで提案段階ですので今後変わる可能性もあります。

SSH3ではHTTP/3を使うことにより以下の特徴を持ちます

  • QUICのメリットが享受できる(例えばIPアドレスが変わってもコネクションを維持できる)
  • HTTPの認証方式をサポートする(Basic認証、OAuth 2.0、Signature HTTP Authentication Scheme
  • SSH通信の秘匿 (第三者からするとただのHTTP通信にみえる)
  • エンドポイントの秘匿 (Signature HTTP Authentication Schemeを使うことで、そこでサービスが動いてることを隠せる)
  • HTTPを使うことでロードバランサ(ホスト名やパスによるルーティング)が利用できる。
  • ポートフォワーディング時に、パケットのreordaringが不要なQUIC DATAGRAM(RFC9221)が利用できる

HTTP/3のリクエスト・レスポンスにSSHのメッセージを乗っけるわけのではなく拡張CONNECTメソッド(RFC8441)をつかって、HTTP/3のコネクションをSSH3用に利用する形になります。なお、WebTransportの利用も検討されていますが、現状はHTTP/3を利用する仕様になっています(フォールバック先としてHTTP/2を利用)。

アーキテクチャ

SSHv2は下記のとおりです


SSH3では次のとおりになります

  • 認証や、URL関連はHTTP/3レイヤで処理する
  • トランスポートはQUICが担い、チャネルの機能はQUICレイヤにマッピングされる


プロトコル

通信の開始

エンドポイントに対してQUICコネクションを確立し、HTTP/3通信を開始します。その際に、QUIC DATAGRAMおよび、HTTP/3 拡張CONNECTメソッドをSETTINGSで有効にします。

拡張CONNECTメソッドを使ってSSH3通信を開始します。この時、:protocol疑似ヘッダには"ssh3"が指定されます。パスにはURIテンプレートでユーザ名を指定できるようになっています。

https://example.org:4443/ssh3?user={username}
https://proxy.example.org:4443/ssh3{?username}

また、拡張CONNECTメソッドを送信する際にHTTPレイヤでの認証を実行します。先述の通り、認証方式としてBasic認証、OAuth 2.0、Signature HTTP Authentication Schemeなどが利用できます。

HTTP Basic認証では以下のような通信になります。

チャネル (ストリームの利用)

クライアント開始の双方向ストリームをチャネルと利用します。WebTransportと同様に、リクエストストリームとは別で新しく開始します。

双方向ストリームには最初に次のとおりに書き込まれます。

Channel {
    Signal Value (i) = 0xaf3627e6,
    Conversation ID (i),
    Channel Type Length (i)
    Channel Type (..)
    Maximum Message Size (i)
    SSH messages (..)
}

Conversation IDとして、リクエストストリームとの紐づけを行う事ができます。それ以外はSSHで必要な値ですね。
チャネルが開設したあとはSSHv2同様のメッセージを投げることが出来ます。

実装

実装も公開されている
github.com

DNSプロトコルの拡張性を担保するGreasingの提案

DNSプロトコルの拡張性を担保するために、『Greasing Protocol Extension Points in the DNS』という提案がIETFに提出されている。

これにより、オペコードやリソースレコードタイプなどにランダムな値が設定される可能性がある。

背景、Greasingについて

プロトコルの将来の拡張性を担保するために、Greasingという仕組みが導入される事があります。

実インターネットでは様々なミドルウェア実装や中継機器などが存在します。プロトコルを拡張した際、既存実装にそれらの拡張が無視される事が期待されます。ただし、実装や中継機器の予期せぬ動作を引き起こし、結果として新しいプロトコルの利用が阻害される事が知られています(ossification問題と呼ばれる)。

これは、TLS1.3策定時に、実際にインターネットでの疎通問題として注目されました。そこで、プロトコルの未知の拡張を無視するという挙動を実装に意識させるために、無視するための拡張を定義して送信するのがGreasingです。

例えば、TLSではRFC 8701でGreasing用の値が定義されており、例えばcipher suitesおよびALPN識別子に次の値を付与して良いことになっています。

  • {0x0A,0x0A}
  • {0x1A,0x1A}
  • {0x2A,0x2A}
  • {0x3A,0x3A}
  • ...

これにより、サポートしてない拡張値を無視する要件が守られていることを保つようにしています。

Greasing Protocol Extension Points in the DNS

Greasing Protocol Extension Points in the DNS』では、次の値をGreasing対象として検討している。

Greasingにランダムな値を使うか、Greasingようの値を予約するかは現在検討中になっているようです。ランダムな値を使ってしまうと、将来利用される番号と衝突してしまう場合の影響が未知数となってしまいます。一方で予約値を使うと、実装がそれを特別扱いできてしまいます。

(個人的には、TLSと同様予約値を与えるので十分なんじゃないかなとは思います)