摘要

  • X.509 v3 的每个扩展由对象标识符、默认值为假的 critical 布尔位和经过编码的扩展值组成,三者都受证书签名保护。
  • 验证程序遇到无法识别或无法处理的关键扩展时必须拒绝证书;未知的非关键扩展可以忽略,但已识别的扩展不能因非关键而不处理。
  • 关键位不是重要性评分,也不证明内容真实。它决定的是:缺少某项语义能力的接收者,是否还有资格接受这张证书。

七个固定字段装不下未来

1993 年的 PEM 证书架构仍站在早期 X.509 的固定结构上。RFC 1422 把证书的主要内容列为版本、序列号、签名、签发者、有效期、主体和主体公钥。它能表达谁为哪把密钥背书,却无法为未来每一种备用身份、密钥用途、策略和授权边界预留一个固定位置。

X.509 v3 的办法是增加一个扩展序列。1999 年的 RFC 2459 首次为互联网系统整理了这套 v3 证书画像:标准可以定义通用扩展,不同组织也可以登记自己的对象标识符。外层证书格式由此可以保持稳定,里面的语义却能继续生长。

真正棘手的问题随之出现。旧程序看到一个后来的 OID,应当怎么办?若所有未知扩展都导致失败,新增任何信息都会切断旧客户端;若所有未知扩展都被跳过,那么一条本应限制证书用途的规则,在最不理解它的软件面前反而完全失效。

一个位决定“不会”能否变成“通过”

RFC 5280 给出的 Extension 结构很短。extnID 是 OID,用来指明解释规则;extnValue 是八位组字符串,内部保存该扩展值的 DER 编码;critical 是默认值为 FALSE 的布尔位。

若系统不认识一个关键扩展,必须拒绝证书。若它认识类型,却无法处理其中的信息,也必须拒绝。未知的非关键扩展可以忽略;但一旦认识了这个非关键扩展,就必须处理,不能把“非关键”误读为“可选”。

因此,critical 不是“优先处理”,不是“危险等级”,也不是“更可信”。签名能证明签发者签过这些字节,不能证明签发者的判断一定正确。该位只声明一个验证后果:没有能力实施这条语义,就不能给出成功结果。

关键位和扩展值一起位于 TBSCertificate 中。中间设备若为兼容旧客户端而把真改成假,签名便不再匹配。同一种扩展也不得在一张证书中重复出现;验证者不用猜测两个相互矛盾的副本谁覆盖谁。

有些字段一旦被略过,授权边界就变了

当普通主体字段为空、身份只写在 subjectAltName 中时,该扩展必须标为关键。否则,一个不理解它的程序会绕过证书中唯一的身份表示,却仍可能认为验证已经完成。

用于签发下级证书的 CA 证书必须携带关键的 basicConstraints。其中的 cA 值说明公钥能否验证证书签名,路径长度还可限制授权向下延伸的层数。忽略它不是少看一条备注,而是可能把有限授权读成无限授权。

nameConstraints 限制后续证书可以使用哪些命名空间,合规 CA 必须将它设为关键。若中间 CA 只能签某些域名,而旧程序看不懂这道边界,继续接受会让有限的签发能力显得普遍有效。策略约束和 inhibitAnyPolicy 也采用关键语义,因为它们的目的正是削减一条路径可保留的策略。

也有扩展被要求或建议保持非关键。某些标识符和信息位置能帮助构建路径,却不是每个应用正确使用证书的必要条件。决定 critical 的问题并非“它听起来是否与安全有关”,而是“不执行这项语义后,证书的用途是否被改变”。

RPKI 与 TLS 把迁移成本放在不同一边

RFC 3779 定义了 IP 地址块和自治系统号的 X.509 扩展,并建议标为关键。用这类证书判断资源使用权的依赖方,必须知道证书到底涵盖哪些地址或 ASN。只验证签名、却忽略资源范围,得到的并不是较旧但仍正确的结论,而是与证书用途无关的结论。

RFC 7633 为 TLS Feature 扩展选择了另一侧。它建议不要标为关键,因为不认识该扩展的旧实现会拒绝整张证书。只有当这种拒绝就是签发者想要的行为时,才有理由主动承担兼容性断裂。

两份规范并不矛盾。非关键模式保护旧软件的可达性,代价是不能声称所有接受者都执行了新规则;关键模式保护规则不可被无知跳过,代价是缺少实现的接收者必须退出。一个位把这笔成本公开了。

规范发出规则,运行代码作出拒绝

2002 年的 RFC 3280 把扩展处理纳入详细的证书路径验证算法。RFC 5280 延续了可观察结果:每一级证书中适用的关键扩展都要被识别和处理,任何一步失败都会终止路径验证。

实现不必照抄规范中的程序结构,但必须得出同样的外部结论。这一安排把标准协调与本地接受分开。IETF 可以发布 OID,CA 可以签下声明;只有依赖方的代码真正识别、解析、执行并在必要时拒绝时,规则才在那台系统上获得效力。登记记录描述语义,不能代替运行程序采用它。

2024 年的 RFC 9618 仍守着这条边界。应用若不需要证书策略验证,可以关闭相关功能;但遇到关键的策略扩展时,就要把它视为无法识别并拒绝。可以诚实承认“我不提供这项能力”,不能在没有执行强制规则的情况下模拟一次成功。

通过路径不等于得到无限信任

关键扩展检查回答的只是一个有限问题:这套验证程序是否理解并满足了该路径中所有必须执行的扩展语义。它不能证明主体诚实、CA 调查无误、私钥未泄露,也不能授权证书从事一切业务。

信任锚、验证时间、应用用途和本地策略仍是输入。已知 OID 可能装着错误编码,正确编码也可能违反命名空间或路径长度约束。同一张末端证书还可能通过不同的中间证书形成不同路径。关键位阻止强制语义被静默跳过,并没有取消其他判断。

证据范围也应保持有限。RFC 1422、RFC 2459、RFC 3280、RFC 5280、RFC 3779、RFC 7633 与 RFC 9618 证明了结构、指定行为和历史演进;它们不提供当前产品份额、现实失败频率或所有浏览器与库的合规证明。

X.509 v3 的历史价值不只在于让证书多说几句话。关键位让其中某些话不能沦为装饰:如果一句限制是证书成立的前提,不理解它就必须留下一个清楚的失败。