4、安全启动概念与威胁模型:启动链信任根、固件完整性、机密性、防回滚、常见攻击路径(调试接口、物理攻击、恶意固件)

安全启动(Secure Boot)是嵌入式系统可信计算基(TCB)的起点,其核心目标并非简单地“让系统能启动”,而是确保系统只运行经授权且未被篡改的固件。在Cortex-M33配合TrustZone的环境中,安全启动不仅涉及代码的完整性校验,还涉及安全/非安全世界的隔离边界、密钥的生命周期管理以及硬件级攻击面的收敛。本章将围绕启动链信任根、固件完整性、机密性、防回滚四大支柱展开,并系统梳理调试接口、物理攻击、恶意固件三类典型攻击路径,帮助开发者建立从威胁建模到落地方案的系统性认知。

Cortex-M33 TrustZone 安全启动威胁模型总览 信任根 (RoT) BootROM + OTP/efuse 不可变代码 + 硬件密钥 启动链 (Boot Chain) BL1 → BL2 → 应用固件 逐级度量 + 签名验证 安全属性 完整性 / 机密性 / 防回滚 认证加密 + 版本计数 攻击面 调试/物理/恶意 信任根组成 • BootROM (掩膜ROM) • OTP/efuse 密钥 • 安全调试控制 • 生命周期状态 • 安全/非安全边界 启动链流程 1. BootROM 验证 BL1 签名 2. BL1 验证 BL2 签名+版本 3. BL2 验证应用固件 4. 建立安全世界上下文 5. 跳转非安全世界 安全属性实现 • 完整性: SHA-256/384 • 签名: ECDSA/RSA • 机密性: AES-GCM/CCM • 防回滚: 单调计数器 • 抗故障注入: 冗余校验 攻击类型 • SWD/JTAG • 电压/时钟毛刺 • 激光/聚焦离子束 • 恶意固件替换 • 中间人攻击 威胁模型核心问题 • 攻击者能否绕过信任根直接执行任意代码? • 攻击者能否提取固件中的机密(密钥、算法)? • 攻击者能否将系统回滚到存在已知漏洞的旧版本? • 攻击者能否通过调试接口或物理探测破坏安全边界? • 攻击者能否利用固件更新流程中的漏洞植入恶意代码?

上图展示了安全启动威胁模型的全景:信任根作为不可变锚点,启动链逐级验证,安全属性提供多维保护,而攻击面则从调试、物理、固件三个方向切入。理解这一模型是设计安全启动方案的前提。

4.1 启动链信任根:不可变锚点与硬件信任基础

信任根(Root of Trust, RoT)是安全启动链中最底层的信任锚点,它必须满足两个核心条件:不可篡改性与不可绕过性。在Cortex-M33系统中,信任根通常由BootROM(掩膜ROM)和一次性可编程(OTP)存储共同构成。BootROM在芯片出厂时固化,无法通过软件或外部接口修改;OTP/efuse则用于存储根密钥、生命周期状态和安全配置。

4.1.1 核心原理:信任根的构成与职责

信任根承担以下关键职责:

  • 根密钥存储:在OTP中烧录根公钥哈希或根公钥本身,用于验证第一级引导加载程序(BL1)的签名。
  • 安全启动使能:通过OTP中的安全位控制是否强制启用安全启动流程,防止攻击者禁用校验。
  • 生命周期管理:记录芯片生命周期状态(如开发、生产、RMA),不同状态下调试接口权限不同。
  • 安全/非安全边界初始化:在启动早期配置TrustZone的SAU(安全属性单元)和IDAU(实现定义属性单元),划定安全世界与非安全世界的隔离边界。

在Cortex-M33中,TrustZone通过SAU_CTRL寄存器控制安全属性的分配,而BootROM在复位后最先执行,它有权配置这些寄存器。这意味着信任根不仅是代码层面的锚点,也是硬件隔离机制的初始化者。

关键设计原则:信任根必须最小化。BootROM中只应包含启动验证所需的最小代码集,任何额外的功能都会扩大攻击面。例如,不应在BootROM中实现网络协议栈或复杂的文件系统解析,这些功能应后移到BL1或BL2阶段。

4.1.2 判断方法:如何验证信任根的正确性

在实际项目中,验证信任根配置是否合理,可以从以下维度检查:

  1. 检查OTP烧录状态:确认根密钥是否已正确烧录,且OTP的写保护位已生效,防止后续篡改。
  2. 验证BootROM版本:通过芯片ID寄存器确认BootROM版本,确保没有已知漏洞。
  3. 测试安全启动使能位:尝试在未使能安全启动的情况下启动,系统应拒绝执行。
  4. 审计SAU配置:在启动早期读取SAU寄存器,确认安全/非安全边界符合设计预期。

4.1.3 实战场景:从开发到量产的安全状态切换

某物联网设备采用Cortex-M33 + TrustZone架构,开发阶段需要开放调试接口以便调试,但量产时必须关闭。具体操作流程如下:

// 开发阶段(OTP未烧录安全位)
1. 通过SWD连接调试器,读取芯片ID和BootROM版本。
2. 配置SAU区域,将外设和内存划分为安全/非安全区域。
3. 烧录BL1、BL2和应用固件,验证签名校验逻辑。

// 量产阶段(烧录安全位)
1. 使用一次性烧录工具写入根公钥哈希到OTP。
2. 设置生命周期状态为"安全封闭"。
3. 烧录安全启动使能位,永久禁用SWD调试接口。
4. 执行最终启动测试,确认系统只能运行签名固件。

此过程中,开发阶段的调试便利性与量产阶段的安全性存在冲突,必须通过生命周期状态机来管理。Cortex-M33的DBGMCU寄存器配合OTP位,可以实现从开发到量产的平滑过渡。

风险提示:OTP烧录是不可逆操作。一旦烧录安全启动使能位,如果后续发现固件签名密钥泄露,将无法通过软件更新更换密钥,只能更换芯片。因此,在量产前必须进行充分的密钥管理和备份策略设计。

4.1.4 常见误区与总结

  • 误区一:信任根等同于安全启动。信任根只是起点,完整的启动链还需要每一级都正确验证下一级。
  • 误区二:BootROM代码越全越好。BootROM功能越多,漏洞风险越大,应保持最小化。
  • 误区三:忽略生命周期状态管理。如果开发阶段的安全位未正确管理,可能导致量产设备仍开放调试接口。

信任根的设计质量直接决定整个安全启动体系的可信度。一个被攻破的信任根意味着所有上层安全措施都形同虚设。

4.2 固件完整性:签名验证与度量启动

固件完整性是安全启动的核心目标之一,它确保固件在存储或传输过程中未被篡改。完整性保护通常通过哈希算法和数字签名实现,而Cortex-M33的TrustZone环境还提供了额外的隔离保护,防止运行时的动态篡改。

4.2.1 核心原理:从哈希到签名的完整性链

完整性验证的基本流程如下:

  1. 哈希计算:对固件镜像计算SHA-256(或SHA-384)哈希值。
  2. 签名生成:使用私钥对哈希值进行签名(如ECDSA-P256或RSA-2048)。
  3. 签名验证:在启动时,使用公钥验证签名,确保哈希值未被篡改。

在Cortex-M33中,TrustZone可以将公钥存储在安全世界,而验证过程在安全世界执行,非安全世界的代码无法访问公钥或篡改验证逻辑。这种隔离设计比传统MCU的单一地址空间方案更安全。

算法密钥长度签名长度计算开销适用场景
SHA-256 + ECDSA-P256256位64字节低资源受限的MCU
SHA-384 + ECDSA-P384384位96字节中高安全等级场景
SHA-256 + RSA-20482048位256字节高兼容性要求高的场景
SHA-256 + HMAC128-256位32字节极低对称密钥场景(不推荐用于启动链)

对于Cortex-M33,推荐使用ECDSA-P256,因为它在安全强度和计算开销之间取得了良好平衡,且TrustZone硬件加速器(如CryptoCell)通常支持该算法。

4.2.2 操作流程:实现多级完整性验证

一个典型的多级启动链完整性验证流程如下:

// 伪代码:BL1验证BL2
void BL1_verify_BL2(void) {
    // 1. 从OTP加载根公钥
    uint8_t root_pubkey[64] = load_from_otp();
    
    // 2. 计算BL2镜像的SHA-256哈希
    uint8_t hash[32];
    sha256_compute(BL2_IMAGE_ADDR, BL2_IMAGE_SIZE, hash);
    
    // 3. 验证BL2签名
    uint8_t signature[64] = read_from_flash(BL2_SIGNATURE_ADDR);
    if (ecdsa_verify(root_pubkey, hash, signature) != SUCCESS) {
        enter_error_state();
    }
    
    // 4. 检查BL2版本号(防回滚)
    uint32_t bl2_version = read_version(BL2_IMAGE_ADDR);
    if (bl2_version < get_min_version()) {
        enter_error_state();
    }
    
    // 5. 跳转到BL2
    jump_to(BL2_IMAGE_ADDR);
}

每一级引导程序都重复上述过程,直到应用固件被验证并加载。这种链式验证确保了从信任根到应用层的完整信任传递。

4.2.3 案例拆解:固件升级中的完整性保护

某智能门锁产品支持OTA固件升级,攻击者尝试在升级过程中注入恶意固件。初始现象:设备在升级后频繁死机,且行为异常。分析过程:

  1. 日志分析:发现设备启动时跳过了签名验证步骤,直接执行了升级包中的代码。
  2. 根因定位:升级流程中,新固件在写入Flash前未进行完整性校验,且启动时BL2的验证逻辑存在漏洞——当固件头部的版本号字段被修改为0xFFFFFFFF时,验证代码误判为“跳过验证”。
  3. 修复方案:在BL2中增加严格的版本号范围检查,并强制要求所有固件必须经过签名验证,不允许任何“跳过”路径。
  4. 结果对比:修复后,攻击者无法通过修改版本号绕过验证,设备启动恢复正常。
经验总结:完整性验证必须覆盖整个固件镜像,包括头部、代码段、数据段和尾部填充。任何“优化”或“快捷路径”都可能成为攻击入口。

4.2.4 常见误区与总结

  • 误区一:只验证固件头部。攻击者可以修改代码段而不改变头部,导致校验失效。
  • 误区二:使用弱哈希算法。MD5和SHA-1已被证明存在碰撞攻击,不应使用。
  • 误区三:公钥存储在可写Flash中。公钥必须存储在OTP或安全Flash区域,防止被替换。

固件完整性是安全启动的“门卫”,但仅靠完整性还不够,还需要机密性保护来防止固件被提取和分析。

4.3 固件机密性:加密存储与安全执行

机密性保护的目标是防止攻击者通过读取Flash、嗅探总线或分析固件镜像来提取敏感信息(如密钥、算法、业务逻辑)。在Cortex-M33中,TrustZone提供了安全世界与非安全世界的硬件隔离,但固件在Flash中的静态存储仍可能被物理攻击读取。

4.3.1 核心原理:加密与隔离的双重保障

固件机密性通过以下机制实现:

  • 静态加密:固件镜像在Flash中以密文形式存储,启动时由安全世界解密后加载到SRAM执行。
  • 安全世界隔离:解密后的明文固件只存在于安全世界可访问的SRAM区域,非安全世界无法读取。
  • 总线加密:部分Cortex-M33实现支持外部存储接口的硬件加密,防止攻击者通过探测外部总线获取数据。
  • 密钥保护:加密密钥存储在OTP或安全密钥存储区,且与信任根绑定,防止密钥被提取。

需要注意的是,机密性保护与完整性保护是互补的:完整性防止固件被篡改,机密性防止固件被读取。两者通常结合使用,例如使用AES-GCM认证加密算法,同时提供加密和完整性校验。

4.3.2 判断方法:评估机密性保护的有效性

评估固件机密性保护时,可以检查以下问题:

  1. 固件是否以明文存储在Flash中?如果是,攻击者可以通过物理读取Flash直接获取固件。
  2. 解密密钥是否与信任根绑定?如果密钥独立存储,攻击者可能通过提取密钥来解密固件。
  3. 解密后的明文是否会被非安全世界访问?如果安全世界与非安全世界共享SRAM,需要检查MPU/SAU配置是否正确。
  4. 是否启用了总线加密?对于外部Flash,总线加密可以防止探测攻击。

4.3.3 实战场景:加密固件启动流程

某医疗设备要求固件在Flash中加密存储,防止逆向工程。实现方案如下:

// 加密固件生成(开发主机侧)
1. 生成随机AES-256密钥K_enc。
2. 使用K_enc对固件明文进行AES-GCM加密,得到密文C和认证标签T。
3. 使用设备公钥(或共享密钥)对K_enc进行加密,得到K_enc_wrapped。
4. 将C、T、K_enc_wrapped打包为固件镜像。

// 设备启动解密(Cortex-M33安全世界)
1. 从OTP加载设备私钥,解密K_enc_wrapped得到K_enc。
2. 使用K_enc对C进行AES-GCM解密,同时验证认证标签T。
3. 将解密后的明文固件加载到安全SRAM区域。
4. 执行完整性验证(如计算哈希并与预期值比较)。
5. 跳转到明文固件执行。

此方案中,即使攻击者物理读取Flash,也只能获得密文,无法直接获取固件逻辑。但需要注意,解密后的明文在SRAM中仍可能被侧信道攻击(如功耗分析)获取,因此还需要配合其他防护措施。

风险提示:机密性保护会增加启动时间和功耗开销。AES-GCM解密和认证需要额外的计算资源,在低功耗设备中需要权衡安全性与性能。此外,密钥管理是机密性保护的最大挑战——如果密钥泄露,所有加密措施都将失效。

4.3.4 常见误区与总结

  • 误区一:加密等于安全。加密只解决机密性问题,不解决完整性或可用性问题。
  • 误区二:密钥存储在Flash中。Flash可被物理读取,密钥必须存储在OTP或安全硬件中。
  • 误区三:忽略侧信道攻击。功耗分析、电磁辐射分析可能泄露解密过程中的密钥信息。

机密性保护是安全启动的重要补充,但并非所有场景都需要加密。对于开源固件或低价值产品,加密可能不划算,应基于威胁模型决定。

4.4 防回滚:版本控制与单调计数器

防回滚(Anti-Rollback)机制防止攻击者将系统固件降级到存在已知漏洞的旧版本。即使攻击者无法篡改固件内容,如果能够替换为旧版本,仍可能利用旧版本中的漏洞实施攻击。

4.4.1 核心原理:版本号与单调计数器

防回滚的核心机制是版本号比较和单调计数器:

  • 版本号:每个固件镜像包含一个版本号(如0x0102表示1.2版本)。启动时,引导程序比较新固件版本与当前系统版本,拒绝低于当前版本的固件。
  • 单调计数器:硬件实现的计数器,只能递增不能递减。每次成功启动后,计数器更新为当前固件版本号。启动时,引导程序检查固件版本号是否大于等于计数器值。

在Cortex-M33中,单调计数器可以实现在TrustZone安全世界中,通过安全服务管理。非安全世界无法修改计数器值,从而防止攻击者重置计数器。

4.4.2 操作流程:实现防回滚的完整步骤

// 防回滚检查流程
1. 读取当前单调计数器值 current_counter。
2. 读取新固件版本号 new_version。
3. 如果 new_version < current_counter,拒绝启动。
4. 如果 new_version == current_counter,允许启动(但需检查完整性)。
5. 如果 new_version > current_counter,允许启动,并在成功启动后更新计数器。

// 计数器更新时机
- 在固件验证通过后、跳转到新固件前更新计数器。
- 更新操作必须是原子的,防止更新过程中断电导致状态不一致。

单调计数器的实现方式有多种:

实现方式优点缺点适用场景
OTP/efuse硬件级不可逆烧录次数有限高安全等级
Flash模拟可多次更新可能被擦除中等安全等级
TrustZone安全存储软件可管理依赖安全世界正确性灵活场景

4.4.3 案例拆解:回滚攻击与防御

某路由器产品使用Cortex-M33,攻击者发现旧版本固件存在远程代码执行漏洞。攻击者尝试将固件回滚到旧版本:

  1. 攻击过程:攻击者下载旧版本固件,修改其版本号字段为高版本号,绕过版本检查。
  2. 防御失败原因:版本号存储在固件头部,未进行签名保护。攻击者修改版本号后,签名验证仍然通过(因为签名只覆盖代码段,不覆盖头部版本字段)。
  3. 修复方案:将版本号纳入签名范围,即签名覆盖固件头部+代码段+数据段。这样,任何对版本号的修改都会导致签名验证失败。
  4. 进一步加固:使用单调计数器,即使攻击者修改版本号,计数器值仍然记录着上次成功启动的版本,无法降级。
经验总结:防回滚必须与完整性验证结合。版本号本身必须被签名保护,否则攻击者可以伪造高版本号。单调计数器提供了硬件级的防回滚保障,但需要合理设计更新时机和存储介质。

4.4.4 常见误区与总结

  • 误区一:版本号不参与签名。这导致攻击者可以修改版本号绕过防回滚。
  • 误区二:计数器更新时机不当。如果在固件执行前更新计数器,可能导致固件启动失败后无法回退。
  • 误区三:忽略计数器存储的耐久性。Flash模拟计数器有擦写寿命限制,需要磨损均衡。

防回滚是安全启动的最后一道防线,它确保系统始终运行在已知安全的最新版本上。

4.5 常见攻击路径:调试接口、物理攻击与恶意固件

理解攻击路径是设计防御措施的前提。Cortex-M33系统面临的主要攻击路径包括调试接口攻击、物理攻击和恶意固件注入。

4.5.1 调试接口攻击:SWD/JTAG的滥用

调试接口(SWD/JTAG)是开发者的重要工具,但也是攻击者的首选入口。攻击者可以通过调试接口读取内存、修改寄存器、绕过安全启动检查。

防御措施:

  • 生命周期状态管理:在量产阶段永久禁用调试接口。
  • 调试认证:使用密码或证书认证调试器,只有授权调试器才能连接。
  • TrustZone隔离:将调试接口配置为仅能访问非安全世界,安全世界内容不可见。
// 禁用调试接口示例(Cortex-M33)
// 设置DBGMCU_CR寄存器
DBGMCU->CR |= DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STOP;
// 在量产阶段,通过OTP位永久锁定调试接口
if (is_production_mode()) {
    DBGMCU->CR |= DBGMCU_CR_DBG_DISABLE;
    // 此操作不可逆,需谨慎
}

4.5.2 物理攻击:芯片级探测与故障注入

物理攻击包括:

  • 电压毛刺(Glitch):在芯片供电引脚上注入短暂的电压波动,可能导致CPU跳过安全检查指令。
  • 时钟毛刺:改变时钟频率,使CPU在错误的时间采样数据。
  • 激光攻击:使用激光照射芯片特定区域,改变晶体管状态。
  • 聚焦离子束(FIB):修改芯片内部电路连接。

防御措施:

  • 电压/时钟监控:使用内部监控电路检测异常波动,触发复位。
  • 冗余校验:关键安全检查执行两次,结果不一致则进入错误状态。
  • 主动屏蔽层:在芯片顶层覆盖金属屏蔽层,防止激光攻击。
风险提示:物理攻击需要专业设备和技能,通常针对高价值目标。对于消费级产品,物理攻击的威胁等级较低,但安全启动设计仍需考虑基本的物理防护。

4.5.3 恶意固件注入:通过更新流程攻击

恶意固件注入是最高频的攻击路径,攻击者通过以下方式植入恶意固件:

  1. 伪造更新包:制作包含恶意代码的固件更新包,诱导用户安装。
  2. 中间人攻击:在OTA更新过程中截获并替换固件包。
  3. 利用更新流程漏洞:如未验证更新包签名、未检查版本号等。

防御措施:

  • 强制签名验证:所有固件更新必须通过签名验证。
  • 安全通道:使用TLS/DTLS保护OTA传输。
  • 双镜像方案:保留当前运行固件,新固件验证通过后再切换。

4.5.4 案例拆解:综合攻击场景与防御

某工业控制器使用Cortex-M33,攻击者尝试通过组合攻击突破安全启动:

  1. 第一步:物理攻击。攻击者使用电压毛刺尝试跳过BL2的签名验证。防御:芯片内置电压监控器检测到异常,触发复位。
  2. 第二步:调试接口攻击。攻击者尝试通过SWD连接读取安全世界内存。防御:量产阶段已禁用调试接口,连接被拒绝。
  3. 第三步:恶意固件注入。攻击者制作包含后门的固件更新包,尝试通过OTA安装。防御:更新包签名验证失败,被拒绝。
  4. 第四步:回滚攻击。攻击者尝试安装旧版本固件。防御:单调计数器阻止了版本降级。

通过多层防御,攻击者的所有尝试均告失败。此案例