]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
Add the missed local variable initialization to remove the possible warning.
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
index 7bc3cc0ec037fb2665f4542cc9b75c38449f4802..a713d0d4ae1949e23622a3da29b8d6294c3083ff 100644 (file)
@@ -1,27 +1,45 @@
 /** @file\r
   Implement image verification services for secure boot service in UEFI2.3.1.\r
 \r
-Copyright (c) 2009 - 2011, Intel 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
+  Caution: This file requires additional review when modified.\r
+  This library will have external input - PE/COFF image.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content\r
+  read is within the image buffer.\r
+\r
+  DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept\r
+  untrusted PE/COFF image and validate its data structure within this image buffer before use.\r
+\r
+Copyright (c) 2009 - 2015, Intel 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
 http://opensource.org/licenses/bsd-license.php\r
 \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
 **/\r
 \r
 #include "DxeImageVerificationLib.h"\r
 \r
+//\r
+// Caution: This is used by a function which may receive untrusted input.\r
+// These global variables hold PE/COFF image data, and they should be validated before use.\r
+//\r
 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
+UINT32                              mPeCoffHeaderOffset;\r
+EFI_GUID                            mCertType;\r
+\r
+//\r
+// Information on current PE/COFF image\r
+//\r
 UINTN                               mImageSize;\r
-UINT32                              mPeCoffHeaderOffset; \r
+UINT8                               *mImageBase       = NULL;\r
 UINT8                               mImageDigest[MAX_DIGEST_SIZE];\r
 UINTN                               mImageDigestSize;\r
-EFI_IMAGE_DATA_DIRECTORY            *mSecDataDir      = NULL;\r
-UINT8                               *mImageBase       = NULL;\r
-EFI_GUID                            mCertType;\r
 \r
 //\r
 // Notify string for authorization UI.\r
@@ -38,7 +56,6 @@ CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
 // OID ASN.1 Value for Hash Algorithms\r
 //\r
 UINT8 mHashOidValue[] = {\r
-  0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,         // OBJ_md5\r
   0x2B, 0x0E, 0x03, 0x02, 0x1A,                           // OBJ_sha1\r
   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,   // OBJ_sha224\r
   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,   // OBJ_sha256\r
@@ -47,21 +64,88 @@ UINT8 mHashOidValue[] = {
   };\r
 \r
 HASH_TABLE mHash[] = {\r
-  { L"SHA1",   20, &mHashOidValue[8],  5, Sha1GetContextSize,  Sha1Init,   Sha1Update,    Sha1Final  },\r
-  { L"SHA224", 28, &mHashOidValue[13], 9, NULL,                NULL,       NULL,          NULL       },\r
-  { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize,Sha256Init, Sha256Update,  Sha256Final},\r
-  { L"SHA384", 48, &mHashOidValue[31], 9, NULL,                NULL,       NULL,          NULL       },\r
-  { L"SHA512", 64, &mHashOidValue[40], 9, NULL,                NULL,       NULL,          NULL       }\r
+  { L"SHA1",   20, &mHashOidValue[0],  5, Sha1GetContextSize,   Sha1Init,   Sha1Update,   Sha1Final  },\r
+  { L"SHA224", 28, &mHashOidValue[5],  9, NULL,                 NULL,       NULL,         NULL       },\r
+  { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},\r
+  { L"SHA384", 48, &mHashOidValue[23], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},\r
+  { L"SHA512", 64, &mHashOidValue[32], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}\r
 };\r
 \r
+/**\r
+  SecureBoot Hook for processing image verification.\r
+\r
+  @param[in] VariableName                 Name of Variable to be found.\r
+  @param[in] VendorGuid                   Variable vendor GUID.\r
+  @param[in] DataSize                     Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in] Data                         Data pointer.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SecureBootHook (\r
+  IN CHAR16                                 *VariableName,\r
+  IN EFI_GUID                               *VendorGuid,\r
+  IN UINTN                                  DataSize,\r
+  IN VOID                                   *Data\r
+  );\r
+\r
+/**\r
+  Reads contents of a PE/COFF image in memory buffer.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
+  read is within the image buffer.\r
+\r
+  @param  FileHandle      Pointer to the file handle to read the PE/COFF image.\r
+  @param  FileOffset      Offset into the PE/COFF image to begin the read operation.\r
+  @param  ReadSize        On input, the size in bytes of the requested read operation.\r
+                          On output, the number of bytes actually read.\r
+  @param  Buffer          Output buffer that contains the data read from the PE/COFF image.\r
+\r
+  @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeImageVerificationLibImageRead (\r
+  IN     VOID    *FileHandle,\r
+  IN     UINTN   FileOffset,\r
+  IN OUT UINTN   *ReadSize,\r
+  OUT    VOID    *Buffer\r
+  )\r
+{\r
+  UINTN               EndPosition;\r
+\r
+  if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  EndPosition = FileOffset + *ReadSize;\r
+  if (EndPosition > mImageSize) {\r
+    *ReadSize = (UINT32)(mImageSize - FileOffset);\r
+  }\r
+\r
+  if (FileOffset >= mImageSize) {\r
+    *ReadSize = 0;\r
+  }\r
+\r
+  CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 \r
 /**\r
   Get the image type.\r
 \r
   @param[in]    File       This is a pointer to the device path of the file that is\r
-                           being dispatched. \r
+                           being dispatched.\r
 \r
-  @return UINT32           Image Type             \r
+  @return UINT32           Image Type\r
 \r
 **/\r
 UINT32\r
@@ -70,15 +154,19 @@ GetImageType (
   )\r
 {\r
   EFI_STATUS                        Status;\r
-  EFI_HANDLE                        DeviceHandle; \r
+  EFI_HANDLE                        DeviceHandle;\r
   EFI_DEVICE_PATH_PROTOCOL          *TempDevicePath;\r
   EFI_BLOCK_IO_PROTOCOL             *BlockIo;\r
 \r
+  if (File == NULL) {\r
+    return IMAGE_UNKNOWN;\r
+  }\r
+\r
   //\r
   // First check to see if File is from a Firmware Volume\r
   //\r
   DeviceHandle      = NULL;\r
-  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
   Status = gBS->LocateDevicePath (\r
                   &gEfiFirmwareVolume2ProtocolGuid,\r
                   &TempDevicePath,\r
@@ -102,7 +190,7 @@ GetImageType (
   // Next check to see if File is from a Block I/O device\r
   //\r
   DeviceHandle   = NULL;\r
-  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
   Status = gBS->LocateDevicePath (\r
                   &gEfiBlockIoProtocolGuid,\r
                   &TempDevicePath,\r
@@ -136,11 +224,11 @@ GetImageType (
   }\r
 \r
   //\r
-  // File is not in a Firmware Volume or on a Block I/O device, so check to see if \r
+  // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r
   // the device path supports the Simple File System Protocol.\r
   //\r
   DeviceHandle   = NULL;\r
-  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
   Status = gBS->LocateDevicePath (\r
                   &gEfiSimpleFileSystemProtocolGuid,\r
                   &TempDevicePath,\r
@@ -155,12 +243,12 @@ GetImageType (
 \r
   //\r
   // File is not from an FV, Block I/O or Simple File System, so the only options\r
-  // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.  \r
+  // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r
   //\r
-  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
   while (!IsDevicePathEndType (TempDevicePath)) {\r
     switch (DevicePathType (TempDevicePath)) {\r
-    \r
+\r
     case MEDIA_DEVICE_PATH:\r
       if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
         return IMAGE_FROM_OPTION_ROM;\r
@@ -170,7 +258,7 @@ GetImageType (
     case MESSAGING_DEVICE_PATH:\r
       if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
         return IMAGE_FROM_REMOVABLE_MEDIA;\r
-      } \r
+      }\r
       break;\r
 \r
     default:\r
@@ -178,20 +266,24 @@ GetImageType (
     }\r
     TempDevicePath = NextDevicePathNode (TempDevicePath);\r
   }\r
-  return IMAGE_UNKNOWN; \r
+  return IMAGE_UNKNOWN;\r
 }\r
 \r
 /**\r
   Caculate hash of Pe/Coff image based on the authenticode image hashing in\r
   PE/COFF Specification 8.0 Appendix A\r
 \r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will validate its data structure\r
+  within this image buffer before use.\r
+\r
   @param[in]    HashAlg   Hash algorithm type.\r
\r
+\r
   @retval TRUE            Successfully hash image.\r
   @retval FALSE           Fail in hash image.\r
 \r
 **/\r
-BOOLEAN \r
+BOOLEAN\r
 HashPeImage (\r
   IN  UINT32              HashAlg\r
   )\r
@@ -207,34 +299,49 @@ HashPeImage (
   EFI_IMAGE_SECTION_HEADER  *SectionHeader;\r
   UINTN                     Index;\r
   UINTN                     Pos;\r
-  UINTN                     SumOfSectionBytes;\r
-  EFI_IMAGE_SECTION_HEADER  *SectionCache;  \r
-  \r
+  UINT32                    CertSize;\r
+  UINT32                    NumberOfRvaAndSizes;\r
+\r
   HashCtx       = NULL;\r
   SectionHeader = NULL;\r
   Status        = FALSE;\r
 \r
-  if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {\r
+  if ((HashAlg >= HASHALG_MAX)) {\r
     return FALSE;\r
   }\r
-  \r
+\r
   //\r
   // Initialize context of hash.\r
   //\r
   ZeroMem (mImageDigest, MAX_DIGEST_SIZE);\r
 \r
-  if (HashAlg == HASHALG_SHA1) {\r
-    mImageDigestSize  = SHA1_DIGEST_SIZE;\r
-    mCertType         = gEfiCertSha1Guid;\r
-  } else if (HashAlg == HASHALG_SHA256) {\r
-    mImageDigestSize  = SHA256_DIGEST_SIZE;\r
-    mCertType         = gEfiCertSha256Guid;\r
-  } else {\r
+  switch (HashAlg) {\r
+  case HASHALG_SHA1:\r
+    mImageDigestSize = SHA1_DIGEST_SIZE;\r
+    mCertType        = gEfiCertSha1Guid;\r
+    break;\r
+\r
+  case HASHALG_SHA256:\r
+    mImageDigestSize = SHA256_DIGEST_SIZE;\r
+    mCertType        = gEfiCertSha256Guid;\r
+    break;\r
+\r
+  case HASHALG_SHA384:\r
+    mImageDigestSize = SHA384_DIGEST_SIZE;\r
+    mCertType        = gEfiCertSha384Guid;\r
+    break;\r
+\r
+  case HASHALG_SHA512:\r
+    mImageDigestSize = SHA512_DIGEST_SIZE;\r
+    mCertType        = gEfiCertSha512Guid;\r
+    break;\r
+\r
+  default:\r
     return FALSE;\r
   }\r
 \r
   CtxSize   = mHash[HashAlg].GetContextSize();\r
-  \r
+\r
   HashCtx = AllocatePool (CtxSize);\r
   if (HashCtx == NULL) {\r
     return FALSE;\r
@@ -244,15 +351,30 @@ HashPeImage (
 \r
   // 2.  Initialize a SHA hash context.\r
   Status = mHash[HashAlg].HashInit(HashCtx);\r
-  \r
+\r
   if (!Status) {\r
     goto Done;\r
   }\r
+\r
   //\r
   // Measuring PE/COFF Image Header;\r
   // But CheckSum field and SECURITY data directory (certificate) are excluded\r
   //\r
-  Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+  if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
+    //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
+    //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+    //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+    //\r
+    Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+  } else {\r
+    //\r
+    // Get the magic value from the PE/COFF Optional Header\r
+    //\r
+    Magic =  mNtHeader.Pe32->OptionalHeader.Magic;\r
+  }\r
+\r
   //\r
   // 3.  Calculate the distance from the base of the image header to the image checksum address.\r
   // 4.  Hash the image header from its base to beginning of the image checksum.\r
@@ -263,11 +385,13 @@ HashPeImage (
     // Use PE32 offset.\r
     //\r
     HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);\r
+    NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
   } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
     //\r
     // Use PE32+ offset.\r
     //\r
     HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
+    NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
   } else {\r
     //\r
     // Invalid header magic number.\r
@@ -280,51 +404,86 @@ HashPeImage (
   if (!Status) {\r
     goto Done;\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
-    //\r
-    // Use PE32 offset.\r
+  if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
     //\r
-    HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
-    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
-  } else {\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
-    // Use PE32+ offset.\r
-    //    \r
-    HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
-    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
-  }\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+    }\r
 \r
-  Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
-  if (!Status) {\r
-    goto Done;\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
+    if (HashSize != 0) {\r
+      Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+      if (!Status) {\r
+        goto Done;\r
+      }\r
+    }\r
+  } else {\r
     //\r
-    // Use PE32 offset\r
+    // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
     //\r
-    HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
-    HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
-  } else {\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+      HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+    }\r
+\r
+    if (HashSize != 0) {\r
+      Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+      if (!Status) {\r
+        goto Done;\r
+      }\r
+    }\r
+\r
     //\r
-    // Use PE32+ offset.\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
-    HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
-    HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
-  }\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+      HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+      HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+    }\r
 \r
-  Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
-  if (!Status) {\r
-    goto Done;\r
+    if (HashSize != 0) {\r
+      Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+      if (!Status) {\r
+        goto Done;\r
+      }\r
+    }\r
   }\r
+\r
   //\r
   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
   //\r
@@ -349,20 +508,6 @@ HashPeImage (
                mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r
                );\r
 \r
-  SectionCache = Section;\r
-  for (Index = 0, SumOfSectionBytes = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++, SectionCache++) {\r
-    SumOfSectionBytes += SectionCache->SizeOfRawData;\r
-  }\r
-  \r
-  //\r
-  // Sanity check for file corruption. Sections raw data size should be smaller\r
-  // than Image Size.\r
-  //\r
-  if (SumOfSectionBytes >= mImageSize) {\r
-    Status = FALSE;\r
-    goto Done;\r
-  }\r
-\r
   //\r
   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
   //     structures in the image. The 'NumberOfSections' field of the image\r
@@ -421,29 +566,36 @@ HashPeImage (
   //\r
   if (mImageSize > SumOfBytesHashed) {\r
     HashBase = mImageBase + SumOfBytesHashed;\r
-    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
-      //\r
-      // Use PE32 offset.\r
-      //\r
-      HashSize = (UINTN)(\r
-                 mImageSize -\r
-                 mNtHeader.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
-      //\r
-      // Use PE32+ offset.\r
-      //\r
-      HashSize = (UINTN)(\r
-                 mImageSize -\r
-                 mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
-                 SumOfBytesHashed);      \r
+      if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+        //\r
+        // Use PE32 offset.\r
+        //\r
+        CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
+      } else {\r
+        //\r
+        // Use PE32+ offset.\r
+        //\r
+        CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
+      }\r
     }\r
 \r
-    Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
-    if (!Status) {\r
+    if (mImageSize > CertSize + SumOfBytesHashed) {\r
+      HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed);\r
+\r
+      Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+      if (!Status) {\r
+        goto Done;\r
+      }\r
+    } else if (mImageSize < CertSize + SumOfBytesHashed) {\r
+      Status = FALSE;\r
       goto Done;\r
     }\r
   }\r
+\r
   Status  = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
 \r
 Done:\r
@@ -457,28 +609,33 @@ Done:
 }\r
 \r
 /**\r
-  Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of \r
-  Pe/Coff image based on the authenticode image hashing in PE/COFF Specification \r
+  Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of\r
+  Pe/Coff image based on the authenticode image hashing in PE/COFF Specification\r
   8.0 Appendix A\r
 \r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will validate its data structure\r
+  within this image buffer before use.\r
+\r
+  @param[in]  AuthData            Pointer to the Authenticode Signature retrieved from signed image.\r
+  @param[in]  AuthDataSize        Size of the Authenticode Signature in bytes.\r
+\r
   @retval EFI_UNSUPPORTED             Hash algorithm is not supported.\r
   @retval EFI_SUCCESS                 Hash successfully.\r
 \r
 **/\r
-EFI_STATUS \r
+EFI_STATUS\r
 HashPeImageByType (\r
-  VOID\r
+  IN UINT8              *AuthData,\r
+  IN UINTN              AuthDataSize\r
   )\r
 {\r
   UINT8                     Index;\r
-  WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;\r
-\r
-  PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);\r
 \r
-  for (Index = 0; Index < HASHALG_MAX; Index++) {  \r
+  for (Index = 0; Index < HASHALG_MAX; Index++) {\r
     //\r
     // Check the Hash algorithm in PE/COFF Authenticode.\r
-    //    According to PKCS#7 Definition: \r
+    //    According to PKCS#7 Definition:\r
     //        SignedData ::= SEQUENCE {\r
     //            version Version,\r
     //            digestAlgorithms DigestAlgorithmIdentifiers,\r
@@ -486,8 +643,20 @@ HashPeImageByType (
     //            .... }\r
     //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r
     //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
-    //    \r
-    if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
+    //    Fixed offset (+32) is calculated based on two bytes of length encoding.\r
+    //\r
+    if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
+      //\r
+      // Only support two bytes of Long Form of Length Encoding.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    if (AuthDataSize < 32 + mHash[Index].OidLength) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
       break;\r
     }\r
   }\r
@@ -514,7 +683,7 @@ HashPeImageByType (
   ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.\r
 \r
   @param  ImageExeInfoTable          A pointer to a image execution info table structure.\r
-  \r
+\r
   @retval 0       If ImageExeInfoTable is NULL.\r
   @retval Others  The size of a image execution info table in bytes.\r
 \r
@@ -550,12 +719,12 @@ GetImageExeInfoTableSize (
   @param[in]  DevicePath      Input device path pointer.\r
   @param[in]  Signature       Input signature info in EFI_SIGNATURE_LIST data structure.\r
   @param[in]  SignatureSize   Size of signature.\r
-  \r
+\r
 **/\r
 VOID\r
 AddImageExeInfo (\r
-  IN       EFI_IMAGE_EXECUTION_ACTION       Action, \r
-  IN       CHAR16                           *Name OPTIONAL, \r
+  IN       EFI_IMAGE_EXECUTION_ACTION       Action,\r
+  IN       CHAR16                           *Name OPTIONAL,\r
   IN CONST EFI_DEVICE_PATH_PROTOCOL         *DevicePath,\r
   IN       EFI_SIGNATURE_LIST               *Signature OPTIONAL,\r
   IN       UINTN                            SignatureSize\r
@@ -577,17 +746,18 @@ AddImageExeInfo (
   if (DevicePath == NULL) {\r
     return ;\r
   }\r
-  \r
+\r
   if (Name != NULL) {\r
     NameStringLen = StrSize (Name);\r
+  } else {\r
+    NameStringLen = sizeof (CHAR16);\r
   }\r
 \r
-  ImageExeInfoTable = NULL;\r
-  EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID**)&ImageExeInfoTable);\r
+  EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
   if (ImageExeInfoTable != NULL) {\r
     //\r
     // The table has been found!\r
-    // We must enlarge the table to accmodate the new exe info entry.\r
+    // We must enlarge the table to accomodate the new exe info entry.\r
     //\r
     ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);\r
   } else {\r
@@ -599,7 +769,7 @@ AddImageExeInfo (
   }\r
 \r
   DevicePathSize            = GetDevicePathSize (DevicePath);\r
-  NewImageExeInfoEntrySize  = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;\r
+  NewImageExeInfoEntrySize  = sizeof (EFI_IMAGE_EXECUTION_INFO) - sizeof (EFI_SIGNATURE_LIST) + NameStringLen + DevicePathSize + SignatureSize;\r
   NewImageExeInfoTable      = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);\r
   if (NewImageExeInfoTable == NULL) {\r
     return ;\r
@@ -613,22 +783,24 @@ AddImageExeInfo (
   NewImageExeInfoTable->NumberOfImages++;\r
   ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);\r
   //\r
-  // Update new item's infomation.\r
+  // Update new item's information.\r
   //\r
-  WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->Action, Action);\r
-  WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->InfoSize, (UINT32) NewImageExeInfoEntrySize);\r
+  WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);\r
+  WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);\r
 \r
   if (Name != NULL) {\r
-    CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen);\r
+    CopyMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), Name, NameStringLen);\r
+  } else {\r
+    ZeroMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), sizeof (CHAR16));\r
   }\r
   CopyMem (\r
-    (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen,\r
+    (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen,\r
     DevicePath,\r
     DevicePathSize\r
     );\r
   if (Signature != NULL) {\r
     CopyMem (\r
-      (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize,\r
+      (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen + DevicePathSize,\r
       Signature,\r
       SignatureSize\r
       );\r
@@ -637,7 +809,7 @@ AddImageExeInfo (
   // Update/replace the image execution table.\r
   //\r
   gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);\r
-  \r
+\r
   //\r
   // Free Old table data!\r
   //\r
@@ -647,57 +819,132 @@ AddImageExeInfo (
 }\r
 \r
 /**\r
-  Discover if the UEFI image is authorized by user's policy setting.\r
+  Check whether the hash of an given X.509 certificate is in forbidden database (DBX).\r
 \r
-  @param[in]    Policy            Specify platform's policy setting. \r
+  @param[in]  Certificate       Pointer to X.509 Certificate that is searched for.\r
+  @param[in]  CertSize          Size of X.509 Certificate.\r
+  @param[in]  SignatureList     Pointer to the Signature List in forbidden database.\r
+  @param[in]  SignatureListSize Size of Signature List.\r
+  @param[out] RevocationTime    Return the time that the certificate was revoked.\r
 \r
-  @retval EFI_ACCESS_DENIED       Image is not allowed to run.\r
-  @retval EFI_SECURITY_VIOLATION  Image is deferred.\r
-  @retval EFI_SUCCESS             Image is authorized to run.\r
+  @return TRUE   The certificate hash is found in the forbidden database.\r
+  @return FALSE  The certificate hash is not found in the forbidden database.\r
 \r
 **/\r
-EFI_STATUS\r
-ImageAuthorization (\r
-  IN UINT32     Policy\r
+BOOLEAN\r
+IsCertHashFoundInDatabase (\r
+  IN  UINT8               *Certificate,\r
+  IN  UINTN               CertSize,\r
+  IN  EFI_SIGNATURE_LIST  *SignatureList,\r
+  IN  UINTN               SignatureListSize,\r
+  OUT EFI_TIME            *RevocationTime\r
   )\r
 {\r
-  EFI_STATUS    Status;\r
-  EFI_INPUT_KEY Key;\r
+  BOOLEAN             IsFound;\r
+  BOOLEAN             Status;\r
+  EFI_SIGNATURE_LIST  *DbxList;\r
+  UINTN               DbxSize;\r
+  EFI_SIGNATURE_DATA  *CertHash;\r
+  UINTN               CertHashCount;\r
+  UINTN               Index;\r
+  UINT32              HashAlg;\r
+  VOID                *HashCtx;\r
+  UINT8               CertDigest[MAX_DIGEST_SIZE];\r
+  UINT8               *DbxCertHash;\r
+  UINTN               SiglistHeaderSize;\r
+  UINT8               *TBSCert;\r
+  UINTN               TBSCertSize;\r
+\r
+  IsFound  = FALSE;\r
+  DbxList  = SignatureList;\r
+  DbxSize  = SignatureListSize;\r
+  HashCtx  = NULL;\r
+  HashAlg  = HASHALG_MAX;\r
+\r
+  if ((RevocationTime == NULL) || (DbxList == NULL)) {\r
+    return FALSE;\r
+  }\r
 \r
-  Status = EFI_ACCESS_DENIED;\r
+  //\r
+  // Retrieve the TBSCertificate from the X.509 Certificate.\r
+  //\r
+  if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {\r
+    return FALSE;\r
+  }\r
 \r
-  switch (Policy) {\r
-  \r
-  case QUERY_USER_ON_SECURITY_VIOLATION:\r
-    do {\r
-      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL);\r
-      if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {\r
-        Status = EFI_SUCCESS;\r
-        break;\r
-      } else if (Key.UnicodeChar == L'N' || Key.UnicodeChar == L'n') {\r
-        Status = EFI_ACCESS_DENIED;\r
-        break;\r
-      } else if (Key.UnicodeChar == L'D' || Key.UnicodeChar == L'd') {\r
-        Status = EFI_SECURITY_VIOLATION;\r
-        break;\r
-      }\r
-    } while (TRUE);\r
-    break;\r
+  while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) {\r
+    //\r
+    // Determine Hash Algorithm of Certificate in the forbidden database.\r
+    //\r
+    if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {\r
+      HashAlg = HASHALG_SHA256;\r
+    } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {\r
+      HashAlg = HASHALG_SHA384;\r
+    } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {\r
+      HashAlg = HASHALG_SHA512;\r
+    } else {\r
+      DbxSize -= DbxList->SignatureListSize;\r
+      DbxList  = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);\r
+      continue;\r
+    }\r
 \r
-  case ALLOW_EXECUTE_ON_SECURITY_VIOLATION:\r
-    Status = EFI_SUCCESS;\r
-    break;\r
+    //\r
+    // Calculate the hash value of current TBSCertificate for comparision.\r
+    //\r
+    if (mHash[HashAlg].GetContextSize == NULL) {\r
+      goto Done;\r
+    }\r
+    ZeroMem (CertDigest, MAX_DIGEST_SIZE);\r
+    HashCtx = AllocatePool (mHash[HashAlg].GetContextSize ());\r
+    if (HashCtx == NULL) {\r
+      goto Done;\r
+    }\r
+    Status = mHash[HashAlg].HashInit (HashCtx);\r
+    if (!Status) {\r
+      goto Done;\r
+    }\r
+    Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);\r
+    if (!Status) {\r
+      goto Done;\r
+    }\r
+    Status = mHash[HashAlg].HashFinal (HashCtx, CertDigest);\r
+    if (!Status) {\r
+      goto Done;\r
+    }\r
 \r
-  case DEFER_EXECUTE_ON_SECURITY_VIOLATION:\r
-    Status = EFI_SECURITY_VIOLATION;\r
-    break;\r
+    SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;\r
+    CertHash          = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);\r
+    CertHashCount     = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;\r
+    for (Index = 0; Index < CertHashCount; Index++) {\r
+      //\r
+      // Iterate each Signature Data Node within this CertList for verify.\r
+      //\r
+      DbxCertHash = CertHash->SignatureData;\r
+      if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {\r
+        //\r
+        // Hash of Certificate is found in forbidden database.\r
+        //\r
+        IsFound = TRUE;\r
+\r
+        //\r
+        // Return the revocation time.\r
+        //\r
+        CopyMem (RevocationTime, (EFI_TIME *)(DbxCertHash + mHash[HashAlg].DigestLength), sizeof (EFI_TIME));\r
+        goto Done;\r
+      }\r
+      CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);\r
+    }\r
 \r
-  case DENY_EXECUTE_ON_SECURITY_VIOLATION:\r
-    Status = EFI_ACCESS_DENIED;\r
-    break;\r
+    DbxSize -= DbxList->SignatureListSize;\r
+    DbxList  = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);\r
   }\r
 \r
-  return Status;\r
+Done:\r
+  if (HashCtx != NULL) {\r
+    FreePool (HashCtx);\r
+  }\r
+\r
+  return IsFound;\r
 }\r
 \r
 /**\r
@@ -715,7 +962,7 @@ ImageAuthorization (
 BOOLEAN\r
 IsSignatureFoundInDatabase (\r
   IN CHAR16             *VariableName,\r
-  IN UINT8              *Signature, \r
+  IN UINT8              *Signature,\r
   IN EFI_GUID           *CertType,\r
   IN UINTN              SignatureSize\r
   )\r
@@ -728,6 +975,7 @@ IsSignatureFoundInDatabase (
   UINTN               Index;\r
   UINTN               CertCount;\r
   BOOLEAN             IsFound;\r
+\r
   //\r
   // Read signature database variable.\r
   //\r
@@ -753,7 +1001,7 @@ IsSignatureFoundInDatabase (
   //\r
   CertList = (EFI_SIGNATURE_LIST *) Data;\r
   while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
-    CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+    CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
     Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
     if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {\r
       for (Index = 0; Index < CertCount; Index++) {\r
@@ -762,6 +1010,7 @@ IsSignatureFoundInDatabase (
           // Find the signature in database.\r
           //\r
           IsFound = TRUE;\r
+          SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
           break;\r
         }\r
 \r
@@ -786,327 +1035,508 @@ Done:
 }\r
 \r
 /**\r
-  Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format .\r
+  Check whether the timestamp is valid by comparing the signing time and the revocation time.\r
+\r
+  @param SigningTime         A pointer to the signing time.\r
+  @param RevocationTime      A pointer to the revocation time.\r
+\r
+  @retval  TRUE              The SigningTime is not later than the RevocationTime.\r
+  @retval  FALSE             The SigningTime is later than the RevocationTime.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidSignatureByTimestamp (\r
+  IN EFI_TIME               *SigningTime,\r
+  IN EFI_TIME               *RevocationTime\r
+  )\r
+{\r
+  if (SigningTime->Year != RevocationTime->Year) {\r
+    return (BOOLEAN) (SigningTime->Year < RevocationTime->Year);\r
+  } else if (SigningTime->Month != RevocationTime->Month) {\r
+    return (BOOLEAN) (SigningTime->Month < RevocationTime->Month);\r
+  } else if (SigningTime->Day != RevocationTime->Day) {\r
+    return (BOOLEAN) (SigningTime->Day < RevocationTime->Day);\r
+  } else if (SigningTime->Hour != RevocationTime->Hour) {\r
+    return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour);\r
+  } else if (SigningTime->Minute != RevocationTime->Minute) {\r
+    return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute);\r
+  }\r
+\r
+  return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second);\r
+}\r
+\r
+/**\r
+  Check if the given time value is zero.\r
+\r
+  @param[in]  Time      Pointer of a time value.\r
+\r
+  @retval     TRUE      The Time is Zero.\r
+  @retval     FALSE     The Time is not Zero.\r
+\r
+**/\r
+BOOLEAN\r
+IsTimeZero (\r
+  IN EFI_TIME               *Time\r
+  )\r
+{\r
+  if ((Time->Year == 0) && (Time->Month == 0) &&  (Time->Day == 0) &&\r
+      (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check whether the timestamp signature is valid and the signing time is also earlier than \r
+  the revocation time.\r
+\r
+  @param[in]  AuthData        Pointer to the Authenticode signature retrieved from signed image.\r
+  @param[in]  AuthDataSize    Size of the Authenticode signature in bytes.\r
+  @param[in]  RevocationTime  The time that the certificate was revoked.\r
 \r
-  @retval EFI_SUCCESS                 Image pass verification.\r
-  @retval EFI_SECURITY_VIOLATION      Image fail verification.\r
-  @retval EFI_OUT_OF_RESOURCE         Fail to allocate memory.\r
+  @retval TRUE      Timestamp signature is valid and signing time is no later than the \r
+                    revocation time.\r
+  @retval FALSE     Timestamp signature is not valid or the signing time is later than the\r
+                    revocation time.\r
 \r
 **/\r
-EFI_STATUS \r
-VerifyCertPkcsSignedData (\r
-  VOID\r
+BOOLEAN\r
+PassTimestampCheck (\r
+  IN UINT8                  *AuthData,\r
+  IN UINTN                  AuthDataSize,\r
+  IN EFI_TIME               *RevocationTime\r
   )\r
 {\r
   EFI_STATUS                Status;\r
   BOOLEAN                   VerifyStatus;\r
-  WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;\r
   EFI_SIGNATURE_LIST        *CertList;\r
   EFI_SIGNATURE_DATA        *Cert;\r
-  UINTN                     DataSize;\r
-  UINT8                     *KekData;\r
-  UINT8                     *DbData;\r
+  UINT8                     *DbtData;\r
+  UINTN                     DbtDataSize;\r
   UINT8                     *RootCert;\r
   UINTN                     RootCertSize;\r
   UINTN                     Index;\r
   UINTN                     CertCount;\r
+  EFI_TIME                  SigningTime;\r
 \r
-  KekData                = NULL;\r
-  DbData                 = NULL;\r
-  CertList               = NULL;\r
-  Cert                   = NULL;\r
-  RootCert               = NULL;\r
-  RootCertSize           = 0;\r
-  VerifyStatus           = FALSE;\r
-  PkcsCertData           = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);\r
+  //\r
+  // Variable Initialization\r
+  //\r
+  VerifyStatus      = FALSE;\r
+  DbtData           = NULL;\r
+  CertList          = NULL;\r
+  Cert              = NULL;\r
+  RootCert          = NULL;\r
+  RootCertSize      = 0;\r
 \r
   //\r
-  // 1: Find certificate from KEK database and try to verify authenticode struct.\r
+  // If RevocationTime is zero, the certificate shall be considered to always be revoked.\r
   //\r
-  DataSize = 0;\r
-  Status   = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);\r
-  if (Status == EFI_BUFFER_TOO_SMALL) {\r
-    KekData = (UINT8 *)AllocateZeroPool (DataSize);\r
-    if (KekData == NULL) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
+  if (IsTimeZero (RevocationTime)) {\r
+    return FALSE;\r
+  }\r
 \r
-    Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, (VOID *)KekData);\r
-    if (EFI_ERROR (Status)) {\r
-      goto Done;\r
-    }\r
-    \r
-    //\r
-    // Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data.\r
-    // \r
-    CertList = (EFI_SIGNATURE_LIST *) KekData;\r
-    while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
-      if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
-        Cert          = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
-        CertCount     = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
-        for (Index = 0; Index < CertCount; Index++) {\r
-          //\r
-          // Iterate each Signature Data Node within this CertList for a verify\r
-          //        \r
-          RootCert      = Cert->SignatureData;\r
-          RootCertSize  = CertList->SignatureSize;\r
-  \r
+  //\r
+  // RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards.\r
+  // Using the dbt to get the trusted TSA certificates.\r
+  //\r
+  DbtDataSize = 0;\r
+  Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, NULL);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    goto Done;\r
+  }\r
+  DbtData = (UINT8 *) AllocateZeroPool (DbtDataSize);\r
+  if (DbtData == NULL) {\r
+    goto Done;\r
+  }\r
+  Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, (VOID *) DbtData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  CertList = (EFI_SIGNATURE_LIST *) DbtData;\r
+  while ((DbtDataSize > 0) && (DbtDataSize >= CertList->SignatureListSize)) {\r
+    if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
+      Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+      CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+      for (Index = 0; Index < CertCount; Index++) {\r
+        //\r
+        // Iterate each Signature Data Node within this CertList for verify.\r
+        //\r
+        RootCert     = Cert->SignatureData;\r
+        RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
+        //\r
+        // Get the signing time if the timestamp signature is valid.\r
+        //\r
+        if (ImageTimestampVerify (AuthData, AuthDataSize, RootCert, RootCertSize, &SigningTime)) {\r
           //\r
-          // Call AuthenticodeVerify library to Verify Authenticode struct. \r
+          // The signer signature is valid only when the signing time is earlier than revocation time.\r
           //\r
-          VerifyStatus = AuthenticodeVerify (\r
-                           PkcsCertData->CertData,\r
-                           mSecDataDir->Size - sizeof(PkcsCertData->Hdr),\r
-                           RootCert,\r
-                           RootCertSize,\r
-                           mImageDigest,\r
-                           mImageDigestSize\r
-                           );\r
-  \r
-          if (VerifyStatus) {\r
+          if (IsValidSignatureByTimestamp (&SigningTime, RevocationTime)) {\r
+            VerifyStatus = TRUE;\r
             goto Done;\r
           }\r
-          Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
-        }        \r
+        }\r
+        Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+      }\r
+    }\r
+    DbtDataSize -= CertList->SignatureListSize;\r
+    CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+  }\r
+\r
+Done:\r
+  if (DbtData != NULL) {\r
+    FreePool (DbtData);\r
+  }\r
+\r
+  return VerifyStatus;\r
+}\r
+\r
+/**\r
+  Check whether the image signature is forbidden by the forbidden database (dbx).\r
+  The image is forbidden to load if any certificates for signing are revoked before signing time.\r
+\r
+  @param[in]  AuthData      Pointer to the Authenticode signature retrieved from the signed image.\r
+  @param[in]  AuthDataSize  Size of the Authenticode signature in bytes.\r
+\r
+  @retval TRUE              Image is forbidden by dbx.\r
+  @retval FALSE             Image is not forbidden by dbx.\r
+\r
+**/\r
+BOOLEAN\r
+IsForbiddenByDbx (\r
+  IN UINT8                  *AuthData,\r
+  IN UINTN                  AuthDataSize\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  BOOLEAN                   IsForbidden;\r
+  UINT8                     *Data;\r
+  UINTN                     DataSize;\r
+  EFI_SIGNATURE_LIST        *CertList;\r
+  UINTN                     CertListSize;\r
+  EFI_SIGNATURE_DATA        *CertData;\r
+  UINT8                     *RootCert;\r
+  UINTN                     RootCertSize;\r
+  UINTN                     CertCount;\r
+  UINTN                     Index;\r
+  UINT8                     *CertBuffer;\r
+  UINTN                     BufferLength;\r
+  UINT8                     *TrustedCert;\r
+  UINTN                     TrustedCertLength;\r
+  UINT8                     CertNumber;\r
+  UINT8                     *CertPtr;\r
+  UINT8                     *Cert;\r
+  UINTN                     CertSize;\r
+  EFI_TIME                  RevocationTime;\r
+\r
+  //\r
+  // Variable Initialization\r
+  //\r
+  IsForbidden       = FALSE;\r
+  Data              = NULL;\r
+  CertList          = NULL;\r
+  CertData          = NULL;\r
+  RootCert          = NULL;\r
+  RootCertSize      = 0;\r
+  Cert              = NULL;\r
+  CertBuffer        = NULL;\r
+  BufferLength      = 0;\r
+  TrustedCert       = NULL;\r
+  TrustedCertLength = 0;\r
+\r
+  //\r
+  // The image will not be forbidden if dbx can't be got.\r
+  //\r
+  DataSize = 0;\r
+  Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return IsForbidden;\r
+  }\r
+  Data = (UINT8 *) AllocateZeroPool (DataSize);\r
+  if (Data == NULL) {\r
+    return IsForbidden;\r
+  }\r
+\r
+  Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return IsForbidden;\r
+  }\r
+\r
+  //\r
+  // Verify image signature with RAW X509 certificates in DBX database.\r
+  // If passed, the image will be forbidden.\r
+  //\r
+  CertList     = (EFI_SIGNATURE_LIST *) Data;\r
+  CertListSize = DataSize;\r
+  while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) {\r
+    if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
+      CertData  = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+      CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+\r
+      for (Index = 0; Index < CertCount; Index++) {\r
+        //\r
+        // Iterate each Signature Data Node within this CertList for verify.\r
+        //\r
+        RootCert     = CertData->SignatureData;\r
+        RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
+\r
+        //\r
+        // Call AuthenticodeVerify library to Verify Authenticode struct.\r
+        //\r
+        IsForbidden = AuthenticodeVerify (\r
+                        AuthData,\r
+                        AuthDataSize,\r
+                        RootCert,\r
+                        RootCertSize,\r
+                        mImageDigest,\r
+                        mImageDigestSize\r
+                        );\r
+        if (IsForbidden) {\r
+          SecureBootHook (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+          goto Done;\r
+        }\r
+\r
+        CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);\r
       }\r
-      DataSize -= CertList->SignatureListSize;\r
-      CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
     }\r
+\r
+    CertListSize -= CertList->SignatureListSize;\r
+    CertList      = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
   }\r
 \r
-  \r
+  //\r
+  // Check X.509 Certificate Hash & Possible Timestamp.\r
+  //\r
+\r
+  //\r
+  // Retrieve the certificate stack from AuthData\r
+  // The output CertStack format will be:\r
+  //       UINT8  CertNumber;\r
+  //       UINT32 Cert1Length;\r
+  //       UINT8  Cert1[];\r
+  //       UINT32 Cert2Length;\r
+  //       UINT8  Cert2[];\r
+  //       ...\r
+  //       UINT32 CertnLength;\r
+  //       UINT8  Certn[];\r
+  //\r
+  Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);\r
+  if ((BufferLength == 0) || (CertBuffer == NULL)) {\r
+    IsForbidden = TRUE;\r
+    goto Done;\r
+  }\r
 \r
   //\r
-  // 2: Find certificate from DB database and try to verify authenticode struct.\r
+  // Check if any hash of certificates embedded in AuthData is in the forbidden database.\r
   //\r
+  CertNumber = (UINT8) (*CertBuffer);\r
+  CertPtr    = CertBuffer + 1;\r
+  for (Index = 0; Index < CertNumber; Index++) {\r
+    CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);\r
+    Cert     = (UINT8 *)CertPtr + sizeof (UINT32);\r
+\r
+    if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {\r
+      //\r
+      // Check the timestamp signature and signing time to determine if the image can be trusted.\r
+      //\r
+      IsForbidden = TRUE;\r
+      if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) {\r
+        IsForbidden = FALSE;\r
+      }\r
+      goto Done;\r
+    }\r
+\r
+    CertPtr = CertPtr + sizeof (UINT32) + CertSize;\r
+  }\r
+\r
+Done:\r
+  if (Data != NULL) {\r
+    FreePool (Data);\r
+  }\r
+\r
+  Pkcs7FreeSigners (CertBuffer);\r
+  Pkcs7FreeSigners (TrustedCert);\r
+\r
+  return IsForbidden;\r
+}\r
+\r
+/**\r
+  Check whether the image signature can be verified by the trusted certificates in DB database.\r
+\r
+  @param[in]  AuthData      Pointer to the Authenticode signature retrieved from signed image.\r
+  @param[in]  AuthDataSize  Size of the Authenticode signature in bytes.\r
+\r
+  @retval TRUE         Image passed verification using certificate in db.\r
+  @retval FALSE        Image didn't pass verification using certificate in db.\r
+\r
+**/\r
+BOOLEAN\r
+IsAllowedByDb (\r
+  IN UINT8              *AuthData,\r
+  IN UINTN              AuthDataSize\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  BOOLEAN                   VerifyStatus;\r
+  EFI_SIGNATURE_LIST        *CertList;\r
+  EFI_SIGNATURE_DATA        *Cert;\r
+  UINTN                     DataSize;\r
+  UINT8                     *Data;\r
+  UINT8                     *RootCert;\r
+  UINTN                     RootCertSize;\r
+  UINTN                     Index;\r
+  UINTN                     CertCount;\r
+  UINTN                     DbxDataSize;\r
+  UINT8                     *DbxData;\r
+  EFI_TIME                  RevocationTime;\r
+\r
+  Data         = NULL;\r
+  CertList     = NULL;\r
+  Cert         = NULL;\r
+  RootCert     = NULL;\r
+  DbxData      = NULL;\r
+  RootCertSize = 0;\r
+  VerifyStatus = FALSE;\r
+\r
   DataSize = 0;\r
   Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
   if (Status == EFI_BUFFER_TOO_SMALL) {\r
-    DbData = (UINT8 *)AllocateZeroPool (DataSize);\r
-    if (DbData == NULL) {\r
-      goto Done;\r
+    Data = (UINT8 *) AllocateZeroPool (DataSize);\r
+    if (Data == NULL) {\r
+      return VerifyStatus;\r
     }\r
 \r
-    Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)DbData);\r
+    Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);\r
     if (EFI_ERROR (Status)) {\r
       goto Done;\r
     }\r
 \r
     //\r
-    // Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data.\r
-    // \r
-    CertList = (EFI_SIGNATURE_LIST *) DbData;\r
+    // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.\r
+    //\r
+    CertList = (EFI_SIGNATURE_LIST *) Data;\r
     while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
       if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
-        Cert          = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
-        CertCount     = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+        Cert       = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+        CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+\r
         for (Index = 0; Index < CertCount; Index++) {\r
           //\r
-          // Iterate each Signature Data Node within this CertList for a verify\r
-          //        \r
-          RootCert      = Cert->SignatureData;\r
-          RootCertSize  = CertList->SignatureSize;\r
-  \r
+          // Iterate each Signature Data Node within this CertList for verify.\r
           //\r
-          // Call AuthenticodeVerify library to Verify Authenticode struct. \r
+          RootCert     = Cert->SignatureData;\r
+          RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
+\r
+          //\r
+          // Call AuthenticodeVerify library to Verify Authenticode struct.\r
           //\r
           VerifyStatus = AuthenticodeVerify (\r
-                           PkcsCertData->CertData,\r
-                           mSecDataDir->Size - sizeof(PkcsCertData->Hdr),\r
+                           AuthData,\r
+                           AuthDataSize,\r
                            RootCert,\r
                            RootCertSize,\r
                            mImageDigest,\r
                            mImageDigestSize\r
                            );\r
-  \r
           if (VerifyStatus) {\r
+            //\r
+            // Here We still need to check if this RootCert's Hash is revoked\r
+            //\r
+            Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL);\r
+            if (Status == EFI_BUFFER_TOO_SMALL) {\r
+              goto Done;\r
+            }\r
+            DbxData = (UINT8 *) AllocateZeroPool (DataSize);\r
+            if (DbxData == NULL) {\r
+              goto Done;\r
+            }\r
+\r
+            Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData);\r
+            if (EFI_ERROR (Status)) {\r
+              goto Done;\r
+            }\r
+\r
+            if (IsCertHashFoundInDatabase (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime)) {\r
+              //\r
+              // Check the timestamp signature and signing time to determine if the image can be trusted.\r
+              //\r
+              VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);\r
+            }\r
+\r
             goto Done;\r
           }\r
+\r
           Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
-        }        \r
+        }\r
       }\r
+\r
       DataSize -= CertList->SignatureListSize;\r
       CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
     }\r
   }\r
 \r
 Done:\r
-  if (KekData != NULL) {\r
-    FreePool (KekData);\r
-  }\r
-\r
-  if (DbData != NULL) {\r
-    FreePool (DbData);\r
-  }\r
-\r
   if (VerifyStatus) {\r
-    return EFI_SUCCESS;\r
-  } else {\r
-    return EFI_SECURITY_VIOLATION;\r
+    SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
   }\r
-}\r
 \r
-/**\r
-  Verify certificate in WIN_CERTIFICATE_UEFI_GUID format. \r
-\r
-  @retval EFI_SUCCESS                 Image pass verification.\r
-  @retval EFI_SECURITY_VIOLATION      Image fail verification.\r
-  @retval other error value\r
-\r
-**/\r
-EFI_STATUS \r
-VerifyCertUefiGuid (\r
-  VOID\r
-  )\r
-{\r
-  BOOLEAN                         Status;\r
-  WIN_CERTIFICATE_UEFI_GUID       *EfiCert;\r
-  EFI_SIGNATURE_LIST              *KekList;\r
-  EFI_SIGNATURE_DATA              *KekItem;\r
-  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
-  VOID                            *Rsa;\r
-  UINTN                           KekCount;\r
-  UINTN                           Index;\r
-  UINTN                           KekDataSize;\r
-  BOOLEAN                         IsFound;\r
-  EFI_STATUS                      Result;\r
-\r
-  EfiCert   = NULL;\r
-  KekList   = NULL;\r
-  KekItem   = NULL;\r
-  CertBlock = NULL;\r
-  Rsa       = NULL;\r
-  Status    = FALSE;\r
-  IsFound   = FALSE;\r
-  KekDataSize = 0;\r
-\r
-  EfiCert   = (WIN_CERTIFICATE_UEFI_GUID *) (mImageBase + mSecDataDir->VirtualAddress);\r
-  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) EfiCert->CertData;\r
-  if (!CompareGuid (&EfiCert->CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r
-    //\r
-    // Invalid Certificate Data Type.\r
-    //\r
-    return EFI_SECURITY_VIOLATION;\r
+  if (Data != NULL) {\r
+    FreePool (Data);\r
   }\r
-\r
-  //\r
-  // Get KEK database variable data size\r
-  //\r
-  Result = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &KekDataSize, NULL);\r
-  if (Result != EFI_BUFFER_TOO_SMALL) {\r
-    return EFI_SECURITY_VIOLATION;\r
+  if (DbxData != NULL) {\r
+    FreePool (DbxData);\r
   }\r
 \r
-  //\r
-  // Get KEK database variable.\r
-  //\r
-  KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME);\r
-  if (KekList == NULL) {\r
-    return EFI_SECURITY_VIOLATION;\r
-  }\r
-  \r
-  //\r
-  // Enumerate all Kek items in this list to verify the variable certificate data.\r
-  // If anyone is authenticated successfully, it means the variable is correct!\r
-  //\r
-  while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
-    if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
-      KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
-      KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
-      for (Index = 0; Index < KekCount; Index++) {\r
-        if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
-          IsFound = TRUE;\r
-          break;\r
-        }\r
-        KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
-      }\r
-    }\r
-    KekDataSize -= KekList->SignatureListSize;\r
-    KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
-  }\r
-  \r
-  if (!IsFound) {\r
-    //\r
-    // Signed key is not a trust one.\r
-    //\r
-    goto Done;\r
-  }\r
-\r
-  //\r
-  // Now, we found the corresponding security policy.\r
-  // Verify the data payload.\r
-  //\r
-  Rsa = RsaNew ();\r
-  if (Rsa == NULL) {\r
-    Status = FALSE;\r
-    goto Done;\r
-  }\r
-  \r
-  // \r
-  // Set RSA Key Components.\r
-  // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
-  //\r
-  Status = RsaSetKey (Rsa, RsaKeyN, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
-  if (!Status) {\r
-    goto Done;\r
-  }\r
-  Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
-  if (!Status) {\r
-    goto Done;\r
-  }\r
-  //\r
-  // Verify the signature.\r
-  //\r
-  Status = RsaPkcs1Verify (\r
-             Rsa, \r
-             mImageDigest, \r
-             mImageDigestSize, \r
-             CertBlock->Signature, \r
-             EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
-             );\r
\r
-Done:\r
-  if (KekList != NULL) {\r
-    FreePool (KekList);\r
-  }\r
-  if (Rsa != NULL ) {\r
-    RsaFree (Rsa);\r
-  }\r
-  if (Status) {\r
-    return EFI_SUCCESS;\r
-  } else {\r
-    return EFI_SECURITY_VIOLATION;\r
-  }\r
+  return VerifyStatus;\r
 }\r
 \r
 /**\r
   Provide verification service for signed images, which include both signature validation\r
-  and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and \r
+  and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and\r
   MSFT Authenticode type signatures are supported.\r
-  \r
-  In this implementation, only verify external executables when in USER MODE.\r
-  Executables from FV is bypass, so pass in AuthenticationStatus is ignored. \r
 \r
-  @param[in]    AuthenticationStatus \r
+  In this implementation, only verify external executables when in USER MODE.\r
+  Executables from FV is bypass, so pass in AuthenticationStatus is ignored.\r
+\r
+  The image verification policy is:\r
+    If the image is signed,\r
+      At least one valid signature or at least one hash value of the image must match a record\r
+      in the security database "db", and no valid signature nor any hash value of the image may\r
+      be reflected in the security database "dbx".\r
+    Otherwise, the image is not signed,\r
+      The SHA256 hash value of the image must match a record in the security database "db", and\r
+      not be reflected in the security data base "dbx".\r
+\r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will validate its data structure\r
+  within this image buffer before use.\r
+\r
+  @param[in]    AuthenticationStatus\r
                            This is the authentication status returned from the security\r
                            measurement services for the input file.\r
   @param[in]    File       This is a pointer to the device path of the file that is\r
                            being dispatched. This will optionally be used for logging.\r
   @param[in]    FileBuffer File buffer matches the input file device path.\r
   @param[in]    FileSize   Size of File buffer matches the input file device path.\r
-\r
-  @retval EFI_SUCCESS            The file specified by File did authenticate, and the\r
-                                 platform policy dictates that the DXE Core may use File.\r
-  @retval EFI_INVALID_PARAMETER  Input argument is incorrect.\r
+  @param[in]    BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
+\r
+  @retval EFI_SUCCESS            The file specified by DevicePath and non-NULL\r
+                                 FileBuffer did authenticate, and the platform policy dictates\r
+                                 that the DXE Foundation may use the file.\r
+  @retval EFI_SUCCESS            The device path specified by NULL device path DevicePath\r
+                                 and non-NULL FileBuffer did authenticate, and the platform\r
+                                 policy dictates that the DXE Foundation may execute the image in\r
+                                 FileBuffer.\r
   @retval EFI_OUT_RESOURCE       Fail to allocate memory.\r
   @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
                                  the platform policy dictates that File should be placed\r
-                                 in the untrusted state. A file may be promoted from\r
-                                 the untrusted to the trusted state at a future time\r
-                                 with a call to the Trust() DXE Service.\r
-  @retval EFI_ACCESS_DENIED      The file specified by File did not authenticate, and\r
-                                 the platform policy dictates that File should not be\r
-                                 used for any purpose.\r
+                                 in the untrusted state. The image has been added to the file\r
+                                 execution table.\r
+  @retval EFI_ACCESS_DENIED      The file specified by File and FileBuffer did not\r
+                                 authenticate, and the platform policy dictates that the DXE\r
+                                 Foundation many not use File.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1115,36 +1545,45 @@ DxeImageVerificationHandler (
   IN  UINT32                           AuthenticationStatus,\r
   IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,\r
   IN  VOID                             *FileBuffer,\r
-  IN  UINTN                            FileSize\r
+  IN  UINTN                            FileSize,\r
+  IN  BOOLEAN                          BootPolicy\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
-  UINT16                      Magic;\r
-  EFI_IMAGE_DOS_HEADER        *DosHdr;\r
-  EFI_STATUS                  VerifyStatus;\r
-  UINT8                       *SetupMode;\r
-  EFI_SIGNATURE_LIST          *SignatureList;\r
-  UINTN                       SignatureListSize;\r
-  EFI_SIGNATURE_DATA          *Signature;\r
-  EFI_IMAGE_EXECUTION_ACTION  Action;\r
-  WIN_CERTIFICATE             *WinCertificate;\r
-  UINT32                      Policy;\r
-  UINT8                       *SecureBootEnable;\r
-\r
-  if (File == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  EFI_STATUS                           Status;\r
+  UINT16                               Magic;\r
+  EFI_IMAGE_DOS_HEADER                 *DosHdr;\r
+  EFI_STATUS                           VerifyStatus;\r
+  EFI_SIGNATURE_LIST                   *SignatureList;\r
+  UINTN                                SignatureListSize;\r
+  EFI_SIGNATURE_DATA                   *Signature;\r
+  EFI_IMAGE_EXECUTION_ACTION           Action;\r
+  WIN_CERTIFICATE                      *WinCertificate;\r
+  UINT32                               Policy;\r
+  UINT8                                *SecureBoot;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;\r
+  UINT32                               NumberOfRvaAndSizes;\r
+  WIN_CERTIFICATE_EFI_PKCS             *PkcsCertData;\r
+  WIN_CERTIFICATE_UEFI_GUID            *WinCertUefiGuid;\r
+  UINT8                                *AuthData;\r
+  UINTN                                AuthDataSize;\r
+  EFI_IMAGE_DATA_DIRECTORY             *SecDataDir;\r
+  UINT32                               OffSet;\r
+  CHAR16                               *NameStr;\r
 \r
   SignatureList     = NULL;\r
   SignatureListSize = 0;\r
   WinCertificate    = NULL;\r
+  SecDataDir        = NULL;\r
+  PkcsCertData      = NULL;\r
   Action            = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
   Status            = EFI_ACCESS_DENIED;\r
+  VerifyStatus      = EFI_ACCESS_DENIED;\r
+\r
   //\r
   // Check the image type and get policy setting.\r
   //\r
   switch (GetImageType (File)) {\r
-  \r
+\r
   case IMAGE_FROM_FV:\r
     Policy = ALWAYS_EXECUTE;\r
     break;\r
@@ -1162,7 +1601,7 @@ DxeImageVerificationHandler (
     break;\r
 \r
   default:\r
-    Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION; \r
+    Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;\r
     break;\r
   }\r
   //\r
@@ -1174,52 +1613,63 @@ DxeImageVerificationHandler (
     return EFI_ACCESS_DENIED;\r
   }\r
 \r
-  SecureBootEnable = GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid);\r
   //\r
-  // Skip verification if SecureBootEnable variable doesn't exist.\r
+  // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION\r
+  // violates the UEFI spec and has been removed.\r
   //\r
-  if (SecureBootEnable == NULL) {\r
-    return EFI_SUCCESS;\r
+  ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);\r
+  if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {\r
+    CpuDeadLoop ();\r
   }\r
 \r
+  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
   //\r
-  // Skip verification if SecureBootEnable is disabled.\r
-  //\r
-  if (*SecureBootEnable == SECURE_BOOT_DISABLE) {\r
-    FreePool (SecureBootEnable);\r
-    return EFI_SUCCESS;\r
-  }    \r
\r
-  SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);\r
-\r
-  //\r
-  // SetupMode doesn't exist means no AuthVar driver is dispatched,\r
-  // skip verification.\r
+  // Skip verification if SecureBoot variable doesn't exist.\r
   //\r
-  if (SetupMode == NULL) {\r
+  if (SecureBoot == NULL) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
   //\r
-  // If platform is in SETUP MODE, skip verification.\r
+  // Skip verification if SecureBoot is disabled.\r
   //\r
-  if (*SetupMode == SETUP_MODE) {\r
-    FreePool (SetupMode);\r
+  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
+    FreePool (SecureBoot);\r
     return EFI_SUCCESS;\r
   }\r
+  FreePool (SecureBoot);\r
+\r
   //\r
   // Read the Dos header.\r
   //\r
   if (FileBuffer == NULL) {\r
-    FreePool (SetupMode);\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+\r
   mImageBase  = (UINT8 *) FileBuffer;\r
   mImageSize  = FileSize;\r
-  DosHdr      = (EFI_IMAGE_DOS_HEADER *) (mImageBase);\r
+\r
+  ZeroMem (&ImageContext, sizeof (ImageContext));\r
+  ImageContext.Handle    = (VOID *) FileBuffer;\r
+  ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;\r
+\r
+  //\r
+  // Get information about the image being loaded\r
+  //\r
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // The information can't be got from the invalid PeImage\r
+    //\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_ACCESS_DENIED;\r
+\r
+  DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;\r
   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
     //\r
-    // DOS image header is present, \r
+    // DOS image header is present,\r
     // so read the PE header after the DOS image header.\r
     //\r
     mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
@@ -1234,126 +1684,187 @@ DxeImageVerificationHandler (
     //\r
     // It is not a valid Pe/Coff file.\r
     //\r
-    return EFI_ACCESS_DENIED;\r
+    goto Done;\r
   }\r
 \r
-  Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
-  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
-    //\r
-    // Use PE32 offset.\r
-    //\r
-    mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
-  } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+  if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
     //\r
-    // Use PE32+ offset.\r
+    // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
+    //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
+    //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+    //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
     //\r
-    mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+    Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
   } else {\r
     //\r
-    // Invalid header magic number.\r
+    // Get the magic value from the PE/COFF Optional Header\r
     //\r
-    Status       = EFI_INVALID_PARAMETER;\r
-    goto Done;\r
+    Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
   }\r
 \r
-  if (mSecDataDir->VirtualAddress >= mImageSize) {\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
     //\r
-    // Sanity check to see if this file is corrupted.\r
+    // Use PE32 offset.\r
     //\r
-    Status       = EFI_INVALID_PARAMETER;\r
-    goto Done;\r
-  }\r
-\r
-  if (mSecDataDir->Size == 0) {\r
+    NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+      SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+    }\r
+  } else {\r
     //\r
-    // This image is not signed.\r
+    // Use PE32+ offset.\r
     //\r
-    Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
-    Status = EFI_ACCESS_DENIED;  \r
-    goto Done; \r
+    NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+      SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+    }\r
   }\r
+\r
   //\r
-  // Verify signature of executables.\r
+  // Start Image Validation.\r
   //\r
-  WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);\r
-\r
-  switch (WinCertificate->wCertificateType) {\r
-  \r
-  case WIN_CERT_TYPE_EFI_GUID:\r
+  if (SecDataDir == NULL || SecDataDir->Size == 0) {\r
+    //\r
+    // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",\r
+    // and not be reflected in the security data base "dbx".\r
     //\r
-    // Verify UEFI GUID type.\r
-    //   \r
     if (!HashPeImage (HASHALG_SHA256)) {\r
       goto Done;\r
     }\r
 \r
-    VerifyStatus = VerifyCertUefiGuid ();\r
-    break;\r
-\r
-  case WIN_CERT_TYPE_PKCS_SIGNED_DATA:\r
-    //\r
-    // Verify Pkcs signed data type.\r
-    //\r
-    Status    = HashPeImageByType();\r
-    if (EFI_ERROR(Status)) {\r
+    if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
+      //\r
+      // Image Hash is in forbidden database (DBX).\r
+      //\r
       goto Done;\r
     }\r
 \r
-    VerifyStatus = VerifyCertPkcsSignedData ();\r
-\r
-    //\r
-    // For image verification against enrolled certificate(root or intermediate),\r
-    // no need to check image's hash in the allowed database.\r
-    //\r
-    if (!EFI_ERROR (VerifyStatus)) {\r
+    if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
+      //\r
+      // Image Hash is in allowed database (DB).\r
+      //\r
       return EFI_SUCCESS;\r
     }\r
 \r
-  default:\r
-    return EFI_ACCESS_DENIED;\r
-  }\r
-  //\r
-  // Get image hash value as executable's signature.\r
-  //\r
-  SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
-  SignatureList     = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
-  if (SignatureList == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
+    //\r
+    // Image Hash is not found in both forbidden and allowed database.\r
+    //\r
     goto Done;\r
   }\r
-  SignatureList->SignatureHeaderSize  = 0;\r
-  SignatureList->SignatureListSize    = (UINT32) SignatureListSize;\r
-  SignatureList->SignatureSize        = (UINT32) mImageDigestSize;\r
-  CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
-  Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
-  CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
+\r
   //\r
-  // Signature database check after verification.\r
+  // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7\r
+  // "Attribute Certificate Table".\r
+  // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.\r
   //\r
-  if (EFI_ERROR (VerifyStatus)) {\r
+  for (OffSet = SecDataDir->VirtualAddress;\r
+       OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);\r
+       OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) {\r
+    WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);\r
+    if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||\r
+        (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {\r
+      break;\r
+    }\r
+\r
     //\r
-    // Verification failure.\r
+    // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.\r
     //\r
-    Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
-    Status = EFI_ACCESS_DENIED;\r
-  } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
+    if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
+      //\r
+      // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the\r
+      // Authenticode specification.\r
+      //\r
+      PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;\r
+      if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {\r
+        break;\r
+      }\r
+      AuthData   = PkcsCertData->CertData;\r
+      AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);\r
+    } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
+      //\r
+      // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.\r
+      //\r
+      WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;\r
+      if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
+        break;\r
+      }\r
+      if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {\r
+        continue;\r
+      }\r
+      AuthData = WinCertUefiGuid->CertData;\r
+      AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);\r
+    } else {\r
+      if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {\r
+        break;\r
+      }\r
+      continue;\r
+    }\r
+\r
+    Status = HashPeImageByType (AuthData, AuthDataSize);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
     //\r
-    // Executable signature verification passes, but is found in forbidden signature database.\r
+    // Check the digital signature against the revoked certificate in forbidden database (dbx).\r
     //\r
-    Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
-    Status = EFI_ACCESS_DENIED;\r
-  } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
+    if (IsForbiddenByDbx (AuthData, AuthDataSize)) {\r
+      Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
+      VerifyStatus = EFI_ACCESS_DENIED;\r
+      break;\r
+    }\r
+\r
     //\r
-    // Executable signature is found in authorized signature database.\r
+    // Check the digital signature against the valid certificate in allowed database (db).\r
     //\r
-    Status = EFI_SUCCESS;\r
-  } else {\r
+    if (EFI_ERROR (VerifyStatus)) {\r
+      if (IsAllowedByDb (AuthData, AuthDataSize)) {\r
+        VerifyStatus = EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Check the image's hash value.\r
+    //\r
+    if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
+      Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
+      VerifyStatus = EFI_ACCESS_DENIED;\r
+      break;\r
+    } else if (EFI_ERROR (VerifyStatus)) {\r
+      if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
+        VerifyStatus = EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {\r
     //\r
-    // Executable signature verification passes, but cannot be found in authorized signature database.\r
-    // Get platform policy to determine the action.\r
+    // The Size in Certificate Table or the attribute certicate table is corrupted.\r
     //\r
-    Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED;\r
-    Status = ImageAuthorization (Policy);\r
+    VerifyStatus = EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  if (!EFI_ERROR (VerifyStatus)) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_ACCESS_DENIED;\r
+    if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {\r
+      //\r
+      // Get image hash value as executable's signature.\r
+      //\r
+      SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
+      SignatureList     = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
+      if (SignatureList == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+      SignatureList->SignatureHeaderSize  = 0;\r
+      SignatureList->SignatureListSize    = (UINT32) SignatureListSize;\r
+      SignatureList->SignatureSize        = (UINT32) mImageDigestSize;\r
+      CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
+      Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
+      CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
+    }\r
   }\r
 \r
 Done:\r
@@ -1361,64 +1872,56 @@ Done:
     //\r
     // Policy decides to defer or reject the image; add its information in image executable information table.\r
     //\r
-    AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);\r
+    NameStr = ConvertDevicePathToText (File, FALSE, TRUE);\r
+    AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize);\r
+    if (NameStr != NULL) {\r
+      DEBUG((EFI_D_INFO, "The image doesn't pass verification: %s\n", NameStr));\r
+      FreePool(NameStr);\r
+    }\r
+    Status = EFI_SECURITY_VIOLATION;\r
   }\r
 \r
   if (SignatureList != NULL) {\r
     FreePool (SignatureList);\r
   }\r
 \r
-  FreePool (SetupMode);\r
-\r
   return Status;\r
 }\r
 \r
 /**\r
-  When VariableWriteArchProtocol install, create "SecureBoot" variable.\r
-  \r
-  @param[in] Event    Event whose notification function is being invoked.\r
-  @param[in] Context  Pointer to the notification function's context.\r
-  \r
+  On Ready To Boot Services Event notification handler.\r
+\r
+  Add the image execution information table if it is not in system configuration table.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
 **/\r
 VOID\r
 EFIAPI\r
-VariableWriteCallBack (\r
-  IN  EFI_EVENT                           Event,\r
-  IN  VOID                                *Context\r
+OnReadyToBoot (\r
+  IN      EFI_EVENT               Event,\r
+  IN      VOID                    *Context\r
   )\r
 {\r
-  UINT8                       SecureBootMode;\r
-  UINT8                       *SecureBootModePtr;\r
-  EFI_STATUS                  Status;\r
-  VOID                        *ProtocolPointer;\r
+  EFI_IMAGE_EXECUTION_INFO_TABLE  *ImageExeInfoTable;\r
+  UINTN                           ImageExeInfoTableSize;\r
 \r
-  Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, &ProtocolPointer);\r
-  if (EFI_ERROR (Status)) {\r
+  EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
+  if (ImageExeInfoTable != NULL) {\r
     return;\r
   }\r
-  \r
-  //\r
-  // Check whether "SecureBoot" variable exists.\r
-  // If this library is built-in, it means firmware has capability to perform\r
-  // driver signing verification.\r
-  //\r
-  SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME);\r
-  if (SecureBootModePtr == NULL) {\r
-    SecureBootMode   = SECURE_BOOT_MODE_DISABLE;\r
-    //\r
-    // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable.\r
-    //\r
-    gRT->SetVariable (\r
-           EFI_SECURE_BOOT_MODE_NAME,\r
-           &gEfiGlobalVariableGuid,\r
-           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
-           sizeof (UINT8),\r
-           &SecureBootMode\r
-           );\r
-  } else {\r
-    FreePool (SecureBootModePtr);\r
+\r
+  ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
+  ImageExeInfoTable     = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize);\r
+  if (ImageExeInfoTable == NULL) {\r
+    return ;\r
   }\r
-}  \r
+\r
+  ImageExeInfoTable->NumberOfImages = 0;\r
+  gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) ImageExeInfoTable);\r
+\r
+}\r
 \r
 /**\r
   Register security measurement handler.\r
@@ -1435,21 +1938,20 @@ DxeImageVerificationLibConstructor (
   IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
-  VOID                *Registration;\r
+  EFI_EVENT            Event;\r
 \r
   //\r
-  // Register callback function upon VariableWriteArchProtocol.\r
-  // \r
-  EfiCreateProtocolNotifyEvent (\r
-    &gEfiVariableWriteArchProtocolGuid,\r
+  // Register the event to publish the image execution table.\r
+  //\r
+  EfiCreateEventReadyToBootEx (\r
     TPL_CALLBACK,\r
-    VariableWriteCallBack,\r
+    OnReadyToBoot,\r
     NULL,\r
-    &Registration\r
+    &Event\r
     );\r
 \r
-  return RegisterSecurityHandler (\r
+  return RegisterSecurity2Handler (\r
           DxeImageVerificationHandler,\r
           EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
-          );      \r
+          );\r
 }\r