证书链顺序错误会导致tls握手失败,必须严格按“叶证书→中间ca→根ca”拼接,首块须为sm2签名的域名证书,可用gmssl s_client和openssl命令验证顺序及完整性。

当 Nginx 配置国密双证书(SM2 服务器证书 + SM2 CA 证书)时,若证书链顺序错误(例如将 CA 证书放在服务器证书前面),会导致 TLS 握手失败,典型表现为客户端(如国密浏览器、GMSSL 工具)报 ssl_handshake_failure 或直接断连,而 Nginx 错误日志中通常只显示 SSL_do_handshake() failed,无明确提示——这正是排查难点。
确认证书链顺序是否合规
国密双证书要求严格遵循“叶证书 → 中间 CA → 根 CA”自上而下顺序拼接(即服务器证书在最前,CA 证书在后),且所有证书必须为 SM2 算法、含正确国密扩展(如 SM2-with-SM3 签名、GMT 0009 兼容格式)。常见错误是把 CA 文件内容写在 server.crt 前面,或用 cat ca.crt server.crt > bundle.crt 导致顺序颠倒。
- 用
openssl x509 -in server.crt -text -noout | grep "Signature Algorithm"确认首张证书是 SM2 签名的服务器证书 - 执行
openssl crl2pkcs7 -nocrl -certfile bundle.crt | openssl pkcs7 -print_certs -text -noout查看实际加载的证书链顺序 - 若输出中第一张证书 Subject 不是你的域名,而是 CA 名称,说明顺序已错
启用 Nginx SSL 调试日志定位握手卡点
默认 error_log 级别不输出 TLS 握手细节。需临时提升日志级别并开启 SSL 模块调试:
- 在
nginx.conf的events或http块中添加:error_log /var/log/nginx/error.log debug; - 确保编译时已启用
--with-debug(可通过nginx -V 2>&1 | grep debug验证) - 重启后复现问题,搜索日志中的
SSL_do_handshake、SSL_alert、no suitable certificate等关键词 - 特别关注类似
SSL_get_servername: NULL或SSL_CTX_use_certificate_chain_file() failed的报错
用 GMSSL 工具模拟握手并验证证书链
普通 OpenSSL 不支持国密套件,必须使用 GMSSL(或支持 SM2/SM4 的定制版 OpenSSL)主动测试:
- 运行:
gmssl s_client -connect your-domain.com:443 -cipher ECDHE-SM2-SM4-CBC-SM3 -servername your-domain.com - 观察输出中
Certificate chain部分是否完整、顺序是否正确;若只显示 1 张证书或报verify error:num=20:unable to get local issuer certificate,说明链不完整或顺序错 - 配合
-debug参数可看到更细粒度的握手消息交换,重点关注Certificate握手包里发送的证书数量和顺序
检查 Nginx 配置中证书与密钥的对应关系
国密双证书常伴随双密钥(SM2 服务器私钥 + 对应 CA 私钥不参与传输),但 Nginx 仅加载 server.key。易错点包括:
- 误将 CA 的私钥(ca.key)当作
ssl_certificate_key配置,导致私钥与证书不匹配 - SM2 私钥未用 PEM 格式且含完整 BEGIN/END 块(部分国密工具导出的是 DER 或无头尾格式)
- 确认
ssl_certificate指向的是拼好的 bundle.crt(server.crt + ca.crt),ssl_certificate_key指向的是 server.key,二者算法和公私钥必须严格配对 - 可用
gmssl pkey -in server.key -pubout -text和gmssl x509 -in server.crt -pubkey -noout对比公钥是否一致











