3、芯片安全启动链:Boot ROM不可篡改性、代码签名与验证、安全加载固件
芯片安全启动链,说白了就是给芯片装上一套「出生证明 + 指纹锁 + 防拆封条」。你想想看,如果芯片上电后执行的第一个代码就被篡改了,那后面所有安全措施都是白搭。我在做物联网芯片安全审计时,见过太多「裸奔」的启动流程——攻击者直接替换固件头,就能让设备加载恶意代码。嗯,这章我们就来拆解这条链上的三个关键环节。
3.1 Boot ROM:芯片的「基因锁」
Boot ROM 是芯片出厂时固化在硅片上的只读代码。它不可篡改,因为物理上就没有写入接口。我习惯把它比作芯片的「基因」——你没法改变自己的 DNA,对吧?
核心特性:
- 物理只读:掩膜 ROM 或 OTP(一次性可编程)实现,流片后无法修改
- 最先执行:上电复位后,CPU 直接从 Boot ROM 地址取指
- 最小可信基:整个安全启动链的信任锚点
我记得有一次,客户问能不能通过固件升级修复 Boot ROM 的漏洞。我直接告诉他:「除非你把芯片拆了重新流片,否则没戏。」这就是为什么 Boot ROM 的代码必须经过极其严格的验证——它没有后悔药。
注意:有些低成本芯片会用 Flash 模拟 Boot ROM,这种方案存在被物理篡改的风险。我在消费电子项目中遇到过,攻击者用探针直接改写 Flash 内容,绕过了整个安全启动链。如果你选型时看到「Flash Boot」字样,一定要问清楚是否有写保护机制。
3.2 代码签名与验证:给固件贴上「防伪标签」
Boot ROM 执行完后,需要加载下一级固件(比如 Bootloader)。但怎么保证这个固件是厂商发布的、没被中间人动过手脚?答案就是代码签名。
流程其实不复杂:
- 厂商用私钥对固件哈希签名,生成签名值
- 固件包 = 固件 + 签名值 + 证书链
- 芯片用预置的公钥验证签名
这里有个关键点——公钥存在哪?我建议放在 Boot ROM 或 OTP 中。如果公钥存在外部 Flash,攻击者可以替换公钥,那签名就形同虚设了。
实战经验:我曾经帮一家车规芯片厂商设计签名方案。他们最初用 RSA-2048,但验签时间太长(约 200ms),影响启动速度。后来换成 ECDSA P-256,验签时间降到 30ms 以内。如果你对启动时间敏感,建议优先考虑 ECC 系列算法。
代码示例(伪代码,展示核心逻辑):
// Boot ROM 中的验签流程
void verify_firmware(uint8_t* firmware, uint32_t len,
uint8_t* signature, uint8_t* pubkey) {
// 1. 计算固件哈希
uint8_t hash[32];
sha256(firmware, len, hash);
// 2. 用预置公钥验签
if (ecdsa_verify(hash, signature, pubkey) != SUCCESS) {
// 验签失败,进入错误处理
halt_boot();
return;
}
// 3. 验签通过,跳转到固件入口
jump_to(firmware);
}
避坑指南:我曾经见过一个方案,验签通过后直接跳转,没检查固件头部的版本号。结果攻击者把旧版本固件(含已知漏洞)重新签名后加载进去,实现了降级攻击。记住:签名验证只是第一步,版本号、设备 ID、防回滚标记都要一起校验。
3.3 安全加载固件:逐级信任,层层把关
现代芯片的启动链通常不止两级。以手机 SoC 为例:
| 启动阶段 | 加载者 | 验证者 | 存储介质 |
|---|---|---|---|
| Boot ROM | 硬件固化 | 物理不可篡改 | 掩膜 ROM |
| Primary Bootloader (PBL) | Boot ROM | Boot ROM 验签 | 内部 SRAM |
| Secondary Bootloader (SBL) | PBL | PBL 验签 | DDR |
| OS Kernel | SBL | SBL 验签 | Flash |
每一级只信任上一级,上一级验证下一级的签名后才加载执行。这就是「信任链」的概念。我习惯把它画成下面这张图:
你可能会问:为什么不用一级启动,直接加载 OS?原因很简单——Boot ROM 空间有限(通常只有几十 KB),放不下复杂的验签逻辑和驱动。分级的另一个好处是:如果 SBL 发现固件损坏,可以回退到 PBL 的恢复模式,不至于变砖。
安全加载的四个检查点:
- 签名验证:确保固件来源可信、未被篡改
- 版本检查:防止降级攻击(结合防回滚计数器)
- 完整性校验:加载过程中 CRC 或哈希校验,防止传输错误
- 地址范围检查:防止固件越界覆盖敏感区域
嗯,说到地址范围检查,我踩过一个坑。某次项目中,Boot ROM 加载 PBL 时没检查目标地址,攻击者构造了一个超长固件头,让 PBL 代码覆盖了安全配置寄存器。结果验签虽然通过了,但安全区域被禁用。从那以后,我每次设计启动链都会加一条硬规则:加载前必须校验目标地址是否在合法范围内。
个人习惯:我建议在 Boot ROM 中实现一个「最小验签引擎」,只支持一种签名算法(比如 ECDSA P-256)和一种哈希算法(SHA-256)。算法越少,攻击面越小。别想着在 Boot ROM 里搞算法可配置——那等于给攻击者留后门。
最后说一句:安全启动链不是万能的。它只能保证加载的固件是厂商签名的,但管不了固件本身有没有漏洞。不过,没有这条链,芯片连「可信」的资格都没有。它是所有上层安全的基础,也是供应链身份安全的第一道防线。