信任根(Root of Trust):硬件信任锚点(ROM Bootloader),不可变代码的物理基础
聊安全启动,第一个绕不开的东西就是信任根。说白了,它是整个安全链的起点。如果这个起点都不可信,后面再怎么折腾也是白搭。
我个人习惯把信任根理解成「物理层面的绝对信任」。它不能改、不能删、不能被绕过。在嵌入式系统里,这个锚点通常就是芯片内部固化的 ROM Bootloader。
为什么是 ROM?不是 Flash?
你想想看,Flash 可以擦写,可以被篡改。攻击者要是改了你的 Flash 启动代码,那整个系统就沦陷了。ROM 不一样——它在芯片制造时就写死了,物理上不可更改。
我记得有一次做车规级芯片的安全评估,客户问能不能把 Bootloader 放在 Flash 里,省成本。我直接说不行。原因很简单:Flash 里的代码可以被物理探针改写,ROM 你拿激光都难改。这不是成本问题,是信任模型的问题。
核心要点:信任根必须是物理不可变的。ROM 是当前最现实的实现方式。
ROM Bootloader 到底干了什么?
ROM Bootloader 的任务其实很纯粹:验证下一级代码的签名。它自己不需要被验证,因为它是信任的起点。
具体来说,它做这几件事:
- 初始化硬件基础——时钟、内存、基本外设。够用就行,不需要全开。
- 加载下一级镜像——通常是从 Flash 的固定位置读出一段代码(比如 SPL 或 BL1)。
- 验证签名——用内置的公钥哈希去验签。公钥本身也固化在 ROM 里,或者用熔丝烧死。
- 跳转执行——验签通过,才把控制权交出去。否则死循环或进错误处理。
嗯,这里要注意:ROM Bootloader 的代码量通常很小。我见过最小的只有 4KB。为什么?因为 ROM 面积贵啊,而且功能越少,攻击面越小。
公钥放哪?
这是个好问题。ROM Bootloader 要验签,总得有个公钥吧?公钥放哪?
常见做法有两种:
| 方案 | 实现方式 | 优缺点 |
|---|---|---|
| ROM 固化 | 公钥直接写在 ROM 掩膜里 | 最安全,但无法更新。一旦密钥泄露,整批芯片报废。 |
| 熔丝(eFuse) | 芯片出厂时烧写公钥哈希 | 可定制,但熔丝数量有限。我建议用哈希而非完整公钥,省空间。 |
我曾经在一个 IoT 项目里踩过坑。当时用了 ROM 固化公钥,结果产品量产半年后,发现私钥被内部泄露了。那批芯片全部得召回。从那以后,我倾向于用熔丝方案,至少留条后路。
避坑指南:公钥的存储位置决定了你的密钥轮换能力。ROM 固化虽然安全,但灵活性差。量产前一定要想清楚密钥管理策略。
信任链的物理基础
ROM Bootloader 之所以能成为信任锚点,靠的是物理不可变性。但这还不够,它还需要满足几个条件:
- 只读性——运行时不能自修改,代码段必须写保护。
- 原子性——验签和跳转之间不能被打断。我见过一个设计,验签过了但跳转前被 DMA 覆盖了内存,结果执行了恶意代码。
- 最小化——功能越少,漏洞越少。ROM Bootloader 不需要 USB 协议栈,不需要文件系统,不需要网络。
说白了,信任根的设计哲学就是:做最少的事,做到最可靠。
一张图看懂信任根
下面这张图展示了 ROM Bootloader 在整个安全启动链中的位置和作用:
实际项目中的经验
我参与过一个安全网关的项目,ROM Bootloader 只有 8KB。当时团队想塞进去一个完整的 SHA-256 和 RSA 验签,结果 ROM 放不下。后来我们改用 ECDSA,密钥长度短,验签速度快,刚好塞下。
还有一次,我发现 ROM Bootloader 里有个 bug——它在验签前先把下一级镜像加载到了 RAM 里。这意味着攻击者可以在验签前通过 DMA 篡改 RAM 内容。嗯,这就是典型的「验签和加载顺序」问题。后来我们改成边加载边验签,或者加载到只读区域。
经验之谈:ROM Bootloader 的代码审查要比普通固件严格十倍。因为一旦流片,就没机会改了。我建议做形式化验证,至少要做代码走查和边界测试。
小结
信任根是整个安全启动链的基石。它必须是物理不可变的,功能必须最小化,验签流程必须原子化。ROM Bootloader 是目前最主流的实现方式,但公钥存储策略、验签算法选择、加载顺序设计,每一个细节都决定了这个锚点是否真的「可信」。
记住一句话:信任根不可信,则一切皆不可信。