信任根(RoT)基础:硬件信任根、软件信任根、信任链的建立与传递
说到固件安全,信任根是个绕不开的话题。我刚开始接触这个领域时,总觉得“信任”是个很虚的概念——芯片上电后,凭什么相信第一行代码是安全的?后来踩过几次坑才明白,信任根就是整个安全体系的锚点。锚点不稳,后面全是白搭。
说白了,信任根(Root of Trust, RoT)是一个绝对可信的起点。它必须满足两个条件:一是自身不可篡改,二是能验证下一级组件的可信度。今天我们就从硬件和软件两个维度,把信任根这件事彻底讲透。
2.1 硬件信任根:物理世界的锚点
硬件信任根,我习惯叫它“物理锚点”。它通常是一个不可更改的硬件模块,比如芯片内部的ROM、一次性可编程熔丝(eFuse),或者专用的安全协处理器。为什么必须是硬件?因为软件可以被改写,而硬件一旦固化,物理上就改不动了。
我在项目中遇到过最典型的硬件信任根,就是Boot ROM。芯片上电后,CPU第一条指令从Boot ROM里取,这段代码是芯片出厂时写死的,谁都没法改。你想想看,如果连Boot ROM都能被篡改,那整个安全体系就崩塌了。
常见的硬件信任根载体包括:
- Boot ROM:只读存储器,出厂固化,用于加载并验证下一级Bootloader。
- eFuse / OTP:一次性可编程存储,用于存储公钥哈希、芯片唯一ID、安全配置位。
- HSM / TPM:专用安全芯片,提供密钥生成、签名验证、随机数等硬件加速能力。
- PUF(物理不可克隆函数):利用芯片制造差异生成唯一密钥,防物理破解。
| 载体类型 | 可篡改性 | 典型用途 | 我见过的坑 |
|---|---|---|---|
| Boot ROM | 不可改(物理只读) | 第一级启动代码 | ROM bug只能通过硬件改版修复 |
| eFuse | 一次性写入 | 存储公钥哈希、安全等级 | 熔丝烧断后无法恢复,测试要格外小心 |
| HSM/TPM | 硬件隔离 | 密钥管理、签名验证 | 通信接口容易被侧信道攻击 |
| PUF | 物理随机 | 芯片唯一密钥生成 | 环境温度变化可能导致密钥不稳定 |
2.2 软件信任根:从硬件到软件的桥梁
硬件信任根再强,最终还是要跑软件。软件信任根,说白了就是被硬件信任根验证通过的那段代码。它本身不一定是硬件不可改的,但它的可信度由硬件信任根来保证。
我习惯把软件信任根理解为“信任接力棒的第一棒”。Boot ROM验证完Bootloader后,Bootloader就成了新的信任根,继续验证下一级。但这里有个关键点:软件信任根必须保持最小化。代码越少,攻击面越小,越容易做形式化验证。
软件信任根通常包含以下功能:
- 度量自身完整性:计算自身哈希,与硬件存储的参考值比对。
- 验证下一级镜像:使用公钥验证下一级固件的签名。
- 建立安全环境:配置MMU、关闭调试接口、初始化安全区域。
- 传递信任:将控制权交给已验证的下级组件。
2.3 信任链的建立与传递:逐级验证,环环相扣
信任链,就是一条从硬件信任根开始,逐级验证、逐级传递信任的链条。每一级都验证下一级的完整性和真实性,验证通过后才移交控制权。一旦某一级验证失败,系统必须进入安全状态——通常是死循环或复位。
典型的信任链流程如下:
- 上电复位:CPU从Boot ROM取指,执行固化代码。
- 度量Bootloader:Boot ROM读取Bootloader镜像,计算哈希,与eFuse中的参考值比对。
- 验证签名:使用eFuse中的公钥验证Bootloader的数字签名。
- 移交控制权:验证通过后,跳转到Bootloader执行。
- Bootloader度量OS Kernel:Bootloader重复上述过程,验证OS内核。
- OS度量应用:OS内核在加载应用时,继续验证应用签名。
这个过程,我称之为“洋葱式信任传递”——每一层都包裹着下一层,从最核心的硬件信任根向外层层展开。
2.4 信任链的常见攻击面与防御
信任链听起来很坚固,但实际落地时到处都是坑。我总结了几类最常见的攻击方式,以及对应的防御措施。
| 攻击类型 | 攻击手法 | 防御措施 | 我的亲身经历 |
|---|---|---|---|
| 回滚攻击 | 攻击者刷入旧版本固件,利用已知漏洞 | eFuse中存储版本计数器,禁止降级 | 曾经有个客户没做版本防回滚,被攻击者刷回一年前的固件,直接绕过所有安全补丁 |
| 密钥泄露 | 私钥被提取,攻击者签名恶意固件 | 使用HSM保护私钥,定期轮换 | 见过某厂商把签名私钥放在CI服务器上,明文存储,被挖矿脚本扫到后全网公开 |
| 侧信道攻击 | 通过功耗、电磁辐射分析提取密钥 | 使用恒定时间比较、随机延时、掩码技术 | 我在做安全认证时,实验室用简单功耗分析(SPA)就破解了一款未防护的签名验证实现 |
| JTAG/SWD调试接口 | 通过调试接口读取内存或篡改流程 | 量产时熔断调试接口,或使用密码保护 | 这个坑我踩过两次,后来强制要求所有产品在出厂前必须锁死调试接口 |
2.5 信任根的度量与报告
信任根不仅要“可信”,还要“可度量”。在可信计算领域,有一个概念叫度量启动(Measured Boot)。它和前面说的安全启动(Secure Boot)有什么区别?
- Secure Boot:验证失败就停止启动,保证只运行可信代码。
- Measured Boot:记录每一级组件的哈希值,即使启动继续,也能向远程验证方报告当前系统的信任状态。
我个人更倾向于两者结合:先用Secure Boot保证启动过程的安全性,再用Measured Boot记录信任链的度量值,用于远程证明(Remote Attestation)。
度量值通常存储在平台配置寄存器(PCR)中,由TPM或HSM管理。每一级启动组件都会扩展(Extend)PCR值:
// 伪代码:信任链度量过程
PCR[0] = HASH(Boot ROM)
PCR[1] = HASH(PCR[0] || Bootloader)
PCR[2] = HASH(PCR[1] || OS Kernel)
PCR[3] = HASH(PCR[2] || Application)
为什么要用“扩展”而不是“覆盖”?因为扩展操作是不可逆的,攻击者无法伪造一个特定的PCR值。你想想看,如果只是覆盖,攻击者完全可以在加载恶意代码后,把PCR改回正常值。扩展操作保证了度量值的完整性。
2.6 小结:信任根设计的三个黄金法则
做了这么多年固件安全,我总结出信任根设计的三个黄金法则,分享给你:
- 最小化原则:信任根的代码越少越好。Boot ROM最好控制在4KB以内,软件信任根不超过16KB。代码越少,越容易验证,越难被攻击。
- 物理隔离原则:硬件信任根必须与主系统物理隔离。Boot ROM不能通过系统总线改写,eFuse不能通过软件接口读取。隔离是信任的物理基础。
- 全链覆盖原则:信任链不能有断层。从Boot ROM到应用层,每一级都必须验证下一级。哪怕有一个环节跳过验证,整个信任链就失去了意义。