TLS 1.3 握手过程的一点笔记

2026-09-30

排障的时候经常要看握手,索性把过程记一遍,下次不用再翻文档。

TLS 1.3 把完整的握手压缩到了一次往返。客户端发出 ClientHello,里面带上支持的密钥交换组、签名算法、SNI 和一串 key_share(通常是 x25519,有时还有 secp256r1)。服务端如果认这个组,就直接用自己的临时私钥算出共享密钥,在 ServerHello 里给出自己的 key_share,之后的所有握手消息都已经加密了。

所以抓包时能看到的是:ClientHello 明文,ServerHello 的后半段开始就只能看到 encrypted extensions 了。证书、CertificateVerify、Finished 全在加密的 flight 里。

看协商结果的办法

openssl s_client -connect example.com:443 \
  -servername example.com -tls1_3 </dev/null \
  | grep -E "Protocol|Cipher|Server Temp Key|Verify return code"

几个常见字段的解释:

  • Server Temp Key: X25519, 253 bits —— 说明用的是 x25519 临时密钥交换;
  • Cipher: TLS_AES_256_GCM_SHA384 —— 1.3 的 cipher suite 只描述 AEAD 和 HKDF,不再描述密钥交换;
  • Verify return code: 0 (ok) —— 证书链校验通过,注意这只校验链,不校验域名。

要强制某个组

可以用 -groups 指定,验证服务端是否真的支持:

openssl s_client -connect example.com:443 -tls1_3 -groups X25519

如果服务端不支持这个组,会直接握手失败,返回 no shared cipher 或者 handshake failure。这个办法在挑选对端、确认配置有没有生效时挺有用。

顺带一提,1.3 里会话恢复用的是 PSK 票据,和服务端会话缓存不是一回事。看到 Reused 字样不代表配置就一定对。

OCSP Stapling 还值得开吗

Let's Encrypt 在 2025 年已经停止签发带 OCSP 地址的证书了,所以新证书的 stapling 基本是空转。老证书(2025 年之前签发的)在有效期内还能用一阵,之后这块配置就可以从 nginx 里删掉了。