TLS1.3 通信プロセスの整理は、基本的に https://tls13.xargs.org から翻訳されたもので、原文を参照することをお勧めします。
クライアント:キーペアの生成#
記録 (client_priv, client_pub)
クライアント:プレーンテキストで Client Hello パケットを送信#
主に以下の内容を含みます:
- ランダム数 client_random
- クライアントがサポートする暗号スイート
- クライアントがサポートするプロトコルバージョン
- リクエストされたサーバー名 SNI (Server Name Indication)
- PSK (pre-shared-keys) 事前共有鍵モード
- Key Share 公開鍵リスト (client_pub)
- セッショントークン
- 圧縮方式など...
SNI フィールドにより、サーバーは同じ ip グループで複数の TLS サービスを提供でき、ハンドシェイクプロセス中に SNI に基づいて対応する証明書を返します。
Key Share 拡張は、クライアントがサーバーが受け入れる可能性が高いと考える公開鍵と暗号アルゴリズムを 1 つ以上送信します。サーバーが受け入れる場合、Server Hello の後続データは暗号化されて送信されます。これは事前に Key Exchange が行われたことに相当します。サーバーが受け入れられない場合は、Retry Hello Request メッセージを返して再度ハンドシェイクを行います。
セッショントークンは接続が確立された後にサーバーから送信され、クライアントはこのデータを保存して後続の迅速な再接続に使用できます。
PSK の使用については When do clients use TLS in PSK mode? を参照してください。
サーバー:キーペアの生成#
記録 (server_priv, server_pub)
サーバー:プレーンテキストで Server Hello パケットを送信#
主に以下の内容を含みます:
- ランダム数 server_random
- 選択された暗号スイート
- 選択された公開鍵
- 選択されたプロトコルバージョン
- Key Share に (server_pub) を含む
- 圧縮方式など...
サーバー:ハンドシェイクキーの計算#
以下の情報を使用してハンドシェイクキーを計算します:
- client_pub は Client Hello パケットから取得
- server_priv はサーバーによって生成
- SHA384 (ClientHello + ServerHello) は以前に送信されたメッセージのハッシュ値を計算
以降のハンドシェイクプロセスはこのキーで暗号化されます。
クライアント:ハンドシェイクキーの計算#
以下の情報を使用してハンドシェイクキーを計算します:
- server_pub は Server Hello パケットから取得
- client_priv はクライアントによって生成
- SHA384 (ClientHello + ServerHello) は以前に送信されたメッセージのハッシュ値を計算
以降のハンドシェイクプロセスはこのキーで暗号化されます。
サーバー:暗号文で証明書を送信#
サーバーは Client Hello で指定された SNI に基づいて証明書を返し、検証を行います。
証明書の検証と発行#
- サーバーは自分のキーペア (host_priv, host_pub) を生成し、host_pub とドメイン情報などを組み合わせて host_info を CA (Certificate authority) に送信します。
- CA は申請者情報を審査し、独自の秘密鍵 CA_priv を使用して hash (host_info) を暗号化し、署名 SIG を取得します。最終的に SIG と host_info を組み合わせて証明書をサーバーに発行します。
- クライアントがサーバーから証明書を取得した後、ローカルにインストールされた CA 公開鍵を使用して署名 SIG を復号し、元のデータ CA_pub (SIG) を取得します。
- クライアントは証明書内の host_info を取り出し、hash (host_info) を計算して署名復号データと一致するか検証します。
信頼チェーン#
特定の状況下では、証明書は二次 CA によって発行されることがあります。クライアントが証明書を要求すると、サーバーは中間証明書と自分の証明書を一緒に返します:
- クライアントはまずローカルにインストールされた CA 公開鍵を使用して中間証明書を検証し、中間証明書の公開鍵を取得します。
- クライアントは次に中間証明書の公開鍵を使用してサーバー証明書の署名検証を行います。
サーバー:暗号文で証明書検証を送信#
前のステップを通じて、クライアントは証明書(その中の公開鍵を含む)が現在のリクエストのサービス名に属することを確認できますが、このサーバーがこの証明書の所有者であることを証明することはできません。したがって、サーバーは証明書発行前に作成された秘密鍵 host_priv を使用してハンドシェイクメッセージの要約を暗号化し、クライアントに返します。クライアントは証明書 host_info の公開鍵 host_pub を使用してこのデータを復号し、ハンドシェイクメッセージの要約を計算して一致するかどうかを比較します。これにより、クライアントはこの接続の安全性を確認できます。
サーバー:暗号文でハンドシェイク終了検証メッセージを送信#
サーバーはハンドシェイク段階のすべてのメッセージのハッシュを検証メッセージとしてクライアントに送信します。
サーバー:アプリケーションキーの計算#
サーバーはハンドシェイクキーと Client Hello からサーバーのハンドシェイク終了までのすべての情報のハッシュを取得してアプリケーションキーを計算します。これは後続のデータ転送段階の対称鍵です。
クライアント:アプリケーションキーの計算#
クライアントは同様の方法でアプリケーションキーを計算します。
クライアント:暗号文でハンドシェイク終了を送信#
クライアントはハンドシェイク段階のすべてのメッセージのハッシュを検証メッセージとしてサーバーに送信します。
これにより、クライアントとサーバー間でアプリケーションキーを使用して対称暗号通信が可能になります。
サーバー:暗号文でセッショントークン 1 を送信#
サーバーはクライアントにセッショントークンを提供し、後続の迅速な新しいセッションの開始を可能にし、セッション作成段階での計算とネットワーク遅延を大幅に削減します。これには以下が含まれます:
- トークンの有効期限
- トークンの年齢追加 (各トークンごとに個別)
- トークンのノンスランダム値 (各トークンごとに個別)
- セッショントークン
ここで Ticket Age Add
はサーバーによって生成されたランダムなミリ秒数であり、クライアントがセッショントークンを使用して接続を復元する際には、ticket_age(セッショントークンを受け取ってから現在までの時間差)にこの値を加えて混乱させる必要があります。サーバーはこの値を受け取った後、クライアントの ticket_age と自分で計算した時間差が近いかどうかを検証します。一定の閾値を超えた場合、この接続を拒否することができます。これにより、セッショントークンの再利用によるリプレイ攻撃をある程度防ぎます。
サーバー:暗号文でセッショントークン 2 を送信#
2 つ目のセッショントークンは、クライアント(例えばブラウザ)が一般的に複数の接続を送信するため、各セッショントークンは一度だけ使用できるため、サーバーは通常複数のセッショントークンを返します。
参考資料:
RFC8446
xargs.org - TLS
xargs.org - x25519
Wikipedia - Shared_secret
Wikipedia - Pre-shared_key
Wikipedia - SNI
A walkthrough of a TLS 1.3 handshake
一文详解 HTTPS 与 TLS 证书链校验
SSL/TLS 协议详解 (中)—— 证书颁发机构
网络安全科普:奇妙的 SSL/TLS 证书(基础篇)