PKCS#10 证书签名请求(CSR)格式详解:RFC 2986 与国密 SM2 适配

协议详解 · 2026-11-03

概述

在 PKI(公钥基础设施)体系中,证书申请是一个关键流程。任何实体想要获得数字证书,都需要向 CA(证书颁发机构)提交一个证书签名请求(Certificate Signing Request,简称 CSR)。CSR 的本质是:申请者向 CA 证明"我是谁",并提供自己的公钥和身份信息,请求 CA 签发正式证书。

PKCS#10 是最广泛使用的 CSR 格式标准,定义于 RFC 2986(1999年发布,替代早期的 PKCS#10 v1.7)。它采用 ASN.1 DER 编码,结构清晰,支持扩展属性,成为 OpenSSL、Bouncy Castle、Go crypto/x509 等主流密码库的默认实现。

国密环境下,SM2 证书的 CSR 需要遵循 GM/T 0034-2014 和 GM/T 0015-2023 的约束,在 PKCS#10 框架上叠加国密 OID 和算法标识。

PKCS#10 数据结构

ASN.1 定义

根据 RFC 2986 Section 4,PKCS#10 的结构如下:

ASN1
CertificateRequest ::= SEQUENCE {
    certificationRequestInfo CertificationRequestInfo,
    signatureAlgorithm AlgorithmIdentifier,
    signature          BIT STRING  
}

CertificationRequestInfo ::= SEQUENCE {
    version       INTEGER {v1(0)},
    subject       Name,
    subjectPKInfo SubjectPublicKeyInfo OPTIONAL,
    attributes    [0] Attributes OPTIONAL
}
字段类型说明
versionINTEGER固定为 0(v1)
subjectName申请者的 X.509 RDN 名称
subjectPKInfoSubjectPublicKeyInfo申请者的公钥信息
attributesSET OF Attribute可选扩展属性
signatureAlgorithmAlgorithmIdentifier签名算法标识
signatureBIT STRING对 certificationRequestInfo 的签名

核心字段详解

#### 1. subject(主体名称)

subject 是 CSR 中最关键的部分之一,决定了证书颁发后的 Subject 字段。它遵循 X.509 Name 结构,由相对可区分名(RDN)组成:

ASN1
Name ::= CHOICE {
    RDNSequence RDNSequence
}

RDNSequence ::= SEQUENCE OF RelativeDistinguishedName

RelativeDistinguishedName ::= SET OF AttributeTypeAndValue

AttributeTypeAndValue ::= SEQUENCE {
    type     AttributeType,
    value    AttributeValue
}

常见 RDN 示例:

  • CN=example.com(通用名称)
  • O=Example Organization(组织名称)
  • OU=IT Department(组织单位)
  • C=CN(国家)
#### 2. subjectPKInfo(公钥信息)

subjectPKInfo 使用标准的 SubjectPublicKeyInfo 结构(RFC 5480 / X.509):

ASN1
SubjectPublicKeyInfo ::= SEQUENCE {
    algorithm         AlgorithmIdentifier,
    subjectPublicKey  BIT STRING  
}

AlgorithmIdentifier ::= SEQUENCE {
    algorithm   OBJECT IDENTIFIER,
    parameters  ANY DEFINED BY algorithm OPTIONAL  
}

对于 SM2 算法,algorithm OID 为 1.2.156.10197.1.301(sm2p256v1),参数为空或曲线参数。

#### 3. attributes(扩展属性)

attributes 是 CSR 中可包含额外信息的可选字段。常见属性包括:

属性 OID名称用途
1.2.840.113549.1.9.1challengePassword挑战密码(可选)
1.2.840.113549.1.9.2unstructuredName未结构化名称
1.2.840.113556.1.4.195requestNonce请求随机数
国密扩展属性(GM/T 0034-2014):
属性 OID名称用途
1.2.156.10197.1.501sm2sign_with_sm3SM2 签名算法 OID
1.2.156.10197.1.301sm2p256v1SM2 曲线 OID

CSR 生成流程

标准流程(OpenSSL 示例)

BASH
# 1. 生成 SM2 私钥
openssl ecparam -genkey -name sm2p256v1 -noout -out private_key.pem

# 2. 生成 CSR(包含完整的 subject 和扩展)
openssl req -new -key private_key.pem -out request.csr \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=Example Corp/OU=IT/CN=test.example.com" \
    -addext "subjectAltName=DNS:test.example.com,DNS:www.test.example.com"

# 3. 查看 CSR 内容
openssl req -in request.csr -text -noout

Python 生成 CSR(cryptography 库)

注意:gmssl 库不提供密钥生成 API,需要先用 OpenSSL 生成 SM2 密钥对,再用 gmssl 进行签名操作。

国密 SM2 CSR 特殊要求

根据 GM/T 0034-2014 第 5.2 节,SM2 证书的 CSR 需要满足以下要求:

  • 签名算法必须是 SM2WithSM3(OID 1.2.156.10197.1.501)
  • 公钥算法必须是 SM2(OID 1.2.156.10197.1.301)
  • 证书主题必须包含国密 CN 扩展(如适用)
  • 必须支持双证书机制:签名证书和加密证书分别申请

CSR 验证流程

CA 收到 CSR 后,需要执行完整的验证流程:

签名验证原理

CSR 的签名是用申请者的私钥对 certificationRequestInfo 字段(DER 编码)计算的哈希值。验证时:

  • 解码 CSR 获取 certificationRequestInfo
  • 提取 subjectPKInfo 中的公钥
  • 用该公钥验证 signature 字段

国密 CSR 验证(SM2)

CSR 与证书的关系

特性CSR证书
用途申请证书证明身份
签名方申请者私钥CA 私钥
有效期无(一次性使用)有(通常 1-2 年)
公开性保密公开分发
内容公钥 + 身份信息公钥 + 身份信息 + CA 签名
关键区别:CSR 只是"请求",证书是 CA 签名后的"结果"。CA 可能会修改 CSR 中的某些字段(如添加扩展、调整有效期),但主体名称和公钥通常保持不变。

工程实践中的常见问题

问题 1:CSR 签名算法不匹配

现象:CA 拒绝 CSR,报"签名算法不支持"。

原因:CSR 使用的签名算法与 CA 策略不符。例如,使用 RSA-SHA256 签名但 CA 只接受 SM2-SM3。

解决方案:确保 CSR 签名算法与目标证书一致。

BASH
# 查看 CSR 的签名算法
openssl req -in request.csr -text -noout | grep "Signature Algorithm"

问题 2:subject 字段格式错误

现象:CA 无法解析 CSR 中的身份信息。

原因:subject 的 RDN 顺序不符合 RFC 4514 规范,或使用了不支持的属性类型。

解决方案:按照标准格式书写 subject:

CODE
/C=CN/ST=Beijing/L=Beijing/O=Example Corp/OU=IT/CN=test.example.com

问题 3:SAN(Subject Alternative Name)缺失

现象:证书签发后浏览器警告"域名不匹配"。

原因:CSR 中未包含 SAN 扩展,或 SAN 与 CN 不一致。

解决方案:在 CSR 生成时显式添加 SAN:

BASH
openssl req -new -key private_key.pem -out request.csr \
    -subj "/CN=test.example.com" \
    -addext "subjectAltName=DNS:test.example.com,DNS:www.test.example.com"

问题 4:挑战密码(Challenge Password)处理

现象:CA 要求提供挑战密码,但 CSR 中未包含。

原因:部分 CA(尤其是 EV 证书)要求 CSR 中包含挑战密码属性。

解决方案:在 CSR 中添加挑战密码属性:

BASH
openssl req -new -key private_key.pem -out request.csr \
    -subj "/CN=test.example.com" \
    -addext "challengePassword=YourChallengePassword"

国密 PKI 中的 CSR 实践

GM/T 0034-2014 要求

根据 GM/T 0034-2014《基于 SM2 密码算法的证书认证系统密码及其相关安全技术规范》,SM2 证书申请的 CSR 需要满足:

  • 双证书申请:签名证书和加密证书必须分别申请 CSR
  • 算法标识:CSR 签名算法必须是 sm2sign_with_sm3(OID 1.2.156.10197.1.501)
  • 密钥用途:签名证书的 keyUsage 必须包含 digitalSignature,加密证书必须包含 keyEncipherment
  • 扩展支持:支持国密扩展的 SAN 格式(如国密域名命名规则)

国密 CSR 生成示例(Python)

国密 CSR 验证流程

与其他 CSR 格式的对比

特性PKCS#10CMP (RFC 4210)SCEP
格式ASN.1 DERASN.1 DERPKCS#7 封装
安全传输无(需配合 TLS/HTTPS)内置安全机制HTTP POST
自动化手动提交完整自动化有限自动化
国密支持原生支持(GM/T 0034)需扩展不支持
应用场景传统 CA 申请企业级 PKI简单部署

总结

PKCS#10 CSR 是 PKI 体系中最基础的数据交换格式之一。理解其结构对于:

  • 开发者:正确生成和处理证书申请
  • CA 运营者:实现安全的证书签发流程
  • 审计人员:验证证书申请的合规性
具有重要价值。在国密环境下,需要特别注意 SM2 算法的 OID 标识、双证书机制和 GM/T 0034-2014 的特殊要求。

参考

相关实践文章