]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
Add security package to repository.
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
1 /** @file
2 Implement image verification services for secure boot service in UEFI2.3.1.
3
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
9
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.
12
13 **/
14
15 #include "DxeImageVerificationLib.h"
16
17 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;
18 UINTN mImageSize;
19 UINT32 mPeCoffHeaderOffset;
20 UINT8 mImageDigest[MAX_DIGEST_SIZE];
21 UINTN mImageDigestSize;
22 EFI_IMAGE_DATA_DIRECTORY *mSecDataDir = NULL;
23 UINT8 *mImageBase = NULL;
24 EFI_GUID mCertType;
25
26 //
27 // Notify string for authorization UI.
28 //
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)";
31 //
32 // Public Exponent of RSA Key.
33 //
34 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
35
36
37 //
38 // OID ASN.1 Value for Hash Algorithms
39 //
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
47 };
48
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 }
55 };
56
57
58 /**
59 Get the image type.
60
61 @param[in] File This is a pointer to the device path of the file that is
62 being dispatched.
63
64 @return UINT32 Image Type
65
66 **/
67 UINT32
68 GetImageType (
69 IN CONST EFI_DEVICE_PATH_PROTOCOL *File
70 )
71 {
72 EFI_STATUS Status;
73 EFI_HANDLE DeviceHandle;
74 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
75 EFI_BLOCK_IO_PROTOCOL *BlockIo;
76
77 //
78 // First check to see if File is from a Firmware Volume
79 //
80 DeviceHandle = NULL;
81 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
82 Status = gBS->LocateDevicePath (
83 &gEfiFirmwareVolume2ProtocolGuid,
84 &TempDevicePath,
85 &DeviceHandle
86 );
87 if (!EFI_ERROR (Status)) {
88 Status = gBS->OpenProtocol (
89 DeviceHandle,
90 &gEfiFirmwareVolume2ProtocolGuid,
91 NULL,
92 NULL,
93 NULL,
94 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
95 );
96 if (!EFI_ERROR (Status)) {
97 return IMAGE_FROM_FV;
98 }
99 }
100
101 //
102 // Next check to see if File is from a Block I/O device
103 //
104 DeviceHandle = NULL;
105 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
106 Status = gBS->LocateDevicePath (
107 &gEfiBlockIoProtocolGuid,
108 &TempDevicePath,
109 &DeviceHandle
110 );
111 if (!EFI_ERROR (Status)) {
112 BlockIo = NULL;
113 Status = gBS->OpenProtocol (
114 DeviceHandle,
115 &gEfiBlockIoProtocolGuid,
116 (VOID **) &BlockIo,
117 NULL,
118 NULL,
119 EFI_OPEN_PROTOCOL_GET_PROTOCOL
120 );
121 if (!EFI_ERROR (Status) && BlockIo != NULL) {
122 if (BlockIo->Media != NULL) {
123 if (BlockIo->Media->RemovableMedia) {
124 //
125 // Block I/O is present and specifies the media is removable
126 //
127 return IMAGE_FROM_REMOVABLE_MEDIA;
128 } else {
129 //
130 // Block I/O is present and specifies the media is not removable
131 //
132 return IMAGE_FROM_FIXED_MEDIA;
133 }
134 }
135 }
136 }
137
138 //
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.
141 //
142 DeviceHandle = NULL;
143 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
144 Status = gBS->LocateDevicePath (
145 &gEfiSimpleFileSystemProtocolGuid,
146 &TempDevicePath,
147 &DeviceHandle
148 );
149 if (!EFI_ERROR (Status)) {
150 //
151 // Simple File System is present without Block I/O, so assume media is fixed.
152 //
153 return IMAGE_FROM_FIXED_MEDIA;
154 }
155
156 //
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.
159 //
160 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
161 while (!IsDevicePathEndType (TempDevicePath)) {
162 switch (DevicePathType (TempDevicePath)) {
163
164 case MEDIA_DEVICE_PATH:
165 if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {
166 return IMAGE_FROM_OPTION_ROM;
167 }
168 break;
169
170 case MESSAGING_DEVICE_PATH:
171 if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {
172 return IMAGE_FROM_REMOVABLE_MEDIA;
173 }
174 break;
175
176 default:
177 break;
178 }
179 TempDevicePath = NextDevicePathNode (TempDevicePath);
180 }
181 return IMAGE_UNKNOWN;
182 }
183
184 /**
185 Caculate hash of Pe/Coff image based on the authenticode image hashing in
186 PE/COFF Specification 8.0 Appendix A
187
188 @param[in] HashAlg Hash algorithm type.
189
190 @retval TRUE Successfully hash image.
191 @retval FALSE Fail in hash image.
192
193 **/
194 BOOLEAN
195 HashPeImage (
196 IN UINT32 HashAlg
197 )
198 {
199 BOOLEAN Status;
200 UINT16 Magic;
201 EFI_IMAGE_SECTION_HEADER *Section;
202 VOID *HashCtx;
203 UINTN CtxSize;
204 UINT8 *HashBase;
205 UINTN HashSize;
206 UINTN SumOfBytesHashed;
207 EFI_IMAGE_SECTION_HEADER *SectionHeader;
208 UINTN Index;
209 UINTN Pos;
210
211 HashCtx = NULL;
212 SectionHeader = NULL;
213 Status = FALSE;
214
215 if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {
216 return FALSE;
217 }
218
219 //
220 // Initialize context of hash.
221 //
222 ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
223
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;
230 } else {
231 return FALSE;
232 }
233
234 CtxSize = mHash[HashAlg].GetContextSize();
235
236 HashCtx = AllocatePool (CtxSize);
237 ASSERT (HashCtx != NULL);
238
239 // 1. Load the image header into memory.
240
241 // 2. Initialize a SHA hash context.
242 Status = mHash[HashAlg].HashInit(HashCtx);
243
244 if (!Status) {
245 goto Done;
246 }
247 //
248 // Measuring PE/COFF Image Header;
249 // But CheckSum field and SECURITY data directory (certificate) are excluded
250 //
251 Magic = mNtHeader.Pe32->OptionalHeader.Magic;
252 //
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.
255 //
256 HashBase = mImageBase;
257 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
258 //
259 // Use PE32 offset.
260 //
261 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);
262 } else {
263 //
264 // Use PE32+ offset.
265 //
266 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
267 }
268
269 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
270 if (!Status) {
271 goto Done;
272 }
273 //
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.
277 //
278 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
279 //
280 // Use PE32 offset.
281 //
282 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
283 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
284 } else {
285 //
286 // Use PE32+ offset.
287 //
288 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
289 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
290 }
291
292 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
293 if (!Status) {
294 goto Done;
295 }
296 //
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.
299 //
300 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
301 //
302 // Use PE32 offset
303 //
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);
306 } else {
307 //
308 // Use PE32+ offset.
309 //
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);
312 }
313
314 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
315 if (!Status) {
316 goto Done;
317 }
318 //
319 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
320 //
321 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
322 //
323 // Use PE32 offset.
324 //
325 SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;
326 } else {
327 //
328 // Use PE32+ offset
329 //
330 SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;
331 }
332
333 //
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.
338 //
339 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);
340 ASSERT (SectionHeader != NULL);
341 //
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
345 // the section.
346 //
347 Section = (EFI_IMAGE_SECTION_HEADER *) (
348 mImageBase +
349 mPeCoffHeaderOffset +
350 sizeof (UINT32) +
351 sizeof (EFI_IMAGE_FILE_HEADER) +
352 mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
353 );
354 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
355 Pos = Index;
356 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
357 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
358 Pos--;
359 }
360 CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
361 Section += 1;
362 }
363
364 //
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.
370 //
371 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
372 Section = &SectionHeader[Index];
373 if (Section->SizeOfRawData == 0) {
374 continue;
375 }
376 HashBase = mImageBase + Section->PointerToRawData;
377 HashSize = (UINTN) Section->SizeOfRawData;
378
379 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
380 if (!Status) {
381 goto Done;
382 }
383
384 SumOfBytesHashed += HashSize;
385 }
386
387 //
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)
392 //
393 if (mImageSize > SumOfBytesHashed) {
394 HashBase = mImageBase + SumOfBytesHashed;
395 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
396 //
397 // Use PE32 offset.
398 //
399 HashSize = (UINTN)(
400 mImageSize -
401 mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
402 SumOfBytesHashed);
403 } else {
404 //
405 // Use PE32+ offset.
406 //
407 HashSize = (UINTN)(
408 mImageSize -
409 mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
410 SumOfBytesHashed);
411 }
412
413 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
414 if (!Status) {
415 goto Done;
416 }
417 }
418 Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);
419
420 Done:
421 if (HashCtx != NULL) {
422 FreePool (HashCtx);
423 }
424 if (SectionHeader != NULL) {
425 FreePool (SectionHeader);
426 }
427 return Status;
428 }
429
430 /**
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
433 8.0 Appendix A
434
435 @retval EFI_UNSUPPORTED Hash algorithm is not supported.
436 @retval EFI_SUCCESS Hash successfully.
437
438 **/
439 EFI_STATUS
440 HashPeImageByType (
441 VOID
442 )
443 {
444 UINT8 Index;
445 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
446
447 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);
448
449 for (Index = 0; Index < HASHALG_MAX; Index++) {
450 //
451 // Check the Hash algorithm in PE/COFF Authenticode.
452 // According to PKCS#7 Definition:
453 // SignedData ::= SEQUENCE {
454 // version Version,
455 // digestAlgorithms DigestAlgorithmIdentifiers,
456 // contentInfo ContentInfo,
457 // .... }
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.
460 //
461 if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
462 break;
463 }
464 }
465
466 if (Index == HASHALG_MAX) {
467 return EFI_UNSUPPORTED;
468 }
469
470 //
471 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
472 //
473 if (!HashPeImage(Index)) {
474 return EFI_UNSUPPORTED;
475 }
476
477 return EFI_SUCCESS;
478 }
479
480
481 /**
482 Returns the size of a given image execution info table in bytes.
483
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.
486
487 @param ImageExeInfoTable A pointer to a image execution info table structure.
488
489 @retval 0 If ImageExeInfoTable is NULL.
490 @retval Others The size of a image execution info table in bytes.
491
492 **/
493 UINTN
494 GetImageExeInfoTableSize (
495 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable
496 )
497 {
498 UINTN Index;
499 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem;
500 UINTN TotalSize;
501
502 if (ImageExeInfoTable == NULL) {
503 return 0;
504 }
505
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));
511 }
512
513 return TotalSize;
514 }
515
516 /**
517 Create an Image Execution Information Table entry and add it to system configuration table.
518
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.
524
525 **/
526 VOID
527 AddImageExeInfo (
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
533 )
534 {
535 EFI_STATUS Status;
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;
541 UINTN NameStringLen;
542 UINTN DevicePathSize;
543
544 ASSERT (DevicePath != NULL);
545 ImageExeInfoTable = NULL;
546 NewImageExeInfoTable = NULL;
547 ImageExeInfoEntry = NULL;
548 NameStringLen = 0;
549
550 if (Name != NULL) {
551 NameStringLen = StrSize (Name);
552 }
553
554 ImageExeInfoTable = NULL;
555 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID**)&ImageExeInfoTable);
556 if (ImageExeInfoTable != NULL) {
557 //
558 // The table has been found!
559 // We must enlarge the table to accmodate the new exe info entry.
560 //
561 ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);
562 } else {
563 //
564 // Not Found!
565 // We should create a new table to append to the configuration table.
566 //
567 ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
568 }
569
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);
574
575 if (ImageExeInfoTable != NULL) {
576 CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);
577 } else {
578 NewImageExeInfoTable->NumberOfImages = 0;
579 }
580 NewImageExeInfoTable->NumberOfImages++;
581 ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);
582 //
583 // Update new item's infomation.
584 //
585 WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->Action, Action);
586 WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->InfoSize, (UINT32) NewImageExeInfoEntrySize);
587
588 if (Name != NULL) {
589 CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen);
590 }
591 CopyMem (
592 (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen,
593 DevicePath,
594 DevicePathSize
595 );
596 if (Signature != NULL) {
597 CopyMem (
598 (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize,
599 Signature,
600 SignatureSize
601 );
602 }
603 //
604 // Update/replace the image execution table.
605 //
606 Status = gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);
607 ASSERT_EFI_ERROR (Status);
608 //
609 // Free Old table data!
610 //
611 if (ImageExeInfoTable != NULL) {
612 FreePool (ImageExeInfoTable);
613 }
614 }
615
616 /**
617 Discover if the UEFI image is authorized by user's policy setting.
618
619 @param[in] Policy Specify platform's policy setting.
620
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.
624
625 **/
626 EFI_STATUS
627 ImageAuthorization (
628 IN UINT32 Policy
629 )
630 {
631 EFI_STATUS Status;
632 EFI_INPUT_KEY Key;
633
634 Status = EFI_ACCESS_DENIED;
635
636 switch (Policy) {
637
638 case QUERY_USER_ON_SECURITY_VIOLATION:
639 do {
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;
643 break;
644 } else if (Key.UnicodeChar == L'N' || Key.UnicodeChar == L'n') {
645 Status = EFI_ACCESS_DENIED;
646 break;
647 } else if (Key.UnicodeChar == L'D' || Key.UnicodeChar == L'd') {
648 Status = EFI_SECURITY_VIOLATION;
649 break;
650 }
651 } while (TRUE);
652 break;
653
654 case ALLOW_EXECUTE_ON_SECURITY_VIOLATION:
655 Status = EFI_SUCCESS;
656 break;
657
658 case DEFER_EXECUTE_ON_SECURITY_VIOLATION:
659 Status = EFI_SECURITY_VIOLATION;
660 break;
661
662 case DENY_EXECUTE_ON_SECURITY_VIOLATION:
663 Status = EFI_ACCESS_DENIED;
664 break;
665 }
666
667 return Status;
668 }
669
670 /**
671 Check whether signature is in specified database.
672
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.
677
678 @return TRUE Found the signature in the variable database.
679 @return FALSE Not found the signature in the variable database.
680
681 **/
682 BOOLEAN
683 IsSignatureFoundInDatabase (
684 IN CHAR16 *VariableName,
685 IN UINT8 *Signature,
686 IN EFI_GUID *CertType,
687 IN UINTN SignatureSize
688 )
689 {
690 EFI_STATUS Status;
691 EFI_SIGNATURE_LIST *CertList;
692 EFI_SIGNATURE_DATA *Cert;
693 UINTN DataSize;
694 UINT8 *Data;
695 UINTN Index;
696 UINTN CertCount;
697 BOOLEAN IsFound;
698 //
699 // Read signature database variable.
700 //
701 IsFound = FALSE;
702 Data = NULL;
703 DataSize = 0;
704 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
705 if (Status != EFI_BUFFER_TOO_SMALL) {
706 return FALSE;
707 }
708
709 Data = (UINT8 *) AllocateZeroPool (DataSize);
710 ASSERT (Data != NULL);
711
712 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
713 if (EFI_ERROR (Status)) {
714 goto Done;
715 }
716 //
717 // Enumerate all signature data in SigDB to check if executable's signature exists.
718 //
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) {
726 //
727 // Find the signature in database.
728 //
729 IsFound = TRUE;
730 break;
731 }
732
733 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
734 }
735
736 if (IsFound) {
737 break;
738 }
739 }
740
741 DataSize -= CertList->SignatureListSize;
742 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
743 }
744
745 Done:
746 if (Data != NULL) {
747 FreePool (Data);
748 }
749
750 return IsFound;
751 }
752
753 /**
754 Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format .
755
756 @retval EFI_SUCCESS Image pass verification.
757 @retval EFI_SECURITY_VIOLATION Image fail verification.
758 @retval other error value
759
760 **/
761 EFI_STATUS
762 VerifyCertPkcsSignedData (
763 VOID
764 )
765 {
766 EFI_STATUS Status;
767 BOOLEAN VerifyStatus;
768 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
769 EFI_SIGNATURE_LIST *CertList;
770 EFI_SIGNATURE_DATA *Cert;
771 UINTN DataSize;
772 UINT8 *Data;
773 UINT8 *RootCert;
774 UINTN RootCertSize;
775 UINTN Index;
776 UINTN CertCount;
777
778 Data = NULL;
779 CertList = NULL;
780 Cert = NULL;
781 RootCert = NULL;
782 RootCertSize = 0;
783 VerifyStatus = FALSE;
784 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);
785
786 //
787 // 1: Find certificate from KEK database and try to verify authenticode struct.
788 //
789 DataSize = 0;
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);
794
795 Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, (VOID *)Data);
796 if (EFI_ERROR (Status)) {
797 goto Done;
798 }
799
800 //
801 // Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data.
802 //
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++) {
809 //
810 // Iterate each Signature Data Node within this CertList for a verify
811 //
812 RootCert = Cert->SignatureData;
813 RootCertSize = CertList->SignatureSize;
814
815 //
816 // Call AuthenticodeVerify library to Verify Authenticode struct.
817 //
818 VerifyStatus = AuthenticodeVerify (
819 PkcsCertData->CertData,
820 mSecDataDir->Size - sizeof(PkcsCertData->Hdr),
821 RootCert,
822 RootCertSize,
823 mImageDigest,
824 mImageDigestSize
825 );
826
827 if (VerifyStatus) {
828 goto Done;
829 }
830 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
831 }
832 }
833 DataSize -= CertList->SignatureListSize;
834 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
835 }
836 }
837
838
839
840 //
841 // 2: Find certificate from DB database and try to verify authenticode struct.
842 //
843 DataSize = 0;
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);
848
849 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)Data);
850 if (EFI_ERROR (Status)) {
851 goto Done;
852 }
853
854 //
855 // Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data.
856 //
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++) {
863 //
864 // Iterate each Signature Data Node within this CertList for a verify
865 //
866 RootCert = Cert->SignatureData;
867 RootCertSize = CertList->SignatureSize;
868
869 //
870 // Call AuthenticodeVerify library to Verify Authenticode struct.
871 //
872 VerifyStatus = AuthenticodeVerify (
873 PkcsCertData->CertData,
874 mSecDataDir->Size - sizeof(PkcsCertData->Hdr),
875 RootCert,
876 RootCertSize,
877 mImageDigest,
878 mImageDigestSize
879 );
880
881 if (VerifyStatus) {
882 goto Done;
883 }
884 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
885 }
886 }
887 DataSize -= CertList->SignatureListSize;
888 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
889 }
890 }
891
892 Done:
893 if (Data != NULL) {
894 FreePool (Data);
895 }
896
897 if (VerifyStatus) {
898 return EFI_SUCCESS;
899 } else {
900 return EFI_SECURITY_VIOLATION;
901 }
902 }
903
904 /**
905 Verify certificate in WIN_CERTIFICATE_UEFI_GUID format.
906
907 @retval EFI_SUCCESS Image pass verification.
908 @retval EFI_SECURITY_VIOLATION Image fail verification.
909 @retval other error value
910
911 **/
912 EFI_STATUS
913 VerifyCertUefiGuid (
914 VOID
915 )
916 {
917 BOOLEAN Status;
918 WIN_CERTIFICATE_UEFI_GUID *EfiCert;
919 EFI_SIGNATURE_LIST *KekList;
920 EFI_SIGNATURE_DATA *KekItem;
921 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
922 VOID *Rsa;
923 UINTN KekCount;
924 UINTN Index;
925 UINTN KekDataSize;
926 BOOLEAN IsFound;
927 EFI_STATUS Result;
928
929 EfiCert = NULL;
930 KekList = NULL;
931 KekItem = NULL;
932 CertBlock = NULL;
933 Rsa = NULL;
934 Status = FALSE;
935 IsFound = FALSE;
936 KekDataSize = 0;
937
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)) {
941 //
942 // Invalid Certificate Data Type.
943 //
944 return EFI_SECURITY_VIOLATION;
945 }
946
947 //
948 // Get KEK database variable data size
949 //
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;
953 }
954
955 //
956 // Get KEK database variable.
957 //
958 KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME);
959 if (KekList == NULL) {
960 return EFI_SECURITY_VIOLATION;
961 }
962
963 //
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!
966 //
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) {
973 IsFound = TRUE;
974 break;
975 }
976 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
977 }
978 }
979 KekDataSize -= KekList->SignatureListSize;
980 KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);
981 }
982
983 if (!IsFound) {
984 //
985 // Signed key is not a trust one.
986 //
987 goto Done;
988 }
989
990 //
991 // Now, we found the corresponding security policy.
992 // Verify the data payload.
993 //
994 Rsa = RsaNew ();
995 ASSERT (Rsa != NULL);
996 //
997 // Set RSA Key Components.
998 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
999 //
1000 Status = RsaSetKey (Rsa, RsaKeyN, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE);
1001 if (!Status) {
1002 goto Done;
1003 }
1004 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
1005 if (!Status) {
1006 goto Done;
1007 }
1008 //
1009 // Verify the signature.
1010 //
1011 Status = RsaPkcs1Verify (
1012 Rsa,
1013 mImageDigest,
1014 mImageDigestSize,
1015 CertBlock->Signature,
1016 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
1017 );
1018
1019 Done:
1020 if (KekList != NULL) {
1021 FreePool (KekList);
1022 }
1023 if (Rsa != NULL ) {
1024 RsaFree (Rsa);
1025 }
1026 if (Status) {
1027 return EFI_SUCCESS;
1028 } else {
1029 return EFI_SECURITY_VIOLATION;
1030 }
1031 }
1032
1033 /**
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.
1037
1038 In this implementation, only verify external executables when in USER MODE.
1039 Executables from FV is bypass, so pass in AuthenticationStatus is ignored.
1040
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.
1048
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.
1060
1061 **/
1062 EFI_STATUS
1063 EFIAPI
1064 DxeImageVerificationHandler (
1065 IN UINT32 AuthenticationStatus,
1066 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
1067 IN VOID *FileBuffer,
1068 IN UINTN FileSize
1069 )
1070
1071 {
1072 EFI_STATUS Status;
1073 UINT16 Magic;
1074 EFI_IMAGE_DOS_HEADER *DosHdr;
1075 EFI_STATUS VerifyStatus;
1076 UINT8 *SetupMode;
1077 EFI_SIGNATURE_LIST *SignatureList;
1078 UINTN SignatureListSize;
1079 EFI_SIGNATURE_DATA *Signature;
1080 EFI_IMAGE_EXECUTION_ACTION Action;
1081 WIN_CERTIFICATE *WinCertificate;
1082 UINT32 Policy;
1083
1084 if (File == NULL) {
1085 return EFI_INVALID_PARAMETER;
1086 }
1087
1088 SignatureList = NULL;
1089 SignatureListSize = 0;
1090 WinCertificate = NULL;
1091 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
1092 Status = EFI_ACCESS_DENIED;
1093 //
1094 // Check the image type and get policy setting.
1095 //
1096 switch (GetImageType (File)) {
1097
1098 case IMAGE_FROM_FV:
1099 Policy = ALWAYS_EXECUTE;
1100 break;
1101
1102 case IMAGE_FROM_OPTION_ROM:
1103 Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);
1104 break;
1105
1106 case IMAGE_FROM_REMOVABLE_MEDIA:
1107 Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);
1108 break;
1109
1110 case IMAGE_FROM_FIXED_MEDIA:
1111 Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);
1112 break;
1113
1114 default:
1115 Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
1116 break;
1117 }
1118 //
1119 // If policy is always/never execute, return directly.
1120 //
1121 if (Policy == ALWAYS_EXECUTE) {
1122 return EFI_SUCCESS;
1123 } else if (Policy == NEVER_EXECUTE) {
1124 return EFI_ACCESS_DENIED;
1125 }
1126 SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);
1127
1128 //
1129 // SetupMode doesn't exist means no AuthVar driver is dispatched,
1130 // skip verification.
1131 //
1132 if (SetupMode == NULL) {
1133 return EFI_SUCCESS;
1134 }
1135
1136 //
1137 // If platform is in SETUP MODE, skip verification.
1138 //
1139 if (*SetupMode == SETUP_MODE) {
1140 FreePool (SetupMode);
1141 return EFI_SUCCESS;
1142 }
1143 //
1144 // Read the Dos header.
1145 //
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) {
1151 //
1152 // DOS image header is present,
1153 // so read the PE header after the DOS image header.
1154 //
1155 mPeCoffHeaderOffset = DosHdr->e_lfanew;
1156 } else {
1157 mPeCoffHeaderOffset = 0;
1158 }
1159 //
1160 // Check PE/COFF image.
1161 //
1162 mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);
1163 if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1164 //
1165 // It is not a valid Pe/Coff file.
1166 //
1167 return EFI_ACCESS_DENIED;
1168 }
1169
1170 Magic = mNtHeader.Pe32->OptionalHeader.Magic;
1171 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1172 //
1173 // Use PE32 offset.
1174 //
1175 mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
1176 } else {
1177 //
1178 // Use PE32+ offset.
1179 //
1180 mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
1181 }
1182
1183 if (mSecDataDir->Size == 0) {
1184 //
1185 // This image is not signed.
1186 //
1187 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
1188 Status = EFI_ACCESS_DENIED;
1189 goto Done;
1190 }
1191 //
1192 // Verify signature of executables.
1193 //
1194 WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);
1195
1196 switch (WinCertificate->wCertificateType) {
1197
1198 case WIN_CERT_TYPE_EFI_GUID:
1199 //
1200 // Verify UEFI GUID type.
1201 //
1202 if (!HashPeImage (HASHALG_SHA256)) {
1203 goto Done;
1204 }
1205
1206 VerifyStatus = VerifyCertUefiGuid ();
1207 break;
1208
1209 case WIN_CERT_TYPE_PKCS_SIGNED_DATA:
1210 //
1211 // Verify Pkcs signed data type.
1212 //
1213 Status = HashPeImageByType();
1214 if (EFI_ERROR(Status)) {
1215 goto Done;
1216 }
1217
1218 VerifyStatus = VerifyCertPkcsSignedData ();
1219
1220 //
1221 // For image verification against enrolled certificate(root or intermediate),
1222 // no need to check image's hash in the allowed database.
1223 //
1224 if (!EFI_ERROR (VerifyStatus)) {
1225 return EFI_SUCCESS;
1226 }
1227
1228 default:
1229 return EFI_ACCESS_DENIED;
1230 }
1231 //
1232 // Get image hash value as executable's signature.
1233 //
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);
1243 //
1244 // Signature database check after verification.
1245 //
1246 if (EFI_ERROR (VerifyStatus)) {
1247 //
1248 // Verification failure.
1249 //
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)) {
1253 //
1254 // Executable signature verification passes, but is found in forbidden signature database.
1255 //
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)) {
1259 //
1260 // Executable signature is found in authorized signature database.
1261 //
1262 Status = EFI_SUCCESS;
1263 } else {
1264 //
1265 // Executable signature verification passes, but cannot be found in authorized signature database.
1266 // Get platform policy to determine the action.
1267 //
1268 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED;
1269 Status = ImageAuthorization (Policy);
1270 }
1271
1272 Done:
1273 if (Status != EFI_SUCCESS) {
1274 //
1275 // Policy decides to defer or reject the image; add its information in image executable information table.
1276 //
1277 AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);
1278 }
1279
1280 if (SignatureList != NULL) {
1281 FreePool (SignatureList);
1282 }
1283
1284 FreePool (SetupMode);
1285
1286 return Status;
1287 }
1288
1289 /**
1290 When VariableWriteArchProtocol install, create "SecureBoot" variable.
1291
1292 @param[in] Event Event whose notification function is being invoked.
1293 @param[in] Context Pointer to the notification function's context.
1294
1295 **/
1296 VOID
1297 EFIAPI
1298 VariableWriteCallBack (
1299 IN EFI_EVENT Event,
1300 IN VOID *Context
1301 )
1302 {
1303 UINT8 SecureBootMode;
1304 UINT8 *SecureBootModePtr;
1305 EFI_STATUS Status;
1306 VOID *ProtocolPointer;
1307
1308 Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, &ProtocolPointer);
1309 if (EFI_ERROR (Status)) {
1310 return;
1311 }
1312
1313 //
1314 // Check whether "SecureBoot" variable exists.
1315 // If this library is built-in, it means firmware has capability to perform
1316 // driver signing verification.
1317 //
1318 SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME);
1319 if (SecureBootModePtr == NULL) {
1320 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
1321 //
1322 // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable.
1323 //
1324 gRT->SetVariable (
1325 EFI_SECURE_BOOT_MODE_NAME,
1326 &gEfiGlobalVariableGuid,
1327 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1328 sizeof (UINT8),
1329 &SecureBootMode
1330 );
1331 } else {
1332 FreePool (SecureBootModePtr);
1333 }
1334 }
1335
1336 /**
1337 Register security measurement handler.
1338
1339 @param ImageHandle ImageHandle of the loaded driver.
1340 @param SystemTable Pointer to the EFI System Table.
1341
1342 @retval EFI_SUCCESS The handlers were registered successfully.
1343 **/
1344 EFI_STATUS
1345 EFIAPI
1346 DxeImageVerificationLibConstructor (
1347 IN EFI_HANDLE ImageHandle,
1348 IN EFI_SYSTEM_TABLE *SystemTable
1349 )
1350 {
1351 VOID *Registration;
1352
1353 //
1354 // Register callback function upon VariableWriteArchProtocol.
1355 //
1356 EfiCreateProtocolNotifyEvent (
1357 &gEfiVariableWriteArchProtocolGuid,
1358 TPL_CALLBACK,
1359 VariableWriteCallBack,
1360 NULL,
1361 &Registration
1362 );
1363
1364 return RegisterSecurityHandler (
1365 DxeImageVerificationHandler,
1366 EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
1367 );
1368 }