/** @file | |
Implement TPM2 Integrity related command. | |
Copyright (c) 2013 - 2021, Intel Corporation. All rights reserved. <BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <IndustryStandard/UefiTcgPlatform.h> | |
#include <Library/Tpm2CommandLib.h> | |
#include <Library/Tpm2DeviceLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/DebugLib.h> | |
#pragma pack(1) | |
typedef struct { | |
TPM2_COMMAND_HEADER Header; | |
TPMI_DH_PCR PcrHandle; | |
UINT32 AuthorizationSize; | |
TPMS_AUTH_COMMAND AuthSessionPcr; | |
TPML_DIGEST_VALUES DigestValues; | |
} TPM2_PCR_EXTEND_COMMAND; | |
typedef struct { | |
TPM2_RESPONSE_HEADER Header; | |
UINT32 ParameterSize; | |
TPMS_AUTH_RESPONSE AuthSessionPcr; | |
} TPM2_PCR_EXTEND_RESPONSE; | |
typedef struct { | |
TPM2_COMMAND_HEADER Header; | |
TPMI_DH_PCR PcrHandle; | |
UINT32 AuthorizationSize; | |
TPMS_AUTH_COMMAND AuthSessionPcr; | |
TPM2B_EVENT EventData; | |
} TPM2_PCR_EVENT_COMMAND; | |
typedef struct { | |
TPM2_RESPONSE_HEADER Header; | |
UINT32 ParameterSize; | |
TPML_DIGEST_VALUES Digests; | |
TPMS_AUTH_RESPONSE AuthSessionPcr; | |
} TPM2_PCR_EVENT_RESPONSE; | |
typedef struct { | |
TPM2_COMMAND_HEADER Header; | |
TPML_PCR_SELECTION PcrSelectionIn; | |
} TPM2_PCR_READ_COMMAND; | |
typedef struct { | |
TPM2_RESPONSE_HEADER Header; | |
UINT32 PcrUpdateCounter; | |
TPML_PCR_SELECTION PcrSelectionOut; | |
TPML_DIGEST PcrValues; | |
} TPM2_PCR_READ_RESPONSE; | |
typedef struct { | |
TPM2_COMMAND_HEADER Header; | |
TPMI_RH_PLATFORM AuthHandle; | |
UINT32 AuthSessionSize; | |
TPMS_AUTH_COMMAND AuthSession; | |
TPML_PCR_SELECTION PcrAllocation; | |
} TPM2_PCR_ALLOCATE_COMMAND; | |
typedef struct { | |
TPM2_RESPONSE_HEADER Header; | |
UINT32 AuthSessionSize; | |
TPMI_YES_NO AllocationSuccess; | |
UINT32 MaxPCR; | |
UINT32 SizeNeeded; | |
UINT32 SizeAvailable; | |
TPMS_AUTH_RESPONSE AuthSession; | |
} TPM2_PCR_ALLOCATE_RESPONSE; | |
#pragma pack() | |
/** | |
This command is used to cause an update to the indicated PCR. | |
The digests parameter contains one or more tagged digest value identified by an algorithm ID. | |
For each digest, the PCR associated with pcrHandle is Extended into the bank identified by the tag (hashAlg). | |
@param[in] PcrHandle Handle of the PCR | |
@param[in] Digests List of tagged digest values to be extended | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR Unexpected device behavior. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tpm2PcrExtend ( | |
IN TPMI_DH_PCR PcrHandle, | |
IN TPML_DIGEST_VALUES *Digests | |
) | |
{ | |
EFI_STATUS Status; | |
TPM2_PCR_EXTEND_COMMAND Cmd; | |
TPM2_PCR_EXTEND_RESPONSE Res; | |
UINT32 CmdSize; | |
UINT32 RespSize; | |
UINT32 ResultBufSize; | |
UINT8 *Buffer; | |
UINTN Index; | |
UINT32 SessionInfoSize; | |
UINT16 DigestSize; | |
Cmd.Header.tag = SwapBytes16 (TPM_ST_SESSIONS); | |
Cmd.Header.commandCode = SwapBytes32 (TPM_CC_PCR_Extend); | |
Cmd.PcrHandle = SwapBytes32 (PcrHandle); | |
// | |
// Add in Auth session | |
// | |
Buffer = (UINT8 *)&Cmd.AuthSessionPcr; | |
// sessionInfoSize | |
SessionInfoSize = CopyAuthSessionCommand (NULL, Buffer); | |
Buffer += SessionInfoSize; | |
Cmd.AuthorizationSize = SwapBytes32 (SessionInfoSize); | |
// Digest Count | |
WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (Digests->count)); | |
Buffer += sizeof (UINT32); | |
// Digest | |
for (Index = 0; Index < Digests->count; Index++) { | |
WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Digests->digests[Index].hashAlg)); | |
Buffer += sizeof (UINT16); | |
DigestSize = GetHashSizeFromAlgo (Digests->digests[Index].hashAlg); | |
if (DigestSize == 0) { | |
DEBUG ((DEBUG_ERROR, "Unknown hash algorithm %d\r\n", Digests->digests[Index].hashAlg)); | |
return EFI_DEVICE_ERROR; | |
} | |
CopyMem ( | |
Buffer, | |
&Digests->digests[Index].digest, | |
DigestSize | |
); | |
DEBUG_CODE_BEGIN (); | |
UINTN Index2; | |
DEBUG (( | |
DEBUG_VERBOSE, | |
"Tpm2PcrExtend - Hash = 0x%04x, Pcr[%02d], digest = ", | |
Digests->digests[Index].hashAlg, | |
(UINT8)PcrHandle | |
)); | |
for (Index2 = 0; Index2 < DigestSize; Index2++) { | |
DEBUG ((DEBUG_VERBOSE, "%02x ", Buffer[Index2])); | |
} | |
DEBUG ((DEBUG_VERBOSE, "\n")); | |
DEBUG_CODE_END (); | |
Buffer += DigestSize; | |
} | |
CmdSize = (UINT32)((UINTN)Buffer - (UINTN)&Cmd); | |
Cmd.Header.paramSize = SwapBytes32 (CmdSize); | |
ResultBufSize = sizeof (Res); | |
Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (ResultBufSize > sizeof (Res)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrExtend: Failed ExecuteCommand: Buffer Too Small\r\n")); | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// Validate response headers | |
// | |
RespSize = SwapBytes32 (Res.Header.paramSize); | |
if (RespSize > sizeof (Res)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrExtend: Response size too large! %d\r\n", RespSize)); | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// Fail if command failed | |
// | |
if (SwapBytes32 (Res.Header.responseCode) != TPM_RC_SUCCESS) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrExtend: Response Code error! 0x%08x\r\n", SwapBytes32 (Res.Header.responseCode))); | |
return EFI_DEVICE_ERROR; | |
} | |
DEBUG_CODE_BEGIN (); | |
DEBUG ((DEBUG_VERBOSE, "Tpm2PcrExtend: PCR read after extend...\n")); | |
Tpm2PcrReadForActiveBank (PcrHandle, NULL); | |
DEBUG_CODE_END (); | |
// | |
// Unmarshal the response | |
// | |
// None | |
return EFI_SUCCESS; | |
} | |
/** | |
This command is used to cause an update to the indicated PCR. | |
The data in eventData is hashed using the hash algorithm associated with each bank in which the | |
indicated PCR has been allocated. After the data is hashed, the digests list is returned. If the pcrHandle | |
references an implemented PCR and not TPM_ALG_NULL, digests list is processed as in | |
TPM2_PCR_Extend(). | |
A TPM shall support an Event.size of zero through 1,024 inclusive. | |
@param[in] PcrHandle Handle of the PCR | |
@param[in] EventData Event data in sized buffer | |
@param[out] Digests List of digest | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR Unexpected device behavior. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tpm2PcrEvent ( | |
IN TPMI_DH_PCR PcrHandle, | |
IN TPM2B_EVENT *EventData, | |
OUT TPML_DIGEST_VALUES *Digests | |
) | |
{ | |
EFI_STATUS Status; | |
TPM2_PCR_EVENT_COMMAND Cmd; | |
TPM2_PCR_EVENT_RESPONSE Res; | |
UINT32 CmdSize; | |
UINT32 RespSize; | |
UINT32 ResultBufSize; | |
UINT8 *Buffer; | |
UINTN Index; | |
UINT32 SessionInfoSize; | |
UINT16 DigestSize; | |
Cmd.Header.tag = SwapBytes16 (TPM_ST_SESSIONS); | |
Cmd.Header.commandCode = SwapBytes32 (TPM_CC_PCR_Event); | |
Cmd.PcrHandle = SwapBytes32 (PcrHandle); | |
// | |
// Add in Auth session | |
// | |
Buffer = (UINT8 *)&Cmd.AuthSessionPcr; | |
// sessionInfoSize | |
SessionInfoSize = CopyAuthSessionCommand (NULL, Buffer); | |
Buffer += SessionInfoSize; | |
Cmd.AuthorizationSize = SwapBytes32 (SessionInfoSize); | |
// Event | |
WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (EventData->size)); | |
Buffer += sizeof (UINT16); | |
CopyMem (Buffer, EventData->buffer, EventData->size); | |
Buffer += EventData->size; | |
CmdSize = (UINT32)((UINTN)Buffer - (UINTN)&Cmd); | |
Cmd.Header.paramSize = SwapBytes32 (CmdSize); | |
ResultBufSize = sizeof (Res); | |
Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (ResultBufSize > sizeof (Res)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrEvent: Failed ExecuteCommand: Buffer Too Small\r\n")); | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// Validate response headers | |
// | |
RespSize = SwapBytes32 (Res.Header.paramSize); | |
if (RespSize > sizeof (Res)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrEvent: Response size too large! %d\r\n", RespSize)); | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// Fail if command failed | |
// | |
if (SwapBytes32 (Res.Header.responseCode) != TPM_RC_SUCCESS) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrEvent: Response Code error! 0x%08x\r\n", SwapBytes32 (Res.Header.responseCode))); | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Unmarshal the response | |
// | |
Buffer = (UINT8 *)&Res.Digests; | |
Digests->count = SwapBytes32 (ReadUnaligned32 ((UINT32 *)Buffer)); | |
if (Digests->count > HASH_COUNT) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrEvent - Digests->count error %x\n", Digests->count)); | |
return EFI_DEVICE_ERROR; | |
} | |
Buffer += sizeof (UINT32); | |
for (Index = 0; Index < Digests->count; Index++) { | |
Digests->digests[Index].hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); | |
Buffer += sizeof (UINT16); | |
DigestSize = GetHashSizeFromAlgo (Digests->digests[Index].hashAlg); | |
if (DigestSize == 0) { | |
DEBUG ((DEBUG_ERROR, "Unknown hash algorithm %d\r\n", Digests->digests[Index].hashAlg)); | |
return EFI_DEVICE_ERROR; | |
} | |
CopyMem ( | |
&Digests->digests[Index].digest, | |
Buffer, | |
DigestSize | |
); | |
Buffer += DigestSize; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This command returns the values of all PCR specified in pcrSelect. | |
@param[in] PcrSelectionIn The selection of PCR to read. | |
@param[out] PcrUpdateCounter The current value of the PCR update counter. | |
@param[out] PcrSelectionOut The PCR in the returned list. | |
@param[out] PcrValues The contents of the PCR indicated in pcrSelect. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR The command was unsuccessful. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tpm2PcrRead ( | |
IN TPML_PCR_SELECTION *PcrSelectionIn, | |
OUT UINT32 *PcrUpdateCounter, | |
OUT TPML_PCR_SELECTION *PcrSelectionOut, | |
OUT TPML_DIGEST *PcrValues | |
) | |
{ | |
EFI_STATUS Status; | |
TPM2_PCR_READ_COMMAND SendBuffer; | |
TPM2_PCR_READ_RESPONSE RecvBuffer; | |
UINT32 SendBufferSize; | |
UINT32 RecvBufferSize; | |
UINTN Index; | |
TPML_DIGEST *PcrValuesOut; | |
TPM2B_DIGEST *Digests; | |
// | |
// Construct command | |
// | |
SendBuffer.Header.tag = SwapBytes16 (TPM_ST_NO_SESSIONS); | |
SendBuffer.Header.commandCode = SwapBytes32 (TPM_CC_PCR_Read); | |
SendBuffer.PcrSelectionIn.count = SwapBytes32 (PcrSelectionIn->count); | |
for (Index = 0; Index < PcrSelectionIn->count; Index++) { | |
SendBuffer.PcrSelectionIn.pcrSelections[Index].hash = SwapBytes16 (PcrSelectionIn->pcrSelections[Index].hash); | |
SendBuffer.PcrSelectionIn.pcrSelections[Index].sizeofSelect = PcrSelectionIn->pcrSelections[Index].sizeofSelect; | |
CopyMem (&SendBuffer.PcrSelectionIn.pcrSelections[Index].pcrSelect, &PcrSelectionIn->pcrSelections[Index].pcrSelect, SendBuffer.PcrSelectionIn.pcrSelections[Index].sizeofSelect); | |
} | |
SendBufferSize = sizeof (SendBuffer.Header) + sizeof (SendBuffer.PcrSelectionIn.count) + sizeof (SendBuffer.PcrSelectionIn.pcrSelections[0]) * PcrSelectionIn->count; | |
SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); | |
// | |
// send Tpm command | |
// | |
RecvBufferSize = sizeof (RecvBuffer); | |
Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize)); | |
return EFI_DEVICE_ERROR; | |
} | |
if (SwapBytes32 (RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - responseCode - %x\n", SwapBytes32 (RecvBuffer.Header.responseCode))); | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Return the response | |
// | |
// | |
// PcrUpdateCounter | |
// | |
if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof (RecvBuffer.PcrUpdateCounter)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize)); | |
return EFI_DEVICE_ERROR; | |
} | |
*PcrUpdateCounter = SwapBytes32 (RecvBuffer.PcrUpdateCounter); | |
// | |
// PcrSelectionOut | |
// | |
if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof (RecvBuffer.PcrUpdateCounter) + sizeof (RecvBuffer.PcrSelectionOut.count)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize)); | |
return EFI_DEVICE_ERROR; | |
} | |
PcrSelectionOut->count = SwapBytes32 (RecvBuffer.PcrSelectionOut.count); | |
if (PcrSelectionOut->count > HASH_COUNT) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - PcrSelectionOut->count error %x\n", PcrSelectionOut->count)); | |
return EFI_DEVICE_ERROR; | |
} | |
if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof (RecvBuffer.PcrUpdateCounter) + sizeof (RecvBuffer.PcrSelectionOut.count) + sizeof (RecvBuffer.PcrSelectionOut.pcrSelections[0]) * PcrSelectionOut->count) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize)); | |
return EFI_DEVICE_ERROR; | |
} | |
for (Index = 0; Index < PcrSelectionOut->count; Index++) { | |
PcrSelectionOut->pcrSelections[Index].hash = SwapBytes16 (RecvBuffer.PcrSelectionOut.pcrSelections[Index].hash); | |
PcrSelectionOut->pcrSelections[Index].sizeofSelect = RecvBuffer.PcrSelectionOut.pcrSelections[Index].sizeofSelect; | |
if (PcrSelectionOut->pcrSelections[Index].sizeofSelect > PCR_SELECT_MAX) { | |
return EFI_DEVICE_ERROR; | |
} | |
CopyMem (&PcrSelectionOut->pcrSelections[Index].pcrSelect, &RecvBuffer.PcrSelectionOut.pcrSelections[Index].pcrSelect, PcrSelectionOut->pcrSelections[Index].sizeofSelect); | |
} | |
// | |
// PcrValues | |
// | |
PcrValuesOut = (TPML_DIGEST *)((UINT8 *)&RecvBuffer + sizeof (TPM2_RESPONSE_HEADER) + sizeof (RecvBuffer.PcrUpdateCounter) + sizeof (RecvBuffer.PcrSelectionOut.count) + sizeof (RecvBuffer.PcrSelectionOut.pcrSelections[0]) * PcrSelectionOut->count); | |
PcrValues->count = SwapBytes32 (PcrValuesOut->count); | |
// | |
// The number of digests in list is not greater than 8 per TPML_DIGEST definition | |
// | |
if (PcrValues->count > 8) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - PcrValues->count error %x\n", PcrValues->count)); | |
return EFI_DEVICE_ERROR; | |
} | |
Digests = PcrValuesOut->digests; | |
for (Index = 0; Index < PcrValues->count; Index++) { | |
PcrValues->digests[Index].size = SwapBytes16 (Digests->size); | |
if (PcrValues->digests[Index].size > sizeof (TPMU_HA)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - Digest.size error %x\n", PcrValues->digests[Index].size)); | |
return EFI_DEVICE_ERROR; | |
} | |
CopyMem (&PcrValues->digests[Index].buffer, &Digests->buffer, PcrValues->digests[Index].size); | |
Digests = (TPM2B_DIGEST *)((UINT8 *)Digests + sizeof (Digests->size) + PcrValues->digests[Index].size); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This command is used to set the desired PCR allocation of PCR and algorithms. | |
@param[in] AuthHandle TPM_RH_PLATFORM+{PP} | |
@param[in] AuthSession Auth Session context | |
@param[in] PcrAllocation The requested allocation | |
@param[out] AllocationSuccess YES if the allocation succeeded | |
@param[out] MaxPCR maximum number of PCR that may be in a bank | |
@param[out] SizeNeeded number of octets required to satisfy the request | |
@param[out] SizeAvailable Number of octets available. Computed before the allocation | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR The command was unsuccessful. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tpm2PcrAllocate ( | |
IN TPMI_RH_PLATFORM AuthHandle, | |
IN TPMS_AUTH_COMMAND *AuthSession, | |
IN TPML_PCR_SELECTION *PcrAllocation, | |
OUT TPMI_YES_NO *AllocationSuccess, | |
OUT UINT32 *MaxPCR, | |
OUT UINT32 *SizeNeeded, | |
OUT UINT32 *SizeAvailable | |
) | |
{ | |
EFI_STATUS Status; | |
TPM2_PCR_ALLOCATE_COMMAND Cmd; | |
TPM2_PCR_ALLOCATE_RESPONSE Res; | |
UINT32 CmdSize; | |
UINT32 RespSize; | |
UINT8 *Buffer; | |
UINT32 SessionInfoSize; | |
UINT8 *ResultBuf; | |
UINT32 ResultBufSize; | |
UINTN Index; | |
// | |
// Construct command | |
// | |
Cmd.Header.tag = SwapBytes16 (TPM_ST_SESSIONS); | |
Cmd.Header.paramSize = SwapBytes32 (sizeof (Cmd)); | |
Cmd.Header.commandCode = SwapBytes32 (TPM_CC_PCR_Allocate); | |
Cmd.AuthHandle = SwapBytes32 (AuthHandle); | |
// | |
// Add in Auth session | |
// | |
Buffer = (UINT8 *)&Cmd.AuthSession; | |
// sessionInfoSize | |
SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); | |
Buffer += SessionInfoSize; | |
Cmd.AuthSessionSize = SwapBytes32 (SessionInfoSize); | |
// Count | |
WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (PcrAllocation->count)); | |
Buffer += sizeof (UINT32); | |
for (Index = 0; Index < PcrAllocation->count; Index++) { | |
WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (PcrAllocation->pcrSelections[Index].hash)); | |
Buffer += sizeof (UINT16); | |
*(UINT8 *)Buffer = PcrAllocation->pcrSelections[Index].sizeofSelect; | |
Buffer++; | |
CopyMem (Buffer, PcrAllocation->pcrSelections[Index].pcrSelect, PcrAllocation->pcrSelections[Index].sizeofSelect); | |
Buffer += PcrAllocation->pcrSelections[Index].sizeofSelect; | |
} | |
CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); | |
Cmd.Header.paramSize = SwapBytes32 (CmdSize); | |
ResultBuf = (UINT8 *)&Res; | |
ResultBufSize = sizeof (Res); | |
// | |
// Call the TPM | |
// | |
Status = Tpm2SubmitCommand ( | |
CmdSize, | |
(UINT8 *)&Cmd, | |
&ResultBufSize, | |
ResultBuf | |
); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
if (ResultBufSize > sizeof (Res)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrAllocate: Failed ExecuteCommand: Buffer Too Small\r\n")); | |
Status = EFI_BUFFER_TOO_SMALL; | |
goto Done; | |
} | |
// | |
// Validate response headers | |
// | |
RespSize = SwapBytes32 (Res.Header.paramSize); | |
if (RespSize > sizeof (Res)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrAllocate: Response size too large! %d\r\n", RespSize)); | |
Status = EFI_BUFFER_TOO_SMALL; | |
goto Done; | |
} | |
// | |
// Fail if command failed | |
// | |
if (SwapBytes32 (Res.Header.responseCode) != TPM_RC_SUCCESS) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrAllocate: Response Code error! 0x%08x\r\n", SwapBytes32 (Res.Header.responseCode))); | |
Status = EFI_DEVICE_ERROR; | |
goto Done; | |
} | |
// | |
// Return the response | |
// | |
*AllocationSuccess = Res.AllocationSuccess; | |
*MaxPCR = SwapBytes32 (Res.MaxPCR); | |
*SizeNeeded = SwapBytes32 (Res.SizeNeeded); | |
*SizeAvailable = SwapBytes32 (Res.SizeAvailable); | |
Done: | |
// | |
// Clear AuthSession Content | |
// | |
ZeroMem (&Cmd, sizeof (Cmd)); | |
ZeroMem (&Res, sizeof (Res)); | |
return Status; | |
} | |
/** | |
Alloc PCR data. | |
@param[in] PlatformAuth platform auth value. NULL means no platform auth change. | |
@param[in] SupportedPCRBanks Supported PCR banks | |
@param[in] PCRBanks PCR banks | |
@retval EFI_SUCCESS Operation completed successfully. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tpm2PcrAllocateBanks ( | |
IN TPM2B_AUTH *PlatformAuth OPTIONAL, | |
IN UINT32 SupportedPCRBanks, | |
IN UINT32 PCRBanks | |
) | |
{ | |
EFI_STATUS Status; | |
TPMS_AUTH_COMMAND *AuthSession; | |
TPMS_AUTH_COMMAND LocalAuthSession; | |
TPML_PCR_SELECTION PcrAllocation; | |
TPMI_YES_NO AllocationSuccess; | |
UINT32 MaxPCR; | |
UINT32 SizeNeeded; | |
UINT32 SizeAvailable; | |
if (PlatformAuth == NULL) { | |
AuthSession = NULL; | |
} else { | |
AuthSession = &LocalAuthSession; | |
ZeroMem (&LocalAuthSession, sizeof (LocalAuthSession)); | |
LocalAuthSession.sessionHandle = TPM_RS_PW; | |
LocalAuthSession.hmac.size = PlatformAuth->size; | |
CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size); | |
} | |
// | |
// Fill input | |
// | |
ZeroMem (&PcrAllocation, sizeof (PcrAllocation)); | |
if ((HASH_ALG_SHA1 & SupportedPCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA1; | |
PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; | |
if ((HASH_ALG_SHA1 & PCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; | |
} else { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; | |
} | |
PcrAllocation.count++; | |
} | |
if ((HASH_ALG_SHA256 & SupportedPCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA256; | |
PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; | |
if ((HASH_ALG_SHA256 & PCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; | |
} else { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; | |
} | |
PcrAllocation.count++; | |
} | |
if ((HASH_ALG_SHA384 & SupportedPCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA384; | |
PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; | |
if ((HASH_ALG_SHA384 & PCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; | |
} else { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; | |
} | |
PcrAllocation.count++; | |
} | |
if ((HASH_ALG_SHA512 & SupportedPCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA512; | |
PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; | |
if ((HASH_ALG_SHA512 & PCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; | |
} else { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; | |
} | |
PcrAllocation.count++; | |
} | |
if ((HASH_ALG_SM3_256 & SupportedPCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SM3_256; | |
PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; | |
if ((HASH_ALG_SM3_256 & PCRBanks) != 0) { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; | |
} else { | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; | |
PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; | |
} | |
PcrAllocation.count++; | |
} | |
Status = Tpm2PcrAllocate ( | |
TPM_RH_PLATFORM, | |
AuthSession, | |
&PcrAllocation, | |
&AllocationSuccess, | |
&MaxPCR, | |
&SizeNeeded, | |
&SizeAvailable | |
); | |
DEBUG ((DEBUG_INFO, "Tpm2PcrAllocateBanks call Tpm2PcrAllocate - %r\n", Status)); | |
if (EFI_ERROR (Status)) { | |
goto Done; | |
} | |
DEBUG ((DEBUG_INFO, "AllocationSuccess - %02x\n", AllocationSuccess)); | |
DEBUG ((DEBUG_INFO, "MaxPCR - %08x\n", MaxPCR)); | |
DEBUG ((DEBUG_INFO, "SizeNeeded - %08x\n", SizeNeeded)); | |
DEBUG ((DEBUG_INFO, "SizeAvailable - %08x\n", SizeAvailable)); | |
Done: | |
ZeroMem (&LocalAuthSession.hmac, sizeof (LocalAuthSession.hmac)); | |
return Status; | |
} | |
/** | |
This function will query the TPM to determine which hashing algorithms and | |
get the digests of all active and supported PCR banks of a specific PCR register. | |
@param[in] PcrHandle The index of the PCR register to be read. | |
@param[out] HashList List of digests from PCR register being read. | |
@retval EFI_SUCCESS The Pcr was read successfully. | |
@retval EFI_DEVICE_ERROR The command was unsuccessful. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tpm2PcrReadForActiveBank ( | |
IN TPMI_DH_PCR PcrHandle, | |
OUT TPML_DIGEST *HashList | |
) | |
{ | |
EFI_STATUS Status; | |
TPML_PCR_SELECTION Pcrs; | |
TPML_PCR_SELECTION PcrSelectionIn; | |
TPML_PCR_SELECTION PcrSelectionOut; | |
TPML_DIGEST PcrValues; | |
UINT32 PcrUpdateCounter; | |
UINT8 PcrIndex; | |
UINT32 TpmHashAlgorithmBitmap; | |
TPMI_ALG_HASH CurrentPcrBankHash; | |
UINT32 ActivePcrBanks; | |
UINT32 TcgRegistryHashAlg; | |
UINTN Index; | |
UINTN Index2; | |
PcrIndex = (UINT8)PcrHandle; | |
if ((PcrIndex < 0) || | |
(PcrIndex >= IMPLEMENTATION_PCR)) | |
{ | |
return EFI_INVALID_PARAMETER; | |
} | |
ZeroMem (&PcrSelectionIn, sizeof (PcrSelectionIn)); | |
ZeroMem (&PcrUpdateCounter, sizeof (UINT32)); | |
ZeroMem (&PcrSelectionOut, sizeof (PcrSelectionOut)); | |
ZeroMem (&PcrValues, sizeof (PcrValues)); | |
ZeroMem (&Pcrs, sizeof (TPML_PCR_SELECTION)); | |
DEBUG ((DEBUG_INFO, "ReadPcr - %02d\n", PcrIndex)); | |
// | |
// Read TPM capabilities | |
// | |
Status = Tpm2GetCapabilityPcrs (&Pcrs); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "ReadPcr: Unable to read TPM capabilities\n")); | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Get Active Pcrs | |
// | |
Status = Tpm2GetCapabilitySupportedAndActivePcrs ( | |
&TpmHashAlgorithmBitmap, | |
&ActivePcrBanks | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "ReadPcr: Unable to read TPM capabilities and active PCRs\n")); | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Select from Active PCRs | |
// | |
for (Index = 0; Index < Pcrs.count; Index++) { | |
CurrentPcrBankHash = Pcrs.pcrSelections[Index].hash; | |
switch (CurrentPcrBankHash) { | |
case TPM_ALG_SHA1: | |
DEBUG ((DEBUG_VERBOSE, "HASH_ALG_SHA1 Present\n")); | |
TcgRegistryHashAlg = HASH_ALG_SHA1; | |
break; | |
case TPM_ALG_SHA256: | |
DEBUG ((DEBUG_VERBOSE, "HASH_ALG_SHA256 Present\n")); | |
TcgRegistryHashAlg = HASH_ALG_SHA256; | |
break; | |
case TPM_ALG_SHA384: | |
DEBUG ((DEBUG_VERBOSE, "HASH_ALG_SHA384 Present\n")); | |
TcgRegistryHashAlg = HASH_ALG_SHA384; | |
break; | |
case TPM_ALG_SHA512: | |
DEBUG ((DEBUG_VERBOSE, "HASH_ALG_SHA512 Present\n")); | |
TcgRegistryHashAlg = HASH_ALG_SHA512; | |
break; | |
case TPM_ALG_SM3_256: | |
DEBUG ((DEBUG_VERBOSE, "HASH_ALG_SM3 Present\n")); | |
TcgRegistryHashAlg = HASH_ALG_SM3_256; | |
break; | |
default: | |
// | |
// Unsupported algorithm | |
// | |
DEBUG ((DEBUG_VERBOSE, "Unknown algorithm present\n")); | |
TcgRegistryHashAlg = 0; | |
break; | |
} | |
// | |
// Skip unsupported and inactive PCR banks | |
// | |
if ((TcgRegistryHashAlg & ActivePcrBanks) == 0) { | |
DEBUG ((DEBUG_VERBOSE, "Skipping unsupported or inactive bank: 0x%04x\n", CurrentPcrBankHash)); | |
continue; | |
} | |
// | |
// Select PCR from current active bank | |
// | |
PcrSelectionIn.pcrSelections[PcrSelectionIn.count].hash = Pcrs.pcrSelections[Index].hash; | |
PcrSelectionIn.pcrSelections[PcrSelectionIn.count].sizeofSelect = PCR_SELECT_MAX; | |
PcrSelectionIn.pcrSelections[PcrSelectionIn.count].pcrSelect[0] = (PcrIndex < 8) ? 1 << PcrIndex : 0; | |
PcrSelectionIn.pcrSelections[PcrSelectionIn.count].pcrSelect[1] = (PcrIndex > 7) && (PcrIndex < 16) ? 1 << (PcrIndex - 8) : 0; | |
PcrSelectionIn.pcrSelections[PcrSelectionIn.count].pcrSelect[2] = (PcrIndex > 15) ? 1 << (PcrIndex - 16) : 0; | |
PcrSelectionIn.count++; | |
} | |
// | |
// Read PCRs | |
// | |
Status = Tpm2PcrRead ( | |
&PcrSelectionIn, | |
&PcrUpdateCounter, | |
&PcrSelectionOut, | |
&PcrValues | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2PcrRead failed Status = %r \n", Status)); | |
return EFI_DEVICE_ERROR; | |
} | |
for (Index = 0; Index < PcrValues.count; Index++) { | |
DEBUG (( | |
DEBUG_INFO, | |
"ReadPcr - HashAlg = 0x%04x, Pcr[%02d], digest = ", | |
PcrSelectionOut.pcrSelections[Index].hash, | |
PcrIndex | |
)); | |
for (Index2 = 0; Index2 < PcrValues.digests[Index].size; Index2++) { | |
DEBUG ((DEBUG_INFO, "%02x ", PcrValues.digests[Index].buffer[Index2])); | |
} | |
DEBUG ((DEBUG_INFO, "\n")); | |
} | |
if (HashList != NULL) { | |
CopyMem ( | |
HashList, | |
&PcrValues, | |
sizeof (TPML_DIGEST) | |
); | |
} | |
return EFI_SUCCESS; | |
} |