国密SSL证书的正确配置核心在于严格区分证书用途,这主要通过 `Key Usage` 和 `Extended Key Usage` 两个扩展属性来定义。目前国密证书主要有两种应用模式:遵循 `GM/T 0015` 标准的单证书模式,以及 `TLCP` 协议下专用的双证书模式。
一、Key Usage(密钥用法)
`Key Usage` 定义了证书公钥最基础的密码学功能,是用途的第一道关口。
关键性:根据RFC 5280标准,此扩展应设为 critical (关键),强制应用程序严格遵守其限制。
OID (对象标识符):`2.5.29.15`。
各用途位(Bit)及GM/T 0015标准建议用法如下表所示:
用途位 (Usage Bit) 建议使用场景
`digitalSignature` 用于签名证书、SSL/TLS 客户端证书。
`nonRepudiation` (contentCommitment) 与 `digitalSignature` 类似,用于法律上不可否认的签名证书,如电子合同签署。
`keyEncipherment` 用于SSL/TLS 服务器证书的密钥交换,或加密证书的公钥加密。
`dataEncipherment` 用于加密证书,直接对数据进行加密。
`keyAgreement` 用于执行密钥协商的证书,如部分SM2加密证书。
`keyCertSign` 仅用于CA证书,表示可用于签发其他证书。
`cRLSign` 仅用于CA证书,表示可用于签发CRL证书撤销列表。
*注意:CA证书也应标记 `keyCertSign` 和 `cRLSign`。*
二、Extended Key Usage(扩展密钥用法/EKU)
`Extended Key Usage` 在Key Usage之上进一步细化证书的高级应用场景。
关键性:由签发者选择是否标记为 `critical`。
OID (对象标识符):`2.5.29.37`。
EKU常见用途OID及其应用场景如下:
EKU 目的 (Purpose) OID 建议使用场景
`serverAuth` `1.3.6.1.5.5.7.3.1` 用于TLS/SSL服务器身份验证(网站、服务端)。
`clientAuth` `1.3.6.1.5.5.7.3.2` 用于TLS/SSL客户端身份验证(用户、设备)。
`codeSigning` `1.3.6.1.5.5.7.3.3` 用于对代码或软件进行数字签名。
`emailProtection` `1.3.6.1.5.5.7.3.4` 用于保护电子邮件安全(如S/MIME)。
`timeStamping` `1.3.6.1.5.5.7.3.8` 用于时间戳服务。
`OCSPSigning` `1.3.6.1.5.5.7.3.9` 用于OCSP响应器签名。
三、场景配置指南
国密证书有两种常见形式:'单证书'和'双证书'。它们的配置思路详见下表:
证书类型 Key Usage (关键) Extended Key Usage (非关键) 说明
签名证书 `digitalSignature`, `nonRepudiation` `clientAuth`, `codeSigning`, `emailProtection` 签名用途广泛,应避免用于加密。
加密证书 `keyEncipherment`, `dataEncipherment`, `keyAgreement` 通常不设置 仅限于密钥传输、加密等操作,不能签名。
SSL 服务器证书(双证书场景) 签名证书用 `digitalSignature`,加密证书用 `keyEncipherment` 签名证书通常包含 `serverAuth` 和 `clientAuth`;加密证书不设置 仅签名证书用于身份验证和协商。
SSL 服务器证书(单证书场景) `digitalSignature`, `keyEncipherment` `serverAuth` 同时支持签名和加密,但功能未分离。
SSL 客户端证书(用于双向TLS) `digitalSignature` `clientAuth` | 核心是用于客户端身份认证。
代码签名证书 `digitalSignature` `codeSigning` 确保软件开发者和代码来源可信。
CA 证书(证书颁发机构) `keyCertSign`, `cRLSign` 不设置** (CA证书不含此扩展) 仅用于签发下级证书和CRL。
四、配置示例
在签发证书时,可以通过配置文件的方式进行设置。
在 `openssl.cnf` (或 `gmssl.cnf`) 文件中配置:
```ini
[ v3_ca_extensions ] # CA证书的扩展配置
basicConstraints = critical, CA:true
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer
[ v3_server_extensions ] # SSL服务器证书的扩展配置 (单证书模式)
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer
[ v3_client_extensions ] # SSL客户端证书的扩展配置
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer
[ v3_code_signing_extensions ] # 代码签名证书的扩展配置
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = codeSigning
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer
```
签发证书操作命令:
```bash
生成受信任的CA证书:
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:sm2p256v1 \
-keyout CAKey.pem -out CACert.pem -days 3650 -nodes \
-config openssl.cnf -extensions v3_ca_extensions
生成并签发服务器证书:
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:sm2p256v1 \
-keyout ServerKey.pem -out ServerReq.pem -nodes
openssl x509 -req -in ServerReq.pem -CA CACert.pem -CAkey CAKey.pem \
-out ServerCert.pem -days 365 -CAcreateserial -extfile openssl.cnf \
-extensions v3_server_extensions
```
五、常见问题与排坑指南
1. 为什么我的国密算法运行失败? 程序报错最常见的原因是该用于签名的SSL证书 `KeyUsage` 中未包含 `digitalSignature`,或应加密的证书未包含 `keyEncipherment`。解决方案:务必先检查证书扩展属性。
2. 什么是国密双证书? 国密SSL协议(GM/T 0024)标准采用“签名证书”与“加密证书”分离的双证书机制,服务器和用户各自持有两对独立密钥对,加密和签名字段必须严格区分。
3. 如何快速检查证书的用途设置? 使用支持国密的OpenSSL或GmSSL工具即可以查看:
```bash
gmssl x509 -in sm2_cert.pem -text -noout | grep -A 5 -B 1 "Key Usage"
```
4. 为什么我的服务器SSL证书在国密浏览器中显示不安全? 很可能签发时将用于签名和用于加密的证书用反了。
5. 一个证书能否既是客户端又是服务器端?技术上可行,但强烈不推荐。将二者混合到一个证书中违背了最小权限原则,会增加安全风险,审计上也不合规,建议分别为服务器和客户端角色签发专用证书。
6. EKU与KeyUsage冲突了会怎样? 两者的定义不能冲突。例如,若KeyUsage只允许数字签名,EKU却要求密钥加密,互不兼容的应用会拒绝使用该证书。