]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
SecurityPkg: Refine type cast for pointer subtraction
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
index 9a6172353047c483977508aeb38c6f4dee6f5d14..588072c6a1d8ca4184b7f14928e722ccaa0a838a 100644 (file)
@@ -1,5 +1,5 @@
 /** @file\r
-  Implement image verification services for secure boot service in UEFI2.3.1.\r
+  Implement image verification services for secure boot service\r
 \r
   Caution: This file requires additional review when modified.\r
   This library will have external input - PE/COFF image.\r
@@ -12,7 +12,8 @@
   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
+Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<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
@@ -71,6 +72,8 @@ HASH_TABLE mHash[] = {
   { L"SHA512", 64, &mHashOidValue[32], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}\r
 };\r
 \r
+EFI_STRING mHashTypeStr;\r
+\r
 /**\r
   SecureBoot Hook for processing image verification.\r
 \r
@@ -272,11 +275,14 @@ GetImageType (
 /**\r
   Calculate hash of Pe/Coff image based on the authenticode image hashing in\r
   PE/COFF Specification 8.0 Appendix A\r
-\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
+  Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in \r
+  its caller function DxeImageVerificationHandler().\r
+\r
   @param[in]    HashAlg   Hash algorithm type.\r
 \r
   @retval TRUE            Successfully hash image.\r
@@ -340,6 +346,7 @@ HashPeImage (
     return FALSE;\r
   }\r
 \r
+  mHashTypeStr = mHash[HashAlg].Name;\r
   CtxSize   = mHash[HashAlg].GetContextSize();\r
 \r
   HashCtx = AllocatePool (CtxSize);\r
@@ -384,13 +391,13 @@ HashPeImage (
     //\r
     // Use PE32 offset.\r
     //\r
-    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);\r
+    HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) 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
+    HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
     NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
   } else {\r
     //\r
@@ -418,13 +425,13 @@ HashPeImage (
       // Use PE32 offset.\r
       //\r
       HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
-      HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+      HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) 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
+      HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);\r
     }\r
 \r
     if (HashSize != 0) {\r
@@ -442,13 +449,13 @@ HashPeImage (
       // 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
+      HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) 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
+      HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
     }\r
 \r
     if (HashSize != 0) {\r
@@ -467,13 +474,13 @@ HashPeImage (
       // 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
+      HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) 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
+      HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);\r
     }\r
 \r
     if (HashSize != 0) {\r
@@ -737,11 +744,13 @@ AddImageExeInfo (
   UINTN                           NewImageExeInfoEntrySize;\r
   UINTN                           NameStringLen;\r
   UINTN                           DevicePathSize;\r
+  CHAR16                          *NameStr;\r
 \r
   ImageExeInfoTable     = NULL;\r
   NewImageExeInfoTable  = NULL;\r
   ImageExeInfoEntry     = NULL;\r
   NameStringLen         = 0;\r
+  NameStr               = NULL;\r
 \r
   if (DevicePath == NULL) {\r
     return ;\r
@@ -769,7 +778,12 @@ AddImageExeInfo (
   }\r
 \r
   DevicePathSize            = GetDevicePathSize (DevicePath);\r
-  NewImageExeInfoEntrySize  = sizeof (EFI_IMAGE_EXECUTION_INFO) - sizeof (EFI_SIGNATURE_LIST) + NameStringLen + DevicePathSize + SignatureSize;\r
+\r
+  //\r
+  // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align\r
+  //\r
+  NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;\r
+\r
   NewImageExeInfoTable      = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);\r
   if (NewImageExeInfoTable == NULL) {\r
     return ;\r
@@ -788,19 +802,21 @@ AddImageExeInfo (
   WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);\r
   WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);\r
 \r
+  NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);\r
   if (Name != NULL) {\r
-    CopyMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), Name, NameStringLen);\r
+    CopyMem ((UINT8 *) NameStr, Name, NameStringLen);\r
   } else {\r
-    ZeroMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), sizeof (CHAR16));\r
+    ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16));\r
   }\r
+\r
   CopyMem (\r
-    (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen,\r
+    (UINT8 *) NameStr + NameStringLen,\r
     DevicePath,\r
     DevicePathSize\r
     );\r
   if (Signature != NULL) {\r
     CopyMem (\r
-      (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen + DevicePathSize,\r
+      (UINT8 *) NameStr + NameStringLen + DevicePathSize,\r
       Signature,\r
       SignatureSize\r
       );\r
@@ -1010,7 +1026,12 @@ IsSignatureFoundInDatabase (
           // Find the signature in database.\r
           //\r
           IsFound = TRUE;\r
-          SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+          //\r
+          // Entries in UEFI_IMAGE_SECURITY_DATABASE that are used to validate image should be measured\r
+          //\r
+          if (StrCmp(VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) {\r
+            SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+          }\r
           break;\r
         }\r
 \r
@@ -1205,9 +1226,9 @@ Done:
 \r
 **/\r
 BOOLEAN\r
-IsForbiddenByDbx (\r
+IsForbiddenByDbx (  \r
   IN UINT8                  *AuthData,\r
-  IN UINTN                  AuthDataSize\r
+  IN UINTN                  AuthDataSize  \r
   )\r
 {\r
   EFI_STATUS                Status;\r
@@ -1230,7 +1251,6 @@ IsForbiddenByDbx (
   UINT8                     *Cert;\r
   UINTN                     CertSize;\r
   EFI_TIME                  RevocationTime;\r
-\r
   //\r
   // Variable Initialization\r
   //\r
@@ -1294,7 +1314,7 @@ IsForbiddenByDbx (
                         mImageDigestSize\r
                         );\r
         if (IsForbidden) {\r
-          SecureBootHook (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+          DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is forbidden by DBX.\n"));\r
           goto Done;\r
         }\r
 \r
@@ -1336,6 +1356,10 @@ IsForbiddenByDbx (
   for (Index = 0; Index < CertNumber; Index++) {\r
     CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);\r
     Cert     = (UINT8 *)CertPtr + sizeof (UINT32);\r
+    //\r
+    // Advance CertPtr to the next cert in image signer's cert list\r
+    //\r
+    CertPtr = CertPtr + sizeof (UINT32) + CertSize;\r
 \r
     if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {\r
       //\r
@@ -1344,11 +1368,15 @@ IsForbiddenByDbx (
       IsForbidden = TRUE;\r
       if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) {\r
         IsForbidden = FALSE;\r
+        //\r
+        // Pass DBT check. Continue to check other certs in image signer's cert list against DBX, DBT\r
+        //\r
+        continue;\r
       }\r
+      DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature failed the timestamp check.\n"));\r
       goto Done;\r
     }\r
 \r
-    CertPtr = CertPtr + sizeof (UINT32) + CertSize;\r
   }\r
 \r
 Done:\r
@@ -1362,6 +1390,7 @@ Done:
   return IsForbidden;\r
 }\r
 \r
+\r
 /**\r
   Check whether the image signature can be verified by the trusted certificates in DB database.\r
 \r
@@ -1381,7 +1410,7 @@ IsAllowedByDb (
   EFI_STATUS                Status;\r
   BOOLEAN                   VerifyStatus;\r
   EFI_SIGNATURE_LIST        *CertList;\r
-  EFI_SIGNATURE_DATA        *Cert;\r
+  EFI_SIGNATURE_DATA        *CertData;\r
   UINTN                     DataSize;\r
   UINT8                     *Data;\r
   UINT8                     *RootCert;\r
@@ -1392,13 +1421,13 @@ IsAllowedByDb (
   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
+  Data              = NULL;\r
+  CertList          = NULL;\r
+  CertData          = 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
@@ -1419,14 +1448,14 @@ IsAllowedByDb (
     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
+        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     = Cert->SignatureData;\r
+          RootCert     = CertData->SignatureData;\r
           RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
 \r
           //\r
@@ -1448,7 +1477,7 @@ IsAllowedByDb (
             if (Status == EFI_BUFFER_TOO_SMALL) {\r
               goto Done;\r
             }\r
-            DbxData = (UINT8 *) AllocateZeroPool (DataSize);\r
+            DbxData = (UINT8 *) AllocateZeroPool (DbxDataSize);\r
             if (DbxData == NULL) {\r
               goto Done;\r
             }\r
@@ -1460,15 +1489,18 @@ IsAllowedByDb (
 \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
+              // Check the timestamp signature and signing time to determine if the RootCert can be trusted.\r
               //\r
               VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);\r
+              if (!VerifyStatus) {\r
+                DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed and signature is accepted by DB, but its root cert failed the timestamp check.\n"));\r
+              }\r
             }\r
 \r
             goto Done;\r
           }\r
 \r
-          Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+          CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);\r
         }\r
       }\r
 \r
@@ -1478,8 +1510,9 @@ IsAllowedByDb (
   }\r
 \r
 Done:\r
+\r
   if (VerifyStatus) {\r
-    SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+    SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);\r
   }\r
 \r
   if (Data != NULL) {\r
@@ -1579,6 +1612,7 @@ DxeImageVerificationHandler (
   Status            = EFI_ACCESS_DENIED;\r
   VerifyStatus      = EFI_ACCESS_DENIED;\r
 \r
+\r
   //\r
   // Check the image type and get policy setting.\r
   //\r
@@ -1631,7 +1665,7 @@ DxeImageVerificationHandler (
   }\r
 \r
   //\r
-  // Skip verification if SecureBoot is disabled.\r
+  // Skip verification if SecureBoot is disabled but not AuditMode\r
   //\r
   if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
     FreePool (SecureBoot);\r
@@ -1661,6 +1695,7 @@ DxeImageVerificationHandler (
     //\r
     // The information can't be got from the invalid PeImage\r
     //\r
+    DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information.\n"));\r
     goto Done;\r
   }\r
 \r
@@ -1684,6 +1719,7 @@ DxeImageVerificationHandler (
     //\r
     // It is not a valid Pe/Coff file.\r
     //\r
+    DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Not a valid PE/COFF image.\n"));\r
     goto Done;\r
   }\r
 \r
@@ -1729,6 +1765,7 @@ DxeImageVerificationHandler (
     // and not be reflected in the security data base "dbx".\r
     //\r
     if (!HashPeImage (HASHALG_SHA256)) {\r
+      DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", mHashTypeStr));\r
       goto Done;\r
     }\r
 \r
@@ -1736,6 +1773,7 @@ DxeImageVerificationHandler (
       //\r
       // Image Hash is in forbidden database (DBX).\r
       //\r
+      DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX.\n", mHashTypeStr));\r
       goto Done;\r
     }\r
 \r
@@ -1749,6 +1787,7 @@ DxeImageVerificationHandler (
     //\r
     // Image Hash is not found in both forbidden and allowed database.\r
     //\r
+    DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));\r
     goto Done;\r
   }\r
 \r
@@ -1828,11 +1867,14 @@ DxeImageVerificationHandler (
     //\r
     if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
       Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
+      DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but %s hash of image is found in DBX.\n", mHashTypeStr));\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
+      } else {\r
+        DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is not allowed by DB and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));\r
       }\r
     }\r
   }\r
@@ -1860,7 +1902,7 @@ DxeImageVerificationHandler (
       }\r
       SignatureList->SignatureHeaderSize  = 0;\r
       SignatureList->SignatureListSize    = (UINT32) SignatureListSize;\r
-      SignatureList->SignatureSize        = (UINT32) mImageDigestSize;\r
+      SignatureList->SignatureSize        = (UINT32) (sizeof (EFI_SIGNATURE_DATA) - 1 + 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