]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
Enable TPM measurement lib to measure all PE image from a FV unmeasured by TcgPei
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
index ec18a1b523388f38c1a97617d8a69a7ad766fb79..9ea3a28ad91b93ede65c6eb159ad5b6b75c52b08 100644 (file)
@@ -1,6 +1,17 @@
 /** @file\r
   Implement image verification services for secure boot service in UEFI2.3.1.\r
 \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 - 2012, 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
@@ -14,14 +25,21 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \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
-UINTN                               mImageSize;\r
 UINT32                              mPeCoffHeaderOffset;\r
+EFI_GUID                            mCertType;\r
+\r
+//\r
+// Information on current PE/COFF image\r
+//\r
+UINTN                               mImageSize;\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
@@ -57,6 +75,10 @@ HASH_TABLE mHash[] = {
 /**\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
@@ -118,6 +140,10 @@ GetImageType (
   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
@@ -229,6 +255,10 @@ GetImageType (
   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
   @retval TRUE            Successfully hash image.\r
@@ -297,7 +327,21 @@ HashPeImage (
   // 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
@@ -536,23 +580,24 @@ Done:
   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
 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
-  if (PkcsCertData->Hdr.dwLength < sizeof (WIN_CERTIFICATE_EFI_PKCS) + 32) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
 \r
   for (Index = 0; Index < HASHALG_MAX; Index++) {\r
     //\r
@@ -567,18 +612,18 @@ HashPeImageByType (
     //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
     //    Fixed offset (+32) is calculated based on two bytes of length encoding.\r
     //\r
-    if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\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 (PkcsCertData->Hdr.dwLength < sizeof (WIN_CERTIFICATE_EFI_PKCS) + 32 + mHash[Index].OidLength) {\r
+    if (AuthDataSize < 32 + mHash[Index].OidLength) {\r
       return EFI_UNSUPPORTED;\r
     }\r
 \r
-    if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
+    if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
       break;\r
     }\r
   }\r
@@ -737,60 +782,6 @@ AddImageExeInfo (
   }\r
 }\r
 \r
-/**\r
-  Discover if the UEFI image is authorized by user's policy setting.\r
-\r
-  @param[in]    Policy            Specify platform's policy setting.\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
-\r
-**/\r
-EFI_STATUS\r
-ImageAuthorization (\r
-  IN UINT32     Policy\r
-  )\r
-{\r
-  EFI_STATUS    Status;\r
-  EFI_INPUT_KEY Key;\r
-\r
-  Status = EFI_ACCESS_DENIED;\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
-\r
-  case ALLOW_EXECUTE_ON_SECURITY_VIOLATION:\r
-    Status = EFI_SUCCESS;\r
-    break;\r
-\r
-  case DEFER_EXECUTE_ON_SECURITY_VIOLATION:\r
-    Status = EFI_SECURITY_VIOLATION;\r
-    break;\r
-\r
-  case DENY_EXECUTE_ON_SECURITY_VIOLATION:\r
-    Status = EFI_ACCESS_DENIED;\r
-    break;\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
 /**\r
   Check whether signature is in specified database.\r
 \r
@@ -880,8 +871,10 @@ Done:
   Verify PKCS#7 SignedData using certificate found in Variable which formatted\r
   as EFI_SIGNATURE_LIST. The Variable may be PK, KEK, DB or DBX.\r
 \r
-  @param VariableName  Name of Variable to search for Certificate.\r
-  @param VendorGuid    Variable vendor GUID.\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]  VariableName  Name of Variable to search for Certificate.\r
+  @param[in]  VendorGuid    Variable vendor GUID.\r
 \r
   @retval TRUE         Image pass verification.\r
   @retval FALSE        Image fail verification.\r
@@ -889,13 +882,14 @@ Done:
 **/\r
 BOOLEAN\r
 IsPkcsSignedDataVerifiedBySignatureList (\r
+  IN UINT8              *AuthData,\r
+  IN UINTN              AuthDataSize,\r
   IN CHAR16             *VariableName,\r
   IN EFI_GUID           *VendorGuid\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
@@ -911,7 +905,6 @@ IsPkcsSignedDataVerifiedBySignatureList (
   RootCert     = NULL;\r
   RootCertSize = 0;\r
   VerifyStatus = FALSE;\r
-  PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);\r
 \r
   DataSize = 0;\r
   Status   = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);\r
@@ -939,14 +932,14 @@ IsPkcsSignedDataVerifiedBySignatureList (
           // Iterate each Signature Data Node within this CertList for verify.\r
           //\r
           RootCert      = Cert->SignatureData;\r
-          RootCertSize  = CertList->SignatureSize;\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
-                           PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr),\r
+                           AuthData,\r
+                           AuthDataSize,\r
                            RootCert,\r
                            RootCertSize,\r
                            mImageDigest,\r
@@ -974,19 +967,23 @@ Done:
 /**\r
   Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format.\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_SUCCESS                 Image pass verification.\r
   @retval EFI_SECURITY_VIOLATION      Image fail verification.\r
 \r
 **/\r
 EFI_STATUS\r
 VerifyCertPkcsSignedData (\r
-  VOID\r
+  IN UINT8              *AuthData,\r
+  IN UINTN              AuthDataSize\r
   )\r
 {\r
   //\r
   // 1: Find certificate from DBX forbidden database for revoked certificate.\r
   //\r
-  if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {\r
+  if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {\r
     //\r
     // DBX is forbidden database, if Authenticode verification pass with\r
     // one of the certificate in DBX, this image should be rejected.\r
@@ -995,149 +992,9 @@ VerifyCertPkcsSignedData (
   }\r
 \r
   //\r
-  // 2: Find certificate from KEK database and try to verify authenticode struct.\r
-  //\r
-  if (IsPkcsSignedDataVerifiedBySignatureList (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid)) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  //\r
-  // 3: Find certificate from DB database and try to verify authenticode struct.\r
-  //\r
-  if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {\r
-    return EFI_SUCCESS;\r
-  } else {\r
-    return EFI_SECURITY_VIOLATION;\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
-  }\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
-  }\r
-\r
-  //\r
-  // Get KEK database variable.\r
-  //\r
-  GetEfiGlobalVariable2 (EFI_KEY_EXCHANGE_KEY_NAME, &KekList, NULL);\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
+  // 2: Find certificate from DB database and try to verify authenticode struct.\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
+  if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {\r
     return EFI_SUCCESS;\r
   } else {\r
     return EFI_SECURITY_VIOLATION;\r
@@ -1153,22 +1010,28 @@ Done:
   Executables from FV is bypass, so pass in AuthenticationStatus is ignored.\r
 \r
   The image verification process is:\r
-    Is the Image signed?\r
-      If yes,\r
-        Does the image verify against a certificate (root or intermediate) in the allowed db?\r
-          Run it\r
-        Image verification fail\r
-          Is the Image's Hash not in forbidden database and the Image's Hash in allowed db?\r
-            Run it\r
-      If no,\r
-        Is the Image's Hash in the forbidden database (DBX)?\r
-          if yes,\r
-            Error out\r
-        Is the Image's Hash in the allowed database (DB)?\r
-          If yes,\r
-            Run it\r
-          If no,\r
-            Error out\r
+    If the image is signed,\r
+      If the image's certificate verifies against a certificate (root or intermediate) in the allowed \r
+      database (DB) and not in the forbidden database (DBX), the certificate verification is passed.\r
+        If the image's hash digest is in DBX,\r
+          deny execution.\r
+        If not,\r
+          run it.\r
+      If the Image's certificate verification failed.\r
+        If the Image's Hash is in DB and not in DBX,\r
+          run it.\r
+        Otherwise,\r
+          deny execution.\r
+    Otherwise, the image is not signed,\r
+      Is the Image's Hash in DBX?\r
+        If yes, deny execution.\r
+        If not, is the Image's Hash in DB?\r
+          If yes, run it.\r
+          If not, deny execution.\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
@@ -1177,19 +1040,23 @@ Done:
                            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
@@ -1198,32 +1065,35 @@ 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
+  UINT8                                *SecureBoot;\r
   PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;\r
   UINT32                               NumberOfRvaAndSizes;\r
   UINT32                               CertSize;\r
-\r
-  if (File == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\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
 \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
   //\r
@@ -1260,43 +1130,22 @@ DxeImageVerificationHandler (
     return EFI_ACCESS_DENIED;\r
   }\r
 \r
-  GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &SecureBootEnable, NULL);\r
-  //\r
-  // Skip verification if SecureBootEnable variable doesn't exist.\r
-  //\r
-  if (SecureBootEnable == NULL) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
+  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
   //\r
-  // Skip verification if SecureBootEnable is disabled.\r
+  // Skip verification if SecureBoot variable doesn't exist.\r
   //\r
-  if (*SecureBootEnable == SECURE_BOOT_DISABLE) {\r
-    FreePool (SecureBootEnable);\r
+  if (SecureBoot == NULL) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  FreePool (SecureBootEnable);\r
-\r
-  GetEfiGlobalVariable2 (EFI_SETUP_MODE_NAME, &SetupMode, NULL);\r
-\r
   //\r
-  // SetupMode doesn't exist means no AuthVar driver is dispatched,\r
-  // skip verification.\r
+  // Skip verification if SecureBoot is disabled.\r
   //\r
-  if (SetupMode == NULL) {\r
+  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
+    FreePool (SecureBoot);\r
     return EFI_SUCCESS;\r
   }\r
-\r
-  //\r
-  // If platform is in SETUP MODE, skip verification.\r
-  //\r
-  if (*SetupMode == SETUP_MODE) {\r
-    FreePool (SetupMode);\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  FreePool (SetupMode);\r
+  FreePool (SecureBoot);\r
 \r
   //\r
   // Read the Dos header.\r
@@ -1346,14 +1195,28 @@ DxeImageVerificationHandler (
     goto Done;\r
   }\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
   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
     //\r
     // Use PE32 offset.\r
     //\r
     NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
-      mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[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
@@ -1361,11 +1224,11 @@ DxeImageVerificationHandler (
     //\r
     NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
-      mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+      SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
     }\r
   }\r
 \r
-  if ((mSecDataDir == NULL) || ((mSecDataDir != NULL) && (mSecDataDir->Size == 0))) {\r
+  if ((SecDataDir == NULL) || ((SecDataDir != NULL) && (SecDataDir->Size == 0))) {\r
     //\r
     // This image is not signed.\r
     //\r
@@ -1396,76 +1259,75 @@ DxeImageVerificationHandler (
   //\r
   // Verify signature of executables.\r
   //\r
-  WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);\r
+  WinCertificate = (WIN_CERTIFICATE *) (mImageBase + SecDataDir->VirtualAddress);\r
 \r
   CertSize = sizeof (WIN_CERTIFICATE);\r
 \r
-  if ((mSecDataDir->Size <= CertSize) || (mSecDataDir->Size < WinCertificate->dwLength)) {\r
+  if ((SecDataDir->Size <= CertSize) || (SecDataDir->Size < WinCertificate->dwLength)) {\r
     goto Done;\r
   }\r
 \r
-  switch (WinCertificate->wCertificateType) {\r
-\r
-  case WIN_CERT_TYPE_EFI_GUID:\r
-    CertSize = sizeof (WIN_CERTIFICATE_UEFI_GUID) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256) - sizeof (UINT8);\r
-    if (WinCertificate->dwLength < CertSize) {\r
-      goto Done;\r
-    }\r
-\r
+  //\r
+  // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.\r
+  //\r
+  if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
     //\r
-    // Verify UEFI GUID type.\r
+    // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the \r
+    // Authenticode specification.\r
     //\r
-    if (!HashPeImage (HASHALG_SHA256)) {\r
+    PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;\r
+    if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {\r
+      goto Done;\r
+    }\r
+    AuthData   = PkcsCertData->CertData;\r
+    AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);\r
+    \r
+    Status = HashPeImageByType (AuthData, AuthDataSize);\r
+    if (EFI_ERROR (Status)) {\r
       goto Done;\r
     }\r
 \r
-    VerifyStatus = VerifyCertUefiGuid ();\r
-    break;\r
-\r
-  case WIN_CERT_TYPE_PKCS_SIGNED_DATA:\r
+    VerifyStatus = VerifyCertPkcsSignedData (AuthData, AuthDataSize);\r
+  } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
     //\r
-    // Verify Pkcs signed data type.\r
+    // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.\r
     //\r
-    Status = HashPeImageByType();\r
+    WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;\r
+    if (!CompareGuid(&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid) ||\r
+        (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData))) {\r
+      goto Done;\r
+    }\r
+    AuthData = WinCertUefiGuid->CertData;\r
+    AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);\r
+    \r
+    Status = HashPeImageByType (AuthData, AuthDataSize);\r
     if (EFI_ERROR (Status)) {\r
       goto Done;\r
     }\r
+    VerifyStatus = VerifyCertPkcsSignedData (AuthData, AuthDataSize);\r
+  } else {\r
+    goto Done;\r
+  }\r
 \r
-    VerifyStatus = VerifyCertPkcsSignedData ();\r
-\r
+  if (!EFI_ERROR (VerifyStatus)) {\r
     //\r
-    // For image verification against enrolled certificate(root or intermediate),\r
-    // no need to check image's hash in the allowed database.\r
+    // Verification is passed.\r
+    // Continue to check the image digest in signature database.\r
     //\r
-    if (!EFI_ERROR (VerifyStatus)) {\r
-      if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
-        return EFI_SUCCESS;\r
-      }\r
+    if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
+      //\r
+      // Executable signature verification passes, but is found in forbidden signature database.\r
+      //\r
+      Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
+      Status = EFI_ACCESS_DENIED;\r
+    } else {\r
+      //\r
+      // For image verification against enrolled X.509 certificate(root or intermediate),\r
+      // no need to check image's hash in the allowed database.\r
+      //\r
+      return EFI_SUCCESS;\r
     }\r
-    break;\r
-\r
-  default:\r
-    goto Done;\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
-    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
-  // Signature database check after verification.\r
-  //\r
-  if (EFI_ERROR (VerifyStatus)) {\r
+  } else {\r
     //\r
     // Verification failure.\r
     //\r
@@ -1480,24 +1342,24 @@ DxeImageVerificationHandler (
       Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
       Status = EFI_ACCESS_DENIED;\r
     }\r
-  } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
-    //\r
-    // Executable signature verification passes, but is found in forbidden signature database.\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
-    //\r
-    // Executable signature is found in authorized signature database.\r
-    //\r
-    Status = EFI_SUCCESS;\r
-  } else {\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
     //\r
-    // Executable signature verification passes, but cannot be found in authorized signature database.\r
-    // Get platform policy to determine the action.\r
+    // Get image hash value as executable's signature.\r
     //\r
-    Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED;\r
-    Status = ImageAuthorization (Policy);\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
 Done:\r
@@ -1506,6 +1368,7 @@ Done:
     // 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
+    Status = EFI_SECURITY_VIOLATION;\r
   }\r
 \r
   if (SignatureList != NULL) {\r
@@ -1544,7 +1407,7 @@ VariableWriteCallBack (
   // If this library is built-in, it means firmware has capability to perform\r
   // driver signing verification.\r
   //\r
-  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, &SecureBootModePtr, NULL);\r
+  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBootModePtr, NULL);\r
   if (SecureBootModePtr == NULL) {\r
     SecureBootMode   = SECURE_BOOT_MODE_DISABLE;\r
     //\r
@@ -1590,7 +1453,7 @@ DxeImageVerificationLibConstructor (
     &Registration\r
     );\r
 \r
-  return RegisterSecurityHandler (\r
+  return RegisterSecurity2Handler (\r
           DxeImageVerificationHandler,\r
           EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
           );\r