3. OCSP 响应结构:响应格式、状态码与签名验证
拿到一条 OCSP 响应,你怎么判断它是真是假?我最早做溯源分析时,经常盯着十六进制报文发愣——后来才明白,只要拆开三层就够了:响应外壳、状态码、签名链。这章我就带你把这三层逐个扒开。
3.1 响应格式:ASN.1 包了啥
OCSP 响应用 DER 编码,打包在 Content-Type: application/ocsp-response 里。最外层是一个 OCSPResponse 结构:
OCSPResponse ::= SEQUENCE {
responseStatus OCSPResponseStatus,
responseBytes [0] EXPLICIT ResponseBytes OPTIONAL
}
OCSPResponseStatus ::= ENUMERATED {
successful (0), -- 正常
malformedRequest (1), -- 请求畸形
internalError (2), -- 内部错误
tryLater (3), -- 稍后再试
-- (4) 未使用
sigRequired (5), -- 必须签名
unauthorized (6) -- 未授权
}
ResponseBytes ::= SEQUENCE {
responseType OBJECT IDENTIFIER,
response OCTET STRING -- 实际是 BasicOCSPResponse 的 DER
}
responseStatus 不是 successful(0),后面就不用看了。状态不对,直接跳过。
responseStatus,如果是 1、2、3、5、6,这张响应大概率是错误应答,不用费劲解析后面。
当 responseStatus 是 0,就要钻进 responseBytes。里面含一个 OID 和 OCTET STRING,OID 通常是 1.3.6.1.5.5.7.48.1.1(id-pkix-ocsp-basic),OCTET STRING 解开就是一个 BasicOCSPResponse:
BasicOCSPResponse ::= SEQUENCE {
tbsResponseData ResponseData,
signatureAlgorithm AlgorithmIdentifier,
signature BIT STRING,
certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
}
ResponseData ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
responderID ResponderID,
producedAt GeneralizedTime,
responses SEQUENCE OF SingleResponse,
responseExtensions [1] EXPLICIT Extensions OPTIONAL
}
解析时,我最关注 tbsResponseData 里的 responses 序列——每条 SingleResponse 对应一个证书的状态查询结果。你想想看,高频请求溯源时,这里每条记录都可能是攻击者的目标。
3.2 状态码详解:good、revoked、unknown
状态码写在 SingleResponse 的 certStatus 字段里。三种取值:
| 枚举值 | 含义 | 我在溯源场景中的处理 |
|---|---|---|
good(0) | 证书有效,未吊销 | 可能是正常业务,也可能是攻击者用有效期内的证书做掩护。需要结合请求频率、来源 IP 等特征判断。 |
revoked(1) | 证书被吊销 | 高优先级告警。我曾经见过一个案例,攻击者用已吊销证书反复查询 OCSP 服务器,试图探测吊销时间点。 |
unknown(2) | 响应者不知道这个证书 | 有两种可能:要么请求的证书序列号不在响应者管辖范围,要么是恶意构造的随机序列号——这个在探测行为中非常常见。 |
unknown 不签名,甚至直接返回 unauthorized(6)。如果你在溯源日志里看到大量 unknown 状态,多半是攻击者在扫你的证书库范围。
3.3 签名验证:信任的最后一道关
OCSP 响应本身可以签名,也可以不签名。但 RFC 6960 强烈建议签名。对于溯源来说,不签名的响应几乎不可信。
验证过程分三步:
- 验签算法:从
signatureAlgorithm拿到算法 OID(通常是 sha256WithRSAEncryption 或 ecdsa-with-SHA256),然后用signatureBIT STRING 对tbsResponseData的 DER 编码做验签。 - 验证签名者证书:从
certs字段取签名证书,检查它是否受信任(通常链到已知的 OCSP 响应者根 CA)。我习惯顺带检查证书有效期和吊销状态——避免循环依赖。 - 验证 Nonce(可选但重要):如果请求里带了
nonce扩展,响应里也必须携带相同 Nonce,否则是重放攻击。我在溯源高频请求时,经常通过 Nonce 缺失或不对应来识别伪造响应。
核心逻辑图:下面这张图展示了一条 OCSP 响应从拿到手到判定可信的完整拆解流程。
producedAt 时间戳是否在合理范围内。结果拿到的都是一周前的重放响应,排查了半天才发现。你一定要检查 producedAt 和当前时间的差值,我通常设 5 分钟容忍窗口。
3.4 实战:从一个高频请求日志里提取响应状态
举个例子,你从抓包或 OCSP 服务器日志里看到这样的响应字节。用 OpenSSL 命令就能快速拆解:
# 从 hex 转 DER 文件
echo "3082..." | xxd -r -p > ocsp_resp.der
# 用 openssl 解析
openssl ocsp -respin ocsp_resp.der -text -noverify 2>/dev/null
输出里你会看到:
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
...
Cert Status: good
This Update: Apr 10 14:32:00 2025 GMT
Next Update: Apr 10 14:37:00 2025 GMT
嗯,这里要注意:Cert Status: good 并不等于安全——如果请求来自同一个 IP 每秒发出 100 条这种 good 响应请求,那就是典型的扫描行为。我个人习惯把状态码和请求频率关联起来做基线,超过阈值再告警,否则会被正常业务淹没。
signatureAlgorithm 为 NULL 或弱签名算法(如 MD5)。如果你不做算法强度校验,攻击者可以直接伪造 revoked 响应让客户端拒绝你的合法证书。我在护网行动中遇到过这种攻击手法,还好被签名验证卡住了。
总结一下:一张 OCSP 响应的质量,90% 体现在 responseStatus 是否正确、签名是否可信、Nonce 是否匹配。你做高频请求溯源时,先把这三关过了,再去看状态码。