4、度量与报告机制:PCR、度量启动与远程证明报告

好,咱们进入第四章。这一章讲的是整个远程证明的“地基”——度量与报告。说白了,就是你的设备怎么证明自己“没被改过”。

我见过不少团队,把精力全花在签名算法和证书链上,结果底层度量一塌糊涂。你想想看,上层做得再花哨,底层 PCR 值对不上,那证明就是废纸一张。

4.1 平台配置寄存器(PCR)——信任的“账本”

PCR 是什么?它是 TPM 芯片里的一组寄存器。你不能直接往里面写数据,只能“扩展”。

扩展操作是这样的:PCR[n] = SHA256( PCR[n]旧值 || 新度量值 )。

这个设计很巧妙。你没法回退,也没法预测最终值。只有严格按照顺序度量,才能得到预期的 PCR 值。

核心要点:PCR 的不可逆性,是信任链的根基。一旦某个环节被篡改,PCR 值就会“跑偏”,远程证明方一眼就能看出来。

4.1.1 PCR 的典型分配

TCG 规范定义了 PCR 的用途。我整理了一张表,这是最常用的几个:

PCR 索引 度量内容 典型用途
PCR 0 BIOS/固件代码 验证 BIOS 是否被篡改
PCR 1 主板配置 检测硬件配置变化
PCR 2 Option ROM 代码 验证扩展卡固件
PCR 3 Option ROM 配置 检测扩展卡配置
PCR 4 MBR / 引导加载程序 验证 Bootloader 完整性
PCR 5 MBR 配置 / GPT 检测分区表篡改
PCR 6 状态转换 / 唤醒 检测休眠恢复状态
PCR 7 安全策略 验证 Secure Boot 策略
PCR 8-15 操作系统组件 度量内核、驱动、关键文件

我的习惯:在项目中,我通常会把 PCR 0-7 作为“硬件信任根”的度量范围,PCR 8-15 留给操作系统。这样分层清晰,出了问题也好排查。

4.2 度量启动(Measured Boot)——信任链的传递

度量启动,不是 Secure Boot。Secure Boot 是“验签,过就启动,不过就停”。度量启动是“度量,记录到 PCR,然后继续启动”。

它不阻止你启动,它只负责记账。启动完了,PCR 里就记下了一笔完整的“启动流水账”。

我遇到过有人问:“那度量启动有什么用?又不能阻止恶意代码。” 嗯,这里要注意:度量启动的价值在于“事后审计”。你把 PCR 值发给远程证明服务器,服务器一比对,就知道你的启动链有没有被动过。

4.2.1 度量启动的流程

流程其实不复杂,我画了张图,你看一眼就明白了:

度量启动信任链流程图 度量启动信任链传递流程 1. BIOS / CRTM 2. Bootloader 3. OS Kernel 4. 关键服务/驱动 5. 目标应用 PCR 0-7 记录 PCR 8-15 记录 关键原则 前一个组件度量下一个 度量值扩展到 PCR 信任链逐级传递

你看,从 BIOS 开始,一级度量一级,每一级都把度量值扩展到 PCR。最终 PCR 里就存了整条链的“指纹”。

4.2.2 代码示例:度量一个文件并扩展 PCR

在 Linux 下,你可以用 tpm2-tools 来模拟这个过程。我写个简单的例子:

# 1. 计算文件的哈希值
sha256_hash=$(sha256sum /boot/vmlinuz-* | awk '{print $1}')

# 2. 将哈希值转换为二进制格式
echo $sha256_hash | xxd -r -p > /tmp/kernel_hash.bin

# 3. 读取当前 PCR 8 的值
tpm2_pcrread sha256:8 > /tmp/pcr8_before.bin

# 4. 扩展 PCR 8(模拟度量启动的扩展操作)
tpm2_pcrextend 8:sha256=/tmp/kernel_hash.bin

# 5. 验证扩展后的 PCR 8 值
tpm2_pcrread sha256:8

我曾经踩过的坑:扩展 PCR 时,一定要确保输入的哈希值格式正确。有一次我忘了做 xxd -r -p 转换,直接把 ASCII 字符串扩展进去了,结果 PCR 值完全不对。排查了半天才发现是格式问题。

4.3 远程证明报告生成——把证据打包好

度量完了,PCR 值也有了,接下来就是生成报告。报告不是直接把 PCR 值扔过去,那样太容易被中间人篡改。

标准的做法是:TPM 用 Attestation Identity Key (AIK) 对 PCR 值签名,生成一个 TPMS_ATTEST 结构。这个结构包含了 PCR 值、时间戳、随机数(nonce)等信息。

4.3.1 报告生成流程

  1. 挑战:验证方生成一个随机数 nonce,发给设备。
  2. 引用:设备调用 TPM2_Quote 命令,传入 nonce 和要引用的 PCR 索引。
  3. 签名:TPM 用 AIK 私钥对 PCR 值 + nonce 签名,生成 TPMS_ATTEST。
  4. 打包:设备把 TPMS_ATTEST、AIK 证书、PCR 日志一起发给验证方。

我建议你在设计时,把 nonce 的生成和校验放在业务层。这样即使 TPM 固件有漏洞,nonce 还能提供一层保护。

4.3.2 代码示例:生成引用报告

# 1. 验证方生成 nonce(这里用随机数模拟)
nonce=$(openssl rand -hex 16)

# 2. 设备端:引用 PCR 8-15,并用 AIK 签名
tpm2_quote \
  --key-context 0x81000000 \    # AIK 密钥句柄
  --pcr-list sha256:8,9,10,11,12,13,14,15 \
  --message /tmp/quote.msg \
  --signature /tmp/quote.sig \
  --qualification $nonce

# 3. 查看引用消息内容
tpm2_print -t TPMS_ATTEST /tmp/quote.msg

关键点:验证方收到报告后,会做三件事:

  • 用 AIK 公钥验证签名
  • 检查 nonce 是否匹配
  • 比对 PCR 值是否与预期一致

三步缺一不可。我见过只验签名不验 nonce 的设计,结果被重放攻击打穿了。

4.4 实战中的常见问题

嗯,这里我总结几个实际项目中容易出问题的地方:

  • PCR 值漂移:固件升级后,PCR 值会变。你需要同步更新验证方的“预期值”数据库。
  • AIK 证书管理:AIK 证书过期了怎么办?我建议用短生命周期证书,配合自动续期。
  • 日志完整性:PCR 日志(Event Log)要和 PCR 值一起验证。日志被篡改,PCR 值对不上,证明就失败。

我的经验:在量产阶段,我会把 PCR 预期值固化在验证方的配置中心。每次固件发布,同步更新配置。这样既保证了安全性,又避免了线上事故。

好了,这一章的内容就到这里。度量与报告是远程证明的“硬功夫”,PCR 是账本,度量启动是记账过程,报告生成是把账本拿出来给人看。三者环环相扣,缺一不可。