/** @file This library uses TPM2 device to calculation hash. Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
(C) Copyright 2015 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include typedef struct { TPM_ALG_ID AlgoId; UINT32 Mask; } TPM2_HASH_MASK; TPM2_HASH_MASK mTpm2HashMask[] = { {TPM_ALG_SHA1, HASH_ALG_SHA1}, {TPM_ALG_SHA256, HASH_ALG_SHA256}, {TPM_ALG_SHA384, HASH_ALG_SHA384}, {TPM_ALG_SHA512, HASH_ALG_SHA512}, }; /** The function get algorithm from hash mask info. @return Hash algorithm **/ TPM_ALG_ID Tpm2GetAlgoFromHashMask ( VOID ) { UINT32 HashMask; UINTN Index; HashMask = PcdGet32 (PcdTpm2HashMask); for (Index = 0; Index < sizeof(mTpm2HashMask)/sizeof(mTpm2HashMask[0]); Index++) { if (mTpm2HashMask[Index].Mask == HashMask) { return mTpm2HashMask[Index].AlgoId; } } return TPM_ALG_NULL; } /** 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 ) { TPMI_DH_OBJECT SequenceHandle; EFI_STATUS Status; TPM_ALG_ID AlgoId; AlgoId = Tpm2GetAlgoFromHashMask (); Status = Tpm2HashSequenceStart (AlgoId, &SequenceHandle); if (!EFI_ERROR (Status)) { *HashHandle = (HASH_HANDLE)SequenceHandle; } 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 ) { UINT8 *Buffer; UINT64 HashLen; TPM2B_MAX_BUFFER HashBuffer; EFI_STATUS Status; 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((TPMI_DH_OBJECT)HashHandle, &HashBuffer); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } } // // Last one // HashBuffer.size = (UINT16)HashLen; CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen); Status = Tpm2SequenceUpdate((TPMI_DH_OBJECT)HashHandle, &HashBuffer); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** 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 ) { UINT8 *Buffer; UINT64 HashLen; TPM2B_MAX_BUFFER HashBuffer; EFI_STATUS Status; TPM_ALG_ID AlgoId; TPM2B_DIGEST Result; AlgoId = Tpm2GetAlgoFromHashMask (); 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((TPMI_DH_OBJECT)HashHandle, &HashBuffer); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } } // // Last one // HashBuffer.size = (UINT16)HashLen; CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen); ZeroMem(DigestList, sizeof(*DigestList)); DigestList->count = HASH_COUNT; if (AlgoId == TPM_ALG_NULL) { Status = Tpm2EventSequenceComplete ( PcrIndex, (TPMI_DH_OBJECT)HashHandle, &HashBuffer, DigestList ); } else { Status = Tpm2SequenceComplete ( (TPMI_DH_OBJECT)HashHandle, &HashBuffer, &Result ); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } DigestList->count = 1; DigestList->digests[0].hashAlg = AlgoId; CopyMem (&DigestList->digests[0].digest, Result.buffer, Result.size); Status = Tpm2PcrExtend ( PcrIndex, DigestList ); } if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } 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; TPM_ALG_ID AlgoId; TPM2B_EVENT EventData; TPM2B_DIGEST Result; DEBUG((EFI_D_VERBOSE, "\n HashAndExtend Entry \n")); SequenceHandle = 0xFFFFFFFF; // Know bad value AlgoId = Tpm2GetAlgoFromHashMask (); if ((AlgoId == TPM_ALG_NULL) && (DataToHashLen <= sizeof(EventData.buffer))) { EventData.size = (UINT16)DataToHashLen; CopyMem (EventData.buffer, DataToHash, DataToHashLen); Status = Tpm2PcrEvent (PcrIndex, &EventData, DigestList); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } Status = Tpm2HashSequenceStart(AlgoId, &SequenceHandle); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } DEBUG((EFI_D_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((EFI_D_VERBOSE, "\n Tpm2SequenceUpdate Success \n")); HashBuffer.size = (UINT16)HashLen; CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen); ZeroMem(DigestList, sizeof(*DigestList)); DigestList->count = HASH_COUNT; if (AlgoId == TPM_ALG_NULL) { Status = Tpm2EventSequenceComplete ( PcrIndex, SequenceHandle, &HashBuffer, DigestList ); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } DEBUG((EFI_D_VERBOSE, "\n Tpm2EventSequenceComplete Success \n")); } else { Status = Tpm2SequenceComplete ( SequenceHandle, &HashBuffer, &Result ); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } DEBUG((EFI_D_VERBOSE, "\n Tpm2SequenceComplete Success \n")); DigestList->count = 1; DigestList->digests[0].hashAlg = AlgoId; CopyMem (&DigestList->digests[0].digest, Result.buffer, Result.size); Status = Tpm2PcrExtend ( PcrIndex, DigestList ); if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } DEBUG((EFI_D_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; }