OpenSSL原生不支持国密算法,因默认仅内置RSA/ECC(NIST曲线)和SHA-1/SHA-2,缺失SM2曲线、SM3哈希及SM4加密;强行使用-sm3或-sm2p256v1会报“unknown option”或“unable to load elliptic curve”错误。

OpenSSL 本身不支持国密算法(SM2/SM3/SM4),直接用 openssl 命令生成国密双向证书会失败——必须换用 gmssl 或适配国密的 openHiTLS。
为什么 openssl genrsa / req / x509 无法生成国密证书
标准 OpenSSL(1.1.1 或 3.x)默认只内置 RSA/ECC(NIST 曲线)、SHA-1/SHA-2,不包含 SM2 签名曲线、SM3 哈希、SM4 加密等国密算法。即使你强行指定 -sm3 或 -name sm2p256v1,会报错:unknown option -sm3 或 unable to load elliptic curve。
常见错误现象:
-
openssl req -new -key key.pem -sm3→unrecognized option -sm3 -
openssl ecparam -name sm2p256v1→unknown curve name - 用普通 OpenSSL 签发的证书,被国密 TLS 客户端(如支持 TLCP 的浏览器或 SDK)拒绝验证
必须用 gmssl 生成 SM2 双证书体系
国密双向认证要求服务器同时持有签名证书(_sign.crt + _sign.key)和加密证书(_enc.crt + _enc.key),这是 TLCP 协议强制规定的双密钥分离机制。只有 gmssl 能原生支持该流程。
实操要点:
- 安装
gmsslv3.0+(非 OpenSSL 分支),推荐从源码编译:./config --prefix=/usr/local/gmssl no-shared - 根 CA 私钥必须用 SM2 生成:
gmssl ecparam -genkey -name sm2p256v1 -out ca.key - CA 自签名时必须显式加
-sm3:gmssl req -x509 -key ca.key -sm3 -days 3650 -out ca.crt - 服务器签名证书 CSR 和加密证书 CSR 必须分别生成,且不能复用同一对密钥
- 签发时需分别指定用途:
gmssl x509 -req -sm3 -extfile 控制扩展项
证书路径与 Nginx/Tomcat 配置的关键区别
国密 TLS 服务(如 Nginx + Wosign 国密模块、Tomcat + openHiTLS connector)对证书文件命名和组合有硬性要求,不是简单替换 ssl_certificate 路径就能跑通。
典型部署结构:
- Nginx 需要四文件:签名证书
server_sm2_sign.crt、签名私钥server_sm2_sign.key、加密证书server_sm2_enc.crt、加密私钥server_sm2_enc.key - 不能把签名和加密证书合并成一个 PEM;也不能把两个私钥合并在一个文件里
- 配置中必须明确区分:
ssl_certificate指向_sign.crt,ssl_certificate_key指向_sign.key;加密证书需通过模块特定指令加载(如ssl_enc_certificate) - 若用
openHiTLS写服务端代码,调用HITLS_Ctx_SetCert时需分别传入签名和加密证书链,顺序错会导致握手失败
最容易被忽略的验证环节:TLCP 握手日志与证书链完整性
生成完所有证书后,光看文件存在不等于能用。真正卡住的地方往往在运行时:
- 用
gmssl s_client -connect example.com:443 -tlcp测试时,若返回no peer certificate或certificate verify failed,大概率是客户端未加载 CA 根证书,或服务端没正确发送完整证书链(缺少中间 CA) - 检查服务端是否把签名证书和加密证书都写进了
send的证书列表(不是只塞了 leaf cert) - 用
gmssl x509 -in server_sm2_sign.crt -text -noout确认Subject Alternative Name包含实际访问域名,否则现代浏览器会直接拦截 - SM2 证书的
Key Usage必须严格区分:签名证书含digitalSignature,加密证书含keyEncipherment,混用会导致 TLS 握手中断











