From 1abfa4ce4835639c66ae82cc0d72cffcf3f28b6b Mon Sep 17 00:00:00 2001 From: "Yao, Jiewen" Date: Thu, 13 Aug 2015 08:24:17 +0000 Subject: Add TPM2 support defined in trusted computing group. TCG EFI Protocol Specification for TPM Family 2.0 Revision 1.0 Version 9 at http://www.trustedcomputinggroup.org/resources/tcg_efi_protocol_specification TCG Physical Presence Interface Specification Version 1.30, Revision 00.52 at http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification Add Tcg2XXX, similar file/directory as TrEEXXX. Old TrEE driver/library can be deprecated. 1) Add Tcg2Pei/Dxe/Smm driver to log event and provide services. 2) Add Dxe/Pei/SmmTcg2PhysicalPresenceLib to support TCG PP. 3) Update Tpm2 library to use TCG2 protocol instead of TrEE protocol. Test Win8/Win10 with SecureBoot enabled, PCR7 shows bound. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" Reviewed-by: "Zhang, Chao B" git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18219 6f19259b-4bc3-4df7-8a09-765794883524 --- SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c | 946 +++++++++++++++++++++++++++++++ SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf | 89 +++ SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni | Bin 0 -> 1876 bytes SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni | Bin 0 -> 1342 bytes 4 files changed, 1035 insertions(+) create mode 100644 SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c create mode 100644 SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf create mode 100644 SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni create mode 100644 SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni (limited to 'SecurityPkg/Tcg/Tcg2Pei') diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c new file mode 100644 index 0000000000..ec94c24e4c --- /dev/null +++ b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c @@ -0,0 +1,946 @@ +/** @file + Initialize TPM2 device and measure FVs before handing off control to DXE. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PERF_ID_TCG2_PEI 0x3080 + +typedef struct { + EFI_GUID *EventGuid; + EFI_TCG2_EVENT_LOG_FORMAT LogFormat; +} TCG2_EVENT_INFO_STRUCT; + +TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = { + {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2}, + {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2}, +}; + +BOOLEAN mImageInMemory = FALSE; +EFI_PEI_FILE_HANDLE mFileHandle; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializedPpiGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializationDonePpiGuid, + NULL +}; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo; +UINT32 mMeasuredBaseFvIndex = 0; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo; +UINT32 mMeasuredChildFvIndex = 0; + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Record all measured Firmware Volum Information into a Guid Hob + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +EndofPeiSignalNotifyCallBack ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfoPpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + }, + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfo2PpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + EndofPeiSignalNotifyCallBack + } +}; + +EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi; + +/** + This function get digest from digest list. + + @param HashAlg digest algorithm + @param DigestList digest list + @param Digest digest + + @retval EFI_SUCCESS Sha1Digest is found and returned. + @retval EFI_NOT_FOUND Sha1Digest is not found. +**/ +EFI_STATUS +Tpm2GetDigestFromDigestList ( + IN TPMI_ALG_HASH HashAlg, + IN TPML_DIGEST_VALUES *DigestList, + IN VOID *Digest + ) +{ + UINTN Index; + UINT16 DigestSize; + + DigestSize = GetHashSizeFromAlgo (HashAlg); + for (Index = 0; Index < DigestList->count; Index++) { + if (DigestList->digests[Index].hashAlg == HashAlg) { + CopyMem ( + Digest, + &DigestList->digests[Index].digest, + DigestSize + ); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Record all measured Firmware Volum Information into a Guid Hob + Guid Hob payload layout is + + UINT32 *************************** FIRMWARE_BLOB number + EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +EndofPeiSignalNotifyCallBack ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + MEASURED_HOB_DATA *MeasuredHobData; + + MeasuredHobData = NULL; + + // + // Create a Guid hob to save all measured Fv + // + MeasuredHobData = BuildGuidHob( + &gMeasuredFvHobGuid, + sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex) + ); + + if (MeasuredHobData != NULL){ + // + // Save measured FV info enty number + // + MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex; + + // + // Save measured base Fv info + // + CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex)); + + // + // Save measured child Fv info + // + CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex)); + } + + return EFI_SUCCESS; +} + +/** + Check if buffer is all zero. + + @param[in] Buffer Buffer to be checked. + @param[in] BufferSize Size of buffer to be checked. + + @retval TRUE Buffer is all zero. + @retval FALSE Buffer is not all zero. +**/ +BOOLEAN +IsZeroBuffer ( + IN VOID *Buffer, + IN UINTN BufferSize + ) +{ + UINT8 *BufferData; + UINTN Index; + + BufferData = Buffer; + for (Index = 0; Index < BufferSize; Index++) { + if (BufferData[Index] != 0) { + return FALSE; + } + } + return TRUE; +} + +/** + Get TPML_DIGEST_VALUES data size. + + @param[in] DigestList TPML_DIGEST_VALUES data. + + @return TPML_DIGEST_VALUES data size. +**/ +UINT32 +GetDigestListSize ( + IN TPML_DIGEST_VALUES *DigestList + ) +{ + UINTN Index; + UINT16 DigestSize; + UINT32 TotalSize; + + TotalSize = sizeof(DigestList->count); + for (Index = 0; Index < DigestList->count; Index++) { + DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg); + TotalSize += sizeof(DigestList->digests[Index].hashAlg) + DigestSize; + } + + return TotalSize; +} + +/** + Return if hash alg is supported in TPM PCR bank. + + @param HashAlg Hash algorithm to be checked. + + @retval TRUE Hash algorithm is supported. + @retval FALSE Hash algorithm is not supported. +**/ +BOOLEAN +IsHashAlgSupportedInPcrBank ( + IN TPMI_ALG_HASH HashAlg + ) +{ + UINT32 ActivePcrBanks; + + ActivePcrBanks = PcdGet32 (PcdTpm2HashMask); + switch (HashAlg) { + case TPM_ALG_SHA1: + if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) { + return TRUE; + } + break; + case TPM_ALG_SHA256: + if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) { + return TRUE; + } + break; + case TPM_ALG_SHA384: + if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) { + return TRUE; + } + break; + case TPM_ALG_SHA512: + if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) { + return TRUE; + } + break; + case TPM_ALG_SM3_256: + if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) { + return TRUE; + } + break; + } + + return FALSE; +} + +/** + Copy TPML_DIGEST_VALUES into a buffer + + @param[in,out] Buffer Buffer to hold TPML_DIGEST_VALUES. + @param[in] DigestList TPML_DIGEST_VALUES to be copied. + + @return The end of buffer to hold TPML_DIGEST_VALUES. +**/ +VOID * +CopyDigestListToBuffer ( + IN OUT VOID *Buffer, + IN TPML_DIGEST_VALUES *DigestList + ) +{ + UINTN Index; + UINT16 DigestSize; + + CopyMem (Buffer, &DigestList->count, sizeof(DigestList->count)); + Buffer = (UINT8 *)Buffer + sizeof(DigestList->count); + for (Index = 0; Index < DigestList->count; Index++) { + if (!IsHashAlgSupportedInPcrBank (DigestList->digests[Index].hashAlg)) { + DEBUG ((EFI_D_ERROR, "WARNING: TPM2 Event log has HashAlg unsupported by PCR bank (0x%x)\n", DigestList->digests[Index].hashAlg)); + continue; + } + CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof(DigestList->digests[Index].hashAlg)); + Buffer = (UINT8 *)Buffer + sizeof(DigestList->digests[Index].hashAlg); + DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg); + CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize); + Buffer = (UINT8 *)Buffer + DigestSize; + } + + return Buffer; +} + +/** + Set Tpm2HashMask PCD value accroding to TPM2 PCR bank. +**/ +VOID +SetTpm2HashMask ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 ActivePcrBanks; + TPML_PCR_SELECTION Pcrs; + UINTN Index; + + DEBUG ((EFI_D_ERROR, "SetTpm2HashMask!\n")); + + Status = Tpm2GetCapabilityPcrs (&Pcrs); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n")); + ActivePcrBanks = EFI_TCG2_BOOT_HASH_ALG_SHA1; + } else { + DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count)); + ActivePcrBanks = 0; + for (Index = 0; Index < Pcrs.count; Index++) { + DEBUG ((EFI_D_INFO, "hash - %x\n", Pcrs.pcrSelections[Index].hash)); + switch (Pcrs.pcrSelections[Index].hash) { + case TPM_ALG_SHA1: + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA1; + } + break; + case TPM_ALG_SHA256: + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA256; + } + break; + case TPM_ALG_SHA384: + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA384; + } + break; + case TPM_ALG_SHA512: + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA512; + } + break; + case TPM_ALG_SM3_256: + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SM3_256; + } + break; + } + } + } + PcdSet32 (PcdTpm2HashMask, ActivePcrBanks); +} + +/** + Add a new entry to the Event Log. + + @param[in] DigestList A list of digest. + @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. +**/ +EFI_STATUS +LogHashEvent ( + IN TPML_DIGEST_VALUES *DigestList, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + VOID *HobData; + EFI_STATUS Status; + UINTN Index; + EFI_STATUS RetStatus; + UINT32 SupportedEventLogs; + TCG_PCR_EVENT2 *TcgPcrEvent2; + UINT8 *DigestBuffer; + + SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; + + RetStatus = EFI_SUCCESS; + for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) { + if ((SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { + DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat)); + switch (mTcg2EventInfo[Index].LogFormat) { + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: + Status = Tpm2GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest); + if (!EFI_ERROR (Status)) { + HobData = BuildGuidHob ( + &gTcgEventEntryHobGuid, + sizeof (*NewEventHdr) + NewEventHdr->EventSize + ); + if (HobData == NULL) { + RetStatus = EFI_OUT_OF_RESOURCES; + break; + } + + CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr)); + HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr)); + CopyMem (HobData, NewEventData, NewEventHdr->EventSize); + } + break; + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: + HobData = BuildGuidHob ( + &gTcgEvent2EntryHobGuid, + sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize + ); + if (HobData == NULL) { + RetStatus = EFI_OUT_OF_RESOURCES; + break; + } + + TcgPcrEvent2 = HobData; + TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex; + TcgPcrEvent2->EventType = NewEventHdr->EventType; + DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest; + DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList); + CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize)); + DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize); + CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize); + break; + } + } + } + + return RetStatus; +} + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and build a GUIDed HOB recording the event which will be passed to the DXE phase and + added into the Event Log. + + @param[in] Flags Bitmap providing additional information. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +HashLogExtendEvent ( + IN UINT64 Flags, + IN UINT8 *HashData, + IN UINTN HashDataLen, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + TPML_DIGEST_VALUES DigestList; + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + return EFI_DEVICE_ERROR; + } + + Status = HashAndExtend ( + NewEventHdr->PCRIndex, + HashData, + HashDataLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { + Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData); + } + } + + if (Status == EFI_DEVICE_ERROR) { + DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status)); + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + + return Status; +} + +/** + Measure CRTM version. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureCRTMVersion ( + VOID + ) +{ + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Use FirmwareVersion string to represent CRTM version. + // OEMs should get real CRTM version string and measure it. + // + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_S_CRTM_VERSION; + TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString)); + + return HashLogExtendEvent ( + 0, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString), + TcgEventHdr.EventSize, + &TcgEventHdr, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString) + ); +} + +/** + Measure FV image. + Add it into the measured FV list after the FV is measured successfully. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @retval EFI_SUCCESS Fv image is measured successfully + or it has been already measured. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureFvImage ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + UINT32 Index; + EFI_STATUS Status; + EFI_PLATFORM_FIRMWARE_BLOB FvBlob; + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Check if it is in Excluded FV list + // + if (mMeasurementExcludedFvPpi != NULL) { + for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) { + if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) { + DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength)); + return EFI_SUCCESS; + } + } + } + + // + // Check whether FV is in the measured FV list. + // + for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) { + if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) { + return EFI_SUCCESS; + } + } + + // + // Measure and record the FV to the TPM + // + FvBlob.BlobBase = FvBase; + FvBlob.BlobLength = FvLength; + + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase)); + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength)); + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; + TcgEventHdr.EventSize = sizeof (FvBlob); + + Status = HashLogExtendEvent ( + 0, + (UINT8*) (UINTN) FvBlob.BlobBase, + (UINTN) FvBlob.BlobLength, + &TcgEventHdr, + (UINT8*) &FvBlob + ); + + // + // Add new FV into the measured FV list. + // + ASSERT (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) { + mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase; + mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength; + mMeasuredBaseFvIndex++; + } + + return Status; +} + +/** + Measure main BIOS. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureMainBios ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 FvInstances; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_FV_INFO VolumeInfo; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + + PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI); + FvInstances = 0; + while (TRUE) { + // + // Traverse all firmware volume instances of Static Core Root of Trust for Measurement + // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special + // platform for special CRTM TPM measuring. + // + Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle); + if (EFI_ERROR (Status)) { + break; + } + + // + // Measure and record the firmware volume that is dispatched by PeiCore + // + Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo); + ASSERT_EFI_ERROR (Status); + // + // Locate the corresponding FV_PPI according to founded FV's format guid + // + Status = PeiServicesLocatePpi ( + &VolumeInfo.FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (!EFI_ERROR (Status)) { + MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize); + } + + FvInstances++; + } + PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1); + + return EFI_SUCCESS; +} + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv; + EFI_STATUS Status; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + UINTN Index; + + Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi; + + // + // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi. + // + Status = PeiServicesLocatePpi ( + &Fv->FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + // + // This is an FV from an FFS file, and the parent FV must have already been measured, + // No need to measure twice, so just record the FV and return + // + if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) { + + ASSERT (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) { + // + // Check whether FV is in the measured child FV list. + // + for (Index = 0; Index < mMeasuredChildFvIndex; Index++) { + if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) { + return EFI_SUCCESS; + } + } + mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo; + mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize; + mMeasuredChildFvIndex++; + } + return EFI_SUCCESS; + } + + return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize); +} + +/** + Do measurement after memory is ready. + + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +PeimEntryMP ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = PeiServicesLocatePpi ( + &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, + 0, + NULL, + (VOID**)&mMeasurementExcludedFvPpi + ); + // Do not check status, because it is optional + + mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); + ASSERT (mMeasuredBaseFvInfo != NULL); + mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); + ASSERT (mMeasuredChildFvInfo != NULL); + + if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) { + Status = MeasureCRTMVersion (); + } + + Status = MeasureMainBios (); + + // + // Post callbacks: + // for the FvInfoPpi services to measure and record + // the additional Fvs to TPM + // + Status = PeiServicesNotifyPpi (&mNotifyList[0]); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Entry point of this module. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Describes the list of possible PEI Services. + + @return Status. + +**/ +EFI_STATUS +EFIAPI +PeimEntryMA ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_BOOT_MODE BootMode; + + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || + CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((EFI_D_ERROR, "No TPM2 instance required!\n")); + return EFI_UNSUPPORTED; + } + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + DEBUG ((EFI_D_ERROR, "TPM2 error!\n")); + return EFI_DEVICE_ERROR; + } + + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + // + // In S3 path, skip shadow logic. no measurement is required + // + if (BootMode != BOOT_ON_S3_RESUME) { + Status = (**PeiServices).RegisterForShadow(FileHandle); + if (Status == EFI_ALREADY_STARTED) { + mImageInMemory = TRUE; + mFileHandle = FileHandle; + } else if (Status == EFI_NOT_FOUND) { + ASSERT_EFI_ERROR (Status); + } + } + + if (!mImageInMemory) { + // + // Initialize TPM device + // + Status = Tpm2RequestUseTpm (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n")); + goto Done; + } + + if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) { + if (BootMode == BOOT_ON_S3_RESUME) { + Status = Tpm2Startup (TPM_SU_STATE); + if (EFI_ERROR (Status) ) { + Status = Tpm2Startup (TPM_SU_CLEAR); + } + } else { + Status = Tpm2Startup (TPM_SU_CLEAR); + } + if (EFI_ERROR (Status) ) { + goto Done; + } + } + + // + // Update Tpm2HashMask according to PCR bank. + // + SetTpm2HashMask (); + // + // TpmSelfTest is optional on S3 path, skip it to save S3 time + // + if (BootMode != BOOT_ON_S3_RESUME) { + if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) { + Status = Tpm2SelfTest (NO); + if (EFI_ERROR (Status)) { + goto Done; + } + } + } + + // + // Only intall TpmInitializedPpi on success + // + Status = PeiServicesInstallPpi (&mTpmInitializedPpiList); + ASSERT_EFI_ERROR (Status); + } + + if (mImageInMemory) { + Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices); + return Status; + } + +Done: + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n")); + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + // + // Always intall TpmInitializationDonePpi no matter success or fail. + // Other driver can know TPM initialization state by TpmInitializedPpi. + // + Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList); + ASSERT_EFI_ERROR (Status2); + + return Status; +} diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf new file mode 100644 index 0000000000..29ca3aa918 --- /dev/null +++ b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf @@ -0,0 +1,89 @@ +## @file +# Initializes TPM 2.0 device and measure FVs in PEI phase +# +# This module will initialize TPM device, measure reported FVs and BIOS version. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2Pei + MODULE_UNI_FILE = Tcg2Pei.uni + FILE_GUID = A0C98B77-CBA5-4BB8-993B-4AF6CE33ECE4 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimEntryMA + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# [BootMode] +# S3_RESUME ## SOMETIMES_CONSUMES +# + +[Sources] + Tcg2Pei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + HobLib + PeimEntryPoint + PeiServicesLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + PeiServicesTablePointerLib + Tpm2DeviceLib + HashLib + PerformanceLib + MemoryAllocationLib + ReportStatusCodeLib + Tcg2PhysicalPresenceLib + +[Guids] + gTcgEventEntryHobGuid ## PRODUCES ## HOB + gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB + gMeasuredFvHobGuid ## PRODUCES ## HOB + gTcgEvent2EntryHobGuid ## PRODUCES ## HOB + gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier + gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier + +[Ppis] + gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES + gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES + gPeiTpmInitializationDonePpiGuid ## PRODUCES + gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid AND + gEfiTpmDeviceSelectedGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2PeiExtra.uni diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni new file mode 100644 index 0000000000..5a226bcce4 Binary files /dev/null and b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni differ diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni b/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni new file mode 100644 index 0000000000..426fc77392 Binary files /dev/null and b/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni differ -- cgit v1.2.3