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>
This commit is contained in:
parent
0233871442
commit
a2481f81b3
@ -113,6 +113,82 @@ _Exit:
|
|||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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.
|
Check whether the hash of data content is revoked by the revocation database.
|
||||||
|
|
||||||
@ -441,6 +517,171 @@ IsValidTimestamp (
|
|||||||
return Status;
|
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] 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
|
Check whether the PKCS7 signedData is revoked by verifying with the revoked
|
||||||
certificates database, and if the signedData is timestamped, the embedded timestamp
|
certificates database, and if the signedData is timestamped, the embedded timestamp
|
||||||
@ -606,6 +847,100 @@ _Exit:
|
|||||||
return Status;
|
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] 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
|
Check whether the PKCS7 signedData can be verified by the trusted certificates
|
||||||
database, and return the content of the signedData if requested.
|
database, and return the content of the signedData if requested.
|
||||||
@ -1051,11 +1386,49 @@ VerifySignature (
|
|||||||
IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL
|
IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
//
|
//
|
||||||
// NOTE: Current EDKII-OpenSSL interface cannot support VerifySignature
|
// Parameters Checking
|
||||||
// directly. EFI_UNSUPPORTED is returned in this version.
|
|
||||||
//
|
//
|
||||||
return EFI_UNSUPPORTED;
|
if ((Signature == NULL) || (SignatureSize == 0) || (AllowedDb == NULL)
|
||||||
|
|| (InHash == NULL) || (InHashSize == 0)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
Loading…
x
Reference in New Issue
Block a user