4、自签名根证书:创建根CA、生成自签名SM2证书、根证书的存储与保护
好,咱们进入实战环节。前面聊了那么多密码学原理和证书链的宏观结构,现在终于要亲手搭建第一个基石了——自签名根证书。
说白了,根证书就是整个信任体系的“祖宗”。它自己证明自己,没有上级CA给它背书。你想想看,如果根证书被人篡改了,那下面签发的所有证书都不可信了。所以这一章,咱们不仅要学会怎么生成它,更要学会怎么把它“供”起来。
4.1 根CA的规划与准备
动手之前,先想清楚几个问题。我在项目中见过不少团队,上来就开干,结果证书体系混乱,最后不得不推倒重来。
根CA的定位:
- 离线存储:根CA的私钥应该放在离线环境,甚至物理隔离的机器上。日常签发证书用二级CA或三级CA。
- 长期有效:根证书的有效期通常设10-20年。我习惯设15年,既够长,又留了轮换的余地。
- 单一职责:一个根CA只做一件事——签发下级CA证书。别用它直接签终端证书。
我的习惯: 我会准备一台不联网的Linux虚拟机,专门用来操作根CA。所有操作都在这台机器上完成,生成的私钥直接写入加密U盘。
4.2 生成SM2根密钥对
咱们用OpenSSL的国密版本来操作。如果你用的是标准OpenSSL 1.1.1以上版本,也支持SM2,但需要显式指定。
先创建目录结构,这是我个人比较喜欢的布局:
# 创建根CA的工作目录
mkdir -p ~/sm2-rootca/{private,certs,crl,newcerts,conf}
cd ~/sm2-rootca
# 初始化索引文件和序列号
touch index.txt
echo '01' > serial
# 生成SM2私钥(加密存储)
openssl ecparam -genkey -name SM2 -out private/ca.key.pem
# 设置私钥权限,只允许当前用户读写
chmod 400 private/ca.key.pem
这里有个关键点:chmod 400。我曾经在一个项目里,因为私钥权限没设好,被安全审计打了个严重漏洞。嗯,从那以后,我每次生成私钥后的第一件事就是改权限。
为什么要加密存储?因为私钥文件本身是明文的。我建议用AES-256-CBC再加密一层:
# 用SM4加密私钥(国密环境推荐)
openssl ec -aes-256-cbc -in private/ca.key.pem -out private/ca.key.enc.pem
# 然后删除明文私钥
shred -u private/ca.key.pem
注意: 加密密码必须足够复杂,并且要离线备份。我见过有人把密码写在便签纸上贴在显示器上……这比不加密还危险。
4.3 生成自签名SM2根证书
有了密钥对,接下来就是生成自签名证书。自签名意味着证书的签发者和使用者是同一个实体。
先准备配置文件。我习惯把配置写清楚,避免每次敲一堆命令行参数:
# conf/root-ca.conf
[ req ]
distinguished_name = req_dn
x509_extensions = v3_ca
prompt = no
[ req_dn ]
countryName = CN
stateOrProvinceName = Beijing
localityName = Haidian
organizationName = My Root CA
organizationalUnitName = Security
commonName = My SM2 Root CA
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:TRUE, pathlen:1
keyUsage = critical, keyCertSign, cRLSign
extendedKeyUsage = serverAuth, clientAuth
然后生成自签名证书:
openssl req -new -x509 -days 5480 \
-config conf/root-ca.conf \
-key private/ca.key.enc.pem \
-out certs/ca.cert.pem
# 查看证书内容
openssl x509 -in certs/ca.cert.pem -text -noout
-days 5480 大约是15年。为什么选这个数?因为SM2算法在合理安全强度下,15年是一个比较稳妥的周期。太短了要频繁轮换根证书,太长了万一算法被攻破就麻烦了。
关键参数说明:
basicConstraints=CA:TRUE:标记为CA证书,这是根证书的核心属性。pathlen:1:限制下级CA只能再签一级证书,防止无限嵌套。keyUsage=keyCertSign, cRLSign:只允许用于签发证书和CRL。
4.4 根证书的存储与保护
证书生成完了,怎么存?我见过最离谱的做法是直接把根证书和私钥放在Web服务器的某个目录下……
我的分级存储方案:
| 层级 | 存储介质 | 存储内容 | 访问频率 |
|---|---|---|---|
| 一级(热) | 加密U盘(离线) | 根私钥(加密)+ 根证书 | 几乎不访问 |
| 二级(温) | 保险柜 + 纸质备份 | 私钥密码 + 证书指纹 | 紧急时使用 |
| 三级(冷) | 银行保管箱 | 完整备份(加密) | 灾难恢复 |
具体操作步骤:
- 导出证书的DER格式:
openssl x509 -in certs/ca.cert.pem -outform DER -out certs/ca.cert.der - 计算证书指纹:
openssl x509 -in certs/ca.cert.pem -fingerprint -sha256,把指纹打印出来,和证书一起存放。 - 私钥分片备份:用Shamir秘密共享算法,把私钥拆成5片,任意3片可恢复。这样即使某个保管人出问题,也不至于丢失私钥。
- 定期验证:每年从备份中恢复一次,验证证书是否仍然有效,私钥是否损坏。
血的教训: 我曾经有一个客户,根证书私钥存在一个加密U盘里,结果U盘坏了。幸好他们有纸质备份的密码和分片,折腾了两天才恢复。从那以后,我坚持“3-2-1”备份原则:3份副本,2种介质,1份异地。
4.5 根证书的生命周期管理
证书不是生成完就完事了。你得考虑它整个生命周期:
- 颁发:生成后立即计算指纹,并发布到公开的证书透明度日志(可选)。
- 使用:根证书只用来签发下级CA证书。每次签发前,检查下级CA的CSR是否合规。
- 轮换:在根证书到期前1-2年,生成新的根证书,并让所有下级CA信任新根。
- 撤销:如果私钥泄露,立即生成CRL,并通知所有依赖方。
这里我画了一张根证书生命周期的流程图,帮你理清思路:
4.6 验证根证书
最后一步,验证你生成的根证书是否合格。我每次都会跑一遍这个检查清单:
# 1. 检查证书是否自签名
openssl verify -CAfile certs/ca.cert.pem certs/ca.cert.pem
# 输出应为:ca.cert.pem: OK
# 2. 检查基本约束
openssl x509 -in certs/ca.cert.pem -text -noout | grep -A2 "X509v3 Basic Constraints"
# 应显示:CA:TRUE
# 3. 检查密钥用法
openssl x509 -in certs/ca.cert.pem -text -noout | grep -A2 "X509v3 Key Usage"
# 应显示:Certificate Sign, CRL Sign
# 4. 检查签名算法
openssl x509 -in certs/ca.cert.pem -text -noout | grep "Signature Algorithm"
# 应显示:SM2