第四章:硬件信任根——eFuse、OTP、HSM与TEE在安全启动中的作用
好,咱们接着聊。上一章讲了签名和验签的流程,你可能觉得「嗯,算法懂了,流程也通了」。但有个关键问题:验签用的公钥,放在哪儿才安全?
你想想看,如果攻击者能把你的公钥给换了,那他自己签的固件也能通过验证。整个安全启动就形同虚设。所以,公钥的存储位置,就是整个信任链的「根」。这个根,必须得是硬件级别的,不可篡改的。
今天我们就来拆解这四个硬件信任根:eFuse、OTP、HSM 和 TEE。我在项目里跟它们打了十几年交道,踩过的坑不少,希望能帮你少走弯路。
4.1 eFuse:一次编程,终生锁定
eFuse,说白了就是芯片里的一排「保险丝」。出厂时都是通的(逻辑1),你可以通过施加高电压把某些熔丝烧断(变成逻辑0)。烧断后就再也接不回来了,这就是「一次编程」的含义。
核心作用:存储根公钥的哈希值,或者存储芯片的唯一身份ID。
我在一个车载项目里用过 eFuse。当时客户要求:固件只能由我们签,别人签的一律不认。做法很简单:
- 先把我们的根公钥算出一个SHA-256哈希
- 把这个哈希烧进eFuse
- BootROM启动时,读取eFuse里的哈希,跟固件签名里的公钥哈希比对
嗯,这里要注意:eFuse的容量通常很小,一般就几百比特到几K比特。你不可能把整个公钥(比如RSA-2048有2048位)存进去。所以存的是哈希值,256位就够了。
警告:eFuse一旦烧写,无法撤销。如果烧错了公钥哈希,整批芯片就废了。我见过有同事在产线上烧错了批次,损失几十万。所以烧写前一定要三重校验。
4.2 OTP:更灵活的「一次性」存储
OTP(One-Time Programmable)跟eFuse类似,也是一次写入。但实现方式不同:OTP用的是浮栅晶体管,跟Flash类似,但只能写一次。
我个人习惯把OTP看作「eFuse的升级版」。为什么?
- 容量更大:可以存几K到几十K的数据
- 可以分区域:有些区域写死后还能再写其他区域
- 支持锁定:可以设置「锁定位」,锁死后连读都不让读
举个例子,我在一个通信设备项目里,用OTP存了三样东西:
| 区域 | 内容 | 访问权限 |
|---|---|---|
| 区域0 | 根公钥哈希 | 只读(BootROM可读) |
| 区域1 | 芯片序列号 | 只读 |
| 区域2 | 调试接口密码 | 锁定(写后不可读) |
你看,区域2的调试密码写进去后,连CPU自己都读不出来。只有调试工具用正确的密码才能解锁JTAG。这招防的就是物理攻击——攻击者想通过JTAG读固件?没门。
4.3 HSM:硬件安全模块,专干脏活累活
HSM(Hardware Security Module)是个独立的加密协处理器。它有自己的CPU、内存、真随机数发生器,甚至有自己的防篡改传感器。
说白了,HSM就是芯片里的「保险柜」。你把私钥、证书、加密密钥全扔进去,外面的人碰不到。
我在一个金融POS机项目里用过HSM。那玩意儿要求:私钥必须物理隔离,主CPU不能直接读取。所有签名操作都得通过HSM完成:
// 伪代码:通过HSM签名固件
hsm_handle = hsm_open(HSM_DEVICE_0);
hsm_session = hsm_create_session(hsm_handle, "admin", "password");
// 注意:私钥从不离开HSM
hsm_key_id = hsm_load_key(hsm_session, KEY_ID_FIRMWARE_SIGN);
// 传入哈希,返回签名
uint8_t hash[32];
uint8_t signature[256];
sha256_compute(firmware_data, firmware_size, hash);
hsm_sign(hsm_session, hsm_key_id, hash, signature);
// 签名完成后,销毁会话
hsm_close_session(hsm_session);
hsm_close(hsm_handle);
你看,主CPU只传了哈希进去,拿回来的是签名。私钥全程没出现过。这就是HSM的价值——即使主CPU被攻破,私钥也拿不到。
小技巧:HSM通常支持「密钥使用计数」。你可以设置某个私钥最多签1000次。超过后自动销毁。这在防重放攻击时特别有用。
4.4 TEE:可信执行环境,软硬结合
TEE(Trusted Execution Environment)跟HSM不同。HSM是独立的硬件,TEE是在主CPU里划出一块「安全区」。这块区域有独立的运行空间、独立的内存、独立的外设访问权限。
ARM的TrustZone就是最典型的TEE实现。它把CPU分成两个世界:
- 正常世界(Normal World):跑VxWorks、Linux这些通用OS
- 安全世界(Secure World):跑一个小型安全OS,专门处理敏感操作
我做过一个项目,把固件验签逻辑放在TEE里执行。流程是这样的:
- BootROM启动,加载TEE内核
- TEE从eFuse读取根公钥哈希
- TEE验证VxWorks内核的签名
- 验证通过后,TEE才释放控制权给VxWorks
这样做的好处是:验签过程对正常世界完全透明。VxWorks根本不知道验签是怎么做的,也没法干预。攻击者就算攻破了VxWorks,也改不了验签逻辑。
关键区别:HSM是「硬件保险柜」,TEE是「软件保险箱」。HSM更安全但成本高,TEE更灵活但依赖CPU架构。实际项目中,我经常两者结合用——HSM存私钥,TEE做验签。
4.5 四种方案的对比与选型建议
好了,四种方案都讲完了。你可能要问:「那我该用哪个?」
嗯,没有标准答案。我根据自己的经验,给个参考:
| 方案 | 安全等级 | 成本 | 灵活性 | 适用场景 |
|---|---|---|---|---|
| eFuse | 中 | 低 | 低 | 消费电子、IoT设备 |
| OTP | 中高 | 中 | 中 | 工业控制、通信设备 |
| HSM | 高 | 高 | 高 | 金融、车规、国防 |
| TEE | 中高 | 中 | 高 | 移动设备、嵌入式Linux |
我个人建议:能用eFuse就别用OTP,能用OTP就别用HSM。为什么?因为越复杂的方案,出问题的概率越大。我曾经在一个项目里用了HSM,结果因为HSM的驱动跟VxWorks的调度器有冲突,导致系统随机死机。查了整整两周才定位到问题。
避坑指南:如果你选择TEE方案,一定要确认TEE的「安全监控模式」是否支持VxWorks。有些TEE实现只支持Linux,跟VxWorks的MMU配置不兼容。我吃过这个亏,后来不得不换方案。
4.6 小结
今天的内容就这些。总结一下:
- eFuse:一次编程,适合存根公钥哈希
- OTP:更灵活的一次性存储,可以分区管理
- HSM:硬件保险柜,私钥物理隔离
- TEE:软件保险箱,验签逻辑隔离
下一章,我们会把这些硬件信任根跟VxWorks的BootLoader结合起来,讲一讲完整的信任链是如何建立的。到时候你会看到,从芯片上电到VxWorks启动,每一步的信任是怎么传递的。
好,今天就到这儿。有问题欢迎交流。