example.comのTLS1.3ハンドシェイクを覗いてみます。
この記事を書くために、TLS1.3について別記事にまとめました。
通信を覗く方法
下記のサイトのやり方でexample.comと通信するchromeの通信をWiresharkで覗きました。
【解析/Wireshark】https(SSL/TLS)を復号化する方法(SSLKEYLOGFILE),ブラウザで見る方法 | SEの道標
TLSハンドシェイク
以下のスクショは、実際にキャプチャしたTLSパケットです。
見やすくシーケンス図にすると次のようになります。[]
は暗号化済みのメッセージで外部からは中身を見ることができません。
翻訳版。
Clinet Hello
Client HelloはサーバにTLS通信の開始を伝えるわけですが、暗号スイート以外の必要な情報は各拡張機能にいれておきます。
思ったより拡張の数が多かったので1フィールド+6拡張に絞って見ていきます(あんまり絞れていない)。
- 利用できるTLSのバージョン(supported_versions)
- 利用できる暗号スイート(Cipher Suitesフィールド)
- 利用できる鍵交換アルゴリズムの提示(supported_groups)
- 通信予定の鍵交換アルゴリズムのパラメータ(key_share)
- 利用できる署名アルゴリズムの提示(signature_algorithms)
- 今後PSKの交換をするかどうか(psk_key_exchange_modes)
- 過去の通信で交換したPSK(pre_shared_key)
supported_versions拡張
クライアント(ここではChrome)が対応しているTLSのバージョンを格納します。
TLS1.0~1.3まで対応しているようです。もちろんクライアントとしては新しいバージョンで通信してほしいわけです。
Cipher Suitesフィールド
クライアントが対応している暗号スイートを格納します。TLS1.3はTLS1.2までとフォーマットが異なり、暗号化アルゴリズム(共通鍵暗号)の部分だけが示されています。詳しくは僕の前の記事に書いています。
※Aはアルゴリズムの略です。 TLS1.2: TLS_鍵交換A_署名A_WITH_(暗号化A_鍵長_暗号利用モード)_ハッシュ関数 TLS1.3: TLS_(暗号化A_鍵長_暗号利用モード)_ハッシュ関数
なるほど~。TLS1.2以前とTLS1.3の暗号スイートが混ざっています。このClient HelloがTLS1.3として解釈されたときは上の3つが、そうでないときは下のものが利用されるというわけですね。TLSが後方互換性に配慮していることが見て取れます*1。
ちなみにVersionフィールドがTLS 1.3ではなくTLS1.2なのも後方互換性のためです。TLS1.3では本当はVersionフィールドを消したかったみたいです*2。
supported_groups拡張
クライアントが対応している鍵交換アルゴリズムを格納します。メッセージの暗号化に必要な鍵を交換するために使います。
ECDHEのうち3つの楕円曲線に対応しているようで、逆に、DHEは提示していません。
x25519はTLS1.3から導入されたアルゴリズムで、新しいためまだ未対応のケースが多いようですが、さずがChrome様。対応済みです。
key_share拡張
TLS1.2では、鍵交換アルゴリズムを決定後に、アルゴリズムの計算に必要なパラメータを別の通信で送ります。TLS1.3では、そのアルゴリズムが使われるかわからないのに、Client Helloの段階で送ってしまいます。そうすることで、あわよくば通信に必要な往復を削減できるのが特徴です。
ここでは、x25519が使われると想定して、そのパラメータを格納しています。どうなるでしょうか。
signature_algorithms拡張
クライアントが対応している署名アルゴリズムを格納します。サーバの認証に必要です。
ECDSAとRSAに対応しているようです。鍵交換アルゴリズムでx25519に対応しているので、その署名アルゴリズムverのed25519にも対応していそうなものですが、提示されていませんね。謎です。
psk_key_exchange_modes拡張
TLS1.3ではセッションの再開にPSK(Pre-Shared Key)を使えます。PSKの共有方法は、前回のセッション中に交換するか、TLSスコープ外(手渡しとか?)で交換するかです。psk_key_exchange_modes拡張では、PSKの交換に対応しているか、PSKで接続を確立する方法を格納します。
対応していました。PSKのみのセッション再開ではPFS(同じ鍵で過去の通信まで復号できないこと)がないため、PSKとECDHEを使ったハイブリッドな鍵交換でPFSを保証できるpsk_dhe_ke方式が指定されています。
pre_shared_key拡張
PSKが格納されています。キャプチャする前に試しにアクセスしているため、そのときに交換したものだと思われます。
Client Helloまとめ
Chrome「サーバーさんサーバーさん
- TLS1.3に対応してるよ!
- こんな暗号スイートに対応してるよ!(雑)
- x25519で鍵交換しようよ!
- 無理でもsecp256r1とsecp384r1に対応してるよ!
- RSAとECDSAで署名の検証ができるよ!
- PSK対応してるよ!
- PSK持ってるよ!
」
Hello Retry Request
クライアントが提示した鍵交換アルゴリズムのパラメータに対応していなかった場合、このメッセージでやり直しをさせます。
Chromeはx25519のパラメータを送っていましたが、サーバはsecp256r1のものがほしかったようです。
Change Cipher Spec
TLS1.2では暗号スイートの変更の際に利用されたメッセージですが、TLS1.3ではHello Retry Requestがあるため不要なはずです。なぜChange Cipher Cpecを送信しているのかはよくわかりません。
- The server sends a dummy change_cipher_spec record immediately after its first handshake message. This may either be after a ServerHello or a HelloRetryRequest.
ミドルボックス互換性のためのようです。
2度目のClient Hello
Chromeは署名アルゴリズムのパラメータとしてsecp256r1のものを送って再挑戦します。
Client Helloが更新された際のPSK
In addition, in its updated ClientHello, the client SHOULD NOT offer any pre-shared keys associated with a hash other than that of the selected cipher suite.
Hello Retry Requestが送られたあとはPSKによるセッションの再開ができない可能性があるようです。
今回はそのパターンのようで、セッション再開されていればやり取りされないはずのCertificateとCertificate Verifyがあります。
Server Hello
クライアントが提示したアルゴリズムリストから1つづつアルゴリズムを選んでクライアントに教えます。 よく考えるとHello Retry Requestと同じ事をしており、実際に中身もほぼ同じなので省きます。
Encrypted Extensions
鍵交換/署名/暗号化アルゴリズム同意後であれば、それ以外の情報はもう暗号化して隠せます。なのでTLS1.3では、Server Helloとは別でEncrypted Extensionsがあります。
ALPNはHTTP通信のバージョンの合意をとるプロトコルで、クライアントがh2(HTTP/2)で通信したいと提案してきたので、対応しているサーバもh2を返しています。
こちらがClient Hello内にあったALPNプロトコルです。
Certificate
サーバの認証に必要な証明書チェーンが格納されています。
ブラウザからも見られます。
Certificate Verify
サーバの認証に必要なデジタル署名が格納されています。証明書チェーンとセットで使われます。
署名アルゴリズムはrsa_pss_rsae_sha256が指定されていました。
Finished
クライアントもサーバもハンドシェイクの最後はFinishedを送り、今までのやりとりが改ざんされたものでないか検証をします。
TLS Session Ticket
PSKの計算に使うチケットをサーバ側から任意のタイミングでクライアントに通知します。Client Hello時のpsk_key_exchange_modes拡張で、クライアントがPSKに対応していることをサーバは確認済みです。
今回は連続で2つのチケットを送信していますが、なぜかはわからないです。
まとめ
1つ1つ調べるのが大変でしたが、TLS1.3について理解が進みました。別のサイトについてモチベーションが保てていれば見ていきたいと思っています。