/** @file\r
Implement image verification services for secure boot service in UEFI2.3.1.\r
\r
-Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
+ Caution: This file requires additional review when modified.\r
+ This library will have external input - PE/COFF image.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content\r
+ read is within the image buffer.\r
+\r
+ DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept\r
+ untrusted PE/COFF image and validate its data structure within this image buffer before use.\r
+\r
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
http://opensource.org/licenses/bsd-license.php\r
\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
\r
**/\r
\r
#include "DxeImageVerificationLib.h"\r
\r
+//\r
+// Caution: This is used by a function which may receive untrusted input.\r
+// These global variables hold PE/COFF image data, and they should be validated before use.\r
+//\r
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
+UINT32 mPeCoffHeaderOffset;\r
+EFI_GUID mCertType;\r
+\r
+//\r
+// Information on current PE/COFF image\r
+//\r
UINTN mImageSize;\r
-UINT32 mPeCoffHeaderOffset; \r
+UINT8 *mImageBase = NULL;\r
UINT8 mImageDigest[MAX_DIGEST_SIZE];\r
UINTN mImageDigestSize;\r
-EFI_IMAGE_DATA_DIRECTORY *mSecDataDir = NULL;\r
-UINT8 *mImageBase = NULL;\r
-EFI_GUID mCertType;\r
\r
//\r
// Notify string for authorization UI.\r
// OID ASN.1 Value for Hash Algorithms\r
//\r
UINT8 mHashOidValue[] = {\r
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, // OBJ_md5\r
0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1\r
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224\r
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256\r
};\r
\r
HASH_TABLE mHash[] = {\r
- { L"SHA1", 20, &mHashOidValue[8], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },\r
- { L"SHA224", 28, &mHashOidValue[13], 9, NULL, NULL, NULL, NULL },\r
- { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize,Sha256Init, Sha256Update, Sha256Final},\r
- { L"SHA384", 48, &mHashOidValue[31], 9, NULL, NULL, NULL, NULL },\r
- { L"SHA512", 64, &mHashOidValue[40], 9, NULL, NULL, NULL, NULL }\r
+ { L"SHA1", 20, &mHashOidValue[0], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },\r
+ { L"SHA224", 28, &mHashOidValue[5], 9, NULL, NULL, NULL, NULL },\r
+ { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize,Sha256Init, Sha256Update, Sha256Final},\r
+ { L"SHA384", 48, &mHashOidValue[23], 9, NULL, NULL, NULL, NULL },\r
+ { L"SHA512", 64, &mHashOidValue[32], 9, NULL, NULL, NULL, NULL }\r
};\r
\r
+/**\r
+ SecureBoot Hook for processing image verification.\r
+\r
+ @param[in] VariableName Name of Variable to be found.\r
+ @param[in] VendorGuid Variable vendor GUID.\r
+ @param[in] DataSize Size of Data found. If size is less than the\r
+ data, this value contains the required size.\r
+ @param[in] Data Data pointer.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SecureBootHook (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ );\r
+\r
+/**\r
+ Reads contents of a PE/COFF image in memory buffer.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
+ read is within the image buffer.\r
+\r
+ @param FileHandle Pointer to the file handle to read the PE/COFF image.\r
+ @param FileOffset Offset into the PE/COFF image to begin the read operation.\r
+ @param ReadSize On input, the size in bytes of the requested read operation. \r
+ On output, the number of bytes actually read.\r
+ @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
+ \r
+ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeImageVerificationLibImageRead (\r
+ IN VOID *FileHandle,\r
+ IN UINTN FileOffset,\r
+ IN OUT UINTN *ReadSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ UINTN EndPosition;\r
+\r
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER; \r
+ }\r
+\r
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EndPosition = FileOffset + *ReadSize;\r
+ if (EndPosition > mImageSize) {\r
+ *ReadSize = (UINT32)(mImageSize - FileOffset);\r
+ }\r
+\r
+ if (FileOffset >= mImageSize) {\r
+ *ReadSize = 0;\r
+ }\r
+\r
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
\r
/**\r
Get the image type.\r
\r
@param[in] File This is a pointer to the device path of the file that is\r
- being dispatched. \r
+ being dispatched.\r
\r
- @return UINT32 Image Type \r
+ @return UINT32 Image Type\r
\r
**/\r
UINT32\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_HANDLE DeviceHandle; \r
+ EFI_HANDLE DeviceHandle;\r
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
\r
+ if (File == NULL) {\r
+ return IMAGE_UNKNOWN;\r
+ }\r
+\r
//\r
// First check to see if File is from a Firmware Volume\r
//\r
DeviceHandle = NULL;\r
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
Status = gBS->LocateDevicePath (\r
&gEfiFirmwareVolume2ProtocolGuid,\r
&TempDevicePath,\r
// Next check to see if File is from a Block I/O device\r
//\r
DeviceHandle = NULL;\r
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
Status = gBS->LocateDevicePath (\r
&gEfiBlockIoProtocolGuid,\r
&TempDevicePath,\r
}\r
\r
//\r
- // File is not in a Firmware Volume or on a Block I/O device, so check to see if \r
+ // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r
// the device path supports the Simple File System Protocol.\r
//\r
DeviceHandle = NULL;\r
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
Status = gBS->LocateDevicePath (\r
&gEfiSimpleFileSystemProtocolGuid,\r
&TempDevicePath,\r
\r
//\r
// File is not from an FV, Block I/O or Simple File System, so the only options\r
- // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. \r
+ // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r
//\r
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
while (!IsDevicePathEndType (TempDevicePath)) {\r
switch (DevicePathType (TempDevicePath)) {\r
- \r
+\r
case MEDIA_DEVICE_PATH:\r
if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
return IMAGE_FROM_OPTION_ROM;\r
case MESSAGING_DEVICE_PATH:\r
if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
return IMAGE_FROM_REMOVABLE_MEDIA;\r
- } \r
+ }\r
break;\r
\r
default:\r
}\r
TempDevicePath = NextDevicePathNode (TempDevicePath);\r
}\r
- return IMAGE_UNKNOWN; \r
+ return IMAGE_UNKNOWN;\r
}\r
\r
/**\r
Caculate hash of Pe/Coff image based on the authenticode image hashing in\r
PE/COFF Specification 8.0 Appendix A\r
\r
+ Caution: This function may receive untrusted input.\r
+ PE/COFF image is external input, so this function will validate its data structure\r
+ within this image buffer before use.\r
+\r
@param[in] HashAlg Hash algorithm type.\r
- \r
+\r
@retval TRUE Successfully hash image.\r
@retval FALSE Fail in hash image.\r
\r
**/\r
-BOOLEAN \r
+BOOLEAN\r
HashPeImage (\r
IN UINT32 HashAlg\r
)\r
EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
UINTN Index;\r
UINTN Pos;\r
- UINTN SumOfSectionBytes;\r
- EFI_IMAGE_SECTION_HEADER *SectionCache; \r
- \r
+ UINT32 CertSize;\r
+ UINT32 NumberOfRvaAndSizes;\r
+\r
HashCtx = NULL;\r
SectionHeader = NULL;\r
Status = FALSE;\r
if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {\r
return FALSE;\r
}\r
- \r
+\r
//\r
// Initialize context of hash.\r
//\r
}\r
\r
CtxSize = mHash[HashAlg].GetContextSize();\r
- \r
+\r
HashCtx = AllocatePool (CtxSize);\r
if (HashCtx == NULL) {\r
return FALSE;\r
\r
// 2. Initialize a SHA hash context.\r
Status = mHash[HashAlg].HashInit(HashCtx);\r
- \r
+\r
if (!Status) {\r
goto Done;\r
}\r
+\r
//\r
// Measuring PE/COFF Image Header;\r
// But CheckSum field and SECURITY data directory (certificate) are excluded\r
//\r
- Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+ if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+ } else {\r
+ //\r
+ // Get the magic value from the PE/COFF Optional Header\r
+ //\r
+ Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+ }\r
+ \r
//\r
// 3. Calculate the distance from the base of the image header to the image checksum address.\r
// 4. Hash the image header from its base to beginning of the image checksum.\r
// Use PE32 offset.\r
//\r
HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);\r
+ NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
} else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
//\r
// Use PE32+ offset.\r
//\r
HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
+ NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
} else {\r
//\r
// Invalid header magic number.\r
if (!Status) {\r
goto Done;\r
}\r
+\r
//\r
// 5. Skip over the image checksum (it occupies a single ULONG).\r
- // 6. Get the address of the beginning of the Cert Directory.\r
- // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
//\r
- if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
//\r
- // Use PE32 offset.\r
+ // 6. Since there is no Cert Directory in optional header, hash everything\r
+ // from the end of the checksum to the end of image header.\r
//\r
- HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
- HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
- } else {\r
- //\r
- // Use PE32+ offset.\r
- // \r
- HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
- HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
- }\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset.\r
+ //\r
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+ HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+ } else {\r
+ //\r
+ // Use PE32+ offset.\r
+ //\r
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+ }\r
\r
- Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
- if (!Status) {\r
- goto Done;\r
- }\r
- //\r
- // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
- // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
- //\r
- if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ if (HashSize != 0) {\r
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+ if (!Status) {\r
+ goto Done;\r
+ }\r
+ }\r
+ } else {\r
//\r
- // Use PE32 offset\r
+ // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
//\r
- HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
- HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
- } else {\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset.\r
+ //\r
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+ } else {\r
+ //\r
+ // Use PE32+ offset.\r
+ //\r
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+ }\r
+\r
+ if (HashSize != 0) {\r
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+ if (!Status) {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
//\r
- // Use PE32+ offset.\r
+ // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
+ // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
//\r
- HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
- HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
- }\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset\r
+ //\r
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+ HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+ } else {\r
+ //\r
+ // Use PE32+ offset.\r
+ //\r
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
+ }\r
\r
- Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
- if (!Status) {\r
- goto Done;\r
+ if (HashSize != 0) {\r
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+ if (!Status) {\r
+ goto Done;\r
+ }\r
+ } \r
}\r
+\r
//\r
// 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
//\r
mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r
);\r
\r
- SectionCache = Section;\r
- for (Index = 0, SumOfSectionBytes = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++, SectionCache++) {\r
- SumOfSectionBytes += SectionCache->SizeOfRawData;\r
- }\r
- \r
- //\r
- // Sanity check for file corruption. Sections raw data size should be smaller\r
- // than Image Size.\r
- //\r
- if (SumOfSectionBytes >= mImageSize) {\r
- Status = FALSE;\r
- goto Done;\r
- }\r
-\r
//\r
// 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
// structures in the image. The 'NumberOfSections' field of the image\r
//\r
if (mImageSize > SumOfBytesHashed) {\r
HashBase = mImageBase + SumOfBytesHashed;\r
- if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
- //\r
- // Use PE32 offset.\r
- //\r
- HashSize = (UINTN)(\r
- mImageSize -\r
- mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
- SumOfBytesHashed);\r
+\r
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+ CertSize = 0;\r
} else {\r
- //\r
- // Use PE32+ offset.\r
- //\r
- HashSize = (UINTN)(\r
- mImageSize -\r
- mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
- SumOfBytesHashed); \r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset.\r
+ //\r
+ CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
+ } else {\r
+ //\r
+ // Use PE32+ offset.\r
+ //\r
+ CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
+ }\r
}\r
\r
- Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
- if (!Status) {\r
+ if (mImageSize > CertSize + SumOfBytesHashed) {\r
+ HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed);\r
+\r
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+ if (!Status) {\r
+ goto Done;\r
+ }\r
+ } else if (mImageSize < CertSize + SumOfBytesHashed) {\r
+ Status = FALSE;\r
goto Done;\r
}\r
}\r
+\r
Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
\r
Done:\r
}\r
\r
/**\r
- Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of \r
- Pe/Coff image based on the authenticode image hashing in PE/COFF Specification \r
+ Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of\r
+ Pe/Coff image based on the authenticode image hashing in PE/COFF Specification\r
8.0 Appendix A\r
\r
+ Caution: This function may receive untrusted input.\r
+ PE/COFF image is external input, so this function will validate its data structure\r
+ within this image buffer before use.\r
+\r
+ @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.\r
+ @param[in] AuthDataSize Size of the Authenticode Signature in bytes.\r
+ \r
@retval EFI_UNSUPPORTED Hash algorithm is not supported.\r
@retval EFI_SUCCESS Hash successfully.\r
\r
**/\r
-EFI_STATUS \r
+EFI_STATUS\r
HashPeImageByType (\r
- VOID\r
+ IN UINT8 *AuthData,\r
+ IN UINTN AuthDataSize\r
)\r
{\r
UINT8 Index;\r
- WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
-\r
- PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);\r
\r
- for (Index = 0; Index < HASHALG_MAX; Index++) { \r
+ for (Index = 0; Index < HASHALG_MAX; Index++) {\r
//\r
// Check the Hash algorithm in PE/COFF Authenticode.\r
- // According to PKCS#7 Definition: \r
+ // According to PKCS#7 Definition:\r
// SignedData ::= SEQUENCE {\r
// version Version,\r
// digestAlgorithms DigestAlgorithmIdentifiers,\r
// .... }\r
// The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r
// This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
- // \r
- if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
+ // Fixed offset (+32) is calculated based on two bytes of length encoding.\r
+ //\r
+ if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
+ //\r
+ // Only support two bytes of Long Form of Length Encoding.\r
+ //\r
+ continue;\r
+ }\r
+\r
+ if (AuthDataSize < 32 + mHash[Index].OidLength) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
break;\r
}\r
}\r
ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.\r
\r
@param ImageExeInfoTable A pointer to a image execution info table structure.\r
- \r
+\r
@retval 0 If ImageExeInfoTable is NULL.\r
@retval Others The size of a image execution info table in bytes.\r
\r
@param[in] DevicePath Input device path pointer.\r
@param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.\r
@param[in] SignatureSize Size of signature.\r
- \r
+\r
**/\r
VOID\r
AddImageExeInfo (\r
- IN EFI_IMAGE_EXECUTION_ACTION Action, \r
- IN CHAR16 *Name OPTIONAL, \r
+ IN EFI_IMAGE_EXECUTION_ACTION Action,\r
+ IN CHAR16 *Name OPTIONAL,\r
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
IN EFI_SIGNATURE_LIST *Signature OPTIONAL,\r
IN UINTN SignatureSize\r
if (DevicePath == NULL) {\r
return ;\r
}\r
- \r
+\r
if (Name != NULL) {\r
NameStringLen = StrSize (Name);\r
+ } else {\r
+ NameStringLen = sizeof (CHAR16);\r
}\r
\r
- ImageExeInfoTable = NULL;\r
- EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID**)&ImageExeInfoTable);\r
+ EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
if (ImageExeInfoTable != NULL) {\r
//\r
// The table has been found!\r
- // We must enlarge the table to accmodate the new exe info entry.\r
+ // We must enlarge the table to accomodate the new exe info entry.\r
//\r
ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);\r
} else {\r
NewImageExeInfoTable->NumberOfImages++;\r
ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);\r
//\r
- // Update new item's infomation.\r
+ // Update new item's information.\r
//\r
- WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->Action, Action);\r
- WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->InfoSize, (UINT32) NewImageExeInfoEntrySize);\r
+ WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);\r
+ WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);\r
\r
if (Name != NULL) {\r
- CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen);\r
+ CopyMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), Name, NameStringLen);\r
+ } else {\r
+ ZeroMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), sizeof (CHAR16));\r
}\r
CopyMem (\r
- (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen,\r
+ (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen,\r
DevicePath,\r
DevicePathSize\r
);\r
if (Signature != NULL) {\r
CopyMem (\r
- (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize,\r
+ (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen + DevicePathSize,\r
Signature,\r
SignatureSize\r
);\r
// Update/replace the image execution table.\r
//\r
gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);\r
- \r
+\r
//\r
// Free Old table data!\r
//\r
}\r
}\r
\r
-/**\r
- Discover if the UEFI image is authorized by user's policy setting.\r
-\r
- @param[in] Policy Specify platform's policy setting. \r
-\r
- @retval EFI_ACCESS_DENIED Image is not allowed to run.\r
- @retval EFI_SECURITY_VIOLATION Image is deferred.\r
- @retval EFI_SUCCESS Image is authorized to run.\r
-\r
-**/\r
-EFI_STATUS\r
-ImageAuthorization (\r
- IN UINT32 Policy\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_INPUT_KEY Key;\r
-\r
- Status = EFI_ACCESS_DENIED;\r
-\r
- switch (Policy) {\r
- \r
- case QUERY_USER_ON_SECURITY_VIOLATION:\r
- do {\r
- CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL);\r
- if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {\r
- Status = EFI_SUCCESS;\r
- break;\r
- } else if (Key.UnicodeChar == L'N' || Key.UnicodeChar == L'n') {\r
- Status = EFI_ACCESS_DENIED;\r
- break;\r
- } else if (Key.UnicodeChar == L'D' || Key.UnicodeChar == L'd') {\r
- Status = EFI_SECURITY_VIOLATION;\r
- break;\r
- }\r
- } while (TRUE);\r
- break;\r
-\r
- case ALLOW_EXECUTE_ON_SECURITY_VIOLATION:\r
- Status = EFI_SUCCESS;\r
- break;\r
-\r
- case DEFER_EXECUTE_ON_SECURITY_VIOLATION:\r
- Status = EFI_SECURITY_VIOLATION;\r
- break;\r
-\r
- case DENY_EXECUTE_ON_SECURITY_VIOLATION:\r
- Status = EFI_ACCESS_DENIED;\r
- break;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
/**\r
Check whether signature is in specified database.\r
\r
BOOLEAN\r
IsSignatureFoundInDatabase (\r
IN CHAR16 *VariableName,\r
- IN UINT8 *Signature, \r
+ IN UINT8 *Signature,\r
IN EFI_GUID *CertType,\r
IN UINTN SignatureSize\r
)\r
//\r
CertList = (EFI_SIGNATURE_LIST *) Data;\r
while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
- CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {\r
for (Index = 0; Index < CertCount; Index++) {\r
// Find the signature in database.\r
//\r
IsFound = TRUE;\r
+ SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
break;\r
}\r
\r
}\r
\r
/**\r
- Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format .\r
+ Verify PKCS#7 SignedData using certificate found in Variable which formatted\r
+ as EFI_SIGNATURE_LIST. The Variable may be PK, KEK, DB or DBX.\r
\r
- @retval EFI_SUCCESS Image pass verification.\r
- @retval EFI_SECURITY_VIOLATION Image fail verification.\r
- @retval EFI_OUT_OF_RESOURCE Fail to allocate memory.\r
+ @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.\r
+ @param[in] AuthDataSize Size of the Authenticode Signature in bytes.\r
+ @param[in] VariableName Name of Variable to search for Certificate.\r
+ @param[in] VendorGuid Variable vendor GUID.\r
+\r
+ @retval TRUE Image pass verification.\r
+ @retval FALSE Image fail verification.\r
\r
**/\r
-EFI_STATUS \r
-VerifyCertPkcsSignedData (\r
- VOID\r
+BOOLEAN\r
+IsPkcsSignedDataVerifiedBySignatureList (\r
+ IN UINT8 *AuthData,\r
+ IN UINTN AuthDataSize,\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
)\r
{\r
EFI_STATUS Status;\r
BOOLEAN VerifyStatus;\r
- WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
EFI_SIGNATURE_LIST *CertList;\r
EFI_SIGNATURE_DATA *Cert;\r
UINTN DataSize;\r
- UINT8 *KekData;\r
- UINT8 *DbData;\r
+ UINT8 *Data;\r
UINT8 *RootCert;\r
UINTN RootCertSize;\r
UINTN Index;\r
UINTN CertCount;\r
\r
- KekData = NULL;\r
- DbData = NULL;\r
- CertList = NULL;\r
- Cert = NULL;\r
- RootCert = NULL;\r
- RootCertSize = 0;\r
- VerifyStatus = FALSE;\r
- PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);\r
+ Data = NULL;\r
+ CertList = NULL;\r
+ Cert = NULL;\r
+ RootCert = NULL;\r
+ RootCertSize = 0;\r
+ VerifyStatus = FALSE;\r
\r
- //\r
- // 1: Find certificate from KEK database and try to verify authenticode struct.\r
- //\r
DataSize = 0;\r
- Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);\r
+ Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);\r
if (Status == EFI_BUFFER_TOO_SMALL) {\r
- KekData = (UINT8 *)AllocateZeroPool (DataSize);\r
- if (KekData == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
+ Data = (UINT8 *) AllocateZeroPool (DataSize);\r
+ if (Data == NULL) {\r
+ return VerifyStatus;\r
}\r
\r
- Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, (VOID *)KekData);\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- \r
- //\r
- // Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data.\r
- // \r
- CertList = (EFI_SIGNATURE_LIST *) KekData;\r
- while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
- if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
- Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
- CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
- for (Index = 0; Index < CertCount; Index++) {\r
- //\r
- // Iterate each Signature Data Node within this CertList for a verify\r
- // \r
- RootCert = Cert->SignatureData;\r
- RootCertSize = CertList->SignatureSize;\r
- \r
- //\r
- // Call AuthenticodeVerify library to Verify Authenticode struct. \r
- //\r
- VerifyStatus = AuthenticodeVerify (\r
- PkcsCertData->CertData,\r
- mSecDataDir->Size - sizeof(PkcsCertData->Hdr),\r
- RootCert,\r
- RootCertSize,\r
- mImageDigest,\r
- mImageDigestSize\r
- );\r
- \r
- if (VerifyStatus) {\r
- goto Done;\r
- }\r
- Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
- } \r
- }\r
- DataSize -= CertList->SignatureListSize;\r
- CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
- }\r
- }\r
-\r
- \r
-\r
- //\r
- // 2: Find certificate from DB database and try to verify authenticode struct.\r
- //\r
- DataSize = 0;\r
- Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
- if (Status == EFI_BUFFER_TOO_SMALL) {\r
- DbData = (UINT8 *)AllocateZeroPool (DataSize);\r
- if (DbData == NULL) {\r
- goto Done;\r
- }\r
-\r
- Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)DbData);\r
+ Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, (VOID *) Data);\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
\r
//\r
- // Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data.\r
- // \r
- CertList = (EFI_SIGNATURE_LIST *) DbData;\r
+ // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.\r
+ //\r
+ CertList = (EFI_SIGNATURE_LIST *) Data;\r
while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
for (Index = 0; Index < CertCount; Index++) {\r
//\r
- // Iterate each Signature Data Node within this CertList for a verify\r
- // \r
+ // Iterate each Signature Data Node within this CertList for verify.\r
+ //\r
RootCert = Cert->SignatureData;\r
- RootCertSize = CertList->SignatureSize;\r
- \r
+ RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
+\r
//\r
- // Call AuthenticodeVerify library to Verify Authenticode struct. \r
+ // Call AuthenticodeVerify library to Verify Authenticode struct.\r
//\r
VerifyStatus = AuthenticodeVerify (\r
- PkcsCertData->CertData,\r
- mSecDataDir->Size - sizeof(PkcsCertData->Hdr),\r
+ AuthData,\r
+ AuthDataSize,\r
RootCert,\r
RootCertSize,\r
mImageDigest,\r
mImageDigestSize\r
);\r
- \r
if (VerifyStatus) {\r
+ SecureBootHook (VariableName, VendorGuid, CertList->SignatureSize, Cert);\r
goto Done;\r
}\r
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
- } \r
+ }\r
}\r
DataSize -= CertList->SignatureListSize;\r
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
}\r
\r
Done:\r
- if (KekData != NULL) {\r
- FreePool (KekData);\r
- }\r
-\r
- if (DbData != NULL) {\r
- FreePool (DbData);\r
- }\r
-\r
- if (VerifyStatus) {\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
-}\r
-\r
-/**\r
- Verify certificate in WIN_CERTIFICATE_UEFI_GUID format. \r
-\r
- @retval EFI_SUCCESS Image pass verification.\r
- @retval EFI_SECURITY_VIOLATION Image fail verification.\r
- @retval other error value\r
-\r
-**/\r
-EFI_STATUS \r
-VerifyCertUefiGuid (\r
- VOID\r
- )\r
-{\r
- BOOLEAN Status;\r
- WIN_CERTIFICATE_UEFI_GUID *EfiCert;\r
- EFI_SIGNATURE_LIST *KekList;\r
- EFI_SIGNATURE_DATA *KekItem;\r
- EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
- VOID *Rsa;\r
- UINTN KekCount;\r
- UINTN Index;\r
- UINTN KekDataSize;\r
- BOOLEAN IsFound;\r
- EFI_STATUS Result;\r
-\r
- EfiCert = NULL;\r
- KekList = NULL;\r
- KekItem = NULL;\r
- CertBlock = NULL;\r
- Rsa = NULL;\r
- Status = FALSE;\r
- IsFound = FALSE;\r
- KekDataSize = 0;\r
-\r
- EfiCert = (WIN_CERTIFICATE_UEFI_GUID *) (mImageBase + mSecDataDir->VirtualAddress);\r
- CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) EfiCert->CertData;\r
- if (!CompareGuid (&EfiCert->CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r
- //\r
- // Invalid Certificate Data Type.\r
- //\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
-\r
- //\r
- // Get KEK database variable data size\r
- //\r
- Result = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &KekDataSize, NULL);\r
- if (Result != EFI_BUFFER_TOO_SMALL) {\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
-\r
- //\r
- // Get KEK database variable.\r
- //\r
- KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME);\r
- if (KekList == NULL) {\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
- \r
- //\r
- // Enumerate all Kek items in this list to verify the variable certificate data.\r
- // If anyone is authenticated successfully, it means the variable is correct!\r
- //\r
- while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
- if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
- KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
- KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
- for (Index = 0; Index < KekCount; Index++) {\r
- if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
- IsFound = TRUE;\r
- break;\r
- }\r
- KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
- }\r
- }\r
- KekDataSize -= KekList->SignatureListSize;\r
- KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
- }\r
- \r
- if (!IsFound) {\r
- //\r
- // Signed key is not a trust one.\r
- //\r
- goto Done;\r
+ if (Data != NULL) {\r
+ FreePool (Data);\r
}\r
\r
- //\r
- // Now, we found the corresponding security policy.\r
- // Verify the data payload.\r
- //\r
- Rsa = RsaNew ();\r
- if (Rsa == NULL) {\r
- Status = FALSE;\r
- goto Done;\r
- }\r
- \r
- // \r
- // Set RSA Key Components.\r
- // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
- //\r
- Status = RsaSetKey (Rsa, RsaKeyN, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
- if (!Status) {\r
- goto Done;\r
- }\r
- Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
- if (!Status) {\r
- goto Done;\r
- }\r
- //\r
- // Verify the signature.\r
- //\r
- Status = RsaPkcs1Verify (\r
- Rsa, \r
- mImageDigest, \r
- mImageDigestSize, \r
- CertBlock->Signature, \r
- EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
- );\r
- \r
-Done:\r
- if (KekList != NULL) {\r
- FreePool (KekList);\r
- }\r
- if (Rsa != NULL ) {\r
- RsaFree (Rsa);\r
- }\r
- if (Status) {\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
+ return VerifyStatus;\r
}\r
\r
/**\r
Provide verification service for signed images, which include both signature validation\r
- and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and \r
+ and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and\r
MSFT Authenticode type signatures are supported.\r
- \r
- In this implementation, only verify external executables when in USER MODE.\r
- Executables from FV is bypass, so pass in AuthenticationStatus is ignored. \r
\r
- @param[in] AuthenticationStatus \r
+ In this implementation, only verify external executables when in USER MODE.\r
+ Executables from FV is bypass, so pass in AuthenticationStatus is ignored.\r
+\r
+ The image verification policy is:\r
+ If the image is signed,\r
+ At least one valid signature or at least one hash value of the image must match a record\r
+ in the security database "db", and no valid signature nor any hash value of the image may\r
+ be reflected in the security database "dbx".\r
+ Otherwise, the image is not signed,\r
+ The SHA256 hash value of the image must match a record in the security database "db", and\r
+ not be reflected in the security data base "dbx".\r
+\r
+ Caution: This function may receive untrusted input.\r
+ PE/COFF image is external input, so this function will validate its data structure\r
+ within this image buffer before use.\r
+\r
+ @param[in] AuthenticationStatus\r
This is the authentication status returned from the security\r
measurement services for the input file.\r
@param[in] File This is a pointer to the device path of the file that is\r
being dispatched. This will optionally be used for logging.\r
@param[in] FileBuffer File buffer matches the input file device path.\r
@param[in] FileSize Size of File buffer matches the input file device path.\r
-\r
- @retval EFI_SUCCESS The file specified by File did authenticate, and the\r
- platform policy dictates that the DXE Core may use File.\r
- @retval EFI_INVALID_PARAMETER Input argument is incorrect.\r
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
+\r
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
+ FileBuffer did authenticate, and the platform policy dictates\r
+ that the DXE Foundation may use the file.\r
+ @retval EFI_SUCCESS The device path specified by NULL device path DevicePath\r
+ and non-NULL FileBuffer did authenticate, and the platform\r
+ policy dictates that the DXE Foundation may execute the image in\r
+ FileBuffer.\r
@retval EFI_OUT_RESOURCE Fail to allocate memory.\r
@retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
the platform policy dictates that File should be placed\r
- in the untrusted state. A file may be promoted from\r
- the untrusted to the trusted state at a future time\r
- with a call to the Trust() DXE Service.\r
- @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
- the platform policy dictates that File should not be\r
- used for any purpose.\r
+ in the untrusted state. The image has been added to the file\r
+ execution table.\r
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r
+ authenticate, and the platform policy dictates that the DXE\r
+ Foundation many not use File.\r
\r
**/\r
EFI_STATUS\r
IN UINT32 AuthenticationStatus,\r
IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
IN VOID *FileBuffer,\r
- IN UINTN FileSize\r
+ IN UINTN FileSize,\r
+ IN BOOLEAN BootPolicy\r
)\r
{\r
- EFI_STATUS Status;\r
- UINT16 Magic;\r
- EFI_IMAGE_DOS_HEADER *DosHdr;\r
- EFI_STATUS VerifyStatus;\r
- UINT8 *SetupMode;\r
- EFI_SIGNATURE_LIST *SignatureList;\r
- UINTN SignatureListSize;\r
- EFI_SIGNATURE_DATA *Signature;\r
- EFI_IMAGE_EXECUTION_ACTION Action;\r
- WIN_CERTIFICATE *WinCertificate;\r
- UINT32 Policy;\r
- UINT8 *SecureBootEnable;\r
-\r
- if (File == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ EFI_STATUS Status;\r
+ UINT16 Magic;\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_STATUS VerifyStatus;\r
+ EFI_SIGNATURE_LIST *SignatureList;\r
+ UINTN SignatureListSize;\r
+ EFI_SIGNATURE_DATA *Signature;\r
+ EFI_IMAGE_EXECUTION_ACTION Action;\r
+ WIN_CERTIFICATE *WinCertificate;\r
+ UINT32 Policy;\r
+ UINT8 *SecureBoot;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ UINT32 NumberOfRvaAndSizes;\r
+ WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
+ WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;\r
+ UINT8 *AuthData;\r
+ UINTN AuthDataSize;\r
+ EFI_IMAGE_DATA_DIRECTORY *SecDataDir;\r
+ UINT32 OffSet;\r
\r
SignatureList = NULL;\r
SignatureListSize = 0;\r
WinCertificate = NULL;\r
+ SecDataDir = NULL;\r
+ PkcsCertData = NULL;\r
Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
Status = EFI_ACCESS_DENIED;\r
+ VerifyStatus = EFI_ACCESS_DENIED;\r
+\r
//\r
// Check the image type and get policy setting.\r
//\r
switch (GetImageType (File)) {\r
- \r
+\r
case IMAGE_FROM_FV:\r
Policy = ALWAYS_EXECUTE;\r
break;\r
break;\r
\r
default:\r
- Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION; \r
+ Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;\r
break;\r
}\r
//\r
return EFI_ACCESS_DENIED;\r
}\r
\r
- SecureBootEnable = GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid);\r
//\r
- // Skip verification if SecureBootEnable variable doesn't exist.\r
+ // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION \r
+ // violates the UEFI spec and has been removed.\r
//\r
- if (SecureBootEnable == NULL) {\r
- return EFI_SUCCESS;\r
+ ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);\r
+ if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {\r
+ CpuDeadLoop ();\r
}\r
\r
+ GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
//\r
- // Skip verification if SecureBootEnable is disabled.\r
+ // Skip verification if SecureBoot variable doesn't exist.\r
//\r
- if (*SecureBootEnable == SECURE_BOOT_DISABLE) {\r
- FreePool (SecureBootEnable);\r
- return EFI_SUCCESS;\r
- } \r
- \r
- SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);\r
-\r
- //\r
- // SetupMode doesn't exist means no AuthVar driver is dispatched,\r
- // skip verification.\r
- //\r
- if (SetupMode == NULL) {\r
+ if (SecureBoot == NULL) {\r
return EFI_SUCCESS;\r
}\r
\r
//\r
- // If platform is in SETUP MODE, skip verification.\r
+ // Skip verification if SecureBoot is disabled.\r
//\r
- if (*SetupMode == SETUP_MODE) {\r
- FreePool (SetupMode);\r
+ if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
+ FreePool (SecureBoot);\r
return EFI_SUCCESS;\r
}\r
+ FreePool (SecureBoot);\r
+\r
//\r
// Read the Dos header.\r
//\r
if (FileBuffer == NULL) {\r
- FreePool (SetupMode);\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
mImageBase = (UINT8 *) FileBuffer;\r
mImageSize = FileSize;\r
- DosHdr = (EFI_IMAGE_DOS_HEADER *) (mImageBase);\r
+\r
+ ZeroMem (&ImageContext, sizeof (ImageContext));\r
+ ImageContext.Handle = (VOID *) FileBuffer;\r
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;\r
+\r
+ //\r
+ // Get information about the image being loaded\r
+ //\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // The information can't be got from the invalid PeImage\r
+ //\r
+ goto Done;\r
+ }\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;\r
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
//\r
- // DOS image header is present, \r
+ // DOS image header is present,\r
// so read the PE header after the DOS image header.\r
//\r
mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
//\r
// It is not a valid Pe/Coff file.\r
//\r
- return EFI_ACCESS_DENIED;\r
+ goto Done;\r
}\r
\r
- Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
- if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
- //\r
- // Use PE32 offset.\r
+ if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
//\r
- mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
- } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
- //\r
- // Use PE32+ offset.\r
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
//\r
- mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
} else {\r
//\r
- // Invalid header magic number.\r
+ // Get the magic value from the PE/COFF Optional Header\r
//\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Done;\r
+ Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
}\r
-\r
- if (mSecDataDir->VirtualAddress >= mImageSize) {\r
+ \r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
//\r
- // Sanity check to see if this file is corrupted.\r
+ // Use PE32 offset.\r
//\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Done;\r
- }\r
-\r
- if (mSecDataDir->Size == 0) {\r
+ NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+ SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+ } \r
+ } else {\r
//\r
- // This image is not signed.\r
+ // Use PE32+ offset.\r
//\r
- Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
- Status = EFI_ACCESS_DENIED; \r
- goto Done; \r
+ NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
+ SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+ }\r
}\r
+\r
//\r
- // Verify signature of executables.\r
+ // Start Image Validation.\r
//\r
- WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);\r
-\r
- switch (WinCertificate->wCertificateType) {\r
- \r
- case WIN_CERT_TYPE_EFI_GUID:\r
+ if (SecDataDir == NULL || SecDataDir->Size == 0) {\r
+ //\r
+ // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db", \r
+ // and not be reflected in the security data base "dbx".\r
//\r
- // Verify UEFI GUID type.\r
- // \r
if (!HashPeImage (HASHALG_SHA256)) {\r
goto Done;\r
}\r
\r
- VerifyStatus = VerifyCertUefiGuid ();\r
- break;\r
-\r
- case WIN_CERT_TYPE_PKCS_SIGNED_DATA:\r
- //\r
- // Verify Pkcs signed data type.\r
- //\r
- Status = HashPeImageByType();\r
- if (EFI_ERROR(Status)) {\r
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
+ //\r
+ // Image Hash is in forbidden database (DBX).\r
+ //\r
goto Done;\r
}\r
\r
- VerifyStatus = VerifyCertPkcsSignedData ();\r
-\r
- //\r
- // For image verification against enrolled certificate(root or intermediate),\r
- // no need to check image's hash in the allowed database.\r
- //\r
- if (!EFI_ERROR (VerifyStatus)) {\r
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
+ //\r
+ // Image Hash is in allowed database (DB).\r
+ //\r
return EFI_SUCCESS;\r
}\r
\r
- default:\r
- return EFI_ACCESS_DENIED;\r
- }\r
- //\r
- // Get image hash value as executable's signature.\r
- //\r
- SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
- SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
- if (SignatureList == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
+ //\r
+ // Image Hash is not found in both forbidden and allowed database.\r
+ //\r
goto Done;\r
}\r
- SignatureList->SignatureHeaderSize = 0;\r
- SignatureList->SignatureListSize = (UINT32) SignatureListSize;\r
- SignatureList->SignatureSize = (UINT32) mImageDigestSize;\r
- CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
- Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
- CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
+\r
//\r
- // Signature database check after verification.\r
+ // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7 \r
+ // "Attribute Certificate Table".\r
+ // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.\r
//\r
- if (EFI_ERROR (VerifyStatus)) {\r
+ for (OffSet = SecDataDir->VirtualAddress;\r
+ OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);\r
+ OffSet += WinCertificate->dwLength, OffSet += ALIGN_SIZE (OffSet)) {\r
+ WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);\r
+ if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||\r
+ (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {\r
+ break;\r
+ }\r
+ \r
//\r
- // Verification failure.\r
+ // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.\r
//\r
- Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
- Status = EFI_ACCESS_DENIED;\r
- } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
+ if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
+ //\r
+ // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the \r
+ // Authenticode specification.\r
+ //\r
+ PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;\r
+ if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {\r
+ break;\r
+ }\r
+ AuthData = PkcsCertData->CertData;\r
+ AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);\r
+ } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
+ //\r
+ // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.\r
+ //\r
+ WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;\r
+ if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
+ break;\r
+ }\r
+ if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {\r
+ continue;\r
+ }\r
+ AuthData = WinCertUefiGuid->CertData;\r
+ AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);\r
+ } else {\r
+ if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {\r
+ break;\r
+ }\r
+ continue;\r
+ }\r
+\r
+ Status = HashPeImageByType (AuthData, AuthDataSize);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ \r
//\r
- // Executable signature verification passes, but is found in forbidden signature database.\r
+ // Check the digital signature against the revoked certificate in forbidden database (dbx).\r
//\r
- Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
- Status = EFI_ACCESS_DENIED;\r
- } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
+ if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {\r
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
+ VerifyStatus = EFI_ACCESS_DENIED;\r
+ break;\r
+ }\r
+\r
//\r
- // Executable signature is found in authorized signature database.\r
+ // Check the digital signature against the valid certificate in allowed database (db).\r
//\r
- Status = EFI_SUCCESS;\r
- } else {\r
+ if (EFI_ERROR (VerifyStatus)) {\r
+ if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {\r
+ VerifyStatus = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
//\r
- // Executable signature verification passes, but cannot be found in authorized signature database.\r
- // Get platform policy to determine the action.\r
+ // Check the image's hash value.\r
//\r
- Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED;\r
- Status = ImageAuthorization (Policy);\r
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
+ VerifyStatus = EFI_ACCESS_DENIED;\r
+ break;\r
+ } else if (EFI_ERROR (VerifyStatus)) {\r
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
+ VerifyStatus = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {\r
+ //\r
+ // The Size in Certificate Table or the attribute certicate table is corrupted.\r
+ //\r
+ VerifyStatus = EFI_ACCESS_DENIED;\r
+ }\r
+ \r
+ if (!EFI_ERROR (VerifyStatus)) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_ACCESS_DENIED;\r
+ if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {\r
+ //\r
+ // Get image hash value as executable's signature.\r
+ //\r
+ SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
+ SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
+ if (SignatureList == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ SignatureList->SignatureHeaderSize = 0;\r
+ SignatureList->SignatureListSize = (UINT32) SignatureListSize;\r
+ SignatureList->SignatureSize = (UINT32) mImageDigestSize;\r
+ CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
+ Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
+ CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
+ }\r
}\r
\r
Done:\r
// Policy decides to defer or reject the image; add its information in image executable information table.\r
//\r
AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);\r
+ Status = EFI_SECURITY_VIOLATION;\r
}\r
\r
if (SignatureList != NULL) {\r
FreePool (SignatureList);\r
}\r
\r
- FreePool (SetupMode);\r
-\r
return Status;\r
}\r
\r
/**\r
- When VariableWriteArchProtocol install, create "SecureBoot" variable.\r
- \r
- @param[in] Event Event whose notification function is being invoked.\r
- @param[in] Context Pointer to the notification function's context.\r
- \r
+ On Ready To Boot Services Event notification handler.\r
+\r
+ Add the image execution information table if it is not in system configuration table.\r
+\r
+ @param[in] Event Event whose notification function is being invoked\r
+ @param[in] Context Pointer to the notification function's context\r
+\r
**/\r
VOID\r
EFIAPI\r
-VariableWriteCallBack (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
+OnReadyToBoot (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
)\r
{\r
- UINT8 SecureBootMode;\r
- UINT8 *SecureBootModePtr;\r
- EFI_STATUS Status;\r
- VOID *ProtocolPointer;\r
+ EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;\r
+ UINTN ImageExeInfoTableSize;\r
\r
- Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, &ProtocolPointer);\r
- if (EFI_ERROR (Status)) {\r
+ EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
+ if (ImageExeInfoTable != NULL) {\r
return;\r
}\r
- \r
- //\r
- // Check whether "SecureBoot" variable exists.\r
- // If this library is built-in, it means firmware has capability to perform\r
- // driver signing verification.\r
- //\r
- SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME);\r
- if (SecureBootModePtr == NULL) {\r
- SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
- //\r
- // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable.\r
- //\r
- gRT->SetVariable (\r
- EFI_SECURE_BOOT_MODE_NAME,\r
- &gEfiGlobalVariableGuid,\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
- sizeof (UINT8),\r
- &SecureBootMode\r
- );\r
- } else {\r
- FreePool (SecureBootModePtr);\r
+\r
+ ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
+ ImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize);\r
+ if (ImageExeInfoTable == NULL) {\r
+ return ;\r
}\r
-} \r
+\r
+ ImageExeInfoTable->NumberOfImages = 0; \r
+ gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) ImageExeInfoTable);\r
+\r
+}\r
\r
/**\r
Register security measurement handler.\r
IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
- VOID *Registration;\r
+ EFI_EVENT Event;\r
\r
//\r
- // Register callback function upon VariableWriteArchProtocol.\r
- // \r
- EfiCreateProtocolNotifyEvent (\r
- &gEfiVariableWriteArchProtocolGuid,\r
+ // Register the event to publish the image execution table.\r
+ //\r
+ EfiCreateEventReadyToBootEx (\r
TPL_CALLBACK,\r
- VariableWriteCallBack,\r
- NULL,\r
- &Registration\r
- );\r
+ OnReadyToBoot, \r
+ NULL, \r
+ &Event\r
+ ); \r
\r
- return RegisterSecurityHandler (\r
+ return RegisterSecurity2Handler (\r
DxeImageVerificationHandler,\r
EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
- ); \r
+ );\r
}\r