错误信息
verify error:num=20:unable to get local issuer certificate
也可能输出为
- Verify return code: 20 (unable to get local issuer certificate)
- error 20 at 0 depth lookup: unable to get local issuer certificate
s_client 在握手期间输出“verify error:num=20:…”,并在汇总信息中输出“Verify return code: 20 (…)”;openssl verify 输出“error 20 at <depth> depth lookup: …”。默认情况下,s_client 遇到验证错误后会继续执行;加上 -verify_return_error 可以让它直接失败。
OpenSSL CLI (openssl s_client / openssl verify) — X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
含义
OpenSSL 错误 20(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY):构建证书链时,OpenSSL 遇到了一张找不到颁发者的证书——服务器发送的证书中没有,信任库中也没有。紧接在错误之前输出的 depth 行指出了缺少颁发者的是哪张证书。curl 的 (60)、Python 的 CERTIFICATE_VERIFY_FAILED 和 Node.js 的 UNABLE_TO_GET_ISSUER_CERT_LOCALLY 背后都是这个代码。
原因
证书链终止于不在信任库中的根证书
常见私有根证书或公司根证书(或者只发送自己中间证书的 TLS 检查代理)。深度最大的那一行列出的是一张中间证书,而你没有它的颁发者证书。
服务器没有发送中间证书
常见只出现了 depth=0,且其颁发者是中间 CA。OpenSSL 从不下载缺失的中间证书,所以服务器必须发送它们。
测试时没有使用信任库
偶见只给 openssl verify 一张证书,或者在没有 ca-certificates 的镜像中运行 s_client 时,即使是公共网站,也没有根证书可以用来补全证书链。
修复方法
- 1.
查看 depth 行
深度 0 是服务器的证书,更大的数字是服务器发送的中间证书。错误之前的最后一行 depth 就是缺少颁发者的那张证书。
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>&1 | grep -E '^depth|verify' # depth=1 CN=Example Corp Issuing CA <- the highest certificate received # verify error:num=20:... <- its issuer is not in the trust store - 2.
用预期的根证书测试
用 -CAfile 指定正确的根证书(并加上 -verify_return_error,让失败直接中止),就能看出该根证书能否补全证书链;“Verify return code: 0 (ok)”表示可以。
bash # Verify against a specific root (exit code and "Verify return code: 0 (ok)" confirm it) echo | openssl s_client -connect api.example.com:443 -servername api.example.com \ -CAfile corp-root-ca.pem -verify_return_error 2>&1 | grep 'Verify return code' - 3.
离线验证证书文件
把根证书作为 -CAfile、中间证书作为 -untrusted 传给 openssl verify;单独一张叶子证书无法验证。
bash # Offline: root as trust anchor, intermediate(s) as untrusted helpers openssl verify -CAfile corp-root-ca.pem -untrusted intermediate.pem server.pem - 4.
把根证书安装到系统信任库
如果证书链本来就应该终止于公司根证书,就把它添加到发行版的信任库中;之后这台机器上基于 OpenSSL 的工具都会信任它。
bash sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt sudo update-ca-certificates # openssl reads /etc/ssl/certs by default on Debian/Ubuntu
相关错误
verify error:num=21:unable to verify the first certificateOpenSSL CLI (openssl s_client)verify error:num=19:self-signed certificate in certificate chainOpenSSL CLI (openssl s_client / openssl verify)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local…Python ssl module (OpenSSL)