]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
Enhances PE image hash algorithm in DxeImageVerificationLib and DxeTpmMeasureBootLib.
[mirror_edk2.git] / SecurityPkg / Library / DxeTpmMeasureBootLib / DxeTpmMeasureBootLib.c
index 17c41e9bae4c17149d873c10f9627784878fdcc2..8179422e4467f1e24367ceaad98a9ccdfa04521a 100644 (file)
@@ -256,7 +256,9 @@ TcgMeasureGptTable (
 \r
   @retval EFI_SUCCESS            Successfully measure image.\r
   @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.\r
+  @retval EFI_UNSUPPORTED        ImageType is unsupported or PE image is mal-format.  \r
   @retval other error value\r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -269,27 +271,31 @@ TcgMeasurePeImage (
   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath\r
   )\r
 {\r
-  EFI_STATUS                        Status;\r
-  TCG_PCR_EVENT                     *TcgEvent;\r
-  EFI_IMAGE_LOAD_EVENT              *ImageLoad;\r
-  UINT32                            FilePathSize;\r
-  VOID                              *Sha1Ctx;\r
-  UINTN                             CtxSize;\r
-  EFI_IMAGE_DOS_HEADER              *DosHdr;\r
-  UINT32                            PeCoffHeaderOffset;\r
-  EFI_IMAGE_SECTION_HEADER          *Section;\r
-  UINT8                             *HashBase;\r
-  UINTN                             HashSize;\r
-  UINTN                             SumOfBytesHashed;\r
-  EFI_IMAGE_SECTION_HEADER          *SectionHeader;\r
-  UINTN                             Index, Pos;\r
-  UINT16                            Magic;\r
-  UINT32                            EventSize;\r
-  UINT32                            EventNumber;\r
-  EFI_PHYSICAL_ADDRESS              EventLogLastEntry;\r
+  EFI_STATUS                           Status;\r
+  TCG_PCR_EVENT                        *TcgEvent;\r
+  EFI_IMAGE_LOAD_EVENT                 *ImageLoad;\r
+  UINT32                               FilePathSize;\r
+  VOID                                 *Sha1Ctx;\r
+  UINTN                                CtxSize;\r
+  EFI_IMAGE_DOS_HEADER                 *DosHdr;\r
+  UINT32                               PeCoffHeaderOffset;\r
+  EFI_IMAGE_SECTION_HEADER             *Section;\r
+  UINT8                                *HashBase;\r
+  UINTN                                HashSize;\r
+  UINTN                                SumOfBytesHashed;\r
+  EFI_IMAGE_SECTION_HEADER             *SectionHeader;\r
+  UINTN                                Index;\r
+  UINTN                                Pos;\r
+  UINT16                               Magic;\r
+  UINT32                               EventSize;\r
+  UINT32                               EventNumber;\r
+  EFI_PHYSICAL_ADDRESS                 EventLogLastEntry;\r
   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;\r
+  UINT32                               NumberOfRvaAndSizes;\r
+  BOOLEAN                              HashStatus;\r
+  UINT32                               CertSize;\r
 \r
-  Status        = EFI_SUCCESS;\r
+  Status        = EFI_UNSUPPORTED;\r
   ImageLoad     = NULL;\r
   SectionHeader = NULL;\r
   Sha1Ctx       = NULL;\r
@@ -326,7 +332,6 @@ TcgMeasurePeImage (
         "TcgMeasurePeImage: Unknown subsystem type %d",\r
         ImageType\r
         ));\r
-      Status = EFI_UNSUPPORTED;\r
       goto Finish;\r
   }\r
 \r
@@ -344,8 +349,9 @@ TcgMeasurePeImage (
   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
     PeCoffHeaderOffset = DosHdr->e_lfanew;\r
   }\r
-  if (((EFI_TE_IMAGE_HEADER *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset))->Signature\r
-       == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
+\r
+  Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
+  if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
     goto Finish;\r
   }\r
 \r
@@ -367,14 +373,16 @@ TcgMeasurePeImage (
     goto Finish;\r
   }\r
 \r
-  Sha1Init (Sha1Ctx);\r
+  HashStatus = Sha1Init (Sha1Ctx);\r
+  if (!HashStatus) {\r
+    goto Finish;\r
+  }\r
 \r
   //\r
   // Measuring PE/COFF Image Header;\r
   // But CheckSum field and SECURITY data directory (certificate) are excluded\r
   //\r
-  Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
-  Magic    = Hdr.Pe32->OptionalHeader.Magic;\r
+  Magic = Hdr.Pe32->OptionalHeader.Magic;\r
   \r
   //\r
   // 3.  Calculate the distance from the base of the image header to the image checksum address.\r
@@ -385,58 +393,99 @@ TcgMeasurePeImage (
     //\r
     // Use PE32 offset\r
     //\r
+    NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);\r
   } else {\r
     //\r
     // Use PE32+ offset\r
     //\r
+    NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
     HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
   }\r
 \r
-  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+  HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+  if (!HashStatus) {\r
+    goto Finish;\r
+  }  \r
 \r
   //\r
   // 5.  Skip over the image checksum (it occupies a single ULONG).\r
-  // 6.  Get the address of the beginning of the Cert Directory.\r
-  // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
   //\r
-  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+  if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
     //\r
-    // Use PE32 offset\r
+    // 6.  Since there is no Cert Directory in optional header, hash everything\r
+    //     from the end of the checksum to the end of image header.\r
     //\r
-    HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
-    HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset.\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
+    }\r
+\r
+    if (HashSize != 0) {\r
+      HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+      if (!HashStatus) {\r
+        goto Finish;\r
+      }\r
+    }    \r
   } else {\r
     //\r
-    // Use PE32+ offset\r
-    //    \r
-    HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
-    HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
-  }\r
+    // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
+    //\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset\r
+      //    \r
+      HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    }\r
 \r
-  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+    if (HashSize != 0) {\r
+      HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+      if (!HashStatus) {\r
+        goto Finish;\r
+      }\r
+    }\r
 \r
-  //\r
-  // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
-  // 9.  Hash everything from the end of the Cert Directory to the end of image header.\r
-  //\r
-  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
     //\r
-    // Use PE32 offset\r
-    //\r
-    HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
-    HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders -\r
-             (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);\r
-  } else {\r
+    // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
+    // 9.  Hash everything from the end of the Cert Directory to the end of image header.\r
     //\r
-    // Use PE32+ offset\r
-    //\r
-    HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
-    HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders -\r
-             (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+      HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset\r
+      //\r
+      HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+      HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
+    }\r
+    \r
+    if (HashSize != 0) {\r
+      HashStatus  = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+      if (!HashStatus) {\r
+        goto Finish;\r
+      }\r
+    }\r
   }\r
-  \r
-  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
 \r
   //\r
   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header\r
@@ -459,7 +508,7 @@ TcgMeasurePeImage (
   //     header indicates how big the table should be. Do not include any\r
   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
   //\r
-  SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
+  SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
   if (SectionHeader == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto Finish;\r
@@ -503,7 +552,10 @@ TcgMeasurePeImage (
     HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;\r
     HashSize = (UINTN) Section->SizeOfRawData;\r
 \r
-    Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+    HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+    if (!HashStatus) {\r
+      goto Finish;\r
+    }\r
 \r
     SumOfBytesHashed += HashSize;\r
   }\r
@@ -516,37 +568,42 @@ TcgMeasurePeImage (
   //\r
   if (ImageSize > SumOfBytesHashed) {\r
     HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;\r
-    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
-      if (ImageSize - SumOfBytesHashed < Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
-        Status = EFI_INVALID_PARAMETER;\r
-        goto Finish;\r
-      }\r
-      //\r
-      // Use PE32 offset\r
-      //\r
-      HashSize = (UINTN)(ImageSize -\r
-                 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
-                 SumOfBytesHashed);\r
+\r
+    if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+      CertSize = 0;\r
     } else {\r
-      if (ImageSize - SumOfBytesHashed < Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
-        Status = EFI_INVALID_PARAMETER;\r
-        goto Finish;\r
+      if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+        //\r
+        // Use PE32 offset.\r
+        //\r
+        CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
+      } else {\r
+        //\r
+        // Use PE32+ offset.\r
+        //\r
+        CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
       }\r
-      //\r
-      // Use PE32+ offset\r
-      //\r
-      HashSize = (UINTN)(ImageSize -\r
-                 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
-                 SumOfBytesHashed);      \r
     }\r
 \r
-    Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+    if (ImageSize > CertSize + SumOfBytesHashed) {\r
+      HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);\r
+\r
+      HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+      if (!HashStatus) {\r
+        goto Finish;\r
+      }\r
+    } else if (ImageSize < CertSize + SumOfBytesHashed) {\r
+      goto Finish;\r
+    }\r
   }\r
 \r
   //\r
   // 17.  Finalize the SHA hash.\r
   //\r
-  Sha1Final (Sha1Ctx, (UINT8 *)&TcgEvent->Digest);\r
+  HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest);\r
+  if (!HashStatus) {\r
+    goto Finish;\r
+  }\r
 \r
   //\r
   // Log the PE data\r