XversePro 知识库 · 网络
TLS 1.3 把完整握手压到一个来回,ServerHello 之后的握手消息全部加密。
结论:TLS 1.3 的完整握手只要一个来回(1-RTT)。客户端在第一条消息里就猜好密钥交换参数,服务器一次回完所有握手消息,客户端收到后就能发业务数据。
ServerHello 之后的握手消息全部加密,证书也不再明文传输。TLS 1.3 由 RFC 8446 定义,2018 年 8 月发布。
客户端先发 ClientHello,意思是打招呼并报上自己支持的算法。关键在 key_share 扩展:客户端直接附上自己这一半的临时密钥交换公钥,不等服务器先选。
服务器选好算法,回 ServerHello,也附上自己那一半公钥。双方此时已能算出同一份握手密钥。服务器紧接着用这份密钥加密发出 EncryptedExtensions、Certificate、CertificateVerify 和 Finished。
客户端验证证书和 Finished 后,发出自己的 Finished,同时就可以带上业务数据。消息顺序见 RFC 8446 第 2 节图 1。
TLS 1.2 由 RFC 5246 定义。按它第 7.3 节图 1 的消息顺序,完整握手要两个来回:第一轮协商算法并拿到证书,第二轮交换密钥材料并互发 Finished,之后才能传业务数据。
TLS 1.3 能省掉一轮,是因为它删掉了大量可选算法。不用 PSK 时,密钥交换只剩临时的 (EC)DHE,也就是每次连接现生成一对密钥的 Diffie-Hellman 交换。可选项少了,客户端就能先猜一组参数,第一条消息直接带上公钥。RFC 8446 第 1.2 节列出了主要变化,下表摘了几条。
| 项目 | TLS 1.2 | TLS 1.3 |
|---|---|---|
| 完整握手来回数 | 2 个 | 1 个 |
| 证书是否加密 | 明文 | ServerHello 之后全部加密 |
| 静态 RSA 密钥交换 | 支持 | 删除,所有公钥交换都有前向保密 |
| 对称加密算法 | 多种,含旧算法 | 只留 AEAD 算法 |
| 版本协商 | ClientHello 的版本字段 | supported_versions 扩展里的列表 |
| 会话恢复 | session ID 和 session ticket | 统一换成 PSK |
表 1 依据 RFC 8446 第 1.2 节和第 2 节。前向保密的含义见 Wikipedia: Forward secrecy:服务器长期私钥日后泄露,以前录下的会话也解不开。
RFC 8446 把握手分成三段。密钥交换阶段确定共享密钥和算法,这之后的一切都加密。服务器参数阶段交代其他握手参数,比如是否要求客户端证书。认证阶段用证书证明服务器身份,并用 Finished 确认整段握手没被篡改。
Finished 里是一段消息认证码(MAC,用密钥对内容算出的校验值),覆盖此前的全部握手消息。中间人改动任何一条,Finished 都对不上。
为兼容老设备,ClientHello 的 legacy_version 字段仍然写 0x0303,也就是 TLS 1.2 的编号。真正的版本放在 supported_versions 扩展里,TLS 1.3 是 0x0304。
客户端提前带上的 key_share 可能不合服务器的意,比如用了服务器不支持的曲线。这时服务器回 HelloRetryRequest,告诉客户端该用哪一组参数,客户端重发 ClientHello。
这样多了一个来回,完整握手变成两个来回,流程见 RFC 8446 第 2.1 节图 2。双方找不到共同参数时,服务器必须以告警中止握手。
握手完成后,服务器可以发一张 NewSessionTicket,给客户端一个 PSK(预共享密钥)的标识。下次连接时客户端出示它,就能跳过证书验证,这叫会话恢复,见 RFC 8446 第 2.2 节。
更进一步,客户端可以用这个 PSK 在第一条消息里直接带上业务数据,叫 0-RTT 或 early data。代价写在第 2.3 节:这部分数据没有前向保密,而且不能防止跨连接重放,攻击者录下后可以再发一遍。所以 0-RTT 只适合重复执行也无害的请求,防重放的做法见第 8 节。