blob: 39fff8e90de1e07e0e3e3bd5e841c31cc8e65fa3 [file] [log] [blame]
/** @file
Copyright (c) 2025, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiPei.h>
#include <Guid/TcgEventHob.h>
#include <Guid/TpmInstance.h>
#include <Guid/TransferListHob.h>
#include <IndustryStandard/UefiTcgPlatform.h>
#include <Library/ArmTransferListLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/Tpm2CommandLib.h>
#include <Library/Tpm2DeviceLib.h>
#include <Library/HashLib.h>
#include <Library/HobLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PrintLib.h>
#define HASH_ALG_ERROR 0x00
#define BAD_SEQ_HANDLE 0xFFFFFFFF
#define BAD_HASH_HANDLE 0x00
typedef struct {
TPM_ALG_ID AlgoId;
UINT32 Mask;
TPMI_DH_OBJECT SequenceHandle;
} TPM2_HASH_MASK;
STATIC TPM2_HASH_MASK mTpm2HashMask[] = {
{ TPM_ALG_SHA1, HASH_ALG_SHA1, BAD_SEQ_HANDLE },
{ TPM_ALG_SHA256, HASH_ALG_SHA256, BAD_SEQ_HANDLE },
{ TPM_ALG_SHA384, HASH_ALG_SHA384, BAD_SEQ_HANDLE },
{ TPM_ALG_SHA512, HASH_ALG_SHA512, BAD_SEQ_HANDLE },
};
STATIC UINT32 mSupportedHashBitmap;
STATIC BOOLEAN mHashLibDisabled;
/**
Get transfer list header.
@param[out] TransferList Transfer list header
@retval EFI_SUCCESS Transfer list is found.
@retval EFI_NOT_FOUND Transfer list is not found.
**/
STATIC
EFI_STATUS
EFIAPI
GetTransferList (
OUT TRANSFER_LIST_HEADER **TransferList
)
{
VOID *HobList;
EFI_HOB_GUID_TYPE *GuidHob;
UINTN *GuidHobData;
*TransferList = NULL;
HobList = GetHobList ();
if (HobList == NULL) {
return EFI_NOT_FOUND;
}
GuidHob = GetNextGuidHob (&gArmTransferListHobGuid, HobList);
if (GuidHob == NULL) {
return EFI_NOT_FOUND;
}
GuidHobData = GET_GUID_HOB_DATA (GuidHob);
*TransferList = (TRANSFER_LIST_HEADER *)(*GuidHobData);
return EFI_SUCCESS;
}
/**
The function get algorithm from hash mask info.
@param[in] HashMask
@return Hash algorithm
**/
STATIC
TPM_ALG_ID
EFIAPI
Tpm2GetAlgoFromHashMask (
IN UINT32 HashMask
)
{
UINTN Idx;
for (Idx = 0; Idx < ARRAY_SIZE (mTpm2HashMask); Idx++) {
if (mTpm2HashMask[Idx].Mask == HashMask) {
return mTpm2HashMask[Idx].AlgoId;
}
}
return TPM_ALG_ERROR;
}
/**
The function get hashmask from algorithm info.
@param[in] AlgoId
@return Hash mask
**/
STATIC
UINT32
EFIAPI
Tpm2GetHashMaskFromAlgo (
TPM_ALG_ID AlgoId
)
{
UINTN Idx;
for (Idx = 0; Idx < ARRAY_SIZE (mTpm2HashMask); Idx++) {
if (mTpm2HashMask[Idx].AlgoId == AlgoId) {
return mTpm2HashMask[Idx].Mask;
}
}
return HASH_ALG_ERROR;
}
/**
Validate hash handle.
@param[in] HashHandle HashHandle
@return EFI_SUCCESS
@return EFI_INVALID_PARAMETER Invalidate HashHandle
**/
STATIC
EFI_STATUS
EFIAPI
ValidateHashHandle (
IN HASH_HANDLE HashHandle
)
{
UINT32 Idx;
UINT32 HashMask;
for (Idx = 0; Idx < ARRAY_SIZE (mTpm2HashMask); Idx++) {
HashMask = 1 << Idx;
if ((HashHandle & HashMask) == 0x00) {
continue;
}
if (((mSupportedHashBitmap & HashMask) == 0x00) ||
(mTpm2HashMask[Idx].SequenceHandle == BAD_SEQ_HANDLE))
{
return EFI_INVALID_PARAMETER;
}
}
return EFI_SUCCESS;
}
/**
Clear Sequence Handles.
**/
STATIC
VOID
ClearSequenceHandles (
IN VOID
)
{
UINT32 Idx;
for (Idx = 0; Idx < ARRAY_SIZE (mTpm2HashMask); Idx++) {
mTpm2HashMask[Idx].SequenceHandle = BAD_SEQ_HANDLE;
}
}
/**
Start hash sequence.
@param HashHandle Hash handle.
@retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
@retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
**/
EFI_STATUS
EFIAPI
HashStart (
OUT HASH_HANDLE *HashHandle
)
{
EFI_STATUS Status;
TPM_ALG_ID AlgoId;
UINT32 Idx;
UINT32 HashMask;
HASH_HANDLE Handle;
if (mHashLibDisabled) {
return EFI_UNSUPPORTED;
}
Handle = BAD_HASH_HANDLE;
for (Idx = 0; Idx < ARRAY_SIZE (mTpm2HashMask); Idx++) {
HashMask = 1 << Idx;
if ((mSupportedHashBitmap & HashMask) == 0x00) {
continue;
}
if (mTpm2HashMask[Idx].SequenceHandle != BAD_SEQ_HANDLE) {
Status = EFI_ALREADY_STARTED;
Handle = BAD_HASH_HANDLE;
goto ErrorHandler;
}
AlgoId = Tpm2GetAlgoFromHashMask (HashMask);
ASSERT (AlgoId != TPM_ALG_ERROR);
Status = Tpm2HashSequenceStart (AlgoId, &mTpm2HashMask[Idx].SequenceHandle);
if (EFI_ERROR (Status)) {
Handle = BAD_HASH_HANDLE;
goto ErrorHandler;
}
Handle |= HashMask;
}
ErrorHandler:
*HashHandle = Handle;
if (Handle == BAD_HASH_HANDLE) {
ClearSequenceHandles ();
}
return Status;
}
/**
Update hash sequence data.
@param HashHandle Hash handle.
@param DataToHash Data to be hashed.
@param DataToHashLen Data size.
@retval EFI_SUCCESS Hash sequence updated.
**/
EFI_STATUS
EFIAPI
HashUpdate (
IN HASH_HANDLE HashHandle,
IN VOID *DataToHash,
IN UINTN DataToHashLen
)
{
EFI_STATUS Status;
UINT32 Idx;
UINT32 HashMask;
UINT8 *Buffer;
UINT64 HashLen;
TPM2B_MAX_BUFFER HashBuffer;
if (mHashLibDisabled) {
return EFI_UNSUPPORTED;
}
Status = ValidateHashHandle (HashHandle);
if (EFI_ERROR (Status)) {
return Status;
}
for (Idx = 0; Idx < ARRAY_SIZE (mTpm2HashMask); Idx++) {
HashMask = 1 << Idx;
if ((HashHandle & HashMask) == 0x00) {
continue;
}
Buffer = (UINT8 *)(UINTN)DataToHash;
for (HashLen = DataToHashLen; HashLen > sizeof (HashBuffer.buffer); HashLen -= sizeof (HashBuffer.buffer)) {
HashBuffer.size = sizeof (HashBuffer.buffer);
CopyMem (HashBuffer.buffer, Buffer, sizeof (HashBuffer.buffer));
Buffer += sizeof (HashBuffer.buffer);
Status = Tpm2SequenceUpdate (mTpm2HashMask[Idx].SequenceHandle, &HashBuffer);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
}
// Last one
HashBuffer.size = (UINT16)HashLen;
CopyMem (HashBuffer.buffer, Buffer, (UINTN)HashLen);
Status = Tpm2SequenceUpdate (mTpm2HashMask[Idx].SequenceHandle, &HashBuffer);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
}
return Status;
}
/**
Hash sequence complete and extend to PCR.
@param HashHandle Hash handle.
@param PcrIndex PCR to be extended.
@param DataToHash Data to be hashed.
@param DataToHashLen Data size.
@param DigestList Digest list.
@retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
**/
EFI_STATUS
EFIAPI
HashCompleteAndExtend (
IN HASH_HANDLE HashHandle,
IN TPMI_DH_PCR PcrIndex,
IN VOID *DataToHash,
IN UINTN DataToHashLen,
OUT TPML_DIGEST_VALUES *DigestList
)
{
EFI_STATUS Status;
UINT32 Idx;
UINT32 DigestIdx;
UINT32 HashMask;
UINT8 *Buffer;
UINT64 HashLen;
TPM2B_MAX_BUFFER HashBuffer;
TPM_ALG_ID AlgoId;
TPM2B_DIGEST Result;
if (mHashLibDisabled) {
return EFI_UNSUPPORTED;
}
Status = ValidateHashHandle (HashHandle);
if (EFI_ERROR (Status)) {
return Status;
}
ZeroMem (DigestList, sizeof (*DigestList));
DigestList->count = HASH_COUNT;
DigestIdx = 0;
for (Idx = 0; Idx < ARRAY_SIZE (mTpm2HashMask); Idx++) {
HashMask = 1 << Idx;
if ((HashHandle & HashMask) == 0x00) {
continue;
}
Buffer = (UINT8 *)(UINTN)DataToHash;
for (HashLen = DataToHashLen; HashLen > sizeof (HashBuffer.buffer); HashLen -= sizeof (HashBuffer.buffer)) {
HashBuffer.size = sizeof (HashBuffer.buffer);
CopyMem (HashBuffer.buffer, Buffer, sizeof (HashBuffer.buffer));
Buffer += sizeof (HashBuffer.buffer);
Status = Tpm2SequenceUpdate (mTpm2HashMask[Idx].SequenceHandle, &HashBuffer);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
}
// Last one
HashBuffer.size = (UINT16)HashLen;
CopyMem (HashBuffer.buffer, Buffer, (UINTN)HashLen);
Status = Tpm2SequenceComplete (
mTpm2HashMask[Idx].SequenceHandle,
&HashBuffer,
&Result
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
AlgoId = Tpm2GetAlgoFromHashMask (HashMask);
ASSERT (AlgoId != TPM_ALG_ERROR);
// Copy the result of hash.
CopyMem (&DigestList->digests[DigestIdx].digest, Result.buffer, Result.size);
DigestList->digests[DigestIdx].hashAlg = AlgoId;
DigestIdx++;
}
DigestList->count = DigestIdx;
Status = Tpm2PcrExtend (
PcrIndex,
DigestList
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
ClearSequenceHandles ();
return EFI_SUCCESS;
}
/**
Hash data and extend to PCR.
@param PcrIndex PCR to be extended.
@param DataToHash Data to be hashed.
@param DataToHashLen Data size.
@param DigestList Digest list.
@retval EFI_SUCCESS Hash data and DigestList is returned.
**/
EFI_STATUS
EFIAPI
HashAndExtend (
IN TPMI_DH_PCR PcrIndex,
IN VOID *DataToHash,
IN UINTN DataToHashLen,
OUT TPML_DIGEST_VALUES *DigestList
)
{
EFI_STATUS Status;
UINT8 *Buffer;
UINT64 HashLen;
TPMI_DH_OBJECT SequenceHandle;
TPM2B_MAX_BUFFER HashBuffer;
TPM2B_DIGEST Result;
TPM_ALG_ID AlgoId;
UINT32 Idx;
UINT32 DigestIdx;
UINT32 HashMask;
if (mHashLibDisabled) {
return EFI_UNSUPPORTED;
}
DEBUG ((DEBUG_VERBOSE, "\n HashAndExtend Entry \n"));
if (mSupportedHashBitmap == 0x00) {
return EFI_DEVICE_ERROR;
}
ZeroMem (DigestList, sizeof (*DigestList));
DigestList->count = HASH_COUNT;
DigestIdx = 0;
for (Idx = 0; Idx < ARRAY_SIZE (mTpm2HashMask); Idx++) {
HashMask = 1 << Idx;
if ((mSupportedHashBitmap & HashMask) == 0x00) {
continue;
}
SequenceHandle = BAD_SEQ_HANDLE; // Know bad value
AlgoId = Tpm2GetAlgoFromHashMask (HashMask);
ASSERT (AlgoId != TPM_ALG_ERROR);
Status = Tpm2HashSequenceStart (AlgoId, &SequenceHandle);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
DEBUG ((DEBUG_VERBOSE, "\n Tpm2HashSequenceStart Success \n"));
Buffer = (UINT8 *)(UINTN)DataToHash;
for (HashLen = DataToHashLen; HashLen > sizeof (HashBuffer.buffer); HashLen -= sizeof (HashBuffer.buffer)) {
HashBuffer.size = sizeof (HashBuffer.buffer);
CopyMem (HashBuffer.buffer, Buffer, sizeof (HashBuffer.buffer));
Buffer += sizeof (HashBuffer.buffer);
Status = Tpm2SequenceUpdate (SequenceHandle, &HashBuffer);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
}
DEBUG ((DEBUG_VERBOSE, "\n Tpm2SequenceUpdate Success \n"));
HashBuffer.size = (UINT16)HashLen;
CopyMem (HashBuffer.buffer, Buffer, (UINTN)HashLen);
Status = Tpm2SequenceComplete (
SequenceHandle,
&HashBuffer,
&Result
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
DEBUG ((DEBUG_VERBOSE, "\n Tpm2SequenceComplete Success \n"));
CopyMem (&DigestList->digests[DigestIdx].digest, Result.buffer, Result.size);
DigestList->digests[DigestIdx].hashAlg = AlgoId;
DigestIdx++;
}
DigestList->count = DigestIdx;
Status = Tpm2PcrExtend (
PcrIndex,
DigestList
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
DEBUG ((DEBUG_VERBOSE, "\n Tpm2PcrExtend Success \n"));
return EFI_SUCCESS;
}
/**
This service register Hash.
@param HashInterface Hash interface
@retval EFI_SUCCESS This hash interface is registered successfully.
@retval EFI_UNSUPPORTED System does not support register this interface.
@retval EFI_ALREADY_STARTED System already register this interface.
**/
EFI_STATUS
EFIAPI
RegisterHashInterfaceLib (
IN HASH_INTERFACE *HashInterface
)
{
return EFI_UNSUPPORTED;
}
/**
Constructor of HashLibTpm2PeilessSecLibConstructor.
**/
EFI_STATUS
EFIAPI
HasLibTpm2PeilessSecLibConstructor (
VOID
)
{
EFI_STATUS Status;
TRANSFER_LIST_HEADER *TransferList;
VOID *EventLog;
UINTN EventLogSize;
TCG_PCR_EVENT *TcgPcrEvent;
TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct;
TCG_EfiSpecIdEventAlgorithmSize *DigestSize;
UINTN Idx;
UINT32 NumberOfAlgorithms;
UINT32 TpmHashBitmap;
UINT32 PcrHashBitmap;
mHashLibDisabled = TRUE;
Status = GetTransferList (&TransferList);
if (EFI_ERROR (Status)) {
goto DisableHandler;
}
if (TransferListCheckHeader (TransferList) == TRANSFER_LIST_OPS_INVALID) {
DEBUG ((DEBUG_ERROR, "Invalid Transfer list..\n"));
goto DisableHandler;
}
Status = TransferListGetEventLog (TransferList, &EventLog, &EventLogSize, NULL);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: No data for Tpm event log...\n", __func__));
goto DisableHandler;
}
TcgPcrEvent = (TCG_PCR_EVENT *)EventLog;
TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)
(EventLog + OFFSET_OF (TCG_PCR_EVENT, Event));
CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms));
DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms));
for (Idx = 0; Idx < NumberOfAlgorithms; Idx++) {
mSupportedHashBitmap |= Tpm2GetHashMaskFromAlgo (DigestSize[Idx].algorithmId);
}
Status = Tpm2RequestUseTpm ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: TPM2 not detected!\n", __func__));
BuildGuidHob (&gTpmErrorHobGuid, 0);
goto DisableHandler;
}
Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashBitmap, &PcrHashBitmap);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Failed to get Tpm capability... Status: %r\n", __func__, Status));
goto DisableHandler;
}
mSupportedHashBitmap &= PcrHashBitmap;
if (mSupportedHashBitmap == 0x00) {
DEBUG ((DEBUG_ERROR, "%a: No supported Hash algorithm with event log Spec...!\n", __func__));
BuildGuidHob (&gTpmErrorHobGuid, 0);
goto DisableHandler;
}
mHashLibDisabled = FALSE;
DisableHandler:
return EFI_SUCCESS;
}