怎么通过在 Nginx 中整合三方国密模块实现 SM2 SM3 SM4 国密标准证书的合规落地部署

作者:袖梨 2026-06-23
Nginx原生不支持SM2/SM3/SM4,必须替换为GMSSL或TASSL等国密增强版OpenSSL并重新编译Nginx,再配置SM2双证书、TLCP协议及国密套件(如ECDHE-SM2-SM4-CBC-SM3)方可实现合规国密TLS握手。

在 Nginx 中直接原生支持 SM2/SM3/SM4 国密算法并不可行,因为官方 Nginx 依赖 OpenSSL(截至 3.0 版本仍不支持国密套件),而 OpenSSL 官方主线至今未集成 SM2/SM3/SM4。要实现国密合规落地,核心路径是:**替换底层密码库为支持国密的 OpenSSL 兼容分支(如 gmssl 或 tassl),再基于其重新编译 Nginx,并配置国密证书与 TLS 协议栈**。

使用国密增强版 OpenSSL 替代标准 OpenSSL

这是整个方案的前提。推荐两个成熟分支:

  • GMSSL(https://github.com/gmssl/gmssl):国内广泛使用的开源国密实现,完整支持 SM2 签名/密钥交换、SM3 哈希、SM4 加解密,并提供兼容 OpenSSL 1.1.1 接口的动态库;
  • TASSL(由江南天安维护):企业级增强版,对国密硬件模块(如 USBKey、PCIe 密码卡)支持更完善,适合高安全要求场景。

部署时需卸载系统默认 OpenSSL 开发包,下载对应分支源码,启用国密选项编译安装(例如 GMSSL 编译时加 --enable-sm2 --enable-sm3 --enable-sm4),确保 pkg-config openssl --modversion 返回的是 GMSSL 版本号。

重新编译 Nginx 并启用国密 TLS 支持

Nginx 本身不内置 TLS 实现,而是通过 configure 阶段链接 OpenSSL 库。需确保:

  • configure 时显式指定国密 OpenSSL 路径:./configure --with-openssl=/path/to/gmssl --with-openssl-opt=enable-sm2(部分版本需额外加 --with-http_ssl_module);
  • 编译后验证是否链接正确:ldd objs/nginx | grep ssl 应指向 GMSSL 的 libssl.so;
  • 启动后检查支持的 cipher list:nginx -V 2>&1 | grep -i sm 或用 openssl s_client -connect localhost:443 -cipher "SM2-SM4-SM3" 测试握手能力。

准备与配置国密证书链(SM2 证书 + SM3 证书签名)

国密 HTTPS 要求整条信任链均使用 SM2 公钥和 SM3 摘要:

  • 服务端证书必须为 SM2 公钥 + SM3 签名(不能是 RSA 公钥配 SM3 签名,也不支持混合签名);
  • 中间 CA 和根 CA 证书也须为 SM2/SM3 格式,且需按顺序拼接进 ssl_certificate 文件(PEM 格式,先服务端证书,再中间证书);
  • 私钥需为 SM2 格式(PEM 中以 -----BEGIN EC PRIVATE KEY----- 或 GMSSL 特有的 -----BEGIN SM2 PRIVATE KEY----- 开头),且无加密口令(Nginx 不支持解密带密码的国密私钥)。

示例配置片段:

server {    listen 443 ssl;    ssl_certificate /etc/nginx/ssl/gm_server.crt;   # SM2 证书 + 中间证书    ssl_certificate_key /etc/nginx/ssl/gm_server.key; # SM2 私钥    ssl_protocols TLSv1.1 TLSv1.2;    ssl_ciphers ECDHE-SM2-SM4-CBC-SM3:SM2-SM4-CBC-SM3;    ssl_prefer_server_ciphers on;}

客户端兼容性与协议协商控制

纯国密 TLS(仅 SM2/SM4/SM3)仅被国产浏览器(如 360 安全浏览器国密版、红莲花浏览器)及部分政务客户端支持。生产环境建议采用双证书+双协议策略:

  • 部署两套证书:一套 SM2/SM3 证书用于国密客户端,一套 RSA/ECC 证书用于国际客户端;
  • 利用 Nginx 的 ssl_certificate_by_lua*(需集成 ngx_lua)或上游负载层(如自研 TLS 分流网关)根据 ClientHello 中的 cipher suites 列表识别国密能力,动态选择证书;
  • 若仅用 OpenResty,可借助 lua-resty-core 的 SSL API 在证书回调中判断 ssl.client_hello():ciphers() 是否含 0x00, 0x9A(SM2-SM4-SM3 的 IANA 注册值)来切换证书。

相关文章

精彩推荐