证书链追溯不到受信任的根:新根交叉签名与私有 CA
浏览器打得开,curl、旧安卓或 Java 客户端却说找不到颁发者证书。
这条结论的意思很具体:服务器发来的链,最上面那张证书的颁发者,不在验证方的信任库里。链断在了半空中,而不是「这家 CA 有问题」。
两种完全不同的成因,修法也完全不同。绝大多数情况是第一种:链没发全。CA 启用新根时会用旧根交叉签名一份,少了这一张,尚未收录新根的客户端就接不上。第二种才是真的由私有 CA 签发。
先分清是哪一种
看颁发者是不是一家公开 CA。如果证书是 Let's Encrypt、DigiCert、Sectigo、Amazon 这类签的,那就是第一种——链没发全,不是 CA 不受信任。
echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null | grep -c 'BEGIN CERTIFICATE'2 张通常就是问题所在:服务器只发了「证书 + 中间证书」。3 张说明它还发了交叉签名的那一张,这是新根切换期间正确的做法。
别用浏览器判断。浏览器和操作系统的信任库更新得快,新根往往已经收录,所以浏览器一切正常——而旧安卓、旧 Java、嵌入式设备、部分 CI 镜像会失败。这正是这类问题最难被发现的原因。
成因一:新根切换期,链少发了交叉签名证书
CA 启用一个新根时,新根自己有一份自签名版本,同时会用已经被广泛信任的老根再签一份。这份「交叉签名」的副本让还没收录新根的客户端也能一路验到老根。
| 服务器发送 | 有新根的客户端 | 没有新根的客户端 |
|---|---|---|
| 证书 + 中间证书 | 通过 | 失败——链断在中间证书 |
| 证书 + 中间证书 + 交叉签名根 | 通过 | 通过——经交叉签名接到老根 |
所以链上会出现一张名字里带 Root、却被标成「中间证书」的东西。这不是标错:那一份不是自签名的,它的颁发者是老根,它在这条链里承担的正是中间证书的角色。
怎么修
- 用 CA 给的完整链文件部署,通常叫
fullchain.pem,而不是只有一张的cert.pem。 - nginx 的
ssl_certificate就应该指向 fullchain 文件——它期望「证书在前、中间证书在后」拼在同一个文件里。 - Apache 用
SSLCertificateChainFile,或在新版本里同样把完整链放进SSLCertificateFile。 - 改完重载服务,再用上面那条 openssl 命令确认张数变了。
ssl_certificate /etc/ssl/example.com/fullchain.pem; # 不是 cert.pem
ssl_certificate_key /etc/ssl/example.com/privkey.pem;成因二:确实由私有 CA 签发
如果颁发者是公司内部的 CA、某个自建的根,或者名字你完全没见过,那就是第二种。这时公网访客的浏览器确实不会信任它,而且没有任何服务器配置能改变这一点——信任来自客户端的信任库,不来自服务器。
- 内网服务:把私有根证书装进内网机器的信任库,这是私有 CA 的正常用法。
- 公网服务:必须换成公开 CA 签发的证书。本站基于 Let's Encrypt 的签发是免费的。
- 两者混用:同一个域名在内外网走不同的证书是可行的,但要确认公网那一侧用的是公开 CA。
常见问题
检测一下你自己的域名
免登录,一次真实的 TLS 握手,直接给出结论:还有多少天到期、证书链是否完整、是否包含这个域名。
需要一张新证书?本站提供基于 Let's Encrypt 的免费签发,支持泛域名。
了解免费证书其他排错指南
- 证书过期了怎么办浏览器拦下访问,提示证书已过期或连接不是私密连接。
- 证书快到期了:先分清是没续期,还是续了没部署证书还没过期,但剩余天数已经不多了。
- 证书还没到生效时间:多半是时钟不对证书的生效时间还没到,被判定为无效。
- 证书透明度日志里出现了没见过的证书监控期间,域名下出现了不是本站签发的新证书。
- 无法连接:证书检测连不上服务器时的排查顺序检测连不上服务器,没能拿到证书。
- 「您的连接不是私密连接」:先找错误代码,再决定修哪里浏览器弹出红色警告拦下访问,但不知道属于哪一种证书问题。
- 关闭 TLS 1.0 / 1.1,只留 1.2 和 1.3服务器还在使用 TLS 1.0 或 1.1 协商连接。
- 证书不包含这个域名:ERR_CERT_COMMON_NAME_INVALID 的几种成因浏览器提示证书不适用于该网站,或者拿到了另一个站点的证书。
- 电脑打得开、手机 App 报证书错误:证书链缺少中间证书电脑浏览器打得开,手机 App、curl 或 Java 客户端却报证书错误。
- OCSP stapling:开了能快一点,不开也不算故障没有启用 OCSP stapling,首次握手会稍慢一些。
- 证书被吊销,或者链验证没通过证书被吊销,或者链验证没有通过。
- 自签名证书:什么时候没问题,什么时候必须换证书是自己签给自己的,浏览器不信任。
- RSA 密钥长度不足:为什么现在才被提醒证书的 RSA 密钥长度低于 2048 位。
- 泛域名证书为什么不覆盖主域名子域名都正常,直接访问主域名却报证书错误。
Last updated on