return Status;\r
}\r
\r
+/**\r
+ Check whether the hash of data content is revoked by the revocation database.\r
+\r
+ @param[in] Hash Pointer to the hash that is searched for.\r
+ @param[in] HashSize The size of the hash in bytes.\r
+ @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
+ structure which contains list of X.509 certificates\r
+ of revoked signers and revoked content hashes.\r
+\r
+ @return TRUE The matched content hash is found in the revocation database.\r
+ @return FALSE The matched content hash is not found in the revocation database.\r
+\r
+**/\r
+BOOLEAN\r
+IsContentHashRevokedByHash (\r
+ IN UINT8 *Hash,\r
+ IN UINTN HashSize,\r
+ IN EFI_SIGNATURE_LIST **RevokedDb\r
+ )\r
+{\r
+ EFI_SIGNATURE_LIST *SigList;\r
+ EFI_SIGNATURE_DATA *SigData;\r
+ UINTN Index;\r
+ UINTN EntryIndex;\r
+ UINTN EntryCount;\r
+ BOOLEAN Status;\r
+\r
+ if (RevokedDb == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = FALSE;\r
+ //\r
+ // Check if any hash matching content hash can be found in RevokedDB\r
+ //\r
+ for (Index = 0; ; Index++) {\r
+ SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);\r
+\r
+ //\r
+ // The list is terminated by a NULL pointer.\r
+ //\r
+ if (SigList == NULL) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Search the signature database to search the revoked content hash\r
+ //\r
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
+ SigList->SignatureHeaderSize);\r
+ EntryCount = (SigList->SignatureListSize - SigList->SignatureHeaderSize -\r
+ sizeof (EFI_SIGNATURE_LIST)) / SigList->SignatureSize;\r
+ for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex++) {\r
+ //\r
+ // The problem case. There's a revocation hash but the sizes\r
+ // don't match, meaning it's a different hash algorithm and we\r
+ // can't tell if it's revoking our binary or not. Assume not.\r
+ //\r
+ if (SigList->SignatureSize - sizeof(EFI_GUID) == HashSize) {\r
+ //\r
+ // Compare Data Hash with Signature Data\r
+ //\r
+ if (CompareMem (SigData->SignatureData, Hash, HashSize) == 0) {\r
+ Status = TRUE;\r
+ goto _Exit;\r
+ }\r
+ }\r
+\r
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigData + SigList->SignatureSize);\r
+ }\r
+ }\r
+\r
+_Exit:\r
+ return Status;\r
+}\r
+\r
/**\r
Check whether the hash of data content is revoked by the revocation database.\r
\r
return Status;\r
}\r
\r
+/**\r
+ Check whether the PKCS7 signedData is revoked by verifying with the revoked\r
+ certificates database, and if the signedData is timestamped, the embedded timestamp\r
+ couterSignature will be checked with the supplied timestamp database.\r
+\r
+ @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7\r
+ signature.\r
+ @param[in] SignedDataSize The size of SignedData buffer in bytes.\r
+ @param[in] InHash Pointer to the buffer containing the hash of the mesage data\r
+ previously signed and to be verified.\r
+ @param[in] InHashSize The size of InHash buffer in bytes.\r
+ @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
+ structure which contains list of X.509 certificates\r
+ of revoked signers and revoked content hashes.\r
+ @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
+ structures which is used to pass a list of X.509\r
+ certificates of trusted timestamp signers.\r
+\r
+ @retval EFI_SUCCESS The PKCS7 signedData is revoked.\r
+ @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.\r
+ @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.\r
+ AllowedDb is NULL.\r
+ Content is not NULL and ContentSize is NULL.\r
+ @retval EFI_NOT_FOUND Content not found because InData is NULL and no\r
+ content embedded in PKCS7 signedData.\r
+ @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.\r
+\r
+**/\r
+EFI_STATUS\r
+P7CheckRevocationByHash (\r
+ IN UINT8 *SignedData,\r
+ IN UINTN SignedDataSize,\r
+ IN UINT8 *InHash,\r
+ IN UINTN InHashSize,\r
+ IN EFI_SIGNATURE_LIST **RevokedDb,\r
+ IN EFI_SIGNATURE_LIST **TimeStampDb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIGNATURE_LIST *SigList;\r
+ EFI_SIGNATURE_DATA *SigData;\r
+ UINT8 *RevokedCert;\r
+ UINTN RevokedCertSize;\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
+ Status = EFI_SECURITY_VIOLATION;\r
+ SigData = NULL;\r
+ RevokedCert = NULL;\r
+ RevokedCertSize = 0;\r
+ CertBuffer = NULL;\r
+ TrustedCert = NULL;\r
+\r
+ //\r
+ // The signedData is revoked if the hash of content existed in RevokedDb\r
+ //\r
+ if (IsContentHashRevokedByHash (InHash, InHashSize, RevokedDb)) {\r
+ Status = EFI_SUCCESS;\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // Check if the signer's certificate can be found in Revoked database\r
+ //\r
+ for (Index = 0; ; Index++) {\r
+ SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);\r
+\r
+ //\r
+ // The list is terminated by a NULL pointer.\r
+ //\r
+ if (SigList == NULL) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Ignore any non-X509-format entry in the list.\r
+ //\r
+ if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
+ continue;\r
+ }\r
+\r
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
+ SigList->SignatureHeaderSize);\r
+\r
+ RevokedCert = SigData->SignatureData;\r
+ RevokedCertSize = SigList->SignatureSize - sizeof (EFI_GUID);\r
+\r
+ //\r
+ // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb\r
+ //\r
+ if (AuthenticodeVerify (SignedData, SignedDataSize, RevokedCert, RevokedCertSize, InHash, InHashSize)) {\r
+ //\r
+ // The signedData was verified by one entry in Revoked Database\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // The signedData was revoked, since it was hit by RevokedDb\r
+ //\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp\r
+ //\r
+ if ((TimeStampDb == NULL) || (*TimeStampDb == NULL)) {\r
+ goto _Exit;\r
+ }\r
+\r
+ Pkcs7GetSigners (SignedData, SignedDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);\r
+ if ((BufferLength == 0) || (CertBuffer == NULL)) {\r
+ Status = EFI_SUCCESS;\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // Check if any hash of certificates embedded in P7 data is in the revoked database.\r
+ //\r
+ CertNumber = (UINT8) (*CertBuffer);\r
+ CertPtr = CertBuffer + 1;\r
+ for (Index = 0; Index < CertNumber; Index++) {\r
+ //\r
+ // Retrieve the Certificate data\r
+ //\r
+ CertSize = (UINTN) ReadUnaligned32 ((UINT32 *) CertPtr);\r
+ Cert = (UINT8 *)CertPtr + sizeof (UINT32);\r
+\r
+ if (IsCertHashRevoked (Cert, CertSize, RevokedDb, &RevocationTime)) {\r
+ //\r
+ // Check the timestamp signature and signing time to determine if p7 data can be trusted.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ if (IsValidTimestamp (SignedData, SignedDataSize, TimeStampDb, &RevocationTime)) {\r
+ //\r
+ // Use EFI_NOT_READY to identify the P7Data is not reovked, because the timestamping\r
+ // occured prior to the time of certificate revocation.\r
+ //\r
+ Status = EFI_NOT_READY;\r
+ }\r
+\r
+ goto _Exit;\r
+ }\r
+\r
+ CertPtr = CertPtr + sizeof (UINT32) + CertSize;\r
+ }\r
+\r
+_Exit:\r
+ Pkcs7FreeSigners (CertBuffer);\r
+ Pkcs7FreeSigners (TrustedCert);\r
+\r
+ return Status;\r
+}\r
+\r
/**\r
Check whether the PKCS7 signedData is revoked by verifying with the revoked\r
certificates database, and if the signedData is timestamped, the embedded timestamp\r
return Status;\r
}\r
\r
+/**\r
+ Check whether the PKCS7 signedData can be verified by the trusted certificates\r
+ database, and return the content of the signedData if requested.\r
+\r
+ @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7\r
+ signature.\r
+ @param[in] SignedDataSize The size of SignedData buffer in bytes.\r
+ @param[in] InHash Pointer to the buffer containing the hash of the message data\r
+ previously signed and to be verified.\r
+ @param[in] InHashSize The size of InHash buffer in bytes.\r
+ @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
+ structures which contains lists of X.509 certificates\r
+ of approved signers.\r
+\r
+ @retval EFI_SUCCESS The PKCS7 signedData is trusted.\r
+ @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.\r
+ @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.\r
+ AllowedDb is NULL.\r
+ Content is not NULL and ContentSize is NULL.\r
+ @retval EFI_NOT_FOUND Content not found because InData is NULL and no\r
+ content embedded in PKCS7 signedData.\r
+ @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.\r
+ @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too\r
+ small to hold the content. ContentSize updated to\r
+ the required size.\r
+\r
+**/\r
+EFI_STATUS\r
+P7CheckTrustByHash (\r
+ IN UINT8 *SignedData,\r
+ IN UINTN SignedDataSize,\r
+ IN UINT8 *InHash,\r
+ IN UINTN InHashSize,\r
+ IN EFI_SIGNATURE_LIST **AllowedDb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIGNATURE_LIST *SigList;\r
+ EFI_SIGNATURE_DATA *SigData;\r
+ UINT8 *TrustCert;\r
+ UINTN TrustCertSize;\r
+ UINTN Index;\r
+\r
+ Status = EFI_SECURITY_VIOLATION;\r
+ SigData = NULL;\r
+ TrustCert = NULL;\r
+ TrustCertSize = 0;\r
+\r
+ if (AllowedDb == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Build Certificate Stack with all valid X509 certificates in the supplied\r
+ // Signature List for PKCS7 Verification.\r
+ //\r
+ for (Index = 0; ; Index++) {\r
+ SigList = (EFI_SIGNATURE_LIST *)(AllowedDb[Index]);\r
+\r
+ //\r
+ // The list is terminated by a NULL pointer.\r
+ //\r
+ if (SigList == NULL) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Ignore any non-X509-format entry in the list.\r
+ //\r
+ if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
+ continue;\r
+ }\r
+\r
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
+ SigList->SignatureHeaderSize);\r
+\r
+ TrustCert = SigData->SignatureData;\r
+ TrustCertSize = SigList->SignatureSize - sizeof (EFI_GUID);\r
+\r
+ //\r
+ // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb\r
+ //\r
+ if (AuthenticodeVerify (SignedData, SignedDataSize, TrustCert, TrustCertSize, InHash, InHashSize)) {\r
+ //\r
+ // The SignedData was verified successfully by one entry in Trusted Database\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
/**\r
Check whether the PKCS7 signedData can be verified by the trusted certificates\r
database, and return the content of the signedData if requested.\r
IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL\r
)\r
{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Parameters Checking\r
//\r
- // NOTE: Current EDKII-OpenSSL interface cannot support VerifySignature\r
- // directly. EFI_UNSUPPORTED is returned in this version.\r
+ if ((Signature == NULL) || (SignatureSize == 0) || (AllowedDb == NULL)\r
+ || (InHash == NULL) || (InHashSize == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
//\r
- return EFI_UNSUPPORTED;\r
+ // Verify PKCS7 SignedData with Revoked database\r
+ //\r
+ if (RevokedDb != NULL) {\r
+ Status = P7CheckRevocationByHash (\r
+ Signature,\r
+ SignatureSize,\r
+ InHash,\r
+ InHashSize,\r
+ RevokedDb,\r
+ TimeStampDb\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // The PKCS7 SignedData is reovked\r
+ //\r
+ return EFI_SECURITY_VIOLATION;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Verify PKCS7 SignedData with AllowedDB\r
+ //\r
+ Status = P7CheckTrustByHash (\r
+ Signature,\r
+ SignatureSize,\r
+ InHash,\r
+ InHashSize,\r
+ AllowedDb\r
+ );\r
+\r
+ return Status;\r
}\r
\r
//\r