SecurityPkg: Update DxeImageVerificationLib with following changes:

1. Update to check image digest against dbx before execute it.
2. Update to support revoke certificate.
3. Update to support enroll unsigned PE image's Hash to allowed database (db). (Note: Unsigned Image's Hash is calculated in the same way with authenticode, the algorithm is assumed to be SHA256.)

Signed-off-by: xdu2
Reviewed-by: tye
Reviewed-by: gdong1

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12598 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
xdu2 2011-10-28 09:54:08 +00:00
parent d26727de5f
commit 45bf2c4789
1 changed files with 207 additions and 178 deletions

View File

@ -2,12 +2,12 @@
Implement image verification services for secure boot service in UEFI2.3.1. Implement image verification services for secure boot service in UEFI2.3.1.
Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR> Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/ **/
@ -16,7 +16,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader; EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;
UINTN mImageSize; UINTN mImageSize;
UINT32 mPeCoffHeaderOffset; UINT32 mPeCoffHeaderOffset;
UINT8 mImageDigest[MAX_DIGEST_SIZE]; UINT8 mImageDigest[MAX_DIGEST_SIZE];
UINTN mImageDigestSize; UINTN mImageDigestSize;
EFI_IMAGE_DATA_DIRECTORY *mSecDataDir = NULL; EFI_IMAGE_DATA_DIRECTORY *mSecDataDir = NULL;
@ -59,9 +59,9 @@ HASH_TABLE mHash[] = {
Get the image type. Get the image type.
@param[in] File This is a pointer to the device path of the file that is @param[in] File This is a pointer to the device path of the file that is
being dispatched. being dispatched.
@return UINT32 Image Type @return UINT32 Image Type
**/ **/
UINT32 UINT32
@ -70,7 +70,7 @@ GetImageType (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_HANDLE DeviceHandle; EFI_HANDLE DeviceHandle;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO_PROTOCOL *BlockIo;
@ -78,7 +78,7 @@ GetImageType (
// First check to see if File is from a Firmware Volume // First check to see if File is from a Firmware Volume
// //
DeviceHandle = NULL; DeviceHandle = NULL;
TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
Status = gBS->LocateDevicePath ( Status = gBS->LocateDevicePath (
&gEfiFirmwareVolume2ProtocolGuid, &gEfiFirmwareVolume2ProtocolGuid,
&TempDevicePath, &TempDevicePath,
@ -102,7 +102,7 @@ GetImageType (
// Next check to see if File is from a Block I/O device // Next check to see if File is from a Block I/O device
// //
DeviceHandle = NULL; DeviceHandle = NULL;
TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
Status = gBS->LocateDevicePath ( Status = gBS->LocateDevicePath (
&gEfiBlockIoProtocolGuid, &gEfiBlockIoProtocolGuid,
&TempDevicePath, &TempDevicePath,
@ -136,11 +136,11 @@ GetImageType (
} }
// //
// File is not in a Firmware Volume or on a Block I/O device, so check to see if // File is not in a Firmware Volume or on a Block I/O device, so check to see if
// the device path supports the Simple File System Protocol. // the device path supports the Simple File System Protocol.
// //
DeviceHandle = NULL; DeviceHandle = NULL;
TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
Status = gBS->LocateDevicePath ( Status = gBS->LocateDevicePath (
&gEfiSimpleFileSystemProtocolGuid, &gEfiSimpleFileSystemProtocolGuid,
&TempDevicePath, &TempDevicePath,
@ -155,12 +155,12 @@ GetImageType (
// //
// File is not from an FV, Block I/O or Simple File System, so the only options // File is not from an FV, Block I/O or Simple File System, so the only options
// left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.
// //
TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
while (!IsDevicePathEndType (TempDevicePath)) { while (!IsDevicePathEndType (TempDevicePath)) {
switch (DevicePathType (TempDevicePath)) { switch (DevicePathType (TempDevicePath)) {
case MEDIA_DEVICE_PATH: case MEDIA_DEVICE_PATH:
if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) { if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {
return IMAGE_FROM_OPTION_ROM; return IMAGE_FROM_OPTION_ROM;
@ -170,7 +170,7 @@ GetImageType (
case MESSAGING_DEVICE_PATH: case MESSAGING_DEVICE_PATH:
if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) { if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {
return IMAGE_FROM_REMOVABLE_MEDIA; return IMAGE_FROM_REMOVABLE_MEDIA;
} }
break; break;
default: default:
@ -178,7 +178,7 @@ GetImageType (
} }
TempDevicePath = NextDevicePathNode (TempDevicePath); TempDevicePath = NextDevicePathNode (TempDevicePath);
} }
return IMAGE_UNKNOWN; return IMAGE_UNKNOWN;
} }
/** /**
@ -186,12 +186,12 @@ GetImageType (
PE/COFF Specification 8.0 Appendix A PE/COFF Specification 8.0 Appendix A
@param[in] HashAlg Hash algorithm type. @param[in] HashAlg Hash algorithm type.
@retval TRUE Successfully hash image. @retval TRUE Successfully hash image.
@retval FALSE Fail in hash image. @retval FALSE Fail in hash image.
**/ **/
BOOLEAN BOOLEAN
HashPeImage ( HashPeImage (
IN UINT32 HashAlg IN UINT32 HashAlg
) )
@ -208,8 +208,8 @@ HashPeImage (
UINTN Index; UINTN Index;
UINTN Pos; UINTN Pos;
UINTN SumOfSectionBytes; UINTN SumOfSectionBytes;
EFI_IMAGE_SECTION_HEADER *SectionCache; EFI_IMAGE_SECTION_HEADER *SectionCache;
HashCtx = NULL; HashCtx = NULL;
SectionHeader = NULL; SectionHeader = NULL;
Status = FALSE; Status = FALSE;
@ -217,7 +217,7 @@ HashPeImage (
if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) { if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {
return FALSE; return FALSE;
} }
// //
// Initialize context of hash. // Initialize context of hash.
// //
@ -234,7 +234,7 @@ HashPeImage (
} }
CtxSize = mHash[HashAlg].GetContextSize(); CtxSize = mHash[HashAlg].GetContextSize();
HashCtx = AllocatePool (CtxSize); HashCtx = AllocatePool (CtxSize);
if (HashCtx == NULL) { if (HashCtx == NULL) {
return FALSE; return FALSE;
@ -244,7 +244,7 @@ HashPeImage (
// 2. Initialize a SHA hash context. // 2. Initialize a SHA hash context.
Status = mHash[HashAlg].HashInit(HashCtx); Status = mHash[HashAlg].HashInit(HashCtx);
if (!Status) { if (!Status) {
goto Done; goto Done;
} }
@ -294,7 +294,7 @@ HashPeImage (
} else { } else {
// //
// Use PE32+ offset. // Use PE32+ offset.
// //
HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
} }
@ -353,7 +353,7 @@ HashPeImage (
for (Index = 0, SumOfSectionBytes = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++, SectionCache++) { for (Index = 0, SumOfSectionBytes = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++, SectionCache++) {
SumOfSectionBytes += SectionCache->SizeOfRawData; SumOfSectionBytes += SectionCache->SizeOfRawData;
} }
// //
// Sanity check for file corruption. Sections raw data size should be smaller // Sanity check for file corruption. Sections raw data size should be smaller
// than Image Size. // than Image Size.
@ -436,7 +436,7 @@ HashPeImage (
HashSize = (UINTN)( HashSize = (UINTN)(
mImageSize - mImageSize -
mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
SumOfBytesHashed); SumOfBytesHashed);
} }
Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
@ -457,15 +457,15 @@ Done:
} }
/** /**
Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of
Pe/Coff image based on the authenticode image hashing in PE/COFF Specification Pe/Coff image based on the authenticode image hashing in PE/COFF Specification
8.0 Appendix A 8.0 Appendix A
@retval EFI_UNSUPPORTED Hash algorithm is not supported. @retval EFI_UNSUPPORTED Hash algorithm is not supported.
@retval EFI_SUCCESS Hash successfully. @retval EFI_SUCCESS Hash successfully.
**/ **/
EFI_STATUS EFI_STATUS
HashPeImageByType ( HashPeImageByType (
VOID VOID
) )
@ -475,10 +475,10 @@ HashPeImageByType (
PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress); PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);
for (Index = 0; Index < HASHALG_MAX; Index++) { for (Index = 0; Index < HASHALG_MAX; Index++) {
// //
// Check the Hash algorithm in PE/COFF Authenticode. // Check the Hash algorithm in PE/COFF Authenticode.
// According to PKCS#7 Definition: // According to PKCS#7 Definition:
// SignedData ::= SEQUENCE { // SignedData ::= SEQUENCE {
// version Version, // version Version,
// digestAlgorithms DigestAlgorithmIdentifiers, // digestAlgorithms DigestAlgorithmIdentifiers,
@ -486,7 +486,7 @@ HashPeImageByType (
// .... } // .... }
// The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
// This field has the fixed offset (+32) in final Authenticode ASN.1 data. // This field has the fixed offset (+32) in final Authenticode ASN.1 data.
// //
if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) { if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
break; break;
} }
@ -514,7 +514,7 @@ HashPeImageByType (
ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned. ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.
@param ImageExeInfoTable A pointer to a image execution info table structure. @param ImageExeInfoTable A pointer to a image execution info table structure.
@retval 0 If ImageExeInfoTable is NULL. @retval 0 If ImageExeInfoTable is NULL.
@retval Others The size of a image execution info table in bytes. @retval Others The size of a image execution info table in bytes.
@ -550,12 +550,12 @@ GetImageExeInfoTableSize (
@param[in] DevicePath Input device path pointer. @param[in] DevicePath Input device path pointer.
@param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure. @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.
@param[in] SignatureSize Size of signature. @param[in] SignatureSize Size of signature.
**/ **/
VOID VOID
AddImageExeInfo ( AddImageExeInfo (
IN EFI_IMAGE_EXECUTION_ACTION Action, IN EFI_IMAGE_EXECUTION_ACTION Action,
IN CHAR16 *Name OPTIONAL, IN CHAR16 *Name OPTIONAL,
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
IN EFI_SIGNATURE_LIST *Signature OPTIONAL, IN EFI_SIGNATURE_LIST *Signature OPTIONAL,
IN UINTN SignatureSize IN UINTN SignatureSize
@ -577,13 +577,13 @@ AddImageExeInfo (
if (DevicePath == NULL) { if (DevicePath == NULL) {
return ; return ;
} }
if (Name != NULL) { if (Name != NULL) {
NameStringLen = StrSize (Name); NameStringLen = StrSize (Name);
} }
ImageExeInfoTable = NULL; ImageExeInfoTable = NULL;
EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID**)&ImageExeInfoTable); EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);
if (ImageExeInfoTable != NULL) { if (ImageExeInfoTable != NULL) {
// //
// The table has been found! // The table has been found!
@ -637,7 +637,7 @@ AddImageExeInfo (
// Update/replace the image execution table. // Update/replace the image execution table.
// //
gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable); gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);
// //
// Free Old table data! // Free Old table data!
// //
@ -649,7 +649,7 @@ AddImageExeInfo (
/** /**
Discover if the UEFI image is authorized by user's policy setting. Discover if the UEFI image is authorized by user's policy setting.
@param[in] Policy Specify platform's policy setting. @param[in] Policy Specify platform's policy setting.
@retval EFI_ACCESS_DENIED Image is not allowed to run. @retval EFI_ACCESS_DENIED Image is not allowed to run.
@retval EFI_SECURITY_VIOLATION Image is deferred. @retval EFI_SECURITY_VIOLATION Image is deferred.
@ -667,7 +667,7 @@ ImageAuthorization (
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
switch (Policy) { switch (Policy) {
case QUERY_USER_ON_SECURITY_VIOLATION: case QUERY_USER_ON_SECURITY_VIOLATION:
do { do {
CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL); CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL);
@ -715,7 +715,7 @@ ImageAuthorization (
BOOLEAN BOOLEAN
IsSignatureFoundInDatabase ( IsSignatureFoundInDatabase (
IN CHAR16 *VariableName, IN CHAR16 *VariableName,
IN UINT8 *Signature, IN UINT8 *Signature,
IN EFI_GUID *CertType, IN EFI_GUID *CertType,
IN UINTN SignatureSize IN UINTN SignatureSize
) )
@ -786,16 +786,20 @@ Done:
} }
/** /**
Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format . Verify PKCS#7 SignedData using certificate found in Variable which formatted
as EFI_SIGNATURE_LIST. The Variable may be PK, KEK, DB or DBX.
@retval EFI_SUCCESS Image pass verification. @param VariableName Name of Variable to search for Certificate.
@retval EFI_SECURITY_VIOLATION Image fail verification. @param VendorGuid Variable vendor GUID.
@retval EFI_OUT_OF_RESOURCE Fail to allocate memory.
@retval TRUE Image pass verification.
@retval FALSE Image fail verification.
**/ **/
EFI_STATUS BOOLEAN
VerifyCertPkcsSignedData ( IsPkcsSignedDataVerifiedBySignatureList (
VOID IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
@ -804,55 +808,50 @@ VerifyCertPkcsSignedData (
EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_LIST *CertList;
EFI_SIGNATURE_DATA *Cert; EFI_SIGNATURE_DATA *Cert;
UINTN DataSize; UINTN DataSize;
UINT8 *KekData; UINT8 *Data;
UINT8 *DbData;
UINT8 *RootCert; UINT8 *RootCert;
UINTN RootCertSize; UINTN RootCertSize;
UINTN Index; UINTN Index;
UINTN CertCount; UINTN CertCount;
KekData = NULL; Data = NULL;
DbData = NULL; CertList = NULL;
CertList = NULL; Cert = NULL;
Cert = NULL; RootCert = NULL;
RootCert = NULL; RootCertSize = 0;
RootCertSize = 0; VerifyStatus = FALSE;
VerifyStatus = FALSE; PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);
PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);
//
// 1: Find certificate from KEK database and try to verify authenticode struct.
//
DataSize = 0; DataSize = 0;
Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL); Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);
if (Status == EFI_BUFFER_TOO_SMALL) { if (Status == EFI_BUFFER_TOO_SMALL) {
KekData = (UINT8 *)AllocateZeroPool (DataSize); Data = (UINT8 *) AllocateZeroPool (DataSize);
if (KekData == NULL) { if (Data == NULL) {
return EFI_OUT_OF_RESOURCES; return VerifyStatus;
} }
Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, (VOID *)KekData); Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, (VOID *) Data);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Done; goto Done;
} }
// //
// Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data. // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.
// //
CertList = (EFI_SIGNATURE_LIST *) KekData; CertList = (EFI_SIGNATURE_LIST *) Data;
while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
for (Index = 0; Index < CertCount; Index++) { for (Index = 0; Index < CertCount; Index++) {
// //
// Iterate each Signature Data Node within this CertList for a verify // Iterate each Signature Data Node within this CertList for verify.
// //
RootCert = Cert->SignatureData; RootCert = Cert->SignatureData;
RootCertSize = CertList->SignatureSize; RootCertSize = CertList->SignatureSize;
// //
// Call AuthenticodeVerify library to Verify Authenticode struct. // Call AuthenticodeVerify library to Verify Authenticode struct.
// //
VerifyStatus = AuthenticodeVerify ( VerifyStatus = AuthenticodeVerify (
PkcsCertData->CertData, PkcsCertData->CertData,
@ -862,68 +861,11 @@ VerifyCertPkcsSignedData (
mImageDigest, mImageDigest,
mImageDigestSize mImageDigestSize
); );
if (VerifyStatus) { if (VerifyStatus) {
goto Done; goto Done;
} }
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
} }
}
DataSize -= CertList->SignatureListSize;
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
}
}
//
// 2: Find certificate from DB database and try to verify authenticode struct.
//
DataSize = 0;
Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
if (Status == EFI_BUFFER_TOO_SMALL) {
DbData = (UINT8 *)AllocateZeroPool (DataSize);
if (DbData == NULL) {
goto Done;
}
Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)DbData);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data.
//
CertList = (EFI_SIGNATURE_LIST *) DbData;
while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
for (Index = 0; Index < CertCount; Index++) {
//
// Iterate each Signature Data Node within this CertList for a verify
//
RootCert = Cert->SignatureData;
RootCertSize = CertList->SignatureSize;
//
// Call AuthenticodeVerify library to Verify Authenticode struct.
//
VerifyStatus = AuthenticodeVerify (
PkcsCertData->CertData,
mSecDataDir->Size - sizeof(PkcsCertData->Hdr),
RootCert,
RootCertSize,
mImageDigest,
mImageDigestSize
);
if (VerifyStatus) {
goto Done;
}
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
}
} }
DataSize -= CertList->SignatureListSize; DataSize -= CertList->SignatureListSize;
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
@ -931,15 +873,47 @@ VerifyCertPkcsSignedData (
} }
Done: Done:
if (KekData != NULL) { if (Data != NULL) {
FreePool (KekData); FreePool (Data);
} }
if (DbData != NULL) { return VerifyStatus;
FreePool (DbData); }
/**
Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format.
@retval EFI_SUCCESS Image pass verification.
@retval EFI_SECURITY_VIOLATION Image fail verification.
**/
EFI_STATUS
VerifyCertPkcsSignedData (
VOID
)
{
//
// 1: Find certificate from DBX forbidden database for revoked certificate.
//
if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {
//
// DBX is forbidden database, if Authenticode verification pass with
// one of the certificate in DBX, this image should be rejected.
//
return EFI_SECURITY_VIOLATION;
} }
if (VerifyStatus) { //
// 2: Find certificate from KEK database and try to verify authenticode struct.
//
if (IsPkcsSignedDataVerifiedBySignatureList (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid)) {
return EFI_SUCCESS;
}
//
// 3: Find certificate from DB database and try to verify authenticode struct.
//
if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {
return EFI_SUCCESS; return EFI_SUCCESS;
} else { } else {
return EFI_SECURITY_VIOLATION; return EFI_SECURITY_VIOLATION;
@ -947,14 +921,14 @@ Done:
} }
/** /**
Verify certificate in WIN_CERTIFICATE_UEFI_GUID format. Verify certificate in WIN_CERTIFICATE_UEFI_GUID format.
@retval EFI_SUCCESS Image pass verification. @retval EFI_SUCCESS Image pass verification.
@retval EFI_SECURITY_VIOLATION Image fail verification. @retval EFI_SECURITY_VIOLATION Image fail verification.
@retval other error value @retval other error value
**/ **/
EFI_STATUS EFI_STATUS
VerifyCertUefiGuid ( VerifyCertUefiGuid (
VOID VOID
) )
@ -1004,7 +978,7 @@ VerifyCertUefiGuid (
if (KekList == NULL) { if (KekList == NULL) {
return EFI_SECURITY_VIOLATION; return EFI_SECURITY_VIOLATION;
} }
// //
// Enumerate all Kek items in this list to verify the variable certificate data. // Enumerate all Kek items in this list to verify the variable certificate data.
// If anyone is authenticated successfully, it means the variable is correct! // If anyone is authenticated successfully, it means the variable is correct!
@ -1024,7 +998,7 @@ VerifyCertUefiGuid (
KekDataSize -= KekList->SignatureListSize; KekDataSize -= KekList->SignatureListSize;
KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize); KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);
} }
if (!IsFound) { if (!IsFound) {
// //
// Signed key is not a trust one. // Signed key is not a trust one.
@ -1041,8 +1015,8 @@ VerifyCertUefiGuid (
Status = FALSE; Status = FALSE;
goto Done; goto Done;
} }
// //
// Set RSA Key Components. // Set RSA Key Components.
// NOTE: Only N and E are needed to be set as RSA public key for signature verification. // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
// //
@ -1058,13 +1032,13 @@ VerifyCertUefiGuid (
// Verify the signature. // Verify the signature.
// //
Status = RsaPkcs1Verify ( Status = RsaPkcs1Verify (
Rsa, Rsa,
mImageDigest, mImageDigest,
mImageDigestSize, mImageDigestSize,
CertBlock->Signature, CertBlock->Signature,
EFI_CERT_TYPE_RSA2048_SHA256_SIZE EFI_CERT_TYPE_RSA2048_SHA256_SIZE
); );
Done: Done:
if (KekList != NULL) { if (KekList != NULL) {
FreePool (KekList); FreePool (KekList);
@ -1081,13 +1055,31 @@ Done:
/** /**
Provide verification service for signed images, which include both signature validation Provide verification service for signed images, which include both signature validation
and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
MSFT Authenticode type signatures are supported. MSFT Authenticode type signatures are supported.
In this implementation, only verify external executables when in USER MODE.
Executables from FV is bypass, so pass in AuthenticationStatus is ignored.
@param[in] AuthenticationStatus In this implementation, only verify external executables when in USER MODE.
Executables from FV is bypass, so pass in AuthenticationStatus is ignored.
The image verification process is:
Is the Image signed?
If yes,
Does the image verify against a certificate (root or intermediate) in the allowed db?
Run it
Image verification fail
Is the Image's Hash not in forbidden database and the Image's Hash in allowed db?
Run it
If no,
Is the Image's Hash in the forbidden database (DBX)?
if yes,
Error out
Is the Image's Hash in the allowed database (DB)?
If yes,
Run it
If no,
Error out
@param[in] AuthenticationStatus
This is the authentication status returned from the security This is the authentication status returned from the security
measurement services for the input file. measurement services for the input file.
@param[in] File This is a pointer to the device path of the file that is @param[in] File This is a pointer to the device path of the file that is
@ -1144,7 +1136,7 @@ DxeImageVerificationHandler (
// Check the image type and get policy setting. // Check the image type and get policy setting.
// //
switch (GetImageType (File)) { switch (GetImageType (File)) {
case IMAGE_FROM_FV: case IMAGE_FROM_FV:
Policy = ALWAYS_EXECUTE; Policy = ALWAYS_EXECUTE;
break; break;
@ -1162,7 +1154,7 @@ DxeImageVerificationHandler (
break; break;
default: default:
Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION; Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
break; break;
} }
// //
@ -1188,8 +1180,8 @@ DxeImageVerificationHandler (
if (*SecureBootEnable == SECURE_BOOT_DISABLE) { if (*SecureBootEnable == SECURE_BOOT_DISABLE) {
FreePool (SecureBootEnable); FreePool (SecureBootEnable);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME); SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);
// //
@ -1216,10 +1208,10 @@ DxeImageVerificationHandler (
} }
mImageBase = (UINT8 *) FileBuffer; mImageBase = (UINT8 *) FileBuffer;
mImageSize = FileSize; mImageSize = FileSize;
DosHdr = (EFI_IMAGE_DOS_HEADER *) (mImageBase); DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
// //
// DOS image header is present, // DOS image header is present,
// so read the PE header after the DOS image header. // so read the PE header after the DOS image header.
// //
mPeCoffHeaderOffset = DosHdr->e_lfanew; mPeCoffHeaderOffset = DosHdr->e_lfanew;
@ -1242,12 +1234,12 @@ DxeImageVerificationHandler (
// //
// Use PE32 offset. // Use PE32 offset.
// //
mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
} else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
// //
// Use PE32+ offset. // Use PE32+ offset.
// //
mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
} else { } else {
// //
// Invalid header magic number. // Invalid header magic number.
@ -1268,21 +1260,45 @@ DxeImageVerificationHandler (
// //
// This image is not signed. // This image is not signed.
// //
if (!HashPeImage (HASHALG_SHA256)) {
goto Done;
}
if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
//
// Image Hash is in forbidden database (DBX).
//
Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
Status = EFI_ACCESS_DENIED;
goto Done;
}
if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
//
// Image Hash is in allowed database (DB).
//
return EFI_SUCCESS;
}
//
// Image Hash is not found in both forbidden and allowed database.
//
Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto Done; goto Done;
} }
// //
// Verify signature of executables. // Verify signature of executables.
// //
WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress); WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);
switch (WinCertificate->wCertificateType) { switch (WinCertificate->wCertificateType) {
case WIN_CERT_TYPE_EFI_GUID: case WIN_CERT_TYPE_EFI_GUID:
// //
// Verify UEFI GUID type. // Verify UEFI GUID type.
// //
if (!HashPeImage (HASHALG_SHA256)) { if (!HashPeImage (HASHALG_SHA256)) {
goto Done; goto Done;
} }
@ -1295,7 +1311,7 @@ DxeImageVerificationHandler (
// Verify Pkcs signed data type. // Verify Pkcs signed data type.
// //
Status = HashPeImageByType(); Status = HashPeImageByType();
if (EFI_ERROR(Status)) { if (EFI_ERROR (Status)) {
goto Done; goto Done;
} }
@ -1306,11 +1322,15 @@ DxeImageVerificationHandler (
// no need to check image's hash in the allowed database. // no need to check image's hash in the allowed database.
// //
if (!EFI_ERROR (VerifyStatus)) { if (!EFI_ERROR (VerifyStatus)) {
return EFI_SUCCESS; if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
return EFI_SUCCESS;
}
} }
break;
default: default:
return EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
goto Done;
} }
// //
// Get image hash value as executable's signature. // Get image hash value as executable's signature.
@ -1334,8 +1354,17 @@ DxeImageVerificationHandler (
// //
// Verification failure. // Verification failure.
// //
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED; if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize) &&
Status = EFI_ACCESS_DENIED; IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
//
// Verification fail, Image Hash is not in forbidden database (DBX),
// and Image Hash is in allowed database (DB).
//
Status = EFI_SUCCESS;
} else {
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
Status = EFI_ACCESS_DENIED;
}
} else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) { } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) {
// //
// Executable signature verification passes, but is found in forbidden signature database. // Executable signature verification passes, but is found in forbidden signature database.
@ -1375,10 +1404,10 @@ Done:
/** /**
When VariableWriteArchProtocol install, create "SecureBoot" variable. When VariableWriteArchProtocol install, create "SecureBoot" variable.
@param[in] Event Event whose notification function is being invoked. @param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context. @param[in] Context Pointer to the notification function's context.
**/ **/
VOID VOID
EFIAPI EFIAPI
@ -1396,7 +1425,7 @@ VariableWriteCallBack (
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return; return;
} }
// //
// Check whether "SecureBoot" variable exists. // Check whether "SecureBoot" variable exists.
// If this library is built-in, it means firmware has capability to perform // If this library is built-in, it means firmware has capability to perform
@ -1418,7 +1447,7 @@ VariableWriteCallBack (
} else { } else {
FreePool (SecureBootModePtr); FreePool (SecureBootModePtr);
} }
} }
/** /**
Register security measurement handler. Register security measurement handler.
@ -1439,7 +1468,7 @@ DxeImageVerificationLibConstructor (
// //
// Register callback function upon VariableWriteArchProtocol. // Register callback function upon VariableWriteArchProtocol.
// //
EfiCreateProtocolNotifyEvent ( EfiCreateProtocolNotifyEvent (
&gEfiVariableWriteArchProtocolGuid, &gEfiVariableWriteArchProtocolGuid,
TPL_CALLBACK, TPL_CALLBACK,
@ -1451,5 +1480,5 @@ DxeImageVerificationLibConstructor (
return RegisterSecurityHandler ( return RegisterSecurityHandler (
DxeImageVerificationHandler, DxeImageVerificationHandler,
EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
); );
} }