TLS 1.3 把握手压缩到了一个往返,证书也不再明文。但它的 ClientHello 里藏着什么、服务器怎么回应、后量子密钥交换为什么让第一个包变成 1529 字节?这篇抓包后手工解析 TLS 记录和握手消息的每个字段,并和 TLS 1.2 对比。
这次连接协商的结果(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 记录 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.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 明文可读。