OCSP 工作原理:请求/响应流程与签名验证
一次真实的 OCSP 对话
OCSP 说白了就是客户端问 CA:“这张证书现在还活着没?”CA 回答:“活着呢”或“挂了”或“我不知道”。就这么简单。但真实场景里,客户端和 CA 之间要交换的信息远不止“是/否”两个字——背后有一套标准化的协议结构,还带了签名保证你能信得过这个回答。
我早期做 PKI 集成的时候,以为 OCSP 就是发个 HTTP GET 回去就完事了。结果线上环境里,某个客户端死活不信任 OCSP 响应,日志里全是“signature verification failed”。查了半天,原来是 CA 那边的 OCSP 响应器签名证书和客户端信任锚没对上。嗯,从那以后我每次对接都先抓包看签名。
OCSP 请求:客户端到底问什么?
请求报文是 ASN.1 编码的 DER 结构。我用 openssl ocsp 命令造一个例子给你看看:
openssl ocsp -issuer intermediate.pem \
-cert target.pem \
-url http://ocsp.example.com \
-text -noverify
这个命令会构造一个 OCSP 请求,里面包含三个核心字段:
- 版本号 – 目前只有 v1(值 0)
- 请求者名称 – 可选。一般留空,不改。
- 请求列表 – 一组
CertID,包含目标证书的 hash 算法、颁发者名称 hash、颁发者公钥 hash、目标证书序列号。
这里有个关键点:请求里 不传证书本身,只传摘要。为什么?为了隐私。你想想,要是每次查询都明文传证书,中间人就能跟踪谁在查谁。我们只给指纹,CA 也能识别。
我个人习惯:生产环境里,OCSP 请求携带
nonce 扩展。nonce 就是个随机数,防止响应被重放。我见过一个客户,没加 nonce,攻击者把昨天的“revoked”响应重放了一遍,导致合法证书被拒了半个月。
OCSP 响应:CA 的回答长什么样?
响应同样用 ASN.1 编码,结构比请求复杂一些。我拆成三步来理解:
- 响应状态 – 最外层:successful 还是 malformedRequest、internalError、tryLater、sigRequired、unauthorized。
- 响应主体 – 成功时才出现。包含版本、颁发者名称 hash、应答时间、证书状态列表(good/revoked/unknown),以及可选的扩展。
- 签名 – 对响应主体做签名,确保完整性和来源。
下面这张流程图把请求→响应的完整路径画清楚了:
签名验证:别被假响应骗了
OCSP 响应如果不带签名,那等于喊了一声“我是好人”——谁都能伪造。所以标准强制要求响应必须签名。但签名不是随便签一签,有一套完整的验证链路。
我按实际排查顺序列一下验证要点:
| 验证步骤 | 具体检查 | 常见翻车点 |
|---|---|---|
| ① 检查响应状态 | 必须是 successful (0),否则直接丢弃 |
遇到 tryLater 不应该无限重试,要退避 |
| ② 验证签名证书 | 证书链完整、未过期、未被吊销 | CA 换了签名证书,但客户端没更新信任锚 |
| ③ 验证 nonce | 响应中的 nonce 与请求一致 | 某些 CA 不支持 nonce,这时要接受无 nonce 的响应 |
| ④ 验签 | 用签名证书公钥验证签名值 | 签名算法不匹配(比如客户端要求 RSA-SHA256,CA 用了 ECDSA) |
| ⑤ 检查 producedAt | 响应时间不能太老(通常不超过 10 分钟) | 时间偏差:客户端系统时间不准,导致把合法响应当成过期 |
我曾经踩过的坑:有一次线上告警说大量证书状态验证失败。我抓包发现 OCSP 响应里证书状态是
good,但客户端就是报错。折腾半天,发现客户端没验证响应签名的证书链——它只检查了签名本身,没检查签名证书是否由受信任的 CA 签发。攻击者可以自己签一个假响应。从那以后,我在代码里加了一条:verify(X509_V_FLAG_PARTIAL_CHAIN) 必须关掉。
几个实战决策
实际部署 OCSP 时,有几个东西需要你根据场景取舍:
- GET 还是 POST? 大部分 CA 支持 GET(查询参数是 Base64 编码的请求 DER)。POST 可以携带更长的扩展,但我推荐优先用 GET,缓存友好。
- 是否开启 Stapling? 如果服务端支持 OCSP Stapling,可以大大减少客户端的额外请求。2017 年之后的主流浏览器都要求 Stapling 的响应时效。我个人习惯:能开就开。
- 超时设置 我一般设 2 秒超时,重试 2 次,失败后走 CRL 兜底。千万别设成 30 秒,用户等不起。
一句话总结:OCSP 的核心就两件事——问得准(CertID 不能错)和信得过(签名必须验完整)。很多线上事故都是签名验证链断了,而不是 CA 真挂了。
好了,这一块你动手抓一次包、自己签一个响应试试,印象会深得多。下次碰到 OCSP 相关的 SSL 握手失败,你就知道从哪里开始查了。