跳到主要内容
加密解密2026-10-02Begin3 分钟阅读

国密 HTTPS 部署指南:TLCP 协议、SM2 双证书与 nginx(Tongsuo)实战

为什么普通 HTTPS 过不了密评

Let's Encrypt、DigiCert 这些常规证书跑的是国际算法栈:RSA/ECDHE 密钥交换、SHA-256 摘要。而《商用密码应用安全性评估》(密评)和等保三级的高密码要求场景,明确要求传输链路使用国密算法——于是三个问题连环出现:证书要 SM2 的、握手要 TLCP 的、摘要要 SM3 的。拿着 RSA 证书去做密评,这一项直接扣分。

TLCP:国密自己的 TLS

TLCP(传输层密码协议,GB/T 38636-2020)不是 TLS 的一个套件,而是一条独立的协议线——国密体系里对标 TLS 1.2 的存在。它和 RFC 8998(把 SM2/SM3/SM4 绑进 TLS 1.3 的 IETF 标准)是两条并行路径:前者是国内合规的主流要求,后者面向国际互通。密评现场认的是 TLCP。

双证书:签名证书 + 加密证书

TLCP 最容易踩的概念坑是两张证书:

证书算法作用
签名证书SM2身份验证、握手签名
加密证书SM2密钥交换中加密预主密钥

申请国密证书时(CFCA、天威诚信等机构)会一并下发这两张。配置时顺序敏感——nginx 里 ssl_certificate 先签名后加密,配反了握手直接失败。

用 Tongsuo 编译支持国密的 nginx

OpenSSL 主线不支持 TLCP,社区主流用 Tongsuo(铜锁,原 BabaSSL)——蚂蚁开源的 OpenSSL 分支。主线流程:

# 1. 编译 Tongsuo(enable-ntls 是关键开关)
./config enable-ntls
make && make install

# 2. nginx 编译时指向 Tongsuo 并开 ntls
./configure --with-openssl=../tongsuo \
  --with-openssl-opt="enable-ntls no-shared"
make && make install

nginx 配置的核心三行:

ssl_certificate      sign.crt;    # 签名证书
ssl_certificate_key  sign.key;
ssl_certificate      enc.crt;     # 加密证书(第二组)
ssl_certificate_key  enc.key;
ssl_ciphers ECC-SM2-SM4-SM3:ECC-SM2-SM4-SM3-SHA256;

enable_ntls on; 指令(新版 Tongsuo 的 nginx 补丁)开启后,同一个 443 端口可以同时挂国密双证书与国际证书——国密浏览器走 TLCP,普通 Chrome 走 TLS 1.2/1.3,双栈共存,不用开两个端口。

浏览器侧的现实

普通 Chrome/Firefox/Safari 至今不支持 TLCP。能完整走国密握手的客户端:

  • 360 安全浏览器(国密模式,政企采购量大)
  • 密信 MeSignEdge、红莲花浏览器(专业国密浏览器)
  • Java 侧:BouncyCastle + Tongsuo JNI,服务端对服务端场景最成熟

这决定了国密 HTTPS 的典型部署形态:面向政企的入口做双栈,面向大众的入口保持国际证书,两者并存而不是二选一。

密评现场的三个高频卡点

  1. 证书顺序配反:本地 curl 国密分支能通、浏览器报握手失败,先查双证书顺序。
  2. 套件名不匹配:服务端只开了 ECC-SM2-SM4-SM3,客户端却协商 ECC-SM4-SM3-SHA256——双端套件列表要对齐。
  3. 只换证书不换协议:证书换成 SM2 但握手仍是国际 TLS,密评按「算法未全链路国密」记缺陷——TLCP 要整体切。

实现注记 / Implementer's note

本站的国密工具族(SM2 加解密、SM3 摘要、SM4 加解密)跑在浏览器本地,实现上有一个本文避不开的细节:Web Crypto API 不提供国密算法,所以只能用 sm-crypto 纯 JavaScript 实现——这也是为什么工具页定位在小数据与联调,而不是大流量加密。SM2 密文的标准排序(C1C3C2)与旧实现(C1C2C3)的差异,是我们在联调场景里见过最高频的坑,密钥格式同理:未压缩公钥 130 位 hex、04 前缀,和证书里的 DER 编码是两套表示。标准号之间的新旧对应关系(GM/T 与 GB/T 与 ISO/IEC),我们在国密标准号速查里单独整理了一张表。