客户端信任的 CA 错给 orders.test 签了另一张证书;网站自己的 TLS 私钥并没有泄露,但攻击者若能使用那张错签证书,访问者就可能连接到错误服务。有人说:“把证书记入透明日志,错误证书就不能用了。”日志通常不能强制 CA 不签错证;它要做的是让发行行为可见、可追踪、可由监视者发现并纠正。包含证据、承诺不删改旧条目的追加一致性和有人真正检查日志,是三项不同工作。

三个验证对象

透明日志对证书或预证书做规范的叶编码,把有序叶集合构成带根哈希的 Merkle 树。包含证明用叶与路径重算到给定根;仅当客户端拿到正确、可信/可核验的树头和日志身份时,才有“这条内容属于这次树承诺”的意义。若日志给出 SCT(签名证书时间戳),那是关于未来按规则纳入日志的一项承诺,不是纳入证明,也不是该证书绝无错签的审计结论。

追加一致性回答另一个问题:先前规模为 m 的树,与后来规模为 n 的树,新的历史是否保留了老树全部条目并只在后面追加?客户端若只验某张证书在新根之下出现,不会发现旧条目被替换/删除;如果攻击者让两个客户端看到两套互相矛盾的树头,仅在同一条恶意视图内部检验还不能发现分裂视图。需要日志身份签名、可比较的树头、监视者/见证者及合理的分发/交叉检查。CA 链与域名验证仍然存在:透明日志不授权另一张名称错误的证书成为正确服务证书。

1
2
3
4
5
CA 签发证书 ─► 日志收录承诺(SCT) ─► 日志持续发布树头
│ │
客户端:证书链 + SAN 验证 │ └──► 旧头→新头追加一致性
客户端/监视者:记录叶 ──► 包含路径 ────┘
监视者:发现给预期服务名的异常证书 ─► 响应与治理

examples/cryptography/E06_ct_log_model.py 仅用标准库 SHA-256 演示 RFC 9162 风格的 0x00 || leaf 与 0x01 || left || right 域分离哈希;四个纯文本 cert-A…cert-D 不是实际 X.509 编码。前两条形成旧 root,四条形成新 root;对于恰好 2→4 的对齐情形,重用可信旧根与右侧新子树算出新根。改旧根不再一致;改某张叶后包含路径不再到达原新根。

1
2
python3 examples/cryptography/E06_ct_log_model.py
python3 -m unittest discover -s examples/cryptography -p 'test_E06*.py' -v

特例之所以简单,是旧两叶本身刚好是一棵完整子树。真实 RFC 9162 通用 m→n 一致性 proof 不可一律只携带一个新子树哈希;本实验没有实现通用算法,也没有核对日志签名、SCT、监视者或在线 CA 错签,均 NOT_RUN。模型根在同一进程内部算出,不能因布尔值为真就把“日志世界可信”当成通过。TLS 的绿锁认证当前服务端时仍须基于 CA、主机名及策略;CT 用来补足可见性,不替代证书认证。

练习及答案

画图题: 画出只有包含证明与同时拥有包含/旧新树头一致性证明两种情况。日志偷偷把旧第 1 条叶换成攻击者证书而为新树提供路径时,各自可能漏掉什么?

答案: 攻击者能为替换后的新树构造一条自洽包含路径;只拿新根和新路径而无先前可信树头,就不知道旧叶被换。若验证者已记录旧根并严格核查追加一致性,替换旧叶会改变其承诺,不能把修改后的树合法解释为旧树的追加版本。若旧根也由攻击者随意指定,两种证明都失去可信比较起点。

实验变更题: 把 old_root 改成全零,保持 right_subtree 与 new_root 原值,哪项断言失败?若只换新树的第 4 条叶而重算 new_root,旧两条是否还一定保持可核对的一致前缀?

答案: 全零假旧根无法与右子树重新算到原新根;旧头一致性检查失败。只改第 4 条并重算新根,旧两叶仍可能是相同前缀且新树根不同,需用新的右子树哈希和新树头证明这个追加关系;旧树头的真实性及日志签名仍须另查。

资料与导航