一种不同的套件
在 RFC 8446 中定义的 TLS 1.3,改变了密码套件所命名的内容。在 TLS 1.2 中,一个套件把密钥交换、身份验证、密码和 MAC 捆在一起。在 TLS 1.3 中,一个套件只命名两样东西: 密码,以及密钥派生函数所用的哈希函数。
TLS_AES_128_GCM_SHA256
| |
| +-- handshake hash (HKDF): SHA-256
+------------- AEAD cipher: AES-128-GCM
名称里没有密钥交换,也没有身份验证,因为 TLS 1.3 是单独协商这些内容的。这是最大的变化,也是为什么一个 TLS 1.3 套件放在一个 TLS 1.2 套件旁边显得如此简短。
密钥交换去了哪里
在 TLS 1.3 中,密钥交换由它自己的扩展 key_share 承载,所提供的群组列在 supported_groups 中。身份验证通过 signature_algorithms 协商。把这些从套件里抽出来有一个实在的好处:寥寥几个密码套件可以与任何受支持的群组和任何签名算法自由组合,而不是那种让 TLS 1.2 拥有数百个已注册套件的组合爆炸。
它还内建了两个良好的默认设置。每一次 TLS 1.3 密钥交换都是临时的,所以前向保密是强制的,而非可选的。而失去前向保密的经典途径,即静态 密钥传输,被彻底移除,RSA 只作为身份验证的签名算法存留下来。
五个套件
基础规范定义了五个套件,实际中你主要会见到前三个:
0x1301 TLS_AES_128_GCM_SHA256 (mandatory to implement)
0x1302 TLS_AES_256_GCM_SHA384
0x1303 TLS_CHACHA20_POLY1305_SHA256
0x1304 TLS_AES_128_CCM_SHA256
0x1305 TLS_AES_128_CCM_8_SHA256
这五个全都是 AEAD,TLS 1.3 不允许别的。TLS_AES_128_GCM_SHA256 是强制实现的,这使它成为安全的最大公约数。ChaCha20-Poly1305 是在没有 加速的硬件上的常用选择。两个 套件面向受限环境,而 CCM_8 以更短的身份验证标签换取更小的开销,所以即便它是一个 TLS 1.3 套件, 也不把它标记为推荐。
同一注册表,但不可互换
TLS 1.3 复用与早期版本相同的 IANA 密码套件注册表和相同的两字节代码空间,但这两套定义并不可互换。TLS 1.3 的套件值不能用于 TLS 1.2,TLS 1.2 的套件值也不能用于 TLS 1.3。这些代码点恰好落在该范围中先前未使用的一段(0x13xx),从而在视觉上保持区分。
正因如此,解码器必须知道一个套件属于哪个世界。在 0x13xx 范围内、不带 WITH 标记的名称,是一个密钥交换在别处协商的 TLS 1.3 套件;带 WITH 标记的名称,是一个密钥交换被写明的 TLS 1.2 及更早版本套件。
降级保护
由于较旧的套件为较旧的对端依然存在,TLS 1.3 增加了对攻击者强制降级的防护。一个支持 TLS 1.3、却最终协商了较旧版本的服务器,会在其 server random 的最后八个字节写入一个固定的哨兵值。真正的 TLS 1.3 客户端会检查这个哨兵,若它出现在本应是 1.3 的连接上就中止,从而把一次悄无声息的降级变成一次失败的握手。密码套件列表缩短了,但围绕它的协议变得更具防御性。
要在一条真实连接上看到这一切,The Illustrated TLS 1.3 Connection 逐条记录、逐个字段地注释了一次真实 TLS 1.3 握手的每一个字节。