このページの目次
TLS 1.2 ハンドシェイク
TLS 1.2 のハンドシェイク: ClientHello→ServerHello→Certificate→KeyExchange→Finished。2ラウンドトリップで鍵合意を完了します。各ステップの暗号学的操作(RSA vs ECDHE、署名 vs 鍵交換)を理解することは、TLS 1.3 がなぜ 1-RTT に削減できたのかを理解するための前提条件です。
概要
TLS(Transport Layer Security)はインターネットの安全な通信の基盤であり、2008年に RFC 5246 で定義されました。これは3つの問題を解決します:認証(サーバーは誰か)、機密性(データは暗号化される)、完全性(データは改ざんされていない)。TLS 1.2 のハンドシェイクは最も広くデプロイされているバージョンです。2-RTT で安全なチャネルを確立し、ECDHE を使用して前方秘匿性を保証し、SNI により複数のドメインが1つのIPアドレスを共有することを可能にします。本稿では、ハンドシェイクのプロセス、鍵導出、およびセッション再開メカニズムをフレームごとに解析します。
フルハンドシェイク (2-RTT)
sequenceDiagram
participant C as Client
participant S as Server
Note over C,S: ═══ RTT 1 ═══
C->>S: ① ClientHello<br/>version + random + cipher_suites<br/>+ extensions (SNI, ALPN, supported_groups)
S->>C: ② ServerHello + Certificate*<br/>+ ServerKeyExchange*<br/>+ CertificateRequest*<br/>+ ServerHelloDone
Note over C: 証明書チェーンの検証<br/>pre_master_secret の計算
Note over C,S: ═══ RTT 2 ═══
C->>S: ③ Certificate*<br/>ClientKeyExchange<br/>CertificateVerify*<br/>[ChangeCipherSpec]<br/>Finished
Note over S: pre_master_secret の復号<br/>セッション鍵の導出
S->>C: ④ [ChangeCipherSpec]<br/>Finished
Note over C,S: ✅ 安全チャネルの確立<br/>アプリケーションデータの暗号化転送
C->>S: Application Data (encrypted)
S->>C: Application Data (encrypted)
* = オプション(cipher suite およびサーバー設定による)
ClientHello
struct {
ProtocolVersion client_version; // {3,3} = TLS 1.2
Random random; // 32B: gmt_unix_time(4) + random_bytes(28)
SessionID session_id; // ≤32B (再開用) または空
CipherSuite cipher_suites<2..2^16-2>; // クライアントがサポートするリスト、優先度順
CompressionMethod compression_methods; // {0} = null (TLS 1.2 では null が必須)
Extension extensions<0..2^16-1>; // SNI, ALPN, supported_groups, signature_algorithms, ...
}
主要な拡張機能:
server_name (SNI): アクセスするドメイン名 — サーバーが正しい証明書を選択(1つのIP上で複数の証明書)
supported_groups: クライアントがサポートするEC曲線 (secp256r1, x25519, ...)
ec_point_formats: uncompressed (唯一の値、実際には無意味)
signature_algorithms: クライアントがサポートする署名アルゴリズム (RSA-PKCS1-SHA256, ECDSA-SHA256, ...)
ALPN: アプリケーション層プロトコルのリスト ("h2", "http/1.1") — サーバーが1つを選択
Extended Master Secret: 三重ハンドシェイク攻撃の防止
SessionTicket TLS: セッションチケットのサポート(ステートレスな再開)
Cipher Suite の形式
鍵導出
1. DH 鍵交換から: pre_master_secret(サーバー/クライアントが共同で計算)
2. master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)[0..47]
3. master_secret から: 6つのセッション鍵
key_block = PRF(master_secret, "key expansion",
ServerHello.random + ClientHello.random)
→ client_write_MAC_key, server_write_MAC_key,
client_write_key, server_write_key,
client_write_IV, server_write_IV
4. Finished メッセージ = PRF(master_secret, "client finished",
hash(all handshake messages))[0..11]
→ ハンドシェイクが改ざんされていないことを保証
セッション再開
Session ID(ステートフル, RFC 5246):
1. 初回フルハンドシェイク → ServerHello.session_id = <ランダムID>
2. サーバーがキャッシュ: session_id → master_secret + cipher_suite
3.再接続: ClientHello.session_id = <キャッシュされたID>
→ サーバーがセッションを検索 → Certificate + ServerKeyExchange をスキップ
→ 1-RTT
Session Ticket(ステートレス, RFC 5077):
1. サーバー: (master_secret + cipher_suite + ticket_lifetime) を
暗号化(サーバーの ticket key を使用)→ クライアントに送信 → SessionTicket 拡張
2. 再接続: ClientHello.session_ticket = <暗号化されたブロブ>
→ サーバーが ticket を復号 → セッションを復元 → 1-RTT
→ サーバーはセッション状態を保存する必要がない(ticket から暗号スイートを取得)
安全性: ticket key は機密保持が必要 + 定期的にローテーション(ticket が漏洩すると、過去のセッションが漏洩する)
参考文献
- RFC: 5246, 6066, 7301, 5077, 7627 (Extended Master Secret)
- ツール:
openssl s_client -connect host:443 -tls1_2, Wiresharkssl.handshake
キーワード: TLS 1.2, ECDHE, cipher suite, session resumption, session ticket, SNI, ALPN, PRF