Search code examples
uefitpm

UEFI TGC2's sendCommand always returns error 21


I'm developing an UEFI app using the TPM2. getCapabilities works, but everything else is shoved onto this submitCommand() function. everything I try there returns EFI_ABORTED as status.

I tried several commands, like read_PCR and get_random_number, but it appears to occur for all commands (TPM2 spec part 3). I chose the random number command because it's a simple command without authorization or encryption that should always return when executed correctly.

struct TPM2_ {
    EFI_HANDLE image;
    EFI_BOOT_SERVICES *BS;
    EFI_TCG2_PROTOCOL *prot;
    UINT32 activePCRbanks;
};

struct TPM2_Rand_Read_Command {
        TPMI_ST_COMMAND_TAG     tag;
        UINT32                  commandSize;
        TPM_CC                  commandCode;
        UINT16                  bytesRequested;
    };
    struct TPM2_Rand_Read_Response {
        TPM_ST                  tag;
        UINT32                  responseSize;
        TPM_RC                  responseCode;
        TPM2B_DIGEST            randomBytes;
    };

UINTN tpm_get_random(TPM2 * tpm) {
    struct TPM2_Rand_Read_Command cmd;
    struct TPM2_Rand_Read_Response resp;

    cmd.tag = __builtin_bswap16(TPM_ST_NO_SESSIONS); //x86 is little endian, TPM2 is big-endian, use bswap to convert!)
    cmd.commandCode = __builtin_bswap32(TPM_CC_GetRandom);
    cmd.commandSize = __builtin_bswap32(sizeof(struct TPM2_Rand_Read_Command));
    cmd.bytesRequested = __builtin_bswap16(4);
    EFI_STATUS stat = tpm->prot->SubmitCommand(tpm->prot,sizeof(struct TPM2_Rand_Read_Command), (UINT8*)&cmd,sizeof(struct TPM2_Rand_Read_Response),(UINT8*)&resp); //responds 0x15 || 21
    Print(L"statreadrand: %x \t %d \r\n", stat, *((UINT32*)resp.randomBytes.buffer));
    CHECK_STATUS(stat, L"SubmitReadCommand");
    return 0;
}

TPM2* tpm_create(EFI_BOOT_SERVICES *BS, EFI_HANDLE image) {
    TPM2* tpm = calloc(1, sizeof(TPM2));
    EFI_GUID prot_guid = (EFI_GUID)EFI_TCG2_PROTOCOL_GUID;
    tpm->BS = BS;
    tpm->image = image;
    EFI_STATUS stat = tpm->BS->LocateProtocol(&prot_guid, NULL, (void **)&tpm->prot);
    CHECK_STATUS(stat, L"LocateTPMProtocol");
    return tpm;
}

I expect the SubmitCommand function to return EFI_SUCCESS (0) and fill the response struct with 4 random bytes. But the function returns EFI_ABORTED (21)

Does anyone know how to solve this?

EDIT: tried different toolchains (GNU-EFI/ plain GCC / EDK2) all give the same behaviour.


Solution

  • The particular PC had this exact problem. probably the TPM was locked. When using a different PC With a TPM2 the problem didn' t occur and instead, I just got a random number back.