这两种吊销检查里,一种返回关于单张证书的签名答复,另一种返回你整份下载的签名列表。两者都意在告诉验证方某份凭据是否仍然可信,而失败时的表现却完全不像。下面的顺序对应运维在生产中实际遇到的情形,从线上字节开始,到网关拒绝连接为止。跳过其中一步,部署最后就会只剩一份只存在于纸面上的吊销策略。

第 1 步:每种检查返回什么,以及能保持可用多久

CRL 作为一份签名对象发布,覆盖签发者已吊销的每一张证书,所以验证方取一次,就一直复用到列表的 nextUpdate 过期为止。OCSP 响应更窄:它只针对一张证书作答,并带有 thisUpdate、producedAt,通常还有 nextUpdate。正是这一差别决定了其余一切。缓存的 CRL 会悄悄变旧,因为文件仍能解析、签名仍能验证;而过期的 OCSP 响应,在你读它的时间戳那一刻就明显毫无价值。

因此首先要定下来的是缓存:由哪个组件持有副本,这份副本服从哪个上限。在网关上,上限应当是 nextUpdate 减去安全余量,绝不是 HTTP 缓存头恰好建议的值。openssl crl -in issuer.crl -noout -lastupdate -nextupdate 会打印这两个日期,而 nextUpdate 已经落在过去的列表,必须当作缺失而不是仅仅过旧。

第 2 步:证书把客户端指向哪里

叶子证书通常带两条线索:CRL 分发点扩展,以及面向 OCSP 的颁发机构信息访问条目。openssl x509 -in client.pem -noout -ext crlDistributionPoints 会打印前者,后者位于 openssl x509 -in client.pem -noout -text 的 AIA 小节下。任一扩展都只是指针,不是义务。从不实现吊销检查的客户端,照样能连上一张扩展里指向已死一年的响应者的证书。

分发点常常指向一个只在一个网段内解析的内部主机,一些较旧的客户端干脆拒绝 ldap URL。要在终止隧道的那个主机上测试可达性,而不是在自己的笔记本上,因为只有这个视角的失败才真正要紧。

第 3 步:在中断之前选定 fail-closed 还是 fail-open

响应者不可达或列表过期,会逼出一个决定:拒绝连接,或者接受并记录这段缺口。OpenSSL 的 verify 子命令把严格选择摆到明面上,因为加上 -crl_check 会把不可用的 CRL 变成 unable to get certificate CRL 和一次失败的验证。大多数技术栈里的软失败根本不是开关,而是检查本身的缺席,正因如此它才会被意外地交付出去。

想知道客户端真正的行为,就把响应者拿走再重连。如果隧道仍然能起来,就去找记录这次被跳过检查的那行日志,然后问:事故当中会有人读那行日志吗。同一个厂商也可能按协议不同,同一台机器上的 IKEv2 客户端和 OpenVPN 客户端读的是互不相关的配置项。

第 4 步:证明确实在放行流量的地方执行了检查

找到终止或授权连接的那个进程,再问它哪条配置打开了吊销检查。只验证证书链却从不询问吊销的网关,执行的是与你文档不同的策略,而任何证书链截图都证明不了相反的事。OpenVPN 把这个选项写作 crl-verify;strongSwan 把 CRL 与 OCSP 查询放在 CA 配置下,在那里设置 crl_uris 或 ocsp_uris。如果两处都指不出来,就假定检查并不存在。

只有当签发 CA 签过名,或由该 CA 委派、持有 OCSPSigning 扩展密钥用途的响应者签过名,OCSP 响应才算数,因此来自无关服务的答复什么也证明不了。如果你自己运营响应者,就把它当成硬依赖来监控,因为一个死掉的服务会同时成为每个 fail-closed 客户端的中断。

第 5 步:故意吊销一张证书

取一张测试证书,用生产所用的同一条通道吊销它,然后直接询问响应者。openssl ocsp -issuer ca.pem -cert old.pem -url http://ocsp.example.net -resp_text 应当报告 Cert Status: revoked 以及吊销时间,而 good 这样的答复说明你的吊销没有到达客户端所询问的那个响应者。随后运行 openssl verify -crl_check -CRLfile issuer.crl -CAfile ca.pem old.pem,从列表这条路径看同一个决定。要读原因字符串而不是退出码,因为吊销拒绝和链错误都以失败收场。

真正要紧的是最后一步:带着旧配置对着真正的执行点重连,确认拒绝来自吊销。然后用一张新的有效证书重连,证明你不是只把监听端弄坏了。在客户端删掉配置并不能说明服务器的决定,在一台从不终止隧道的机器上跑通 openssl verify 同样不能。 RFC 6960 规定了一份合规的 OCSP 响应包含什么,也包括这个测试所读的状态值。

相关文章