国密 HTTPS 改造实战:SM2/SM4 双证书配置

国密 HTTPS 改造的核心是把 TLS 握手从国际算法体系切到以 SM2、SM3、SM4 为底座的国密体系,同时保留 RSA 证书对外提供兼容访问。国密 HTTPS 改造并不需要改动后端业务代码,只要在 Web 服务或网关层完成双证书加载与 NTLS 协议启用即可。本文给出基于 Tengine + Tongsuo(铜锁)的国密 HTTPS 改造完整配置流程,包含 SM2 双证书生成、签名结构与加密结构分离、配置验证与兼容性处理。

适用场景

  • 政务、金融、能源、医疗等行业的系统需要满足国密算法改造与信创验收要求。
  • 站点需要在保留主流浏览器访问能力的同时,为支持国密协议的客户端提供自主可控的加密通道。
  • 内网系统、专用终端、政务专网客户端已支持 SM2/SM4,需要服务端同步开启。
  • 产品交付时被要求提供「国密算法支持能力」的配置说明与验证报告。

前置条件

  • 服务器已开放 443 端口,域名解析正常,且已完成基础的 HTTPS 可用性验证。
  • Tengine 2.4 及以上,编译时接入 Tongsuo 密码库并加载 ngx_tongsuo_ntls 模块。
  • 国密证书两套:签名证书(用于身份认证与签名)与加密证书(用于密钥交换),两者必须是独立密钥对。
  • 正式环境建议使用具备国密资质的 CA 签发证书;测试环境可用 Tongsuo 自签 CA 生成。
  • 已确认业务侧不需要支持 TLS 1.0/1.1,国密改造通常与协议版本收紧同时执行。

原理说明

国密 TLS(NTLS)与国际 TLS 的差异集中在三处:

  • 算法替换:非对称加密与签名使用 SM2(基于椭圆曲线),摘要使用 SM3,对称加密使用 SM4。
  • 双证书体系:国际 TLS 中一张证书同时承担签名与加密职责,国密体系要求签名证书与加密证书分离,各自独立密钥,私钥分离存放可降低单点泄露的影响范围。
  • 协议标识:Tengine 通过 enable_ntls 开关启用 NTLS 握手,国密握手与国际握手在同一 443 端口上按客户端 ClientHello 自动分流。

兼容策略上推荐 双栈共存:国密客户端走 SM2 签名+SM4 加密套件,普通浏览器走 RSA 证书与国际套件,两者互不干扰,不需要为国密单独开端口或子域名。

操作步骤

1. 编译安装 Tengine 与 Tongsuo

cd /usr/local/src
tar -xzf Tongsuo-8.2.1.tar.gz
tar -xzf tengine-2.4.1.tar.gz
cd tengine-2.4.1

./configure --prefix=/usr/local/tengine \
  --add-module=modules/ngx_tongsuo_ntls \
  --with-openssl=../Tongsuo-8.2.1 \
  --with-openssl-opt="enable-ntls" \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-stream --with-stream_ssl_module

make -j$(nproc) && make install

关键点是 –with-openssl-opt=”enable-ntls”,它让底层密码库开放 NTLS 能力;缺少该参数时 enable_ntls 指令会报未知指令。编译完成后用 /usr/local/tengine/sbin/nginx -V 确认模块与编译参数已包含上述内容。

2. 生成 SM2 双证书(测试环境自签)

cd /usr/local/tengine/conf && mkdir -p cert && cd cert
OSSL=/usr/local/tongsuo/bin/openssl

# 生成 SM2 根 CA
$OSSL ecparam -genkey -name SM2 -out ca.key
$OSSL req -new -x509 -key ca.key -out ca.crt -days 3650 -sm3 \
  -subj "/C=CN/O=Example Security/CN=Example SM2 Root CA"

# 生成签名密钥与 CSRs
$OSSL ecparam -genkey -name SM2 -out sign.key
$OSSL req -new -key sign.key -out sign.csr -sm3 \
  -subj "/C=CN/O=Example Security/CN=www.example.com"

# 生成加密密钥与 CSR
$OSSL ecparam -genkey -name SM2 -out enc.key
$OSSL req -new -key enc.key -out enc.csr -sm3 \
  -subj "/C=CN/O=Example Security/CN=www.example.com"

# 用 CA 分别签发签名证书与加密证书
$OSSL x509 -req -in sign.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out sign.crt -days 3650 -sm3
$OSSL x509 -req -in enc.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out enc.crt -days 3650 -sm3

# 合并证书链
cat sign.crt ca.crt > server_sign.pem
cat enc.crt ca.crt > server_enc.pem
chmod 600 sign.key enc.key ca.key

两套密钥必须分开生成,严禁复用同一密钥对。生产环境把 CA 私钥离线保存,服务器上只放服务端证书与私钥,私钥文件权限设为 600 并由专用账户持有。

3. 配置双证书与 NTLS

server {
    listen 443 ssl;
    server_name www.example.com;

    # 启用国密 NTLS 协议
    enable_ntls on;

    # 国密签名证书
    ssl_sign_certificate      cert/server_sign.pem;
    ssl_sign_certificate_key  cert/sign.key;

    # 国密加密证书
    ssl_enc_certificate       cert/server_enc.pem;
    ssl_enc_certificate_key   cert/enc.key;

    # 国际 RSA 证书,用于兼容普通浏览器
    ssl_certificate           cert/server_rsa.pem;
    ssl_certificate_key       cert/server_rsa.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECC-SM2-WITH-SM4-GCM-SM3:ECDHE-SM2-WITH-SM4-GCM-SM3:HIGH:!aNULL:!MD5;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    root /var/www/html;
    index index.html;
}

四条国密指令中,ssl_sign_certificate 与 ssl_enc_certificate 分别对应签名与加密结构,不可混用文件。若不需要兼容国际客户端,可省略 RSA 两行,但多数面向公网的站点都建议保留双栈。实际可用的国密套件名称以本机编译结果为准,先用 /usr/local/tongsuo/bin/openssl ciphers -ntls -v | grep SM2 列出支持的套件再回填。

4. 平滑生效

/usr/local/tengine/sbin/nginx -t
/usr/local/tengine/sbin/nginx -s reload

nginx -t 必须通过后再 reload。若报 unknown directive "enable_ntls",说明模块未编译进去,需回到第 1 步检查 --add-module 与 enable-ntls 参数。

配置验证

  • 国密握手验证:用支持 NTLS 的客户端测试,命令为 /usr/local/tongsuo/bin/openssl s_client -connect www.example.com:443 -ntls -cipher ECC-SM2-WITH-SM4-GCM-SM3,握手成功后会输出国密套件与 Peer signature type: SM2 字样。
  • 国际协议兼容验证:用普通 openssl 执行 openssl s_client -connect www.example.com:443 -tls1_2,确认 RSA 链路仍可用,双栈没有互相挤占。
  • 证书结构验证:openssl x509 -in server_sign.pem -noout -text 查看公钥算法是否为 id-ecPublicKey 且曲线为 SM2,签名算法为 SM3withSM2。
  • 浏览器可用性验证:主流浏览器访问应正常展示锁标识;若报证书错误,通常是证书链合并顺序有误或缺少中间证书。
  • 协议收紧验证:openssl s_client -connect www.example.com:443 -tls1_1 应当握手失败,确认弱协议已按预期禁用。

常见问题

FAQ 1:配置完成后浏览器仍提示证书无效,如何排查?

按三步定位。第一,确认访问路径走的是 RSA 还是国密:普通浏览器不支持 NTLS,必然走 RSA 链路,若只配置了国密证书而没配置 RSA 证书,浏览器就会握手失败。第二,检查证书链是否完整,server_rsa.pem 必须是「站点证书 + 中间证书」的完整链,顺序不能颠倒。第三,核对域名与证书 CN/SAN 是否一致,国密证书与国际证书的 SAN 需覆盖全部对外域名。三步都正常但仍报错时,用 openssl s_client -connect 域名:443 -servername 域名 观察服务端实际下发的证书序列号,确认与预期文件一致。

FAQ 2:国密改造后性能下降明显,如何优化?

国密握手的计算开销高于部分国际套件,优先从四方面优化。一是开启会话复用,配置 ssl_session_cache shared:SSL:10m 并适当延长 ssl_session_timeout,把重复握手的比例压下来。二是优先使用 GCM 模式套件,其吞吐优于 CBC 模式。三是在网关层终结国密流量,后端内网继续使用明文或国际协议,避免每层都做国密运算。四是国密证书的私钥运算在 CPU 上完成,若单机承载连接数很高,可开启多 worker 进程并把加密任务分散到更多核心,必要时引入国密硬件加密卡。压测时用 ab 或 wrk 分别测试国密与国际链路的 QPS,对比后再决定是否需要扩容。

总结

国密 HTTPS 改造的落地要点只有四个:编译时打开 enable-ntls、配置四个国密证书指令、保留 RSA 证书做兼容、用 s_client 验证握手套件。签名证书与加密证书必须分离生成并分离存放,这是国密体系与国际体系最大的结构差异,也是合规检查的重点项。改造完成后建议把验证命令固化成巡检脚本,在证书到期、配置变更与系统升级后自动跑一遍,避免出现「配置看起来对、实际走的是国际套件」的假合规。