]> 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 c86ce1f312ae5c7543e4ea356863fb9c81b08c64..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
@@ -585,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
@@ -616,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
@@ -875,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
@@ -884,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
@@ -906,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
@@ -940,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
@@ -969,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
@@ -992,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
@@ -1081,10 +1083,17 @@ DxeImageVerificationHandler (
   PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;\r
   UINT32                               NumberOfRvaAndSizes;\r
   UINT32                               CertSize;\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
@@ -1207,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
@@ -1215,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
@@ -1250,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