本页目录

TLS 1.2 握手

TLS 1.2 的握手:ClientHello→ServerHello→Certificate→KeyExchange→Finished,两次往返完成密钥协商。理解每步的密码学操作(RSA vs ECDHE、签名 vs 密钥交换),是理解 TLS 1.3 为什么能减到 1-RTT 的前提。

概述

TLS(Transport Layer Security)是互联网安全通信的基础,2008 年由 RFC 5246 定义。它解决了三个问题:身份认证(server 是谁)、机密性(数据被加密)和完整性(数据未被篡改)。TLS 1.2 握手是最广泛部署的版本——2-RTT 建立安全通道,使用 ECDHE 保证前向安全,SNI 使多域名共享一个 IP。本文逐帧解析握手过程、密钥派生和会话恢复机制。

Full Handshake (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/>派生 session keys

    S->>C: ④ [ChangeCipherSpec]<br/>Finished

    Note over C,S: ✅ 安全通道建立<br/>应用数据加密传输

    C->>S: Application Data (encrypted)
    S->>C: Application Data (encrypted)

* = optional (取决于 cipher suite 和 server 配置)

ClientHello

struct {
    ProtocolVersion client_version;     // {3,3} = TLS 1.2
    Random random;                      // 32B: gmt_unix_time(4) + random_bytes(28)
    SessionID session_id;               // ≤32B (for resumption) or empty
    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, ...
}

关键 Extensions:

server_name (SNI): 要访问的域名 — server 选正确证书 (一个 IP 上多证书)
supported_groups: 客户端支持的 EC curves (secp256r1, x25519, ...)
ec_point_formats: uncompressed (唯一值, 实际无用)
signature_algorithms: 客户端支持的签名算法 (RSA-PKCS1-SHA256, ECDSA-SHA256, ...)
ALPN: 应用层协议列表 ("h2", "http/1.1") — server 选一个
Extended Master Secret: 防止 Triple Handshake 攻击
SessionTicket TLS: 支持 session ticket (无状态 resumption)

Cipher Suite 格式

Cipher Suite 拆解:套件名 = 四段密码学参数 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ECDHE 密钥交换算法 Elliptic Curve Diffie-Hellman Ephemeral RSA 服务器认证 证书中的公钥类型 — RSA signing AES_128_GCM 对称加密 AES-128-GCM AEAD SHA256 PRF Pseudo-Random Function,密钥派生 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 ECDHE 密钥交换 ECDSA 服务器认证 EC 证书 CHACHA20_POLY1305 对称加密 ChaCha20-Poly1305 AEAD SHA256 PRF 套件名的四段可独立组合:密钥交换算法定前向安全性,认证算法定证书类型, 对称加密定数据加密方式,PRF(TLS 1.2 固定用 SHA256)负责密钥派生。

密钥派生

1. 从 DH key exchange: pre_master_secret (服务器/客户端共同计算)
2. master_secret = PRF(pre_master_secret, "master secret",
                        ClientHello.random + ServerHello.random)[0..47]

3. 从 master_secret: 6 个 session key
   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 message = PRF(master_secret, "client finished",
                           hash(all handshake messages))[0..11]
   → 保证 handshake 未被篡改

Session Resumption

Session ID (有状态, RFC 5246):
  1. 首次 full handshake → ServerHello.session_id = <random ID>
  2. Server 缓存: session_id → master_secret + cipher_suite
  3. 重连: ClientHello.session_id = <cached ID>
     → Server 找到 session → 跳过 Certificate + ServerKeyExchange
     → 1-RTT

Session Ticket (无状态, RFC 5077):
  1. Server: 把 (master_secret + cipher_suite + ticket_lifetime)
     加密 (用 server 的 ticket key) → 发给 client → SessionTicket extension
  2. 重连: ClientHello.session_ticket = <encrypted blob>
     → Server 解密 ticket → 恢复 session → 1-RTT
     → Server 不需要存 session state (cipher from ticket)

  安全: ticket key 必须保密 + 定期轮换 (ticket 泄露 → 历史 session 泄露)

参考

  • RFC: 5246, 6066, 7301, 5077, 7627 (Extended Master Secret)
  • 工具⁠: openssl s_client -connect host:443 -tls1_2, Wireshark ssl.handshake

Keywords: TLS 1.2, ECDHE, cipher suite, session resumption, session ticket, SNI, ALPN, PRF