From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by mx.groups.io with SMTP id smtpd.web08.26035.1652686973757576480 for ; Mon, 16 May 2022 00:42:55 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=Ixe8iYzR; spf=pass (domain: intel.com, ip: 134.134.136.126, mailfrom: min.m.xu@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1652686974; x=1684222974; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oJxxfU9Rz5qFXRacUyIYl9OKa3LxR3UKSlIOOT2h+OM=; b=Ixe8iYzRIjVzTnRimsIiJI2qULNlTbYSa9l23JjJxgp3f/0qH+DPrpN8 1YRNhGaD69lvPma2D7SiB4EmNIiBgfKj/2xq8NiALpGA7HL1i31Daxshq RrOD3QXiiybjMCm5Qdn9cDhCx9qt770Blx4MVpXiJP/9gzCjxPWE/EqC6 koHvAB7xW3mkj+Xx7NNpnicCsth4UUczCG1l6WCSGy4GPCPwVQ1X0HqHy AD/cG+5wd8EqN9tRNTmtT1hsy8YTIi/mBeZF43gC2Q+TaR4bvlbhEByKH ypfUKUXa9M7Ypdvevi23o+Vy2u8RUQXW31RyQCAEKVLFkZyax57HbmodW w==; X-IronPort-AV: E=McAfee;i="6400,9594,10348"; a="252830429" X-IronPort-AV: E=Sophos;i="5.91,229,1647327600"; d="scan'208";a="252830429" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 May 2022 00:42:51 -0700 X-IronPort-AV: E=Sophos;i="5.91,229,1647327600"; d="scan'208";a="699418974" Received: from mxu9-mobl1.ccr.corp.intel.com ([10.249.170.79]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 May 2022 00:42:45 -0700 From: "Min Xu" To: devel@edk2.groups.io Cc: Min Xu , Brijesh Singh , Erdem Aktas , James Bottomley , Jiewen Yao , Tom Lendacky , Ken Lu , Sami Mujawar , Gerd Hoffmann Subject: [PATCH V4 4/9] OvmfPkg: Introduce SecMeasurementLib Date: Mon, 16 May 2022 15:42:18 +0800 Message-Id: <71ee1a1ede4e8ef742ab611323f2fa42e0468cd6.1652686674.git.min.m.xu@intel.com> X-Mailer: git-send-email 2.29.2.windows.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3853 SecMeasurementLib is designed to do the measurement in SEC phase. In current stage there are 2 functions introduced: - MeasureHobList: Measure the Hoblist passed from the VMM. - MeasureFvImage: Measure the FV image. SecMeasurementLibTdx is the TDX version of the library. Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Cc: Ken Lu Cc: Sami Mujawar Cc: Gerd Hoffmann Reviewed-by: Jiewen Yao Signed-off-by: Min Xu --- OvmfPkg/Include/Library/SecMeasurementLib.h | 46 +++ .../SecMeasurementLib/SecMeasurementLibTdx.c | 340 ++++++++++++++++++ .../SecMeasurementLibTdx.inf | 30 ++ OvmfPkg/OvmfPkg.dec | 4 + 4 files changed, 420 insertions(+) create mode 100644 OvmfPkg/Include/Library/SecMeasurementLib.h create mode 100644 OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.c create mode 100644 OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.inf diff --git a/OvmfPkg/Include/Library/SecMeasurementLib.h b/OvmfPkg/Include/Library/SecMeasurementLib.h new file mode 100644 index 000000000000..ca7a7dc3a9b2 --- /dev/null +++ b/OvmfPkg/Include/Library/SecMeasurementLib.h @@ -0,0 +1,46 @@ +/** @file + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SEC_MEASUREMENT_LIB_H_ +#define SEC_MEASUREMENT_LIB_H_ + +/** + Measure the Hoblist passed from the VMM. + + @param[in] VmmHobList The Hoblist pass the firmware + + @retval EFI_SUCCESS Fv image is measured successfully + or it has been already measured. + @retval Others Other errors as indicated +**/ +EFI_STATUS +EFIAPI +MeasureHobList ( + IN CONST VOID *VmmHobList + ); + +/** + Measure FV image. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + @param[in] PcrIndex Index of PCR + + @retval EFI_SUCCESS Fv image is measured successfully + or it has been already measured. + @retval Others Other errors as indicated +**/ +EFI_STATUS +EFIAPI +MeasureFvImage ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength, + IN UINT8 PcrIndex + ); + +#endif diff --git a/OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.c b/OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.c new file mode 100644 index 000000000000..274fda1e563e --- /dev/null +++ b/OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.c @@ -0,0 +1,340 @@ +/** @file +* +* Copyright (c) 2021, Intel Corporation. All rights reserved.
+* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma pack(1) + +typedef struct { + UINT32 count; + TPMI_ALG_HASH hashAlg; + BYTE sha384[SHA384_DIGEST_SIZE]; +} TDX_DIGEST_VALUE; + +#define HANDOFF_TABLE_DESC "TdxTable" +typedef struct { + UINT8 TableDescriptionSize; + UINT8 TableDescription[sizeof (HANDOFF_TABLE_DESC)]; + UINT64 NumberOfTables; + EFI_CONFIGURATION_TABLE TableEntry[1]; +} TDX_HANDOFF_TABLE_POINTERS2; + +#define FV_HANDOFF_TABLE_DESC "Fv(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)" +typedef struct { + UINT8 BlobDescriptionSize; + UINT8 BlobDescription[sizeof (FV_HANDOFF_TABLE_DESC)]; + EFI_PHYSICAL_ADDRESS BlobBase; + UINT64 BlobLength; +} FV_HANDOFF_TABLE_POINTERS2; + +#pragma pack() + +#define INVALID_PCR2MR_INDEX 0xFF + +/** + RTMR[0] => PCR[1,7] + RTMR[1] => PCR[2,3,4,5] + RTMR[2] => PCR[8~15] + RTMR[3] => NA + Note: + PCR[0] is mapped to MRTD and should not appear here. + PCR[6] is reserved for OEM. It is not used. +**/ +UINT8 +GetMappedRtmrIndex ( + UINT32 PCRIndex + ) +{ + UINT8 RtmrIndex; + + if ((PCRIndex == 6) || (PCRIndex == 0) || (PCRIndex > 15)) { + DEBUG ((DEBUG_ERROR, "Invalid PCRIndex(%d) map to MR Index.\n", PCRIndex)); + ASSERT (FALSE); + return INVALID_PCR2MR_INDEX; + } + + RtmrIndex = 0; + if ((PCRIndex == 1) || (PCRIndex == 7)) { + RtmrIndex = 0; + } else if ((PCRIndex >= 2) && (PCRIndex < 6)) { + RtmrIndex = 1; + } else if ((PCRIndex >= 8) && (PCRIndex <= 15)) { + RtmrIndex = 2; + } + + return RtmrIndex; +} + +/** + Tpm measure and log data, and extend the measurement result into a specific PCR. + + @param[in] PcrIndex PCR Index. + @param[in] EventType Event type. + @param[in] EventLog Measurement event log. + @param[in] LogLen Event log length in bytes. + @param[in] HashData The start of the data buffer to be hashed, extended. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED TPM device not available. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. +**/ +EFI_STATUS +EFIAPI +TdxMeasureAndLogData ( + IN UINT32 PcrIndex, + IN UINT32 EventType, + IN VOID *EventLog, + IN UINT32 LogLen, + IN VOID *HashData, + IN UINT64 HashDataLen + ) +{ + EFI_STATUS Status; + UINT32 RtmrIndex; + VOID *EventHobData; + TCG_PCR_EVENT2 *TcgPcrEvent2; + UINT8 *DigestBuffer; + TDX_DIGEST_VALUE *TdxDigest; + TPML_DIGEST_VALUES DigestList; + UINT8 *Ptr; + + RtmrIndex = GetMappedRtmrIndex (PcrIndex); + if (RtmrIndex == INVALID_PCR2MR_INDEX) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "Creating TdTcg2PcrEvent PCR[%d]/RTMR[%d] EventType 0x%x\n", PcrIndex, RtmrIndex, EventType)); + + Status = HashAndExtend ( + RtmrIndex, + (VOID *)HashData, + HashDataLen, + &DigestList + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Failed to HashAndExtend. %r\n", Status)); + return Status; + } + + // + // Use TDX_DIGEST_VALUE in the GUID HOB DataLength calculation + // to reserve enough buffer to hold TPML_DIGEST_VALUES compact binary + // which is limited to a SHA384 digest list + // + EventHobData = BuildGuidHob ( + &gCcEventEntryHobGuid, + sizeof (TcgPcrEvent2->PCRIndex) + sizeof (TcgPcrEvent2->EventType) + + sizeof (TDX_DIGEST_VALUE) + + sizeof (TcgPcrEvent2->EventSize) + LogLen + ); + + if (EventHobData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Ptr = (UINT8 *)EventHobData; + // + // Initialize PcrEvent data now + // + RtmrIndex++; + CopyMem (Ptr, &RtmrIndex, sizeof (UINT32)); + Ptr += sizeof (UINT32); + CopyMem (Ptr, &EventType, sizeof (TCG_EVENTTYPE)); + Ptr += sizeof (TCG_EVENTTYPE); + + DigestBuffer = Ptr; + + TdxDigest = (TDX_DIGEST_VALUE *)DigestBuffer; + TdxDigest->count = 1; + TdxDigest->hashAlg = TPM_ALG_SHA384; + CopyMem ( + TdxDigest->sha384, + DigestList.digests[0].digest.sha384, + SHA384_DIGEST_SIZE + ); + + Ptr += sizeof (TDX_DIGEST_VALUE); + + CopyMem (Ptr, &LogLen, sizeof (UINT32)); + Ptr += sizeof (UINT32); + CopyMem (Ptr, EventLog, LogLen); + Ptr += LogLen; + + Status = EFI_SUCCESS; + return Status; +} + +/** + Measure the Hoblist passed from the VMM. + + @param[in] VmmHobList The Hoblist pass the firmware + + @retval EFI_SUCCESS Fv image is measured successfully + or it has been already measured. + @retval Others Other errors as indicated +**/ +EFI_STATUS +EFIAPI +MeasureHobList ( + IN CONST VOID *VmmHobList + ) +{ + EFI_PEI_HOB_POINTERS Hob; + TDX_HANDOFF_TABLE_POINTERS2 HandoffTables; + EFI_STATUS Status; + + if (!TdIsEnabled ()) { + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + Hob.Raw = (UINT8 *)VmmHobList; + + // + // Parse the HOB list until end of list. + // + while (!END_OF_HOB_LIST (Hob)) { + Hob.Raw = GET_NEXT_HOB (Hob); + } + + // + // Init the log event for HOB measurement + // + + HandoffTables.TableDescriptionSize = sizeof (HandoffTables.TableDescription); + CopyMem (HandoffTables.TableDescription, HANDOFF_TABLE_DESC, sizeof (HandoffTables.TableDescription)); + HandoffTables.NumberOfTables = 1; + CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gUefiOvmfPkgTokenSpaceGuid); + HandoffTables.TableEntry[0].VendorTable = (VOID *)VmmHobList; + + Status = TdxMeasureAndLogData ( + 1, // PCRIndex + EV_EFI_HANDOFF_TABLES2, // EventType + (VOID *)&HandoffTables, // EventData + sizeof (HandoffTables), // EventSize + (UINT8 *)(UINTN)VmmHobList, // HashData + (UINTN)((UINT8 *)Hob.Raw - (UINT8 *)VmmHobList) // HashDataLen + ); + + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + } + + return Status; +} + +/** + Get the FvName from the FV header. + + Causion: The FV is untrusted input. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @return FvName pointer + @retval NULL FvName is NOT found +**/ +VOID * +GetFvName ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; + + if (FvBase >= MAX_ADDRESS) { + return NULL; + } + + if (FvLength >= MAX_ADDRESS - FvBase) { + return NULL; + } + + if (FvLength < sizeof (EFI_FIRMWARE_VOLUME_HEADER)) { + return NULL; + } + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase; + if (FvHeader->ExtHeaderOffset < sizeof (EFI_FIRMWARE_VOLUME_HEADER)) { + return NULL; + } + + if (FvHeader->ExtHeaderOffset + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER) > FvLength) { + return NULL; + } + + FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(UINTN)(FvBase + FvHeader->ExtHeaderOffset); + + return &FvExtHeader->FvName; +} + +/** + Measure FV image. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + @param[in] PcrIndex Index of PCR + + @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 +EFIAPI +MeasureFvImage ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength, + IN UINT8 PcrIndex + ) +{ + EFI_STATUS Status; + FV_HANDOFF_TABLE_POINTERS2 FvBlob2; + VOID *FvName; + + // + // Init the log event for FV measurement + // + FvBlob2.BlobDescriptionSize = sizeof (FvBlob2.BlobDescription); + CopyMem (FvBlob2.BlobDescription, FV_HANDOFF_TABLE_DESC, sizeof (FvBlob2.BlobDescription)); + FvName = GetFvName (FvBase, FvLength); + if (FvName != NULL) { + AsciiSPrint ((CHAR8 *)FvBlob2.BlobDescription, sizeof (FvBlob2.BlobDescription), "Fv(%g)", FvName); + } + + FvBlob2.BlobBase = FvBase; + FvBlob2.BlobLength = FvLength; + + Status = TdxMeasureAndLogData ( + 1, // PCRIndex + EV_EFI_PLATFORM_FIRMWARE_BLOB2, // EventType + (VOID *)&FvBlob2, // EventData + sizeof (FvBlob2), // EventSize + (UINT8 *)(UINTN)FvBase, // HashData + (UINTN)(FvLength) // HashDataLen + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase)); + ASSERT (FALSE); + } + + return Status; +} diff --git a/OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.inf b/OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.inf new file mode 100644 index 000000000000..6215df5af8fc --- /dev/null +++ b/OvmfPkg/Library/SecMeasurementLib/SecMeasurementLibTdx.inf @@ -0,0 +1,30 @@ +#/** @file +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecMeasurementLibTdx + FILE_GUID = 3e3fc69d-e834-40e9-96ed-e1e721f41883 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SecMeasurementLib + +[Sources] + SecMeasurementLibTdx.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[Guids] + gCcEventEntryHobGuid + gUefiOvmfPkgTokenSpaceGuid + +[LibraryClasses] + HashLib diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index 8c2048051bea..1dd86af55b91 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -125,6 +125,10 @@ # PeilessStartupLib|Include/Library/PeilessStartupLib.h + ## @libraryclass SecMeasurementLib + # + SecMeasurementLib|Include/Library/SecMeasurementLib.h + [Guids] gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}} gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}} -- 2.29.2.windows.2