QUICの現状確認をしたい 2018/2 (MTU, Migration, Packet Number Encryptionなど)

3月分も書きました
asnokaze.hatenablog.com


QUICの標準化状況に関して、幾つかトピックを取り上げる

シリーズ化するつもりは無いが、1月に書いたので、今回は2月初旬版
qiita.com

拾いきれてないトピック沢山有るので、皆さんも是非補足して頂ければ

目次

Call for Adoption

1月に行われたQUIC Interimの議論を経て、2つのドキュメントがCall for Adoptionとなっている

QUICのHTTPヘッダ圧縮については幾つか提案があり、ながく議論されていたがその一つがAdoptionされることは追う側としては喜ばしい。WG Draftが出たら読み直そうと思う

詳しくは以前書いた記事を参考に

接続性テスト(Interoperativity)

QUICにおいても、標準化段階から実装を持ち寄って接続性テストを行うことで仕様の確度を高めている。

1月に行った3rd Implementation Draftinterop結果は以下の通り表にまとめられている。
docs.google.com


今後は4th Implementation Draftinteropが実施される

Interim Meeting

オフラインの中間ミーティングが、1月メルボルンで実施された。


アジェンダは下記の通り

  • Summary of interop meeting (EKR)
  • Status update from editors (Martin)
  • QUIC Invariants (Martin)
  • HTTP compression (Mike)
  • Multiplexing with other UDP protocols (Jana)
  • Greasing (Martin)
  • Connection ID and Handshake review (Ian)
  • Connection migration (Jana)
  • Loss recovery (Ian)
  • QUIC Application Abstractions (Jeff / Roberto)
  • ECN in QUIC (Ingemar, morning time MEL preferred)
  • 3rd implementation draft
  • Next Steps (Mark / Lars)

資料と議事録はGithubリポジトリより確認できる。
github.com

QUIC MTU

QUICのトランスポート draft-09にて、Path Maximum Transmission Unit (PMTU)の記述が増えた。

まず、最初のパケットは1200 octet以上になるように決められた。これは、反射型DDoS攻撃を緩和するためである。UDPだと送信元IPを攻撃対象のものに偽装することで、最初のパケットへの応答を攻撃対象に送信させることが出来る。QUICでは最初のパケットを大きくすることでデータ量を増幅できないようになっている。

クライアントがもし経路がそれ以上でも疎通できることを知っていれば、それ以上のサイズの初期パケットを送信しても良い。

PMTUは、経路上で疎通可能なIPヘッダ + UDPヘッダ + UDPペイロードの最大サイズです。QUICパケットはこのPMTUに収まるように送信すべきです。そのため、Path MTU Discoveryを使うべきです。

これらの仕組みを使用せず、1280 octetより大きいパケットを送信すべきではありません(IPv6で保証される、最小PMTU)。

また、IPv4のPath MTU Discoveryには脆弱性が知られているため、そのための緩和策を取るよう書かれています。

Migration

QUICでは、QUICのレイヤでコネクションを管理しているため、IPやポートが変わっても切断されません。NAT rebindingによってIPが変わっても大丈夫ですし、明示的に4G回線からWi-FI回線に切り替える事もできます。このコネクションのマイグレーションに関して、専用のフレームが用意された。

その変更が先日マージされた。
github.com


PATH_CHALLENGE, PATH_RESPONSEというフレームタイプである。
f:id:ASnoKaze:20180206001133p:plain


両方共、Data領域のみを持ちます。新しい経路に切り替える際、推測されにくい値を格納したPATH_CHALLENGEを新しい経路で送信します、それを受け取ったピアは任意の経路で同じ値を持つPATH_RESPONSEを送り返します。このときアドレストークンの検証もちゃんと行います。

こうして経路の確認が取れた後にコネクションをマイグレーションすることが出来ます。

17 octet connection ID

QUICのコネクションIDはサーバから払い出すことが出来ます。この時、そのコネクションに関する情報、例えばそれを払い出したサーバの識別情報を暗号化してコネクションIDに含める事ができます。そうすることで、そのコネクションIDをもつクライアントはそのサーバで処理するといった事ができます。

この使い方は「Manageability of the QUIC Transport Protocol」の4.3でも触れられています。


さて、コネクションIDはもちろんクライアント側から任意の値を使用しようとできるので、サーバ側から発行するコネクションIDに何かしらの情報を埋め込む際は暗号化する必要があります。その時に問題になるのがコネクションIDの長さです。

認証付き暗号を使用のに、128bit長にすることが提案されています。また、使っている鍵の識別子も付け加えて、系17octetになります。
github.com


だたし、可変長コネクションIDという意見も出ており、今後も議論が続くかと思います。

Packet Number Protection

下記記事でも触れているとおり、ファイアウォールなどの中間装置がパケットを読み正しくない挙動を起こす問題が知られています。そのため、そもそもそれらのパラメータを見えないようにするという議論が進んでいます。
asnokaze.hatenablog.com

さらに暗号化を進め、パケット番号も暗号化しようという議論が出ています。

秘密値から導出されるpn_keyと、パケットのデータ領域を暗号化した後に、暗号化領域からサンプリングしてきた値を暗号へのインプットとしてパケット番号を暗号化します。


AES-BasedとChaCha20-Basedがありますが、AES-Basedでは下記のとおりです。

encrypted_pn = AES-CTR(pn_key, sample, packet_number)

EXTENSION Frames

QUICでも拡張フレームを定義する議論が出ています。
github.com

フレームタイプ0x0fで、さらにExtension Typeを持ちます。未知の拡張タイプは無視されます
f:id:ASnoKaze:20180206155611p:plain

QUIC IN ECN

QUICにおけるECNは「ECN support in QUIC」としてInternet-Draftが出ていますが、WikiECN in QUICで編集が進められています。


ECNは詳しくないので、正直良くわからないのですが、「Suggested additions to 'to become' RFCs」と書かれている通り、トランスポート及びロスリカバリのドキュメントに追記されECNサポートへ向かうようだ。

Unbound Server Push (USP) for HTTP/QUIC

メーリングリストで話題になっていないのと、V1のスコープ外なのでどうなるかわからないが、「Unbound Server Push (USP) for HTTP/QUIC」という提案が出ていた。


HTTP/2サーバプッシュは、HEADERSフレームを受けてそれと関連するレスポンスをプッシュすることが出来る。つまり、まずHEADERSフレームを受け取る必要があるが、上記の提案ではそれがなくてもプッシュできるUnbound Server Pushを提案しているようだ。

Application-Layer TLS の標準化動向

IETFでApplication-Layer TLSの議論が行われ始めているので、雑に書き留めておく

Application Transport LAyer Security (Atlas)

前回、アプリケーションレイヤでTLSを喋る「HTTP over TLS」について、記事を書いた。
asnokaze.hatenablog.com


その後、IETFでは、Application Transport LAyer Security (Atlas) というメーリングリストが開設され、WG化のためのチャータの議論が行われています。


以前取り上げたHTTP over TLSユースケースの他にも

f:id:ASnoKaze:20180201082004p:plain
f:id:ASnoKaze:20180201084938p:plain

例えばIoT機器などのデバイスが、Zigbeeであったり、CoAP/DTLS などでゲートウェイと通信し、ゲートウェイからプロトコルを変えインターネットに出ていくようなケースにおいても、エンドツーエンドで暗号通信したい場合があります。その際にエンドツーエンドでの鍵交換の仕組みを新しく作るのではなく、アプリケーションレイヤでTLSのやり取りを行い、鍵交換を行い、中間装置の影響を受けずに暗号通信できるようにします。


まだ、チャーターの議論が始まったばかりで、たたき台(URL)はあるものの、これからいろいろな人の意見を受けて変わるでしょう。ただ、IoT関連を強く意識しているようです。


いまのところでは、下記の提案仕様をWGアイテムとして扱うところを目指し


さらに、大津先生が書かれていたGoogleのATLSもスコープに含まれているようです。
しかし、紛らわしいですが今あるIETF側のドキュメント類はGoogle ATLSとは別物です。
jovi0608.hatenablog.com


2018年 秋頃にユースケースやApplication-Layer TLSのドキュメントをIESGに送る事を考えているようです。

Application-Layer TLS

ATLS (WGとしてATLASだけど、プロトコルはATLSと描かれる)に関するドキュメントとして、下記の2つがありました

  • draft-friel-tls-over-http-00
  • draft-tschofenig-layered-tls-00

これらはマージされて、「Application-Layer TLS (ATLS)」draft-friel-tls-atlsとなりました。それぞれのユースケースを想定し、ATLS over HTTP, ATLS over CoAP について記述されています。


接続の確立時の、クライアント・サーバの各コンポーネント間のやり取りは下記のとおりです。
AppはATLSコンポーネントTLSメッセージを作らせ、使用するトランスポート上で送信します。そのようにしてTLSハンドシェイクを行います。
f:id:ASnoKaze:20180201083853p:plain

DNSで負荷分散を可能にするLBレコードの提案

名前解決を行っているクライアントの国や地域によって、近い場所のサーバのIPを返すといったことは既に行われている。しかし、そのDNSによる負荷分散の方法は標準化されていない。

DNS load balancing」という提案仕様では、新しくLBレコードを定義し、権威DNSサーバからフルリゾルバに対して負荷分散のための情報を伝達できるようにします。

日本の方が書かれている提案なので緊張感がありつつも、ざっと読んでみたので簡単に書く。

LBレコード

LBレコードは、分散のための情報と重みと、分散先を示すを持つ

例えば

# <owner> <ttl> <class> LB <weight> <location> <target>
   example.jp. 3600 IN LB 1 AP ap.example.com.
   example.jp. 3600 IN LB 1 JP jp1.example.jp.
   example.jp. 3600 IN LB 3 JP jp2.example.jp.
   example.jp. 3600 IN LB 1 JP-13 tokyo.example.jp.
   example.jp. 3600 IN LB 1 AS2496 as2497.example.jp.
   example.jp. 3600 IN LB 1 AS2496:1 as2497.example.jp.
   example.jp. 3600 IN LB 1 +BEER beer.example.jp.

地域としてAP, 国としてJP, 日本の都道府県コードで東京を示すJP-13, AS番号も指定可能であるほか、プライベートユースとして+から始まる文字列が使用できる。

が同じ場合は、Weightによって使い分けることが出来る。

流れ

f:id:ASnoKaze:20180127020236p:plain
(一部省略)

Authoritative name serverが下記のようなレコードを持つとする

   example.jp. 3600 IN A 198.51.100.1
   example.jp. 3600 IN LB 1 * www.example.com.
   example.jp. 3600 IN LB 1 JP jp1.example.com.
   example.jp. 3600 IN LB 3 JP jp2.example.com.
  • 1) スタブリゾルバがフルリゾルバに問い合わせる
  • 2) フルリゾルバはAuthoritativeサーバに問い合わせる際に、LBレコードに対応している旨を示すLB Support Flagを立てて名前解決を行う。
  • 3) Authoritativeサーバは問い合わせに対応するLBレコードを返す。
  • 4) フルリゾルバは受け取ったLBレコードの中からスタブリゾルバに適切なLocationを選択しWeightより「jp1.example.com.」を選び、解決しスタブリゾルバに応答する

DNS ALTSVC recordの提案仕様

Alternative ServicesをDNSで通知できるように、ALTSVCレコードを定義する「Finding HTTP Alternative Services via the Domain Name Service」という仕様が出ています。

DNSレコードタイプの議論ですが、HTTPbis WGから議論が始まっています。

HTTP Alternative Services

Alternative Servicesは、オリジンを別のエンドポイント、別のプロトコルで提供できることをクライアントに通知する仕組みです。

例えば、現在もQUICの通信を始める際はHTTPレスポンスヘッダで自身のサービスはQUICでも提供できることを通知しています。

googleにアクセスすると、下記のようにalt-svcヘッダを付けてきます

alt-svc:hq=":443"; ma=2592000; quic=51303431; quic=51303339; quic=51303338; quic=51303337; quic=51303335,quic=":443"; ma=2592000; v="41,39,38,37,35"

現在alt-svcを通知する方法は 「RFC7838 HTTP Alternative Services」で定義されているとおり

  • alt-svcレスポンスヘッダを用いる
  • HTTP/2でALTSVC frameを使用する

これらは、HTTPの通信が始まってから切り替えを行う流れになります。

より早いタイミングで、Alternative Servicesを通知するためにDNSレコードを使う方法が出てきたというわけです。

DNS ALTSVCレコード

Alternative Servicesを通知するALTSVCレコーとタイプを新しく定義します。

例えば、このようなalt-svcレスポンスヘッダは

Alt-Svc: h2=":8000"; ma=60

このようなDNSレコーとなります

_https._443.www.example.com. 60S IN ALTSVC "h2=\":8000\""

クライアントは、A/AAAAレコードを取得する際にALTSVCレコードも問い合わせ、Alternative Servicesを確認することでより早く代替エンドポイント・プロトコルで接続することが出来ます。

何故SRVレコードを使わないのか

似たようなレコードとして、SRVレコードが有ります。SRVレコードはそのドメインが対応しているか確認できる。

例えば、「_http2._tcp.example.com.」のように問い合わせる。

このSRVレコードを使わない理由としては以下などがあげられている

  • プロトコルのアップグレードすることを指示できない
  • パラメータの拡張性がない
  • 後の接続でAlt-Svc情報の処理をスキップ出来ない

HTTP/2 クロスオリジン サーバプッシュを可能にする提案仕様

ちょっと不明瞭な部分が修正できてません。すみません。

20180824追記
Loading Signed Exchangesについて記事を書きました
Loading Signed Exchangesの仕様 (WebPackaging) - ASnoKaze blog

20180213補足
「Origin-signed HTTP Responses」は「Signed HTTP Exchanges」に改称されました。

この仕様では、HTTP Exchange(リクエストとレスポンス)両方を署名対象にし、それらの署名値であるSignatureヘッダをレスポンスヘッダに追加して返します。署名値を計算するために一旦リクエストレスポンスをCBOR形式にシリアライズします。

ただHTTP Exchangeに署名をする仕様という点に注意が必要です

20180208追記
Bundled HTTP Exchangesについて記事を書きました
Bundled HTTP Exchanges とは (WebPackagingの議論より) - ASnoKaze blog


20180121追記
Intent to Implement: Origin-Signed HTTP Exchanges (Part of Web Packaging)
https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/n7cZXSTwBTY
Chromeでは導入検討中



現状HTTP/2では、クロスオリジンでのサーバプッシュは出来い。

a.comからb.comのコンテンツを、b.comのコンテンツだとしてプッシュされてもクライアントは信頼することが出来ない。

f:id:ASnoKaze:20180211101317p:plain

それを可能にする「Origin-signed HTTP Responses」という仕様がGoogleのJeffrey Yasskin氏から提案されている。

Origin-signed HTTP Responses」では、コンテンツを署名する仕組みを定義している。b.comの署名があれば、b.comのコンテンツを別の所から配布しても信頼できるという感じである。

自分も正しく理解できてるかわからないが、簡単に読んでみた。

Origin-signed HTTP Responses

Origin-signed HTTP Responses」は、以前書いたWebPackagingの議論からでてきた仕様である。
asnokaze.hatenablog.com

Webページを1つにまとめる仕組みとそれに署名する仕組みは分離され、後者が「Origin-signed HTTP Responses」である。

コンテンツをCBOR形式で表現する

再配布するコンテンツは、HTTPリクエストヘッダ・HTTPレスポンスヘッダ含めてCBOR形式でシリアライズしてから署名が行われる

例えば、以下のようなやりとりは

GET https://example.com/ HTTP/1.1
Accept: */*
HTTP/1.1 200
Content-Type: text/html
Signed-Headers: "content-type"

<!doctype html>
<html>
...

CBOR形式で以下のようにシリアライズされます(分かりやすいように書き下されている)

[
  "request",
  [
    ':method', 'GET',
    ':url', 'https://example.com/'
  ],
  "response",
  [
    ':status', '200',
    'content-type', 'text/html'
  ],
  "payload",
  '<!doctype html>\n<html>...'
]

この時、Signed-Headersレスポンスヘッダで指定された領域が署名の対象に含まれる。

Signatureヘッダ

この仕様では、Signatureレスポンスヘッダを新しく定義している。

Signature: sig1;
  sig=*MEUCIQDXlI2gN3RNBlgFiuRNFpZXcDIaUpX6HIEwcZEc0cZYLAIga9DsVOMM+g5YpwEBdGW3sS+bvnmAJJiSMwhuBdqp5UY;
  validityUrl="https://example.com/resource.validity";
  certUrl="https://example.com/certs";
  certSha256=*W7uB969dFW3Mb5ZefPS9Tq5ZbH5iSmOILpjv2qEArmI;
  date=1511128380; expires=1511560380
  • sig: 署名 (リクエストメソッド, リクエスURI, Signed-Headersで指定されたレスポンスヘッダ, ペイロードの署名)
  • validityUrl: 署名が更新(expire)された場合、validityUrlで指定された場所に新しい署名が格納されている
  • certUrl: 証明書のURL。TLS1.3のCertificate message形式のデータが得られる
  • certSha256: 証明書のハッシュ
  • date: 現在のUnix Time
  • expires: 失効 Unix Time (現在時間より7日以内である必要がある)

元コンテンツがレスポンスする際にSignatureヘッダを付けてくるので、再配布者はこれをそのまま再配布すれば良い

クライアントはそのコンテンツの署名を確認し、有効であれば受け入れる。

HTTP/2 extension for cross-origin Server Push

HTTP/2でクロスオリジン サーバプッシュを可能にするため、幾つかの拡張を定義している。

まだ、IETFに提出されている提案仕様では含まれていないが、Github上ではmasterにコミットされている(コミットURL)

  • ENABLE_CROSS_ORIGIN_PUSH SETTINGSパラメータ: クロスオリジン サーバプッシュに使うことをネゴシエーションするためのSETTINGSパラメータ
  • NO_TRUSTED_EXCHANGE_SIGNATURE error code: プッシュされたコンテンツが署名検証できなかったときなど、信頼できなかったときのエラー

雑感

なんでサーバ証明書そのものを、ヘッダに入れないんだろうか、キャッシュできるようにかな

preloadを使うのがシンプルで強力だが、クロスオリジン サーバプッシュも面白いなと思いました。

そろそろ標準化されるHTTP/2 ORIGIN フレームについて (RFC8336)

20180322 更新
RFC8336としてRFCになりました


HTTP/2の拡張仕様で、ORIGINフレームという提案仕様が大詰めを迎えています。
https://tools.ietf.org/html/draft-ietf-httpbis-origin-frame-05


IESGに送られていますが、現在のところでは反対意見は出ていません。

このORIGINフレームについては、数年前に一度記事を書きましたが幾つかの更新があるので補足する。
asnokaze.hatenablog.com

背景

HTTP/2では、上限があえば異なるオリジンとの通信でも1つのコネクションを使いまわすことが出来ます。

しかし、クライアントがコネクションを使いまわそうとしたものの、サーバ側がそのオリジンのコンテンツを提供できないという場合があります。その時は、サーバは421 (Misdirected Request)を返すことになっています。

421レスポンスを貰ってから再度目的のオリジンにコネクションをはるというのは、待ち時間を発生させます。

ORIGIN フレームは、サーバ側が対応しているオリジンのリストをクライアントに提供することで、クライアントはコネクションを再利用可能か判断出来るようにします。

HTTP/2 ORIGINフレーム

初期の提案仕様と異なり、複数オリジンをOrigin-Entryとして1つのフレームで送信できるようになっています

ORIGINフレームの中身はOrigin-Entryと呼ばれる領域が一つだけあります。

   +-------------------------------+-------------------------------+
   |         Origin-Entry (*)                                    ...
   +-------------------------------+-------------------------------+

Origin-Entryの中身は、通知するオリジンが長さと値を繰り返したものです。複数のオリジンを通知できます。

   +-------------------------------+-------------------------------+
   |         Origin-Len (16)       | ASCII-Origin?               ...
   +-------------------------------+-------------------------------+

ASCII-Originは、Scheme, Host, Portからなり、https://example.com:443 のように記述されます

クライアントはORIGINフレームで指定されたオリジンの場合のみそのコネクションを再利用できます。書かれてないものに関してコネクションを再利用しては行けません。

セキュリティ上の対応

セキュリティ上の対応で、初期提案と比べ変更点が有ります

  • クライアントはhttpsで接続している場合のみ、ORIGINフレームを解釈する。h2cの場合は無視する
  • *.example.comのようなアスタリスクは無効
  • alt-svcの広告の影響をうけない
  • コネクションを再利用するオリジン間でTLSハンドシェイク中に取得した証明書が有効なこと(subjectAltName or ワイルドカード証明書)

特に大きなトピックだったのは、クライントはORIGINフレームで提供されたオリジンの名前解決をすべきかどうかでした。

HTTP/2のコネクション再利用条件に、同じIPアドレスであることが条件の一つになっていますが、悪意あるサーバに悪用される可能性があるため、ORIGINフレームでもIPアドレスが同一かどうか確認するべきなのかが議論になりました。

今のところ、名前解決をしなくても良いことになっていますが、その場合はCTやOCSPをつかって証明書の確度をあげるべきだとしています。

Amazonの人が提案するDistributed OAuthという提案仕様

AnazonのDick Hardt氏が「Distributed OAuth」という仕様を提案している。

昨年行われたIETF100でも議論があり、来週行われるOAuth WG Virtual Meetingでも話が進められるようだ。

遅らせばながら簡単に読んで見る。

Distributed OAuthとは

通常のOAuth2では、一つのリソースサーバと一つの認可サーバがあり、その関係は固定的です。この提案仕様では、もっと複雑で大きなケースを想定しています。
同様の機能を持つ複数のリソースサーバと、リソースサーバごとに別の認可サーバがあるようなケースです。

IETF100の発表資料を見るとイメージは湧きやすいでしょう(あくまで例だと思います)
f:id:ASnoKaze:20180108010721p:plain
https://datatracker.ietf.org/meeting/100/materials/slides-100-oauth-sessa-distributed-oauth/

Distributed OAuthでは、クライアントがリソースの認可を行う認可サーバをリソースサーバに問い合わせることで、そのリソースサーバと関連する認可サーバを知れるようにする提案仕様です。

Distributed OAuthフロー

f:id:ASnoKaze:20180108011422p:plain

  • (A) クライアントは認可サーバを見つけるために、Authorizationヘッダをつけずリソースサーバにリクエストを送信する (この時TLS通信で得られた証明書から、hostを取得しておく)
  • (B) リソースサーバは401レスポンスを返す。WWW-Authenticateヘッダのissトークンを発行する認可サーバのエンドポイントを指定する
       HTTP/1.1 401 Unauthorized
       WWW-Authenticate: Bearer realm="example_realm",
                                iss="http://issuer.example.com/token",
                                scope="example_scope",
                                error="invalid_token"
  • (C) クライアントはissで指定されたURLにアクセストークンリクエストを送信する
       POST /token HTTP/1.1
       Host: issuer.example.com
       Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
       Content-Type: application/x-www-form-urlencoded

       grant_type=client_credentials
       &scope="example scope"
       &host=resource.example.com
       &realm="example_realm"
  • (D) 認可サーバはhost属性を持つアクセストークンを払い出す際に、
  • (E) クライアントは保護されたリソースにアクセストークンを持ってアクセスする
  • (F) リソースサーバはそのアクセストークンのhost属性がリソースサーバのhostであることを検証を行い、保護されたリソースへの処理をおこないます。

攻撃モデル

このDistributed OAuthでは、幾つかの攻撃モデルについて検討しています。

  • 悪意あるリソースサーバがクライアントから得たアクセストークンを再利用し、別のリソースサーバにアクセスする
  • 悪意あるリソースサーバは、異なるリソースサーバーで使用できるアクセストークンを取得するようにクライアントに指示しアクセストークンを取得する
  • 悪意あるリソースサーバは、悪意ある認可サーバにクライアントをリダイレクトし、クライアントからの情報を取得する

host属性を検証する、mutual TLS・proof of possion認証で上記の問題は緩和できるらしい...