4、CRL 分发点(CDP)扩展:如何定位 CRL 下载地址

拿到一张证书,怎么知道它对应的 CRL 该去哪下载?答案就在证书的 CRL 分发点(CDP)扩展里。这个扩展就像是一张“导航地图”,告诉客户端去哪里取吊销列表。没它,CRL 验证就无从谈起。

我个人习惯,拿到证书先看 CDP。不是别的,因为绝大部分 CRL 下载失败,根源都是 CDP 写错了或者指向了不可达地址。你想想看,地址都找不到,后面所有步骤全是白费。

CDP 扩展长什么样?

CDP 是 X.509 v3 扩展中的一个标准项。它的结构其实挺简单——一个或多个分发点(Distribution Point),每个分发点里包含一组 URI 地址。证书里可以写多个地址,客户端按顺序尝试,直到拿到 CRL 为止。

用 OpenSSL 看 CDP 最方便。我常用的命令是:

openssl x509 -in certificate.pem -text -noout | grep -A 6 'X509v3 CRL Distribution Points'

输出大概长这样:

X509v3 CRL Distribution Points:

    Full Name:
      URI:http://crl.example.com/ca.crl
      URI:ldap://ldap.example.com/cn=CA,dc=example,dc=com?certificateRevocationList;binary
      URI:file:///var/crl/ca.crl

嗯,这里要注意。每个 URI 前面都有 URI: 前缀,协议可以是 http://、ldap://、file:// 甚至 ftp://。但现实中,HTTP 占多数,LDAP 偶尔见,文件路径基本只在内部用。

为什么要多个地址?

不是闲得慌。多写几个地址,是为了容错。我曾经遇到过,CA 给了一个 HTTP 地址,但那个 CDN 节点挂了,幸好证书里还配了一个 LDAP 地址,从域控里硬拉了下来。如果只写一个地址,那次巡检就要报异常了。

证书签发者会按优先级排地址顺序。大部分 CA 会把 HTTP 放在第一个,因为通用性好、防火墙兼容性强。LDAP 虽然有目录同步优势,但端口 389/636 在企业内网经常被自定义 ACL 拦截,外网更不用说了。

用工具解析 CDP——不只是 OpenSSL

OpenSSL 最基础,但信息展示不够结构化。我习惯在诊断时用 certutil(Windows)或 keytool(Java)做交叉验证。比如:

工具命令示例适用场景
OpenSSLopenssl x509 -in cert.pem -text -nooutLinux / 通用
certutilcertutil -v -urlfetch cert.cerWindows 企业环境
keytoolkeytool -printcert -file cert.cerJava 应用栈

用 certutil 有个好处——它会自动尝试下载 CRL,并告诉你哪个地址成功、哪个失败。我曾经在生产环境抓到一个诡异问题:OpenSSL 显示 CDP 是正常的,但 certutil 实际下载时报 404。

小技巧: 用 certutil -urlfetch cert.cer 时带上 -v 参数,会打印每一步的 HTTP 状态码。省得你手动去 curl 一堆地址。

常见 CDP 格式与坑点

地址格式写错了,比地址不可达更隐蔽。我简单列一下我会特别注意的几种:

  • HTTP URL —— 最常见。注意路径是否包含 . 或 .crl 后缀?有些 CA 用 application/pkix-crl 响应,但 URL 写的是 .der,客户端照样能处理。但如果你看到 URL 结尾是 / 没有文件名,那基本是错的。
  • LDAP URL —— 结构复杂。标准格式是 ldap://host:port/baseDN?attributeName?scope?filter。我见过最坑的写法是:属性名写成了 certificateRevocationList;binary 但忘了写分号,导致 LDAP 返回不了二进制内容。
  • file:// URI —— 只在本地验证有用。证书发布到客户端后,客户端根本访问不到 CA 本地的文件路径。要是 CDP 里只有 file://,CRL 分布必失败。
  • AIA 扩展混用 —— 有人会把 CRL 地址放在 Authority Information Access 里,但 CRL 应该用 CDP。这不是标准做法,但有些 CA 自作聪明,你查时必须两者都看。
注意: CDP 扩展可能被证书策略限制标记为“不关键”。即使如此,客户端(尤其是浏览器)仍然会尝试使用它。不要以为标记为“非关键”就可以随便写。

实战:从证书里拽出 CDP 地址

假设你现在有一张 DER 格式的证书 server.cer。我来演示一下完整的手动流程:

  1. 转成 PEM(方便文本查看)
    openssl x509 -in server.cer -inform DER -out server.pem -outform PEM
  2. 查看 CDP
    openssl x509 -in server.pem -text -noout | grep -A 10 'X509v3 CRL Distribution Points'
  3. 提取出 URI 列表(可能有多个)
    用 sed 或 awk 简单清洗,或者直接用眼睛看。
  4. 逐个测试 HTTP 地址(最常用)
    curl -I http://crl.example.com/ca.crl
    返回 200 OK 且 Content-Type: application/pkix-crl 才算可用。

我实际遇到过,证书里写的 HTTP 地址是 http://crl.example.com/ca.crl,但 curl 返回 302 重定向到 https://。客户端如果没配置跟随重定向,就下载失败了。排查时你不去实际 curl 一下,光看 CDP 文本根本发现不了。

流程图:从证书到 CRL 下载地址

下面这张图帮你梳理整个逻辑链条。我习惯把它贴在排查文档第一页,看完就清楚下一步该干什么。

CDP 地址解析流程图 证书文件 解析 CDP 扩展 提取 URI 列表(可能多个) HTTP:// 地址 LDAP:// 地址 file:// 地址 curl 测试 / 浏览器下载 LDAP 查询 / 域控 基本不可用(本地) HTTP 成功率最高,LDAP 次之,file:// 不可用于远程客户端

避坑指南:我曾经踩过的坑

讲几个真实教训,你碰到类似情况就别绕弯了。

  • CDP 里写的是 IP 而不是域名 —— 不少内网 CA 图方便直接填了 IP。一旦发生网络规划变更,IP 被回收,CRL 瞬间全崩。我建议任何生产的 CDP 都要用域名,并且做 DNS 冗余。
  • 多个 CDP 指向同一个域名但不同路径 —— 有些 CA 为了让负载均衡,写了好几个 URL,但实际解析到同一台服务器。一旦那台服务器挂了,所有地址都废了。最好保证不同地址在不同网络区域或 CDN 上。
  • .crl 文件实际是 DER 格式但 URL 后缀是 .pem —— 大多数客户端在下载时根据 Content-Type 判断,不看后缀。但老旧设备(尤其是一些嵌入式系统)必须靠后缀来识别。我遇到过打印机只认 .crl 后缀,给它 .pem 直接拒绝下载。

总结一句话: 定位 CRL 下载地址,核心就是找到 CDP 扩展里所有 URI,然后逐一验证可达性。不要只依赖 OpenSSL 文本输出,要实际发起 HTTP 请求或 LDAP 查询。地址格式哪怕错一个字符,CRL 分发就全盘卡死。