OpenSSL verify报unable to get issuer certificate:error 2与partial_chain排查

中间证书明明放进了CA文件,OpenSSL却报unable to get issuer certificate。补了链还不行,是证书坏了,还是信任放错了位置?本文以error 2为入口,区分"提供建链材料"和"指定信任锚",再判断是否真的应该使用-partial_chain。

一、先认完整错误,不只看issuer

error 2的名称是X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,表示查找到的证书缺少可用签发者;常见于信任材料不完整。error 20则是UNABLE_TO_GET_ISSUER_CERT_LOCALLY,涉及未受信任证书的签发者查找。两者英文很像,不能把所有issuer错误都归结为服务器漏发中间证书。

保存depth、subject、参数与退出码。depth 0是目标证书,1是直接签发者,不自动指出该装哪张根。验证错误号不等于进程退出码;以下报错限定本机实验。

二、先把三份材料分清楚

实验采用Root → Intermediate → api.example.test三级链。leaf.pem只放叶证书,intermediate.pem只放中间CA,root.pem只放经核验的根。三者均为PEM证书,不含私钥,也没有额外正负信任属性。文件名叫CA,并不会自动赋予它你期望的信任语义。

-untrusted提供辅助建链材料,不将其中的证书直接变成信任锚;-trusted提供本次验证的信任材料,并排除默认CA文件与目录。本文用它隔离系统信任库,避免"本机刚好已装根证书"掩盖问题。它不能与-CAfile、-CApath混用。OpenSSL 3.x还有CAstore选项,须按对应版本帮助核对。

bash 复制代码
openssl version
openssl x509 -in intermediate.pem -noout -subject -issuer -dates
openssl x509 -in intermediate.pem -noout -fingerprint -sha256
openssl verify -show_chain -trusted intermediate.pem \
  -purpose sslserver -verify_hostname api.example.test leaf.pem

上述最后一条故意只信任普通中间CA,不加-partial_chain;本机1.1.1k FIPS得到error 2 at 1 depth,签发者是未提供的Root。前面的x509仅做单张诊断,subject/issuer名称吻合不等于签名可信。指纹应通过可信渠道与预期材料比对,不能从未知站点抓一张就直接安装。

三、常规修复:回到完整根信任链

如果既定策略信任Root,修复方向就是保留该根为锚,把中间CA放进建链输入,而不是为了绿灯改变终点。下面的命令同时检查服务端用途和域名,-show_chain用于观察最终路径。

bash 复制代码
openssl verify -show_chain -trusted root.pem \
  -untrusted intermediate.pem -purpose sslserver \
  -verify_hostname api.example.test leaf.pem

正常结果应为leaf.pem: OK,并显示叶子、中间CA、根的路径。实验中删去-untrusted后会报error 20,说明"根可信"和"中间链材料齐全"是两件事。给服务端补fullchain可以帮助客户端建链,但服务端发送根证书并不能替客户端做出信任决定。

四、partial_chain改变的是信任终点

当组织明确批准某张中间CA作为本应用信任锚,且已通过受控渠道分发材料,才考虑下面这条路径。该参数允许验证链在信任存储中的非自签证书结束,而不必继续构建到自签根;不是自动补链,也不是"缺什么就忽略什么"。

bash 复制代码
# 仅用于已批准中间CA作为信任锚的独立验证
openssl verify -show_chain -partial_chain \
  -trusted intermediate.pem -purpose sslserver \
  -verify_hostname api.example.test leaf.pem

同一实验此时通过,路径止于Intermediate。它改变了信任边界:终点以上的Root不再是这条验证路径的成员,不能把成功结果描述为"验证到了Root"。原本依赖上级路径的策略需要重新评估,证书轮换、撤销和更新责任也必须明确。

不要直接信任网络抓取的中间证书。先核验来源、授权和指纹;CLI通过不代表应用或浏览器采用相同策略。

五、通过一个正例,还要留下负例

本次在临时目录生成测试链,执行OpenSSL 1.1.1k FIPS;不改系统信任库、时钟或线上配置。仅验证离线路径,不代表真实HTTPS握手。

输入与选项 本机观察
普通中间CA为trusted,不加partial_chain error 2,depth 1
根为trusted,中间CA为untrusted 通过,路径到根
中间CA为trusted,加partial_chain 通过,路径止于中间CA
根为trusted,未提供中间CA error 20,depth 0
partial_chain配错误验证名 error 62,不会跳过名称检查
partial_chain配过期叶证书 error 10,不会跳过时间检查

另测只含clientAuth用途的叶证书,在sslserver验证下失败;换成无关信任根也失败。这些负例用来证明开关没有关闭全部验证,不是穷尽所有PKI约束。生产环境还需按自己的吊销、策略及算法要求验收。

六、别让日志把失败盖住

别只搜索OK,也别让管道吞掉失败。下面保留verify退出状态,日志写入失败也进入失败分支;只写非敏感诊断,不记录私钥或凭据。

bash 复制代码
if openssl verify -show_chain -trusted root.pem \
  -untrusted intermediate.pem -purpose sslserver \
  -verify_hostname api.example.test leaf.pem >verify.log 2>&1; then
  printf 'certificate path verified\n'
else
  rc=$?
  printf 'verification or log write failed: %s\n' "$rc" >&2
  exit "$rc"
fi

隔离实验重放四个代码块,验证错误名称与日志路径不可写均不能输出成功。多目标应逐个记录状态,不能只看最后一个结果。

七、离线OK之后还缺什么

离线验证只证明给定文件在给定选项下成立。实际服务可能发送另一张证书、缺中间链,或应用读取了不同CA路径。上线验收要固定目标、SNI、验证名和真实客户端,重新检查所见证书与信任配置;网络、TLS与HTTP结果分开记录。

不能用关闭TLS验证作验收,也不要把中间CA盲目全局导入。报错消失不等于信任变更合理。

八、交付前检查清单

  • 记录完整错误、depth、版本与真实命令。
  • 区分目标证书、辅助中间链、受信任材料。
  • 先按既有根信任策略补齐链;改变锚必须有依据。
  • 核验show_chain终点、名称、用途、时间与负例。
  • 另做真实客户端验收,保留无凭据日志。

参考:OpenSSL 1.1.1 verify;OpenSSL 3.0信任锚与验证选项;OpenSSL x509诊断。

相关推荐
0+1117 小时前
Linux --从 poll 到 epoll多路转接
linux·服务器·1024程序员节
青瓦梦滋7 小时前
WebSocket协议
linux·服务器·网络·c++·websocket·网络协议·http
2601_9498477510 小时前
bcrypt.js 跨端三方库仓颉适配全流程
linux·运维·ubuntu
m0_6399069410 小时前
Linux 操作系统入门:目录结构、服务排查常用命令、Shell 脚本基础
linux·运维·后端
水饺编程12 小时前
第2章:Linux 基础,exit 命令
linux·c语言·汇编
木子欢儿12 小时前
Debian 13 + vsftpd 搭建FTP服务
linux·服务器·前端·网络·debian
GeW13 小时前
新质生产力落地实践:企业级Linux迁移与数据库国产化
linux
雯宝13 小时前
usb_serial_generic_register
linux
伤心的梧桐叶14 小时前
商品大图断点续传后打不开,先看是不是把完整响应又接了一遍
http·https
疯狂的Meng14 小时前
我把第一周的 Linux 命令整理成了自己的手册(附 7 个我踩的坑)
linux