+ UINT8 *DbtData;\r
+ UINTN DbtDataSize;\r
+ UINT8 *RootCert;\r
+ UINTN RootCertSize;\r
+ UINTN Index;\r
+ UINTN CertCount;\r
+ EFI_TIME SigningTime;\r
+\r
+ //\r
+ // Variable Initialization\r
+ //\r
+ VerifyStatus = FALSE;\r
+ DbtData = NULL;\r
+ CertList = NULL;\r
+ Cert = NULL;\r
+ RootCert = NULL;\r
+ RootCertSize = 0;\r
+\r
+ //\r
+ // If RevocationTime is zero, the certificate shall be considered to always be revoked.\r
+ //\r
+ if (IsTimeZero (RevocationTime)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards.\r
+ // Using the dbt to get the trusted TSA certificates.\r
+ //\r
+ DbtDataSize = 0;\r
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, NULL);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ goto Done;\r
+ }\r
+ DbtData = (UINT8 *) AllocateZeroPool (DbtDataSize);\r
+ if (DbtData == NULL) {\r
+ goto Done;\r
+ }\r
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, (VOID *) DbtData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ CertList = (EFI_SIGNATURE_LIST *) DbtData;\r
+ while ((DbtDataSize > 0) && (DbtDataSize >= 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
+ for (Index = 0; Index < CertCount; Index++) {\r
+ //\r
+ // Iterate each Signature Data Node within this CertList for verify.\r
+ //\r
+ RootCert = Cert->SignatureData;\r
+ RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
+ //\r
+ // Get the signing time if the timestamp signature is valid.\r
+ //\r
+ if (ImageTimestampVerify (AuthData, AuthDataSize, RootCert, RootCertSize, &SigningTime)) {\r
+ //\r
+ // The signer signature is valid only when the signing time is earlier than revocation time.\r
+ //\r
+ if (IsValidSignatureByTimestamp (&SigningTime, RevocationTime)) {\r
+ VerifyStatus = TRUE;\r
+ goto Done;\r
+ }\r
+ }\r
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+ }\r
+ }\r
+ DbtDataSize -= CertList->SignatureListSize;\r
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+ }\r
+\r
+Done:\r
+ if (DbtData != NULL) {\r
+ FreePool (DbtData);\r
+ }\r
+\r
+ return VerifyStatus;\r
+}\r
+\r
+/**\r
+ Check whether the image signature is forbidden by the forbidden database (dbx).\r
+ The image is forbidden to load if any certificates for signing are revoked before signing time.\r
+\r
+ @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image.\r
+ @param[in] AuthDataSize Size of the Authenticode signature in bytes.\r
+\r
+ @retval TRUE Image is forbidden by dbx.\r
+ @retval FALSE Image is not forbidden by dbx.\r
+\r
+**/\r
+BOOLEAN\r
+IsForbiddenByDbx ( \r
+ IN UINT8 *AuthData,\r
+ IN UINTN AuthDataSize \r
+ )\r
+{\r
+ EFI_STATUS Status;\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
+ UINT8 *TrustedCert;\r
+ UINTN TrustedCertLength;\r
+ UINT8 CertNumber;\r
+ UINT8 *CertPtr;\r
+ UINT8 *Cert;\r
+ UINTN CertSize;\r
+ EFI_TIME RevocationTime;\r
+ //\r
+ // Variable Initialization\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
+ TrustedCert = NULL;\r
+ TrustedCertLength = 0;\r
+\r
+ //\r
+ // The image will not be forbidden if dbx can't be got.\r
+ //\r
+ DataSize = 0;\r
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return IsForbidden;\r
+ }\r
+ Data = (UINT8 *) AllocateZeroPool (DataSize);\r
+ if (Data == NULL) {\r
+ return IsForbidden;\r
+ }\r
+\r
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);\r
+ if (EFI_ERROR (Status)) {\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
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is forbidden by DBX.\n"));\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
+ // UINT8 CertNumber;\r
+ // UINT32 Cert1Length;\r
+ // UINT8 Cert1[];\r
+ // UINT32 Cert2Length;\r
+ // UINT8 Cert2[];\r
+ // ...\r
+ // UINT32 CertnLength;\r
+ // UINT8 Certn[];\r
+ //\r
+ Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);\r
+ if ((BufferLength == 0) || (CertBuffer == NULL)) {\r
+ IsForbidden = TRUE;\r
+ goto Done;\r
+ }\r
+\r
+ //\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
+ // 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
+ // Check the timestamp signature and signing time to determine if the image can be trusted.\r
+ //\r
+ 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
+ }\r
+\r
+Done:\r
+ if (Data != NULL) {\r
+ FreePool (Data);\r
+ }\r
+\r
+ Pkcs7FreeSigners (CertBuffer);\r
+ Pkcs7FreeSigners (TrustedCert);\r
+\r
+ return IsForbidden;\r
+}\r
+\r
+\r
+/**\r
+ Check whether the image signature can be verified by the trusted certificates in DB database.\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 TRUE Image passed verification using certificate in db.\r
+ @retval FALSE Image didn't pass verification using certificate in db.\r
+\r
+**/\r
+BOOLEAN\r
+IsAllowedByDb (\r
+ IN UINT8 *AuthData,\r
+ IN UINTN AuthDataSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN VerifyStatus;\r
+ EFI_SIGNATURE_LIST *CertList;\r
+ EFI_SIGNATURE_DATA *CertData;\r