1、固件度量概述:什么是固件度量、度量在安全启动中的作用、TPM与度量根

各位同学,咱们今天聊点实在的。固件度量,这个词听起来挺唬人,对吧?其实说白了,就是给固件做一次「体检」——在它运行之前,先检查它是不是原装的、有没有被篡改过。

我刚开始接触这个领域的时候,也觉得这东西离自己很远。直到有一次,我在一个IoT项目里发现,某款设备的启动固件被人偷偷植入了后门,整批设备都得召回。嗯,从那以后,我再也不敢小看「度量」这两个字了。

1.1 什么是固件度量

固件度量,简单来说,就是在系统启动的早期阶段,对即将执行的固件代码、配置数据、关键参数进行哈希计算,并把计算结果(度量值)安全地存储起来。这个度量值就像固件的「指纹」,独一无二。

你想想看,如果固件被人动过手脚,它的哈希值一定会变。度量机制就是抓住这个变化,然后告诉系统:「嘿,这东西不对劲,别让它跑起来。」

核心要点:度量 ≠ 验证。度量只是记录固件的当前状态,而验证是把度量值和预期值做比较。两者是上下游关系,缺一不可。

我个人习惯把固件度量拆成三个要素:

  • 度量对象:BIOS/UEFI、Option ROM、Bootloader、OS Kernel 等
  • 度量算法:通常是 SHA-1、SHA-256 或更安全的 SHA-384
  • 度量存储:TPM 中的平台配置寄存器(PCR)

我在项目中遇到过不少团队,只做了度量,没做存储保护。结果度量值被篡改了,整个安全链条形同虚设。记住,度量值必须放在硬件隔离的区域里,比如 TPM。

1.2 度量在安全启动中的作用

安全启动(Secure Boot)大家应该都听过。它的核心逻辑是「链式信任」——从最底层的硬件开始,一级验证一级,直到操作系统。度量在这个链条里扮演什么角色?

我画了一张图,帮你理清这个流程:

安全启动中的度量链 安全启动中的度量链 硬件根信任 (Root of Trust) 度量 BIOS/UEFI 度量 Bootloader 度量 OS Kernel TPM PCR 存储度量值 度量链特点 • 逐级度量,不可跳过 • 前一级度量后一级 • 任何一级失败则中断 度量 vs 验证 • 度量:记录哈希值 • 验证:比对预期值 • 两者必须配合使用

从这张图你能看到,度量不是一次性的动作,而是一条链。每一级固件在交出控制权之前,都要先度量下一级,然后把度量值存到 TPM 里。如果中间任何一级的度量值和预期不符,系统就会停下来。

我曾经帮一个客户排查启动失败的问题,折腾了两天,最后发现是 Bootloader 的度量顺序写反了——先度量了内核,才度量自己。这种低级错误,在代码审查阶段就应该被揪出来。

实战建议:在开发阶段,建议把每个度量步骤的日志都打印出来。这样一旦安全启动失败,你能快速定位到是哪一级出了问题。别问我怎么知道的——我踩过这个坑。

1.3 TPM 与度量根

TPM(Trusted Platform Module)是度量机制的核心硬件。它提供了一组被称为 PCR(Platform Configuration Register)的寄存器,专门用来存储度量值。这些寄存器有几个关键特性:

特性 说明 为什么重要
不可重置 PCR 值只能扩展(extend),不能直接写入 防止攻击者伪造度量值
硬件隔离 PCR 位于 TPM 芯片内部,CPU 无法直接访问 即使 OS 被攻破,度量值依然安全
持久化 系统重启后 PCR 会重置,但度量过程会重新执行 保证每次启动都是全新的信任链
有限数量 通常有 16~24 个 PCR,每个用途不同 需要合理规划 PCR 的使用

度量根(Root of Trust for Measurement,RTM)是整个信任链的起点。它通常是 CPU 微码或固化在 ROM 里的一小段代码。这段代码不可修改,所以它度量出来的结果天然可信。

你想想看,如果度量根本身可以被篡改,那整个安全体系就崩塌了。所以硬件厂商在设计时,会把 RTM 放在芯片内部,用物理手段保护起来。

注意:TPM 2.0 和 TPM 1.2 在 PCR 管理上有显著差异。TPM 2.0 支持更多的 PCR(最多 24 个),并且引入了 Bank 的概念,可以同时使用多种哈希算法。如果你还在用 TPM 1.2,建议尽快升级。

我记得有一次,一个团队在移植安全启动方案时,发现 PCR 值总是对不上。排查了半天,原来是 TPM 芯片的固件版本太老,不支持 SHA-256 扩展操作。换了个新版本的 TPM,问题就解决了。所以,选型的时候一定要确认 TPM 的固件版本和功能集。

1.4 度量流程的典型实现

说了这么多理论,咱们来看看实际代码。下面是一个简化的固件度量流程,用伪代码表示:

// 伪代码:固件度量流程
void measure_and_boot() {
    // 1. 度量 BIOS 自身
    uint8_t bios_hash[SHA256_DIGEST_SIZE];
    sha256_compute(BIOS_BASE_ADDR, BIOS_SIZE, bios_hash);
    tpm_pcr_extend(PCR_0, bios_hash);
    
    // 2. 度量 Option ROM
    uint8_t option_rom_hash[SHA256_DIGEST_SIZE];
    sha256_compute(OPTION_ROM_ADDR, OPTION_ROM_SIZE, option_rom_hash);
    tpm_pcr_extend(PCR_2, option_rom_hash);
    
    // 3. 度量 Bootloader
    uint8_t bootloader_hash[SHA256_DIGEST_SIZE];
    sha256_compute(BOOTLOADER_ADDR, BOOTLOADER_SIZE, bootloader_hash);
    tpm_pcr_extend(PCR_4, bootloader_hash);
    
    // 4. 验证度量值
    if (!tpm_pcr_verify(PCR_4, EXPECTED_BOOTLOADER_HASH)) {
        halt_system("Bootloader integrity check failed!");
    }
    
    // 5. 跳转到 Bootloader
    jump_to(BOOTLOADER_ADDR);
}

这段代码看起来简单,但实际项目中要考虑的细节很多。比如:

  • 度量范围要精确,不能多量也不能少量
  • PCR 的选择要符合 TCG 规范,否则兼容性会出问题
  • 度量值的预期值要安全存储,通常放在 TPM 的 NVRAM 里

小技巧:在调试阶段,可以用 tpm2_pcrread 命令查看当前 PCR 的值。这样你能实时确认度量是否生效。命令格式:tpm2_pcrread sha256:0

好了,关于固件度量的基本概念,咱们就聊到这儿。记住三个关键词:度量、PCR、信任链。后面的章节,我会带你一步步搭建实际的度量环境,到时候你会对这些概念有更深的体会。