构建可信证书链:OpenSSL证书验证失败的原因及修复方案
问题场景
创建了一条包含4个证书的信任链:rootCA.crt->A.crt->partner.crt->sm.crt,创建命令如下:
openssl req -x509 -sha256 -days 356 -nodes -newkey rsa:2048 -subj "/CN=www.aaa.com /C=US/L=San Fransisco" -keyout rootCA.key -out rootCA.crt openssl genrsa -out A.key 2048 openssl req -new -key A.key -out A.csr -config csr.conf openssl x509 -req -in A.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out A.crt -days 365 -sha256 -extfile cert.conf openssl genrsa -out partner.key 2048 openssl req -new -key partner.key -out partner.csr -config csr_partner.conf openssl x509 -req -in partner.csr -CA A.crt -CAkey A.key -CAcreateserial -out partner.crt -days 365 -sha256 -extfile cert_partner.conf openssl x509 -req -in sm.csr -CA partner.crt -CAkey partner.key -CAcreateserial -out sm.crt -days 365 -sha256 -extfile cert_sm.conf
使用以下命令验证证书可信度:
openssl verify -CAfile rootCA.crt -untrusted A.crt partner.crt sm.crt
得到错误:
error 20 at 0 depth lookup: unable to get local issuer certificate error partner.crt: verification failed error 20 at 0 depth lookup: unable to get local issuer certificate error sm.crt: verification failed
失败原因
中间证书链传递不完整:
验证partner.crt时,它的签发者是A.crt,而验证sm.crt时,需要完整的中间链(A.crt→partner.crt)才能追溯到根证书rootCA.crt。原命令中仅将A.crt设为非受信任中间证书,partner.crt被当作待验证目标,导致验证时无法找到它的上级签发证书;验证sm.crt时同样缺少partner.crt这条中间链。命令参数使用逻辑错误:
openssl verify的参数规则是:-CAfile指定受信任的根证书,-untrusted指定所有需要的中间证书(需按从根下一级到待验证证书上一级的顺序),最后是待验证的目标证书。原命令同时将partner.crt和sm.crt作为待验证目标,但未提供足够的中间链支持两者的验证。潜在的subject/issuer匹配问题:
根证书rootCA.crt的subject包含多余空格(/CN=www.aaa.com /C=US),如果后续签发的A.crt的issuer未完全匹配这个格式(包括空格),也会导致链验证失败。
修复方法
方法1:合并中间证书为链文件
先将所有中间证书按顺序合并成一个链文件,再进行验证:
# 合并A.crt和partner.crt为中间链文件 cat A.crt partner.crt > intermediate_chain.crt
分别验证每个证书:
# 验证partner.crt openssl verify -CAfile rootCA.crt -untrusted A.crt partner.crt # 验证sm.crt openssl verify -CAfile rootCA.crt -untrusted intermediate_chain.crt sm.crt
方法2:按顺序传递所有中间证书
无需合并文件,直接在-untrusted参数后按顺序列出所需中间证书:
# 验证partner.crt openssl verify -CAfile rootCA.crt -untrusted A.crt partner.crt # 验证sm.crt openssl verify -CAfile rootCA.crt -untrusted A.crt -untrusted partner.crt sm.crt
额外检查:确保subject与issuer完全匹配
检查每一级证书的subject和下一级的issuer是否完全一致:
# 查看rootCA的subject openssl x509 -in rootCA.crt -noout -subject # 查看A.crt的issuer openssl x509 -in A.crt -noout -issuer # 查看A.crt的subject openssl x509 -in A.crt -noout -subject # 查看partner.crt的issuer openssl x509 -in partner.crt -noout -issuer
如果发现不一致(比如多余空格),需重新签发对应证书,确保subj参数完全匹配上级证书的subject。
内容的提问来源于stack exchange,提问作者vico

