OpenSSL verify报error 62:证书主机名不匹配与-verify_hostname排查

证书链已经显示OK,加上主机名却报 error 62: hostname mismatch,先别急着重签。链信任回答"谁签的、是否可信",名称验证回答"是不是我要访问的服务"。下面用OpenSSL 1.1.1的参数把这两件事拆开,再检查SNI选证书和Shell退出码。能连上,不等于找对了人。

一、error 62检查的是名称,不是所有TLS问题

error 62是主机名不匹配,常见位置是叶子证书的depth 0;error 20/21则指向链构建问题。错误编号不等于Shell退出码,脚本不能拿进程返回值62当判断条件。多个检查也可能同时失败,要保留完整输出。

这里要纠正一个容易说满的结论:OpenSSL默认名称检查在没有DNS类型SAN时,可以回退到subject的CN;有DNS SAN时,默认不再靠CN补救。现代HTTPS应按SAN部署,RFC 9525不再接受CN-ID。命令行兼容旧证书,不代表浏览器也接受它。

二、把SAN读全,别只截两行

准备叶子证书leaf.pem、受信任根root.pem及中间证书intermediate.pem。fullchain不是天然可信的根库。先确认读的是最终证书,而非CSR或本地另一个同名文件;SAN可能换行,固定截取两行容易漏掉名称。

bash 复制代码
openssl x509 -in leaf.pem -noout -subject -issuer -dates
openssl x509 -in leaf.pem -noout -ext subjectAltName
openssl x509 -in leaf.pem -noout -sha256 -fingerprint

没有DNS SAN但CN匹配时,OpenSSL可能通过;这应当促使你补齐现代客户端需要的SAN,而不是宣布证书通用兼容。记录指纹,后面才能比较"磁盘上的"和"入口发出的"是否同一张。

三、同一份材料,分开验证链与域名

在Bash里逐条运行,分别记录退出码。加入sslserver用途检查;根和中间证书角色不要对调。下例关闭默认CA目录,避免旁边的信任材料干扰结果。

bash 复制代码
HOST=api.example.com
openssl verify -no-CApath -CAfile root.pem -untrusted intermediate.pem \
  -purpose sslserver leaf.pem
printf "chain_rc=%s\n" "$?"
openssl verify -no-CApath -CAfile root.pem -untrusted intermediate.pem \
  -purpose sslserver -verify_hostname "$HOST" leaf.pem
printf "hostname_rc=%s\n" "$?"

只验链通过、带名称失败,才把重心转向目标名称和SAN。HOST只填域名,不带https://、端口或路径。若两条都失败,先处理链和用途;不要靠关闭验证,把红灯拆掉当修好了。

四、连接IP、SNI和验证名是三个输入

连接IP决定去哪里,SNI帮助服务端选择证书,验证名决定客户端接受谁。三者应分别显式设置;固定某个节点IP时,SNI和验证名通常仍是业务域名。HTTP Host属于后续请求路由,不能替代TLS名称验证。

将示例保留地址换成获准检测的节点。下面是独立Bash片段:子Shell关闭errexit,确保失败后仍能保存PIPESTATUS;外层若启用errexit,仍可据其非零状态停止。

bash 复制代码
(
set +e
set -o pipefail
IP=192.0.2.10
PORT=443
SNI=api.example.com
NAME=api.example.com
openssl s_client -connect "$IP:$PORT" -servername "$SNI" \
  -verify_hostname "$NAME" -verify_return_error \
  -no-CApath -CAfile root.pem </dev/null 2>&1 | tee sclient.log
st=("${PIPESTATUS[@]}")
printf "tls_rc=%s log_rc=%s\n" "${st[0]}" "${st[1]}"
(( st[0] == 0 && st[1] == 0 ))
)

普通管道的?可能只是tee成功。pipefail虽能报非零,也不能区分TLS失败还是日志写失败;这里立即复制整个数组,再分别判定。别先echo或保存?,它们会覆盖PIPESTATUS。默认s_client是诊断工具,验证报错后仍可能退出0,所以还要启用verify_return_error并看握手详情。

五、验证IP用verify_ip,别把64写成62

如果访问身份本来就是IP,应匹配iPAddress SAN,不能把IP字符串放进DNS SAN或CN就算数。此时使用专门的参数:

bash 复制代码
openssl verify -no-CApath -CAfile root.pem -untrusted intermediate.pem \
  -purpose sslserver -verify_ip 192.0.2.10 leaf.pem
printf "ip_rc=%s\n" "$?"

IP不匹配是error 64: IP address mismatch,不是error 62。仅仅固定连接IP、但访问身份仍为域名时,不要改用verify_ip。默认完整通配符*.example.com匹配一个左侧标签,不覆盖裸域或a.b.example.com;多个SAN也不豁免链、用途和其他策略检查。

六、换证后仍失败,先确认入口发了什么

别只盯证书文件日期。负载均衡某个节点未更新、SNI选到默认站点,或应用传入了另一个验证名,都可能让本地验证与线上结果分叉。逐入口保留名称、SAN、指纹和时间,不要把一个节点的成功外推给全站。

现象 信号 先做什么
链构建失败 error 20/21 检查根与中间证书
域名不匹配 error 62 核对验证名和DNS SAN
IP不匹配 error 64 检查iPAddress SAN
日志写入失败 log_rc非零 检查路径与空间,勿归因于证书

七、回归要有反例,边界也要写清

正例之外,换错误验证名、错误根,确认探针确实会拒绝;再模拟日志写入失败,避免把磁盘问题报成证书故障。离线验证与回环TLS实验能说明参数行为,不能冒充浏览器或生产验收。本文配套复现限定OpenSSL 1.1.1k、临时根和中间CA,回环握手固定TLS 1.2;不修改系统CA和生产服务。

八、收尾检查与官方依据

收尾保留四组证据:完整SAN与指纹;链和名称各自结果;固定IP、SNI、验证名的严格握手;TLS与日志的独立退出码。修复后回到真实客户端验证HTTP响应和业务行为,证书名称正确不等于授权正确。共享日志前去除内部地址和会话信息,不上传私钥。

参数与规范可核对:OpenSSL verify手册、s_client手册及RFC 9525服务身份规范。老版本实验用于解释行为,不是部署版本建议。

相关推荐
rm -rf * && haha.sh1 小时前
【Linux】Rocky 9.8 操作系统磁盘分区与MySQL数据目录迁移
linux·运维·mysql
吴声子夜歌1 小时前
Nginx应用与运维——Nginx Web服务应用实战(Python网站的搭建)
运维·前端·nginx
资深技术分享员2 小时前
Geejing WebBuilder 数据库连接配置与在线 SQL 工具,运维的左右手
运维·数据库·sql·低代码
高山有多高2 小时前
【Linux笔记】UpdSocket
linux·运维·笔记
皓月盈江2 小时前
Linux系统grep、sed 、awk介绍下,使用方法及区别?
linux·运维·服务器·sed·grep·awk
云栖梦泽2 小时前
Linux内存管理
linux·运维·服务器
吴声子夜歌2 小时前
Nginx应用与运维——Nginx Web服务应用实战(静态文件服务器的搭建)
运维·前端·nginx
海宇服务3 小时前
零信任架构实战:基于海宇身份证OCR构建自动化自助终端核验网关
运维·人工智能·架构·自动化
ken22323 小时前
ubuntu 24.04, audacity 4 AppImage 加载 libavdevice.so.62 /.61 /.63 失败:依赖缺失?
linux·运维·ubuntu