4. TPM 2.0 架构详解:TPM的结构、PCR寄存器、EK与AK密钥、Quote机制

TPM 2.0,说白了就是一颗专门干「脏活累活」的安全芯片。我最早接触它是在做服务器可信启动的项目,那时候觉得这东西就是个黑盒子,往里写数据、往外读摘要。后来踩了几个坑才明白——TPM 的设计哲学其实很优雅:它不信任任何人,包括它自己所在的宿主系统。

4.1 TPM 的物理与逻辑结构

TPM 2.0 的物理结构,你可以想象成一个「带保险柜的微型计算机」。它有自己的 CPU、ROM、RAM、非易失性存储(NVRAM),还有一堆密码学加速器。逻辑上,它分为几个关键组件:

  • I/O 接口:通过 LPC、SPI 或 I²C 与 CPU 通信。我见过不少开发板因为 SPI 信号线没做隔离,导致 TPM 通信间歇性失败。
  • 密码协处理器:硬件加速 RSA、ECC、SHA-256、AES。纯软件算一个 RSA-2048 签名要几十毫秒,TPM 硬件几毫秒搞定。
  • 非易失性存储(NVRAM):存放持久化数据,比如 EK 私钥、AK 私钥、PCR 初始值。这部分掉电不丢。
  • 易失性存储器(RAM):运行时存放会话上下文、临时密钥。每次 TPM 复位就清空。
  • 随机数生成器(RNG):真随机数发生器,基于硬件噪声。我曾在项目中用 TPM 的 RNG 替代软件伪随机,效果立竿见影。

核心要点:TPM 的私钥永远不出芯片。你只能用它签名、解密,但永远拿不到私钥原文。这是远程证明信任的根基。

下面这张图展示了 TPM 2.0 的内部架构和关键组件之间的关系:

TPM 2.0 内部架构图 TPM 2.0 芯片边界 I/O 接口 LPC / SPI / I²C 密码协处理器 RSA / ECC / SHA / AES RNG 真随机数发生器 NVRAM EK 私钥 AK 私钥 / PCR 初值 RAM 会话上下文 临时密钥 PCR 寄存器 平台配置寄存器 SHA-256 摘要 关键设计原则 私钥永远不出 TPM 芯片 所有密码操作在芯片内部完成

4.2 PCR 寄存器:平台的「指纹记录仪」

PCR(Platform Configuration Register)是 TPM 里最核心的概念之一。你可以把它理解成一组「只能扩展、不能直接写」的哈希累加器。每个 PCR 寄存器存储一个 SHA-256 摘要值(32 字节)。

扩展操作是这样的:

PCR_new = SHA256(PCR_old || 新测量值)

也就是说,你没法把 PCR 设成任意值。你只能把新数据「叠」到当前值上。这个特性保证了——只要测量顺序固定,最终 PCR 值就是确定的。任何篡改都会导致最终值不同。

我的经验:我曾经在调试一个 UEFI 安全启动问题时,发现 PCR[0] 的值总是不对。查了两天才发现,是 BIOS 在加载某个 Option ROM 时多了一次测量。顺序一变,PCR 值全乱。所以 PCR 的「测量顺序」和「测量内容」同等重要。

TPM 2.0 规范定义了 24 个 PCR 寄存器(索引 0-23),每个有特定用途:

PCR 索引 用途 测量内容
0-1 BIOS/固件 BIOS 代码、ACPI 表、SMBIOS
2-3 Option ROM 扩展卡固件、网卡 PXE 代码
4 MBR/GPT 主引导记录或 GPT 头
5 MBR/GPT 分区 分区表后续部分
6 状态转换 平台状态变化(如休眠恢复)
7 安全启动策略 安全启动策略数据库
8-15 静态操作系统 操作系统内核、驱动、initramfs
16-23 动态/应用 运行时测量、容器、应用代码

注意:PCR 在 TPM 复位(如系统重启)时会被重置为初始值。但有些 PCR(如 16-23)可以配置为「仅在 TPM 上电时复位一次」,用于支持动态远程证明。

4.3 EK 与 AK 密钥:身份的「出生证明」和「工作证」

EK(Endorsement Key)是 TPM 的「出生证明」。它在 TPM 出厂时生成,私钥永久固化在 NVRAM 里,公钥由芯片厂商签发证书。EK 的唯一用途是——证明「我是一个真实的 TPM 芯片」。但 EK 不能直接用于远程证明,因为它是全局唯一的,会暴露设备身份。

AK(Attestation Key)是 TPM 的「工作证」。它由 EK 担保生成,用于日常的签名和证明操作。AK 可以随时创建和销毁,每次创建时 TPM 会用 EK 对 AK 的公钥签名,生成 AK 证书。

我习惯把 EK 和 AK 的关系比作「身份证」和「工牌」:身份证证明你是你,但你不能到处亮;工牌证明你有权限,丢了可以补办。

创建 AK 的流程大致如下:

  1. 调用 TPM2_Create 生成 AK 密钥对(RSA-2048 或 ECC P-256)。
  2. 调用 TPM2_Certify 用 EK 对 AK 公钥签名,生成 AK 证书。
  3. 将 AK 公钥和证书发送给验证方。
  4. 验证方用 EK 证书链验证 AK 证书的合法性。

关键区别:EK 是静态的、唯一的、不可变的;AK 是动态的、可撤销的、可批量创建的。远程证明中你永远用 AK 签名,EK 只用来证明 AK 的合法性。

4.4 Quote 机制:TPM 的「自证清白」

Quote 是 TPM 远程证明的核心操作。它的本质是——TPM 用 AK 对一组 PCR 值签名,证明「当前平台的 PCR 值就是这些,而且是我这个 TPM 签的」。

Quote 的输入参数包括:

  • AK 句柄:指定用哪个 AK 签名。
  • PCR 选择:要引用的 PCR 索引列表(如 PCR[0,2,4])。
  • Nonce:验证方提供的随机数,防止重放攻击。
  • 额外数据:可选,用于绑定上下文。

Quote 的输出是一个 TPMS_ATTEST 结构体,包含:

TPMS_ATTEST {
  UINT64    magic;          // 固定魔数
  TPMI_ST_ATTEST type;      // 类型 = TPM_ST_ATTEST_QUOTE
  TPM2B_NAME qualifiedSigner; // AK 名称
  TPM2B_DATA extraData;     // 额外数据
  TPMS_CLOCK_INFO clockInfo; // TPM 时钟信息
  UINT64    firmwareVersion; // 固件版本
  TPM2B_DIGEST attested;    // PCR 摘要值(关键!)
}

验证方收到 Quote 后,做三件事:

  1. 用 AK 公钥验证签名。
  2. 检查 Nonce 是否匹配。
  3. 将 attested 中的 PCR 值与「预期值」对比。

如果都通过,说明平台当前状态是可信的。

避坑指南:我曾经在项目中遇到一个问题——Quote 验证总是失败。排查了半天,发现是 Nonce 在传输过程中被 URL 编码了一次,导致长度变了。TPM 对 Nonce 的字节长度非常敏感,多一个字节都不行。所以,Nonce 的传输一定要用二进制安全的方式(如 Base64 编码)。

Quote 的完整流程可以用下面这张图概括:

TPM Quote 远程证明流程 验证方 (Verifier) 生成 Nonce 验证签名 & PCR TPM 读取 PCR 值 用 AK 签名 ① Nonce + PCR 选择 ② Quote (签名后的 PCR) Quote 验证关键步骤 1. 验证 AK 证书链(EK → AK) 2. 用 AK 公钥验证 Quote 签名 3. 检查 Nonce 是否与发送的一致 4. 比对 PCR 值与预期基准值

4.5 小结:TPM 2.0 的信任链

把上面几个概念串起来,TPM 2.0 的远程证明信任链就很清晰了:

  • 信任根:TPM 芯片本身(硬件安全)。
  • 身份根:EK(出厂固化,不可伪造)。
  • 工作密钥:AK(由 EK 担保,可动态创建)。
  • 证据:PCR 值(记录平台状态)。
  • 证明:Quote(AK 对 PCR 的签名)。

嗯,这套设计其实很巧妙。你想想看——验证方不需要信任宿主操作系统,不需要信任 BIOS,甚至不需要信任网络。只要 TPM 芯片是真实的,只要 EK 证书链是完整的,那么 Quote 给出的 PCR 值就是可信的。这就是远程证明的「信任锚点」。

最后提醒:TPM 2.0 的规范有 2000 多页,我上面讲的只是冰山一角。但如果你理解了 PCR、EK、AK 和 Quote 这四者的关系,你就掌握了远程证明的核心骨架。剩下的细节,都是在骨架上填肉。