diff options
author | Long Qin <qin.long@intel.com> | 2017-09-05 15:46:21 +0800 |
---|---|---|
committer | Long Qin <qin.long@intel.com> | 2017-09-05 15:47:31 +0800 |
commit | a2481f81b357c892c8eda725836f255cf4f72879 (patch) | |
tree | b264016b1b47376febbed9eb30dd091e9545a1ed /SecurityPkg/Pkcs7Verify | |
parent | 023387144299741d727521b425ef443438aecc1f (diff) | |
download | edk2-a2481f81b357c892c8eda725836f255cf4f72879.zip edk2-a2481f81b357c892c8eda725836f255cf4f72879.tar.gz edk2-a2481f81b357c892c8eda725836f255cf4f72879.tar.bz2 |
SecurityPkg/Pkcs7Verify: Complete the Pkcs7VerifyDxe protocol
VerifySignature can be implemented using a mirror of the
AuthenticodeVerify function that's already in use in the
ImageVerificationDXE environment, so this patch simply wires up
VerifySignature using that code.
<NOTE: Only Authenticode-signature verification was supported by
this VerifySignature() implementation now.)
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Reviewed-by: Long Qin <qin.long@intel.com>
Diffstat (limited to 'SecurityPkg/Pkcs7Verify')
-rw-r--r-- | SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c | 379 |
1 files changed, 376 insertions, 3 deletions
diff --git a/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c b/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c index 3776f90..d901321 100644 --- a/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c +++ b/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c @@ -116,6 +116,82 @@ _Exit: /**
Check whether the hash of data content is revoked by the revocation database.
+ @param[in] Hash Pointer to the hash that is searched for.
+ @param[in] HashSize The size of the hash in bytes.
+ @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structure which contains list of X.509 certificates
+ of revoked signers and revoked content hashes.
+
+ @return TRUE The matched content hash is found in the revocation database.
+ @return FALSE The matched content hash is not found in the revocation database.
+
+**/
+BOOLEAN
+IsContentHashRevokedByHash (
+ IN UINT8 *Hash,
+ IN UINTN HashSize,
+ IN EFI_SIGNATURE_LIST **RevokedDb
+ )
+{
+ EFI_SIGNATURE_LIST *SigList;
+ EFI_SIGNATURE_DATA *SigData;
+ UINTN Index;
+ UINTN EntryIndex;
+ UINTN EntryCount;
+ BOOLEAN Status;
+
+ if (RevokedDb == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+ //
+ // Check if any hash matching content hash can be found in RevokedDB
+ //
+ for (Index = 0; ; Index++) {
+ SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);
+
+ //
+ // The list is terminated by a NULL pointer.
+ //
+ if (SigList == NULL) {
+ break;
+ }
+
+ //
+ // Search the signature database to search the revoked content hash
+ //
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
+ SigList->SignatureHeaderSize);
+ EntryCount = (SigList->SignatureListSize - SigList->SignatureHeaderSize -
+ sizeof (EFI_SIGNATURE_LIST)) / SigList->SignatureSize;
+ for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex++) {
+ //
+ // The problem case. There's a revocation hash but the sizes
+ // don't match, meaning it's a different hash algorithm and we
+ // can't tell if it's revoking our binary or not. Assume not.
+ //
+ if (SigList->SignatureSize - sizeof(EFI_GUID) == HashSize) {
+ //
+ // Compare Data Hash with Signature Data
+ //
+ if (CompareMem (SigData->SignatureData, Hash, HashSize) == 0) {
+ Status = TRUE;
+ goto _Exit;
+ }
+ }
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigData + SigList->SignatureSize);
+ }
+ }
+
+_Exit:
+ return Status;
+}
+
+/**
+ Check whether the hash of data content is revoked by the revocation database.
+
@param[in] Content Pointer to the content buffer that is searched for.
@param[in] ContentSize The size of data content in bytes.
@param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
@@ -449,6 +525,171 @@ IsValidTimestamp ( @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
signature.
@param[in] SignedDataSize The size of SignedData buffer in bytes.
+ @param[in] InHash Pointer to the buffer containing the hash of the mesage data
+ previously signed and to be verified.
+ @param[in] InHashSize The size of InHash buffer in bytes.
+ @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structure which contains list of X.509 certificates
+ of revoked signers and revoked content hashes.
+ @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structures which is used to pass a list of X.509
+ certificates of trusted timestamp signers.
+
+ @retval EFI_SUCCESS The PKCS7 signedData is revoked.
+ @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.
+ @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
+ AllowedDb is NULL.
+ Content is not NULL and ContentSize is NULL.
+ @retval EFI_NOT_FOUND Content not found because InData is NULL and no
+ content embedded in PKCS7 signedData.
+ @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.
+
+**/
+EFI_STATUS
+P7CheckRevocationByHash (
+ IN UINT8 *SignedData,
+ IN UINTN SignedDataSize,
+ IN UINT8 *InHash,
+ IN UINTN InHashSize,
+ IN EFI_SIGNATURE_LIST **RevokedDb,
+ IN EFI_SIGNATURE_LIST **TimeStampDb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *SigList;
+ EFI_SIGNATURE_DATA *SigData;
+ UINT8 *RevokedCert;
+ UINTN RevokedCertSize;
+ UINTN Index;
+ UINT8 *CertBuffer;
+ UINTN BufferLength;
+ UINT8 *TrustedCert;
+ UINTN TrustedCertLength;
+ UINT8 CertNumber;
+ UINT8 *CertPtr;
+ UINT8 *Cert;
+ UINTN CertSize;
+ EFI_TIME RevocationTime;
+
+ Status = EFI_SECURITY_VIOLATION;
+ SigData = NULL;
+ RevokedCert = NULL;
+ RevokedCertSize = 0;
+ CertBuffer = NULL;
+ TrustedCert = NULL;
+
+ //
+ // The signedData is revoked if the hash of content existed in RevokedDb
+ //
+ if (IsContentHashRevokedByHash (InHash, InHashSize, RevokedDb)) {
+ Status = EFI_SUCCESS;
+ goto _Exit;
+ }
+
+ //
+ // Check if the signer's certificate can be found in Revoked database
+ //
+ for (Index = 0; ; Index++) {
+ SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);
+
+ //
+ // The list is terminated by a NULL pointer.
+ //
+ if (SigList == NULL) {
+ break;
+ }
+
+ //
+ // Ignore any non-X509-format entry in the list.
+ //
+ if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
+ continue;
+ }
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
+ SigList->SignatureHeaderSize);
+
+ RevokedCert = SigData->SignatureData;
+ RevokedCertSize = SigList->SignatureSize - sizeof (EFI_GUID);
+
+ //
+ // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb
+ //
+ if (AuthenticodeVerify (SignedData, SignedDataSize, RevokedCert, RevokedCertSize, InHash, InHashSize)) {
+ //
+ // The signedData was verified by one entry in Revoked Database
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The signedData was revoked, since it was hit by RevokedDb
+ //
+ goto _Exit;
+ }
+
+ //
+ // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp
+ //
+ if ((TimeStampDb == NULL) || (*TimeStampDb == NULL)) {
+ goto _Exit;
+ }
+
+ Pkcs7GetSigners (SignedData, SignedDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);
+ if ((BufferLength == 0) || (CertBuffer == NULL)) {
+ Status = EFI_SUCCESS;
+ goto _Exit;
+ }
+
+ //
+ // Check if any hash of certificates embedded in P7 data is in the revoked database.
+ //
+ CertNumber = (UINT8) (*CertBuffer);
+ CertPtr = CertBuffer + 1;
+ for (Index = 0; Index < CertNumber; Index++) {
+ //
+ // Retrieve the Certificate data
+ //
+ CertSize = (UINTN) ReadUnaligned32 ((UINT32 *) CertPtr);
+ Cert = (UINT8 *)CertPtr + sizeof (UINT32);
+
+ if (IsCertHashRevoked (Cert, CertSize, RevokedDb, &RevocationTime)) {
+ //
+ // Check the timestamp signature and signing time to determine if p7 data can be trusted.
+ //
+ Status = EFI_SUCCESS;
+ if (IsValidTimestamp (SignedData, SignedDataSize, TimeStampDb, &RevocationTime)) {
+ //
+ // Use EFI_NOT_READY to identify the P7Data is not reovked, because the timestamping
+ // occured prior to the time of certificate revocation.
+ //
+ Status = EFI_NOT_READY;
+ }
+
+ goto _Exit;
+ }
+
+ CertPtr = CertPtr + sizeof (UINT32) + CertSize;
+ }
+
+_Exit:
+ Pkcs7FreeSigners (CertBuffer);
+ Pkcs7FreeSigners (TrustedCert);
+
+ return Status;
+}
+
+/**
+ Check whether the PKCS7 signedData is revoked by verifying with the revoked
+ certificates database, and if the signedData is timestamped, the embedded timestamp
+ couterSignature will be checked with the supplied timestamp database.
+
+ @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
+ signature.
+ @param[in] SignedDataSize The size of SignedData buffer in bytes.
@param[in] InData Pointer to the buffer containing the raw message data
previously signed and to be verified.
@param[in] InDataSize The size of InData buffer in bytes.
@@ -613,6 +854,100 @@ _Exit: @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
signature.
@param[in] SignedDataSize The size of SignedData buffer in bytes.
+ @param[in] InHash Pointer to the buffer containing the hash of the message data
+ previously signed and to be verified.
+ @param[in] InHashSize The size of InHash buffer in bytes.
+ @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structures which contains lists of X.509 certificates
+ of approved signers.
+
+ @retval EFI_SUCCESS The PKCS7 signedData is trusted.
+ @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.
+ @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
+ AllowedDb is NULL.
+ Content is not NULL and ContentSize is NULL.
+ @retval EFI_NOT_FOUND Content not found because InData is NULL and no
+ content embedded in PKCS7 signedData.
+ @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.
+ @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too
+ small to hold the content. ContentSize updated to
+ the required size.
+
+**/
+EFI_STATUS
+P7CheckTrustByHash (
+ IN UINT8 *SignedData,
+ IN UINTN SignedDataSize,
+ IN UINT8 *InHash,
+ IN UINTN InHashSize,
+ IN EFI_SIGNATURE_LIST **AllowedDb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *SigList;
+ EFI_SIGNATURE_DATA *SigData;
+ UINT8 *TrustCert;
+ UINTN TrustCertSize;
+ UINTN Index;
+
+ Status = EFI_SECURITY_VIOLATION;
+ SigData = NULL;
+ TrustCert = NULL;
+ TrustCertSize = 0;
+
+ if (AllowedDb == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Build Certificate Stack with all valid X509 certificates in the supplied
+ // Signature List for PKCS7 Verification.
+ //
+ for (Index = 0; ; Index++) {
+ SigList = (EFI_SIGNATURE_LIST *)(AllowedDb[Index]);
+
+ //
+ // The list is terminated by a NULL pointer.
+ //
+ if (SigList == NULL) {
+ break;
+ }
+
+ //
+ // Ignore any non-X509-format entry in the list.
+ //
+ if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
+ continue;
+ }
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
+ SigList->SignatureHeaderSize);
+
+ TrustCert = SigData->SignatureData;
+ TrustCertSize = SigList->SignatureSize - sizeof (EFI_GUID);
+
+ //
+ // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb
+ //
+ if (AuthenticodeVerify (SignedData, SignedDataSize, TrustCert, TrustCertSize, InHash, InHashSize)) {
+ //
+ // The SignedData was verified successfully by one entry in Trusted Database
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the PKCS7 signedData can be verified by the trusted certificates
+ database, and return the content of the signedData if requested.
+
+ @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
+ signature.
+ @param[in] SignedDataSize The size of SignedData buffer in bytes.
@param[in] InData Pointer to the buffer containing the raw message data
previously signed and to be verified.
@param[in] InDataSize The size of InData buffer in bytes.
@@ -1051,11 +1386,49 @@ VerifySignature ( IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL
)
{
+ EFI_STATUS Status;
+
+ //
+ // Parameters Checking
//
- // NOTE: Current EDKII-OpenSSL interface cannot support VerifySignature
- // directly. EFI_UNSUPPORTED is returned in this version.
+ if ((Signature == NULL) || (SignatureSize == 0) || (AllowedDb == NULL)
+ || (InHash == NULL) || (InHashSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
//
- return EFI_UNSUPPORTED;
+ // Verify PKCS7 SignedData with Revoked database
+ //
+ if (RevokedDb != NULL) {
+ Status = P7CheckRevocationByHash (
+ Signature,
+ SignatureSize,
+ InHash,
+ InHashSize,
+ RevokedDb,
+ TimeStampDb
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The PKCS7 SignedData is reovked
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+
+ //
+ // Verify PKCS7 SignedData with AllowedDB
+ //
+ Status = P7CheckTrustByHash (
+ Signature,
+ SignatureSize,
+ InHash,
+ InHashSize,
+ AllowedDb
+ );
+
+ return Status;
}
//
|