跳到主要内容

4. 承载 TLS 消息

QUIC 在 CRYPTO frame 中承载 TLS 握手数据. 每个 CRYPTO frame 包含一段连续的握手数据, 由 offset 和 length 标识. 这些 frame 被封装进 QUIC packet, 并使用当前加密级别进行保护. 与 TCP 上的 TLS 类似, 一旦 TLS 握手数据交给 QUIC, QUIC 就负责可靠交付.

TLS 产生的每段数据都关联到 TLS 当前使用的一组密钥. 如果 QUIC 需要重传该数据, 即使 TLS 已经更新到更新的密钥, 也必须使用原来的密钥. 每个加密级别对应一个 packet number space, 而 packet number space 会影响 frame 的语义; 某些 frame 在不同 packet number space 中被禁止.

QUIC 和 TLS 的接口主要包括: 发送和接收握手消息; 处理恢复会话中保存的传输和应用状态, 并判断是否可以产生或接受 0-RTT 数据; 重新生成发送和接收密钥; 更新握手状态. QUIC 与 TLS 还需要约定由哪一方负责验证对等方凭据, 例如证书验证.

本文档中, 当 TLS 栈报告握手完成时, 认为 TLS handshake complete. 在服务器侧, 握手完成也表示 handshake confirmed, 服务器必须尽快发送 HANDSHAKE_DONE frame. 在客户端侧, 收到 HANDSHAKE_DONE frame 时认为握手已确认; 客户端也可以在收到 1-RTT packet 的确认后认为握手已确认.

TLS 1.3 是本文档定义的基线. 客户端禁止提供早于 TLS 1.3 的版本; 如果协商出 TLS 1.2 或更早版本, 端点必须终止连接. 服务器在处理 ClientHello 时应注意首个 Initial packet 的大小和地址验证状态; 如果 ClientHello 被拆分到多个 Initial packet 中, 未验证地址的客户端可能造成服务器缓冲压力, 此时服务器可以使用 Retry.

QUIC 支持 TLS 1.3 的 session resumption 和 0-RTT. 0-RTT 依赖客户端保存此前连接的关键参数, 并向服务器提供可恢复相同信息的 TLS session ticket. 端点必须一致使用建立 0-RTT 所需的全部信息, 不能选择性忽略会改变 0-RTT 发送或处理方式的信息.

TLS alert 会映射为 QUIC CONNECTION_CLOSE 错误码. 当某个加密级别不再需要时, QUIC 会丢弃对应密钥: Initial key 会更积极地丢弃, Handshake key 在握手确认后丢弃, 0-RTT key 在不再需要发送或接收 0-RTT packet 后丢弃.