3、OpenSSL工具链:安装、配置与自签名根证书
说到固件签名,OpenSSL 是绕不开的工具。我入行那会儿,前辈丢给我一句「去学 OpenSSL」,然后扔了个 man 页面链接就走了。说实话,那感觉就像给你一把瑞士军刀,却不告诉你哪个是开瓶器。
这一章,咱们就把 OpenSSL 这把刀磨利索。从安装配置,到常用命令,再到生成第一张自签名根证书。嗯,一步步来。
3.1 安装与基础配置
OpenSSL 的安装其实没什么玄学。不同平台有不同玩法,我列个表,你对着看就行。
| 平台 | 安装方式 | 备注 |
|---|---|---|
| Ubuntu/Debian | sudo apt install openssl |
一般系统自带,版本可能偏旧 |
| CentOS/RHEL | sudo yum install openssl |
同上,建议用 EPEL 源更新 |
| macOS | brew install openssl |
系统自带的是 LibreSSL,建议用 Homebrew 装 |
| Windows | 下载安装包或 WSL | 我个人习惯用 WSL,省心 |
装完之后,先看一眼版本:
openssl version -a
你会看到类似 OpenSSL 1.1.1w 11 Sep 2023 的输出。为什么强调版本?因为 1.1.1 和 3.x 的某些命令参数有差异。我在项目中遇到过因为版本不同导致脚本跑挂的情况,后来学乖了,第一件事就是锁版本。
3.2 配置文件:openssl.cnf 的秘密
很多人觉得 OpenSSL 难用,其实一半的坑都在配置文件上。默认的 openssl.cnf 路径可以通过 openssl version -d 查到。但说实话,我从来不用系统自带的那个——太啰嗦,而且很多默认值不适合固件签名场景。
我自己会准备一个精简版配置,像这样:
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
prompt = no
[ req_distinguished_name ]
countryName = CN
stateOrProvinceName = Beijing
localityName = Beijing
organizationName = MySecureBoot
organizationalUnitName = FirmwareSigning
commonName = My Root CA
emailAddress = ca@mysecureboot.com
[ ca ]
default_ca = CA_default
[ CA_default ]
database = index.txt
serial = serial
new_certs_dir = newcerts
default_md = sha256
policy = policy_loose
copy_extensions = copy
你看,我故意把 prompt 设成了 no。为什么?因为自动化脚本里不能有交互式输入。你想想看,半夜三点流水线跑起来,弹个对话框让你输国家代码,那画面太美我不敢看。
database、serial、new_certs_dir 这些路径,在运行命令前必须手动创建好。我曾经因为忘了建 newcerts 目录,折腾了半小时才找到原因。
3.3 常用命令速查
OpenSSL 命令多如牛毛,但固件签名场景下,常用的就那么十几个。我按用途分了个类:
| 用途 | 命令示例 | 说明 |
|---|---|---|
| 生成私钥 | openssl genrsa -out key.pem 2048 |
2048 位 RSA,固件签名够用了 |
| 生成 CSR | openssl req -new -key key.pem -out csr.pem -config openssl.cnf |
证书签名请求,交给 CA 去签 |
| 自签名证书 | openssl req -x509 -new -key key.pem -out cert.pem -days 3650 -config openssl.cnf |
直接生成自签名证书,省掉 CSR 步骤 |
| 查看证书 | openssl x509 -in cert.pem -text -noout |
看证书内容,调试时必备 |
| 计算哈希 | openssl dgst -sha256 -sign key.pem -out sig.bin firmware.bin |
对固件做哈希签名 |
| 验证签名 | openssl dgst -sha256 -verify pub.pem -signature sig.bin firmware.bin |
验签,确认固件没被改过 |
这些命令我几乎每天都要敲。说实话,敲多了就形成肌肉记忆了。但有个坑我得提醒你——genrsa 生成的私钥默认是 PKCS#1 格式,而有些固件签名工具只认 PKCS#8。遇到这种情况,加一步转换:
openssl pkcs8 -topk8 -inform PEM -outform PEM -in key.pem -out key_pkcs8.pem -nocrypt
3.4 生成自签名根证书
好,重头戏来了。咱们亲手造一张根证书。这张证书将来会用来签发固件签名证书,所以它的私钥要像命根子一样保护好。
步骤其实就三步:
- 生成根证书私钥
- 生成根证书(自签名)
- 验证证书内容
先跑第一步:
mkdir -p ~/myca && cd ~/myca
openssl genrsa -aes256 -out rootCA.key 4096
这里我用了 -aes256,意思是私钥本身用 AES-256 加密。每次使用私钥时都要输密码。你可能会觉得麻烦,但想想看——如果私钥文件被人拷走了,没有密码他照样干瞪眼。
第二步,生成自签名根证书:
openssl req -x509 -new -sha256 -key rootCA.key -out rootCA.crt -days 7300 -config openssl.cnf
这里 -days 7300 是 20 年。根证书有效期长一点没关系,反正它只用来签中间证书,不直接签固件。我见过有些公司设 10 年,也有设 25 年的。我个人习惯是 20 年,够长但也不至于太离谱。
第三步,验证一下:
openssl x509 -in rootCA.crt -text -noout | head -20
你会看到证书的颁发者(Issuer)和主题(Subject)是一样的——这就是自签名的特征。还会看到签名算法是 sha256WithRSAEncryption,公钥长度 4096 位。
openssl x509 -fingerprint -sha256 -in rootCA.crt -noout。把这个指纹记下来,以后部署到设备端时,可以用来做证书锁定(Certificate Pinning)。
3.5 知识体系:根证书生成流程
说了这么多,咱们用一张图把整个流程串起来。这样你脑子里就有个全局画面了。
这张图把整个流程拆成了五步。你看,从准备环境到安全存储,每一步都有明确的产出物。我当年第一次做根证书时,就是照着这个思路一步步来的,没出过岔子。
3.6 避坑指南
最后,分享几个我踩过的坑:
- 私钥权限: 生成完私钥,立刻
chmod 600 rootCA.key。别问我为什么强调这个——有一次我忘了设权限,同事一个cat就把私钥内容打到终端上了。 - 证书序列号: 自签名证书的序列号是随机生成的,但如果你用 CA 模式签发子证书,必须手动维护
serial文件。我习惯用echo 01 > serial初始化。 - 哈希算法: 别再用 SHA-1 了。虽然 OpenSSL 默认可能还是 SHA-1,但你一定要显式指定
-sha256。SHA-1 的碰撞攻击已经不是理论问题了。 - 备份策略: 根证书私钥建议做离线备份,存到硬件安全模块(HSM)或者加密的 U 盘里。我见过一家公司把根证书私钥放在共享文件夹里,结果被勒索病毒一锅端了。
好了,这一章的内容就到这儿。OpenSSL 工具链的安装配置、常用命令、自签名根证书生成,咱们都过了一遍。这些东西看着简单,但每一个细节都关系到固件签名的安全性。你动手试试,有问题随时回来翻翻这一章。