4. 固件签名工具链搭建:OpenSSL 安装与密钥生成

好,咱们进入实战环节。前面几章讲了签名验证的理论,现在该动手了。这一章的核心就三件事:装好 OpenSSL、生成密钥对、用它对固件做哈希和签名。

我个人习惯把工具链搭建放在课程前半段,因为后面所有章节的代码、脚本、流程都依赖这套环境。你想想看,如果连签名工具都没配好,后面讲再多也是纸上谈兵。

4.1 OpenSSL 安装与配置

OpenSSL 是嵌入式签名领域的事实标准。我见过不少项目用自研的签名工具,最后都因为兼容性问题回退到 OpenSSL。所以,别折腾,直接用。

4.1.1 Linux 环境安装

大多数 Linux 发行版都预装了 OpenSSL。你可以先检查一下版本:

openssl version

如果没装,或者版本太旧(低于 1.1.1),建议更新。我个人习惯用包管理器安装:

# Ubuntu / Debian
sudo apt-get update
sudo apt-get install openssl libssl-dev

# CentOS / RHEL
sudo yum install openssl openssl-devel
小提示: 我建议安装后执行 openssl version -a 查看编译参数。确保支持你需要的算法,比如 EC(椭圆曲线)。我曾经遇到过客户提供的 OpenSSL 没编译 EC 支持,折腾了半天才发现。

4.1.2 Windows 环境安装

Windows 下我推荐两种方式:

  • 方式一: 下载官方安装包(slproweb.com/products/Win32OpenSSL.html),选 Light 版本就行。
  • 方式二: 用 WSL(Windows Subsystem for Linux),直接在 Linux 子系统里操作。我个人更倾向这种方式,因为脚本环境统一,避免路径和换行符的坑。

安装完后,记得把 OpenSSL 的 bin 目录加到系统 PATH 里。验证方法很简单:打开命令行,输入 openssl version,能看到版本号就说明成了。

4.2 生成 RSA / ECC 密钥对

密钥对是签名的根基。公钥要烧到设备里,私钥必须保存在安全的构建服务器上。这个原则一定要记住。

4.2.1 生成 RSA 密钥对

RSA 是目前最广泛使用的非对称算法。我一般用 2048 位,安全性和性能比较均衡。4096 位更安全,但签名和验签都慢,嵌入式设备上尤其明显。

# 生成 RSA 私钥(2048 位)
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private_rsa.pem

# 从私钥提取公钥
openssl rsa -pubout -in private_rsa.pem -out public_rsa.pem
注意: 私钥文件一定要妥善保管。我见过有团队把私钥直接放在代码仓库里,结果被外部攻击者拿到,整个产品的 OTA 安全体系瞬间崩塌。私钥应该放在离线环境或硬件安全模块(HSM)里。

4.2.2 生成 ECC 密钥对

ECC(椭圆曲线密码学)的优势是密钥短、速度快。对于资源受限的 IoT 设备,ECC 比 RSA 更友好。我推荐使用 prime256v1(也叫 secp256r1),这是 NIST 标准曲线,兼容性最好。

# 生成 ECC 私钥(prime256v1 曲线)
openssl ecparam -genkey -name prime256v1 -out private_ecc.pem

# 从私钥提取公钥
openssl ec -pubout -in private_ecc.pem -out public_ecc.pem

为什么选 prime256v1?说白了,大多数安全芯片和 MCU 的硬件加速器都支持这条曲线。你选一条冷门曲线,可能连硬件加速都用不了,纯软件算签名会慢得让人崩溃。

4.2.3 RSA 与 ECC 对比

对比项 RSA-2048 ECC-256 (prime256v1)
密钥长度 2048 位 256 位
签名长度 256 字节 64 字节
签名速度 较慢 较快
验签速度 较快 较快
硬件加速支持 广泛 广泛(主流 MCU)
推荐场景 网关、服务器端 IoT 终端、MCU

我个人在车规级 MCU 项目里更倾向 ECC。签名短,传输快,验签时占用的 RAM 也少。但如果你做的是 Linux 网关或者服务器端的固件验证,RSA 也完全够用。

4.3 使用 OpenSSL 对固件进行哈希与签名

密钥有了,接下来就是给固件“盖戳”。流程很简单:先算哈希,再用私钥加密哈希值,得到签名。

4.3.1 计算固件哈希

哈希算法我推荐 SHA-256。SHA-1 已经不安全了,SHA-512 又太慢。SHA-256 是当前最平衡的选择。

# 计算固件文件的 SHA-256 哈希值
openssl dgst -sha256 -binary firmware.bin > firmware.hash

这条命令会输出二进制格式的哈希值。你也可以用 -hex 参数输出十六进制文本,方便调试时肉眼查看。

核心要点: 哈希计算必须在签名前完成。签名是对哈希值签名,不是对整个固件签名。这样做的好处是签名长度固定,不受固件大小影响。

4.3.2 生成签名

用私钥对哈希值签名。RSA 和 ECC 的命令略有不同:

# RSA 签名
openssl dgst -sha256 -sign private_rsa.pem -out firmware.sig firmware.bin

# ECC 签名
openssl dgst -sha256 -sign private_ecc.pem -out firmware.sig firmware.bin

嗯,这里要注意:-sign 参数会自动完成哈希计算和签名两步。你不需要先手动算哈希再签名,OpenSSL 帮你做了。但为了教学清晰,我前面还是拆开演示了。

4.3.3 验证签名

签名生成后,一定要验证一遍。我习惯在构建脚本里自动执行验证,确保签名没出错。

# RSA 验签
openssl dgst -sha256 -verify public_rsa.pem -signature firmware.sig firmware.bin

# ECC 验签
openssl dgst -sha256 -verify public_ecc.pem -signature firmware.sig firmware.bin

如果输出 Verified OK,说明签名正确。如果输出 Verification Failure,赶紧检查密钥是否匹配、固件是否被修改过。

避坑指南: 我曾经遇到一个案例,客户在 CI 流水线里签名后没做验证,结果发现私钥文件被误替换了。所有固件都是用错误的私钥签的名,导致设备端验签全部失败。那次教训之后,我在所有签名脚本里都加上了自动验证步骤。

4.4 完整签名流程

把上面几步串起来,就是一个完整的固件签名流水线。我画了一张流程图,帮你理清整体逻辑。

固件签名完整流程 固件 firmware.bin SHA-256 哈希 哈希值 (32 字节) 私钥 private.pem 签名算法 (RSA/ECC) 签名 firmware.sig 固件 + 签名打包 说明: 签名是对哈希值签名, 不是对整个固件签名。 签名长度固定,不受固件大小影响。

流程其实不复杂。固件进来,算哈希,用私钥签名,最后把固件和签名打包在一起。设备端收到后,用公钥验签,比对哈希,就能确认固件是否完整、是否来自可信源。

4.5 本章小结

这一章我们搭好了签名工具链。你学会了:

  • 安装和配置 OpenSSL
  • 生成 RSA 和 ECC 密钥对
  • 用 OpenSSL 对固件做哈希和签名
  • 验证签名是否正确