TPM 基础:硬件架构、密钥层次、PCR 与命令响应

各位同学,咱们今天聊聊 TPM。这东西听起来像个黑盒子,其实没那么玄乎。我最早接触 TPM 是在做一款工控网关的安全启动方案,那时候芯片手册看得我头皮发麻。后来摸熟了,发现它的设计思路非常清晰——说白了,就是一个专门干密码活儿的“保险柜”。

TPM 硬件架构:一个独立的密码协处理器

TPM 不是跑在 CPU 上的软件,它是一颗独立的芯片。你想想看,如果密钥存在硬盘里,攻击者拿到 root 权限就能偷走。TPM 的做法是:密钥永远不离开芯片,所有密码运算都在芯片内部完成。

它的核心组件包括:

  • I/O 接口:通过 LPC 或 SPI 总线与主板通信,接收命令、返回响应。
  • 非易失性存储 (NVRAM):存放持久化数据,比如背书密钥 (EK)、存储根密钥 (SRK)。掉电不丢失。
  • 易失性存储 (RAM):运行时存放会话密钥、临时数据。
  • 密码协处理器:硬件加速 RSA、ECC、SHA-256、HMAC 等运算。比纯软件快一个数量级。
  • 随机数生成器 (RNG):真随机数发生器,用于生成密钥和 nonce。
  • 平台配置寄存器 (PCR):一组不可篡改的度量值寄存器,后面重点讲。

关键设计原则:TPM 是“被动”设备。它不会主动发起任何操作,只响应外部命令。这意味着你无法远程直接控制 TPM,必须通过本地软件栈(如 Linux 的 tpm2-tools)与它交互。

我在项目中踩过一个坑:某款 TPM 芯片的 SPI 时钟频率设得太高,导致通信不稳定,开机时有时认不到设备。后来我强制降频到 20MHz,问题解决。嗯,硬件细节往往藏在时序里。

TPM 密钥层次:从根密钥到会话密钥

TPM 的密钥管理是一个树形结构。根在芯片内部,叶子在应用层。我习惯把它想象成“俄罗斯套娃”——每一层密钥都由上一层保护。

层级 密钥类型 存储位置 用途
0 背书密钥 (EK) NVRAM(出厂预置) 芯片唯一身份标识,用于远程证明
1 存储根密钥 (SRK) NVRAM(由 EK 派生) 保护所有存储密钥的根
2 存储密钥 (SK) 受 SRK 加密后存于外部 保护应用密钥或数据
3 身份密钥 (AIK) 受 SK 加密后存于外部 签名 PCR 值,用于远程证明
4 会话密钥 RAM(运行时生成) 加密通信通道

这里有个重要概念:密钥迁移。TPM 2.0 允许将密钥导出到外部存储,但必须用父密钥加密。我曾经遇到一个需求:需要把 AIK 从一台设备迁移到另一台。当时没注意父密钥的授权策略,结果迁移后签名验证失败。后来发现是策略会话的 nonce 没对齐。细节决定成败啊。

我的建议:生产环境中,EK 和 SRK 永远不要导出。AIK 可以导出备份,但必须用强密码保护。我个人习惯用 TPM 2.0 的 TPM2_Duplicate 命令配合对称加密做迁移,既安全又可控。

平台配置寄存器 (PCR):系统的“指纹”

PCR 是 TPM 最巧妙的设计之一。它是一组 20 字节(SHA-1)或 32 字节(SHA-256)的寄存器,用于记录系统状态。关键特性是:只能扩展,不能重置(除非重启)。

扩展操作是:PCR[n] = SHA256(PCR[n] || new_measurement)。这意味着 PCR 值依赖于所有历史度量值的顺序。你想想看,如果攻击者篡改了某个启动组件,PCR 值就会和预期不同——远程验证方一眼就能看出来。

TPM 2.0 规范定义了 24 个 PCR,每个有特定用途:

PCR 索引 用途 度量内容
0 BIOS/固件 主机平台固件代码
1 主机平台配置 BIOS 设置、跳线状态
2 Option ROM 扩展卡固件
3 Option ROM 配置 扩展卡配置数据
4 MBR/引导加载程序 主引导记录或 UEFI 引导加载程序
5 引导加载程序配置 GRUB 配置、内核命令行
6 状态转换/唤醒 休眠恢复、S3 唤醒路径
7 安全策略 Secure Boot 策略、TPM 策略
8-15 操作系统使用 内核、initramfs、模块、应用

注意:PCR 0-7 在平台复位时自动重置。PCR 8-15 由操作系统管理,可以跨重启保持。如果你做远程证明,通常引用 PCR 0-7 来证明固件完整性,引用 PCR 8-15 来证明内核和关键服务的完整性。

我曾经调试过一个诡异的问题:某台服务器每次重启后 PCR 0 的值都不一样。查了两天,发现是 BIOS 版本升级后,微码补丁的加载顺序变了。嗯,PCR 对顺序敏感,这个特性既是优点也是坑。

TPM 命令与响应:如何与芯片对话

TPM 的通信模型很简单:你发一条命令,它回一个响应。命令和响应都是 TPM 2.0 规范定义的 TPM2B 结构体。我刚开始看规范时,被那几百页的字节布局吓到了。后来发现,你不需要手拼字节流——有现成的库。

一个典型的命令流程:

  1. 应用层调用 tpm2-tools 或直接调用 TSS(TPM Software Stack)API。
  2. TSS 将命令序列化为 TPM2B 格式,加上命令头和授权信息。
  3. 通过 /dev/tpm0 或 /dev/tpmrm0 发送给 TPM 驱动。
  4. TPM 芯片执行命令,返回响应字节流。
  5. TSS 解析响应,返回给应用层。

举个例子,用 tpm2-tools 读取 PCR 0 的值:

# 读取 PCR 0 的当前值
tpm2_pcrread sha256:0

# 输出示例
sha256:
  0 : 0x3A4F... (32 字节十六进制)

如果你想做远程证明,核心命令是 TPM2_Quote。它会用 AIK 对一组 PCR 值签名,并附带一个 nonce 防止重放攻击。验证方收到签名后,用 AIK 的公钥验签,再比对 PCR 值是否与预期一致。

核心命令速查:

  • TPM2_Startup:初始化 TPM,必须在每次上电后调用。
  • TPM2_PCR_Extend:扩展 PCR 值。
  • TPM2_PCR_Read:读取 PCR 值。
  • TPM2_Quote:用 AIK 签名 PCR 值,用于远程证明。
  • TPM2_GetRandom:获取真随机数。
  • TPM2_Create:在 TPM 内部生成密钥。
  • TPM2_Load:加载外部密钥到 TPM。

我建议你从 tpm2_pcrread 和 tpm2_quote 开始练手。先读 PCR,再签名,最后验签。走通这个流程,你就掌握了远程证明的核心。

本章知识体系

下面这张图总结了 TPM 的核心逻辑:硬件是底座,密钥是资产,PCR 是证据,命令是接口。四者缺一不可。

TPM 核心知识体系 TPM 核心知识体系 硬件架构 独立密码协处理器 密钥层次 EK → SRK → SK → AIK 平台配置寄存器 系统状态指纹 命令与响应 TPM2B 协议交互 核心关系 硬件保护密钥 密钥签名 PCR 命令驱动一切

这张图里,硬件在最左边,密钥在中间,PCR 在最右边,命令在最下面。箭头表示依赖关系:硬件提供安全执行环境,密钥层次提供信任链,PCR 记录度量值,命令是操作接口。远程证明的本质就是:用硬件保护的密钥,去签名不可篡改的 PCR 值,然后通过网络发给验证方。