摘要
- TLS 1.3 的 CertificateVerify 用证书私钥签署当时的握手转录;
Finished再用由发送方握手流量秘密派生的密钥,对更完整的转录做独立 MAC 校验。 - 完成状态属于端点与方向。服务端
Finished有效,不等于客户端Finished已被收到,也不证明早期数据获接受、代理上游握手成功或应用交易落地。
一条迟到的错误揭穿了过早的成功
这次误判里,证书链符合服务身份策略,CertificateVerify 的签名也完全正确。仪表板据此把连接归入“已认证”,甚至开始计算成功率。
随后客户端解开服务端 Finished,却算不出相同的 verify_data。现行 RFC 9846 要求接收方以 decrypt_error 终止连接。客户端照做,普通应用数据阶段根本没有建立。
问题不在证书,也不在签名算法。系统只是把认证块的倒数第二项当成了终点:私钥持有证明被扩大为“双方共享同一握手秘密、看见同一段历史”的证明。
相邻消息不共享同一种权力
CertificateVerify 对经过角色隔离的结构签名,其中包含直到 Certificate 为止的转录哈希。它说明发送方控制所呈凭证对应的私钥。证书路径与服务名判断仍是另一层;签名在数学上正确,并不能让策略不接受的证书变成合格身份。
Finished 不是第二次证书签名。TLS 1.3 从发送方的握手流量秘密派生 finished_key,再对包含 CertificateVerify(若存在)在内的转录哈希计算 HMAC。它确认的是当前握手密钥与当前历史,而非长期证书本身。
PSK 模式把差异显得更清楚。恢复连接或外部 PSK 可以完全没有 Certificate 与 CertificateVerify,但双方仍须发送 Finished。反过来,CertificateVerify 有效而 Finished 错误,结论只能是握手失败。
转录不是抓包文件的简单拼接
转录哈希按顺序覆盖握手消息,并计入握手消息类型与长度头;TLS 记录头、告警和应用记录不在其中。一个握手消息可跨多个记录,一个记录也可承载多个握手消息,逻辑转录并不会因此改变。
HelloRetryRequest 还有专门规则:第一次 ClientHello 以合成的 message_hash 进入后续历史。于是,被动抓包工具不能把可见记录载荷直接串起来就声称重建了 Finished 输入。TLS 1.3 后续握手消息本身已加密,精确复核需要受控的端点秘密或同等级的实现证据。
密码套件选定的哈希同时服务于转录与 HKDF。在 TLS 1.3 中,verify_data 的长度等于该哈希的输出长度。若监控仍坚持 TLS 1.2 固定 12 字节的旧假设,它会制造另一种看似精确的错误。
完成并非一个全连接布尔值
客户端与服务端拥有各自的握手流量秘密,因此各自生成一个 Finished,并在不同时间验证对方的值。
服务端发出 Finished 后,发送方向切换到应用流量密钥。规范允许它在尚未收到客户端 Finished 时发送应用数据,但同时明确:此刻服务端尚不能确信客户端身份或存活性,因为 ClientHello 可能来自重放。
客户端先验证服务端 Finished,若被要求再发送客户端 Certificate、CertificateVerify,最后发送自己的 Finished。把整个过程压成 tls_complete=true,会抹去谁发过、谁验证过以及客户端认证是否仍悬而未决。
较小而可靠的共同规则是按方向记录 finished_sent、peer_finished_verified 与实现状态机的完成时刻。应用再声明某项操作究竟需要哪组状态。
0-RTT 是明示例外,不是提前完成
客户端可在收到服务端 Finished 之前发送 0-RTT。它依赖旧会话的 PSK,安全属性更弱,并存在跨连接重放风险。看见早期数据既不能证明服务端接受,也不能证明当前握手最终成功。
运营账本至少要拆成三项:早期数据是否提出、接受或拒绝;服务端 Finished 是否已验证;普通握手后流量是否建立。若只记“收到加密请求”,可重放请求就会错误继承完整新握手的权威。
EAP-TLS 说明外层协议还会定义自己的已连接或隧道可用状态。外层状态不能仅因内层某条认证消息有效,就越过 Finished 所在的边界。
TLS 终止器切断了证据连续性
客户端到边缘代理是一条握手,代理到源站是另一条。两边即使都使用 TLS 1.3,其随机数、参数、密钥、凭证、转录与完成时间也不相同。
把下游的 peer_finished_verified 复制给上游请求,相当于编造一段不存在的密码学连续性。源站需要上游握手自己的证据;若它还要理解下游身份,代理必须另行建立经过认证的应用层关联。
连接池与重试同理。迁移到第二条上游连接的请求不能继承第一条连接的 Finished 状态。关联标识可以说明迁移过程,却不能合并两段密码学历史。
实现 API 只会证明它实际暴露的事实
OpenSSL 的 SSL_is_init_finished() 表示状态机是否到达可传送完整保护应用数据的阶段;文档也提醒,早期数据使“未开始、进行中、已完成”的简单三分法失效。SSL_get_verify_result() 报告证书验证结果,不负责 Finished 或应用授权。
密钥日志回调可用于受控解密和转录重建,但它输出的是敏感密钥材料。为完善普通仪表板而在全量生产环境开启,会创造新的泄露面。日常监控宜保存状态迁移、协商标识、错误类别与有限关联;原始秘密只进入隔离、限时的符合性测试。
同名 API 也不能跨库类推。BoringSSL 当前头文件明确说明 TLS 1.3 下 Finished 访问器返回零;GnuTLS 则提供握手钩子和专门的 Finished 包错误,并警告握手完成前的输入还不能排除主动中间人。控制项应先定义所需协议状态,再逐库映射和测试。
建立可以反驳自己的证据账本
一条可审计记录应保存端点角色、方向、版本、密码套件、转录哈希、认证模式、证书策略结果、CertificateVerify 结果、服务端与客户端 Finished 状态、早期数据处置及 TLS 终止连接段。
失败必须保留。CertificateVerify 成功后出现 decrypt_error,不是应该被“证书成功”吞掉的噪声,而是后一道边界拒绝握手的直接证据。
最有力的测试每次只改一个条件:篡改一个转录字节或一个 Finished 字节并要求致命失败;保持证书与签名有效,只破坏 Finished;服务端 Finished 通过后扣留客户端 Finished;执行无证书消息的 PSK 恢复;触发 HelloRetryRequest;再通过上下游参数不同的代理重复。
这些结果说明正在运行的实现尊重边界。RFC 条文、API 名称或已配置的回调,只能证明规则或能力存在。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
