TLS1.3 通信流程梳理,基本是从 https://tls13.xargs.org 翻译过来的,建议看原文
客户端:生成密钥对#
记作 (client_priv, client_pub)
客户端:明文发送 Client Hello Packet#
主要包含以下内容:
- 随机数 client_random
- 客户端支持的 cipher suites
- 客户端支持的协议版本
- 请求的服务器名称 SNI (Server Name Indication)
- PSK (pre-shared-keys) 预共享密钥模式
- Key Share 公钥列表 (client_pub)
- Session Ticket
- 压缩方式等...
SNI 字段使服务器可以在同一个 ip 组上提供多个 TLS 服务,在握手过程中根据 SNI 返回对应的证书。
Key Share 扩展会发送一个或多个客户端认为服务端很可能会接受的公钥及加密算法,如果服务端接受,则 Server Hello 后续的数据可以加密传输。相当于提前进行了 Key Exchange 如果服务端不能接受则返回一个 Retry Hello Request 消息重新进行握手。
Session Ticket 在连接建立完成后由服务端发送,客户端可以保存此数据用于后续快速恢复重连。
PSK 的使用参考 When do clients use TLS in PSK mode?
服务端:生成密钥对#
记作 (server_priv, server_pub)
服务端:明文发送 Server Hello Packet#
主要包含以下内容:
- 随机数 server_random
- 选定一个 cipher suite
- 选定一个 public key
- 选定协议版本
- 返回 Key Share 包含 (server_pub)
- 压缩方式等...
服务端:计算 Handshake Key#
通过以下信息计算握手密钥:
- client_pub 从 Client Hello Packet 中获得
- server_priv 由服务端生成
- SHA384 (ClientHello + ServerHello) 计算之前发送的消息的哈希值
后续的握手过程都通过此密钥加密
客户端:计算 Handshake Key#
通过以下信息计算握手密钥:
- server_pub 从 Server Hello Packet 中获得
- client_priv 由客户端生成
- SHA384 (ClientHello + ServerHello) 计算之前发送的消息的哈希值
后续的握手过程都通过此密钥加密
服务端:密文发送证书#
服务端根据 Client Hello 中指定的 SNI 返回证书并进行校验
证书的校验与签发#
- 服务端生成自己的密钥对 (host_priv, host_pub) 并将 host_pub 和域名信息地域信息等组合成 host_info 发送给 CA (Certificate authority)
- CA 审核校验申请者信息,并使用自己的私钥 CA_priv 对 hash (host_info) 加密得到签名 SIG 最终 SIG 和 host_info 组合成证书颁发给服务端
- 客户端请求服务端得到证书后,通过本机安装的 CA 公钥对签名 SIG 解密得到原始数据 CA_pub (SIG)
- 客户端取出证书中的 host_info 自行计算 hash (host_info) 并校验和签名解密数据是否一致
信任链#
某些情况下,证书可能由二级 CA 颁发,当客户端请求证书时,服务端会将中间证书和自己的证书一并返回:
- 客户端首先需要使用本机安装的 CA 公钥对中间证书进行校验,取出中间证书的公钥
- 客户端再使用中间证书公钥对服务器证书进行签名校验
服务端:密文发送证书校验#
通过上一步,客户端可以确认证书 (包括其中的公钥) 属于当前请求的服务名,但还不能证明此服务器是此证书的所有者。因此服务端需要使用证书签发前创建的私钥 host_priv 加密握手消息摘要返回给客户端,客户端可以根据证书 host_info 中的公钥 host_pub 解密此数据,再自行计算握手消息摘要进行比对是否一致。至此客户端可以确认此连接的安全性
服务端:密文发送握手结束验证消息#
服务端将握手阶段的所有消息取哈希作为验证消息发送给客户端
服务端:计算 Application Key#
服务端通过 Handshake Key 和从 Client Hello 到服务端握手结束的所有信息取哈希计算 Application Key 即后续数据传输阶段的对称密钥
客户端:计算 Application Key#
客户端使用同样的方式计算 Application Key
客户端:密文发送握手结束#
客户端将握手阶段的所有消息取哈希作为验证消息发送给服务端
至此客户端和服务端之间可以通过 Application Key 进行对称加密通信
服务端:密文发送 Session Ticket 1#
服务端为客户端提供 Session Ticket 用于后续快速开启新的会话,减少会话创建阶段大量的计算和网络延迟。包括:
- Ticket Lifetime 有效期
- Ticket Age Add (每个 ticket 单独一份)
- Ticket Nonce 随机值 (每个 ticket 单独一份)
- Session Ticket
其中 Ticket Age Add
是由服务端生成的随机毫秒数,客户端在使用 Session Ticket 恢复连接时需要将 ticket_age (表示从收到 Session Ticket 到目前当前的时间差) 加上此值进行混淆。服务端收到此值后校验客户端的 ticket_age 和自己计算的时间差是否接近,如果超过了一定的阈值可以直接拒绝此连接。一定程度上避免了重用 Session Ticket 制造的重放攻击。
服务端:密文发送 Session Ticket 2#
第二个 Session Ticket 由于客户端比如浏览器一般会发送多个连接,且每个 Session Ticket 只能使用一次,服务器一般会返回多个 Session Ticket
参考资料:
RFC8446
xargs.org - TLS
xargs.org - x25519
Wikipedia - Shared_secret
Wikipedia - Pre-shared_key
Wikipedia - SNI
A walkthrough of a TLS 1.3 handshake
一文详解 HTTPS 与 TLS 证书链校验
SSL/TLS 协议详解 (中)—— 证书颁发机构
网络安全科普:奇妙的 SSL/TLS 证书(基础篇)