读取不是信任

解剖一文以一个值得重申的要点收尾:解码一份证书告诉你它所声称之事,而非那个声称是否真实。验证是一个 TLS 客户端为判定是否信任它面前的那份证书而运行的、单独的过程。它主要由 RFC 5280 所辖,且它是一连串独立的核查之合取,其中每一项都必须通过。一个解码器,本工具在内,向你展示那个过程的输入;客户端才是强制执行它之物。

步骤一:构建链

一片叶子证书几乎从不凭其自身被信任。客户端必须构建一条从叶子向上直到一个它已持于其信任库中的根的路径。它通过追随颁发者名字来做此事:叶子的 Issuer 应匹配某个中间证书的 Subject,而那个中间证书的 Issuer 应匹配再上一层的那一个,直到它抵达一个自颁发的根。Authority Key Identifier 与 Subject Key Identifier 扩展会加速这种匹配,办法是让客户端凭密钥哈希、而非仅凭名字,把一份证书链接到它的颁发者。若无法构建一条通往一个受信任的根的路径,验证立即失败,无论那片叶子何等格式良好。

步骤二:核验每一个签名

一条链唯有当每一环在密码学上都站得住脚时才有意义。对路径中的每一份证书,客户端核验那个签名确由颁发者的私钥所产生,办法是凭颁发者的公钥、对子的待签名主体的 字节来核对它。因签名覆盖那些确切的字节,主体中任何位置一个被改动的字节都会破坏该核查。这也是为何签名算法(例如 sha256WithRSAEncryption 或 ecdsa-with-SHA256)要紧:一条链的强度,只及于它最弱的那个签名与哈希。关于哈希在此处所担保之事,见哈希一文

步骤三:核查有效期窗口

每一份证书都承载一个 notBefore 与 notAfter 时间戳,而客户端针对链中的每一份证书、而非仅是叶子,以当前时间核对那个窗口。一份已过期、或尚未有效的证书会失败。本工具针对你的本地时钟执行这同一项核查,并报告一份证书是此刻有效、尚未有效、还是已过期,这往往是诊断一个“你的连接不是私密的”警告的最快途径。

步骤四:匹配名字

一条有效的链证明该证书是真实的,但不证明它是为你正在访问的那个站点而颁发的。客户端核查它所连接到的那个主机出现在该证书的 Subject Alternative Name 扩展中。现代客户端为此目的全然无视 Common Name,只看 ,遵循 RFC 6125 的身份匹配规则。诸如 *.ronutz.com 的通配符匹配单个标签,所以它们涵盖 api.ronutz.com,但不涵盖 ronutz.com 本身或 a.b.ronutz.com。一份其链完美、但其 SAN 并不列出你所求之名字的证书,仍会被拒绝。

步骤五:强制约束

那些 v3 扩展不是装饰;它们是客户端所强制执行的规则。Basic Constraints 言明一份证书是否可作为一个 ,以及,经由路径长度,多少个中间证书可坐落于它之下,这便是阻止一片叶子证书被用来签署其他证书之物。Key Usage 与 Extended Key Usage 约束该密钥被允许做什么:一份 TLS 服务器证书必须承载 serverAuth EKU,而一个被标记为 critical、客户端却不理解的扩展,会强制一次拒绝,而非一个耸肩。本工具会浮现这些字段,以便你能确切看到一个颁发者设定了哪些约束。

步骤六:核查吊销

最后,一份在颁发时有效的证书,可能自那以后已被吊销,例如因其私钥泄露。客户端可查询一个 或一个 响应者以查明。在实践中这是最弱、也最不一致的一步,而业界正转向改用短寿命证书,吊销一文对此有完整论述。

验证是一个“与”,而非一个“或”

一份单独的、被篡改或配置错误的证书之所以被拒绝,原因在于所有这些核查以逻辑“与”相结合。链必须能构建、每一个签名必须能核验、每一份证书必须处于其有效期窗口、名字必须在 SAN 之中、约束必须许可那一用途,且该证书必须未被吊销。一个解码器清晰而忠实地铺陈该证书的断言;把那当作对该文档的一次审慎读取,并记住:那个裁决,归属于运行全部六项核查的那个客户端。