ブラウザでTCPを直接送受信できるDirect Sockets APIについて

ブラウザから直接TCPUDPで送受信する「Direct Sockets API」という仕組みが議論されています。

実験段階ですが、Chromeでは起動時にオプションを付けることでこの機能を有効にできます。今回はTCPの方で簡単に動作を見てみます。

Direct Sockets API

Direct Sockets APIは、TCPUDPで直接送受信可能にするAPIです。既存のアプリケーションプロトコル(SSHIRC)、P2Pのような機能を実現可能になります。

もちろんセキュリティ上の問題もあるので、Chromeでは現状デフォルトでは有効になっていない機能です。

セキュリティ面についてはだいぶGithubリポジトリで議論されておりますので目を通すと良いでしょう。ローカルネットワークへの通信やSame-Origin-Policy(CORS)回避の話が上がっていますが、今回は細かくは紹介しません。

その他、意見がある場合はコメントすることもできます。
github.com

試してみる

Chromeでは実験的に実装されています。おそらくまだ実装途中ですので、今後変わる可能性は高いです。

今回は、現在時点のChrome Canaryで動作確認しています。

クライアント側準備

起動時にオプションが必要です。
Chrome 99 では次の起動オプションをつけて、Chromeを起動します (現在の起動コマンドは、chrome:version から確認できます)

  • --enable-blink-features=DirectSockets
  • --enable-features=DirectSockets
  • --restricted-api-origins=https://asnokaze.com
サーバ側準備

有効にするページ(上記 --restricted-api-origins で指定したページ)で、次のレスポンスヘッダをつけます

  • Cross-Origin-Embedder-Policy: require-corp
  • Cross-Origin-Opener-Policy: same-origin
  • Permissions-Policy: direct-sockets=(self)

なお、TCPサーバ特定ポートで接続を受け付けるために、下記のコマンドを実行して123番ポートでリッスンしておきます。(well-knownポートが使用できるか確認するために、123番を使用)

$ while true; do ( echo "Hello from server" ) | sudo nc -l 123; done

つなぐ

Webページを開いたら、今回はデベロッパーツールで以下に示すスクリプトを実行します。このスクリプトでは

  • 指定されたサーバに、123番ポートで接続して、"Hello from chrome" と書き込みます
  • サーバから送信されたデータをデベロッパーツールに出力します

すると、ダイアログが出るので接続先を入力します。(現状は任意のサーバ・任意のポートが指定可能...)
f:id:ASnoKaze:20220104001004p:plain

const options = {
    remoteAddress: 'asnokaze.com',
    remotePort: 123
};
navigator.openTCPSocket(options).then(tcpSocket => {
	readableStream = tcpSocket.readable;
	writableStream = tcpSocket.writable;
	const defaultWriter = writableStream.getWriter();
	defaultWriter.ready.then(() => {
		return defaultWriter.write(str2ab("Hello from chrome"));
	})
	const defaultReader = readableStream.getReader()
	defaultReader.read().then( ({done, value}) => {
		console.log(ab2str(value));
	})
})

function str2ab(str) {
	var buf = new ArrayBuffer(str.length);
	var bufView = new Uint8Array(buf);
	for (var i=0, strLen=str.length; i < strLen; i++) {
		bufView[i] = str.charCodeAt(i);
	}
	return buf;
}

function ab2str(buf) {
	return String.fromCharCode.apply(null, new Uint8Array(buf));
}
サーバ側

クライアントからのメッセージが表示されました

$ while true; do ( echo "Hello from server" ) | sudo nc -l 123; done
Hello from chrome
クライアント側

サーバからのメッセージが表示されました
f:id:ASnoKaze:20220104001351p:plain

標準化に対する姿勢

この仕様は、かなり強力な機能であるため、標準化に対する姿勢はそれぞれです。

そもそもこの仕様はGoogleの方によって提案されています。しかし、Mozillaは反意を示しています(参考URL)。その他、Node.jsやDenoの領域でこの仕様に興味をもっている方も居ます。

なんにせよ、すぐに標準的な仕様になりそうというものではなさそうです。

Greasing the QUIC Bit の仕様について (RFC9287)

Greasing the QUIC Bit」という仕様が提案されています。

背景

仕様の解説の前に、QUIC BitとDemultiplexingの補足をします。

QUIC Bit

QUIC v1ではロングヘッダパケット、ショートヘッダパケット(1-RTTパケット)とも先頭から2bit目がFixed Bitとして "1" に固定されています。


UDP demultiplexing

たとえばWebRTCでは、一つのUDPポートで複数のプロトコルのパケットをやりとりします。RFC7983では、その多重化の方法を定義していますが、その仕様もQUICを考慮した形で改訂作業が進められています。それが「Multiplexing Scheme Updates for QUIC」です。

具体的には、下記のように各パケットの先頭1バイトによってパケットを識別します。

この識別に、QUIC Bitが利用できます。

硬直化

QUIC v1では、QUICパケットのヘッダもほとんどの領域が暗号化されていますが、QUIC Bitは暗号化されません。demultiplexingするために、QUIC Bitは復号前に利用されるからです。

このようにパケットの特定値が経路上で利用されていると、予期せぬ形で利用され、新しい拡張仕様や将来のQUICバージョンをデプロイするときに誤作動する要因となりえます。このような問題を硬直化とよんでおり、TLS1.3やQUICではすでに、そのような問題がすでに見つかっています。

そのため、一般的にGreasing という仕組みを導入し硬直化しづらくします。

Greasing the QUIC Bit

demultiplexingが必要ない通信では、クライアントとサーバ合意のもとQUIC Bitをランダムに設定しても通信上は問題有りません。それが「Greasing the QUIC Bit」です。

Greasing the QUIC Bit」では、grease_quic_bitトランスポートパラメータをemptyで送信します。

grease_quic_bitトランスポートパラメータを受信下側は、その相手に対してQUIC Bitをランダムに設定してもよくなります。

また将来的に、このbitをその他の用途に利用もすることもできます。

2021年 HTTPやQUICの最新動向振り返り

2021年について、プロトコル周りの動向を振り返っていきたいと思います。

今年は、個人的には次の2点がホットトピックと挙げられると思います。

  • QUICやHTTP/3を活用した応用系プロトコルの作業が進む
  • プライバシー系の取り組みが活発化

それでは、個別に補足していきます。(IETFの動向がメインです。なお、個人的にキャッチアップできてないトピックもあります...)

f:id:ASnoKaze:20211231030248p:plain

HTTP関連

まずは、HTTPです。HTTP/3の標準化が注目を浴びていますが、HTTP/1.1やHTTP/2なども改定作業が行われております。あわせて、HTTPセマンティクスは各バージョンから独立し、各バージョンから参照される形となりました。それぞれRFC出版の最終段階となっています。

f:id:ASnoKaze:20211230235428p:plain

書いた記事はここらへん

また、それ以外にもメソッド・ヘッダ・Cookieなど様々な仕様が提案されております

また、書いたのは一昨年ですが、次のトピックも標準化が進められています

その他書けていないトピックとしてRFC6265 HTTPのCookieも仕様の改定作業が進められています

QUIC

QUICは、RFC 9000として標準化が完了しました。いくつかの拡張仕様の議論や、実際のQUICの運用に関するトピックの議論が行われています。

個人的に注目しているところとして、Ossification(硬直化)対策として進められているQUIC v2や、Wi-FI+LTEといった複数通信を扱うMultipath QUICといったトピックがあります。
書いた記事はここらへん

その他記事には書けておりませんが、QUIC WGでは他にも次のような仕様の標準化が進んでいます

DATAGRAM拡張

QUICにはDatagram拡張という仕様の標準化が進められています。トランスポートプロトコルであるQUICはアプリケーションプロトコルのデータは再送されますが、再送を必要としない通信方法を規定しています。WebTransportやMASQUEなど多くのプロトコルで利用されます。

もともとはHTTP/3で利用のみとして標準化されていますが、TCPにより再送されてしまいますがHTTP/2, HTTP/1.1でも利用できる形での標準化が目指されています。また、DATAGRAM拡張自体を拡張出来るように現在専任デザインチームで議論されています。そのため、またその部分は変更されるものと思われます。

WebSocket, WebTransport

Webでのアプリケーションデータの双方向通信として、WebTransportというものが出てきました。これはHTTP/3を活用し再送が不要なアプリケーションデータの送信を可能にするものです。

今年は方針が固まった年であり、WebTransportは over HTTP/3でまず標準化することと、フォールバック先としてover HTTP/2の標準化を行うことが決まりました。

また、WebSocketではHTTP/3対応した仕様の標準化作業が進められています。

書いた記事はここらへん

WebTransport over HTTP/2は最初の仕様とは異なり、最新版ではlayered designという形で再設計されております。

また、ブラウザへのマルチキャスト配信についてW3CのMulticastCGで議論されておりますが、そこでもWebTransportを使用できないかという議論が進んでいます。

OHTTP, Masque

OHTTPもMasqueもそれぞれ全く違う技術ですが、合わせて紹介します

OHTTP(Oblivious HTTP)は、ユーザのIPを秘匿する通信方法の標準化を行っています。AppleのPrivate Relayなどの取り組みを行っている方々も興味をもっているようです。書いた記事はここらへん

Masqueは、HTTP/3上UDPパケットやIPパケットをトンネリングする仕組みを標準化しています。それぞれWGアイテムとして標準化が勧めラ得ています。書いた記事はここらへん

なお、CONNECTメソッドを使用していましたが、最新仕様ではWebSocket over HTTP/2と同様に拡張CONNECTメソッドを使う形で標準化されています。CONNECT-IPは複数の提案仕様があったのですが、合わせるような形で新しい仕様が出されています。

Media over QUIC

IETFでは、QUIC上でどのようにメディアデータを送信するかというトピックがホットになっています。すでに、FacebookやTwitchではそれぞれ独自の手法で実利用が始まっているようです。とはいえ、注目は浴びているものの、標準化のためにユースケース別に要件を整理している段階になります。

主なユースケースは次のとおりです。

  • 配信者からのアップロード
  • 視聴者のダウンロード
  • P2Pによる通信

FacebookはRUSHというプロトコルを、TwitchはWarpという仕組みを利用しているようです。Warpは提案仕様を提出する準備ができているようですが、まだ出てきておりません。その他SRT over QUICや、RTP over QUICの議論も行われています。

RUSHについては記事を書いております

XX over QUIC

QUICがRFCとなり、既存のアプリケーションプロトコルでも、QUICを利用することが考えられています。それぞれのワーキンググループにより標準化が進められています。

  • BGP over QUIC
  • DNS over QUIC
  • SSH over QUIC
  • SMB over QUIC
  • RTP over QUIC
  • (NTP over QUIC)

TLS

TLS関連も引き続き標準化が進められています。ココでは、個人的に注目しているトピックを触れます。

TLS1.3の仕様も改訂作業が進められています。機能上は大きな差はありません。

あと大きなところで言うと、Encrypt SNI(ESNI)とも呼ばれていましたが、ClientHelloを暗号するECHという仕様も標準化が進められています。以前記事に書いております。


その他にDTLS 1.3や、余分なデータ量を削ったコンパクトなcTLSの標準化も進めれています。また、TLSを安全に使うためのガイドラインRFC7525の改訂作業も進められています。

追えてないトピック

  • OAuth, Gnapまわり
  • Privacy Pass まわり
  • Privacy Interest Group まわり
  • 暗号系トピック

gRPC over HTTP/3のプロトコルと実装を眺める

gRPC over HTTP/3のプロポーザルと、実装が出てきています。

今回は、仕様を眺めつつ、Ubuntuで実装を動かすところまで試してみようと思います

プロトコル仕様

プロポーザルは、現在 "In review" の状態となっています。
github.com

HTTP/3の基本

HTTP/3はHTTP/2と機能上は大きな違いはありません。HTTPリクエストで通信が始まり、各HTTPリクエスト・レスポンスはQUICのストリームによって多重化されます。そのため、gRPC over HTTP/2にほぼマッピングされます。

HTTP/3では、トランスポートとしてQUICを使用します。これにより、ストリームが異なる場合は、パケットロスやパケットの順番が入れ替わったとしても、受信した後続のパケットを処理しすることができます
(TCPでは一般的にOSがそのパケットを回復するまで、後続のパケットを受信してても処理できません)

また、各コネクションはコネクションIDによって識別されるため、IPアドレスやポート番号が変わってもコネクションを維持することができます。
(サーバ間の通信が主なgRPCではそのメリットは少ないかもしれない)

一方で、QUICの通信は暗号化されます。暗号化しない手段は提供されていません。QUICは通信の中で、TLSハンドシェイク相当の処理を行うので、一般にはサーバ証明書が必要になります。

なお、1度通信した相手とは、0-RTTハンドシェイクを行うことで、コネクションの確立を早く行えます。

おまけ: QUIC及びHTTP/3の詳細

QUIC及びHTTP/3の詳細については、過去にガッツリ解説を書いたのでこちらを参照ください
asnokaze.hatenablog.com

gRPC over HTTP/3のプロトコル仕様

ここでは、gRPC over HTTP/2 との違うところ/同じところを簡単にかいつまんで紹介します。

  • ストリームID: HTTP/3ではQUICにより提供されるストリームを使用しますが、HTTP/2のストリームIDと同じように機能する
  • データフレーム: DATAフレームの使い方は、HTTP/3では変更されない
  • エラーコード: HTTP/3では、HTTP/2と異なるエラーコードをもちます。そのため、gRPCのエラーコードと改めてマッピングが行われます(仕様参照)
  • 接続の管理: GOAWAYフレームおよび、PINGフレームはHTTP/2のときと同様に使用できます。

そのため細かい点はありますが、HTTP/3とHTTP/2を変換するProxyを間に挟むだけで、プロトコル上は問題なく動作すると思われます。

また、HTTP/2はTCPであり、HTTP/3はQUIC(UDP)ですのでどちらで通信を行うのかうまく選択しなければなりません。その戦略には、一般的に2種類の方法があります。

  • クライアントがHTTP/3を使うように設定されている場合は、HTTP/3で最初に接続しに行く (Happy Eyeballsや、フォルバックは実装依存)
  • ブラウザが行うのと同じように、クライアントはまずHTTP/2で接続してから、alt-svcヘッダの情報をもとにサーバがHTTP/3に対応している事を知ります。その後、HTTP/3で通信を開始します。

実装

Ubuntu 20.04で、.Net core6 を[公式ドキュメント]にそってインストールします。

その後、下記のexampleを実行します。このGreeterは、nameをつけてSayHelloすると、「hello name」と返してくれます。
github.com

サーバ

.Net 6.0でビルドして、HTTPSと証明書の設定をし、ドキュメントに沿ってHTTP/3を有効化します。

要所としてはこんな感じで動きました。

webBuilder.ConfigureKestrel(options => {
	X509Certificate2 cert = new X509Certificate2("/path/to/server.pfx");
	options.ListenLocalhost(5001, o => {
		o.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
		o.UseHttps(cert);
	});
});

その後、ビルドして起動するだけです。

動作確認

今回は単純に、HTTP/3に対応したcurl で grpcなリクエストを投げ込んで動作確認しました

クライアントログ (出力はgrpc形式のバイナリがかえってきています)

$ hexdump -C ./req.bin 
00000000  00 00 00 00 0f 0a 0d 47  72 65 65 74 65 72 43 6c  |.......GreeterCl|
00000010  69 65 6e 74                                       |ient|
00000014

$ cat ./req.bin | curl -sS -X POST --data-binary @- https://localhost:5001/greet.Greeter/SayHello  -k -H"content-type:application/grpc"   --http3 -o - | hexdump -C
00000000  00 00 00 00 15 0a 13 48  65 6c 6c 6f 20 47 72 65  |.......Hello Gre|
00000010  65 74 65 72 43 6c 69 65  6e 74                    |eterClient|
0000001a

サーバ側ログ

:~/work/grpc-dotnet/examples/Greeter$ ./Server/bin/Debug/net6.0/Server
...

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/3 POST https://localhost:5001/greet.Greeter/SayHello application/grpc 20
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'gRPC - /greet.Greeter/SayHello'
info: Server.GreeterService[0]
      Sending hello to GreeterClient
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'gRPC - /greet.Greeter/SayHello'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/3 POST https://localhost:5001/greet.Greeter/SayHello application/grpc 20 - 200 - application/grpc 6.2228ms

一旦、ちゃんと動いてそう。

最後に

他の言語でも繋いでみたいですね(冬休みの宿題)

QUICのPath MTU Discovery手法の論文を読んで

QUICに関するEPIQ 2021というワークショップで、「The search of the path MTU with QUIC」という発表がありました。

論文と発表スライドはEPIQ 2021のページより見ることができます。

簡単に内容に目を通していきたいと思います。

TL;DR 3行で

  • RFC 9000 QUICは1280バイト以上のIPパケットを送信する場合に、Path MTU Discoveryを行う必要がある
  • Path MTU Discoveryの方法としてRFC 8899 DPLPMTUDを使用するが、RFC 9000 QUICでは具体的な探索アルゴリズムを与えていない
  • 本論文では、7種の探索アルゴリズムに対して4種類の評価項目を評価及び、シミュレーションを行った。

前提

RFC 9000 QUICのPath MTU Discovery

1280バイトのIPパケットは通る事を想定し、QUICのRFC9000ではデータグラムのサイズは1200バイトを初期の上限に設定されます。Path MTU Discoveryを行うことでそれ以上のサイズのIPパケットを送信できるようになります。(IPv4を使う場合はDon't Fragmentフラグを設定しなければなりません)

ICMPを使ったPath MTU Discovery方式として、下記のRFCで定義されるとおりです

しかし、インターネット上の経路ではICMP (Packet Too Big)がフィードバックされない場合もあるため、上記の手段が使えない場合があります。

RFC 8899 Packetization Layer Path MTU Discovery for Datagram Transports」では、QUICのレイヤでプローブを送りPath MTU を探索します。

RFC 8899 DPLPMTUDとQUIC

RFC 8899 DPLPMTUDは次のようなフェーズを持ちます。
f:id:ASnoKaze:20211219235750p:plain

  • Base: 最初に基本的なサイズでプローブを送ります。QUICでは指定された1280バイトが通ることが前提となるので次のフェーズから始まります。
  • Search: プローブを送りながら、候補となるPath MTUを探索する。最良であろうPath MTUを検出すると次のフェーズに進みます。
  • Search Complete: 経路変更に伴いPath MTUが変わる可能性があるため、依然として最良か確認する

なお、プローブはQUIC PINGフレームとPADDINGフレームで構成されます。PINGフレームはack-elicitingフレームですので、受信側はAckを返す必要があります。

プローブには3つの結果があります

  • Acknowledgement: プローブ送信側はピアからのackを受信する。これにより、送ったプローブのパケットサイズが送信可能なことがわかります。
  • Loss: QUICのロス検出(RFC9002)により送ったプローブがドロップしたことがわかります。パケットロスはパケットサイズに関わらず発生するため、RFC8899の通りMAX_PROBES回試行後に送ったプローブのパケットサイズが送信できないことが分かります。
  • PTB: プローブパケットに対して、PTBにはPTBを送った側のMTUが含まれます。その値が可能なパケットサイズの最小値となります。

The search of the path MTU with QUIC

「The search of the path MTU with QUIC」の内容に触れていきます。

PMTU Candidates

本論文では、PMTU候補として 1280バイトから1500バイトまで4バイトおきの値を候補とします。

探索アルゴリズム

本論文では、7つの探索アルゴリズムを比較します。その7つについて説明します。

  • UP: 小さい方から順番に試行します
  • Down: 大きい方から順番に試行します
  • OptUp: 最初に最大値をためしてから、小さい方から順番に試行します
  • DownUp: 未試行の最大値・最小値を交互に試行します
  • Binary: 二分探索で試行します
  • OptBinary: 最初に最大値をためしてから、二分探索で試行します
  • Jump: 幅をもたせ大きい方から成功するまで試行し、そこから失敗するまで値を上げて試行しながら絞り込んでいく

f:id:ASnoKaze:20211220002721p:plain
(発表スライドより)

評価項目

7つの探索アルゴリズムの評価する上で4つの評価項目をあげています

  • Number of probed PMTU candidates: 送ったプローブの数
  • Network Load: 送信したデータ量
  • Time: かかった時間
  • Average PMTU Estimation: 探索中に利用できたPMTU

PTBが無い場合は、それぞれのアルゴリズムは次のように評価されています
f:id:ASnoKaze:20211220003130p:plain
(論文より)

論文では、Binary>OptBinary>Jumpの順で良いと述べています。

シミュレーション

本論文では、シミュレーションを行っています。次の通り構成しています。

f:id:ASnoKaze:20211220003555p:plain
(論文より)

f:id:ASnoKaze:20211220004918p:plain

シミュレーションで、一般に良い結果を示していたOptBinary, OptBinary でいくつかの実験を行っています。

  • Figure4: データ送信量がある状態で、Path MTU Discoveryにかかる時間
  • Figure5: パケットロスがある環境での、プローブ回数とかかる時間
結果

ココまでの結果を踏まえて、この論文では次の通り述べています

  • 一般にOptBinaryを使用することをお勧めします。ただし、現在一般的なPMTU候補の小さいがまだ正確なセットがわかっている場合、このセットを最初に使用するように構成されたJumpは、バイナリよりもパフォーマンスが優れている可能性があります。

また、PTBを引き起こすことはメリットが有るため、OptBinaryなど最初に大きなパケットを送ること評価しています。

今後の課題

また、論文では、今後の取組としては、次の課題をあげている

  • SearchCompleteフェーズでのPMTU推定の検証
  • プローブパケットの輻輳を制御

メディアタイプで複数サフィックスを許可する提案仕様

HTTPレスポンスでは、content-typeとしてメディアタイプ(MIME Type)が指定されます。
例えば次のようなものがあります。

  • content-type: text/html
  • content-type: text/javascript
  • content-type: image/svg+xml

メディアタイプは "+" でサフィックスをつけることが出来ます。
例えば次のようなものがあります。

RFC 6838ではサフィックスは一つのみが想定されています。
このサフィックスを複数つけられるようにする「Media Types with Multiple Suffixes」という提案仕様が出ています。

すでにW3Cの「Decentralized Identifiers(DID)」の仕様では、複数サフィックスのメディアタイプを利用しており、IETF側でもそれをサポートできるようにするという流れです。(なぜDIDで複数サフィックスを選んだかまでは追えてない...)

特に複雑な仕様ではなく、右側から解釈していきますよという話なようだ。

f:id:ASnoKaze:20211203005602p:plain
(IETF 112 mediaman WG スライド)

QUIC Version 2 の仕様

QUIC Version 2」という仕様が提案されています。これは、「RFC 9000」で標準化されたQUIC v1と機能上はまったく同じものです。

この提案仕様の目的は、主にふたつあります。

  • 硬直化(ossification)の問題を緩和し将来のQUICバージョンをインターネットでデプロイしやすくする
  • バージョンネゴシエーションを実行できるようにする

11月に実施されたIETF 112の後に、QUIC WGのメーリングリストで、この仕様にWGとして取り組んでいくコンセンサスが得られました。現在はWG Draftとなっています。

なお、Version 2はまだ2番目のバージョンということで便宜上そう呼んでいるようです。バージョン番号の正式なアサインは後に行われます。

硬直化(ossification)の問題の緩和

硬直化とは、新しいバージョンのプロトコルを使おうとしたときに、対応していないネットワーク機器やミドルウェアが不具合を起こし、通信が阻害されることを言います。TCP Fast Openや、TLS 1.3 などで、ハンドジェクは完了するが片方向で通信がブロックされるといった、おかしな挙動をするネットワーク機器が見つかり、問題になりました。

QUICも硬直化する可能性があります。将来デプロイされるQUICv2に対応してない実装が誤ってそのパケットを処理し、不具合が起き通信が阻害される可能性があります。Google QUICでの実験ではその問題がすでに起こっていたことを明らかにしています。もちろん、IETF QUICでは硬直化が起きないように対策されています。

QUICv1のパケットは、暗号化にバージョン固有のソルトを使用しています。将来のQUICでも同様にバージョン固有のソルトを使えば、そのバージョンに対応していない(=ソルトを知らない)実装は、暗号的に初期パケットを解読できません。ですので、間違えて処理をするという問題を軽減されています。

QUIC Version 2では、これらのバージョンに固有な暗号用のパラーメータが実装上正しく変えられるようになります。逆にQUIC Version 2に対応していない実装が、QUIC Version 1のロジックで復号しようとするネットワーク装置などの問題をあぶり出すことが出来ます。

暗号関連の変更点

QUIC Version 2で変更される暗号関係のパラメータは次のとおりです。

QUIC Version 2」では、initial_salt を次のように指定しています。

initial_salt = 0xa707c203a59b47184a1d62ca570406ea7ae3e5d3

またパケット保護に使う鍵の導出に使うラベルも変更されます

  • quic key => quicv2 key
  • quic iv => quicv2 iv
  • quic hp => quicv2 hp
  • quic ku => quicv2 ku

Retry Integrityタグに使う値は次に変更されます

secret = 0x3425c20cf88779df2ff71e8abfa78249891e763bbed2f13c048343d348c060e2
key = 0xba858dc7b43de5dbf87617ff4ab253db
nonce = 0x141b99c239b03e785d6a2e9f

バージョンネゴシエーション

QUICはクライアント・サーバ間で使用するQUICバージョンをネゴシエーションします。将来標準化されるQUICの登場を待ってその仕組を作るのではなく、すでに「Compatible Version Negotiation for QUIC」として標準化が進められています。この仕組を実際に使っていくことで、将来のQUICバージョンのデプロイをしやすく出来ます。バージョンネゴシエーションを行う選択肢として「QUIC Version 2」の標準化を行っているという意味もあります

バージョンネゴシエーションの仕組みは以前書いたとおりになります。
asnokaze.hatenablog.com

アプリケーションでの利用、拡張機能

QUIC Version 2は、機能上QUICv1と代わりありません。QUICv1を使うアプリケーションプロトコルは、ALPNの変更無くQUIC Version 2を使用出来ます。

また、QUICv1で機能する拡張は、QUIC Version 2でも使用できます。

その他

ふと、疑問が一点。
QUICv1で通信したことある、Version 2に対応しているクライアントとサーバがいたとする。次の通信で、QUICv1で0-RTTを投げたときにCompatible Version NegotiationしたときのEarly Dataの扱いは、実装依存なのかな?ハンドシェイク上はただのPSKという感じで?

なんだかややこしい...orz