2 Implement image verification services for secure boot service in UEFI2.3.1.
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "DxeImageVerificationLib.h"
17 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader
;
19 UINT32 mPeCoffHeaderOffset
;
20 UINT8 mImageDigest
[MAX_DIGEST_SIZE
];
21 UINTN mImageDigestSize
;
22 EFI_IMAGE_DATA_DIRECTORY
*mSecDataDir
= NULL
;
23 UINT8
*mImageBase
= NULL
;
27 // Notify string for authorization UI.
29 CHAR16 mNotifyString1
[MAX_NOTIFY_STRING_LEN
] = L
"Image verification pass but not found in authorized database!";
30 CHAR16 mNotifyString2
[MAX_NOTIFY_STRING_LEN
] = L
"Launch this image anyway? (Yes/Defer/No)";
32 // Public Exponent of RSA Key.
34 CONST UINT8 mRsaE
[] = { 0x01, 0x00, 0x01 };
38 // OID ASN.1 Value for Hash Algorithms
40 UINT8 mHashOidValue
[] = {
41 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, // OBJ_md5
42 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1
43 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224
44 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256
45 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384
46 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512
49 HASH_TABLE mHash
[] = {
50 { L
"SHA1", 20, &mHashOidValue
[8], 5, Sha1GetContextSize
, Sha1Init
, Sha1Update
, Sha1Final
},
51 { L
"SHA224", 28, &mHashOidValue
[13], 9, NULL
, NULL
, NULL
, NULL
},
52 { L
"SHA256", 32, &mHashOidValue
[22], 9, Sha256GetContextSize
,Sha256Init
, Sha256Update
, Sha256Final
},
53 { L
"SHA384", 48, &mHashOidValue
[31], 9, NULL
, NULL
, NULL
, NULL
},
54 { L
"SHA512", 64, &mHashOidValue
[40], 9, NULL
, NULL
, NULL
, NULL
}
61 @param[in] File This is a pointer to the device path of the file that is
64 @return UINT32 Image Type
69 IN CONST EFI_DEVICE_PATH_PROTOCOL
*File
73 EFI_HANDLE DeviceHandle
;
74 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
75 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
78 // First check to see if File is from a Firmware Volume
81 TempDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)File
;
82 Status
= gBS
->LocateDevicePath (
83 &gEfiFirmwareVolume2ProtocolGuid
,
87 if (!EFI_ERROR (Status
)) {
88 Status
= gBS
->OpenProtocol (
90 &gEfiFirmwareVolume2ProtocolGuid
,
94 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
96 if (!EFI_ERROR (Status
)) {
102 // Next check to see if File is from a Block I/O device
105 TempDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)File
;
106 Status
= gBS
->LocateDevicePath (
107 &gEfiBlockIoProtocolGuid
,
111 if (!EFI_ERROR (Status
)) {
113 Status
= gBS
->OpenProtocol (
115 &gEfiBlockIoProtocolGuid
,
119 EFI_OPEN_PROTOCOL_GET_PROTOCOL
121 if (!EFI_ERROR (Status
) && BlockIo
!= NULL
) {
122 if (BlockIo
->Media
!= NULL
) {
123 if (BlockIo
->Media
->RemovableMedia
) {
125 // Block I/O is present and specifies the media is removable
127 return IMAGE_FROM_REMOVABLE_MEDIA
;
130 // Block I/O is present and specifies the media is not removable
132 return IMAGE_FROM_FIXED_MEDIA
;
139 // File is not in a Firmware Volume or on a Block I/O device, so check to see if
140 // the device path supports the Simple File System Protocol.
143 TempDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)File
;
144 Status
= gBS
->LocateDevicePath (
145 &gEfiSimpleFileSystemProtocolGuid
,
149 if (!EFI_ERROR (Status
)) {
151 // Simple File System is present without Block I/O, so assume media is fixed.
153 return IMAGE_FROM_FIXED_MEDIA
;
157 // File is not from an FV, Block I/O or Simple File System, so the only options
158 // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.
160 TempDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*)File
;
161 while (!IsDevicePathEndType (TempDevicePath
)) {
162 switch (DevicePathType (TempDevicePath
)) {
164 case MEDIA_DEVICE_PATH
:
165 if (DevicePathSubType (TempDevicePath
) == MEDIA_RELATIVE_OFFSET_RANGE_DP
) {
166 return IMAGE_FROM_OPTION_ROM
;
170 case MESSAGING_DEVICE_PATH
:
171 if (DevicePathSubType(TempDevicePath
) == MSG_MAC_ADDR_DP
) {
172 return IMAGE_FROM_REMOVABLE_MEDIA
;
179 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
181 return IMAGE_UNKNOWN
;
185 Caculate hash of Pe/Coff image based on the authenticode image hashing in
186 PE/COFF Specification 8.0 Appendix A
188 @param[in] HashAlg Hash algorithm type.
190 @retval TRUE Successfully hash image.
191 @retval FALSE Fail in hash image.
201 EFI_IMAGE_SECTION_HEADER
*Section
;
206 UINTN SumOfBytesHashed
;
207 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
212 SectionHeader
= NULL
;
215 if ((HashAlg
!= HASHALG_SHA1
) && (HashAlg
!= HASHALG_SHA256
)) {
220 // Initialize context of hash.
222 ZeroMem (mImageDigest
, MAX_DIGEST_SIZE
);
224 if (HashAlg
== HASHALG_SHA1
) {
225 mImageDigestSize
= SHA1_DIGEST_SIZE
;
226 mCertType
= gEfiCertSha1Guid
;
227 } else if (HashAlg
== HASHALG_SHA256
) {
228 mImageDigestSize
= SHA256_DIGEST_SIZE
;
229 mCertType
= gEfiCertSha256Guid
;
234 CtxSize
= mHash
[HashAlg
].GetContextSize();
236 HashCtx
= AllocatePool (CtxSize
);
237 ASSERT (HashCtx
!= NULL
);
239 // 1. Load the image header into memory.
241 // 2. Initialize a SHA hash context.
242 Status
= mHash
[HashAlg
].HashInit(HashCtx
);
248 // Measuring PE/COFF Image Header;
249 // But CheckSum field and SECURITY data directory (certificate) are excluded
251 Magic
= mNtHeader
.Pe32
->OptionalHeader
.Magic
;
253 // 3. Calculate the distance from the base of the image header to the image checksum address.
254 // 4. Hash the image header from its base to beginning of the image checksum.
256 HashBase
= mImageBase
;
257 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
261 HashSize
= (UINTN
) ((UINT8
*) (&mNtHeader
.Pe32
->OptionalHeader
.CheckSum
) - HashBase
);
266 HashSize
= (UINTN
) ((UINT8
*) (&mNtHeader
.Pe32Plus
->OptionalHeader
.CheckSum
) - HashBase
);
269 Status
= mHash
[HashAlg
].HashUpdate(HashCtx
, HashBase
, HashSize
);
274 // 5. Skip over the image checksum (it occupies a single ULONG).
275 // 6. Get the address of the beginning of the Cert Directory.
276 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
278 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
282 HashBase
= (UINT8
*) &mNtHeader
.Pe32
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
283 HashSize
= (UINTN
) ((UINT8
*) (&mNtHeader
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
]) - HashBase
);
288 HashBase
= (UINT8
*) &mNtHeader
.Pe32Plus
->OptionalHeader
.CheckSum
+ sizeof (UINT32
);
289 HashSize
= (UINTN
) ((UINT8
*) (&mNtHeader
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
]) - HashBase
);
292 Status
= mHash
[HashAlg
].HashUpdate(HashCtx
, HashBase
, HashSize
);
297 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
298 // 9. Hash everything from the end of the Cert Directory to the end of image header.
300 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
304 HashBase
= (UINT8
*) &mNtHeader
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1];
305 HashSize
= mNtHeader
.Pe32
->OptionalHeader
.SizeOfHeaders
- (UINTN
) ((UINT8
*) (&mNtHeader
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1]) - mImageBase
);
310 HashBase
= (UINT8
*) &mNtHeader
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1];
311 HashSize
= mNtHeader
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- (UINTN
) ((UINT8
*) (&mNtHeader
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1]) - mImageBase
);
314 Status
= mHash
[HashAlg
].HashUpdate(HashCtx
, HashBase
, HashSize
);
319 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
321 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
325 SumOfBytesHashed
= mNtHeader
.Pe32
->OptionalHeader
.SizeOfHeaders
;
330 SumOfBytesHashed
= mNtHeader
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
334 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
335 // structures in the image. The 'NumberOfSections' field of the image
336 // header indicates how big the table should be. Do not include any
337 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
339 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER
) * mNtHeader
.Pe32
->FileHeader
.NumberOfSections
);
340 ASSERT (SectionHeader
!= NULL
);
342 // 12. Using the 'PointerToRawData' in the referenced section headers as
343 // a key, arrange the elements in the table in ascending order. In other
344 // words, sort the section headers according to the disk-file offset of
347 Section
= (EFI_IMAGE_SECTION_HEADER
*) (
349 mPeCoffHeaderOffset
+
351 sizeof (EFI_IMAGE_FILE_HEADER
) +
352 mNtHeader
.Pe32
->FileHeader
.SizeOfOptionalHeader
354 for (Index
= 0; Index
< mNtHeader
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
356 while ((Pos
> 0) && (Section
->PointerToRawData
< SectionHeader
[Pos
- 1].PointerToRawData
)) {
357 CopyMem (&SectionHeader
[Pos
], &SectionHeader
[Pos
- 1], sizeof (EFI_IMAGE_SECTION_HEADER
));
360 CopyMem (&SectionHeader
[Pos
], Section
, sizeof (EFI_IMAGE_SECTION_HEADER
));
365 // 13. Walk through the sorted table, bring the corresponding section
366 // into memory, and hash the entire section (using the 'SizeOfRawData'
367 // field in the section header to determine the amount of data to hash).
368 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
369 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
371 for (Index
= 0; Index
< mNtHeader
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
372 Section
= &SectionHeader
[Index
];
373 if (Section
->SizeOfRawData
== 0) {
376 HashBase
= mImageBase
+ Section
->PointerToRawData
;
377 HashSize
= (UINTN
) Section
->SizeOfRawData
;
379 Status
= mHash
[HashAlg
].HashUpdate(HashCtx
, HashBase
, HashSize
);
384 SumOfBytesHashed
+= HashSize
;
388 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
389 // data in the file that needs to be added to the hash. This data begins
390 // at file offset SUM_OF_BYTES_HASHED and its length is:
391 // FileSize - (CertDirectory->Size)
393 if (mImageSize
> SumOfBytesHashed
) {
394 HashBase
= mImageBase
+ SumOfBytesHashed
;
395 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
401 mNtHeader
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
-
409 mNtHeader
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
-
413 Status
= mHash
[HashAlg
].HashUpdate(HashCtx
, HashBase
, HashSize
);
418 Status
= mHash
[HashAlg
].HashFinal(HashCtx
, mImageDigest
);
421 if (HashCtx
!= NULL
) {
424 if (SectionHeader
!= NULL
) {
425 FreePool (SectionHeader
);
431 Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of
432 Pe/Coff image based on the authenticode image hashing in PE/COFF Specification
435 @retval EFI_UNSUPPORTED Hash algorithm is not supported.
436 @retval EFI_SUCCESS Hash successfully.
445 WIN_CERTIFICATE_EFI_PKCS
*PkcsCertData
;
447 PkcsCertData
= (WIN_CERTIFICATE_EFI_PKCS
*) (mImageBase
+ mSecDataDir
->VirtualAddress
);
449 for (Index
= 0; Index
< HASHALG_MAX
; Index
++) {
451 // Check the Hash algorithm in PE/COFF Authenticode.
452 // According to PKCS#7 Definition:
453 // SignedData ::= SEQUENCE {
455 // digestAlgorithms DigestAlgorithmIdentifiers,
456 // contentInfo ContentInfo,
458 // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
459 // This field has the fixed offset (+32) in final Authenticode ASN.1 data.
461 if (CompareMem (PkcsCertData
->CertData
+ 32, mHash
[Index
].OidValue
, mHash
[Index
].OidLength
) == 0) {
466 if (Index
== HASHALG_MAX
) {
467 return EFI_UNSUPPORTED
;
471 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
473 if (!HashPeImage(Index
)) {
474 return EFI_UNSUPPORTED
;
482 Returns the size of a given image execution info table in bytes.
484 This function returns the size, in bytes, of the image execution info table specified by
485 ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.
487 @param ImageExeInfoTable A pointer to a image execution info table structure.
489 @retval 0 If ImageExeInfoTable is NULL.
490 @retval Others The size of a image execution info table in bytes.
494 GetImageExeInfoTableSize (
495 EFI_IMAGE_EXECUTION_INFO_TABLE
*ImageExeInfoTable
499 EFI_IMAGE_EXECUTION_INFO
*ImageExeInfoItem
;
502 if (ImageExeInfoTable
== NULL
) {
506 ImageExeInfoItem
= (EFI_IMAGE_EXECUTION_INFO
*) ((UINT8
*) ImageExeInfoTable
+ sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE
));
507 TotalSize
= sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE
);
508 for (Index
= 0; Index
< ImageExeInfoTable
->NumberOfImages
; Index
++) {
509 TotalSize
+= ReadUnaligned32 ((UINT32
*) &ImageExeInfoItem
->InfoSize
);
510 ImageExeInfoItem
= (EFI_IMAGE_EXECUTION_INFO
*) ((UINT8
*) ImageExeInfoItem
+ ReadUnaligned32 ((UINT32
*) &ImageExeInfoItem
->InfoSize
));
517 Create an Image Execution Information Table entry and add it to system configuration table.
519 @param[in] Action Describes the action taken by the firmware regarding this image.
520 @param[in] Name Input a null-terminated, user-friendly name.
521 @param[in] DevicePath Input device path pointer.
522 @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.
523 @param[in] SignatureSize Size of signature.
528 IN EFI_IMAGE_EXECUTION_ACTION Action
,
529 IN CHAR16
*Name OPTIONAL
,
530 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
531 IN EFI_SIGNATURE_LIST
*Signature OPTIONAL
,
532 IN UINTN SignatureSize
536 EFI_IMAGE_EXECUTION_INFO_TABLE
*ImageExeInfoTable
;
537 EFI_IMAGE_EXECUTION_INFO_TABLE
*NewImageExeInfoTable
;
538 EFI_IMAGE_EXECUTION_INFO
*ImageExeInfoEntry
;
539 UINTN ImageExeInfoTableSize
;
540 UINTN NewImageExeInfoEntrySize
;
542 UINTN DevicePathSize
;
544 ASSERT (DevicePath
!= NULL
);
545 ImageExeInfoTable
= NULL
;
546 NewImageExeInfoTable
= NULL
;
547 ImageExeInfoEntry
= NULL
;
551 NameStringLen
= StrSize (Name
);
554 ImageExeInfoTable
= NULL
;
555 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid
, (VOID
**)&ImageExeInfoTable
);
556 if (ImageExeInfoTable
!= NULL
) {
558 // The table has been found!
559 // We must enlarge the table to accmodate the new exe info entry.
561 ImageExeInfoTableSize
= GetImageExeInfoTableSize (ImageExeInfoTable
);
565 // We should create a new table to append to the configuration table.
567 ImageExeInfoTableSize
= sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE
);
570 DevicePathSize
= GetDevicePathSize (DevicePath
);
571 NewImageExeInfoEntrySize
= sizeof (EFI_IMAGE_EXECUTION_INFO
) + NameStringLen
+ DevicePathSize
+ SignatureSize
;
572 NewImageExeInfoTable
= (EFI_IMAGE_EXECUTION_INFO_TABLE
*) AllocateRuntimePool (ImageExeInfoTableSize
+ NewImageExeInfoEntrySize
);
573 ASSERT (NewImageExeInfoTable
!= NULL
);
575 if (ImageExeInfoTable
!= NULL
) {
576 CopyMem (NewImageExeInfoTable
, ImageExeInfoTable
, ImageExeInfoTableSize
);
578 NewImageExeInfoTable
->NumberOfImages
= 0;
580 NewImageExeInfoTable
->NumberOfImages
++;
581 ImageExeInfoEntry
= (EFI_IMAGE_EXECUTION_INFO
*) ((UINT8
*) NewImageExeInfoTable
+ ImageExeInfoTableSize
);
583 // Update new item's infomation.
585 WriteUnaligned32 ((UINT32
*) &ImageExeInfoEntry
->Action
, Action
);
586 WriteUnaligned32 ((UINT32
*) &ImageExeInfoEntry
->InfoSize
, (UINT32
) NewImageExeInfoEntrySize
);
589 CopyMem ((UINT8
*) &ImageExeInfoEntry
->InfoSize
+ sizeof (UINT32
), Name
, NameStringLen
);
592 (UINT8
*) &ImageExeInfoEntry
->InfoSize
+ sizeof (UINT32
) + NameStringLen
,
596 if (Signature
!= NULL
) {
598 (UINT8
*) &ImageExeInfoEntry
->InfoSize
+ sizeof (UINT32
) + NameStringLen
+ DevicePathSize
,
604 // Update/replace the image execution table.
606 Status
= gBS
->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid
, (VOID
*) NewImageExeInfoTable
);
607 ASSERT_EFI_ERROR (Status
);
609 // Free Old table data!
611 if (ImageExeInfoTable
!= NULL
) {
612 FreePool (ImageExeInfoTable
);
617 Discover if the UEFI image is authorized by user's policy setting.
619 @param[in] Policy Specify platform's policy setting.
621 @retval EFI_ACCESS_DENIED Image is not allowed to run.
622 @retval EFI_SECURITY_VIOLATION Image is deferred.
623 @retval EFI_SUCCESS Image is authorized to run.
634 Status
= EFI_ACCESS_DENIED
;
638 case QUERY_USER_ON_SECURITY_VIOLATION
:
640 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, mNotifyString1
, mNotifyString2
, NULL
);
641 if (Key
.UnicodeChar
== L
'Y' || Key
.UnicodeChar
== L
'y') {
642 Status
= EFI_SUCCESS
;
644 } else if (Key
.UnicodeChar
== L
'N' || Key
.UnicodeChar
== L
'n') {
645 Status
= EFI_ACCESS_DENIED
;
647 } else if (Key
.UnicodeChar
== L
'D' || Key
.UnicodeChar
== L
'd') {
648 Status
= EFI_SECURITY_VIOLATION
;
654 case ALLOW_EXECUTE_ON_SECURITY_VIOLATION
:
655 Status
= EFI_SUCCESS
;
658 case DEFER_EXECUTE_ON_SECURITY_VIOLATION
:
659 Status
= EFI_SECURITY_VIOLATION
;
662 case DENY_EXECUTE_ON_SECURITY_VIOLATION
:
663 Status
= EFI_ACCESS_DENIED
;
671 Check whether signature is in specified database.
673 @param[in] VariableName Name of database variable that is searched in.
674 @param[in] Signature Pointer to signature that is searched for.
675 @param[in] CertType Pointer to hash algrithom.
676 @param[in] SignatureSize Size of Signature.
678 @return TRUE Found the signature in the variable database.
679 @return FALSE Not found the signature in the variable database.
683 IsSignatureFoundInDatabase (
684 IN CHAR16
*VariableName
,
686 IN EFI_GUID
*CertType
,
687 IN UINTN SignatureSize
691 EFI_SIGNATURE_LIST
*CertList
;
692 EFI_SIGNATURE_DATA
*Cert
;
699 // Read signature database variable.
704 Status
= gRT
->GetVariable (VariableName
, &gEfiImageSecurityDatabaseGuid
, NULL
, &DataSize
, NULL
);
705 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
709 Data
= (UINT8
*) AllocateZeroPool (DataSize
);
710 ASSERT (Data
!= NULL
);
712 Status
= gRT
->GetVariable (VariableName
, &gEfiImageSecurityDatabaseGuid
, NULL
, &DataSize
, Data
);
713 if (EFI_ERROR (Status
)) {
717 // Enumerate all signature data in SigDB to check if executable's signature exists.
719 CertList
= (EFI_SIGNATURE_LIST
*) Data
;
720 while ((DataSize
> 0) && (DataSize
>= CertList
->SignatureListSize
)) {
721 CertCount
= (CertList
->SignatureListSize
- CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
722 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
723 if ((CertList
->SignatureSize
== sizeof(EFI_SIGNATURE_DATA
) - 1 + SignatureSize
) && (CompareGuid(&CertList
->SignatureType
, CertType
))) {
724 for (Index
= 0; Index
< CertCount
; Index
++) {
725 if (CompareMem (Cert
->SignatureData
, Signature
, SignatureSize
) == 0) {
727 // Find the signature in database.
733 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
741 DataSize
-= CertList
->SignatureListSize
;
742 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
754 Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format .
756 @retval EFI_SUCCESS Image pass verification.
757 @retval EFI_SECURITY_VIOLATION Image fail verification.
758 @retval other error value
762 VerifyCertPkcsSignedData (
767 BOOLEAN VerifyStatus
;
768 WIN_CERTIFICATE_EFI_PKCS
*PkcsCertData
;
769 EFI_SIGNATURE_LIST
*CertList
;
770 EFI_SIGNATURE_DATA
*Cert
;
783 VerifyStatus
= FALSE
;
784 PkcsCertData
= (WIN_CERTIFICATE_EFI_PKCS
*) (mImageBase
+ mSecDataDir
->VirtualAddress
);
787 // 1: Find certificate from KEK database and try to verify authenticode struct.
790 Status
= gRT
->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME
, &gEfiGlobalVariableGuid
, NULL
, &DataSize
, NULL
);
791 if (Status
== EFI_BUFFER_TOO_SMALL
) {
792 Data
= (UINT8
*)AllocateZeroPool (DataSize
);
793 ASSERT (Data
!= NULL
);
795 Status
= gRT
->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME
, &gEfiGlobalVariableGuid
, NULL
, &DataSize
, (VOID
*)Data
);
796 if (EFI_ERROR (Status
)) {
801 // Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data.
803 CertList
= (EFI_SIGNATURE_LIST
*) Data
;
804 while ((DataSize
> 0) && (DataSize
>= CertList
->SignatureListSize
)) {
805 if (CompareGuid (&CertList
->SignatureType
, &gEfiCertX509Guid
)) {
806 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
807 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
808 for (Index
= 0; Index
< CertCount
; Index
++) {
810 // Iterate each Signature Data Node within this CertList for a verify
812 RootCert
= Cert
->SignatureData
;
813 RootCertSize
= CertList
->SignatureSize
;
816 // Call AuthenticodeVerify library to Verify Authenticode struct.
818 VerifyStatus
= AuthenticodeVerify (
819 PkcsCertData
->CertData
,
820 mSecDataDir
->Size
- sizeof(PkcsCertData
->Hdr
),
830 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
833 DataSize
-= CertList
->SignatureListSize
;
834 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
841 // 2: Find certificate from DB database and try to verify authenticode struct.
844 Status
= gRT
->GetVariable (EFI_IMAGE_SECURITY_DATABASE
, &gEfiImageSecurityDatabaseGuid
, NULL
, &DataSize
, NULL
);
845 if (Status
== EFI_BUFFER_TOO_SMALL
) {
846 Data
= (UINT8
*)AllocateZeroPool (DataSize
);
847 ASSERT (Data
!= NULL
);
849 Status
= gRT
->GetVariable (EFI_IMAGE_SECURITY_DATABASE
, &gEfiImageSecurityDatabaseGuid
, NULL
, &DataSize
, (VOID
*)Data
);
850 if (EFI_ERROR (Status
)) {
855 // Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data.
857 CertList
= (EFI_SIGNATURE_LIST
*) Data
;
858 while ((DataSize
> 0) && (DataSize
>= CertList
->SignatureListSize
)) {
859 if (CompareGuid (&CertList
->SignatureType
, &gEfiCertX509Guid
)) {
860 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
861 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
862 for (Index
= 0; Index
< CertCount
; Index
++) {
864 // Iterate each Signature Data Node within this CertList for a verify
866 RootCert
= Cert
->SignatureData
;
867 RootCertSize
= CertList
->SignatureSize
;
870 // Call AuthenticodeVerify library to Verify Authenticode struct.
872 VerifyStatus
= AuthenticodeVerify (
873 PkcsCertData
->CertData
,
874 mSecDataDir
->Size
- sizeof(PkcsCertData
->Hdr
),
884 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
887 DataSize
-= CertList
->SignatureListSize
;
888 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
900 return EFI_SECURITY_VIOLATION
;
905 Verify certificate in WIN_CERTIFICATE_UEFI_GUID format.
907 @retval EFI_SUCCESS Image pass verification.
908 @retval EFI_SECURITY_VIOLATION Image fail verification.
909 @retval other error value
918 WIN_CERTIFICATE_UEFI_GUID
*EfiCert
;
919 EFI_SIGNATURE_LIST
*KekList
;
920 EFI_SIGNATURE_DATA
*KekItem
;
921 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
938 EfiCert
= (WIN_CERTIFICATE_UEFI_GUID
*) (mImageBase
+ mSecDataDir
->VirtualAddress
);
939 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) EfiCert
->CertData
;
940 if (!CompareGuid (&EfiCert
->CertType
, &gEfiCertTypeRsa2048Sha256Guid
)) {
942 // Invalid Certificate Data Type.
944 return EFI_SECURITY_VIOLATION
;
948 // Get KEK database variable data size
950 Result
= gRT
->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME
, &gEfiGlobalVariableGuid
, NULL
, &KekDataSize
, NULL
);
951 if (Result
!= EFI_BUFFER_TOO_SMALL
) {
952 return EFI_SECURITY_VIOLATION
;
956 // Get KEK database variable.
958 KekList
= GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME
);
959 if (KekList
== NULL
) {
960 return EFI_SECURITY_VIOLATION
;
964 // Enumerate all Kek items in this list to verify the variable certificate data.
965 // If anyone is authenticated successfully, it means the variable is correct!
967 while ((KekDataSize
> 0) && (KekDataSize
>= KekList
->SignatureListSize
)) {
968 if (CompareGuid (&KekList
->SignatureType
, &gEfiCertRsa2048Guid
)) {
969 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekList
+ sizeof (EFI_SIGNATURE_LIST
) + KekList
->SignatureHeaderSize
);
970 KekCount
= (KekList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - KekList
->SignatureHeaderSize
) / KekList
->SignatureSize
;
971 for (Index
= 0; Index
< KekCount
; Index
++) {
972 if (CompareMem (KekItem
->SignatureData
, CertBlock
->PublicKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
976 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekItem
+ KekList
->SignatureSize
);
979 KekDataSize
-= KekList
->SignatureListSize
;
980 KekList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) KekList
+ KekList
->SignatureListSize
);
985 // Signed key is not a trust one.
991 // Now, we found the corresponding security policy.
992 // Verify the data payload.
995 ASSERT (Rsa
!= NULL
);
997 // Set RSA Key Components.
998 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
1000 Status
= RsaSetKey (Rsa
, RsaKeyN
, CertBlock
->PublicKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
1004 Status
= RsaSetKey (Rsa
, RsaKeyE
, mRsaE
, sizeof (mRsaE
));
1009 // Verify the signature.
1011 Status
= RsaPkcs1Verify (
1015 CertBlock
->Signature
,
1016 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
1020 if (KekList
!= NULL
) {
1029 return EFI_SECURITY_VIOLATION
;
1034 Provide verification service for signed images, which include both signature validation
1035 and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
1036 MSFT Authenticode type signatures are supported.
1038 In this implementation, only verify external executables when in USER MODE.
1039 Executables from FV is bypass, so pass in AuthenticationStatus is ignored.
1041 @param[in] AuthenticationStatus
1042 This is the authentication status returned from the security
1043 measurement services for the input file.
1044 @param[in] File This is a pointer to the device path of the file that is
1045 being dispatched. This will optionally be used for logging.
1046 @param[in] FileBuffer File buffer matches the input file device path.
1047 @param[in] FileSize Size of File buffer matches the input file device path.
1049 @retval EFI_SUCCESS The file specified by File did authenticate, and the
1050 platform policy dictates that the DXE Core may use File.
1051 @retval EFI_INVALID_PARAMETER File is NULL.
1052 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
1053 the platform policy dictates that File should be placed
1054 in the untrusted state. A file may be promoted from
1055 the untrusted to the trusted state at a future time
1056 with a call to the Trust() DXE Service.
1057 @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
1058 the platform policy dictates that File should not be
1059 used for any purpose.
1064 DxeImageVerificationHandler (
1065 IN UINT32 AuthenticationStatus
,
1066 IN CONST EFI_DEVICE_PATH_PROTOCOL
*File
,
1067 IN VOID
*FileBuffer
,
1074 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1075 EFI_STATUS VerifyStatus
;
1077 EFI_SIGNATURE_LIST
*SignatureList
;
1078 UINTN SignatureListSize
;
1079 EFI_SIGNATURE_DATA
*Signature
;
1080 EFI_IMAGE_EXECUTION_ACTION Action
;
1081 WIN_CERTIFICATE
*WinCertificate
;
1085 return EFI_INVALID_PARAMETER
;
1088 SignatureList
= NULL
;
1089 SignatureListSize
= 0;
1090 WinCertificate
= NULL
;
1091 Action
= EFI_IMAGE_EXECUTION_AUTH_UNTESTED
;
1092 Status
= EFI_ACCESS_DENIED
;
1094 // Check the image type and get policy setting.
1096 switch (GetImageType (File
)) {
1099 Policy
= ALWAYS_EXECUTE
;
1102 case IMAGE_FROM_OPTION_ROM
:
1103 Policy
= PcdGet32 (PcdOptionRomImageVerificationPolicy
);
1106 case IMAGE_FROM_REMOVABLE_MEDIA
:
1107 Policy
= PcdGet32 (PcdRemovableMediaImageVerificationPolicy
);
1110 case IMAGE_FROM_FIXED_MEDIA
:
1111 Policy
= PcdGet32 (PcdFixedMediaImageVerificationPolicy
);
1115 Policy
= DENY_EXECUTE_ON_SECURITY_VIOLATION
;
1119 // If policy is always/never execute, return directly.
1121 if (Policy
== ALWAYS_EXECUTE
) {
1123 } else if (Policy
== NEVER_EXECUTE
) {
1124 return EFI_ACCESS_DENIED
;
1126 SetupMode
= GetEfiGlobalVariable (EFI_SETUP_MODE_NAME
);
1129 // SetupMode doesn't exist means no AuthVar driver is dispatched,
1130 // skip verification.
1132 if (SetupMode
== NULL
) {
1137 // If platform is in SETUP MODE, skip verification.
1139 if (*SetupMode
== SETUP_MODE
) {
1140 FreePool (SetupMode
);
1144 // Read the Dos header.
1146 ASSERT (FileBuffer
!= NULL
);
1147 mImageBase
= (UINT8
*) FileBuffer
;
1148 mImageSize
= FileSize
;
1149 DosHdr
= (EFI_IMAGE_DOS_HEADER
*) (mImageBase
);
1150 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1152 // DOS image header is present,
1153 // so read the PE header after the DOS image header.
1155 mPeCoffHeaderOffset
= DosHdr
->e_lfanew
;
1157 mPeCoffHeaderOffset
= 0;
1160 // Check PE/COFF image.
1162 mNtHeader
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*) (mImageBase
+ mPeCoffHeaderOffset
);
1163 if (mNtHeader
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1165 // It is not a valid Pe/Coff file.
1167 return EFI_ACCESS_DENIED
;
1170 Magic
= mNtHeader
.Pe32
->OptionalHeader
.Magic
;
1171 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1175 mSecDataDir
= (EFI_IMAGE_DATA_DIRECTORY
*)&mNtHeader
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
];
1178 // Use PE32+ offset.
1180 mSecDataDir
= (EFI_IMAGE_DATA_DIRECTORY
*)&mNtHeader
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
];
1183 if (mSecDataDir
->Size
== 0) {
1185 // This image is not signed.
1187 Action
= EFI_IMAGE_EXECUTION_AUTH_UNTESTED
;
1188 Status
= EFI_ACCESS_DENIED
;
1192 // Verify signature of executables.
1194 WinCertificate
= (WIN_CERTIFICATE
*) (mImageBase
+ mSecDataDir
->VirtualAddress
);
1196 switch (WinCertificate
->wCertificateType
) {
1198 case WIN_CERT_TYPE_EFI_GUID
:
1200 // Verify UEFI GUID type.
1202 if (!HashPeImage (HASHALG_SHA256
)) {
1206 VerifyStatus
= VerifyCertUefiGuid ();
1209 case WIN_CERT_TYPE_PKCS_SIGNED_DATA
:
1211 // Verify Pkcs signed data type.
1213 Status
= HashPeImageByType();
1214 if (EFI_ERROR(Status
)) {
1218 VerifyStatus
= VerifyCertPkcsSignedData ();
1221 // For image verification against enrolled certificate(root or intermediate),
1222 // no need to check image's hash in the allowed database.
1224 if (!EFI_ERROR (VerifyStatus
)) {
1229 return EFI_ACCESS_DENIED
;
1232 // Get image hash value as executable's signature.
1234 SignatureListSize
= sizeof (EFI_SIGNATURE_LIST
) + sizeof (EFI_SIGNATURE_DATA
) - 1 + mImageDigestSize
;
1235 SignatureList
= (EFI_SIGNATURE_LIST
*) AllocateZeroPool (SignatureListSize
);
1236 ASSERT (SignatureList
!= NULL
);
1237 SignatureList
->SignatureHeaderSize
= 0;
1238 SignatureList
->SignatureListSize
= (UINT32
) SignatureListSize
;
1239 SignatureList
->SignatureSize
= (UINT32
) mImageDigestSize
;
1240 CopyMem (&SignatureList
->SignatureType
, &mCertType
, sizeof (EFI_GUID
));
1241 Signature
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SignatureList
+ sizeof (EFI_SIGNATURE_LIST
));
1242 CopyMem (Signature
->SignatureData
, mImageDigest
, mImageDigestSize
);
1244 // Signature database check after verification.
1246 if (EFI_ERROR (VerifyStatus
)) {
1248 // Verification failure.
1250 Action
= EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED
;
1251 Status
= EFI_ACCESS_DENIED
;
1252 } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1
, Signature
->SignatureData
, &mCertType
, mImageDigestSize
)) {
1254 // Executable signature verification passes, but is found in forbidden signature database.
1256 Action
= EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND
;
1257 Status
= EFI_ACCESS_DENIED
;
1258 } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE
, Signature
->SignatureData
, &mCertType
, mImageDigestSize
)) {
1260 // Executable signature is found in authorized signature database.
1262 Status
= EFI_SUCCESS
;
1265 // Executable signature verification passes, but cannot be found in authorized signature database.
1266 // Get platform policy to determine the action.
1268 Action
= EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED
;
1269 Status
= ImageAuthorization (Policy
);
1273 if (Status
!= EFI_SUCCESS
) {
1275 // Policy decides to defer or reject the image; add its information in image executable information table.
1277 AddImageExeInfo (Action
, NULL
, File
, SignatureList
, SignatureListSize
);
1280 if (SignatureList
!= NULL
) {
1281 FreePool (SignatureList
);
1284 FreePool (SetupMode
);
1290 When VariableWriteArchProtocol install, create "SecureBoot" variable.
1292 @param[in] Event Event whose notification function is being invoked.
1293 @param[in] Context Pointer to the notification function's context.
1298 VariableWriteCallBack (
1303 UINT8 SecureBootMode
;
1304 UINT8
*SecureBootModePtr
;
1306 VOID
*ProtocolPointer
;
1308 Status
= gBS
->LocateProtocol (&gEfiVariableWriteArchProtocolGuid
, NULL
, &ProtocolPointer
);
1309 if (EFI_ERROR (Status
)) {
1314 // Check whether "SecureBoot" variable exists.
1315 // If this library is built-in, it means firmware has capability to perform
1316 // driver signing verification.
1318 SecureBootModePtr
= GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME
);
1319 if (SecureBootModePtr
== NULL
) {
1320 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
1322 // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable.
1325 EFI_SECURE_BOOT_MODE_NAME
,
1326 &gEfiGlobalVariableGuid
,
1327 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1332 FreePool (SecureBootModePtr
);
1337 Register security measurement handler.
1339 @param ImageHandle ImageHandle of the loaded driver.
1340 @param SystemTable Pointer to the EFI System Table.
1342 @retval EFI_SUCCESS The handlers were registered successfully.
1346 DxeImageVerificationLibConstructor (
1347 IN EFI_HANDLE ImageHandle
,
1348 IN EFI_SYSTEM_TABLE
*SystemTable
1354 // Register callback function upon VariableWriteArchProtocol.
1356 EfiCreateProtocolNotifyEvent (
1357 &gEfiVariableWriteArchProtocolGuid
,
1359 VariableWriteCallBack
,
1364 return RegisterSecurityHandler (
1365 DxeImageVerificationHandler
,
1366 EFI_AUTH_OPERATION_VERIFY_IMAGE
| EFI_AUTH_OPERATION_IMAGE_REQUIRED