摘要

  • CRYPTO 帧是某个加密级别握手字节流中的连续 offset/length 区间。
  • 帧边界和包边界都不能证明完整 TLS 消息、完整握手消息序列、证书接受、密钥可用或应用就绪。
  • 证据应分开记录 QUIC 承载、按级别重组、TLS 解析、密钥状态、重传以及后续完成状态。

最容易出现的误判是:观察者看到一个受保护的数据包,去除 QUIC 包保护后发现一帧 CRYPTO,于是直接记录一个完整的 ClientHello 或 Finished。实际上,QUIC 给出的只是某个加密级别中、由 offset 和 length 标识的一段握手字节。它没有声明这段字节正好对应一个 TLS 消息,也没有提供显式的消息结束标记。

CRYPTO 帧必须完整地放在一个 QUIC 包内,但握手字节并不会因此被限制在一个包中。一个 TLS 握手消息或一组握手消息可以跨越多个 CRYPTO 帧和多个数据包;一帧也可能从消息中间开始,在消息结束前结束。丢失的加密信息重传时,会重新封装进新的 CRYPTO 帧,并使用与原始字节所属加密级别相同的密钥保护;新的帧和包可以采用不同边界。因此,看到相同字节出现在不同的帧中,并不能证明存在第二个 TLS 消息或重放。

CRYPTO 还不是连接级的单一序列。每个加密级别拥有独立的握手字节流,offset 都从零开始。Initial、Handshake 和 1-RTT 包可以承载 CRYPTO,0-RTT 包不能承载。不同级别中相同的 offset 不应拼成一个全局序列。接收端按级别放置数据,保留缺口,也可以暂存尚未适用的未来级别数据;只有新形成的连续字节才按顺序交给 TLS。

这里有两个不同的缓冲责任。QUIC 负责按 offset 排序、保存乱序字节以及等待级别可用;TLS 负责处理已经按序交付的字节,并决定何时拥有完整消息或完整的握手消息序列。TLS 可能增量处理,也可能继续缓冲。成功去除包保护只说明 QUIC 层的条件成立,不等于 TLS 已经成功解析。密钥可用是 TLS 处理输入后的结果,而不是某一帧存在本身的证明;该帧同样不能证明密钥已经安装。

运营记录应逐层展开:QUIC 版本、包类型、包号空间、加密级别、包保护结果和包号;CRYPTO offset、length 和隐私安全的数据摘要;该级别已经收到的连续范围与仍由 QUIC 缓冲的缺口;QUIC 实际交给 TLS 的范围和时间。只有 TLS 解析出完整消息后,才记录消息类型。证书验证、告警、密钥可用、密钥丢弃、TLS 握手完成、QUIC 握手确认和应用就绪必须各自拥有独立回执。

CRYPTO 只承载 TLS 握手消息。TLS 告警会映射为 QUIC CONNECTION_CLOSE 错误码,TLS 应用数据和其他 TLS 内容类型不能由 CRYPTO 帧承载。CRYPTO 不受流量控制,没有 stream ID、FIN 或显式结束标志。实现至少必须支持 4096 字节乱序 CRYPTO 数据;过大的最大 offset 可能导致 FRAME_ENCODING_ERROR 或 CRYPTO_BUFFER_EXCEEDED。这些是传输和资源保护事实,不是证书接受、密钥转换或服务可用的证明。

如果 TLS 已进入更高加密级别,而较低级别仍有未被 TLS 消费的数据,端点将其视为 PROTOCOL_VIOLATION。对应包号空间的密钥被丢弃时,Initial 或 Handshake 数据也会被丢弃,但这仍不是某个 TLS 消息的语义边界。TLS 握手只有在 TLS 栈发送 Finished 并验证对端 Finished 后报告完成,才算完成。握手确认和应用就绪属于更晚、独立的状态。

还必须与五个相邻维度保持距离。TR-048讨论握手确认和应用就绪;TR-049讨论同一 UDP 数据报中的包聚合;TR-045讨论 ACK 能证明什么;TR-056讨论包号重建和包号空间;TR-063讨论首选地址迁移。它们都不能把 CRYPTO 帧的运输边界变成 TLS 消息边界。

最稳妥的规则是让每个结论对应实际层级的证据。CRYPTO 帧证明一个受保护包在特定级别携带了特定范围的握手字节。按级别重组证明连续性。TLS 解析证明完整消息。证书、密钥、TLS 完成、QUIC 确认和应用就绪则需要各自的状态回执。