不同OpenSSL版本下证书验证报错error 20:无法获取本地颁发者证书
证书跨版本验证异常根因与修复
问题现象
- 同一套自签根CA、服务器/客户端证书,在Ubuntu 18.04内置的OpenSSL 1.1.1(2018.09构建)环境下可正常通过
openssl verify校验 - 在Ubuntu 20.04内置的OpenSSL 1.1.1f,以及同系列后续小版本(1.1.1g/1.1.1i,Nginx官方镜像内置)环境下,执行相同验证命令会报
error 20 at 0 depth lookup: unable to get local issuer certificate - 服务器证书、客户端证书均存在该问题,直接导致Nginx mTLS场景下的客户端证书校验失败
核心根因
OpenSSL从1.1.1e版本(2020年3月发布,是1.1.1f的基线版本)开始,调整了可信CA证书的校验逻辑:
- 旧版本仅检查CA证书是否携带
keyCertSign权限位,不会校验keyUsage字段的配置合理性 - 新版本会强制校验:如果作为可信CA使用的证书在
keyUsage中包含keyEncipherment或dataEncipherment权限位,就会直接将该证书判定为终端实体证书,从可信CA列表中过滤掉 - 被过滤的根CA自然无法匹配下级证书的颁发者信息,最终触发error 20的“无法获取本地颁发者证书”错误
对照你的证书生成脚本,两个配置问题完全触发了上述严格校验规则:
- 自签根CA的
keyUsage配置错误加入了keyEncipherment、dataEncipherment等终端实体专属权限 - 下级服务器、客户端等终端证书的
keyUsage配置错误加入了keyCertSign、cRLSign等CA专属权限,不符合X.509证书规范
修复步骤
- 调整自签根CA的
keyUsage配置,替换原有全权限列表为仅CA需要的权限:
删除所有终端实体类的权限位(keyEncipherment、dataEncipherment、keyAgreement、encipherOnly、decipherOnly)# 原配置行替换为: -addext "keyUsage = digitalSignature, nonRepudiation, keyCertSign, cRLSign" - 调整下级终端证书的
keyUsage配置,去掉CA专属权限:
删除原有配置中# 服务器证书配置替换为: keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = serverAuth # 客户端证书配置替换为: keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = clientAuthkeyCertSign、cRLSign、keyAgreement、encipherOnly、decipherOnly等不相关的权限位 - 在下级证书的openssl配置段中补充链匹配扩展,避免证书匹配歧义:
subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always, issuer:always - 重新生成整套证书链后,即可同时兼容新旧版本OpenSSL的校验逻辑,Nginx mTLS的客户端证书校验也会恢复正常
补充说明
- 该问题和加密算法兼容性、证书签名强度无关,纯粹是OpenSSL校验规则严格化导致的配置不兼容
- 无需降级OpenSSL版本,按照X.509规范调整证书的权限配置即可全版本兼容
内容的提问来源于stack exchange,提问作者HXK8
相关产品推荐
相关产品推荐

