# OpenSSL 检查证书吊销：OCSP 与 CRL 命令

> 用 OpenSSL 3.x 检查证书吊销状态：找出 OCSP 和 CRL 地址、查询 OCSP、查看装订响应、下载解析 CRL、用 -crl_check 验证，并说明 Let's Encrypt 已停用 OCSP。

Source: https://ssl.sh/zh/cookbook/ocsp-crl/
Last updated: 2026-11-10

证书吊销用来告诉客户端：这张证书虽然没到期，但已经不该再被信任。吊销信息有两种发布方式：OCSP（按证书在线查询）和 CRL（CA 签名的吊销序列号列表）。下面的 OpenSSL 3.x 命令用来找出证书里的吊销地址、查询它们，并用它们验证证书链。注意 Let's Encrypt 已在 2025 年停用 OCSP，它签发的证书只能通过 CRL 检查，背景见 [OCSP 与 CRL 原理](https://ssl.sh/zh/learn/ocsp-and-crl/)。

## 找出 OCSP 地址和 CRL 分发点

OCSP 地址在 AIA（颁发机构信息访问）扩展里，CRL 地址在 CRL 分发点扩展里。

```bash
openssl x509 -in cert.pem -noout -ocsp_uri
openssl x509 -in cert.pem -noout -ext authorityInfoAccess,crlDistributionPoints
```

```text
Authority Information Access: 
    CA Issuers - URI:http://ye2.i.lencr.org/
X509v3 CRL Distribution Points: 
    Full Name:
      URI:http://ye2.c.lencr.org/51.crl
```

这是 2026 年 11 月检查的一张 Let's Encrypt 证书：`-ocsp_uri` 没有任何输出，AIA 里只剩 CA Issuers 地址。CRL 地址末尾是分片编号，因为 Let's Encrypt 把 CRL 拆成了很多小文件。仍在提供 OCSP 的 CA 签发的证书，`-ocsp_uri` 会输出类似 `http://ocsp.example.net` 的地址。

## 向 OCSP 服务器查询

`openssl ocsp` 需要签发者证书、待查证书和 OCSP 地址三样东西。

```bash
openssl ocsp -issuer intermediate.pem -cert cert.pem -url http://ocsp.example.net
```

```text
WARNING: no nonce in response
Response verify OK
cert.pem: good
	This Update: Nov  8 22:09:00 2026 GMT
	Next Update: Nov 15 21:09:00 2026 GMT
```

状态有 `good`、`revoked`、`unknown` 三种。`Response verify OK` 表示响应签名能链到受信任的根；默认信任库里缺这个根时加 `-CAfile root.pem`，只想看一眼可以加 `-noverify`。公网 OCSP 服务大多返回预先签好的响应，不回显随机数，所以会有那条警告，加 `-no_nonce` 可以去掉。`intermediate.pem` 可以用 `-showcerts` 从服务器取，也可以从 CA Issuers 地址下载（见[验证证书链](https://ssl.sh/zh/cookbook/verify-chains/)）。

## 查看完整的 OCSP 响应

`-resp_text` 会打印响应者 ID、证书 ID 以及响应的有效时间窗口。

```bash
openssl ocsp -issuer intermediate.pem -cert cert.pem -url http://ocsp.example.net -resp_text -no_nonce
```

```text
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    Version: 1 (0x0)
    Responder Id: 6A4E50BF98689D5B7B2075D45901794866923206
    Produced At: Nov  8 22:25:24 2026 GMT
    Responses:
    Certificate ID:
      Hash Algorithm: sha1
      Issuer Name Hash: D613075FB6DEA11BDF0182D397E1D37C6E925509
      Issuer Key Hash: 6A4E50BF98689D5B7B2075D45901794866923206
      Serial Number: 0F07FCB7C21FB7667C1BFD9496F28B4C
    Cert Status: good
    This Update: Nov  8 22:09:00 2026 GMT
    Next Update: Nov 15 21:09:00 2026 GMT
```

证书 ID 由签发者名称哈希、签发者公钥哈希和序列号组成，所以签发者证书必不可少。这里的 SHA-1 只是用作标识，不是签名算法。响应只在 This Update 到 Next Update 之间有效，服务器装订了过期响应，严格的客户端会报错。

## 查看服务器装订的 OCSP 响应

`s_client -status` 请求 OCSP 装订，服务器返回了就打印出来。

```bash
openssl s_client -connect www.example.com:443 -servername www.example.com -status < /dev/null 2>/dev/null \
  | sed -n '/OCSP response/,/Next Update/p'
```

```text
OCSP responses: number of responses: 1
======================================
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    ...
    Cert Status: good
    This Update: Nov  9 04:50:45 2026 GMT
    Next Update: Nov 16 04:50:45 2026 GMT
```

显示 `OCSP responses: no responses sent` 表示没有装订，证书没有 OCSP 地址时本来就该如此。证书有 OCSP 地址时，Nginx 是在收到请求后才去取响应的，重载后的第一次请求常常没有装订，多跑一次即可；另外 Nginx 装订需要配置 `resolver`，国内服务器可以用 `223.5.5.5` 或 `119.29.29.29` 这类公共 DNS。3.x 之前的版本显示的是单数形式 `OCSP response: no response sent`。

## 检查证书是否要求必须装订（Must-Staple）

带有 `status_request` 的 TLS Feature 扩展，表示这张证书要求服务器必须装订 OCSP 响应。

```bash
openssl x509 -in cert.pem -noout -ext tlsfeature
```

```text
TLS Feature: 
    status_request
```

没有输出说明不带这个扩展，绝大多数证书都是如此。执行 Must-Staple 的客户端（Firefox 多年来一直如此）在收不到装订响应时会直接拒绝连接。Let's Encrypt 在 2025 年 5 月 7 日停止写入 OCSP 地址的同时，也不再签发 Must-Staple 证书，老配置里如果还有 `--must-staple` 参数要删掉。参见 [Must-Staple](https://ssl.sh/zh/glossary/must-staple/)。

## 保存 OCSP 响应并从文件装订

`-respout` 把 DER 格式的响应写成文件，服务器访问不到 OCSP 服务时可以用它装订。

```bash
openssl ocsp -issuer intermediate.pem -cert cert.pem -url http://ocsp.example.net \
  -no_nonce -respout cert.ocsp
openssl s_server -accept 8443 -cert cert.pem -key key.pem -cert_chain intermediate.pem \
  -status_file cert.ocsp -www
```

```text
Response verify OK
cert.pem: good
	This Update: Nov  9 18:19:28 2026 GMT
```

用 `openssl s_client -connect 127.0.0.1:8443 -status` 测试效果。Nginx 的 `ssl_stapling_file`、HAProxy 的 `.ocsp` 文件都用这种 DER 格式。服务器所在网络访问境外 OCSP 服务不稳定时，这种“离线装订”很实用，但要用 cron 在 Next Update 之前及时刷新。

## 下载并查看 CRL

CRL 通常以 DER 格式通过 HTTP 提供，用 `openssl crl -inform DER` 读取。

```bash
curl -s -o ca.crl http://ye2.c.lencr.org/51.crl
openssl crl -inform DER -in ca.crl -noout -issuer -lastupdate -nextupdate -crlnumber
openssl crl -inform DER -in ca.crl -noout -text | head -25
```

```text
issuer=C=US, O=Let's Encrypt, CN=YE2
lastUpdate=Nov  9 17:52:09 2026 GMT
nextUpdate=Nov 18 17:52:08 2026 GMT
crlNumber=0x18E671E4DCCF25A0
Certificate Revocation List (CRL):
    ...
        X509v3 Issuing Distribution Point: critical
            Full Name:
              URI:http://ye2.c.lencr.org/51.crl
            Only User Certificates
Revoked Certificates:
    Serial Number: 05E7C117F64B64BC83F3691B78C8F454F1B2
        Revocation Date: Sep 24 17:49:02 2026 GMT
    Serial Number: 06D1E637E94367185DAF628054DAD4CED532
        Revocation Date: Aug 17 16:24:19 2026 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code: 
                Key Compromise
```

这个分片约 100 KB，包含 2345 条记录。Issuing Distribution Point 扩展表明它是只覆盖终端证书的分片 CRL。如果 `openssl crl` 报解码错误，说明文件本来就是 PEM，去掉 `-inform DER` 即可。

## 在 CRL 里查找某张证书

取出证书的序列号，到解码后的 CRL 里搜索。

```bash
SERIAL=$(openssl x509 -in cert.pem -noout -serial | cut -d= -f2)
echo "$SERIAL"
openssl crl -inform DER -in ca.crl -noout -text | grep -c "$SERIAL"
```

```text
05688C92AD512A3678DB6355831A0BFBBD32
0
```

结果为 `0` 表示这张证书不在该 CRL 上。两条命令输出的都是不带冒号的大写十六进制，直接 grep 就行。一定要下载证书自己 CRL 分发点里写的那个文件，分片 CRL 查错分片等于没查。

## 验证 CRL 的签名

`openssl crl -CAfile` 检查 CRL 是否由指定的签发者签名。

```bash
openssl crl -inform DER -in ca.crl -CAfile intermediate.pem -noout
```

```text
verify OK
```

显示 `verify failure` 说明 CRL 是另一把密钥签的，比如换代后的另一张中间证书。通过 HTTP 下载的 CRL 用之前一定先验签：它的可信度来自签名，而不是传输通道。

## 带 CRL 检查验证证书链

`openssl verify -crl_check` 用 CRL 检查服务器证书，`-crl_download` 则按证书里的地址自动下载 CRL。

```bash
openssl verify -crl_check -CRLfile ca.crl -untrusted chain.pem cert.pem
openssl verify -crl_check -crl_download -untrusted chain.pem cert.pem
```

```text
cert.pem: OK
cert.pem: OK
```

已吊销的证书会报 `error 23 at 0 depth lookup: certificate revoked`。`-crl_check_all` 还要求中间证书也有 CRL，缺了就报 `error 3 at 1 depth lookup: unable to get certificate CRL`。OpenSSL 3.x 的 `-CRLfile` 能直接读 PEM 和 DER。浏览器里吊销证书显示为 [NET::ERR_CERT_REVOKED](https://ssl.sh/zh/errors/net-err-cert-revoked/)。

## 为私有 CA 运行测试用 OCSP 服务

`openssl ocsp -index` 能基于 `openssl ca` 的数据库应答状态查询，做实验和装订测试足够用了。

```bash
openssl ocsp -index ica/index.txt -port 8888 -rsigner ica/ica.crt -rkey ica/ica.key \
  -CA ica/ica.crt -nrequest 1 &
openssl ocsp -issuer ica/ica.crt -cert old.crt -url http://127.0.0.1:8888 -CAfile root.crt
```

```text
Response verify OK
old.crt: revoked
	This Update: Nov  9 18:19:28 2026 GMT
	Reason: keyCompromise
	Revocation Time: Nov  9 18:18:25 2026 GMT
```

`-port` 只接受端口号（写成 `127.0.0.1:8888` 会报错），`-nrequest 1` 表示应答一次就退出。它是单线程的，不适合生产环境。私有 CA 和 `index.txt` 的搭建见[搭建私有 CA](https://ssl.sh/zh/cookbook/private-ca/)。
