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)大家应该都听过。它的核心逻辑是「链式信任」——从最底层的硬件开始,一级验证一级,直到操作系统。度量在这个链条里扮演什么角色?
我画了一张图,帮你理清这个流程:
从这张图你能看到,度量不是一次性的动作,而是一条链。每一级固件在交出控制权之前,都要先度量下一级,然后把度量值存到 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、信任链。后面的章节,我会带你一步步搭建实际的度量环境,到时候你会对这些概念有更深的体会。