| /** @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; | |
| } |