+IsValidSignatureByTimestamp (\r
+ IN EFI_TIME *SigningTime,\r
+ IN EFI_TIME *RevocationTime\r
+ )\r
+{\r
+ if (SigningTime->Year != RevocationTime->Year) {\r
+ return (BOOLEAN) (SigningTime->Year < RevocationTime->Year);\r
+ } else if (SigningTime->Month != RevocationTime->Month) {\r
+ return (BOOLEAN) (SigningTime->Month < RevocationTime->Month);\r
+ } else if (SigningTime->Day != RevocationTime->Day) {\r
+ return (BOOLEAN) (SigningTime->Day < RevocationTime->Day);\r
+ } else if (SigningTime->Hour != RevocationTime->Hour) {\r
+ return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour);\r
+ } else if (SigningTime->Minute != RevocationTime->Minute) {\r
+ return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute);\r
+ }\r
+\r
+ return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second);\r
+}\r
+\r
+/**\r
+ Check if the given time value is zero.\r
+\r
+ @param[in] Time Pointer of a time value.\r
+\r
+ @retval TRUE The Time is Zero.\r
+ @retval FALSE The Time is not Zero.\r
+\r
+**/\r
+BOOLEAN\r
+IsTimeZero (\r
+ IN EFI_TIME *Time\r
+ )\r
+{\r
+ if ((Time->Year == 0) && (Time->Month == 0) && (Time->Day == 0) &&\r
+ (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Check whether the timestamp signature is valid and the signing time is also earlier than \r
+ the revocation time.\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
+ @param[in] RevocationTime The time that the certificate was revoked.\r
+\r
+ @retval TRUE Timestamp signature is valid and signing time is no later than the \r
+ revocation time.\r
+ @retval FALSE Timestamp signature is not valid or the signing time is later than the\r
+ revocation time.\r
+\r
+**/\r
+BOOLEAN\r
+PassTimestampCheck (\r
+ IN UINT8 *AuthData,\r
+ IN UINTN AuthDataSize,\r
+ IN EFI_TIME *RevocationTime\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN VerifyStatus;\r
+ EFI_SIGNATURE_LIST *CertList;\r
+ EFI_SIGNATURE_DATA *Cert;\r
+ 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
+ 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
+ //\r
+ // Variable Initialization\r
+ //\r
+ IsForbidden = FALSE;\r
+ Data = NULL;\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
+ // 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 certificates 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
+ 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
+ // 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
+ goto Done;\r
+ }\r
+\r
+ CertPtr = CertPtr + sizeof (UINT32) + CertSize;\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
+ 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