Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:jejb1:UEFI
OVMF
pkcs7verify-add-signature.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File pkcs7verify-add-signature.diff of Package OVMF
From a7c4ce23f5aea8c48a2772b6cfac8dab37c0199b Mon Sep 17 00:00:00 2001 From: James Bottomley <James.Bottomley@HansenPartnership.com> Date: Tue, 23 Feb 2016 15:53:50 -0800 Subject: [PATCH 3/3] Pkcs7VerifyDxe: Preliminary additions for implementing VerifySignature Implement verification by hash in spite of the flaws (if the hash is the wrong algorithm, revocation by hash will not work). Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> --- .../Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c | 378 ++++++++++++++++++++- 1 file changed, 375 insertions(+), 3 deletions(-) diff --git a/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c b/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c index 07fdf55..319e11a 100644 --- a/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c +++ b/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c @@ -116,6 +116,81 @@ _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 +524,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 +853,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. @@ -997,11 +1331,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; } // -- 2.6.6
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor