You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 03:25:31