QUIC の initial鍵生成に使用する initial_salt と QUIC version

QUICでinitial packetを送る前に client/server initial key, IV, header protection key の6つの鍵を作成する必要があります。これらの鍵を作成するためにclient_initial_secret, server_initial_secretを作成する必要があります。そしてそれらを作成するためにinitial_secretを作成する必要があり、initial_secretを作成するためにinitial_saltとクライアントが送る initial Destination Connection ID(8 bytes of random data)を使用します。

以下のように鍵を生成します。

initial_salt = 0x38762cf7f55934b34d179ae6a4c80cadccbb7f0a

initial_secret = HKDF-Extract(initial_salt, client_dst_connection_id)

client_initial_secret = HKDF-Expand-Label(initial_secret, "client in", "", Hash.length)
server_initial_secret = HKDF-Expand-Label(initial_secret, "server in", "", Hash.length)

client_key = HKDF-Expand-Label(key: client_secret, label: "quic key", ctx: "", len: 16)
server_key = HKDF-Expand-Label(key: server_secret, label: "quic key", ctx: "", len: 16)
client_iv = HKDF-Expand-Label(key: client_secret, label: "quic iv", ctx: "", len: 12)
server_iv = HKDF-Expand-Label(key: server_secret, label: "quic iv", ctx: "", len: 12)
client_hp_key = HKDF-Expand-Label(key: client_secret, label: "quic hp", ctx: "", len: 16)
server_hp_key = HKDF-Expand-Label(key: server_secret, label: "quic hp", ctx: "", len: 16)

 

HKDF-Extract はソルトと数バイトの鍵素材を与えると、256ビット(32バイト)の新しい鍵素材を作成するもので

RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF) section2.2 で説明されています。

HKDF-Expand-Labelは鍵素材、ラベル、コンテキストデータを入力から、要求された長さの新しい鍵を作成するもので、

RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3 section7.1で説明されています。

 

initical salt については以下のように書かれています。

Future versions of QUIC SHOULD generate a new salt value, thus ensuring that the keys are different for each version of QUIC. This prevents a middlebox that recognizes only one version of QUIC from seeing or modifying the contents of packets from future versions.

RFC 9001 - Using TLS to Secure QUIC

QUICの将来のバージョンは新しいソルト値を生成すべきであり[SHOULD]、 その結果、鍵はQUICの各バージョンで異なることが保証される。これは、QUICの一つのバージョンだけを認識するミドルボックスが、 将来のバージョンからのパケットのコンテンツを見たり修正したりすることを防ぐ。

つまり将来のQUICの硬直化(ossification)の問題を緩和するために格バージョンごとにソルト値を変えます。将来新しいバージョンのQUICが出た時、そのバージョンに対応していない(そのバージョンのソルトを知らない)実装は、初期パケットを読めないようにしています。

QUIC version 2 では新しいソルトの値を記しています。

3.3.  Cryptography changes

3.3.1.  Initial Salt

   The salt used to derive Initial keys in Section 5.2 of [QUIC-TLS]
   changes to:

   initial_salt = 0xa707c203a59b47184a1d62ca570406ea7ae3e5d3

datatracker.ietf.org

QUIC Version 2やQUICの硬直化の対策について詳しくはゆきさんのブログで。

asnokaze.hatenablog.com

 

 

 

RFC9001 に書かれているQUIC v1 のソルトは

initial_salt = 38762cf7f55934b34d179ae6a4c80cadccbb7f0a

ですが、この値"38762cf7f55934b34d179ae6a4c80cadccbb7f0a"はGoogleが見つけた初めてのSHA1衝突の値らしいです。

security.googleblog.com

nakedsecurity.sophos.com

 

 

 

 

QUIC が RFCとして標準化せれる前のdraft段階ではdraftごとに変更が入っていました。

RFC9001の元となったdraft draft-ietf-quic-tlsの変更履歴をgithub上で眺めるとsaltが変更されているのがわかります。

github.com

 

Dec 8, 2020 現在のsaltになる。

github.com

 

draft29 draft-ietf-quic-http-29 で変更

github.com

C.5.  Since draft-ietf-quic-tls-28

   *  Defined limits on the number of packets that can be protected with
      a single key and limits on the number of packets that can fail
      authentication (#3619, #3620)

   *  Update Initial salt, Retry keys, and samples (#3711)

https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-34#appendix-C.5

 

draft23 で変更

github.com

C.11.  Since draft-ietf-quic-tls-22

   *  Update the salt used for Initial secrets (#2887, #2980)

https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-34#appendix-C.11

 

draft21 で変更

github.com

C.13.  Since draft-ietf-quic-tls-20

   *  Mandate the use of the QUIC transport parameters extension (#2528,
      #2560)

   *  Define handshake completion and confirmation; define clearer rules
      when it encryption keys should be discarded (#2214, #2267, #2673)

https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-34#appendix-C.13

 

draft17

github.com

*  Update the salt used for Initial secrets (#1970)

https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-34#appendix-C.16

 

 

draft13

github.com

(たくさんこの一つのコミットで変更が入ってる)

*  Changes to integration of the TLS handshake (#829, #1018, #1094,
      #1165, #1190, #1233, #1242, #1252, #1450)

https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-34#appendix-C.18

 

draft9

github.com

C.21.  Since draft-ietf-quic-tls-09

   *  Cleaned up key schedule and updated the salt used for handshake
      packet protection (#1077)

https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-34#appendix-C.21

 

draft7

github.com

面白いことに上記のコミットのコミットメッセージから分かる通り、今回のソルト

quic_version_1_salt = afc824ec5fc77eca1e9d36f37fb2d46518c36639

draft06のコミットハッシュです。

https://github.com/quicwg/base-drafts/commit/afc824ec5fc77eca1e9d36f37fb2d46518c36639

 

 

draftを追いながらQUICを実装していた方々はinitial saltに変更があるたびに変更を入れていたようです。

google/quicheを眺めると

https://source.chromium.org/chromium/chromium/src/+/main:net/third_party/quiche/src/quiche/quic/core/crypto/crypto_utils.cc;l=149

const uint8_t kDraft29InitialSalt = {0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2,
0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61,
0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99};
const uint8_t kRFCv1InitialSalt = {0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34,
0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a};
0xa7, 0x07, 0xc2, 0x03, 0xa5, 0x9b, 0x47, 0x18, 0x4a, 0x1d,
0x62, 0xca, 0x57, 0x04, 0x06, 0xea, 0x7a, 0xe3, 0xe5, 0xd3};

 

drart29, RFC QUIC v1, QUIC v2 draft の initial saltが設定されています。