bigywater.tech
网络协议 · 90

TLS 1.3 握手:一个往返里发生了什么

TLS 1.3 把握手压缩到了一个往返,证书也不再明文。但它的 ClientHello 里藏着什么、服务器怎么回应、后量子密钥交换为什么让第一个包变成 1529 字节?这篇抓包后手工解析 TLS 记录和握手消息的每个字段,并和 TLS 1.2 对比。

1529 字节
Python 的 ClientHello 记录大小,其中 key_share 有 X25519MLKEM768 的 1216 字节公钥
164 vs 325 ms
TLS 1.3 与 TLS 1.2 握手耗时的中位数(example.com,各 4 次)
4420 字节
ServerHello 之后服务器发的加密记录合计,包含证书

ClientHello

实测 · 本机执行输出
  这次连接协商的结果(Python ssl 告诉的):TLSv1.3,TLS_AES_256_GCM_SHA384,ALPN h2;TCP 握手 158 ms,TLS 握手 352 ms
  第一条记录:类型 Handshake,记录层版本 0x0301(旧版本号,为兼容中间设备),长度 1529 字节;握手消息类型 1(1 = ClientHello),长度 1525 字节
  ClientHello 里的版本字段 0x0303(= TLS 1.2,同样为兼容;真正的版本在 supported_versions 扩展里);session_id 长度 32(TLS 1.3 的兼容模式下是 32 字节随机数)
  提供的密码套件(17 个):['TLS_AES_256_GCM_SHA384', 'TLS_CHACHA20_POLY1305_SHA256', 'TLS_AES_128_GCM_SHA256', 'ECDHE_ECDSA_AES256_GCM', 'ECDHE_RSA_AES256_GCM', 'ECDHE_ECDSA_AES128_GCM', 'ECDHE_RSA_AES128_GCM', 'ECDHE_ECDSA_CHACHA20', 'ECDHE_RSA_CHACHA20', '0xc024', '0xc028', '0xc023', '0xc027', '0x9f', '0x9e', '0x6b', '0x67']
  扩展(12 个):renegotiation_info, server_name, ec_point_formats, supported_groups, session_ticket, ALPN, encrypt_then_mac, extended_master_secret, signature_algorithms, supported_versions, psk_key_exchange_modes, key_share
    server_name        example.com
    supported_groups   ['X25519MLKEM768', 'x25519', 'secp256r1', 'x448', 'secp384r1', 'secp521r1', 'ffdhe2048', 'ffdhe3072']
    ALPN               ['h2', 'http/1.1']
    signature_algorithms 26 种签名算法
    supported_versions ['0x304', '0x303']
    psk_key_exchange_modes [1]
    key_share          ['X25519MLKEM768(1216 字节公钥)', 'x25519(32 字节公钥)']

明文,包含 SNI、密码套件、支持的组、ALPN 和已经算好的 key_share 公钥。

ServerHello

实测 · 本机执行输出
  ServerHello 记录 1210 字节:选了密码套件 TLS_AES_256_GCM_SHA384;扩展 key_share, supported_versions
    key_share 选定的组 X25519MLKEM768,服务器的公钥 1120 字节(客户端用自己的私钥 + 这个公钥算出共享密钥)
    supported_versions 选定 0x0304(0x0304 = TLS 1.3)
  服务器→客户端 的全部 TLS 记录(顺序、类型、长度):
    Handshake          版本 0x0303  长度  1210
    ChangeCipherSpec   版本 0x0303  长度     1
    ApplicationData    版本 0x0303  长度  3852
    ApplicationData    版本 0x0303  长度   477
    ApplicationData    版本 0x0303  长度    57
    ApplicationData    版本 0x0303  长度    34
  客户端→服务器 的全部 TLS 记录:Handshake 1529 字节; ChangeCipherSpec 1 字节; ApplicationData 69 字节; ApplicationData 73 字节
  服务器的 ServerHello 之后:1 个 ChangeCipherSpec(兼容用,内容是 1 个字节的 01)、4 个加密记录,合计 4420 字节——里面是 EncryptedExtensions、Certificate、CertificateVerify、Finished(以及之后的应用数据)

选定套件和密钥交换组(X25519MLKEM768),此后全部加密。

往返数

实测 · 本机执行输出
    相对时间(ms)  方向  载荷字节
           0.0   C→S     1388
           0.0   C→S      146
         155.7   S→C     1440
         155.7   S→C     1440
         156.1   S→C      758
         349.2   S→C     1440
         351.5   C→S       80
         502.9   S→C      544
         503.0   C→S       78
         659.6   S→C       39
  ClientHello(+0 ms)→ 服务器回 ServerHello 等(+156 ms)= 1 个往返 156 ms;客户端随后发出 Finished(+351 ms),这时客户端已经可以同时发应用数据
  Python 量到的 TLS 握手总计 352 ms ≈ 1 个往返(156 ms)加上本机计算

正常 1 个往返;这次抓包里有一个段晚到 193 ms,握手 352 ms 是离群样本。

对比 TLS 1.2

实测 · 本机执行输出
  TLS 1.3 握手耗时(ms):[164, 164, 184, 156],中位 164
  TLS 1.2 握手耗时(ms):[310, 322, 415, 328],中位 325;协商结果 TLSv1.2,ECDHE-ECDSA-AES128-GCM-SHA256
  TLS 1.2 握手里服务器→客户端的记录:Handshake 76 字节; Handshake 3677 字节; Handshake 115 字节; Handshake 4 字节; Handshake 202 字节; ChangeCipherSpec 1 字节(这里 Certificate 是明文的,可以直接被路径上的设备读到)
  TLS 1.2 服务器发出的握手消息类型:['ServerHello', 'Certificate', 'ServerKeyExchange', 'ServerHelloDone', 'NewSessionTicket', 0]

多一个往返,Certificate 明文可读。

分步演示

TLS 1.3 握手
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64(Apple 芯片)/ Python 3.14.8 / tcpdump(libpcap)/ scapy 2.8 / dpkt / dnspython / h2 / aioquic / OpenSSL / curl 8.7.1;抓包在 lo0(环回)上做,少数实验用真实网卡 en0(这台机器上 en0 是 Wi-Fi,tcpdump 看到的是系统转成以太网格式的帧,所以文中的“以太网头”都指这个 14 字节的头)或访问公网(会在文章里注明);需要丢包 / 延迟 / 限速时,用一个只作用于 lo0 端口 9400-9499 的 dummynet 辅助脚本(netlab);所有服务端都是本机自己起的进程;时间戳取自 tcpdump 的 -tt,数字每次运行会有小幅抖动。对 example.com:443 的真实 TLS 握手,en0 抓包后手工解析记录与握手消息(没有用任何 TLS 解析库);ClientHello 内容取决于本机 Python 3.14 / OpenSSL 的默认设置;第三节抓的那一次握手有一个离群样本
    • 没有验证:密钥派生(HKDF、握手密钥与应用密钥)的计算;解密 Certificate 等加密记录(需要密钥日志,没有做);HelloRetryRequest;ECH(加密 ClientHello);PSK 恢复(下面有一篇讲会话恢复);其它 TLS 实现(Go、Rust、浏览器)的 ClientHello 差异;X25519MLKEM768 的计算开销
    京ICP备2026067502号-1京公网安备11010502063487号