前言

在使用 HTTPS 或构建 PKI 系统时,证书验证是一个核心环节。OpenSSL 的 verify 命令是验证证书链的利器,理解它的工作原理能帮助我们排查证书问题、正确配置 CA 存储。

本文详细介绍 verify 命令的各种用法,所有命令都经过实际验证。

基本用法

验证单个证书

验证自签名证书(会显示警告但仍可验证):

1
openssl verify self-signed.crt

输出示例:

1
2
error 18 at 0 depth lookup: self-signed certificate
error self-signed.crt: verification failed

验证证书链

验证服务器证书,需要提供 CA 证书:

1
openssl verify -CAfile ca.crt server.crt

输出:

1
server.crt: OK

核心参数详解

-CAfile:指定 CA 证书文件

1
openssl verify -CAfile ca.crt server.crt

当证书链有多个 CA 时,可以串联多个文件:

1
openssl verify -CAfile intermediate-ca.crt -CAfile root-ca.crt server.crt

-CApath:指定 CA 目录

将 CA 证书放入目录(文件名为哈希值):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 创建 CA 存储目录
mkdir -p /etc/ssl/certs/myca
cp ca.crt /etc/ssl/certs/myca/

# 计算哈希值并重命名
cd /etc/ssl/certs/myca
ln -s ca.crt $(openssl x509 -hash -noout -in ca.crt).0

# 使用 CApath 验证
openssl verify -CApath /etc/ssl/certs/myca server.crt

-untrusted:指定中间 CA

当证书链包含中间 CA 时,使用 -untrusted 指定:

1
openssl verify -CAfile root-ca.crt -untrusted intermediate-ca.crt server.crt

完整示例:

1
2
# 验证完整证书链
openssl verify -CAfile root-ca.crt -untrusted intermediate-ca.crt server.crt

输出:

1
server.crt: OK

-partial_chain:允许部分链验证

允许验证到不在存储中的中间 CA:

1
openssl verify -partial_chain -CAfile intermediate-ca.crt server.crt

这在调试证书链时很有用。

-trusted:设置信任锚

-CAfile 类似,但会检查证书的 trust 设置:

1
openssl verify -trusted root-ca.crt server.crt

检查证书 trust 设置

查看证书的 trust 标记:

1
openssl x509 -in ca.crt -noout -text | grep -A2 "TLS Web Client"

添加 trust 标记:

1
openssl x509 -in ca.crt -addtrust clientAuth -out trusted-ca.crt

验证场景实战

场景 1:验证完整证书链

创建测试证书链:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 生成 CA
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -out ca.crt \
    -subj "/C=CN/O=Test CA/CN=Test Root CA"

# 生成中间 CA
openssl genrsa -out intermediate.key 2048
openssl req -new -key intermediate.key -out intermediate.csr \
    -subj "/C=CN/O=Test CA/CN=Test Intermediate CA"
openssl x509 -req -days 180 -in intermediate.csr -CA ca.crt \
    -CAkey ca.key -CAcreateserial -out intermediate.crt

# 生成服务器证书
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
    -subj "/C=CN/O=Test/CN=example.com"
echo "subjectAltName=DNS:example.com" > ext.cnf
openssl x509 -req -days 90 -in server.csr -CA intermediate.crt \
    -CAkey intermediate.key -CAcreateserial -out server.crt -extfile ext.cnf

# 验证完整链
openssl verify -CAfile ca.crt -untrusted intermediate.crt server.crt

输出:

1
server.crt: OK

场景 2:排查证书链不完整

当证书链不完整时:

1
2
# 不提供中间 CA,验证会失败
openssl verify -CAfile ca.crt server.crt

输出:

1
2
error 20 at 0 depth lookup: unable to get local issuer certificate
error server.crt: verification failed

错误代码含义:

错误码 含义
2 无法获取本地颁发者证书
10 证书已过期
18 自签名证书
19 证书链中有自签名证书
20 无法获取本地颁发者证书
21 无法验证证书链

场景 3:提取证书链信息

查看证书链的每一层:

1
2
3
# 提取并显示证书链
openssl crl2pkcs7 -nocrl -certfile server.crt -certfile intermediate.crt | \
    openssl pkcs7 -print_certs -noout

输出示例:

1
2
3
4
5
subject=C = CN, O = Test CA, CN = Test Intermediate CA
issuer=C = CN, O = Test CA, CN = Test Root CA

subject=C = CN, O = Test, CN = example.com
issuer=C = CN, O = Test CA, CN = Test Intermediate CA

场景 4:验证时检查多个 CA 存储

系统 CA 和自定义 CA 配合使用:

1
2
3
4
# 使用系统 CA 加上自定义 CA
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \
    -untrusted custom-ca.crt \
    your-cert.crt

验证结果的返回码

verify 命令会根据验证结果返回不同的退出码:

1
2
3
openssl verify -CAfile ca.crt server.crt
RESULT=$?
echo "验证结果: $RESULT"
返回码 含义
0 验证成功
1 验证失败
2 无法使用,参数错误

常用命令速查表

场景 命令
验证证书链 openssl verify -CAfile root-ca.crt -untrusted intermediate.crt server.crt
使用 CA 目录 openssl verify -CApath /path/to/ca-dir server.crt
允许部分链 openssl verify -partial_chain -CAfile intermediate.crt server.crt
查看证书链 openssl crl2pkcs7 -nocrl -certfile server.crt -certfile chain.crt | openssl pkcs7 -print_certs
验证并显示详情 openssl verify -verbose -CAfile ca.crt server.crt

小结

verify 命令是证书链验证的核心工具:

  1. 基本验证openssl verify -CAfile ca.crt cert.crt
  2. 中间 CA:使用 -untrusted 参数
  3. 调试技巧-partial_chain 允许部分链验证
  4. CA 存储-CApath 支持目录形式的 CA 存储

掌握这些命令,能快速排查证书验证问题,确保 HTTPS 服务的可靠性。


参考来源