mirror of https://github.com/acidanthera/audk.git
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;
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
|
@ -441,6 +517,171 @@ IsValidTimestamp (
|
|||
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
|
||||
certificates database, and if the signedData is timestamped, the embedded timestamp
|
||||
|
@ -606,6 +847,100 @@ _Exit:
|
|||
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
|
||||
database, and return the content of the signedData if requested.
|
||||
|
@ -1051,11 +1386,49 @@ VerifySignature (
|
|||
IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// NOTE: Current EDKII-OpenSSL interface cannot support VerifySignature
|
||||
// directly. EFI_UNSUPPORTED is returned in this version.
|
||||
// Parameters Checking
|
||||
//
|
||||
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…
Reference in New Issue