← 首页

XversePro 知识库 · 网络

TLS 1.3 握手过程

TLS 1.3 把完整握手压到一个来回,ServerHello 之后的握手消息全部加密。

结论:TLS 1.3 的完整握手只要一个来回(1-RTT)。客户端在第一条消息里就猜好密钥交换参数,服务器一次回完所有握手消息,客户端收到后就能发业务数据。

ServerHello 之后的握手消息全部加密,证书也不再明文传输。TLS 1.3 由 RFC 8446 定义,2018 年 8 月发布。

1. 完整握手:一个来回

客户端先发 ClientHello,意思是打招呼并报上自己支持的算法。关键在 key_share 扩展:客户端直接附上自己这一半的临时密钥交换公钥,不等服务器先选。

服务器选好算法,回 ServerHello,也附上自己那一半公钥。双方此时已能算出同一份握手密钥。服务器紧接着用这份密钥加密发出 EncryptedExtensions、Certificate、CertificateVerify 和 Finished。

客户端验证证书和 Finished 后,发出自己的 Finished,同时就可以带上业务数据。消息顺序见 RFC 8446 第 2 节图 1。

客户端服务器 ClientHello + key_share + supported_versions ServerHello + key_share {EncryptedExtensions}{Certificate}{CertificateVerify}{Finished} {Finished} [Application Data] 1-RTT 灰色:明文。蓝色 { }:握手密钥加密。绿色 [ ]:应用密钥加密。 省略了可选的 CertificateRequest 和客户端证书。
图 1 TLS 1.3 完整握手(示意,依据 RFC 8446 图 1 简化)。红线标出的就是那一个来回。

2. 和 TLS 1.2 比,省在哪里

TLS 1.2 由 RFC 5246 定义。按它第 7.3 节图 1 的消息顺序,完整握手要两个来回:第一轮协商算法并拿到证书,第二轮交换密钥材料并互发 Finished,之后才能传业务数据。

TLS 1.3 能省掉一轮,是因为它删掉了大量可选算法。不用 PSK 时,密钥交换只剩临时的 (EC)DHE,也就是每次连接现生成一对密钥的 Diffie-Hellman 交换。可选项少了,客户端就能先猜一组参数,第一条消息直接带上公钥。RFC 8446 第 1.2 节列出了主要变化,下表摘了几条。

项目TLS 1.2TLS 1.3
完整握手来回数2 个1 个
证书是否加密明文ServerHello 之后全部加密
静态 RSA 密钥交换支持删除,所有公钥交换都有前向保密
对称加密算法多种,含旧算法只留 AEAD 算法
版本协商ClientHello 的版本字段supported_versions 扩展里的列表
会话恢复session ID 和 session ticket统一换成 PSK

表 1 依据 RFC 8446 第 1.2 节和第 2 节。前向保密的含义见 Wikipedia: Forward secrecy:服务器长期私钥日后泄露,以前录下的会话也解不开。

3. 握手的三个阶段和各自的密钥

RFC 8446 把握手分成三段。密钥交换阶段确定共享密钥和算法,这之后的一切都加密。服务器参数阶段交代其他握手参数,比如是否要求客户端证书。认证阶段用证书证明服务器身份,并用 Finished 确认整段握手没被篡改。

Finished 里是一段消息认证码(MAC,用密钥对内容算出的校验值),覆盖此前的全部握手消息。中间人改动任何一条,Finished 都对不上。

为兼容老设备,ClientHello 的 legacy_version 字段仍然写 0x0303,也就是 TLS 1.2 的编号。真正的版本放在 supported_versions 扩展里,TLS 1.3 是 0x0304。

密钥交换明文 ClientHello, ServerHello交换 key_share,算出握手密钥 服务器参数握手密钥 { } EncryptedExtensions, CertificateRequest*原先明文的扩展挪到这里加密发送 认证握手密钥 { } Certificate, CertificateVerify, Finished证明身份,校验整段握手 应用数据 应用密钥 [ ],由 HKDF 从握手结果派生
图 2 三个阶段与各自使用的密钥(示意)。HKDF 是一种从一份共享秘密派生出多把密钥的标准函数。

4. 猜错了怎么办:HelloRetryRequest

客户端提前带上的 key_share 可能不合服务器的意,比如用了服务器不支持的曲线。这时服务器回 HelloRetryRequest,告诉客户端该用哪一组参数,客户端重发 ClientHello。

这样多了一个来回,完整握手变成两个来回,流程见 RFC 8446 第 2.1 节图 2。双方找不到共同参数时,服务器必须以告警中止握手。

客户端服务器 ClientHello + key_share(猜错) HelloRetryRequest + key_share ClientHello + key_share(按要求重发) ServerHello … {Finished} 第 1 轮 第 2 轮 之后客户端发 {Finished},与图 1 相同
图 3 参数不匹配时的握手,多出一个来回(示意,依据 RFC 8446 图 2 简化)。

5. 会话恢复与 0-RTT

握手完成后,服务器可以发一张 NewSessionTicket,给客户端一个 PSK(预共享密钥)的标识。下次连接时客户端出示它,就能跳过证书验证,这叫会话恢复,见 RFC 8446 第 2.2 节。

更进一步,客户端可以用这个 PSK 在第一条消息里直接带上业务数据,叫 0-RTT 或 early data。代价写在第 2.3 节:这部分数据没有前向保密,而且不能防止跨连接重放,攻击者录下后可以再发一遍。所以 0-RTT 只适合重复执行也无害的请求,防重放的做法见第 8 节。

客户端服务器 ClientHello + early_data + pre_shared_key (Application Data) ServerHello … {Finished} (EndOfEarlyData) {Finished} 红色这条随第一条消息发出,但可能被重放
图 4 0-RTT 握手(示意,依据 RFC 8446 图 4 简化)。圆括号表示用早期密钥加密。

参考资料

  1. 《RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3》(2018 年 8 月) https://www.rfc-editor.org/rfc/rfc8446.html
  2. 《RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2》(2008 年 8 月) https://www.rfc-editor.org/rfc/rfc5246.html
  3. 《Forward secrecy》,Wikipedia https://en.wikipedia.org/wiki/Forward_secrecy