4. 设备证书的生成:密钥对生成、CSR 构造与 CA 签发
证书生成是整个生命周期里最基础、也最容易出坑的一步。我见过不少团队在密钥算法上选错、CSR 字段填错,最后导致证书无法使用,还得重新走流程。说白了,这一步要是没走稳,后面全是白搭。
咱们分三段来讲:密钥对怎么生成、CSR 怎么构造和提交、CA 怎么签发。嗯,先看整体流程。
4.1 密钥对生成:RSA 还是 ECC?
密钥对是证书的根基。私钥必须安全存储在设备内部(HSM、TEE、安全芯片),公钥则放进 CSR 交给 CA。我个人习惯在项目初期就定好算法,不然后面改起来很麻烦。
| 对比维度 | RSA | ECC |
|---|---|---|
| 密钥长度 | 2048 / 4096 bit | 256 / 384 bit |
| 安全强度 | 2048 bit ≈ 112 位对称 | 256 bit ≈ 128 位对称 |
| 计算性能 | 签名慢,验签快 | 签名快,验签稍慢 |
| 证书体积 | 较大(公钥 ~256 字节) | 较小(公钥 ~32 字节) |
| 兼容性 | 最广泛,老设备也支持 | 较新,部分老旧系统不支持 |
我的建议:物联网终端设备优先选 ECC-256,省带宽、省电量、省存储。服务器和网关设备用 RSA-2048 更稳妥,兼容性最好。至于 RSA-4096,除非合规强制要求,否则没必要——性能开销大,安全增益有限。
生成密钥对的命令其实很简单。以 OpenSSL 为例:
# RSA 2048 位私钥
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out device_rsa_priv.pem
# ECC P-256 私钥
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out device_ecc_priv.pem
# 从私钥提取公钥(CSR 时需要)
openssl pkey -in device_rsa_priv.pem -pubout -out device_rsa_pub.pem
我在项目中遇到过一件事:某次批量产线用脚本生成密钥对,忘记指定随机数种子,结果一批设备的私钥竟然相同。嗯,后来我们强制在生成命令里加上了硬件随机数源,再也没出过这种问题。
⚠️ 避坑指南:我曾经见过有人直接在 CSR 命令里用 -newkey 临时生成密钥,然后私钥没保存就丢了。记住:先生成密钥对,再构造 CSR,两步分开做。私钥一旦丢失,证书就是废纸。
4.2 CSR 的构造与提交
CSR(Certificate Signing Request)说白了就是一张申请表。里面填三样东西:
- 主体信息(DN):CN、O、OU、L、ST、C 等字段
- 公钥:上一步生成的公钥
- 签名:用私钥对上述信息签名,证明你持有私钥
构造 CSR 的标准格式是 PKCS#10。我习惯把 DN 字段写在一个配置文件里,避免每次敲命令输错:
# csr_config.cnf
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
C = CN
ST = Beijing
L = Haidian
O = Example Corp
OU = IoT Division
CN = device-001.example.com
然后用 OpenSSL 生成 CSR:
openssl req -new -key device_rsa_priv.pem -config csr_config.cnf -out device.csr
# 查看 CSR 内容
openssl req -in device.csr -noout -text
你想想看,CSR 里最容易被忽略的是什么?是 Subject Alternative Names (SAN)。现在的浏览器和操作系统都要求证书包含 SAN 字段,光靠 CN 已经不够了。我建议在 CSR 生成时就带上 SAN:
# 在 csr_config.cnf 里追加
[ req ]
req_extensions = v3_req
[ v3_req ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = device-001.example.com
DNS.2 = device-001.local
IP.1 = 192.168.1.100
提交方式有两种:
- 在线提交(SCEP / EST / ACME):设备自动向 CA 发送 CSR,适合大规模部署。我曾在 10 万台设备的项目里用 EST 协议,一天内全部完成证书签发。
- 离线提交(手动上传 / 邮件):CSR 导出为 .csr 文件,人工提交给 CA 管理员。适合少量设备或高安全环境。
4.3 CA 签发流程
CA 收到 CSR 后,不会直接签发。它会做几件事:
- 验证 CSR 签名:用 CSR 里的公钥验证签名,确认申请人确实持有私钥。
- 审核身份信息:DN 字段是否合规?SAN 是否允许?组织信息是否匹配?
- 检查策略约束:密钥用途(Key Usage)、扩展密钥用途(EKU)是否符合 CA 策略。
- 签发证书:CA 用自己的私钥对证书主体信息 + 公钥 + 扩展字段进行签名,生成 X.509 v3 证书。
签发命令(CA 侧操作):
openssl ca -config ca_config.cnf -in device.csr -out device_cert.pem -days 3650 -extensions v3_req
签出来的证书长什么样?我一般用这个命令看:
openssl x509 -in device_cert.pem -noout -text
你会看到证书里有版本号、序列号、签名算法、颁发者、有效期、主体、公钥、扩展字段,最后是 CA 的数字签名。
一个小细节:CA 签发时会在证书里嵌入 Authority Key Identifier (AKI) 和 Subject Key Identifier (SKI)。这两个字段用来构建证书链。我曾经排查过一个证书链验证失败的问题,最后发现是 AKI 指向了错误的父证书——嗯,从那以后我每次签发完都会检查这两个字段。
4.4 常见问题与避坑
| 问题 | 原因 | 解决方法 |
|---|---|---|
| CSR 签名验证失败 | 私钥与 CSR 不匹配 | 重新生成密钥对,确保 CSR 使用对应私钥 |
| 证书链不完整 | 签发时未包含中间 CA 证书 | 下发证书时附带完整链(设备 + 中间 + 根) |
| 证书有效期太短/太长 | 策略配置不当 | 设备证书建议 1-3 年,根 CA 可 10-20 年 |
| SAN 缺失导致浏览器报错 | CSR 未包含 SAN 扩展 | 生成 CSR 时强制添加 SAN 字段 |
⚠️ 我曾经踩过的坑:有一次给设备签发证书,CA 配置里忘了设置 basicConstraints=CA:FALSE,结果签出来的证书竟然可以作为 CA 继续签发下级证书。这在生产环境里是严重的安全事故。所以每次签发前,我都会检查 CA 策略文件里的 basicConstraints 和 keyUsage 是否严格限制。