このページの目次

TLS 1.3 ハンドシェイク

TLS 1.3 はハンドシェイクを 1-RTT、0-RTT、さらにはゼロラウンドトリップに圧縮します。その手段は、静的 RSA の削除、前方秘匿性の強制、鍵合意を ClientHello へ前倒しすることです。潔いプロトコル設計ですが、その代償として 0-RTT はリプレイ保護を失います。

概要

TLS 1.3 (RFC 8446, 2018) は TLS 1.2 に対する最大のリビジョンであり、その核心となる手法は一言で表せます。⁠クライアントは「サーバーは何を使いたいか」と問いかけるのではなく、直接推測する⁠——ClientHello 内で ECDHE 公開鍵 (key_share) を送り、サーバーが x25519 をサポートしていることを賭けます(ほぼ必ず当たります)。その結果、TLS 1.2 で見られた「アルゴリズムの合意 → 鍵の交換」という 2 ラウンドの往復は 1 ラウンドに収縮し、セッションチケットがある場合はゼロラウンドトリップ (0-RTT) すら可能です。

設計目標は以下の 4 点です。

  1. ハンドシェイクのラウンドトリップ削減⁠: 2-RTT → 1-RTT (初回)、0-RTT (再接続)
  2. 安全でないアルゴリズムの削除⁠: 静的 RSA 鍵交換、CBC、RC4、MD5/SHA-1——過去に問題を起こしたものはすべて排除
  3. ハンドシェイクメッセージの暗号化範囲拡大⁠: ServerHello 以降はすべて暗号化され、傍受者でも証明書を見ることができません
  4. 簡素化⁠: 約 100 個あった暗号スイートを 5 個に削減

TLS 1.2 との主な違いを以下の表で確認できます。

TLS 1.2TLS 1.3
初回ハンドシェイク2-RTT1-RTT
セッション再開session ID / ticket, 1-RTTPSK, 0-RTT
鍵交換RSA または (EC)DHE(EC)DHE のみ → 前方秘匿性の強制
ハンドシェイクの暗号化全明文ServerHello 以降は完全暗号化
暗号スイート~100 個 (鍵交換 + 署名を含む)5 個 (AEAD + ハッシュのみ)
鍵導出PRFHKDF

1-RTT 完全ハンドシェイクフロー

sequenceDiagram
    participant C as Client
    participant S as Server
    C->>S: ClientHello<br>key_share(x25519 公開鍵), cipher_suites,<br>supported_groups, signature_algorithms
    Note over S: 共有鍵を算出可能<br>→ 以降のメッセージはすべて暗号化
    S->>C: ServerHello (key_share)<br>🔒 EncryptedExtensions<br>🔒 Certificate + CertificateVerify<br>🔒 Finished
    Note over C: 証明書と署名を検証し、<br>同じ鍵を算出
    C->>S: 🔒 Finished + アプリケーションデータ
    Note over C,S: 最初の RTT 終了時点でデータは進行中<br>(TLS 1.2 では 2 RTT 必要)

このフローには 3 つの設計上のポイントが隠されています。

key_share: 鍵合意の前倒し⁠。クライアントは複数の楕円曲線に対してそれぞれ ECDHE 公開鍵 (x25519 は 32 バイト、secp256r1 は 65 バイト) を付与し、サーバーは曲線を選択して自身の公開鍵を返信します——これにより、双方は最初の往復内で Diffie-Hellman を完了します。もし外れた場合はどうなるでしょうか?サーバーは HelloRetryRequest を返し曲線を指定し、クライアントは ClientHello を再送します。これにより 2-RTT に後退しますが、実運用ではほぼ発生しません。

認証と機密性の分離⁠。TLS 1.2 の静的 RSA では、2 つのことが結びついていました。サーバーの秘密鍵は身元証明としても、鍵の復号にも使われていたのです。秘密鍵が漏洩すると、過去に録画されたすべてのトラフィックを復号して読み取られてしまいます。TLS 1.3 では、鍵は毎回新規の ECDHE から生成されるため (⁠前方秘匿性⁠)、証明書秘密鍵は単一の役割、つまりハンドシェイクレコードへの署名 (CertificateVerify) を行い、「私がこのドメインの正当な所有者であること」を証明します。

暗号スイートは AEAD + ハッシュの組み合わせのみ⁠:

Suite用途
TLS_AES_128_GCM_SHA256デフォルトの主力
TLS_AES_256_GCM_SHA384より高いセキュリティマージン
TLS_CHACHA20_POLY1305_SHA256AES ハードウェアアクセラレーションがないモバイル向け
TLS_AES_128_CCM_SHA256 / CCM_8IoT 制約付きデバイス向け

鍵導出: HKDF

TLS 1.3 では PRF の代わりに HKDF を使用し、鍵の連鎖は 3 段階の「鍵の階段」となります。

Early Secret     = HKDF-Extract(salt=0, PSK または 0)          ← 0-RTT 鍵はこの層から派生
Handshake Secret = HKDF-Extract(Early Secret, ECDHE 共有鍵) ← ハンドシェイク暗号化鍵
Master Secret    = HKDF-Extract(Handshake Secret, 0)        ← アプリケーションデータ鍵

各 Expand 処理では、⁠トランスクリプトハッシュ⁠(これまでに送受信されたすべてのハンドシェイクメッセージのハッシュ)が混入されます。そのため、たとえ 2 回のハンドシェイクで同じ PSK を使用しても、メッセージのバイトが 1 つでも異なれば、派生される鍵は完全に異なります。これがハンドシェイクの改ざん防止の根拠です。メッセージのいずれかを変更すると、双方が計算する Finished チェックサムは一致しなくなります。

0-RTT PSK: 再接続時のゼロラウンドトリップ

初回ハンドシェイク後、サーバーはセッションチケット (本質的には PSK) を発行します。再接続時、クライアントは ClientHello 内で PSK 識別子と binder を付与し、⁠同じパケット内に暗号化されたアプリケーションデータ (early data) を直接添付します。サーバーは PSK を検証するとすぐに処理を開始し、1 ラウンドの待ち時間すら不要です。

その代償として安全性が低下するため、以下の 3 点を明確に理解する必要があります。

  • リプレイ攻撃⁠: 攻撃者がキャプチャした 0-RTT パケットをそのまま再送すると、サーバーは early data を再度処理してしまいます。プロトコルレベルでの完全な防御はありません。アプリケーション層で自己防衛する必要があります——0-RTT には冪等な操作のみを含める (HTTP の GET/HEAD など) ことが求められ、これが主要 CDN の実装方針となっています。
  • 前方秘匿性の欠如⁠: early data の鍵は PSK のみから派生されるため、PSK が漏洩すると過去のすべての 0-RTT データを復号可能になります (1-RTT 部分は新しい ECDHE が混入されているため影響を受けません)。
  • サーバーは max_early_data_size を使用して暴露範囲を制限するか、early data を拒否して 1-RTT へのフォールバックを強制することができます。

Encrypted ClientHello (ECH)

TLS 1.3 に残された最後の平文部分、それが ClientHello 本身です。其中的 SNI (ターゲットドメイン) により、中間デバイスがドメイン名に基づいて審査やブロックを依然として行えます。ECH (ESNI の後継、RFC ドラフト) はこの穴を埋めます。

  1. サーバーは DNS の HTTPS レコード (type 65) に ECH 公開鍵を公開します。
  2. クライアントは、実際の ClientHello (実際の SNI 含む) を内側として暗号化し、外側にはカモフラージュ用のドメイン (例: cloudflare-ech.com) を使用します。
  3. ECH 秘密鍵を持つサーバーのみが内側を解読可能であり、パス上の観測者はカモフラージュドメインしか見えません。

DoH/DoT (DNS クエリ自体も暗号化されます。DNS プライバシー を参照) と組み合わせることで、「ユーザーがどのサイトにアクセスしたか」というメタデータを完全に隠蔽できます。

関連

TLS 1.2 の完全なハンドシェイクとその歴史的な負債については TLS 1.2 ハンドシェイク を参照してください。証明書チェーンの検証方法については 証明書と PKI を参照してください。QUIC は TLS 1.3 をトランスポート層に直接組み込んでおり、HTTP/3 を参照してください。

参考

  • RFC: 8446 (Appendix D に 0-RTT のセキュリティ分析あり)
  • ECH: draft-ietf-tls-esni
  • ツール⁠: openssl s_client -tls1_3 -connect host:443 · Wireshark フィルタ tls.handshake.type
  • 可視化⁠: tls13.xargs.org (TLS 1.3 ハンドシェイクをバイト単位で図解、非常に優れている)

Keywords: TLS 1.3, TLS1.3 ハンドシェイクフロー, 1-RTT, key_share, ECDHE, 前方秘匿性, forward secrecy, 0-RTT, PSK, リプレイ攻撃, セッションチケット, HKDF, トランスクリプトハッシュ, ECH, SNI, 暗号スイート, TLS1.2 違い