一、信任根(RoT)设计:硬件信任根的概念

信任根,说白了就是整个安全体系的「老祖宗」。

我经常跟团队讲,你设计再复杂的加密算法、再精巧的访问控制,如果最底层的信任根被人动了手脚,那一切都是白搭。就像盖房子,地基要是歪了,上面装修得再漂亮也没用。

硬件信任根,就是那个不可篡改、不可伪造的「初始信任点」。它必须满足三个条件:

  • 不可伪造:攻击者无法通过软件或硬件手段伪造一个假的信任根
  • 不可篡改:一旦写入,就不能被修改或擦除
  • 唯一性:每颗芯片的信任根都是唯一的,就像人的指纹

核心观点:信任根是整个安全链路的起点。没有它,后续的签名验证、安全启动、加密存储全都是空中楼阁。

我在做一款4K机顶盒项目时,客户要求支持HDCP 2.3内容保护。当时我们用的SoC信任根设计不够健壮,结果被第三方通过电压毛刺攻击绕过了信任根校验。嗯,那次教训让我深刻认识到——信任根不是「有就行」,而是要「足够硬」。

二、一次性可编程存储器(OTP/eFuse)原理

2.1 OTP是什么?

OTP,全称One-Time Programmable,一次性可编程存储器。你想想看,名字已经说得很清楚了——只能写一次,写完就改不了。

常见的OTP实现有两种:

类型 原理 特点 典型应用
熔丝型(Fuse) 通过大电流熔断金属丝 写入后不可恢复,可靠性高 密钥存储、芯片ID
反熔丝型(Anti-fuse) 通过高电压击穿绝缘层 面积小,功耗低 配置位、修调参数
eFuse 基于电迁移效应的硅熔丝 可编程性好,支持部分写入 SoC中广泛使用

我个人习惯用eFuse,因为它可以在芯片封装后编程,灵活性更好。不过要注意,eFuse的编程电压和时序要求很严格,搞不好就把整颗芯片废了。

2.2 eFuse的工作原理

eFuse本质上是一根很细的硅化多晶硅导线。编程时,我们给它通一个大电流,让电子在导线中产生「电迁移」效应——说白了就是把原子从一端推到另一端,形成断路。

为什么会这样?因为硅化多晶硅的电阻率比金属高,电流密度一大,局部温度升高,原子就开始「搬家」了。一旦断开,就再也接不回去了。

// eFuse编程的典型时序(伪代码)
void program_efuse(uint32_t address, uint32_t data) {
    // 1. 使能编程电压(通常1.8V -> 2.5V)
    set_program_voltage(2.5);
    
    // 2. 选择目标eFuse单元
    select_efuse_cell(address);
    
    // 3. 施加编程脉冲(约10μs)
    apply_program_pulse(10);  // 单位:微秒
    
    // 4. 验证编程结果
    if (read_efuse(address) != data) {
        // 编程失败,这颗芯片可能废了
        mark_chip_as_defective();
    }
    
    // 5. 恢复电压
    set_program_voltage(1.8);
}

警告:eFuse编程是不可逆操作!我曾经见过一个同事,在调试时不小心把测试模式写进了eFuse,结果芯片再也无法进入正常工作模式。所以,编程前一定要三思,最好有「写保护」机制。

2.3 OTP中存什么?

在机顶盒SoC中,OTP/eFuse通常存储以下关键信息:

  • 根公钥哈希:用于验证启动镜像签名的公钥的哈希值
  • 芯片唯一ID:每颗芯片独一无二的标识符
  • 安全配置位:比如JTAG是否禁用、调试接口是否锁定
  • 密钥种子:用于派生其他密钥的根密钥材料
  • 生命周期状态:芯片处于开发、生产还是最终用户模式

三、信任根在SoC中的实现方式

3.1 硬件信任根的典型架构

在SoC中,信任根不是孤立的,它需要和CPU、内存控制器、外设等协同工作。我画了一个简化的架构图(用文字描述):

+------------------+
|    OTP/eFuse     |  ← 存储根密钥和配置
+--------+---------+
         |
         v
+------------------+
|  信任根控制器     |  ← 硬件状态机,负责校验
+--------+---------+
         |
    +----+----+
    |         |
    v         v
+--------+ +--------+
| CPU    | | 内存   |
| BootROM| | 控制器 |
+--------+ +--------+

信任根控制器是一个硬件状态机,它在上电后最先运行。它的工作流程是这样的:

  1. 上电复位:CPU被复位,BootROM开始执行
  2. 读取OTP:从eFuse中读取根公钥哈希和配置位
  3. 验证BootROM:用根公钥验证BootROM的签名(如果BootROM本身需要验证)
  4. 加载下一级:从Flash中读取bootloader,验证签名,然后跳转执行
  5. 链式信任:每一级都验证下一级的签名,形成信任链

经验之谈:我建议在信任根控制器中加入「防回滚」机制。什么意思呢?就是OTP中记录一个版本号,只允许加载不低于该版本的镜像。这样即使攻击者拿到了旧版本的漏洞,也无法降级攻击。

3.2 信任根的物理安全

光有逻辑上的信任根还不够,物理安全同样重要。攻击者可能会尝试:

  • 电压毛刺攻击:在信任根校验时注入电压毛刺,让校验跳过
  • 激光切割:用激光切断eFuse的读取路径
  • 探针攻击:用微探针直接读取OTP中的密钥
  • 温度攻击:通过极端温度改变eFuse的物理特性

针对这些攻击,我们在SoC中做了以下防护:

攻击类型 防护措施 实现方式
电压毛刺 电压/频率检测器 实时监控电源电压,异常时复位
激光切割 金属屏蔽层 在eFuse上方覆盖金属网格
探针攻击 总线加密 OTP到控制器的数据加密传输
温度攻击 温度传感器 超出工作温度范围时触发安全响应

3.3 实际项目中的避坑指南

我曾经在一个项目中踩过一个大坑。当时我们用的SoC支持「安全调试模式」,允许开发者在OTP中写入一个调试密钥来解锁调试接口。结果呢?生产时忘了把这个功能关掉,导致攻击者可以通过暴力破解调试密钥来绕过信任根。

从那以后,我定了一个规矩:量产芯片的OTP中,必须把调试接口永久锁定。具体做法是在OTP中设置一个「生命周期」字段:

// 生命周期状态定义
#define LIFECYCLE_DEV        0x00  // 开发模式:JTAG开放
#define LIFECYCLE_PROD       0x01  // 生产模式:JTAG锁定
#define LIFECYCLE_RMA        0x02  // 返修模式:仅允许特定操作

// 在BootROM中检查生命周期
void check_lifecycle() {
    uint8_t lc = read_otp(OTP_LIFECYCLE_ADDR);
    
    if (lc == LIFECYCLE_PROD) {
        // 永久锁定JTAG
        disable_jtag_permanently();
        // 锁定OTP写入
        lock_otp_write();
    }
}

关键提醒:信任根设计不是「一锤子买卖」。它需要在芯片设计阶段就考虑进去,后期想加都加不了。我建议在SoC架构设计初期,就成立一个安全小组,专门负责信任根的设计和评审。

3.4 信任根的验证流程

最后,我总结一下信任根在SoC中的完整验证流程:

  1. 硬件初始化:上电后,信任根控制器自动启动
  2. OTP读取:从eFuse中读取根公钥哈希(256位)
  3. BootROM校验:用根公钥验证BootROM的RSA签名
  4. BootROM执行:校验通过后,CPU开始执行BootROM
  5. 加载bootloader:BootROM从Flash读取bootloader,验证签名
  6. 加载内核:bootloader验证Linux内核镜像的签名
  7. 加载文件系统:内核验证文件系统的完整性(dm-verity)

你看,整个链条从硬件信任根开始,一级一级往上验证。只要最底层的信任根是安全的,整个系统就是安全的。

嗯,这一章的内容就到这里。下一章我们会深入讲「安全启动流程」,看看信任根是如何一步步保护整个启动过程的。