1724 字
约 5 分钟
6
S02-J02 · TLS 深水区:握手细节、证书链、双向认证与常见错误

适用读者:遇到 SSLHandshakeException、certificate verify failed、mTLS 配置卡住的人。
前置:S02-B06(HTTP 与 HTTPS)。
实测环境:OpenSSL 3.x / Ubuntu 24.04.1;自签 CA、证书链、验证失败均为 2026-11-05 实测。
覆盖旧文:—(E 驱动;B06 的证书链在此深化)
覆盖扩展:E-S02-023(mTLS)、E-S02-011 深化(TLS 1.3 / 0-RTT)。
上一篇:S02-J01 · TCP 排障与调优:抓包、重传、TIME_WAIT 与内核参数
下一篇:S02-J03 · 实时通信工程。


1. 一句话结论

TLS 报错只有三大类,先分类再动手:

类别 典型报错 病因
链不可信 unable to get local issuer certificate(num=20) 中间证书缺失 / 根不受信任
主机名不匹配 hostname mismatch(num=62) SAN 里没有你访问的域名
过期/未生效 certificate has expired(num=10) 时间不在有效期内

外加两类"配置类":协议/套件不匹配、mTLS 客户端证书缺失。


2. 实测:自建 CA,复现两类错误

2.1 生成 CA 与服务器证书

# 1) 自签 CA
openssl req -x509 -newkey rsa:2048 -nodes -keyout ca.key -out ca.crt -days 2 -subj "/CN=Demo Test CA"

# 2) 服务器证书请求
openssl req -newkey rsa:2048 -nodes -keyout srv.key -out srv.csr -subj "/CN=localhost"

# 3) 用 CA 签发,并注入 SAN
cat > san.cnf <<'EOF'
subjectAltName=DNS:localhost,IP:127.0.0.1
EOF
openssl x509 -req -in srv.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out srv.crt -days 2 -extfile san.cnf

2.2 验证成功(客户端带正确 CA)

openssl s_server -accept 19040 -cert srv.crt -key srv.key -www &
echo | openssl s_client -connect 127.0.0.1:19040 -servername localhost \
      -CAfile ca.crt -verify_hostname localhost -verify_return_error

实测输出:

subject=CN = localhost
Verification: OK
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Verify return code: 0 (ok)

2.3 验证失败:客户端不信任这个 CA

echo | openssl s_client -connect 127.0.0.1:19040 -servername localhost -verify_return_error

实测输出:

verify error:num=20:unable to get local issuer certificate
Verification error: unable to get local issuer certificate
Verify return code: 20 (unable to get local issuer certificate)

num=20 的含义:客户端沿着链往上找,找不到签发者的证书——要么中间证书没下发,要么根不在信任库。

2.4 验证失败:主机名不匹配

$ openssl verify -CAfile ca.crt -verify_hostname example.com srv.crt
CN = localhost
error 62 at 0 depth lookup: hostname mismatch
error srv.crt: verification failed

num=62:链是可信的,但证书里的名字(SAN)不包含你访问的名字。

关键:这两类错误修法完全不同——num=20 补链/换信任库,num=62 重新签发证书。先看错误码,别猜。


3. 证书链:为什么"只配服务器证书"会失败

叶证书(你的服务器)  ──签──►  中间 CA  ──签──►  根 CA(客户端内置)

服务器必须下发"叶 + 中间",根由客户端自带。

配置 结果
只下发叶证书 客户端可能找到中间证书(有缓存则成功),否则 num=20
叶 + 中间 ✅ 标准做法
叶 + 中间 + 根 也能用,但多了几百字节,且根不该由服务器下发

Nginx 配置示例:

ssl_certificate     /etc/nginx/ssl/fullchain.pem;   # 叶 + 中间
ssl_certificate_key /etc/nginx/ssl/privkey.pem;

自检命令(部署后必做):

openssl s_client -connect <域名>:443 -servername <域名> -showcerts | grep -E "^ *[0-9] s:|^ *[0-9] i:"
# 期望:至少两层(叶 → 中间 → 根)

4. TLS 1.3 与 0-RTT 的边界(E-S02-011 深化)

特性 说明 风险
1-RTT 握手 首包即带密钥协商,比 1.2 少一轮 无
0-RTT 复用会话时可在第一个包带数据 可被重放 → 只用于幂等请求
证书加密传输 1.3 中证书在加密通道内 抓包只能看到 SNI(域名)
强制前向安全 只允许 (EC)DHE 老客户端/老服务端不兼容(需 1.2 兜底)

配置建议:

ssl_protocols TLSv1.2 TLSv1.3;      # 保留 1.2 兜底
ssl_prefer_server_ciphers off;       # TLS1.3 下无需指定套件

5. mTLS(双向认证,E-S02-023)

普通 TLS:客户端验证服务端。
mTLS:双方互相验证(服务端也要求客户端出示证书)。

ssl_client_certificate /etc/nginx/ssl/ca.crt;   # 用于验证客户端证书的 CA
ssl_verify_client on;                            # 或 optional
项 说明
客户端证书由同一个或受信的 CA 签发 否则服务端验证失败
服务端要显式开启 ssl_verify_client 默认不验证客户端
证书里要有 clientAuth 用途 否则 unsupported certificate purpose
常见错误 400 No required SSL certificate was sent → 客户端没带证书

适用场景:内部服务间、合作伙伴 API、IoT 设备接入。
不适用:面向公众的网站(用户体验成本太高)。


6. 错误码速查

错误码 含义 处置
num=10 证书过期 续期;检查服务器时间
num=18 自签证书 把该 CA 加入信任库(仅测试)
num=20 找不到签发者 补中间证书 / 换信任库
num=19 自签证书在链中 同上
num=62 主机名不匹配 证书 SAN 加该域名
alert handshake failure 无共同协议/套件 放宽 ssl_protocols/ciphers
no shared cipher 同上(服务端) 检查需 ECDSA 还是 RSA
unsupported certificate purpose 证书用途不对 重签(加 clientAuth)

7. 五个误区

误区 真相
"证书配置好了就一定能连" 链、主机名、时间、用途四项都要对
"自签证书加到信任库就安全" 信任库加错根 = 对所有站点失去保护
"TLS 1.3 一定比 1.2 快" 首次握手快;但兼容性与中间设备支持要验证
"mTLS 就是加个客户端证书" 还要 CA 链、用途、服务端开关三件配套
"报错是服务端问题" num=20/62 里,一半是客户端信任库或域名问题

8. 自检

  1. num=20 与 num=62 分别该怎么修?
  2. 为什么服务器要下发中间证书、而不下发根证书?
  3. 0-RTT 为什么不能用于下单?
  4. mTLS 里"Nginx 配了证书但客户端连不上",最可能漏了哪一项?
  5. 部署新证书后,用哪条命令 30 秒内验证链完整?

9. 下一篇

S02-J03 · 实时通信工程:连接数、心跳、消息可靠性与水平扩展

TLS 之后回到连接本身:一台机器到底能扛多少长连接、内存怎么估、扇出怎么算、怎么水平扩展。下一篇给出估算式与实测约束(fd 上限、内核缓冲)。


本篇属于系列《S02 · 计算机与网络基础》。扩展点 E-S02-011/023。自建 CA、num=20、num=62 均为 2026-11-05 实测。

S02-J02 · TLS 深水区:握手细节、证书链、双向认证与常见错误
https://www.clxhxhhr.top/posts/5193/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。