TLS握手
本篇详细从理论与实践角度,解析TLS 1.2握手流程,并没有涉及TLS 1.3的内容。
1、TLS握手流程
不同版本的TLS由不同文档定义,其关系如下:
TLS 1.0 → RFC 2246
TLS 1.1 → RFC 4346
TLS 1.2 → RFC 5246
TLS 1.3 → RFC 8446
根据RFC 5246,TLS 1.2握手分为两种,一种为完整的握手,另一种为简短的握手。

这是一个完整的TLS 1.2握手流程,包含了许多带*的可选项。此外,后续文档在此基础上添加了一些扩展,如RFC 5077定义了New Session Ticket包,这里不做讨论。
然而,当客户端和服务器决定恢复之前的会话或复用已有会话,而不是协商新的安全参数时,就会用到简短握手,其流程如下:

2、TLS握手包解释
| Name | Content Type | Handshake Type |
|---|---|---|
| Client Hello | 0x16 | 0x01 |
| Server Hello | 0x16 | 0x02 |
| Certificate | 0x16 | 0x0B |
| Server Key Exchange | 0x16 | 0x0C |
| Certificate Request | 0x16 | 0x0D |
| Server Hello Done | 0x16 | 0x0E |
| Client Key Exchange | 0x16 | 0x10 |
| Certificate Verify | 0x16 | 0x0F |
| Change Cipher Spec | 0x14 | — |
| Finished | 0x16 | 0x14 |
| New Session Ticket | 0x16 | 0x04 |
这里之所以Change Cipher Spec与其他的包Content Type不同,是因为要避免阻塞,详细请参考RFC 5246。
- Client Hello:该包由客户端发往服务端,包含支持的TLS版本、加密套件、扩展等信息,同时包含第1随机数。JA3和JA4指纹就是根据该包计算而来,通常能够标识客户端的身份。
- Server Hello:服务端回应客户端,说明选择了哪个TLS版本、加密套件、扩展等,同时包含第2随机数。JA4S指纹就是根据该包计算而来的。
- Certificate:发送证书链,以用来验证自己的身份,可以是服务端,也可以是客户端发送。其中包含公钥、持有者信息、证书颁发机构签名等。接收方收到证书后,通过CA公钥进行本地验证,通常这些公钥由操作系统预装或者用户自行安装。
- Server Key Exchange:对于某些加密算法,如DHE/ECDHE,服务器证书本身不足以生成预主密钥(Pre-Master Secret),需要额外的参数,如素数p、生成元g等,从而帮助客户端生成预主密钥。RSA场景下,无需此包。
- Certificate Request:请求客户端提供证书以进行双向认证,通常用于网银等场景。
- Server Hello Done:标志性消息,不携带密钥信息或证书,而是起到通知客户端服务器端握手消息发送完毕的作用。
- Client Key Exchange:将客户端生成的预主密钥共享给服务端。对于RSA,客户端用服务端公钥加密预主密钥后传给服务端;对于DHE/ECDHE,客户端发送公钥参数,不用加密,双方通过密钥协商算法计算得到预主密钥。预主密钥通常放在内存里,抓流量不会抓到。RSA加密的TLS不满足向前保密(Perfect Forward Secrecy,PFS),因为服务器私钥泄露后,以往的所有流量都能够解密。而DHE/ECDHE则是各自生成新的临时私钥,然后进行密钥协商,服务器的私钥只用作身份认证。
- Certificate Verify:该包是客户端用来证明自己拥有证书私钥的消息,通过签名验证身份。
- Change Cipher Spec:该包用于通知对方“从现在起启用协商好的加密参数”的消息,它本身不加密也不签名,仅作为握手流程的信号,标志后续通信使用新的对称密钥和加密算法。
- Finished:用于验证握手过程的完整性和双方的身份。用会话密钥加密之前握手消息的摘要,进行加密正确性的验证。在Wireshark中,由于加密过,常显示Encrypted Handshake Message。
- New Session Ticket:于RFC 5077中新增,允许客户端保存会话信息,下次连接时可以直接恢复,而无需完整握手。
3、流量分析

该流量由curl https://cip.cc产生,其中TLS握手中穿插了TCP的ACK数据,该数据不包含应用层数据,为传输层控制的数据,在分析应用层流量时,可以将其忽略。
此外,实际场景中的TLS握手会将多个握手包合并为一个数据包,这提高了传输效率,但是基本TLS握手规则没变。
References
[1] RFC 5246