国密 PKI 证书签发流水线实战:从 CSR 解析到 CRL 管理的完整工程实现

PKI 体系 · 2026-09-18 · 15 阅读

前言:为什么证书签发流水线值得单独写一篇文章

在国密改造和密评实践中,很多团队止步于"申请一张 SM2 证书"这一步——要么用 openssl/gmssl 命令行工具手动签发,要么依赖商业 CA 服务。但当企业需要自建 CA 体系时,会遇到一系列工程问题:

典型痛点:

问题后果
CSR 中的 SAN/DNS 验证缺失签发包含无效域名的证书,引发信任链断裂
证书扩展字段配置错误EKU 不匹配导致 TLS 握手失败
多级 CA 链管理混乱根 CA 私钥暴露风险,吊销时无法追溯
CRL 过期或编号不连续客户端缓存过期证书,安全漏洞
未集成国密算法标识GM/T 0015-2023 合规检查不过
这些问题在现有文章中分散讨论过——证书链验证有专门的踩坑文章,OCSP/CRL 机制有原理性解读,但它们没有串成一条完整的工程流水线。

本文的目标:给你一套可运行、可复用的 Python 代码,覆盖从 CSR 接收到证书签发、CRL 管理的完整流程。代码基于 cryptography 库(cryptography ≥ 42.0),并标注国密适配点。

注意:标准 cryptography 库不支持 SM2 曲线(无 ec.SM2())。本文使用 SECP256R1 作为演示,生产环境请使用 Tongsuo/BabaSSL 或 gmssl 库替换密钥生成和签名环节。国密适配的替代方案在文末给出。

一、流水线架构概览

核心模块职责:

模块职责关键标准
CSR 验证器解析 CSR、验证签名、检查 SAN/域名RFC 2986, RFC 5280
证书签发器签发叶子证书/中间 CA 证书GM/T 0015-2023, RFC 5280
多级 CA 管理器Root CA ↔ Intermediate CA 层级维护GM/T 0034-2014 §6.3
CRL 生成器生成/更新吊销列表RFC 5280, GM/T 0015-2023
吊销处理器接收吊销请求、更新 CRLGM/T 0034-2014 §6.5

二、环境准备

BASH
pip install cryptography>=42.0
pip install gmssl>=3.2.0

环境依赖说明:

组件版本用途
cryptography≥ 42.0X.509 CSR/证书/CRL 操作
gmssl≥ 3.2.0SM2 签名/验签(国密场景)
Python3.10+类型注解支持
国密适配提示:cryptography 库本身不支持 SM2 曲线。在生产环境中,你需要: 1. 使用 Tongsuo(国密版 OpenSSL)编译安装,获取带 SM2 支持的 cryptography 扩展 2. 或使用 gmssl 库的 CryptSM2 类完成 SM2 签名环节 3. 证书结构(X.509 字段、扩展)完全兼容,仅签名算法不同

三、CSR 接收与验证

3.1 解析 CSR

证书签名请求(Certificate Signing Request)是申请证书的入口。服务端需要验证其合法性:

3.2 关键验证项清单

检查项原因违规后果
CSR 签名有效性防止恶意伪造 CSR攻击者冒用他人身份申请证书
SAN 域名授权域控制验证(DCV)证书被用于非授权域名
公钥算法合规密钥强度要求弱密钥无法通过密评
密钥用途扩展证书用途限定用途错配导致信任链断裂

四、多级 CA 证书签发

4.1 证书层级设计

根据 GM/T 0034-2014 第 6.3 节要求,CA 系统应采用分级证书结构:

设计原则:

  • Root CA 离线:根 CA 私钥必须存储在 HSM 中且离线保存,仅用于签发中间 CA 证书
  • 中间 CA 隔离:不同用途(服务器证书、客户端证书、代码签名)使用不同中间 CA,便于独立吊销
  • 层级深度限制:GM/T 0034-2014 建议 CA 层级不超过 3 级(Root → Intermediate → End Entity)

4.2 Root CA 证书签发

4.3 中间 CA 证书签发

4.4 叶子证书签发


五、CRL 管理与吊销

5.1 CRL 结构详解

根据 RFC 5280 第 5 节,一个 CRL 包含以下关键字段:

关键字段说明:

字段类型说明
thisUpdateTimeCRL 签发时间
nextUpdateTime下次 CRL 预计签发时间
revokedCertificatesSEQUENCE被吊销证书列表
crlNumberINTEGERCRL 序号(防止重放)
authorityKeyIdentifierKeyIdentifier签发者标识

5.2 CRL 生成器

5.3 CRL 吊销流程


六、完整流水线示例

6.1 端到端流程

6.2 运行输出示例


七、国密适配指南

7.1 SM2 证书签发的替代方案

由于标准 cryptography 库不支持 SM2 曲线,生产环境需要以下适配:

方案 A:使用 Tongsuo(推荐)

BASH
# 安装 Tongsuo
git clone https://github.com/tongsuo-project/Tongsuo.git
cd Tongsuo && ./config enable-sm2 --prefix=/usr/local/tongsuo
make && make install

# 编译带 SM2 支持的 cryptography
pip install --no-binary cryptography cryptography

Tongsuo 编译后,cryptography 库会自动识别 SM2 曲线,API 与标准库一致。

方案 B:混合使用 gmssl + cryptography

PYTHON
from gmssl.sm2 import CryptSM2
from cryptography import x509
from cryptography.hazmat.primitives import hashes

# 1. 使用 gmssl 生成 SM2 密钥对
# (需手动实现 double-and-add 或使用 Tongsuo)
# 2. 使用 gmssl 进行 SM2 签名
sm2 = CryptSM2(private_key=priv_hex, public_key=pub_hex)
signature = sm2.sign_with_sm3(data_to_sign)

# 3. 使用 cryptography 构建证书结构
# 证书中的签名算法字段设为 SM2WithSM3 (1.2.156.10197.1.501)

7.2 GM/T 0015-2023 合规检查清单

根据 GM/T 0015-2023《数字证书格式》,国密证书需满足:

检查项要求代码实现
签名算法 OID1.2.156.10197.1.501 (SM2WithSM3)hashes.SM3() 替代 hashes.SHA256()
曲线参数SM2 标准曲线(GM/T 0003.1-2012)使用 default_ecc_table
证书版本号v3.not_valid_before() / .not_valid_after()
序列号至少 64 位x509.random_serial_number()
有效期≤ 3 年(Leaf),≤ 10 年(Root)根据 CA 层级设置

7.3 国密证书扩展字段映射

标准扩展OID说明
SM2 签名算法1.2.156.10197.1.501替换 ecdsa-with-SHA256
SM2 密钥标识1.2.156.10197.1.301SM2 公钥 OID
国密证书策略1.2.156.10197.1.101证书策略标识

八、生产环境踩坑记录

坑 #1:CRL 分发点 URL 格式错误

现象:签发证书后,客户端验证时报 CRL distribution point not found。

原因:CRLDistributionPoint 的 full_name 参数需要使用 UniformResourceIdentifier,而不是直接传字符串。

PYTHON
# ❌ 错误
x509.CRLDistributionPoints(["http://crl.example.com/ca.crl"])

# ✅ 正确
x509.CRLDistributionPoints([
    x509.DistributionPoint(
        full_name=[x509.UniformResourceIdentifier("http://crl.example.com/ca.crl")]
    )
])

坑 #2:证书链验证时缺少 AKI 扩展

现象:使用 gmssl verify 验证证书链时,提示 certificate has no authority key identifier。

原因:中间 CA 证书缺少 AuthorityKeyIdentifier 扩展。

PYTHON
# 签发中间 CA 时必须添加
builder = builder.add_extension(
    x509.AuthorityKeyIdentifier.from_issuer_public_key(root_key.public_key()),
    critical=False
)

坑 #3:CRL 序号不连续导致客户端拒绝

现象:CRL 发布后,某些客户端报 CRL number mismatch。

原因:每次生成 CRL 时,CRLNumber 必须严格递增。

PYTHON
# 必须在数据库中持久化 crl_number
crl_number = get_next_crl_number_from_db()  # 原子递增
crl = generate_crl(..., crl_number=crl_number)
save_crl_number_to_db(crl_number + 1)

坑 #4:SM2 证书无法在标准浏览器中使用

现象:生成的 SM2 证书在 Chrome/Firefox 中提示 UNKNOWN_CA。

原因:标准浏览器不识别 SM2 曲线 OID。必须使用国密浏览器(如 360 安全浏览器国密版、奇安信安全浏览器)或配置浏览器信任国密根证书。


九、总结

本文提供了一套完整的国密 PKI 证书签发流水线实现,核心要点:

  • 多层 CA 架构:Root CA 离线保护,中间 CA 在线签发,符合 GM/T 0034-2014 要求
  • CSR 验证:确保域名授权、公钥强度、签名合法性
  • CRL 管理:完整的吊销流程和序号管理
  • 国密适配:提供 Tongsuo 和 gmssl 两种替代方案
下一步:
  • 接入数据库实现证书持久化
  • 集成 ACME 协议实现自动化签发
  • 对接国密浏览器完成端到端测试
相关实践文章:

参考

  • GM/T 0034-2014《基于 SM2 密码算法的证书认证系统密码及其相关安全技术规范》
  • GM/T 0015-2023《数字证书格式》
  • RFC 5280《Internet X.509 Public Key Infrastructure Certificate and CRL Profile》
  • RFC 2986《Certification Request Specification》
  • cryptography 文档
  • gmssl 文档