固件签名与验证机制:数字签名原理(RSA/ECDSA),固件哈希校验,安全启动链(Secure Boot)的建立
这一章,我们聊聊固件安全里最核心的防线——签名与验证。说白了,就是怎么确保你烧进设备的固件,确实是官方发布的,没被人动过手脚。
我见过太多产品,因为省了这一步,被黑客直接刷入恶意固件,整批设备沦为肉鸡。嗯,咱们今天就把这块彻底讲透。
数字签名:给固件贴上防伪标签
数字签名不是加密,它解决的是「谁写的」和「改没改」两个问题。你想想看,固件从开发到发布,要经过编译、测试、分发、烧录,中间任何环节都可能被篡改。签名就是给固件贴一个不可伪造的防伪标签。
RSA 与 ECDSA:两种主流算法
目前嵌入式领域,RSA 和 ECDSA 是两大主力。我个人的习惯是:资源受限的 MCU 优先选 ECDSA,性能充裕的应用处理器用 RSA 也没问题。
| 特性 | RSA | ECDSA |
|---|---|---|
| 密钥长度 | 2048 / 4096 bit | 256 / 384 bit |
| 签名速度 | 较慢(私钥操作) | 较快 |
| 验证速度 | 较快(公钥操作) | 较快 |
| 存储占用 | 大(公钥、签名) | 小 |
| 典型场景 | 网关、服务器 | IoT 终端、MCU |
我在一个智能门锁项目里用过 ECDSA P-256。当时 Flash 只剩 4KB 给安全模块,RSA 2048 的公钥就占了 256 字节,签名更是 256 字节,根本塞不下。换成 ECDSA,公钥 64 字节,签名 64 字节,空间压力瞬间没了。
固件哈希校验:先算个摘要再说
签名不是直接对固件本身算的,那样太慢了。实际做法是:先对固件算一个哈希值(比如 SHA-256),然后对这个哈希值签名。
验证时也一样:设备收到固件,先算哈希,再用公钥验证签名是否匹配这个哈希。
// 伪代码:固件签名流程
hash = SHA256(firmware_binary)
signature = RSA_Sign(private_key, hash)
// 将 signature 附加到 firmware_binary 尾部发布
// 伪代码:设备端验证流程
received_hash = SHA256(received_firmware)
extracted_signature = extract_from_firmware(received_firmware)
is_valid = RSA_Verify(public_key, received_hash, extracted_signature)
if (is_valid) {
// 固件可信,允许更新
} else {
// 固件被篡改,拒绝更新
}
这里有个坑,我曾经踩过:哈希算法别用 MD5 或 SHA-1,它们已经被证明可碰撞。哪怕你的 MCU 算力有限,也至少用 SHA-256。实在不行,用硬件加速模块算,别省这个安全成本。
安全启动链(Secure Boot):从第一行代码开始信任
安全启动,说白了就是让设备从 ROM 开始,一级一级验证,确保每一段代码都是可信的。一旦某级验证失败,立即停止启动。
我参与过一个车载 T-Box 项目,客户要求安全启动链必须覆盖从 BootROM 到应用层的每一级。当时我们画了这么一条链:
你看,BootROM 是信任根,它固化在芯片内部,不可更改。它负责验证 Bootloader 的签名。Bootloader 再验证固件镜像的签名。固件镜像再验证应用层的完整性。每一级都只信任上一级传递过来的公钥。
建立安全启动链的步骤
- 生成密钥对:在离线安全环境中生成 RSA 或 ECDSA 密钥对。私钥严格保管,公钥嵌入固件。
- 烧录公钥:将公钥烧录到设备的 OTP(一次性可编程)区域或 eFuse 中。一旦写入,不可更改。
- 签名固件:每次发布固件,用私钥对固件哈希签名,将签名附加到固件尾部。
- 设备验证:设备启动时,BootROM 从 OTP 读取公钥,验证 Bootloader 签名。通过后,Bootloader 再用同样的方式验证固件镜像。
- 回滚保护:在固件版本号上做签名,防止攻击者刷回有漏洞的旧版本。
我曾经在一个客户现场遇到一个问题:他们的设备支持 OTA 更新,但安全启动链只做到了 Bootloader 验证固件,BootROM 却没有验证 Bootloader。结果黑客通过物理手段直接替换了 Bootloader,绕过了所有安全校验。嗯,这就是典型的「信任链断裂」。
实践中的几个关键点
- 密钥管理:私钥必须离线存储,最好用 HSM(硬件安全模块)。我见过有人把私钥放在 CI 服务器上,结果被拖库,整个产品线报废。
- 公钥保护:公钥虽然可以公开,但必须防篡改。写入 OTP 或 eFuse 是最安全的。如果放在 Flash 里,攻击者可以替换公钥,用自己的私钥签名恶意固件。
- 签名算法选择:MCU 资源紧张时,ECDSA 是首选。如果芯片有硬件加速,RSA 也可以。但别用 ECDSA 的曲线参数自己改,直接用标准曲线(P-256、P-384)。
- 哈希算法:SHA-256 是底线。别用 SHA-1,别用 MD5。哪怕算力不够,也要用硬件加速模块。
- 回滚保护:签名时把版本号也签进去。设备验证时检查版本号是否大于当前版本。防止攻击者刷回有漏洞的旧固件。