3、信任根(RoT)设计:信任根的定义与作用、片上ROM作为信任根、eFuse/Otp存储根密钥、物理不可克隆函数(PUF)技术
好,咱们今天聊聊信任根。这是整个安全启动的基石,说白了就是「第一把锁」。如果这把锁本身就不靠谱,后面再多的安全措施都是白搭。
我刚开始做嵌入式安全那会儿,总觉得信任根就是个概念,离实际代码很远。直到有一次,我负责的一个IoT设备被攻破了——攻击者直接替换了Flash里的Bootloader,设备就完全失控了。嗯,那次教训让我彻底明白了:没有信任根,安全就是空中楼阁。
3.1 信任根的定义与作用
信任根,英文叫Root of Trust,简称RoT。它是什么?
简单说,它是系统中绝对可信的一个起点。这个起点必须是硬件级别的,不能被篡改,不能被绕过。整个安全启动链,就是从它开始,一级一级验证下去的。
打个比方:你想想看,你要验证一份文件的真伪,你得先有一枚绝对真实的印章。这枚印章就是信任根。没有它,你拿什么去比对?
信任根的作用,我归纳为三点:
- 提供初始信任:系统上电后,第一个执行的代码必须是可信的。它决定了后续所有代码的可信度。
- 存储根密钥:用于验证固件签名的公钥,必须安全地存放在信任根里。密钥泄露,一切归零。
- 执行度量与验证:信任根负责测量下一级代码的哈希值,并与存储的期望值比对。不一致就拒绝启动。
核心原则:信任根必须是不可变的、不可绕过的、物理安全的。任何软件层面的信任,最终都要追溯到硬件信任根。
3.2 片上ROM作为信任根
最常见的信任根实现方式,就是片上ROM。芯片出厂时,在ROM里固化一段启动代码。这段代码是只读的,谁都没法改。
我个人习惯把这段ROM代码叫做「BootROM」。它通常很小,几KB到几十KB,但功能极其关键:
- 初始化硬件(时钟、内存控制器等)
- 从指定存储介质(如NAND Flash、eMMC)读取下一级Bootloader
- 验证Bootloader的签名或哈希值
- 验证通过后,跳转到Bootloader执行
为什么ROM适合做信任根?原因很简单:
- 物理不可改:ROM是掩膜编程的,出厂后内容就固定了。攻击者想改?除非换芯片。
- 执行最早:CPU复位后,第一条指令就是从ROM取址。没有比它更早的代码了。
- 设计简单:ROM代码功能单一,不容易有漏洞。我见过一些复杂的BootROM,反而成了攻击面。
避坑指南:我曾经遇到过一个项目,BootROM里有个调试后门——只要拉高某个GPIO引脚,就会跳过签名验证。这玩意儿在开发阶段确实方便,但量产时忘了熔断相关eFuse,结果被安全团队一锅端了。所以,量产前一定要检查所有调试接口是否关闭。
3.3 eFuse/OTP存储根密钥
信任根有了,但根密钥放哪儿?
你不能把公钥直接写在ROM里——因为ROM内容固定,一旦密钥需要更新,就得换芯片。这显然不现实。
所以,业界普遍使用eFuse或OTP(一次性可编程)存储器来存放根密钥。
eFuse是什么?说白了就是芯片上的一排「保险丝」。出厂时都是连通的,你可以通过施加高电压把某些熔丝「烧断」。烧断后状态就永久改变了。用二进制表示:连通是0,烧断是1。
OTP类似,但实现方式不同。有些用反熔丝技术,有些用电荷存储。共同点是:只能写一次,不能擦除。
根密钥的存储流程一般是这样的:
- 芯片出厂时,eFuse/OTP区域全是默认值(通常是0)
- 在安全产线上,将公钥的哈希值或公钥本身写入eFuse/OTP
- 写入后立即锁定,防止后续篡改
- BootROM启动时,从eFuse/OTP读取根密钥,用于验证Bootloader签名
| 存储方式 | 优点 | 缺点 | 典型容量 |
|---|---|---|---|
| eFuse | 工艺成熟,集成度高 | 写入需要高电压,有物理探测风险 | 几百bit ~ 几Kbit |
| OTP (反熔丝) | 抗物理攻击能力强 | 面积大,成本高 | 几Kbit ~ 几十Kbit |
| OTP (电荷存储) | 密度高,成本低 | 数据保持时间有限(10年左右) | 几十Kbit ~ 几百Kbit |
注意:eFuse/OTP的容量非常有限,通常只存储根公钥的哈希值(256位或384位),而不是完整的公钥。BootROM里预置了公钥模板,验证时只需比对哈希即可。这样可以节省宝贵的OTP空间。
3.4 物理不可克隆函数(PUF)技术
讲完eFuse,咱们聊聊PUF。这玩意儿挺有意思的。
eFuse有个硬伤:密钥是明文存储在芯片上的。虽然物理上难以篡改,但攻击者可以用探针、电子显微镜等手段直接读取。你想想看,密钥都被人看到了,那还安全个啥?
PUF就是来解决这个问题的。它的核心理念是:不存储密钥,而是「生成」密钥。
怎么生成?利用芯片制造过程中不可避免的物理差异。每颗芯片的晶体管阈值电压、金属线延迟、SRAM上电初始值……这些参数都是随机的、唯一的。PUF电路测量这些物理特征,然后通过算法提取出稳定的密钥。
好处很明显:
- 密钥不存储:只在需要时临时生成,用完就消失。攻击者想偷?没门。
- 芯片唯一:每颗芯片的PUF响应都不同,相当于芯片的「指纹」。
- 抗物理攻击:探针一碰,物理特征就变了,密钥就没了。
我记得有一次,客户要求做防克隆设计。他们担心有人抄板,复制固件和硬件。我建议用PUF生成设备唯一密钥,然后绑定到固件加密上。这样即使固件被dump出来,换到另一颗芯片上也跑不了——因为PUF生成的密钥不同,解密失败。
PUF也有缺点:
- 环境敏感:温度、电压变化会影响PUF输出。需要纠错电路(Helper Data)来保证稳定性。
- 面积开销:PUF电路和纠错逻辑会占用芯片面积。
- 成熟度:相比eFuse,PUF技术相对较新,有些方案还没经过大规模量产验证。
实际应用建议:我个人倾向的方案是「eFuse + PUF」混合使用。eFuse存储根公钥哈希(用于验证Bootloader),PUF生成设备私钥(用于身份认证和加密)。这样既保证了启动链的信任根安全,又实现了设备级别的唯一性。
好,信任根这块就聊到这儿。总结一下:
- 信任根是安全启动的基石,必须是硬件级别的、不可篡改的
- 片上ROM是最常见的信任根载体,负责执行初始验证
- eFuse/OTP用于存储根密钥,容量有限但足够安全
- PUF技术不存储密钥,而是利用物理差异生成密钥,抗物理攻击能力强
下一章,咱们聊聊签名验证的具体实现——RSA、ECDSA这些算法在Bootloader里怎么用,以及我踩过的那些坑。