]> 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 402540eb1b2bd4469f42bffcc5b6975537848ea5..9ea3a28ad91b93ede65c6eb159ad5b6b75c52b08 100644 (file)
@@ -31,7 +31,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\r
 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
 UINT32                              mPeCoffHeaderOffset;\r
-EFI_IMAGE_DATA_DIRECTORY            *mSecDataDir      = NULL;\r
 EFI_GUID                            mCertType;\r
 \r
 //\r
@@ -141,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
@@ -581,23 +584,20 @@ Done:
   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
@@ -612,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
@@ -871,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
@@ -880,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
@@ -902,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
@@ -936,8 +938,8 @@ IsPkcsSignedDataVerifiedBySignatureList (
           // 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
@@ -965,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
@@ -988,7 +994,7 @@ VerifyCertPkcsSignedData (
   //\r
   // 2: Find certificate from DB database and try to verify authenticode struct.\r
   //\r
-  if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {\r
+  if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {\r
     return EFI_SUCCESS;\r
   } else {\r
     return EFI_SECURITY_VIOLATION;\r
@@ -1034,19 +1040,23 @@ VerifyCertPkcsSignedData (
                            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
@@ -1055,7 +1065,8 @@ 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
@@ -1072,14 +1083,17 @@ DxeImageVerificationHandler (
   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
@@ -1202,7 +1216,7 @@ DxeImageVerificationHandler (
     //\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
@@ -1210,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
@@ -1245,24 +1259,52 @@ 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
+  //\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 Pkcs signed data type.\r
+    // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the \r
+    // Authenticode specification.\r
     //\r
-    Status = HashPeImageByType();\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 = VerifyCertPkcsSignedData (AuthData, AuthDataSize);\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 (!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
-    VerifyStatus = VerifyCertPkcsSignedData ();\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
@@ -1326,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
@@ -1410,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