国密SDK架构:两大主流方案的模块划分

咱们做国密改造,第一步就得搞清楚 SDK 里面到底拆成了哪些块。GmSSL 和 OpenSSL 国密分支我前后都折腾过,说实话,两个的设计思路差挺大的。今天咱们就拆开看看它们的模块划分,避坑经验我也会一并聊。

GmSSL:从零造的“全套国密”

GmSSL 的作者是我很佩服的一位前辈。它完全是按照国密标准从零写的一套库,模块划分很清晰,我当初第一次看源码目录,基本能猜到哪块负责什么。

GmSSL 核心模块清单

  • libcrypto – 基础密码算法实现(SM2、SM3、SM4、ZUC 等)
  • libssl – SSL/TLS 协议层,支持国密套件(ECC_SM4_SM3 等)
  • libx509 – 证书解析、SM2 证书链验证
  • libpki – PKI 基础设施:证书签发、CRL、OCSP
  • libsdf – 密码设备接口(对接加密卡、HSM 的抽象层)
  • libsdsm – 分布式签名管理模块(我接触不多,但架构上很清晰)

每个库可以独立编译,也可以静态链接到主程序。我记得有一次项目只用到 SM2 签名验证,我就只编译了 libcrypto,直接把 libssl 和 libx509 跳过了,编译时间少了将近一半。

模块名定位典型场景
libcrypto底层算法引擎纯加解密、哈希、密钥生成
libssl通信协议封装HTTPS 国密握手、TLS 1.3 国密套件
libx509证书栈SM2 证书解析、双向认证
libsdf硬件抽象层适配国产加密卡、UKey

注意一个小细节:GmSSL 的 libcrypto 里把 SM2 签名和 SM2 加密分成了两个文件 sm2_sign.c 和 sm2_enc.c,刚开始我不理解,后来发现国密标准对签名和加密的 ASN.1 格式要求不一样,拆开反而好维护。

OpenSSL 国密分支:在巨人肩膀上打补丁

OpenSSL 官方其实一直没有完整支持国密,咱们用的多是华为或者银联维护的国密分支。它们没动 OpenSSL 的整体架构,而是在现有模块里“插桩”。说白了就是 复用 OpenSSL 的 EVP 框架 + ENGINE 机制,把 SM2/SM3/SM4 注册成新的算法。

我个人习惯把 OpenSSL 国密分支的模块划分理解为三层:

  1. 算法层 – 在 crypto/ec 里新增 SM2 曲线参数,在 crypto/evp 里注册 SM3 哈希和 SM4-CBC。
  2. 引擎层 – 通过 dynamic ENGINE 加载国密算法,或者直接内嵌 built-in ENGINE(如 engine/gmssl.so)。
  3. 协议层 – 在 ssl/t1_lib.c 里修改 cipher suites 列表,添加 SM2-WITH-SM4-SM3。

我曾经在适配华为版 OpenSSL 国密分支时踩了一个坑:分支里把 SM2 密钥结构挂在 EC_KEY 上,但标准 EC_KEY 的公开接口不支持国密曲线 OID 1.2.156.10197.1.301。后来只能在 ec_cvt.c 里手动加一段 OID 映射。如果你也用 OpenSSL 国密分支,记得先确认你的版本有没有打上这个补丁。

模块划分对比:GmSSL vs OpenSSL国密分支

维度GmSSLOpenSSL国密分支
独立程度完全自研,无 OpenSSL 依赖基于 OpenSSL,需同步主线更新
模块粒度细(libcrypto/libssl/libx509/…)粗(在 OpenSSL 现有模块内打补丁)
国密算法集成方式内建、无外部引擎EVP + ENGINE 动态加载
证书链支持原生 SM2 证书解析通过 OID 映射 + 扩展 patch
硬件适配提供 libsdf 统一接口需自己写 ENGINE 桥接
内存泄漏风险相对可控(代码量少)较高(patch 可能和主线冲突)

为什么要掌握模块划分?因为做适配改造时,你不可能每次都给整个 SDK 打补丁。比如你只需要 SM3 哈希,在 GmSSL 里只需要 #include "gmssl/sm3.h",在 OpenSSL 国密分支里则要 EVP_MD_CTX_new + EVP_DigestInit_ex 带 EVP_sm3() 参数。模块边界不同,接口调用习惯完全不同。

一张图看懂模块关系

这是我根据实际项目画的一张简图,把两个框架的模块层次放在一起对比。你注意看:GmSSL 各层互不依赖,而 OpenSSL 国密分支所有国密能力都寄生在已有的 EC/EVP/SSL 模块里。

GmSSL vs OpenSSL国密分支 模块划分对比 GmSSL 应用层 libssl (国密TLS) libx509 + libpki libcrypto (SM2/SM3/SM4) libsdf (硬件抽象层) OpenSSL 应用层 SSL/TLS 协议层 (patch) X.509 证书层 (OID映射) EC_KEY + EVP (国密ENGINE) 硬件ENGINE (需自行实现) GmSSL 各层独立编译 接口干净,国密原生 两者核心差异 模块依赖 vs 寄生 OpenSSL 国密分支 依赖主线,patch 风险 选择哪套框架,取决于项目对 OpenSSL 生态的依赖程度和国密原生性要求

重要提醒:模块划分决定了你改代码时的影响面。如果你项目里已经有大量 OpenSSL 调用(比如 EVP_ 系列),强上 GmSSL 会导致接口重写,不如直接用 OpenSSL 国密分支。反过来,如果你从零开始做国密产品,GmSSL 更干净、合规审计也更容易通过。

好了,模块划分大概就这些。下一块咱们会聊到各模块的接口调用方式,到时候我会直接放几个实际改造中用过的代码片段,你们看完就能拿来用。