4. TPM 2.0规范体系
TPM 2.0 并不是一份单一文档,而是一套由 TCG(Trusted Computing Group)维护的规范族。它把“可信根”的硬件行为、命令接口、授权模型、层级组织和平台适配方式拆分成多个相互引用的部分。理解这套体系,是后续做密封存储、密钥迁移、远程证明和策略授权的基础。若只把 TPM 当成一个“加密芯片”,很容易在会话、授权和层级归属上踩坑。
一、规范结构:从架构到平台接口
TPM 2.0 规范族通常分为四个主要部分:Part 1 架构(Architecture)、Part 2 结构(Structures)、Part 3 命令(Commands)、Part 4 支持例程(Supporting Routines)。此外还有平台特定规范(PC Client、Mobile、Server)以及 TPM 软件栈(TSS)规范。Part 1 定义对象、层级、会话、授权等概念模型;Part 2 定义命令与响应的二进制布局、字节序和数据类型;Part 3 逐条定义命令的输入输出、错误码和授权要求;Part 4 给出密码算法和辅助例程的参考实现。
这种分层带来一个关键工程事实:命令的语义在 Part 3,但命令的字节格式在 Part 2,授权行为在 Part 1。开发时若只查命令名而忽略会话和授权上下文,往往会在实际调用中收到 TPM_RC_AUTH_FAIL 或 TPM_RC_POLICY_FAIL。
二、命令与响应格式:统一的消息骨架
所有 TPM 2.0 命令都遵循统一的消息头结构,命令头为 10 字节,响应头为 10 字节。命令头包含 tag、commandSize、commandCode;响应头包含 tag、responseSize、responseCode。命令体由句柄区和参数区组成,参数区又分为授权区、输入参数区和输出参数区。响应体则包含输出参数区和授权区。
TPM2.0 命令消息结构(简化)
命令头:
tag 2 字节 TPM_ST_NO_SESSIONS / TPM_ST_SESSIONS
commandSize 4 字节 整个命令的字节数
commandCode 4 字节 命令编号,如 TPM_CC_CreatePrimary
命令体:
句柄区 若干 4 字节句柄
授权区 若干授权会话
参数区 输入参数
响应头:
tag 2 字节
responseSize 4 字节
responseCode 4 字节
响应体:
参数区 输出参数
授权区 会话响应
字节序统一为大端(Big-Endian),这是跨平台实现时最容易出错的地方之一。命令编号的高位字节还携带了命令类型信息,例如 0x0000011F 对应 TPM_CC_CreatePrimary。响应码中,高位表示错误类别,低位表示具体错误,工程上应优先解析 responseCode 再决定是否重试或回滚。
三、会话管理:授权、加密与审计的通道
TPM 2.0 的会话是命令与响应之间的状态通道,主要分为三类:HMAC 会话、策略会话和试用会话。HMAC 会话用于基于共享密钥的授权和参数完整性校验;策略会话用于基于策略的授权,例如 PCR 策略、口令策略、NV 索引策略;试用会话用于在不实际授权的情况下测试策略是否满足。
会话的建立通常从 TPM2_StartAuthSession 开始,返回一个会话句柄。会话可以绑定到某个 TPM 对象,也可以保持未绑定。会话的 sessionAttributes 决定是否继续、是否审计、是否解密参数。一个常见误区是:认为会话只是“登录凭证”。实际上,会话还承担参数加密、重放保护和审计记录功能。
四、授权机制:从口令到策略
TPM 2.0 的授权机制比 TPM 1.2 更灵活。对象可以设置 userWithAuth 属性,决定是否允许口令授权;也可以设置策略授权,通过 TPM2_PolicyPCR、TPM2_PolicyCommandCode、TPM2_PolicyNV 等命令构建策略会话。策略会话的核心思想是:授权不再依赖单一口令,而是依赖一组可验证的条件。
例如,一个磁盘加密密钥可以绑定到 PCR 0、2、4、7 的度量值。启动时若固件、引导加载程序和内核度量值匹配,策略满足,密钥释放;若被篡改,策略失败,密钥不可用。这种机制是 BitLocker、systemd-cryptenroll 等方案的基础。
TPM2_StartAuthSession,再依次执行策略命令,最后在目标命令中引用该会话。策略命令的顺序和参数必须与创建对象时记录的 policyDigest 完全一致,否则会返回 TPM_RC_POLICY_FAIL。
五、层级结构:对象归属与生命周期
TPM 2.0 定义了四个层级:平台层级(Platform)、存储层级(Storage)、背书层级(Endorsement)和空层级(Null)。每个层级有独立的种子和授权值。平台层级通常由固件控制,用于平台级配置;存储层级由所有者控制,用于存放用户密钥和 NV 数据;背书层级用于隐私敏感操作,如 EK 和远程证明;空层级用于临时对象,不持久化。
对象创建时必须指定 parentHandle,这决定了对象属于哪个层级。层级归属影响对象的持久化、迁移和授权路径。一个常见误区是:把 EK 密钥当作普通存储密钥使用。EK 属于背书层级,其证书和隐私属性有特殊要求,不应随意迁移或删除。
| 层级 | 典型控制者 | 典型对象 | 持久化 | 常见用途 |
|---|---|---|---|---|
| 平台层级 | 固件 / 启动环境 | 平台策略、部分 NV 索引 | 是 | 平台配置、启动控制 |
| 存储层级 | 所有者 / 管理员 | SRK、用户密钥、NV 存储 | 是 | 磁盘加密、密钥密封 |
| 背书层级 | 隐私管理员 | EK、EK 证书 | 是 | 远程证明、身份标识 |
| 空层级 | 临时调用方 | 临时会话、易失对象 | 否 | 短期操作、测试 |
六、案例与复盘:一次密封密钥失败排查
某 Linux 服务器使用 TPM 2.0 密封磁盘密钥,重启后无法自动解锁。排查发现:系统更新了内核,PCR 7 的度量值发生变化,而策略中只绑定了 PCR 7。由于策略会话在启动时无法满足,TPM2_Unseal 返回 TPM_RC_POLICY_FAIL。复盘结论是:策略设计应同时绑定 PCR 0、2、4、7,并预留恢复密钥或使用 TPM2_PolicyAuthorize 允许签名更新策略。
掌握 TPM 2.0 规范结构、命令格式、会话管理、授权机制和层级结构后,后续的密封存储、密钥迁移、远程证明和策略授权才能建立在正确的模型之上。工程实现中,建议优先使用成熟的 TSS 库(如 tpm2-tss、TSS.MSR),并在设计阶段明确对象归属、授权路径和策略条件,避免在部署后才发现层级或会话不匹配。