2011-09-02 09:49:32 +02:00
/** @file
2015-06-23 12:48:30 +02:00
Implement image verification services for secure boot service
2011-09-02 09:49:32 +02:00
2012-06-12 10:28:43 +02:00
Caution : This file requires additional review when modified .
This library will have external input - PE / COFF image .
This external input must be validated carefully to avoid security issue like
buffer overflow , integer overflow .
DxeImageVerificationLibImageRead ( ) function will make sure the PE / COFF image content
read is within the image buffer .
DxeImageVerificationHandler ( ) , HashPeImageByType ( ) , HashPeImage ( ) function will accept
untrusted PE / COFF image and validate its data structure within this image buffer before use .
2016-04-13 10:25:50 +02:00
Copyright ( c ) 2009 - 2016 , Intel Corporation . All rights reserved . < BR >
2016-05-13 06:24:59 +02:00
( C ) Copyright 2016 Hewlett Packard Enterprise Development LP < BR >
2011-10-28 11:54:08 +02:00
This program and the accompanying materials
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
2011-09-02 09:49:32 +02:00
http : //opensource.org/licenses/bsd-license.php
2011-10-28 11:54:08 +02:00
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN " AS IS " BASIS ,
2011-09-02 09:49:32 +02:00
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND , EITHER EXPRESS OR IMPLIED .
* */
# include "DxeImageVerificationLib.h"
2012-06-12 10:28:43 +02:00
//
// Caution: This is used by a function which may receive untrusted input.
// These global variables hold PE/COFF image data, and they should be validated before use.
//
2011-09-02 09:49:32 +02:00
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader ;
2011-10-28 11:54:08 +02:00
UINT32 mPeCoffHeaderOffset ;
2011-09-02 09:49:32 +02:00
EFI_GUID mCertType ;
2012-06-12 10:28:43 +02:00
//
// Information on current PE/COFF image
//
UINTN mImageSize ;
UINT8 * mImageBase = NULL ;
UINT8 mImageDigest [ MAX_DIGEST_SIZE ] ;
UINTN mImageDigestSize ;
2011-09-02 09:49:32 +02:00
//
// Notify string for authorization UI.
//
CHAR16 mNotifyString1 [ MAX_NOTIFY_STRING_LEN ] = L " Image verification pass but not found in authorized database! " ;
CHAR16 mNotifyString2 [ MAX_NOTIFY_STRING_LEN ] = L " Launch this image anyway? (Yes/Defer/No) " ;
//
// Public Exponent of RSA Key.
//
CONST UINT8 mRsaE [ ] = { 0x01 , 0x00 , 0x01 } ;
//
// OID ASN.1 Value for Hash Algorithms
//
UINT8 mHashOidValue [ ] = {
0x2B , 0x0E , 0x03 , 0x02 , 0x1A , // OBJ_sha1
0x60 , 0x86 , 0x48 , 0x01 , 0x65 , 0x03 , 0x04 , 0x02 , 0x04 , // OBJ_sha224
0x60 , 0x86 , 0x48 , 0x01 , 0x65 , 0x03 , 0x04 , 0x02 , 0x01 , // OBJ_sha256
0x60 , 0x86 , 0x48 , 0x01 , 0x65 , 0x03 , 0x04 , 0x02 , 0x02 , // OBJ_sha384
0x60 , 0x86 , 0x48 , 0x01 , 0x65 , 0x03 , 0x04 , 0x02 , 0x03 , // OBJ_sha512
} ;
HASH_TABLE mHash [ ] = {
2014-11-14 09:41:12 +01:00
{ L " SHA1 " , 20 , & mHashOidValue [ 0 ] , 5 , Sha1GetContextSize , Sha1Init , Sha1Update , Sha1Final } ,
{ L " SHA224 " , 28 , & mHashOidValue [ 5 ] , 9 , NULL , NULL , NULL , NULL } ,
{ L " SHA256 " , 32 , & mHashOidValue [ 14 ] , 9 , Sha256GetContextSize , Sha256Init , Sha256Update , Sha256Final } ,
{ L " SHA384 " , 48 , & mHashOidValue [ 23 ] , 9 , Sha384GetContextSize , Sha384Init , Sha384Update , Sha384Final } ,
{ L " SHA512 " , 64 , & mHashOidValue [ 32 ] , 9 , Sha512GetContextSize , Sha512Init , Sha512Update , Sha512Final }
2011-09-02 09:49:32 +02:00
} ;
2016-05-13 06:24:59 +02:00
EFI_STRING mHashTypeStr ;
2013-09-18 07:31:18 +02:00
/**
SecureBoot Hook for processing image verification .
@ param [ in ] VariableName Name of Variable to be found .
@ param [ in ] VendorGuid Variable vendor GUID .
@ param [ in ] DataSize Size of Data found . If size is less than the
data , this value contains the required size .
@ param [ in ] Data Data pointer .
* */
VOID
EFIAPI
SecureBootHook (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
IN UINTN DataSize ,
IN VOID * Data
) ;
2012-04-24 05:00:32 +02:00
/**
Reads contents of a PE / COFF image in memory buffer .
2012-06-12 10:28:43 +02:00
Caution : This function may receive untrusted input .
PE / COFF image is external input , so this function will make sure the PE / COFF image content
read is within the image buffer .
2012-04-24 05:00:32 +02:00
@ param FileHandle Pointer to the file handle to read the PE / COFF image .
@ param FileOffset Offset into the PE / COFF image to begin the read operation .
2014-11-14 09:41:12 +01:00
@ param ReadSize On input , the size in bytes of the requested read operation .
2012-04-24 05:00:32 +02:00
On output , the number of bytes actually read .
@ param Buffer Output buffer that contains the data read from the PE / COFF image .
2014-11-14 09:41:12 +01:00
@ retval EFI_SUCCESS The specified portion of the PE / COFF image was read and the size
2012-04-24 05:00:32 +02:00
* */
EFI_STATUS
EFIAPI
2012-04-26 03:50:34 +02:00
DxeImageVerificationLibImageRead (
2012-04-24 05:00:32 +02:00
IN VOID * FileHandle ,
IN UINTN FileOffset ,
IN OUT UINTN * ReadSize ,
OUT VOID * Buffer
)
{
UINTN EndPosition ;
if ( FileHandle = = NULL | | ReadSize = = NULL | | Buffer = = NULL ) {
2014-11-14 09:41:12 +01:00
return EFI_INVALID_PARAMETER ;
2012-04-24 05:00:32 +02:00
}
if ( MAX_ADDRESS - FileOffset < * ReadSize ) {
return EFI_INVALID_PARAMETER ;
}
EndPosition = FileOffset + * ReadSize ;
if ( EndPosition > mImageSize ) {
* ReadSize = ( UINT32 ) ( mImageSize - FileOffset ) ;
}
if ( FileOffset > = mImageSize ) {
* ReadSize = 0 ;
}
CopyMem ( Buffer , ( UINT8 * ) ( ( UINTN ) FileHandle + FileOffset ) , * ReadSize ) ;
return EFI_SUCCESS ;
}
2011-09-02 09:49:32 +02:00
/**
Get the image type .
@ param [ in ] File This is a pointer to the device path of the file that is
2011-10-28 11:54:08 +02:00
being dispatched .
2011-09-02 09:49:32 +02:00
2011-10-28 11:54:08 +02:00
@ return UINT32 Image Type
2011-09-02 09:49:32 +02:00
* */
UINT32
GetImageType (
IN CONST EFI_DEVICE_PATH_PROTOCOL * File
)
{
EFI_STATUS Status ;
2011-10-28 11:54:08 +02:00
EFI_HANDLE DeviceHandle ;
2011-09-02 09:49:32 +02:00
EFI_DEVICE_PATH_PROTOCOL * TempDevicePath ;
EFI_BLOCK_IO_PROTOCOL * BlockIo ;
2012-08-22 04:33:00 +02:00
if ( File = = NULL ) {
return IMAGE_UNKNOWN ;
}
2011-09-02 09:49:32 +02:00
//
// First check to see if File is from a Firmware Volume
//
DeviceHandle = NULL ;
2011-10-28 11:54:08 +02:00
TempDevicePath = ( EFI_DEVICE_PATH_PROTOCOL * ) File ;
2011-09-02 09:49:32 +02:00
Status = gBS - > LocateDevicePath (
& gEfiFirmwareVolume2ProtocolGuid ,
& TempDevicePath ,
& DeviceHandle
) ;
if ( ! EFI_ERROR ( Status ) ) {
Status = gBS - > OpenProtocol (
DeviceHandle ,
& gEfiFirmwareVolume2ProtocolGuid ,
NULL ,
NULL ,
NULL ,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
) ;
if ( ! EFI_ERROR ( Status ) ) {
return IMAGE_FROM_FV ;
}
}
//
// Next check to see if File is from a Block I/O device
//
DeviceHandle = NULL ;
2011-10-28 11:54:08 +02:00
TempDevicePath = ( EFI_DEVICE_PATH_PROTOCOL * ) File ;
2011-09-02 09:49:32 +02:00
Status = gBS - > LocateDevicePath (
& gEfiBlockIoProtocolGuid ,
& TempDevicePath ,
& DeviceHandle
) ;
if ( ! EFI_ERROR ( Status ) ) {
BlockIo = NULL ;
Status = gBS - > OpenProtocol (
DeviceHandle ,
& gEfiBlockIoProtocolGuid ,
( VOID * * ) & BlockIo ,
NULL ,
NULL ,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
) ;
if ( ! EFI_ERROR ( Status ) & & BlockIo ! = NULL ) {
if ( BlockIo - > Media ! = NULL ) {
if ( BlockIo - > Media - > RemovableMedia ) {
//
// Block I/O is present and specifies the media is removable
//
return IMAGE_FROM_REMOVABLE_MEDIA ;
} else {
//
// Block I/O is present and specifies the media is not removable
//
return IMAGE_FROM_FIXED_MEDIA ;
}
}
}
}
//
2011-10-28 11:54:08 +02:00
// File is not in a Firmware Volume or on a Block I/O device, so check to see if
2011-09-02 09:49:32 +02:00
// the device path supports the Simple File System Protocol.
//
DeviceHandle = NULL ;
2011-10-28 11:54:08 +02:00
TempDevicePath = ( EFI_DEVICE_PATH_PROTOCOL * ) File ;
2011-09-02 09:49:32 +02:00
Status = gBS - > LocateDevicePath (
& gEfiSimpleFileSystemProtocolGuid ,
& TempDevicePath ,
& DeviceHandle
) ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Simple File System is present without Block I/O, so assume media is fixed.
//
return IMAGE_FROM_FIXED_MEDIA ;
}
//
// File is not from an FV, Block I/O or Simple File System, so the only options
2011-10-28 11:54:08 +02:00
// left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.
2011-09-02 09:49:32 +02:00
//
2011-10-28 11:54:08 +02:00
TempDevicePath = ( EFI_DEVICE_PATH_PROTOCOL * ) File ;
2011-09-02 09:49:32 +02:00
while ( ! IsDevicePathEndType ( TempDevicePath ) ) {
switch ( DevicePathType ( TempDevicePath ) ) {
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
case MEDIA_DEVICE_PATH :
if ( DevicePathSubType ( TempDevicePath ) = = MEDIA_RELATIVE_OFFSET_RANGE_DP ) {
return IMAGE_FROM_OPTION_ROM ;
}
break ;
case MESSAGING_DEVICE_PATH :
if ( DevicePathSubType ( TempDevicePath ) = = MSG_MAC_ADDR_DP ) {
return IMAGE_FROM_REMOVABLE_MEDIA ;
2011-10-28 11:54:08 +02:00
}
2011-09-02 09:49:32 +02:00
break ;
default :
break ;
}
TempDevicePath = NextDevicePathNode ( TempDevicePath ) ;
}
2011-10-28 11:54:08 +02:00
return IMAGE_UNKNOWN ;
2011-09-02 09:49:32 +02:00
}
/**
2015-03-13 09:25:27 +01:00
Calculate hash of Pe / Coff image based on the authenticode image hashing in
2011-09-02 09:49:32 +02:00
PE / COFF Specification 8.0 Appendix A
2012-06-12 10:28:43 +02:00
Caution : This function may receive untrusted input .
PE / COFF image is external input , so this function will validate its data structure
within this image buffer before use .
2011-09-02 09:49:32 +02:00
@ param [ in ] HashAlg Hash algorithm type .
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
@ retval TRUE Successfully hash image .
@ retval FALSE Fail in hash image .
* */
2011-10-28 11:54:08 +02:00
BOOLEAN
2011-09-02 09:49:32 +02:00
HashPeImage (
IN UINT32 HashAlg
)
{
BOOLEAN Status ;
UINT16 Magic ;
EFI_IMAGE_SECTION_HEADER * Section ;
VOID * HashCtx ;
UINTN CtxSize ;
UINT8 * HashBase ;
UINTN HashSize ;
UINTN SumOfBytesHashed ;
EFI_IMAGE_SECTION_HEADER * SectionHeader ;
UINTN Index ;
UINTN Pos ;
2012-04-28 09:48:15 +02:00
UINT32 CertSize ;
UINT32 NumberOfRvaAndSizes ;
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
HashCtx = NULL ;
SectionHeader = NULL ;
Status = FALSE ;
2014-11-14 09:41:12 +01:00
if ( ( HashAlg > = HASHALG_MAX ) ) {
2011-09-02 09:49:32 +02:00
return FALSE ;
}
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
//
// Initialize context of hash.
//
ZeroMem ( mImageDigest , MAX_DIGEST_SIZE ) ;
2014-11-14 09:41:12 +01:00
switch ( HashAlg ) {
case HASHALG_SHA1 :
mImageDigestSize = SHA1_DIGEST_SIZE ;
mCertType = gEfiCertSha1Guid ;
break ;
case HASHALG_SHA256 :
mImageDigestSize = SHA256_DIGEST_SIZE ;
mCertType = gEfiCertSha256Guid ;
break ;
case HASHALG_SHA384 :
mImageDigestSize = SHA384_DIGEST_SIZE ;
mCertType = gEfiCertSha384Guid ;
break ;
case HASHALG_SHA512 :
mImageDigestSize = SHA512_DIGEST_SIZE ;
mCertType = gEfiCertSha512Guid ;
break ;
default :
2011-09-02 09:49:32 +02:00
return FALSE ;
}
2016-05-13 06:24:59 +02:00
mHashTypeStr = mHash [ HashAlg ] . Name ;
2011-09-02 09:49:32 +02:00
CtxSize = mHash [ HashAlg ] . GetContextSize ( ) ;
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
HashCtx = AllocatePool ( CtxSize ) ;
2011-09-21 07:23:55 +02:00
if ( HashCtx = = NULL ) {
return FALSE ;
}
2011-09-02 09:49:32 +02:00
// 1. Load the image header into memory.
// 2. Initialize a SHA hash context.
Status = mHash [ HashAlg ] . HashInit ( HashCtx ) ;
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
if ( ! Status ) {
goto Done ;
}
2012-04-28 09:48:15 +02:00
2011-09-02 09:49:32 +02:00
//
// Measuring PE/COFF Image Header;
// But CheckSum field and SECURITY data directory (certificate) are excluded
//
2012-06-08 04:09:48 +02:00
if ( mNtHeader . Pe32 - > FileHeader . Machine = = IMAGE_FILE_MACHINE_IA64 & & mNtHeader . Pe32 - > OptionalHeader . Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
2014-11-14 09:41:12 +01:00
// NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
// in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
2012-06-08 04:09:48 +02:00
// Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
// then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
//
Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC ;
} else {
//
// Get the magic value from the PE/COFF Optional Header
//
Magic = mNtHeader . Pe32 - > OptionalHeader . Magic ;
}
2014-11-14 09:41:12 +01:00
2011-09-02 09:49:32 +02:00
//
// 3. Calculate the distance from the base of the image header to the image checksum address.
// 4. Hash the image header from its base to beginning of the image checksum.
//
HashBase = mImageBase ;
if ( Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
// Use PE32 offset.
//
HashSize = ( UINTN ) ( ( UINT8 * ) ( & mNtHeader . Pe32 - > OptionalHeader . CheckSum ) - HashBase ) ;
2012-04-28 09:48:15 +02:00
NumberOfRvaAndSizes = mNtHeader . Pe32 - > OptionalHeader . NumberOfRvaAndSizes ;
2011-09-21 07:23:55 +02:00
} else if ( Magic = = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC ) {
2011-09-02 09:49:32 +02:00
//
// Use PE32+ offset.
//
HashSize = ( UINTN ) ( ( UINT8 * ) ( & mNtHeader . Pe32Plus - > OptionalHeader . CheckSum ) - HashBase ) ;
2012-04-28 09:48:15 +02:00
NumberOfRvaAndSizes = mNtHeader . Pe32Plus - > OptionalHeader . NumberOfRvaAndSizes ;
2011-09-21 07:23:55 +02:00
} else {
//
// Invalid header magic number.
//
Status = FALSE ;
goto Done ;
2011-09-02 09:49:32 +02:00
}
Status = mHash [ HashAlg ] . HashUpdate ( HashCtx , HashBase , HashSize ) ;
if ( ! Status ) {
goto Done ;
}
2012-04-28 09:48:15 +02:00
2011-09-02 09:49:32 +02:00
//
// 5. Skip over the image checksum (it occupies a single ULONG).
//
2012-04-28 09:48:15 +02:00
if ( NumberOfRvaAndSizes < = EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ) {
2011-09-02 09:49:32 +02:00
//
2012-04-28 09:48:15 +02:00
// 6. Since there is no Cert Directory in optional header, hash everything
// from the end of the checksum to the end of image header.
2011-09-02 09:49:32 +02:00
//
2012-04-28 09:48:15 +02:00
if ( Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
// Use PE32 offset.
//
HashBase = ( UINT8 * ) & mNtHeader . Pe32 - > OptionalHeader . CheckSum + sizeof ( UINT32 ) ;
HashSize = mNtHeader . Pe32 - > OptionalHeader . SizeOfHeaders - ( UINTN ) ( HashBase - mImageBase ) ;
} else {
//
// Use PE32+ offset.
//
HashBase = ( UINT8 * ) & mNtHeader . Pe32Plus - > OptionalHeader . CheckSum + sizeof ( UINT32 ) ;
HashSize = mNtHeader . Pe32Plus - > OptionalHeader . SizeOfHeaders - ( UINTN ) ( HashBase - mImageBase ) ;
}
if ( HashSize ! = 0 ) {
Status = mHash [ HashAlg ] . HashUpdate ( HashCtx , HashBase , HashSize ) ;
if ( ! Status ) {
goto Done ;
}
}
2011-09-02 09:49:32 +02:00
} else {
//
2012-04-28 09:48:15 +02:00
// 7. Hash everything from the end of the checksum to the start of the Cert Directory.
2011-10-28 11:54:08 +02:00
//
2012-04-28 09:48:15 +02:00
if ( Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
// Use PE32 offset.
//
HashBase = ( UINT8 * ) & mNtHeader . Pe32 - > OptionalHeader . CheckSum + sizeof ( UINT32 ) ;
HashSize = ( UINTN ) ( ( UINT8 * ) ( & mNtHeader . Pe32 - > OptionalHeader . DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ] ) - HashBase ) ;
} else {
//
// Use PE32+ offset.
//
HashBase = ( UINT8 * ) & mNtHeader . Pe32Plus - > OptionalHeader . CheckSum + sizeof ( UINT32 ) ;
HashSize = ( UINTN ) ( ( UINT8 * ) ( & mNtHeader . Pe32Plus - > OptionalHeader . DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ] ) - HashBase ) ;
}
if ( HashSize ! = 0 ) {
Status = mHash [ HashAlg ] . HashUpdate ( HashCtx , HashBase , HashSize ) ;
if ( ! Status ) {
goto Done ;
}
}
2011-09-02 09:49:32 +02:00
//
2012-04-28 09:48:15 +02:00
// 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
// 9. Hash everything from the end of the Cert Directory to the end of image header.
2011-09-02 09:49:32 +02:00
//
2012-04-28 09:48:15 +02:00
if ( Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
// Use PE32 offset
//
HashBase = ( UINT8 * ) & mNtHeader . Pe32 - > OptionalHeader . DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1 ] ;
HashSize = mNtHeader . Pe32 - > OptionalHeader . SizeOfHeaders - ( UINTN ) ( HashBase - mImageBase ) ;
} else {
//
// Use PE32+ offset.
//
HashBase = ( UINT8 * ) & mNtHeader . Pe32Plus - > OptionalHeader . DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1 ] ;
HashSize = mNtHeader . Pe32Plus - > OptionalHeader . SizeOfHeaders - ( UINTN ) ( HashBase - mImageBase ) ;
}
2011-09-02 09:49:32 +02:00
2012-04-28 09:48:15 +02:00
if ( HashSize ! = 0 ) {
Status = mHash [ HashAlg ] . HashUpdate ( HashCtx , HashBase , HashSize ) ;
if ( ! Status ) {
goto Done ;
}
2014-11-14 09:41:12 +01:00
}
2011-09-02 09:49:32 +02:00
}
2012-04-28 09:48:15 +02:00
2011-09-02 09:49:32 +02:00
//
// 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
//
if ( Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
// Use PE32 offset.
//
SumOfBytesHashed = mNtHeader . Pe32 - > OptionalHeader . SizeOfHeaders ;
} else {
//
// Use PE32+ offset
//
SumOfBytesHashed = mNtHeader . Pe32Plus - > OptionalHeader . SizeOfHeaders ;
}
2011-09-21 07:23:55 +02:00
Section = ( EFI_IMAGE_SECTION_HEADER * ) (
mImageBase +
mPeCoffHeaderOffset +
sizeof ( UINT32 ) +
sizeof ( EFI_IMAGE_FILE_HEADER ) +
mNtHeader . Pe32 - > FileHeader . SizeOfOptionalHeader
) ;
2011-09-02 09:49:32 +02:00
//
// 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
// structures in the image. The 'NumberOfSections' field of the image
// header indicates how big the table should be. Do not include any
// IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
//
SectionHeader = ( EFI_IMAGE_SECTION_HEADER * ) AllocateZeroPool ( sizeof ( EFI_IMAGE_SECTION_HEADER ) * mNtHeader . Pe32 - > FileHeader . NumberOfSections ) ;
2011-09-21 07:23:55 +02:00
if ( SectionHeader = = NULL ) {
Status = FALSE ;
goto Done ;
}
2011-09-02 09:49:32 +02:00
//
// 12. Using the 'PointerToRawData' in the referenced section headers as
// a key, arrange the elements in the table in ascending order. In other
// words, sort the section headers according to the disk-file offset of
// the section.
//
for ( Index = 0 ; Index < mNtHeader . Pe32 - > FileHeader . NumberOfSections ; Index + + ) {
Pos = Index ;
while ( ( Pos > 0 ) & & ( Section - > PointerToRawData < SectionHeader [ Pos - 1 ] . PointerToRawData ) ) {
CopyMem ( & SectionHeader [ Pos ] , & SectionHeader [ Pos - 1 ] , sizeof ( EFI_IMAGE_SECTION_HEADER ) ) ;
Pos - - ;
}
CopyMem ( & SectionHeader [ Pos ] , Section , sizeof ( EFI_IMAGE_SECTION_HEADER ) ) ;
Section + = 1 ;
}
//
// 13. Walk through the sorted table, bring the corresponding section
// into memory, and hash the entire section (using the 'SizeOfRawData'
// field in the section header to determine the amount of data to hash).
// 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
// 15. Repeat steps 13 and 14 for all the sections in the sorted table.
//
for ( Index = 0 ; Index < mNtHeader . Pe32 - > FileHeader . NumberOfSections ; Index + + ) {
Section = & SectionHeader [ Index ] ;
if ( Section - > SizeOfRawData = = 0 ) {
continue ;
}
HashBase = mImageBase + Section - > PointerToRawData ;
HashSize = ( UINTN ) Section - > SizeOfRawData ;
Status = mHash [ HashAlg ] . HashUpdate ( HashCtx , HashBase , HashSize ) ;
if ( ! Status ) {
goto Done ;
}
SumOfBytesHashed + = HashSize ;
}
//
// 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
// data in the file that needs to be added to the hash. This data begins
// at file offset SUM_OF_BYTES_HASHED and its length is:
// FileSize - (CertDirectory->Size)
//
if ( mImageSize > SumOfBytesHashed ) {
HashBase = mImageBase + SumOfBytesHashed ;
2012-04-28 09:48:15 +02:00
if ( NumberOfRvaAndSizes < = EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ) {
CertSize = 0 ;
2011-09-02 09:49:32 +02:00
} else {
2012-04-28 09:48:15 +02:00
if ( Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
// Use PE32 offset.
//
CertSize = mNtHeader . Pe32 - > OptionalHeader . DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ] . Size ;
} else {
//
// Use PE32+ offset.
//
CertSize = mNtHeader . Pe32Plus - > OptionalHeader . DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ] . Size ;
2012-04-24 05:00:32 +02:00
}
2011-09-02 09:49:32 +02:00
}
2012-04-28 09:48:15 +02:00
if ( mImageSize > CertSize + SumOfBytesHashed ) {
HashSize = ( UINTN ) ( mImageSize - CertSize - SumOfBytesHashed ) ;
Status = mHash [ HashAlg ] . HashUpdate ( HashCtx , HashBase , HashSize ) ;
if ( ! Status ) {
goto Done ;
}
} else if ( mImageSize < CertSize + SumOfBytesHashed ) {
Status = FALSE ;
2011-09-02 09:49:32 +02:00
goto Done ;
}
}
2012-04-28 09:48:15 +02:00
2011-09-02 09:49:32 +02:00
Status = mHash [ HashAlg ] . HashFinal ( HashCtx , mImageDigest ) ;
Done :
if ( HashCtx ! = NULL ) {
FreePool ( HashCtx ) ;
}
if ( SectionHeader ! = NULL ) {
FreePool ( SectionHeader ) ;
}
return Status ;
}
/**
2015-03-13 09:25:27 +01:00
Recognize the Hash algorithm in PE / COFF Authenticode and calculate hash of
2011-10-28 11:54:08 +02:00
Pe / Coff image based on the authenticode image hashing in PE / COFF Specification
2011-09-02 09:49:32 +02:00
8.0 Appendix A
2012-06-12 10:28:43 +02:00
Caution : This function may receive untrusted input .
PE / COFF image is external input , so this function will validate its data structure
within this image buffer before use .
2012-08-23 09:55:35 +02:00
@ param [ in ] AuthData Pointer to the Authenticode Signature retrieved from signed image .
@ param [ in ] AuthDataSize Size of the Authenticode Signature in bytes .
2014-11-14 09:41:12 +01:00
2011-09-02 09:49:32 +02:00
@ retval EFI_UNSUPPORTED Hash algorithm is not supported .
@ retval EFI_SUCCESS Hash successfully .
* */
2011-10-28 11:54:08 +02:00
EFI_STATUS
2011-09-02 09:49:32 +02:00
HashPeImageByType (
2012-08-23 09:55:35 +02:00
IN UINT8 * AuthData ,
IN UINTN AuthDataSize
2011-09-02 09:49:32 +02:00
)
{
UINT8 Index ;
2012-05-08 04:53:49 +02:00
2011-10-28 11:54:08 +02:00
for ( Index = 0 ; Index < HASHALG_MAX ; Index + + ) {
2011-09-02 09:49:32 +02:00
//
// Check the Hash algorithm in PE/COFF Authenticode.
2011-10-28 11:54:08 +02:00
// According to PKCS#7 Definition:
2011-09-02 09:49:32 +02:00
// SignedData ::= SEQUENCE {
// version Version,
// digestAlgorithms DigestAlgorithmIdentifiers,
// contentInfo ContentInfo,
// .... }
// 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.
2012-03-19 06:10:46 +01:00
// Fixed offset (+32) is calculated based on two bytes of length encoding.
2011-10-28 11:54:08 +02:00
//
2012-08-23 09:55:35 +02:00
if ( ( * ( AuthData + 1 ) & TWO_BYTE_ENCODE ) ! = TWO_BYTE_ENCODE ) {
2012-03-19 06:10:46 +01:00
//
// Only support two bytes of Long Form of Length Encoding.
//
continue ;
}
2012-08-23 09:55:35 +02:00
if ( AuthDataSize < 32 + mHash [ Index ] . OidLength ) {
2012-05-08 04:53:49 +02:00
return EFI_UNSUPPORTED ;
}
2012-08-23 09:55:35 +02:00
if ( CompareMem ( AuthData + 32 , mHash [ Index ] . OidValue , mHash [ Index ] . OidLength ) = = 0 ) {
2011-09-02 09:49:32 +02:00
break ;
}
}
if ( Index = = HASHALG_MAX ) {
return EFI_UNSUPPORTED ;
}
//
// HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
//
if ( ! HashPeImage ( Index ) ) {
return EFI_UNSUPPORTED ;
}
return EFI_SUCCESS ;
}
/**
Returns the size of a given image execution info table in bytes .
This function returns the size , in bytes , of the image execution info table specified by
ImageExeInfoTable . If ImageExeInfoTable is NULL , then 0 is returned .
@ param ImageExeInfoTable A pointer to a image execution info table structure .
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
@ retval 0 If ImageExeInfoTable is NULL .
@ retval Others The size of a image execution info table in bytes .
* */
UINTN
GetImageExeInfoTableSize (
EFI_IMAGE_EXECUTION_INFO_TABLE * ImageExeInfoTable
)
{
UINTN Index ;
EFI_IMAGE_EXECUTION_INFO * ImageExeInfoItem ;
UINTN TotalSize ;
if ( ImageExeInfoTable = = NULL ) {
return 0 ;
}
ImageExeInfoItem = ( EFI_IMAGE_EXECUTION_INFO * ) ( ( UINT8 * ) ImageExeInfoTable + sizeof ( EFI_IMAGE_EXECUTION_INFO_TABLE ) ) ;
TotalSize = sizeof ( EFI_IMAGE_EXECUTION_INFO_TABLE ) ;
for ( Index = 0 ; Index < ImageExeInfoTable - > NumberOfImages ; Index + + ) {
TotalSize + = ReadUnaligned32 ( ( UINT32 * ) & ImageExeInfoItem - > InfoSize ) ;
ImageExeInfoItem = ( EFI_IMAGE_EXECUTION_INFO * ) ( ( UINT8 * ) ImageExeInfoItem + ReadUnaligned32 ( ( UINT32 * ) & ImageExeInfoItem - > InfoSize ) ) ;
}
return TotalSize ;
}
/**
Create an Image Execution Information Table entry and add it to system configuration table .
@ param [ in ] Action Describes the action taken by the firmware regarding this image .
@ param [ in ] Name Input a null - terminated , user - friendly name .
@ param [ in ] DevicePath Input device path pointer .
@ param [ in ] Signature Input signature info in EFI_SIGNATURE_LIST data structure .
@ param [ in ] SignatureSize Size of signature .
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
* */
VOID
AddImageExeInfo (
2011-10-28 11:54:08 +02:00
IN EFI_IMAGE_EXECUTION_ACTION Action ,
IN CHAR16 * Name OPTIONAL ,
2011-09-02 09:49:32 +02:00
IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath ,
IN EFI_SIGNATURE_LIST * Signature OPTIONAL ,
IN UINTN SignatureSize
)
{
EFI_IMAGE_EXECUTION_INFO_TABLE * ImageExeInfoTable ;
EFI_IMAGE_EXECUTION_INFO_TABLE * NewImageExeInfoTable ;
EFI_IMAGE_EXECUTION_INFO * ImageExeInfoEntry ;
UINTN ImageExeInfoTableSize ;
UINTN NewImageExeInfoEntrySize ;
UINTN NameStringLen ;
UINTN DevicePathSize ;
2015-12-07 07:20:02 +01:00
CHAR16 * NameStr ;
2011-09-02 09:49:32 +02:00
ImageExeInfoTable = NULL ;
NewImageExeInfoTable = NULL ;
ImageExeInfoEntry = NULL ;
NameStringLen = 0 ;
2015-12-07 07:20:02 +01:00
NameStr = NULL ;
2011-09-02 09:49:32 +02:00
2011-09-21 07:23:55 +02:00
if ( DevicePath = = NULL ) {
return ;
}
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
if ( Name ! = NULL ) {
NameStringLen = StrSize ( Name ) ;
2012-12-12 04:03:07 +01:00
} else {
NameStringLen = sizeof ( CHAR16 ) ;
2011-09-02 09:49:32 +02:00
}
2011-10-28 11:54:08 +02:00
EfiGetSystemConfigurationTable ( & gEfiImageSecurityDatabaseGuid , ( VOID * * ) & ImageExeInfoTable ) ;
2011-09-02 09:49:32 +02:00
if ( ImageExeInfoTable ! = NULL ) {
//
// The table has been found!
2012-12-12 04:03:07 +01:00
// We must enlarge the table to accomodate the new exe info entry.
2011-09-02 09:49:32 +02:00
//
ImageExeInfoTableSize = GetImageExeInfoTableSize ( ImageExeInfoTable ) ;
} else {
//
// Not Found!
// We should create a new table to append to the configuration table.
//
ImageExeInfoTableSize = sizeof ( EFI_IMAGE_EXECUTION_INFO_TABLE ) ;
}
DevicePathSize = GetDevicePathSize ( DevicePath ) ;
2015-12-07 07:20:02 +01:00
//
// Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align
//
NewImageExeInfoEntrySize = sizeof ( EFI_IMAGE_EXECUTION_INFO ) + NameStringLen + DevicePathSize + SignatureSize ;
2011-09-02 09:49:32 +02:00
NewImageExeInfoTable = ( EFI_IMAGE_EXECUTION_INFO_TABLE * ) AllocateRuntimePool ( ImageExeInfoTableSize + NewImageExeInfoEntrySize ) ;
2011-09-21 07:23:55 +02:00
if ( NewImageExeInfoTable = = NULL ) {
return ;
}
2011-09-02 09:49:32 +02:00
if ( ImageExeInfoTable ! = NULL ) {
CopyMem ( NewImageExeInfoTable , ImageExeInfoTable , ImageExeInfoTableSize ) ;
} else {
NewImageExeInfoTable - > NumberOfImages = 0 ;
}
NewImageExeInfoTable - > NumberOfImages + + ;
ImageExeInfoEntry = ( EFI_IMAGE_EXECUTION_INFO * ) ( ( UINT8 * ) NewImageExeInfoTable + ImageExeInfoTableSize ) ;
//
2014-06-25 04:02:22 +02:00
// Update new item's information.
2011-09-02 09:49:32 +02:00
//
2014-06-25 08:00:49 +02:00
WriteUnaligned32 ( ( UINT32 * ) ImageExeInfoEntry , Action ) ;
WriteUnaligned32 ( ( UINT32 * ) ( ( UINT8 * ) ImageExeInfoEntry + sizeof ( EFI_IMAGE_EXECUTION_ACTION ) ) , ( UINT32 ) NewImageExeInfoEntrySize ) ;
2011-09-02 09:49:32 +02:00
2015-12-07 07:20:02 +01:00
NameStr = ( CHAR16 * ) ( ImageExeInfoEntry + 1 ) ;
2011-09-02 09:49:32 +02:00
if ( Name ! = NULL ) {
2015-12-07 07:20:02 +01:00
CopyMem ( ( UINT8 * ) NameStr , Name , NameStringLen ) ;
2012-12-12 04:03:07 +01:00
} else {
2015-12-07 07:20:02 +01:00
ZeroMem ( ( UINT8 * ) NameStr , sizeof ( CHAR16 ) ) ;
2011-09-02 09:49:32 +02:00
}
2015-12-07 07:20:02 +01:00
2011-09-02 09:49:32 +02:00
CopyMem (
2015-12-07 07:20:02 +01:00
( UINT8 * ) NameStr + NameStringLen ,
2011-09-02 09:49:32 +02:00
DevicePath ,
DevicePathSize
) ;
if ( Signature ! = NULL ) {
CopyMem (
2015-12-07 07:20:02 +01:00
( UINT8 * ) NameStr + NameStringLen + DevicePathSize ,
2011-09-02 09:49:32 +02:00
Signature ,
SignatureSize
) ;
}
//
// Update/replace the image execution table.
//
2011-09-21 07:23:55 +02:00
gBS - > InstallConfigurationTable ( & gEfiImageSecurityDatabaseGuid , ( VOID * ) NewImageExeInfoTable ) ;
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
//
// Free Old table data!
//
if ( ImageExeInfoTable ! = NULL ) {
FreePool ( ImageExeInfoTable ) ;
}
}
2014-11-14 09:41:12 +01:00
/**
Check whether the hash of an given X .509 certificate is in forbidden database ( DBX ) .
@ param [ in ] Certificate Pointer to X .509 Certificate that is searched for .
@ param [ in ] CertSize Size of X .509 Certificate .
@ param [ in ] SignatureList Pointer to the Signature List in forbidden database .
@ param [ in ] SignatureListSize Size of Signature List .
@ param [ out ] RevocationTime Return the time that the certificate was revoked .
@ return TRUE The certificate hash is found in the forbidden database .
@ return FALSE The certificate hash is not found in the forbidden database .
* */
BOOLEAN
IsCertHashFoundInDatabase (
IN UINT8 * Certificate ,
IN UINTN CertSize ,
IN EFI_SIGNATURE_LIST * SignatureList ,
IN UINTN SignatureListSize ,
OUT EFI_TIME * RevocationTime
)
{
BOOLEAN IsFound ;
2014-12-11 07:34:57 +01:00
BOOLEAN Status ;
2014-11-14 09:41:12 +01:00
EFI_SIGNATURE_LIST * DbxList ;
UINTN DbxSize ;
EFI_SIGNATURE_DATA * CertHash ;
UINTN CertHashCount ;
UINTN Index ;
UINT32 HashAlg ;
VOID * HashCtx ;
UINT8 CertDigest [ MAX_DIGEST_SIZE ] ;
UINT8 * DbxCertHash ;
UINTN SiglistHeaderSize ;
2014-12-25 09:37:08 +01:00
UINT8 * TBSCert ;
UINTN TBSCertSize ;
2014-11-14 09:41:12 +01:00
IsFound = FALSE ;
DbxList = SignatureList ;
DbxSize = SignatureListSize ;
HashCtx = NULL ;
HashAlg = HASHALG_MAX ;
2014-12-25 09:37:08 +01:00
if ( ( RevocationTime = = NULL ) | | ( DbxList = = NULL ) ) {
return FALSE ;
}
//
// Retrieve the TBSCertificate from the X.509 Certificate.
//
if ( ! X509GetTBSCert ( Certificate , CertSize , & TBSCert , & TBSCertSize ) ) {
return FALSE ;
}
2014-11-14 09:41:12 +01:00
while ( ( DbxSize > 0 ) & & ( SignatureListSize > = DbxList - > SignatureListSize ) ) {
//
// Determine Hash Algorithm of Certificate in the forbidden database.
//
if ( CompareGuid ( & DbxList - > SignatureType , & gEfiCertX509Sha256Guid ) ) {
HashAlg = HASHALG_SHA256 ;
} else if ( CompareGuid ( & DbxList - > SignatureType , & gEfiCertX509Sha384Guid ) ) {
HashAlg = HASHALG_SHA384 ;
} else if ( CompareGuid ( & DbxList - > SignatureType , & gEfiCertX509Sha512Guid ) ) {
HashAlg = HASHALG_SHA512 ;
} else {
DbxSize - = DbxList - > SignatureListSize ;
DbxList = ( EFI_SIGNATURE_LIST * ) ( ( UINT8 * ) DbxList + DbxList - > SignatureListSize ) ;
continue ;
}
//
2014-12-25 09:37:08 +01:00
// Calculate the hash value of current TBSCertificate for comparision.
2014-11-14 09:41:12 +01:00
//
if ( mHash [ HashAlg ] . GetContextSize = = NULL ) {
goto Done ;
}
ZeroMem ( CertDigest , MAX_DIGEST_SIZE ) ;
HashCtx = AllocatePool ( mHash [ HashAlg ] . GetContextSize ( ) ) ;
if ( HashCtx = = NULL ) {
goto Done ;
}
Status = mHash [ HashAlg ] . HashInit ( HashCtx ) ;
if ( ! Status ) {
goto Done ;
}
2014-12-25 09:37:08 +01:00
Status = mHash [ HashAlg ] . HashUpdate ( HashCtx , TBSCert , TBSCertSize ) ;
2014-11-14 09:41:12 +01:00
if ( ! Status ) {
goto Done ;
}
Status = mHash [ HashAlg ] . HashFinal ( HashCtx , CertDigest ) ;
if ( ! Status ) {
goto Done ;
}
SiglistHeaderSize = sizeof ( EFI_SIGNATURE_LIST ) + DbxList - > SignatureHeaderSize ;
CertHash = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) DbxList + SiglistHeaderSize ) ;
CertHashCount = ( DbxList - > SignatureListSize - SiglistHeaderSize ) / DbxList - > SignatureSize ;
for ( Index = 0 ; Index < CertHashCount ; Index + + ) {
//
// Iterate each Signature Data Node within this CertList for verify.
//
DbxCertHash = CertHash - > SignatureData ;
if ( CompareMem ( DbxCertHash , CertDigest , mHash [ HashAlg ] . DigestLength ) = = 0 ) {
//
// Hash of Certificate is found in forbidden database.
//
IsFound = TRUE ;
//
// Return the revocation time.
//
CopyMem ( RevocationTime , ( EFI_TIME * ) ( DbxCertHash + mHash [ HashAlg ] . DigestLength ) , sizeof ( EFI_TIME ) ) ;
goto Done ;
}
CertHash = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) CertHash + DbxList - > SignatureSize ) ;
}
DbxSize - = DbxList - > SignatureListSize ;
DbxList = ( EFI_SIGNATURE_LIST * ) ( ( UINT8 * ) DbxList + DbxList - > SignatureListSize ) ;
}
Done :
if ( HashCtx ! = NULL ) {
FreePool ( HashCtx ) ;
}
return IsFound ;
}
2011-09-02 09:49:32 +02:00
/**
Check whether signature is in specified database .
@ param [ in ] VariableName Name of database variable that is searched in .
@ param [ in ] Signature Pointer to signature that is searched for .
@ param [ in ] CertType Pointer to hash algrithom .
@ param [ in ] SignatureSize Size of Signature .
@ return TRUE Found the signature in the variable database .
@ return FALSE Not found the signature in the variable database .
* */
BOOLEAN
IsSignatureFoundInDatabase (
IN CHAR16 * VariableName ,
2011-10-28 11:54:08 +02:00
IN UINT8 * Signature ,
2011-09-02 09:49:32 +02:00
IN EFI_GUID * CertType ,
IN UINTN SignatureSize
)
{
EFI_STATUS Status ;
EFI_SIGNATURE_LIST * CertList ;
EFI_SIGNATURE_DATA * Cert ;
UINTN DataSize ;
UINT8 * Data ;
UINTN Index ;
UINTN CertCount ;
BOOLEAN IsFound ;
2014-11-14 09:41:12 +01:00
2011-09-02 09:49:32 +02:00
//
// Read signature database variable.
//
IsFound = FALSE ;
Data = NULL ;
DataSize = 0 ;
Status = gRT - > GetVariable ( VariableName , & gEfiImageSecurityDatabaseGuid , NULL , & DataSize , NULL ) ;
if ( Status ! = EFI_BUFFER_TOO_SMALL ) {
return FALSE ;
}
Data = ( UINT8 * ) AllocateZeroPool ( DataSize ) ;
2011-09-21 07:23:55 +02:00
if ( Data = = NULL ) {
return FALSE ;
}
2011-09-02 09:49:32 +02:00
Status = gRT - > GetVariable ( VariableName , & gEfiImageSecurityDatabaseGuid , NULL , & DataSize , Data ) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
//
// Enumerate all signature data in SigDB to check if executable's signature exists.
//
CertList = ( EFI_SIGNATURE_LIST * ) Data ;
while ( ( DataSize > 0 ) & & ( DataSize > = CertList - > SignatureListSize ) ) {
2013-03-06 02:42:04 +01:00
CertCount = ( CertList - > SignatureListSize - sizeof ( EFI_SIGNATURE_LIST ) - CertList - > SignatureHeaderSize ) / CertList - > SignatureSize ;
2011-09-02 09:49:32 +02:00
Cert = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) CertList + sizeof ( EFI_SIGNATURE_LIST ) + CertList - > SignatureHeaderSize ) ;
if ( ( CertList - > SignatureSize = = sizeof ( EFI_SIGNATURE_DATA ) - 1 + SignatureSize ) & & ( CompareGuid ( & CertList - > SignatureType , CertType ) ) ) {
for ( Index = 0 ; Index < CertCount ; Index + + ) {
if ( CompareMem ( Cert - > SignatureData , Signature , SignatureSize ) = = 0 ) {
//
// Find the signature in database.
//
IsFound = TRUE ;
2013-09-18 07:31:18 +02:00
SecureBootHook ( VariableName , & gEfiImageSecurityDatabaseGuid , CertList - > SignatureSize , Cert ) ;
2011-09-02 09:49:32 +02:00
break ;
}
Cert = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) Cert + CertList - > SignatureSize ) ;
}
if ( IsFound ) {
break ;
}
}
DataSize - = CertList - > SignatureListSize ;
CertList = ( EFI_SIGNATURE_LIST * ) ( ( UINT8 * ) CertList + CertList - > SignatureListSize ) ;
}
Done :
if ( Data ! = NULL ) {
FreePool ( Data ) ;
}
return IsFound ;
}
/**
2014-11-14 09:41:12 +01:00
Check whether the timestamp is valid by comparing the signing time and the revocation time .
2011-09-02 09:49:32 +02:00
2014-11-14 09:41:12 +01:00
@ param SigningTime A pointer to the signing time .
@ param RevocationTime A pointer to the revocation time .
2011-10-28 11:54:08 +02:00
2014-11-14 09:41:12 +01:00
@ retval TRUE The SigningTime is not later than the RevocationTime .
@ retval FALSE The SigningTime is later than the RevocationTime .
2011-09-02 09:49:32 +02:00
* */
2011-10-28 11:54:08 +02:00
BOOLEAN
2014-11-14 09:41:12 +01:00
IsValidSignatureByTimestamp (
IN EFI_TIME * SigningTime ,
IN EFI_TIME * RevocationTime
)
{
if ( SigningTime - > Year ! = RevocationTime - > Year ) {
return ( BOOLEAN ) ( SigningTime - > Year < RevocationTime - > Year ) ;
} else if ( SigningTime - > Month ! = RevocationTime - > Month ) {
return ( BOOLEAN ) ( SigningTime - > Month < RevocationTime - > Month ) ;
} else if ( SigningTime - > Day ! = RevocationTime - > Day ) {
return ( BOOLEAN ) ( SigningTime - > Day < RevocationTime - > Day ) ;
} else if ( SigningTime - > Hour ! = RevocationTime - > Hour ) {
return ( BOOLEAN ) ( SigningTime - > Hour < RevocationTime - > Hour ) ;
} else if ( SigningTime - > Minute ! = RevocationTime - > Minute ) {
return ( BOOLEAN ) ( SigningTime - > Minute < RevocationTime - > Minute ) ;
}
return ( BOOLEAN ) ( SigningTime - > Second < = RevocationTime - > Second ) ;
}
/**
Check if the given time value is zero .
@ param [ in ] Time Pointer of a time value .
@ retval TRUE The Time is Zero .
@ retval FALSE The Time is not Zero .
* */
BOOLEAN
IsTimeZero (
IN EFI_TIME * Time
)
{
if ( ( Time - > Year = = 0 ) & & ( Time - > Month = = 0 ) & & ( Time - > Day = = 0 ) & &
( Time - > Hour = = 0 ) & & ( Time - > Minute = = 0 ) & & ( Time - > Second = = 0 ) ) {
return TRUE ;
}
return FALSE ;
}
/**
Check whether the timestamp signature is valid and the signing time is also earlier than
the revocation time .
@ param [ in ] AuthData Pointer to the Authenticode signature retrieved from signed image .
@ param [ in ] AuthDataSize Size of the Authenticode signature in bytes .
@ param [ in ] RevocationTime The time that the certificate was revoked .
@ retval TRUE Timestamp signature is valid and signing time is no later than the
revocation time .
@ retval FALSE Timestamp signature is not valid or the signing time is later than the
revocation time .
* */
BOOLEAN
PassTimestampCheck (
IN UINT8 * AuthData ,
IN UINTN AuthDataSize ,
IN EFI_TIME * RevocationTime
)
{
EFI_STATUS Status ;
BOOLEAN VerifyStatus ;
EFI_SIGNATURE_LIST * CertList ;
EFI_SIGNATURE_DATA * Cert ;
UINT8 * DbtData ;
UINTN DbtDataSize ;
UINT8 * RootCert ;
UINTN RootCertSize ;
UINTN Index ;
UINTN CertCount ;
EFI_TIME SigningTime ;
//
// Variable Initialization
//
VerifyStatus = FALSE ;
DbtData = NULL ;
CertList = NULL ;
Cert = NULL ;
RootCert = NULL ;
RootCertSize = 0 ;
//
// If RevocationTime is zero, the certificate shall be considered to always be revoked.
//
if ( IsTimeZero ( RevocationTime ) ) {
return FALSE ;
}
//
// RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards.
// Using the dbt to get the trusted TSA certificates.
//
DbtDataSize = 0 ;
Status = gRT - > GetVariable ( EFI_IMAGE_SECURITY_DATABASE2 , & gEfiImageSecurityDatabaseGuid , NULL , & DbtDataSize , NULL ) ;
2014-12-03 08:40:32 +01:00
if ( Status ! = EFI_BUFFER_TOO_SMALL ) {
goto Done ;
}
DbtData = ( UINT8 * ) AllocateZeroPool ( DbtDataSize ) ;
if ( DbtData = = NULL ) {
goto Done ;
}
Status = gRT - > GetVariable ( EFI_IMAGE_SECURITY_DATABASE2 , & gEfiImageSecurityDatabaseGuid , NULL , & DbtDataSize , ( VOID * ) DbtData ) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
2014-11-14 09:41:12 +01:00
}
CertList = ( EFI_SIGNATURE_LIST * ) DbtData ;
while ( ( DbtDataSize > 0 ) & & ( DbtDataSize > = 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 verify.
//
RootCert = Cert - > SignatureData ;
RootCertSize = CertList - > SignatureSize - sizeof ( EFI_GUID ) ;
//
// Get the signing time if the timestamp signature is valid.
//
if ( ImageTimestampVerify ( AuthData , AuthDataSize , RootCert , RootCertSize , & SigningTime ) ) {
//
// The signer signature is valid only when the signing time is earlier than revocation time.
//
if ( IsValidSignatureByTimestamp ( & SigningTime , RevocationTime ) ) {
VerifyStatus = TRUE ;
goto Done ;
}
}
Cert = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) Cert + CertList - > SignatureSize ) ;
}
}
DbtDataSize - = CertList - > SignatureListSize ;
CertList = ( EFI_SIGNATURE_LIST * ) ( ( UINT8 * ) CertList + CertList - > SignatureListSize ) ;
}
Done :
if ( DbtData ! = NULL ) {
FreePool ( DbtData ) ;
}
return VerifyStatus ;
}
/**
Check whether the image signature is forbidden by the forbidden database ( dbx ) .
The image is forbidden to load if any certificates for signing are revoked before signing time .
2016-04-28 07:28:39 +02:00
@ param [ in ] AuthData Pointer to the Authenticode signature retrieved from the signed image .
@ param [ in ] AuthDataSize Size of the Authenticode signature in bytes .
2014-11-14 09:41:12 +01:00
@ retval TRUE Image is forbidden by dbx .
@ retval FALSE Image is not forbidden by dbx .
* */
BOOLEAN
2016-04-28 07:28:39 +02:00
IsForbiddenByDbx (
IN UINT8 * AuthData ,
IN UINTN AuthDataSize
2014-11-14 09:41:12 +01:00
)
{
EFI_STATUS Status ;
BOOLEAN IsForbidden ;
UINT8 * Data ;
UINTN DataSize ;
2015-02-04 09:19:53 +01:00
EFI_SIGNATURE_LIST * CertList ;
UINTN CertListSize ;
EFI_SIGNATURE_DATA * CertData ;
UINT8 * RootCert ;
UINTN RootCertSize ;
UINTN CertCount ;
2014-11-14 09:41:12 +01:00
UINTN Index ;
UINT8 * CertBuffer ;
UINTN BufferLength ;
UINT8 * TrustedCert ;
UINTN TrustedCertLength ;
UINT8 CertNumber ;
UINT8 * CertPtr ;
UINT8 * Cert ;
UINTN CertSize ;
EFI_TIME RevocationTime ;
//
// Variable Initialization
//
IsForbidden = FALSE ;
Data = NULL ;
2015-02-04 09:19:53 +01:00
CertList = NULL ;
CertData = NULL ;
RootCert = NULL ;
RootCertSize = 0 ;
2014-11-14 09:41:12 +01:00
Cert = NULL ;
CertBuffer = NULL ;
BufferLength = 0 ;
TrustedCert = NULL ;
TrustedCertLength = 0 ;
//
// The image will not be forbidden if dbx can't be got.
//
DataSize = 0 ;
Status = gRT - > GetVariable ( EFI_IMAGE_SECURITY_DATABASE1 , & gEfiImageSecurityDatabaseGuid , NULL , & DataSize , NULL ) ;
2014-12-03 08:40:32 +01:00
if ( Status ! = EFI_BUFFER_TOO_SMALL ) {
return IsForbidden ;
2014-11-14 09:41:12 +01:00
}
2014-12-03 08:40:32 +01:00
Data = ( UINT8 * ) AllocateZeroPool ( DataSize ) ;
if ( Data = = NULL ) {
return IsForbidden ;
}
Status = gRT - > GetVariable ( EFI_IMAGE_SECURITY_DATABASE1 , & gEfiImageSecurityDatabaseGuid , NULL , & DataSize , ( VOID * ) Data ) ;
2014-11-14 09:41:12 +01:00
if ( EFI_ERROR ( Status ) ) {
return IsForbidden ;
}
2015-02-04 09:19:53 +01:00
//
// Verify image signature with RAW X509 certificates in DBX database.
// If passed, the image will be forbidden.
//
CertList = ( EFI_SIGNATURE_LIST * ) Data ;
CertListSize = DataSize ;
while ( ( CertListSize > 0 ) & & ( CertListSize > = CertList - > SignatureListSize ) ) {
if ( CompareGuid ( & CertList - > SignatureType , & gEfiCertX509Guid ) ) {
CertData = ( 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 verify.
//
RootCert = CertData - > SignatureData ;
RootCertSize = CertList - > SignatureSize - sizeof ( EFI_GUID ) ;
//
// Call AuthenticodeVerify library to Verify Authenticode struct.
//
IsForbidden = AuthenticodeVerify (
AuthData ,
AuthDataSize ,
RootCert ,
RootCertSize ,
mImageDigest ,
mImageDigestSize
) ;
if ( IsForbidden ) {
2015-06-09 07:20:06 +02:00
SecureBootHook ( EFI_IMAGE_SECURITY_DATABASE1 , & gEfiImageSecurityDatabaseGuid , CertList - > SignatureSize , CertData ) ;
2016-05-13 06:24:59 +02:00
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Image is signed but signature is forbidden by DBX. \n " ) ) ;
2015-02-04 09:19:53 +01:00
goto Done ;
}
CertData = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) CertData + CertList - > SignatureSize ) ;
}
}
CertListSize - = CertList - > SignatureListSize ;
CertList = ( EFI_SIGNATURE_LIST * ) ( ( UINT8 * ) CertList + CertList - > SignatureListSize ) ;
}
//
// Check X.509 Certificate Hash & Possible Timestamp.
//
2014-11-14 09:41:12 +01:00
//
// Retrieve the certificate stack from AuthData
// The output CertStack format will be:
// UINT8 CertNumber;
// UINT32 Cert1Length;
// UINT8 Cert1[];
// UINT32 Cert2Length;
// UINT8 Cert2[];
// ...
// UINT32 CertnLength;
// UINT8 Certn[];
//
Pkcs7GetSigners ( AuthData , AuthDataSize , & CertBuffer , & BufferLength , & TrustedCert , & TrustedCertLength ) ;
2014-12-03 08:40:32 +01:00
if ( ( BufferLength = = 0 ) | | ( CertBuffer = = NULL ) ) {
2014-11-14 09:41:12 +01:00
IsForbidden = TRUE ;
goto Done ;
}
//
2015-02-04 09:19:53 +01:00
// Check if any hash of certificates embedded in AuthData is in the forbidden database.
2014-11-14 09:41:12 +01:00
//
CertNumber = ( UINT8 ) ( * CertBuffer ) ;
CertPtr = CertBuffer + 1 ;
for ( Index = 0 ; Index < CertNumber ; Index + + ) {
CertSize = ( UINTN ) ReadUnaligned32 ( ( UINT32 * ) CertPtr ) ;
Cert = ( UINT8 * ) CertPtr + sizeof ( UINT32 ) ;
2016-04-13 10:25:50 +02:00
//
// Advance CertPtr to the next cert in image signer's cert list
//
CertPtr = CertPtr + sizeof ( UINT32 ) + CertSize ;
2014-11-14 09:41:12 +01:00
if ( IsCertHashFoundInDatabase ( Cert , CertSize , ( EFI_SIGNATURE_LIST * ) Data , DataSize , & RevocationTime ) ) {
//
// Check the timestamp signature and signing time to determine if the image can be trusted.
//
IsForbidden = TRUE ;
if ( PassTimestampCheck ( AuthData , AuthDataSize , & RevocationTime ) ) {
IsForbidden = FALSE ;
2016-04-13 10:25:50 +02:00
//
// Pass DBT check. Continue to check other certs in image signer's cert list against DBX, DBT
//
continue ;
2014-11-14 09:41:12 +01:00
}
2016-05-13 06:24:59 +02:00
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Image is signed but signature failed the timestamp check. \n " ) ) ;
2014-11-14 09:41:12 +01:00
goto Done ;
}
}
Done :
if ( Data ! = NULL ) {
FreePool ( Data ) ;
}
Pkcs7FreeSigners ( CertBuffer ) ;
Pkcs7FreeSigners ( TrustedCert ) ;
return IsForbidden ;
}
2015-12-07 07:20:02 +01:00
2014-11-14 09:41:12 +01:00
/**
Check whether the image signature can be verified by the trusted certificates in DB database .
2016-04-28 07:28:39 +02:00
@ param [ in ] AuthData Pointer to the Authenticode signature retrieved from signed image .
@ param [ in ] AuthDataSize Size of the Authenticode signature in bytes .
2014-11-14 09:41:12 +01:00
@ retval TRUE Image passed verification using certificate in db .
@ retval FALSE Image didn ' t pass verification using certificate in db .
* */
BOOLEAN
IsAllowedByDb (
2016-04-28 07:28:39 +02:00
IN UINT8 * AuthData ,
IN UINTN AuthDataSize
2011-09-02 09:49:32 +02:00
)
{
EFI_STATUS Status ;
BOOLEAN VerifyStatus ;
EFI_SIGNATURE_LIST * CertList ;
2015-12-07 07:20:02 +01:00
EFI_SIGNATURE_DATA * CertData ;
2011-09-02 09:49:32 +02:00
UINTN DataSize ;
2011-10-28 11:54:08 +02:00
UINT8 * Data ;
2011-09-02 09:49:32 +02:00
UINT8 * RootCert ;
UINTN RootCertSize ;
UINTN Index ;
UINTN CertCount ;
2015-02-04 09:19:53 +01:00
UINTN DbxDataSize ;
UINT8 * DbxData ;
EFI_TIME RevocationTime ;
2011-09-02 09:49:32 +02:00
2015-12-07 07:20:02 +01:00
Data = NULL ;
CertList = NULL ;
CertData = NULL ;
RootCert = NULL ;
DbxData = NULL ;
RootCertSize = 0 ;
VerifyStatus = FALSE ;
2011-09-02 09:49:32 +02:00
DataSize = 0 ;
2014-11-14 09:41:12 +01:00
Status = gRT - > GetVariable ( EFI_IMAGE_SECURITY_DATABASE , & gEfiImageSecurityDatabaseGuid , NULL , & DataSize , NULL ) ;
2011-09-02 09:49:32 +02:00
if ( Status = = EFI_BUFFER_TOO_SMALL ) {
2011-10-28 11:54:08 +02:00
Data = ( UINT8 * ) AllocateZeroPool ( DataSize ) ;
if ( Data = = NULL ) {
return VerifyStatus ;
2011-09-21 07:23:55 +02:00
}
2011-09-02 09:49:32 +02:00
2014-11-14 09:41:12 +01:00
Status = gRT - > GetVariable ( EFI_IMAGE_SECURITY_DATABASE , & gEfiImageSecurityDatabaseGuid , NULL , & DataSize , ( VOID * ) Data ) ;
2011-09-02 09:49:32 +02:00
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
2011-10-28 11:54:08 +02:00
//
// Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.
2011-09-02 09:49:32 +02:00
//
2011-10-28 11:54:08 +02:00
CertList = ( EFI_SIGNATURE_LIST * ) Data ;
2011-09-02 09:49:32 +02:00
while ( ( DataSize > 0 ) & & ( DataSize > = CertList - > SignatureListSize ) ) {
if ( CompareGuid ( & CertList - > SignatureType , & gEfiCertX509Guid ) ) {
2015-12-07 07:20:02 +01:00
CertData = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) CertList + sizeof ( EFI_SIGNATURE_LIST ) + CertList - > SignatureHeaderSize ) ;
CertCount = ( CertList - > SignatureListSize - sizeof ( EFI_SIGNATURE_LIST ) - CertList - > SignatureHeaderSize ) / CertList - > SignatureSize ;
2014-11-14 09:41:12 +01:00
2011-09-02 09:49:32 +02:00
for ( Index = 0 ; Index < CertCount ; Index + + ) {
//
2011-10-28 11:54:08 +02:00
// Iterate each Signature Data Node within this CertList for verify.
//
2015-12-07 07:20:02 +01:00
RootCert = CertData - > SignatureData ;
2014-11-14 09:41:12 +01:00
RootCertSize = CertList - > SignatureSize - sizeof ( EFI_GUID ) ;
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
//
2011-10-28 11:54:08 +02:00
// Call AuthenticodeVerify library to Verify Authenticode struct.
2011-09-02 09:49:32 +02:00
//
VerifyStatus = AuthenticodeVerify (
2012-08-23 09:55:35 +02:00
AuthData ,
AuthDataSize ,
2011-09-02 09:49:32 +02:00
RootCert ,
RootCertSize ,
mImageDigest ,
mImageDigestSize
) ;
if ( VerifyStatus ) {
2015-02-04 09:19:53 +01:00
//
// Here We still need to check if this RootCert's Hash is revoked
//
Status = gRT - > GetVariable ( EFI_IMAGE_SECURITY_DATABASE1 , & gEfiImageSecurityDatabaseGuid , NULL , & DbxDataSize , NULL ) ;
if ( Status = = EFI_BUFFER_TOO_SMALL ) {
goto Done ;
}
2015-07-15 04:13:48 +02:00
DbxData = ( UINT8 * ) AllocateZeroPool ( DbxDataSize ) ;
2015-02-04 09:19:53 +01:00
if ( DbxData = = NULL ) {
goto Done ;
}
Status = gRT - > GetVariable ( EFI_IMAGE_SECURITY_DATABASE1 , & gEfiImageSecurityDatabaseGuid , NULL , & DbxDataSize , ( VOID * ) DbxData ) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
if ( IsCertHashFoundInDatabase ( RootCert , RootCertSize , ( EFI_SIGNATURE_LIST * ) DbxData , DbxDataSize , & RevocationTime ) ) {
//
2016-05-13 06:24:59 +02:00
// Check the timestamp signature and signing time to determine if the RootCert can be trusted.
2015-02-04 09:19:53 +01:00
//
VerifyStatus = PassTimestampCheck ( AuthData , AuthDataSize , & RevocationTime ) ;
2016-05-13 06:24:59 +02:00
if ( ! VerifyStatus ) {
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Image is signed and signature is accepted by DB, but its root cert failed the timestamp check. \n " ) ) ;
}
2015-02-04 09:19:53 +01:00
}
2011-09-02 09:49:32 +02:00
goto Done ;
}
2014-11-14 09:41:12 +01:00
2015-12-07 07:20:02 +01:00
CertData = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) CertData + CertList - > SignatureSize ) ;
2011-10-28 11:54:08 +02:00
}
2011-09-02 09:49:32 +02:00
}
2014-11-14 09:41:12 +01:00
2011-09-02 09:49:32 +02:00
DataSize - = CertList - > SignatureListSize ;
CertList = ( EFI_SIGNATURE_LIST * ) ( ( UINT8 * ) CertList + CertList - > SignatureListSize ) ;
}
}
2011-10-28 11:54:08 +02:00
Done :
2015-12-07 07:20:02 +01:00
2015-02-04 09:19:53 +01:00
if ( VerifyStatus ) {
2015-12-07 07:20:02 +01:00
SecureBootHook ( EFI_IMAGE_SECURITY_DATABASE , & gEfiImageSecurityDatabaseGuid , CertList - > SignatureSize , CertData ) ;
2015-02-04 09:19:53 +01:00
}
2011-10-28 11:54:08 +02:00
if ( Data ! = NULL ) {
FreePool ( Data ) ;
}
2015-02-04 09:19:53 +01:00
if ( DbxData ! = NULL ) {
FreePool ( DbxData ) ;
}
2011-09-02 09:49:32 +02:00
2011-10-28 11:54:08 +02:00
return VerifyStatus ;
}
2011-09-02 09:49:32 +02:00
/**
Provide verification service for signed images , which include both signature validation
2011-10-28 11:54:08 +02:00
and platform policy control . For signature types , both UEFI WIN_CERTIFICATE_UEFI_GUID and
2011-09-02 09:49:32 +02:00
MSFT Authenticode type signatures are supported .
2011-10-28 11:54:08 +02:00
In this implementation , only verify external executables when in USER MODE .
Executables from FV is bypass , so pass in AuthenticationStatus is ignored .
2013-02-21 06:00:21 +01:00
The image verification policy is :
2012-08-15 03:39:43 +02:00
If the image is signed ,
2013-02-21 06:00:21 +01:00
At least one valid signature or at least one hash value of the image must match a record
in the security database " db " , and no valid signature nor any hash value of the image may
be reflected in the security database " dbx " .
2012-08-15 03:39:43 +02:00
Otherwise , the image is not signed ,
2013-02-21 06:00:21 +01:00
The SHA256 hash value of the image must match a record in the security database " db " , and
not be reflected in the security data base " dbx " .
2011-10-28 11:54:08 +02:00
2012-06-12 10:28:43 +02:00
Caution : This function may receive untrusted input .
PE / COFF image is external input , so this function will validate its data structure
within this image buffer before use .
2011-10-28 11:54:08 +02:00
@ param [ in ] AuthenticationStatus
2011-09-02 09:49:32 +02:00
This is the authentication status returned from the security
measurement services for the input file .
@ param [ in ] File This is a pointer to the device path of the file that is
being dispatched . This will optionally be used for logging .
@ param [ in ] FileBuffer File buffer matches the input file device path .
@ param [ in ] FileSize Size of File buffer matches the input file device path .
2012-08-22 04:33:00 +02:00
@ param [ in ] BootPolicy A boot policy that was used to call LoadImage ( ) UEFI service .
@ retval EFI_SUCCESS The file specified by DevicePath and non - NULL
FileBuffer did authenticate , and the platform policy dictates
that the DXE Foundation may use the file .
@ retval EFI_SUCCESS The device path specified by NULL device path DevicePath
and non - NULL FileBuffer did authenticate , and the platform
policy dictates that the DXE Foundation may execute the image in
FileBuffer .
2011-09-21 07:23:55 +02:00
@ retval EFI_OUT_RESOURCE Fail to allocate memory .
2011-09-02 09:49:32 +02:00
@ retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate , and
the platform policy dictates that File should be placed
2012-08-22 04:33:00 +02:00
in the untrusted state . The image has been added to the file
execution table .
@ retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
authenticate , and the platform policy dictates that the DXE
Foundation many not use File .
2011-09-02 09:49:32 +02:00
* */
EFI_STATUS
EFIAPI
DxeImageVerificationHandler (
IN UINT32 AuthenticationStatus ,
IN CONST EFI_DEVICE_PATH_PROTOCOL * File ,
IN VOID * FileBuffer ,
2012-08-22 04:33:00 +02:00
IN UINTN FileSize ,
IN BOOLEAN BootPolicy
2011-09-02 09:49:32 +02:00
)
{
2012-04-28 09:48:15 +02:00
EFI_STATUS Status ;
UINT16 Magic ;
EFI_IMAGE_DOS_HEADER * DosHdr ;
EFI_STATUS VerifyStatus ;
EFI_SIGNATURE_LIST * SignatureList ;
UINTN SignatureListSize ;
EFI_SIGNATURE_DATA * Signature ;
EFI_IMAGE_EXECUTION_ACTION Action ;
WIN_CERTIFICATE * WinCertificate ;
UINT32 Policy ;
2016-04-28 07:28:39 +02:00
UINT8 * SecureBoot ;
2012-04-28 09:48:15 +02:00
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext ;
UINT32 NumberOfRvaAndSizes ;
2012-08-23 09:55:35 +02:00
WIN_CERTIFICATE_EFI_PKCS * PkcsCertData ;
WIN_CERTIFICATE_UEFI_GUID * WinCertUefiGuid ;
UINT8 * AuthData ;
UINTN AuthDataSize ;
EFI_IMAGE_DATA_DIRECTORY * SecDataDir ;
2013-02-21 06:00:21 +01:00
UINT32 OffSet ;
2014-12-10 09:09:20 +01:00
CHAR16 * NameStr ;
2011-09-02 09:49:32 +02:00
SignatureList = NULL ;
SignatureListSize = 0 ;
WinCertificate = NULL ;
2012-08-23 09:55:35 +02:00
SecDataDir = NULL ;
PkcsCertData = NULL ;
2011-09-02 09:49:32 +02:00
Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED ;
Status = EFI_ACCESS_DENIED ;
2013-02-21 06:00:21 +01:00
VerifyStatus = EFI_ACCESS_DENIED ;
2015-12-07 07:20:02 +01:00
2011-09-02 09:49:32 +02:00
//
// Check the image type and get policy setting.
//
switch ( GetImageType ( File ) ) {
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
case IMAGE_FROM_FV :
Policy = ALWAYS_EXECUTE ;
break ;
case IMAGE_FROM_OPTION_ROM :
Policy = PcdGet32 ( PcdOptionRomImageVerificationPolicy ) ;
break ;
case IMAGE_FROM_REMOVABLE_MEDIA :
Policy = PcdGet32 ( PcdRemovableMediaImageVerificationPolicy ) ;
break ;
case IMAGE_FROM_FIXED_MEDIA :
Policy = PcdGet32 ( PcdFixedMediaImageVerificationPolicy ) ;
break ;
default :
2011-10-28 11:54:08 +02:00
Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION ;
2011-09-02 09:49:32 +02:00
break ;
}
//
// If policy is always/never execute, return directly.
//
if ( Policy = = ALWAYS_EXECUTE ) {
return EFI_SUCCESS ;
} else if ( Policy = = NEVER_EXECUTE ) {
return EFI_ACCESS_DENIED ;
}
2011-10-28 05:46:20 +02:00
2013-08-28 11:06:40 +02:00
//
2014-11-14 09:41:12 +01:00
// The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION
2013-12-02 08:52:35 +01:00
// violates the UEFI spec and has been removed.
2013-08-28 11:06:40 +02:00
//
2013-12-02 08:52:35 +01:00
ASSERT ( Policy ! = QUERY_USER_ON_SECURITY_VIOLATION & & Policy ! = ALLOW_EXECUTE_ON_SECURITY_VIOLATION ) ;
if ( Policy = = QUERY_USER_ON_SECURITY_VIOLATION | | Policy = = ALLOW_EXECUTE_ON_SECURITY_VIOLATION ) {
2013-08-28 11:06:40 +02:00
CpuDeadLoop ( ) ;
}
2016-04-28 07:28:39 +02:00
GetEfiGlobalVariable2 ( EFI_SECURE_BOOT_MODE_NAME , ( VOID * * ) & SecureBoot , NULL ) ;
2011-10-28 05:46:20 +02:00
//
2012-07-05 10:08:12 +02:00
// Skip verification if SecureBoot variable doesn't exist.
2011-10-28 05:46:20 +02:00
//
2016-04-28 07:28:39 +02:00
if ( SecureBoot = = NULL ) {
2011-10-28 05:46:20 +02:00
return EFI_SUCCESS ;
}
//
2015-12-07 07:20:02 +01:00
// Skip verification if SecureBoot is disabled but not AuditMode
2011-10-28 05:46:20 +02:00
//
2016-04-28 07:28:39 +02:00
if ( * SecureBoot = = SECURE_BOOT_MODE_DISABLE ) {
FreePool ( SecureBoot ) ;
2011-10-28 05:46:20 +02:00
return EFI_SUCCESS ;
2011-10-28 11:54:08 +02:00
}
2016-04-28 07:28:39 +02:00
FreePool ( SecureBoot ) ;
2012-04-28 09:48:15 +02:00
2011-09-02 09:49:32 +02:00
//
// Read the Dos header.
//
2011-09-21 07:23:55 +02:00
if ( FileBuffer = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
2012-04-28 09:48:15 +02:00
2011-09-02 09:49:32 +02:00
mImageBase = ( UINT8 * ) FileBuffer ;
mImageSize = FileSize ;
2012-04-24 05:00:32 +02:00
ZeroMem ( & ImageContext , sizeof ( ImageContext ) ) ;
ImageContext . Handle = ( VOID * ) FileBuffer ;
2012-04-26 03:50:34 +02:00
ImageContext . ImageRead = ( PE_COFF_LOADER_READ_FILE ) DxeImageVerificationLibImageRead ;
2012-04-24 05:00:32 +02:00
//
// Get information about the image being loaded
//
Status = PeCoffLoaderGetImageInfo ( & ImageContext ) ;
if ( EFI_ERROR ( Status ) ) {
//
// The information can't be got from the invalid PeImage
//
2016-05-13 06:24:59 +02:00
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information. \n " ) ) ;
2012-04-24 05:00:32 +02:00
goto Done ;
}
2012-05-08 04:53:49 +02:00
Status = EFI_ACCESS_DENIED ;
DosHdr = ( EFI_IMAGE_DOS_HEADER * ) mImageBase ;
2011-09-02 09:49:32 +02:00
if ( DosHdr - > e_magic = = EFI_IMAGE_DOS_SIGNATURE ) {
//
2011-10-28 11:54:08 +02:00
// DOS image header is present,
2011-09-02 09:49:32 +02:00
// so read the PE header after the DOS image header.
//
mPeCoffHeaderOffset = DosHdr - > e_lfanew ;
} else {
mPeCoffHeaderOffset = 0 ;
}
//
// Check PE/COFF image.
//
mNtHeader . Pe32 = ( EFI_IMAGE_NT_HEADERS32 * ) ( mImageBase + mPeCoffHeaderOffset ) ;
if ( mNtHeader . Pe32 - > Signature ! = EFI_IMAGE_NT_SIGNATURE ) {
//
// It is not a valid Pe/Coff file.
//
2016-05-13 06:24:59 +02:00
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Not a valid PE/COFF image. \n " ) ) ;
2012-04-28 09:48:15 +02:00
goto Done ;
2011-09-02 09:49:32 +02:00
}
2012-06-08 04:09:48 +02:00
if ( mNtHeader . Pe32 - > FileHeader . Machine = = IMAGE_FILE_MACHINE_IA64 & & mNtHeader . Pe32 - > OptionalHeader . Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
2014-11-14 09:41:12 +01:00
// NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
// in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
2012-06-08 04:09:48 +02:00
// Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
// then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
//
Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC ;
} else {
//
// Get the magic value from the PE/COFF Optional Header
//
Magic = mNtHeader . Pe32 - > OptionalHeader . Magic ;
}
2014-11-14 09:41:12 +01:00
2011-09-02 09:49:32 +02:00
if ( Magic = = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) {
//
// Use PE32 offset.
//
2012-04-28 09:48:15 +02:00
NumberOfRvaAndSizes = mNtHeader . Pe32 - > OptionalHeader . NumberOfRvaAndSizes ;
if ( NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ) {
2012-08-23 09:55:35 +02:00
SecDataDir = ( EFI_IMAGE_DATA_DIRECTORY * ) & mNtHeader . Pe32 - > OptionalHeader . DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ] ;
2014-11-14 09:41:12 +01:00
}
2011-09-21 07:23:55 +02:00
} else {
//
2012-04-28 09:48:15 +02:00
// Use PE32+ offset.
2011-09-21 07:23:55 +02:00
//
2012-04-28 09:48:15 +02:00
NumberOfRvaAndSizes = mNtHeader . Pe32Plus - > OptionalHeader . NumberOfRvaAndSizes ;
if ( NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ) {
2012-08-23 09:55:35 +02:00
SecDataDir = ( EFI_IMAGE_DATA_DIRECTORY * ) & mNtHeader . Pe32Plus - > OptionalHeader . DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_SECURITY ] ;
2012-04-28 09:48:15 +02:00
}
2011-09-02 09:49:32 +02:00
}
2013-02-21 06:00:21 +01:00
//
// Start Image Validation.
//
if ( SecDataDir = = NULL | | SecDataDir - > Size = = 0 ) {
2011-09-02 09:49:32 +02:00
//
2014-11-14 09:41:12 +01:00
// This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",
2013-02-21 06:00:21 +01:00
// and not be reflected in the security data base "dbx".
2011-09-02 09:49:32 +02:00
//
2011-10-28 11:54:08 +02:00
if ( ! HashPeImage ( HASHALG_SHA256 ) ) {
2016-05-13 06:24:59 +02:00
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Failed to hash this image using %s. \n " , mHashTypeStr ) ) ;
2011-10-28 11:54:08 +02:00
goto Done ;
}
if ( IsSignatureFoundInDatabase ( EFI_IMAGE_SECURITY_DATABASE1 , mImageDigest , & mCertType , mImageDigestSize ) ) {
//
// Image Hash is in forbidden database (DBX).
//
2016-05-13 06:24:59 +02:00
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX. \n " , mHashTypeStr ) ) ;
2011-10-28 11:54:08 +02:00
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.
//
2016-05-13 06:24:59 +02:00
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX. \n " , mHashTypeStr ) ) ;
2011-10-28 11:54:08 +02:00
goto Done ;
2011-09-02 09:49:32 +02:00
}
2011-10-28 11:54:08 +02:00
2011-09-02 09:49:32 +02:00
//
2014-11-14 09:41:12 +01:00
// Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7
2013-02-21 06:00:21 +01:00
// "Attribute Certificate Table".
// The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
for ( OffSet = SecDataDir - > VirtualAddress ;
OffSet < ( SecDataDir - > VirtualAddress + SecDataDir - > Size ) ;
2014-11-26 09:21:54 +01:00
OffSet + = ( WinCertificate - > dwLength + ALIGN_SIZE ( WinCertificate - > dwLength ) ) ) {
2013-02-21 06:00:21 +01:00
WinCertificate = ( WIN_CERTIFICATE * ) ( mImageBase + OffSet ) ;
if ( ( SecDataDir - > VirtualAddress + SecDataDir - > Size - OffSet ) < = sizeof ( WIN_CERTIFICATE ) | |
( SecDataDir - > VirtualAddress + SecDataDir - > Size - OffSet ) < WinCertificate - > dwLength ) {
break ;
}
2014-11-14 09:41:12 +01:00
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
// Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
if ( WinCertificate - > wCertificateType = = WIN_CERT_TYPE_PKCS_SIGNED_DATA ) {
//
2014-11-14 09:41:12 +01:00
// The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the
2013-02-21 06:00:21 +01:00
// Authenticode specification.
//
PkcsCertData = ( WIN_CERTIFICATE_EFI_PKCS * ) WinCertificate ;
if ( PkcsCertData - > Hdr . dwLength < = sizeof ( PkcsCertData - > Hdr ) ) {
break ;
}
AuthData = PkcsCertData - > CertData ;
AuthDataSize = PkcsCertData - > Hdr . dwLength - sizeof ( PkcsCertData - > Hdr ) ;
} else if ( WinCertificate - > wCertificateType = = WIN_CERT_TYPE_EFI_GUID ) {
//
// The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.
//
WinCertUefiGuid = ( WIN_CERTIFICATE_UEFI_GUID * ) WinCertificate ;
if ( WinCertUefiGuid - > Hdr . dwLength < = OFFSET_OF ( WIN_CERTIFICATE_UEFI_GUID , CertData ) ) {
break ;
}
if ( ! CompareGuid ( & WinCertUefiGuid - > CertType , & gEfiCertPkcs7Guid ) ) {
continue ;
}
AuthData = WinCertUefiGuid - > CertData ;
AuthDataSize = WinCertUefiGuid - > Hdr . dwLength - OFFSET_OF ( WIN_CERTIFICATE_UEFI_GUID , CertData ) ;
} else {
if ( WinCertificate - > dwLength < sizeof ( WIN_CERTIFICATE ) ) {
break ;
}
continue ;
2012-09-06 04:15:59 +02:00
}
2013-02-21 06:00:21 +01:00
2012-08-23 09:55:35 +02:00
Status = HashPeImageByType ( AuthData , AuthDataSize ) ;
2011-10-28 11:54:08 +02:00
if ( EFI_ERROR ( Status ) ) {
2013-02-21 06:00:21 +01:00
continue ;
2011-09-02 09:49:32 +02:00
}
2014-11-14 09:41:12 +01:00
2012-08-23 09:55:35 +02:00
//
2013-02-21 06:00:21 +01:00
// Check the digital signature against the revoked certificate in forbidden database (dbx).
2012-08-23 09:55:35 +02:00
//
2016-04-28 07:28:39 +02:00
if ( IsForbiddenByDbx ( AuthData , AuthDataSize ) ) {
2013-02-21 06:00:21 +01:00
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED ;
VerifyStatus = EFI_ACCESS_DENIED ;
break ;
2012-08-23 09:55:35 +02:00
}
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
// Check the digital signature against the valid certificate in allowed database (db).
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
if ( EFI_ERROR ( VerifyStatus ) ) {
2016-04-28 07:28:39 +02:00
if ( IsAllowedByDb ( AuthData , AuthDataSize ) ) {
2013-02-21 06:00:21 +01:00
VerifyStatus = EFI_SUCCESS ;
}
2011-09-02 09:49:32 +02:00
}
2013-02-21 06:00:21 +01:00
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
// Check the image's hash value.
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
if ( IsSignatureFoundInDatabase ( EFI_IMAGE_SECURITY_DATABASE1 , mImageDigest , & mCertType , mImageDigestSize ) ) {
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND ;
2016-05-13 06:24:59 +02:00
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Image is signed but %s hash of image is found in DBX. \n " , mHashTypeStr ) ) ;
2013-02-21 06:00:21 +01:00
VerifyStatus = EFI_ACCESS_DENIED ;
break ;
} else if ( EFI_ERROR ( VerifyStatus ) ) {
if ( IsSignatureFoundInDatabase ( EFI_IMAGE_SECURITY_DATABASE , mImageDigest , & mCertType , mImageDigestSize ) ) {
VerifyStatus = EFI_SUCCESS ;
2016-05-13 06:24:59 +02:00
} else {
DEBUG ( ( DEBUG_INFO , " DxeImageVerificationLib: Image is signed but signature is not allowed by DB and %s hash of image is not found in DB/DBX. \n " , mHashTypeStr ) ) ;
2013-02-21 06:00:21 +01:00
}
2011-10-28 11:54:08 +02:00
}
2012-08-15 03:39:43 +02:00
}
2013-02-21 06:00:21 +01:00
if ( OffSet ! = ( SecDataDir - > VirtualAddress + SecDataDir - > Size ) ) {
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
// The Size in Certificate Table or the attribute certicate table is corrupted.
2011-09-02 09:49:32 +02:00
//
2013-02-21 06:00:21 +01:00
VerifyStatus = EFI_ACCESS_DENIED ;
}
2014-11-14 09:41:12 +01:00
2013-02-21 06:00:21 +01:00
if ( ! EFI_ERROR ( VerifyStatus ) ) {
return EFI_SUCCESS ;
} else {
Status = EFI_ACCESS_DENIED ;
if ( Action = = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | | Action = = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND ) {
//
// Get image hash value as executable's signature.
//
SignatureListSize = sizeof ( EFI_SIGNATURE_LIST ) + sizeof ( EFI_SIGNATURE_DATA ) - 1 + mImageDigestSize ;
SignatureList = ( EFI_SIGNATURE_LIST * ) AllocateZeroPool ( SignatureListSize ) ;
if ( SignatureList = = NULL ) {
Status = EFI_OUT_OF_RESOURCES ;
goto Done ;
}
SignatureList - > SignatureHeaderSize = 0 ;
SignatureList - > SignatureListSize = ( UINT32 ) SignatureListSize ;
2015-08-17 04:50:26 +02:00
SignatureList - > SignatureSize = ( UINT32 ) ( sizeof ( EFI_SIGNATURE_DATA ) - 1 + mImageDigestSize ) ;
2013-02-21 06:00:21 +01:00
CopyMem ( & SignatureList - > SignatureType , & mCertType , sizeof ( EFI_GUID ) ) ;
Signature = ( EFI_SIGNATURE_DATA * ) ( ( UINT8 * ) SignatureList + sizeof ( EFI_SIGNATURE_LIST ) ) ;
CopyMem ( Signature - > SignatureData , mImageDigest , mImageDigestSize ) ;
2012-08-15 03:39:43 +02:00
}
2011-09-02 09:49:32 +02:00
}
Done :
if ( Status ! = EFI_SUCCESS ) {
//
// Policy decides to defer or reject the image; add its information in image executable information table.
//
2014-12-10 09:09:20 +01:00
NameStr = ConvertDevicePathToText ( File , FALSE , TRUE ) ;
AddImageExeInfo ( Action , NameStr , File , SignatureList , SignatureListSize ) ;
if ( NameStr ! = NULL ) {
DEBUG ( ( EFI_D_INFO , " The image doesn't pass verification: %s \n " , NameStr ) ) ;
FreePool ( NameStr ) ;
}
2012-08-22 04:33:00 +02:00
Status = EFI_SECURITY_VIOLATION ;
2011-09-02 09:49:32 +02:00
}
if ( SignatureList ! = NULL ) {
FreePool ( SignatureList ) ;
}
return Status ;
}
2014-06-25 04:02:22 +02:00
/**
On Ready To Boot Services Event notification handler .
Add the image execution information table if it is not in system configuration table .
@ param [ in ] Event Event whose notification function is being invoked
@ param [ in ] Context Pointer to the notification function ' s context
* */
VOID
EFIAPI
OnReadyToBoot (
IN EFI_EVENT Event ,
IN VOID * Context
)
{
EFI_IMAGE_EXECUTION_INFO_TABLE * ImageExeInfoTable ;
UINTN ImageExeInfoTableSize ;
EfiGetSystemConfigurationTable ( & gEfiImageSecurityDatabaseGuid , ( VOID * * ) & ImageExeInfoTable ) ;
if ( ImageExeInfoTable ! = NULL ) {
return ;
}
ImageExeInfoTableSize = sizeof ( EFI_IMAGE_EXECUTION_INFO_TABLE ) ;
ImageExeInfoTable = ( EFI_IMAGE_EXECUTION_INFO_TABLE * ) AllocateRuntimePool ( ImageExeInfoTableSize ) ;
if ( ImageExeInfoTable = = NULL ) {
return ;
}
2014-11-14 09:41:12 +01:00
ImageExeInfoTable - > NumberOfImages = 0 ;
2014-06-25 04:02:22 +02:00
gBS - > InstallConfigurationTable ( & gEfiImageSecurityDatabaseGuid , ( VOID * ) ImageExeInfoTable ) ;
}
2011-09-02 09:49:32 +02:00
/**
Register security measurement handler .
@ param ImageHandle ImageHandle of the loaded driver .
@ param SystemTable Pointer to the EFI System Table .
@ retval EFI_SUCCESS The handlers were registered successfully .
* */
EFI_STATUS
EFIAPI
DxeImageVerificationLibConstructor (
IN EFI_HANDLE ImageHandle ,
IN EFI_SYSTEM_TABLE * SystemTable
)
{
2014-06-25 04:02:22 +02:00
EFI_EVENT Event ;
//
// Register the event to publish the image execution table.
//
EfiCreateEventReadyToBootEx (
TPL_CALLBACK ,
2014-11-14 09:41:12 +01:00
OnReadyToBoot ,
NULL ,
2014-06-25 04:02:22 +02:00
& Event
2014-11-14 09:41:12 +01:00
) ;
2014-06-25 04:02:22 +02:00
2012-08-22 04:33:00 +02:00
return RegisterSecurity2Handler (
2011-09-02 09:49:32 +02:00
DxeImageVerificationHandler ,
EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
2011-10-28 11:54:08 +02:00
) ;
2011-09-02 09:49:32 +02:00
}