ctpmnon-volatiletss

Tss2_Sys_NV_DefineSpace failed with 0x80013 error


I'm trying to Define/Undefine NV Index for TPM 2.0 using SAPI (part of this code stolen from tpm2-tss tests) at 0x01500020 as in tests, but this fails for unknown reasons as for me:

#include <tss2/tss2_sys.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TEST_NV_INDEX 0x01500020
#define MAX_PSWD_LEN 8

static TSS2_RC tcti_transmit(TSS2_TCTI_CONTEXT *tctiContext,
    size_t size, uint8_t const *command) {
  (void) tctiContext;
  (void) size;
  (void) command;

  return TPM2_RC_SUCCESS;
}

static TSS2_RC tcti_receive(TSS2_TCTI_CONTEXT *tctiContext,
    size_t *size, uint8_t *response, int32_t timeout) {
  (void) tctiContext;
  (void) size;
  (void) response;
  (void) timeout;

  return TPM2_RC_SUCCESS;
}


static TSS2_ABI_VERSION g_ver = TSS2_ABI_VERSION_CURRENT;
static TSS2_TCTI_CONTEXT_COMMON_V1 g_tcti_ctx_v1;

int main(void) {
  char passwd[] = { "password" };
  UINT32 rc;
  TSS2L_SYS_AUTH_RESPONSE sessionsDataOut;
  TPM2B_NV_PUBLIC publicInfo;
  TPM2B_AUTH nvAuth;

  size_t ctx_size = Tss2_Sys_GetContextSize(0);
  TSS2_SYS_CONTEXT *ctx = calloc(1, ctx_size);
  TSS2_TCTI_CONTEXT *tcti_ctx = (TSS2_TCTI_CONTEXT *) &g_tcti_ctx_v1;
  TSS2L_SYS_AUTH_COMMAND sessionsData = { .count = 1, .auths = {{
    .sessionHandle = TPM2_RH_PW,
    .sessionAttributes = 0,
    .nonce = { .size = 0 },
    .hmac = { .size = 0 }
  }}};

  nvAuth.size = strnlen(passwd, MAX_PSWD_LEN);
  memcpy(&nvAuth.buffer[0], &passwd[0], nvAuth.size);

  publicInfo.size = 0;
  publicInfo.nvPublic.nvIndex = TEST_NV_INDEX;
  publicInfo.nvPublic.nameAlg = TPM2_ALG_SHA256;

  *(UINT32 *)&(publicInfo.nvPublic.attributes) = 0;

  publicInfo.nvPublic.attributes |= TPMA_NV_AUTHREAD;
  publicInfo.nvPublic.attributes |= TPMA_NV_AUTHWRITE;
  publicInfo.nvPublic.attributes |= TPMA_NV_PLATFORMCREATE;
  publicInfo.nvPublic.attributes |= TPMA_NV_ORDERLY;
  publicInfo.nvPublic.authPolicy.size = 0;
  publicInfo.nvPublic.dataSize = 32;

  g_tcti_ctx_v1.version = 1;
  g_tcti_ctx_v1.transmit = tcti_transmit;
  g_tcti_ctx_v1.receive = tcti_receive;

  if (ctx == NULL) {
    fprintf(stderr, "Sys Context NULL\n");
    exit(1);
  }

  printf("Context's size = %ld\n", ctx_size);

  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);
    exit(1);
  }

  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 free_ctx;
  }

  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", rc);
    goto free_ctx;
  }

  Tss2_Sys_Finalize(ctx);
  exit(0);

free_ctx:
  Tss2_Sys_Finalize(ctx);
  exit(1);
}

After compiling it and executing I got an error:

$ gcc -o nvdefine nvdefine.c -ltss2-sys && ./nvdefine
Failed to Tss2_Sys_NV_DefineSpace: rc = 0x80013

I tried to use TPM2_RH_PLATFORM and TPM2_RH_OWNER, but this had no effect, what I'm doing wrong? Can anybody help with this?


Solution

  • I found a solution for my problem, that was because of a wrong TCTI Context, I replaced that code by this:

    #include <tss2/tss2_tctildr.h>
    ...
    
    int main(void) {
      ...
      TPM2_RC rc;
      TSS2_TCTI_CONTEXT *tcti_ctx = NULL;
      ...
    
      rc = Tss2_Sys_TctiLdr_Initialize(NULL, &tcti_ctx);
      ...
    }
    

    Another moment is that for TPM2_RH_PLATFORM I need a session, so I replaced it by TPM2_RH_OWNER according to NV Public Attributes:

    ...
    int main(void) {
      ...
      publicInfo.nvPublic.attributes |= TPMA_NV_AUTHREAD;
      publicInfo.nvPublic.attributes |= TPMA_NV_AUTHWRITE;
      publicInfo.nvPublic.attributes |= TPMA_NV_OWNERWRITE;
      publicInfo.nvPublic.attributes |= TPMA_NV_OWNERREAD;
      publicInfo.nvPublic.attributes |= TPMA_NV_WRITE_STCLEAR;
      publicInfo.nvPublic.attributes |= TPMA_NV_READ_STCLEAR;
      ...
    
      rc = Tss2_Sys_NV_DefineSpace(ctx, TPM2_RH_OWNER,
          &sessionsData, &nvAuth, &publicInfo, &sessionsDataOut);
      ...
      
      rc = Tss2_Sys_NV_UndefineSpace(ctx, TPM2_RH_OWNER,
          TEST_NV_INDEX, &sessionsData, 0);
      ...
    }
    

    And compile this with TctiLdr:

    $ gcc -o nvdefine nvdefine.c -ltss2-sys -ltss2-tctildr
    

    The whole code listing:

    #include <tss2/tss2_sys.h>
    #include <tss2/tss2_tctildr.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define TEST_NV_INDEX 0x01500020
    
    
    int main(void) {
      char passwd[] = { "password" };
      UINT32 rc;
      TSS2L_SYS_AUTH_RESPONSE sessionsDataOut;
      TPM2B_NV_PUBLIC publicInfo;
      TPM2B_AUTH nvAuth;
    
      size_t ctx_size = Tss2_Sys_GetContextSize(0);
      TSS2_SYS_CONTEXT *ctx = calloc(1, ctx_size);
      TSS2_TCTI_CONTEXT *tcti_ctx = NULL;
      TSS2_ABI_VERSION abiVersion = TSS2_ABI_VERSION_CURRENT;
      TSS2L_SYS_AUTH_COMMAND sessionsData = { .count = 1, .auths = {{
        .sessionHandle = TPM2_RH_PW,
        .sessionAttributes = 0,
        .nonce = { .size = 0 },
        .hmac = { .size = 0 }
      }}};
    
      nvAuth.size = strlen(passwd);
      memcpy(&nvAuth.buffer[0], &passwd[0], nvAuth.size);
    
      publicInfo.size = 0;
      publicInfo.nvPublic.nvIndex = TEST_NV_INDEX;
      publicInfo.nvPublic.nameAlg = TPM2_ALG_SHA256;
    
      *(UINT32 *)&(publicInfo.nvPublic.attributes) = 0;
    
      publicInfo.nvPublic.attributes |= TPMA_NV_AUTHREAD;
      publicInfo.nvPublic.attributes |= TPMA_NV_AUTHWRITE;
      publicInfo.nvPublic.attributes |= TPMA_NV_OWNERWRITE;
      publicInfo.nvPublic.attributes |= TPMA_NV_OWNERREAD;
      publicInfo.nvPublic.attributes |= TPMA_NV_WRITE_STCLEAR;
      publicInfo.nvPublic.attributes |= TPMA_NV_READ_STCLEAR;
      publicInfo.nvPublic.authPolicy.size = 0;
      publicInfo.nvPublic.dataSize = 32;
    
      if (!ctx) {
        fprintf(stderr, "Sys Context NULL\n");
        exit(1);
      }
    
      rc = Tss2_TctiLdr_Initialize(NULL, &tcti_ctx);
      if (rc != TPM2_RC_SUCCESS) {
        fprintf(stderr, "Failed to Tss2_TctiLdr_Initialize: 0x%x\n", rc);
        exit(1);
      }
    
      rc = Tss2_Sys_Initialize(ctx, ctx_size,
          tcti_ctx, &abiVersion);
      if (rc != TPM2_RC_SUCCESS) {
        fprintf(stderr, "Failed to Tss2_Sys_Initialize: rc = 0x%x\n", rc);
        exit(1);
      }
    
      rc = Tss2_Sys_NV_DefineSpace(ctx, TPM2_RH_OWNER,
          &sessionsData, &nvAuth, &publicInfo, &sessionsDataOut);
      if (rc != TPM2_RC_SUCCESS) {
        fprintf(stderr, "Failed to Tss2_Sys_NV_DefineSpace: rc = 0x%x\n", rc);
        goto free_ctx;
      }
    
      rc = Tss2_Sys_NV_UndefineSpace(ctx, TPM2_RH_OWNER,
          TEST_NV_INDEX, &sessionsData, 0);
      if (rc != TPM2_RC_SUCCESS) {
        fprintf(stderr, "Failed to Tss2_Sys_NV_UndefineSpace: rc = 0x%x", rc);
        goto free_ctx;
      }
    
      Tss2_Sys_Finalize(ctx);
      exit(0);
    
    free_ctx:
      Tss2_Sys_Finalize(ctx);
      exit(1);
    }
    

    This works!