使用TPM 2.0 SAPI定义NV Index时Tss2_Sys_NV_DefineSpace报错0x80013求助
问题分析与解决
1. 核心问题:无效的TCTI实现
你代码里自定义的tcti_transmit和tcti_receive是空实现,仅返回TPM2_RC_SUCCESS,但完全没有和真实TPM设备(物理TPM的/dev/tpmrm0,或软件模拟TPM如swtpm)通信。TSS2_Sys库依赖TCTI层完成与TPM的指令交互,空实现无法传递命令、接收有效响应,这是错误码0x80013(TCTI层错误)的根源。
解决方法:使用官方标准TCTI
放弃自定义TCTI,改用tpm2-tss提供的标准实现:
- 物理TPM用
tss2-tcti-device,连接/dev/tpmrm0或/dev/tpm0 - 软件模拟TPM用
tss2-tcti-swtpm或tss2-tcti-mssim
修改TCTI初始化代码示例:
#include <tss2/tss2_tcti_device.h> int main(void) { // ... 其他变量定义 ... TSS2_TCTI_CONTEXT *tcti_ctx = NULL; size_t tcti_size; TSS2_RC rc = Tss2_Tcti_Device_Init(NULL, &tcti_size, "/dev/tpmrm0"); if (rc != TPM2_RC_SUCCESS) { fprintf(stderr, "Failed to get TCTI device size: 0x%x\n", rc); exit(1); } tcti_ctx = calloc(1, tcti_size); if (tcti_ctx == NULL) { fprintf(stderr, "Failed to allocate TCTI context\n"); exit(1); } rc = Tss2_Tcti_Device_Init(tcti_ctx, &tcti_size, "/dev/tpmrm0"); if (rc != TPM2_RC_SUCCESS) { fprintf(stderr, "Failed to initialize TCTI device: 0x%x\n", rc); free(tcti_ctx); exit(1); } // ... 后续Sys Context初始化 ... }
编译时需链接对应库,比如-ltss2-tcti-device。
2. NV Public信息size字段错误
你设置publicInfo.size = 0是错误的。TPM2B_NV_PUBLIC的size字段需设为内部nvPublic结构体的大小,即sizeof(TPM2_NV_PUBLIC),修改为:
publicInfo.size = sizeof(TPM2_NV_PUBLIC);
3. 授权会话配置问题
使用TPM2_RH_PLATFORM作为授权句柄时,需匹配平台授权密码:
- 若平台密码为空(默认状态),将
sessionsData.auths[0].hmac.size设为0 - 若有密码,把密码复制到
hmac.buffer并设置对应size
nvAuth作为NV索引自身的授权密码,当前设置逻辑是正确的,注意密码长度不超过MAX_PSWD_LEN即可。
4. NV索引属性合理性检查
你设置的TPMA_NV_PLATFORMCREATE属性表示该NV索引由平台创建,对应使用TPM2_RH_PLATFORM作为授权句柄是正确的。如果后续要切换为TPM2_RH_OWNER操作,需移除该属性,改用TPMA_NV_OWNERWRITE等所有者权限属性。
修正后的完整代码示例
#include <tss2/tss2_sys.h> #include <tss2/tss2_tcti_device.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define TEST_NV_INDEX 0x01500020 #define MAX_PSWD_LEN 8 int main(void) { char passwd[] = { "password" }; UINT32 rc; TSS2L_SYS_AUTH_RESPONSE sessionsDataOut; TPM2B_NV_PUBLIC publicInfo; TPM2B_AUTH nvAuth; // 初始化TCTI设备上下文 TSS2_TCTI_CONTEXT *tcti_ctx = NULL; size_t tcti_size; rc = Tss2_Tcti_Device_Init(NULL, &tcti_size, "/dev/tpmrm0"); if (rc != TPM2_RC_SUCCESS) { fprintf(stderr, "Failed to get TCTI device size: 0x%x\n", rc); exit(1); } tcti_ctx = calloc(1, tcti_size); if (tcti_ctx == NULL) { fprintf(stderr, "Failed to allocate TCTI context\n"); exit(1); } rc = Tss2_Tcti_Device_Init(tcti_ctx, &tcti_size, "/dev/tpmrm0"); if (rc != TPM2_RC_SUCCESS) { fprintf(stderr, "Failed to initialize TCTI device: 0x%x\n", rc); free(tcti_ctx); exit(1); } // 初始化Sys上下文 size_t ctx_size = Tss2_Sys_GetContextSize(0); TSS2_SYS_CONTEXT *ctx = calloc(1, ctx_size); if (ctx == NULL) { fprintf(stderr, "Sys Context NULL\n"); free(tcti_ctx); exit(1); } TSS2_ABI_VERSION g_ver = TSS2_ABI_VERSION_CURRENT; rc = Tss2_Sys_Initialize(ctx, ctx_size, tcti_ctx, &g_ver); if (rc != TPM2_RC_SUCCESS) { fprintf(stderr, "Failed to Tss2_Sys_Initialize: rc = 0x%x\n", rc); free(ctx); free(tcti_ctx); exit(1); } // 设置授权会话(平台密码为空的情况) TSS2L_SYS_AUTH_COMMAND sessionsData = { .count = 1, .auths = {{ .sessionHandle = TPM2_RH_PW, .sessionAttributes = 0, .nonce = { .size = 0 }, .hmac = { .size = 0 } // 平台密码为空 }} }; // 设置NV索引的授权密码 nvAuth.size = strnlen(passwd, MAX_PSWD_LEN); memcpy(nvAuth.buffer, passwd, nvAuth.size); // 设置NV Public信息 memset(&publicInfo, 0, sizeof(publicInfo)); publicInfo.size = sizeof(TPM2_NV_PUBLIC); publicInfo.nvPublic.nvIndex = TEST_NV_INDEX; publicInfo.nvPublic.nameAlg = TPM2_ALG_SHA256; publicInfo.nvPublic.attributes = TPMA_NV_AUTHREAD | TPMA_NV_AUTHWRITE | TPMA_NV_PLATFORMCREATE | TPMA_NV_ORDERLY; publicInfo.nvPublic.authPolicy.size = 0; publicInfo.nvPublic.dataSize = 32; // 定义NV空间 rc = Tss2_Sys_NV_DefineSpace(ctx, TPM2_RH_PLATFORM, &sessionsData, &nvAuth, &publicInfo, &sessionsDataOut); if (rc != TPM2_RC_SUCCESS) { fprintf(stderr, "Failed to Tss2_Sys_NV_DefineSpace: rc = 0x%x\n", rc); goto cleanup; } printf("NV space defined successfully\n"); // 取消定义NV空间 rc = Tss2_Sys_NV_UndefineSpace(ctx, TPM2_RH_PLATFORM, TEST_NV_INDEX, &sessionsData, 0); if (rc != TPM2_RC_SUCCESS) { fprintf(stderr, "Failed to Tss2_Sys_NV_UndefineSpace: rc = 0x%x\n", rc); goto cleanup; } printf("NV space undefined successfully\n"); cleanup: Tss2_Sys_Finalize(ctx); free(ctx); free(tcti_ctx); return rc == TPM2_RC_SUCCESS ? 0 : 1; }
编译命令
gcc -o nvdefine nvdefine.c -ltss2-sys -ltss2-tcti-device
额外注意事项
- 使用软件模拟TPM时,需先启动swtpm服务,并替换为对应TCTI库
- 确保运行程序的用户有TPM设备访问权限(通常需加入
tss用户组) - 可通过
tpm2_rc_decode工具解析错误码,比如tpm2_rc_decode 0x80013查看具体原因
内容的提问来源于stack exchange,提问作者k1r1t0
相关产品推荐
相关产品推荐

