Correct the DBX and Certificate Hash Checking.
authorLong, Qin <qin.long@intel.com>
Wed, 4 Feb 2015 08:19:53 +0000 (08:19 +0000)
committerqlong <qlong@Edk2>
Wed, 4 Feb 2015 08:19:53 +0000 (08:19 +0000)
Add the missed image signature verification against DBX;
and add the missed logic to enhance the certificate hash checking when handling DB database.

Contributed-under: TianoCore Contribution Agreement 1.0

Signed-off-by: "Long, Qin" <qin.long@intel.com>
Reviewed-by: "Fu, Siyuan" <siyuan.fu@intel.com>
Reviewed-by: "Dong, Guo" <guo.dong@initel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16744 6f19259b-4bc3-4df7-8a09-765794883524

SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c

index 959a9b062db3714fa13b244452a93a43cf3b821a..c01ffda61608591840557d88c1150a4a0ae6cd1f 100644 (file)
@@ -12,7 +12,7 @@
   DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept\r
   untrusted PE/COFF image and validate its data structure within this image buffer before use.\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 - 2014, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2015, 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
 which accompanies this distribution.  The full text of the license may be found at\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
@@ -1214,6 +1214,12 @@ IsForbiddenByDbx (
   BOOLEAN                   IsForbidden;\r
   UINT8                     *Data;\r
   UINTN                     DataSize;\r
   BOOLEAN                   IsForbidden;\r
   UINT8                     *Data;\r
   UINTN                     DataSize;\r
+  EFI_SIGNATURE_LIST        *CertList;\r
+  UINTN                     CertListSize;\r
+  EFI_SIGNATURE_DATA        *CertData;\r
+  UINT8                     *RootCert;\r
+  UINTN                     RootCertSize;\r
+  UINTN                     CertCount;\r
   UINTN                     Index;\r
   UINT8                     *CertBuffer;\r
   UINTN                     BufferLength;\r
   UINTN                     Index;\r
   UINT8                     *CertBuffer;\r
   UINTN                     BufferLength;\r
@@ -1230,6 +1236,10 @@ IsForbiddenByDbx (
   //\r
   IsForbidden       = FALSE;\r
   Data              = NULL;\r
   //\r
   IsForbidden       = FALSE;\r
   Data              = NULL;\r
+  CertList          = NULL;\r
+  CertData          = NULL;\r
+  RootCert          = NULL;\r
+  RootCertSize      = 0;\r
   Cert              = NULL;\r
   CertBuffer        = NULL;\r
   BufferLength      = 0;\r
   Cert              = NULL;\r
   CertBuffer        = NULL;\r
   BufferLength      = 0;\r
@@ -1254,6 +1264,52 @@ IsForbiddenByDbx (
     return IsForbidden;\r
   }\r
 \r
     return IsForbidden;\r
   }\r
 \r
+  //\r
+  // Verify image signature with RAW X509 certificates in DBX database.\r
+  // If passed, the image will be forbidden.\r
+  //\r
+  CertList     = (EFI_SIGNATURE_LIST *) Data;\r
+  CertListSize = DataSize;\r
+  while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) {\r
+    if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\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     = CertData->SignatureData;\r
+        RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
+\r
+        //\r
+        // Call AuthenticodeVerify library to Verify Authenticode struct.\r
+        //\r
+        IsForbidden = AuthenticodeVerify (\r
+                        AuthData,\r
+                        AuthDataSize,\r
+                        RootCert,\r
+                        RootCertSize,\r
+                        mImageDigest,\r
+                        mImageDigestSize\r
+                        );\r
+        if (IsForbidden) {\r
+          SecureBootHook (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+          goto Done;\r
+        }\r
+\r
+        CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);\r
+      }\r
+    }\r
+\r
+    CertListSize -= CertList->SignatureListSize;\r
+    CertList      = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+  }\r
+\r
+  //\r
+  // Check X.509 Certificate Hash & Possible Timestamp.\r
+  //\r
+\r
   //\r
   // Retrieve the certificate stack from AuthData\r
   // The output CertStack format will be:\r
   //\r
   // Retrieve the certificate stack from AuthData\r
   // The output CertStack format will be:\r
@@ -1273,20 +1329,13 @@ IsForbiddenByDbx (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  // Check if any certificates in AuthData is in the forbidden database.\r
+  // Check if any hash of certificates embedded in AuthData is in the forbidden database.\r
   //\r
   CertNumber = (UINT8) (*CertBuffer);\r
   CertPtr    = CertBuffer + 1;\r
   for (Index = 0; Index < CertNumber; Index++) {\r
     CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);\r
     Cert     = (UINT8 *)CertPtr + sizeof (UINT32);\r
   //\r
   CertNumber = (UINT8) (*CertBuffer);\r
   CertPtr    = CertBuffer + 1;\r
   for (Index = 0; Index < CertNumber; Index++) {\r
     CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);\r
     Cert     = (UINT8 *)CertPtr + sizeof (UINT32);\r
-    if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Cert, &gEfiCertX509Guid, CertSize)) {\r
-      //\r
-      // Raw certificate in dbx means the image signed by the certificate is forbidden.\r
-      //\r
-      IsForbidden = TRUE;\r
-      goto Done;\r
-    }\r
 \r
     if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {\r
       //\r
 \r
     if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {\r
       //\r
@@ -1339,6 +1388,9 @@ IsAllowedByDb (
   UINTN                     RootCertSize;\r
   UINTN                     Index;\r
   UINTN                     CertCount;\r
   UINTN                     RootCertSize;\r
   UINTN                     Index;\r
   UINTN                     CertCount;\r
+  UINTN                     DbxDataSize;\r
+  UINT8                     *DbxData;\r
+  EFI_TIME                  RevocationTime;\r
 \r
   Data         = NULL;\r
   CertList     = NULL;\r
 \r
   Data         = NULL;\r
   CertList     = NULL;\r
@@ -1388,7 +1440,30 @@ IsAllowedByDb (
                            mImageDigestSize\r
                            );\r
           if (VerifyStatus) {\r
                            mImageDigestSize\r
                            );\r
           if (VerifyStatus) {\r
-            SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+            //\r
+            // Here We still need to check if this RootCert's Hash is revoked\r
+            //\r
+            Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL);\r
+            if (Status == EFI_BUFFER_TOO_SMALL) {\r
+              goto Done;\r
+            }\r
+            DbxData = (UINT8 *) AllocateZeroPool (DataSize);\r
+            if (DbxData == NULL) {\r
+              goto Done;\r
+            }\r
+\r
+            Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData);\r
+            if (EFI_ERROR (Status)) {\r
+              goto Done;\r
+            }\r
+\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
+              //\r
+              VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);\r
+            }\r
+\r
             goto Done;\r
           }\r
 \r
             goto Done;\r
           }\r
 \r
@@ -1402,9 +1477,16 @@ IsAllowedByDb (
   }\r
 \r
 Done:\r
   }\r
 \r
 Done:\r
+  if (VerifyStatus) {\r
+    SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+  }\r
+\r
   if (Data != NULL) {\r
     FreePool (Data);\r
   }\r
   if (Data != NULL) {\r
     FreePool (Data);\r
   }\r
+  if (DbxData != NULL) {\r
+    FreePool (DbxData);\r
+  }\r
 \r
   return VerifyStatus;\r
 }\r
 \r
   return VerifyStatus;\r
 }\r