Update the DxeImageVerificationLib to handle the signed image which CertType is set to EFI_CERT_TYPE_PKCS7_GUID.

Signed-off-by: Fu Siyuan <siyuan.fu@intel.com>
Reviewed-by: Ye Ting  <ting.ye@intel.com>
Reviewed-by: Dong Guo <guo.dong@intel.com>

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13672 6f19259b-4bc3-4df7-8a09-765794883524
diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
index c86ce1f..b3648bd 100644
--- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -31,7 +31,6 @@
 //

 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;

 UINT32                              mPeCoffHeaderOffset;

-EFI_IMAGE_DATA_DIRECTORY            *mSecDataDir      = NULL;

 EFI_GUID                            mCertType;

 

 //

@@ -585,23 +584,20 @@
   PE/COFF image is external input, so this function will validate its data structure

   within this image buffer before use.

 

+  @param[in]  AuthData            Pointer to the Authenticode Signature retrieved from signed image.

+  @param[in]  AuthDataSize        Size of the Authenticode Signature in bytes.

+  

   @retval EFI_UNSUPPORTED             Hash algorithm is not supported.

   @retval EFI_SUCCESS                 Hash successfully.

 

 **/

 EFI_STATUS

 HashPeImageByType (

-  VOID

+  IN UINT8              *AuthData,

+  IN UINTN              AuthDataSize

   )

 {

   UINT8                     Index;

-  WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;

-

-  PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);

-

-  if (PkcsCertData->Hdr.dwLength < sizeof (WIN_CERTIFICATE_EFI_PKCS) + 32) {

-    return EFI_UNSUPPORTED;

-  }

 

   for (Index = 0; Index < HASHALG_MAX; Index++) {

     //

@@ -616,18 +612,18 @@
     //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.

     //    Fixed offset (+32) is calculated based on two bytes of length encoding.

     //

-    if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {

+    if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {

       //

       // Only support two bytes of Long Form of Length Encoding.

       //

       continue;

     }

 

-    if (PkcsCertData->Hdr.dwLength < sizeof (WIN_CERTIFICATE_EFI_PKCS) + 32 + mHash[Index].OidLength) {

+    if (AuthDataSize < 32 + mHash[Index].OidLength) {

       return EFI_UNSUPPORTED;

     }

 

-    if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {

+    if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {

       break;

     }

   }

@@ -875,8 +871,10 @@
   Verify PKCS#7 SignedData using certificate found in Variable which formatted

   as EFI_SIGNATURE_LIST. The Variable may be PK, KEK, DB or DBX.

 

-  @param VariableName  Name of Variable to search for Certificate.

-  @param VendorGuid    Variable vendor GUID.

+  @param[in]  AuthData      Pointer to the Authenticode Signature retrieved from signed image.

+  @param[in]  AuthDataSize  Size of the Authenticode Signature in bytes.

+  @param[in]  VariableName  Name of Variable to search for Certificate.

+  @param[in]  VendorGuid    Variable vendor GUID.

 

   @retval TRUE         Image pass verification.

   @retval FALSE        Image fail verification.

@@ -884,13 +882,14 @@
 **/

 BOOLEAN

 IsPkcsSignedDataVerifiedBySignatureList (

+  IN UINT8              *AuthData,

+  IN UINTN              AuthDataSize,

   IN CHAR16             *VariableName,

   IN EFI_GUID           *VendorGuid

   )

 {

   EFI_STATUS                Status;

   BOOLEAN                   VerifyStatus;

-  WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;

   EFI_SIGNATURE_LIST        *CertList;

   EFI_SIGNATURE_DATA        *Cert;

   UINTN                     DataSize;

@@ -906,7 +905,6 @@
   RootCert     = NULL;

   RootCertSize = 0;

   VerifyStatus = FALSE;

-  PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);

 

   DataSize = 0;

   Status   = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);

@@ -940,8 +938,8 @@
           // Call AuthenticodeVerify library to Verify Authenticode struct.

           //

           VerifyStatus = AuthenticodeVerify (

-                           PkcsCertData->CertData,

-                           PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr),

+                           AuthData,

+                           AuthDataSize,

                            RootCert,

                            RootCertSize,

                            mImageDigest,

@@ -969,19 +967,23 @@
 /**

   Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format.

 

+  @param[in]  AuthData      Pointer to the Authenticode Signature retrieved from signed image.

+  @param[in]  AuthDataSize  Size of the Authenticode Signature in bytes.

+

   @retval EFI_SUCCESS                 Image pass verification.

   @retval EFI_SECURITY_VIOLATION      Image fail verification.

 

 **/

 EFI_STATUS

 VerifyCertPkcsSignedData (

-  VOID

+  IN UINT8              *AuthData,

+  IN UINTN              AuthDataSize

   )

 {

   //

   // 1: Find certificate from DBX forbidden database for revoked certificate.

   //

-  if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {

+  if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {

     //

     // DBX is forbidden database, if Authenticode verification pass with

     // one of the certificate in DBX, this image should be rejected.

@@ -992,7 +994,7 @@
   //

   // 2: Find certificate from DB database and try to verify authenticode struct.

   //

-  if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {

+  if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {

     return EFI_SUCCESS;

   } else {

     return EFI_SECURITY_VIOLATION;

@@ -1081,10 +1083,17 @@
   PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;

   UINT32                               NumberOfRvaAndSizes;

   UINT32                               CertSize;

+  WIN_CERTIFICATE_EFI_PKCS             *PkcsCertData;

+  WIN_CERTIFICATE_UEFI_GUID            *WinCertUefiGuid;

+  UINT8                                *AuthData;

+  UINTN                                AuthDataSize;

+  EFI_IMAGE_DATA_DIRECTORY             *SecDataDir;

 

   SignatureList     = NULL;

   SignatureListSize = 0;

   WinCertificate    = NULL;

+  SecDataDir        = NULL;

+  PkcsCertData      = NULL;

   Action            = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;

   Status            = EFI_ACCESS_DENIED;

   //

@@ -1207,7 +1216,7 @@
     //

     NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;

     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {

-      mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];

+      SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];

     }        

   } else {

     //

@@ -1215,11 +1224,11 @@
     //

     NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;

     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {

-      mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];

+      SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];

     }

   }

 

-  if ((mSecDataDir == NULL) || ((mSecDataDir != NULL) && (mSecDataDir->Size == 0))) {

+  if ((SecDataDir == NULL) || ((SecDataDir != NULL) && (SecDataDir->Size == 0))) {

     //

     // This image is not signed.

     //

@@ -1250,24 +1259,48 @@
   //

   // Verify signature of executables.

   //

-  WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);

+  WinCertificate = (WIN_CERTIFICATE *) (mImageBase + SecDataDir->VirtualAddress);

 

   CertSize = sizeof (WIN_CERTIFICATE);

 

-  if ((mSecDataDir->Size <= CertSize) || (mSecDataDir->Size < WinCertificate->dwLength)) {

+  if ((SecDataDir->Size <= CertSize) || (SecDataDir->Size < WinCertificate->dwLength)) {

     goto Done;

   }

 

+  //

+  // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.

+  //

   if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {

     //

-    // Verify Pkcs signed data type.

+    // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the 

+    // Authenticode specification.

     //

-    Status = HashPeImageByType();

+    PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;

+    AuthData   = PkcsCertData->CertData;

+    AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);

+    

+    Status = HashPeImageByType (AuthData, AuthDataSize);

     if (EFI_ERROR (Status)) {

       goto Done;

     }

+

+    VerifyStatus = VerifyCertPkcsSignedData (AuthData, AuthDataSize);

+  } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {

+    //

+    // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.

+    //

+    WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;

+    if (!CompareGuid(&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {

+      goto Done;

+    }

+    AuthData = WinCertUefiGuid->CertData;

+    AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);

     

-    VerifyStatus = VerifyCertPkcsSignedData ();

+    Status = HashPeImageByType (AuthData, AuthDataSize);

+    if (EFI_ERROR (Status)) {

+      goto Done;

+    }

+    VerifyStatus = VerifyCertPkcsSignedData (AuthData, AuthDataSize);

   } else {

     goto Done;

   }

diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
index 8ec41f4..dd03b0b 100644
--- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
@@ -68,6 +68,7 @@
   gEfiCertSha256Guid

   gEfiCertX509Guid

   gEfiCertRsa2048Guid

+  gEfiCertPkcs7Guid

   

 [Pcd]

   gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy