]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
SecurityPkg\Tcg2Pei: FV measure performance enhancement
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Pei / Tcg2Pei.c
index 69adad43aa644e70c0877c5bb8a22e5b28e10f50..a7ae3354b5bca3a1d81e8786bf29768b73aeef84 100644 (file)
@@ -2,6 +2,7 @@
   Initialize TPM2 device and measure FVs before handing off control to DXE.\r
 \r
 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2017, Microsoft Corporation.  All rights reserved. <BR>\r
 This program and the accompanying materials \r
 are licensed and made available under the terms and conditions of the BSD License \r
 which accompanies this distribution.  The full text of the license may be found at \r
@@ -22,6 +23,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Ppi/FirmwareVolume.h>\r
 #include <Ppi/EndOfPeiPhase.h>\r
 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>\r
+#include <Ppi/FirmwareVolumeInfoPrehashedFV.h>\r
 \r
 #include <Guid/TcgEventHob.h>\r
 #include <Guid/MeasuredFvHob.h>\r
@@ -133,7 +135,6 @@ EFI_PEI_NOTIFY_DESCRIPTOR           mNotifyList[] = {
   }\r
 };\r
 \r
-EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;\r
 \r
 /**\r
   Record all measured Firmware Volum Information into a Guid Hob\r
@@ -215,6 +216,13 @@ SyncPcrAllocationsAndPcrMask (
   ASSERT_EFI_ERROR (Status);\r
 \r
   Tpm2PcrMask = PcdGet32 (PcdTpm2HashMask);\r
+  if (Tpm2PcrMask == 0) {\r
+    //\r
+    // if PcdTPm2HashMask is zero, use ActivePcr setting\r
+    //\r
+    PcdSet32S (PcdTpm2HashMask, TpmActivePcrBanks);\r
+    Tpm2PcrMask = TpmActivePcrBanks;\r
+  }\r
 \r
   //\r
   // Find the intersection of Pcd support and TPM support.\r
@@ -455,53 +463,152 @@ MeasureFvImage (
   IN UINT64                         FvLength\r
   )\r
 {\r
-  UINT32                            Index;\r
-  EFI_STATUS                        Status;\r
-  EFI_PLATFORM_FIRMWARE_BLOB        FvBlob;\r
-  TCG_PCR_EVENT_HDR                 TcgEventHdr;\r
-\r
-  //\r
-  // Check if it is in Excluded FV list\r
-  //\r
-  if (mMeasurementExcludedFvPpi != NULL) {\r
-    for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {\r
-      if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {\r
-        DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));\r
-        DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));\r
-        return EFI_SUCCESS;\r
+  UINT32                                                Index;\r
+  EFI_STATUS                                            Status;\r
+  EFI_PLATFORM_FIRMWARE_BLOB                            FvBlob;\r
+  TCG_PCR_EVENT_HDR                                     TcgEventHdr;\r
+  UINT32                                                Instance;\r
+  UINT32                                                Tpm2HashMask;\r
+  TPML_DIGEST_VALUES                                    DigestList;\r
+  UINT32                                                DigestCount;\r
+  EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *MeasurementExcludedFvPpi;\r
+  EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI       *PrehashedFvPpi;\r
+  HASH_INFO                                             *PreHashInfo;\r
+  UINT32                                                HashAlgoMask;\r
+\r
+  //\r
+  // Check Excluded FV list\r
+  //\r
+  Instance = 0;\r
+  do {\r
+    Status = PeiServicesLocatePpi(\r
+                 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,\r
+                 Instance,\r
+                 NULL,\r
+                 (VOID**)&MeasurementExcludedFvPpi\r
+                 );\r
+    if (!EFI_ERROR(Status)) {\r
+      for (Index = 0; Index < MeasurementExcludedFvPpi->Count; Index ++) {\r
+        if (MeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase\r
+         && MeasurementExcludedFvPpi->Fv[Index].FvLength == FvLength) {\r
+          DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));\r
+          DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));\r
+          return EFI_SUCCESS;\r
+        }\r
       }\r
+\r
+      Instance++;\r
     }\r
-  }\r
+  } while (!EFI_ERROR(Status));\r
 \r
   //\r
-  // Check whether FV is in the measured FV list.\r
+  // Check measured FV list\r
   //\r
   for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {\r
-    if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {\r
+    if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase && mMeasuredBaseFvInfo[Index].BlobLength == FvLength) {\r
+      DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei starts at: 0x%x\n", FvBase));\r
+      DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei has the size: 0x%x\n", FvLength));\r
       return EFI_SUCCESS;\r
     }\r
   }\r
-  \r
+\r
   //\r
-  // Measure and record the FV to the TPM\r
+  // Check pre-hashed FV list\r
   //\r
-  FvBlob.BlobBase   = FvBase;\r
-  FvBlob.BlobLength = FvLength;\r
+  Instance     = 0;\r
+  Tpm2HashMask = PcdGet32 (PcdTpm2HashMask);\r
+  do {\r
+    Status = PeiServicesLocatePpi (\r
+               &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid,\r
+               Instance,\r
+               NULL,\r
+               (VOID**)&PrehashedFvPpi\r
+               );\r
+    if (!EFI_ERROR(Status) && PrehashedFvPpi->FvBase == FvBase && PrehashedFvPpi->FvLength == FvLength) {\r
+      ZeroMem (&DigestList, sizeof(TPML_DIGEST_VALUES));\r
+\r
+      //\r
+      // The FV is prehashed, check against TPM hash mask\r
+      //\r
+      PreHashInfo = (HASH_INFO *)(PrehashedFvPpi + 1);\r
+      for (Index = 0, DigestCount = 0; Index < PrehashedFvPpi->Count; Index++) {\r
+        DEBUG((DEBUG_INFO, "Hash Algo ID in PrehashedFvPpi=0x%x\n", PreHashInfo->HashAlgoId));\r
+        HashAlgoMask = GetHashMaskFromAlgo(PreHashInfo->HashAlgoId);\r
+        if ((Tpm2HashMask & HashAlgoMask) != 0 ) {\r
+          //\r
+          // Hash is required, copy it to DigestList\r
+          //\r
+          WriteUnaligned16(&(DigestList.digests[DigestCount].hashAlg), PreHashInfo->HashAlgoId);\r
+          CopyMem (\r
+            &DigestList.digests[DigestCount].digest,\r
+            PreHashInfo + 1,\r
+            PreHashInfo->HashSize\r
+            );\r
+          DigestCount++;\r
+          //\r
+          // Clean the corresponding Hash Algo mask bit\r
+          //\r
+          Tpm2HashMask &= ~HashAlgoMask;\r
+        }\r
+        PreHashInfo = (HASH_INFO *)((UINT8 *)(PreHashInfo + 1) + PreHashInfo->HashSize);\r
+      }\r
+\r
+      WriteUnaligned32(&DigestList.count, DigestCount);\r
 \r
-  DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));\r
-  DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));\r
+      break;\r
+    }\r
+    Instance++;\r
+  } while (!EFI_ERROR(Status));\r
 \r
-  TcgEventHdr.PCRIndex = 0;\r
+  //\r
+  // Init the log event for FV measurement\r
+  //\r
+  FvBlob.BlobBase       = FvBase;\r
+  FvBlob.BlobLength     = FvLength;\r
+  TcgEventHdr.PCRIndex  = 0;\r
   TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;\r
   TcgEventHdr.EventSize = sizeof (FvBlob);\r
 \r
-  Status = HashLogExtendEvent (\r
-             0,\r
-             (UINT8*) (UINTN) FvBlob.BlobBase,\r
-             (UINTN) FvBlob.BlobLength,\r
-             &TcgEventHdr,\r
-             (UINT8*) &FvBlob\r
-             );\r
+  if (Tpm2HashMask == 0) {\r
+    //\r
+    // FV pre-hash algos comply with current TPM hash requirement\r
+    // Skip hashing step in measure, only extend DigestList to PCR and log event\r
+    //\r
+    Status = Tpm2PcrExtend(\r
+               0,\r
+               &DigestList\r
+               );\r
+\r
+    if (!EFI_ERROR(Status)) {\r
+       Status = LogHashEvent (&DigestList, &TcgEventHdr, (UINT8*) &FvBlob);\r
+       DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));\r
+       DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));\r
+    } else if (Status == EFI_DEVICE_ERROR) {\r
+      BuildGuidHob (&gTpmErrorHobGuid,0);\r
+      REPORT_STATUS_CODE (\r
+        EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+        (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
+        );\r
+    }\r
+  } else {\r
+    //\r
+    // Hash the FV, extend digest to the TPM and log TCG event\r
+    //\r
+    Status = HashLogExtendEvent (\r
+               0,\r
+               (UINT8*) (UINTN) FvBlob.BlobBase,\r
+               (UINTN) FvBlob.BlobLength,\r
+               &TcgEventHdr,\r
+               (UINT8*) &FvBlob\r
+               );\r
+    DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));\r
+    DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));\r
+  }\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase));\r
+    return Status;\r
+  }\r
 \r
   //\r
   // Add new FV into the measured FV list.\r
@@ -530,47 +637,44 @@ MeasureMainBios (
   )\r
 {\r
   EFI_STATUS                        Status;\r
-  UINT32                            FvInstances;\r
   EFI_PEI_FV_HANDLE                 VolumeHandle;\r
   EFI_FV_INFO                       VolumeInfo;\r
   EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;\r
 \r
   PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);\r
-  FvInstances    = 0;\r
-  while (TRUE) {\r
-    //\r
-    // Traverse all firmware volume instances of Static Core Root of Trust for Measurement\r
-    // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special\r
-    // platform for special CRTM TPM measuring.\r
-    //\r
-    Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);\r
-    if (EFI_ERROR (Status)) {\r
-      break;\r
-    }\r
-  \r
-    //\r
-    // Measure and record the firmware volume that is dispatched by PeiCore\r
-    //\r
-    Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
-    ASSERT_EFI_ERROR (Status);\r
-    //\r
-    // Locate the corresponding FV_PPI according to founded FV's format guid\r
-    //\r
-    Status = PeiServicesLocatePpi (\r
-               &VolumeInfo.FvFormat, \r
-               0, \r
-               NULL,\r
-               (VOID**)&FvPpi\r
-               );\r
-    if (!EFI_ERROR (Status)) {\r
-      MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);\r
-    }\r
 \r
-    FvInstances++;\r
-  }\r
+  //\r
+  // Only measure BFV at the very beginning. Other parts of Static Core Root of\r
+  // Trust for Measurement(S-CRTM) will be measured later on FvInfoNotify.\r
+  // BFV is processed without installing FV Info Ppi. Other FVs either inside BFV or\r
+  // reported by platform will be installed with Fv Info Ppi\r
+  // This firmware volume measure policy can be modified/enhanced by special\r
+  // platform for special CRTM TPM measuring.\r
+  //\r
+  Status = PeiServicesFfsFindNextVolume (0, &VolumeHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Measure and record the firmware volume that is dispatched by PeiCore\r
+  //\r
+  Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Locate the corresponding FV_PPI according to founded FV's format guid\r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &VolumeInfo.FvFormat,\r
+             0,\r
+             NULL,\r
+             (VOID**)&FvPpi\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);\r
+\r
   PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -655,14 +759,6 @@ PeimEntryMP (
 {\r
   EFI_STATUS                        Status;\r
 \r
-  Status = PeiServicesLocatePpi (\r
-               &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, \r
-               0, \r
-               NULL,\r
-               (VOID**)&mMeasurementExcludedFvPpi\r
-               );\r
-  // Do not check status, because it is optional\r
-\r
   mMeasuredBaseFvInfo  = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
   ASSERT (mMeasuredBaseFvInfo != NULL);\r
   mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
@@ -673,6 +769,9 @@ PeimEntryMP (
   }\r
 \r
   Status = MeasureMainBios ();\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
 \r
   //\r
   // Post callbacks:\r