OpenSSL CLI (openssl s_client / openssl verify)OpenSSL CLI
错误信息
verify error:num=19:self-signed certificate in certificate chain
也可能输出为
- verify error:num=19:self signed certificate in certificate chain
- error 19 at 2 depth lookup: self-signed certificate in certificate chain
OpenSSL 3.x 输出“self-signed”,1.1.1 输出“self signed”。openssl verify 将其报告为“error 19 at <depth> depth lookup: …”,其中的深度就是根证书在证书链中的位置。
OpenSSL CLI (openssl s_client / openssl verify) — X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
含义
OpenSSL 错误 19(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN):证书链一直构建到了对端发来的自签名根证书,而这个根证书不在信任库中。与错误 18 不同,这里存在真正的 CA 层级;与错误 20 不同,这里什么都不缺。要么在本地信任这个根证书,要么连接正在被拦截。
原因
执行 TLS 检查的代理
常见企业代理会在证书链中发送自己的根证书。如果最顶端证书的主体是你的公司或某家安全厂商,说明连接正在被检查。
服务器发送了私有 CA 的根证书
常见内部服务常常发送包括根证书在内的完整证书链;客户端仍然需要把根证书安装为信任锚。
测试时没有使用预期的信任库
偶见测试时如果 -CAfile 指向了错误的文件,或者所用镜像的信任库中没有公司根证书,那么即使内部服务配置正确,也会报出这个错误码。
修复方法
- 1.
确认根证书及其指纹
拆分服务器提供的证书链,输出每张证书的主体、颁发者和 SHA-256 指纹;把根证书的指纹与你的 IT 或 PKI 团队公布的指纹比对。
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | awk '/BEGIN CERT/{n++} {print > ("cert" n ".pem")}' for f in cert[0-9]*.pem; do openssl x509 -in "$f" -noout -subject -issuer -fingerprint -sha256 2>/dev/null; done - 2.
先用正确的根证书测试,再安装它
如果用 -CAfile 指定公布的根证书后得到“Verify return code: 0 (ok)”,就把该根证书安装到系统信任库中。
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com \ -CAfile corp-root-ca.pem 2>&1 | grep 'Verify return code' sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt && sudo update-ca-certificates - 3.
服务器所有者:只发送叶子证书和中间证书
发送根证书只会让每次握手多传输一些字节,并不能让它因此受信任;应当把根证书分发给客户端。
bash # Server owners: the root does not belong in the served chain cat server.pem intermediate.pem > fullchain.pem
相关错误
verify error:num=18:self-signed certificateOpenSSL CLI (openssl s_client / openssl verify)verify error:num=20:unable to get local issuer certificateOpenSSL CLI (openssl s_client / openssl verify)curl: (60) SSL certificate problem: self-signed certificate in certificate chaincurl (OpenSSL backend)self-signed certificate in certificate chainNode.js tls / https / fetch