]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
66d96a9396b9137cd4a7bb3367c82affc9f59389
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
1 /** @file
2 Implement image verification services for secure boot service
3
4 Caution: This file requires additional review when modified.
5 This library will have external input - PE/COFF image.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8
9 DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content
10 read is within the image buffer.
11
12 DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept
13 untrusted PE/COFF image and validate its data structure within this image buffer before use.
14
15 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
16 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
17 This program and the accompanying materials
18 are licensed and made available under the terms and conditions of the BSD License
19 which accompanies this distribution. The full text of the license may be found at
20 http://opensource.org/licenses/bsd-license.php
21
22 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
23 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24
25 **/
26
27 #include "DxeImageVerificationLib.h"
28
29 //
30 // Caution: This is used by a function which may receive untrusted input.
31 // These global variables hold PE/COFF image data, and they should be validated before use.
32 //
33 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;
34 UINT32 mPeCoffHeaderOffset;
35 EFI_GUID mCertType;
36
37 //
38 // Information on current PE/COFF image
39 //
40 UINTN mImageSize;
41 UINT8 *mImageBase = NULL;
42 UINT8 mImageDigest[MAX_DIGEST_SIZE];
43 UINTN mImageDigestSize;
44
45 //
46 // Notify string for authorization UI.
47 //
48 CHAR16 mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"Image verification pass but not found in authorized database!";
49 CHAR16 mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"Launch this image anyway? (Yes/Defer/No)";
50 //
51 // Public Exponent of RSA Key.
52 //
53 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
54
55
56 //
57 // OID ASN.1 Value for Hash Algorithms
58 //
59 UINT8 mHashOidValue[] = {
60 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1
61 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224
62 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256
63 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384
64 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512
65 };
66
67 HASH_TABLE mHash[] = {
68 { L"SHA1", 20, &mHashOidValue[0], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },
69 { L"SHA224", 28, &mHashOidValue[5], 9, NULL, NULL, NULL, NULL },
70 { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},
71 { L"SHA384", 48, &mHashOidValue[23], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},
72 { L"SHA512", 64, &mHashOidValue[32], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}
73 };
74
75 EFI_STRING mHashTypeStr;
76
77 /**
78 SecureBoot Hook for processing image verification.
79
80 @param[in] VariableName Name of Variable to be found.
81 @param[in] VendorGuid Variable vendor GUID.
82 @param[in] DataSize Size of Data found. If size is less than the
83 data, this value contains the required size.
84 @param[in] Data Data pointer.
85
86 **/
87 VOID
88 EFIAPI
89 SecureBootHook (
90 IN CHAR16 *VariableName,
91 IN EFI_GUID *VendorGuid,
92 IN UINTN DataSize,
93 IN VOID *Data
94 );
95
96 /**
97 Reads contents of a PE/COFF image in memory buffer.
98
99 Caution: This function may receive untrusted input.
100 PE/COFF image is external input, so this function will make sure the PE/COFF image content
101 read is within the image buffer.
102
103 @param FileHandle Pointer to the file handle to read the PE/COFF image.
104 @param FileOffset Offset into the PE/COFF image to begin the read operation.
105 @param ReadSize On input, the size in bytes of the requested read operation.
106 On output, the number of bytes actually read.
107 @param Buffer Output buffer that contains the data read from the PE/COFF image.
108
109 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
110 **/
111 EFI_STATUS
112 EFIAPI
113 DxeImageVerificationLibImageRead (
114 IN VOID *FileHandle,
115 IN UINTN FileOffset,
116 IN OUT UINTN *ReadSize,
117 OUT VOID *Buffer
118 )
119 {
120 UINTN EndPosition;
121
122 if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
123 return EFI_INVALID_PARAMETER;
124 }
125
126 if (MAX_ADDRESS - FileOffset < *ReadSize) {
127 return EFI_INVALID_PARAMETER;
128 }
129
130 EndPosition = FileOffset + *ReadSize;
131 if (EndPosition > mImageSize) {
132 *ReadSize = (UINT32)(mImageSize - FileOffset);
133 }
134
135 if (FileOffset >= mImageSize) {
136 *ReadSize = 0;
137 }
138
139 CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
140
141 return EFI_SUCCESS;
142 }
143
144
145 /**
146 Get the image type.
147
148 @param[in] File This is a pointer to the device path of the file that is
149 being dispatched.
150
151 @return UINT32 Image Type
152
153 **/
154 UINT32
155 GetImageType (
156 IN CONST EFI_DEVICE_PATH_PROTOCOL *File
157 )
158 {
159 EFI_STATUS Status;
160 EFI_HANDLE DeviceHandle;
161 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
162 EFI_BLOCK_IO_PROTOCOL *BlockIo;
163
164 if (File == NULL) {
165 return IMAGE_UNKNOWN;
166 }
167
168 //
169 // First check to see if File is from a Firmware Volume
170 //
171 DeviceHandle = NULL;
172 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
173 Status = gBS->LocateDevicePath (
174 &gEfiFirmwareVolume2ProtocolGuid,
175 &TempDevicePath,
176 &DeviceHandle
177 );
178 if (!EFI_ERROR (Status)) {
179 Status = gBS->OpenProtocol (
180 DeviceHandle,
181 &gEfiFirmwareVolume2ProtocolGuid,
182 NULL,
183 NULL,
184 NULL,
185 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
186 );
187 if (!EFI_ERROR (Status)) {
188 return IMAGE_FROM_FV;
189 }
190 }
191
192 //
193 // Next check to see if File is from a Block I/O device
194 //
195 DeviceHandle = NULL;
196 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
197 Status = gBS->LocateDevicePath (
198 &gEfiBlockIoProtocolGuid,
199 &TempDevicePath,
200 &DeviceHandle
201 );
202 if (!EFI_ERROR (Status)) {
203 BlockIo = NULL;
204 Status = gBS->OpenProtocol (
205 DeviceHandle,
206 &gEfiBlockIoProtocolGuid,
207 (VOID **) &BlockIo,
208 NULL,
209 NULL,
210 EFI_OPEN_PROTOCOL_GET_PROTOCOL
211 );
212 if (!EFI_ERROR (Status) && BlockIo != NULL) {
213 if (BlockIo->Media != NULL) {
214 if (BlockIo->Media->RemovableMedia) {
215 //
216 // Block I/O is present and specifies the media is removable
217 //
218 return IMAGE_FROM_REMOVABLE_MEDIA;
219 } else {
220 //
221 // Block I/O is present and specifies the media is not removable
222 //
223 return IMAGE_FROM_FIXED_MEDIA;
224 }
225 }
226 }
227 }
228
229 //
230 // File is not in a Firmware Volume or on a Block I/O device, so check to see if
231 // the device path supports the Simple File System Protocol.
232 //
233 DeviceHandle = NULL;
234 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
235 Status = gBS->LocateDevicePath (
236 &gEfiSimpleFileSystemProtocolGuid,
237 &TempDevicePath,
238 &DeviceHandle
239 );
240 if (!EFI_ERROR (Status)) {
241 //
242 // Simple File System is present without Block I/O, so assume media is fixed.
243 //
244 return IMAGE_FROM_FIXED_MEDIA;
245 }
246
247 //
248 // File is not from an FV, Block I/O or Simple File System, so the only options
249 // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.
250 //
251 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;
252 while (!IsDevicePathEndType (TempDevicePath)) {
253 switch (DevicePathType (TempDevicePath)) {
254
255 case MEDIA_DEVICE_PATH:
256 if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {
257 return IMAGE_FROM_OPTION_ROM;
258 }
259 break;
260
261 case MESSAGING_DEVICE_PATH:
262 if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {
263 return IMAGE_FROM_REMOVABLE_MEDIA;
264 }
265 break;
266
267 default:
268 break;
269 }
270 TempDevicePath = NextDevicePathNode (TempDevicePath);
271 }
272 return IMAGE_UNKNOWN;
273 }
274
275 /**
276 Calculate hash of Pe/Coff image based on the authenticode image hashing in
277 PE/COFF Specification 8.0 Appendix A
278
279 Caution: This function may receive untrusted input.
280 PE/COFF image is external input, so this function will validate its data structure
281 within this image buffer before use.
282
283 Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
284 its caller function DxeImageVerificationHandler().
285
286 @param[in] HashAlg Hash algorithm type.
287
288 @retval TRUE Successfully hash image.
289 @retval FALSE Fail in hash image.
290
291 **/
292 BOOLEAN
293 HashPeImage (
294 IN UINT32 HashAlg
295 )
296 {
297 BOOLEAN Status;
298 EFI_IMAGE_SECTION_HEADER *Section;
299 VOID *HashCtx;
300 UINTN CtxSize;
301 UINT8 *HashBase;
302 UINTN HashSize;
303 UINTN SumOfBytesHashed;
304 EFI_IMAGE_SECTION_HEADER *SectionHeader;
305 UINTN Index;
306 UINTN Pos;
307 UINT32 CertSize;
308 UINT32 NumberOfRvaAndSizes;
309
310 HashCtx = NULL;
311 SectionHeader = NULL;
312 Status = FALSE;
313
314 if ((HashAlg >= HASHALG_MAX)) {
315 return FALSE;
316 }
317
318 //
319 // Initialize context of hash.
320 //
321 ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
322
323 switch (HashAlg) {
324 case HASHALG_SHA1:
325 mImageDigestSize = SHA1_DIGEST_SIZE;
326 mCertType = gEfiCertSha1Guid;
327 break;
328
329 case HASHALG_SHA256:
330 mImageDigestSize = SHA256_DIGEST_SIZE;
331 mCertType = gEfiCertSha256Guid;
332 break;
333
334 case HASHALG_SHA384:
335 mImageDigestSize = SHA384_DIGEST_SIZE;
336 mCertType = gEfiCertSha384Guid;
337 break;
338
339 case HASHALG_SHA512:
340 mImageDigestSize = SHA512_DIGEST_SIZE;
341 mCertType = gEfiCertSha512Guid;
342 break;
343
344 default:
345 return FALSE;
346 }
347
348 mHashTypeStr = mHash[HashAlg].Name;
349 CtxSize = mHash[HashAlg].GetContextSize();
350
351 HashCtx = AllocatePool (CtxSize);
352 if (HashCtx == NULL) {
353 return FALSE;
354 }
355
356 // 1. Load the image header into memory.
357
358 // 2. Initialize a SHA hash context.
359 Status = mHash[HashAlg].HashInit(HashCtx);
360
361 if (!Status) {
362 goto Done;
363 }
364
365 //
366 // Measuring PE/COFF Image Header;
367 // But CheckSum field and SECURITY data directory (certificate) are excluded
368 //
369
370 //
371 // 3. Calculate the distance from the base of the image header to the image checksum address.
372 // 4. Hash the image header from its base to beginning of the image checksum.
373 //
374 HashBase = mImageBase;
375 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
376 //
377 // Use PE32 offset.
378 //
379 HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
380 NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
381 } else if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
382 //
383 // Use PE32+ offset.
384 //
385 HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
386 NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
387 } else {
388 //
389 // Invalid header magic number.
390 //
391 Status = FALSE;
392 goto Done;
393 }
394
395 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
396 if (!Status) {
397 goto Done;
398 }
399
400 //
401 // 5. Skip over the image checksum (it occupies a single ULONG).
402 //
403 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
404 //
405 // 6. Since there is no Cert Directory in optional header, hash everything
406 // from the end of the checksum to the end of image header.
407 //
408 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
409 //
410 // Use PE32 offset.
411 //
412 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
413 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);
414 } else {
415 //
416 // Use PE32+ offset.
417 //
418 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
419 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);
420 }
421
422 if (HashSize != 0) {
423 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
424 if (!Status) {
425 goto Done;
426 }
427 }
428 } else {
429 //
430 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
431 //
432 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
433 //
434 // Use PE32 offset.
435 //
436 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
437 HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
438 } else {
439 //
440 // Use PE32+ offset.
441 //
442 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
443 HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
444 }
445
446 if (HashSize != 0) {
447 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
448 if (!Status) {
449 goto Done;
450 }
451 }
452
453 //
454 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
455 // 9. Hash everything from the end of the Cert Directory to the end of image header.
456 //
457 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
458 //
459 // Use PE32 offset
460 //
461 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
462 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);
463 } else {
464 //
465 // Use PE32+ offset.
466 //
467 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
468 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);
469 }
470
471 if (HashSize != 0) {
472 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
473 if (!Status) {
474 goto Done;
475 }
476 }
477 }
478
479 //
480 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
481 //
482 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
483 //
484 // Use PE32 offset.
485 //
486 SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;
487 } else {
488 //
489 // Use PE32+ offset
490 //
491 SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;
492 }
493
494
495 Section = (EFI_IMAGE_SECTION_HEADER *) (
496 mImageBase +
497 mPeCoffHeaderOffset +
498 sizeof (UINT32) +
499 sizeof (EFI_IMAGE_FILE_HEADER) +
500 mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
501 );
502
503 //
504 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
505 // structures in the image. The 'NumberOfSections' field of the image
506 // header indicates how big the table should be. Do not include any
507 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
508 //
509 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);
510 if (SectionHeader == NULL) {
511 Status = FALSE;
512 goto Done;
513 }
514 //
515 // 12. Using the 'PointerToRawData' in the referenced section headers as
516 // a key, arrange the elements in the table in ascending order. In other
517 // words, sort the section headers according to the disk-file offset of
518 // the section.
519 //
520 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
521 Pos = Index;
522 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
523 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
524 Pos--;
525 }
526 CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
527 Section += 1;
528 }
529
530 //
531 // 13. Walk through the sorted table, bring the corresponding section
532 // into memory, and hash the entire section (using the 'SizeOfRawData'
533 // field in the section header to determine the amount of data to hash).
534 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
535 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
536 //
537 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
538 Section = &SectionHeader[Index];
539 if (Section->SizeOfRawData == 0) {
540 continue;
541 }
542 HashBase = mImageBase + Section->PointerToRawData;
543 HashSize = (UINTN) Section->SizeOfRawData;
544
545 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
546 if (!Status) {
547 goto Done;
548 }
549
550 SumOfBytesHashed += HashSize;
551 }
552
553 //
554 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
555 // data in the file that needs to be added to the hash. This data begins
556 // at file offset SUM_OF_BYTES_HASHED and its length is:
557 // FileSize - (CertDirectory->Size)
558 //
559 if (mImageSize > SumOfBytesHashed) {
560 HashBase = mImageBase + SumOfBytesHashed;
561
562 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
563 CertSize = 0;
564 } else {
565 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
566 //
567 // Use PE32 offset.
568 //
569 CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
570 } else {
571 //
572 // Use PE32+ offset.
573 //
574 CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
575 }
576 }
577
578 if (mImageSize > CertSize + SumOfBytesHashed) {
579 HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed);
580
581 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
582 if (!Status) {
583 goto Done;
584 }
585 } else if (mImageSize < CertSize + SumOfBytesHashed) {
586 Status = FALSE;
587 goto Done;
588 }
589 }
590
591 Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);
592
593 Done:
594 if (HashCtx != NULL) {
595 FreePool (HashCtx);
596 }
597 if (SectionHeader != NULL) {
598 FreePool (SectionHeader);
599 }
600 return Status;
601 }
602
603 /**
604 Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of
605 Pe/Coff image based on the authenticode image hashing in PE/COFF Specification
606 8.0 Appendix A
607
608 Caution: This function may receive untrusted input.
609 PE/COFF image is external input, so this function will validate its data structure
610 within this image buffer before use.
611
612 @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.
613 @param[in] AuthDataSize Size of the Authenticode Signature in bytes.
614
615 @retval EFI_UNSUPPORTED Hash algorithm is not supported.
616 @retval EFI_SUCCESS Hash successfully.
617
618 **/
619 EFI_STATUS
620 HashPeImageByType (
621 IN UINT8 *AuthData,
622 IN UINTN AuthDataSize
623 )
624 {
625 UINT8 Index;
626
627 for (Index = 0; Index < HASHALG_MAX; Index++) {
628 //
629 // Check the Hash algorithm in PE/COFF Authenticode.
630 // According to PKCS#7 Definition:
631 // SignedData ::= SEQUENCE {
632 // version Version,
633 // digestAlgorithms DigestAlgorithmIdentifiers,
634 // contentInfo ContentInfo,
635 // .... }
636 // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
637 // This field has the fixed offset (+32) in final Authenticode ASN.1 data.
638 // Fixed offset (+32) is calculated based on two bytes of length encoding.
639 //
640 if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
641 //
642 // Only support two bytes of Long Form of Length Encoding.
643 //
644 continue;
645 }
646
647 if (AuthDataSize < 32 + mHash[Index].OidLength) {
648 return EFI_UNSUPPORTED;
649 }
650
651 if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
652 break;
653 }
654 }
655
656 if (Index == HASHALG_MAX) {
657 return EFI_UNSUPPORTED;
658 }
659
660 //
661 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
662 //
663 if (!HashPeImage(Index)) {
664 return EFI_UNSUPPORTED;
665 }
666
667 return EFI_SUCCESS;
668 }
669
670
671 /**
672 Returns the size of a given image execution info table in bytes.
673
674 This function returns the size, in bytes, of the image execution info table specified by
675 ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.
676
677 @param ImageExeInfoTable A pointer to a image execution info table structure.
678
679 @retval 0 If ImageExeInfoTable is NULL.
680 @retval Others The size of a image execution info table in bytes.
681
682 **/
683 UINTN
684 GetImageExeInfoTableSize (
685 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable
686 )
687 {
688 UINTN Index;
689 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem;
690 UINTN TotalSize;
691
692 if (ImageExeInfoTable == NULL) {
693 return 0;
694 }
695
696 ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE));
697 TotalSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
698 for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) {
699 TotalSize += ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize);
700 ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoItem + ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize));
701 }
702
703 return TotalSize;
704 }
705
706 /**
707 Create an Image Execution Information Table entry and add it to system configuration table.
708
709 @param[in] Action Describes the action taken by the firmware regarding this image.
710 @param[in] Name Input a null-terminated, user-friendly name.
711 @param[in] DevicePath Input device path pointer.
712 @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.
713 @param[in] SignatureSize Size of signature.
714
715 **/
716 VOID
717 AddImageExeInfo (
718 IN EFI_IMAGE_EXECUTION_ACTION Action,
719 IN CHAR16 *Name OPTIONAL,
720 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
721 IN EFI_SIGNATURE_LIST *Signature OPTIONAL,
722 IN UINTN SignatureSize
723 )
724 {
725 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;
726 EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable;
727 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry;
728 UINTN ImageExeInfoTableSize;
729 UINTN NewImageExeInfoEntrySize;
730 UINTN NameStringLen;
731 UINTN DevicePathSize;
732 CHAR16 *NameStr;
733
734 ImageExeInfoTable = NULL;
735 NewImageExeInfoTable = NULL;
736 ImageExeInfoEntry = NULL;
737 NameStringLen = 0;
738 NameStr = NULL;
739
740 if (DevicePath == NULL) {
741 return ;
742 }
743
744 if (Name != NULL) {
745 NameStringLen = StrSize (Name);
746 } else {
747 NameStringLen = sizeof (CHAR16);
748 }
749
750 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);
751 if (ImageExeInfoTable != NULL) {
752 //
753 // The table has been found!
754 // We must enlarge the table to accomodate the new exe info entry.
755 //
756 ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);
757 } else {
758 //
759 // Not Found!
760 // We should create a new table to append to the configuration table.
761 //
762 ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
763 }
764
765 DevicePathSize = GetDevicePathSize (DevicePath);
766
767 //
768 // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align
769 //
770 NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
771
772 NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);
773 if (NewImageExeInfoTable == NULL) {
774 return ;
775 }
776
777 if (ImageExeInfoTable != NULL) {
778 CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);
779 } else {
780 NewImageExeInfoTable->NumberOfImages = 0;
781 }
782 NewImageExeInfoTable->NumberOfImages++;
783 ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);
784 //
785 // Update new item's information.
786 //
787 WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);
788 WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);
789
790 NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);
791 if (Name != NULL) {
792 CopyMem ((UINT8 *) NameStr, Name, NameStringLen);
793 } else {
794 ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16));
795 }
796
797 CopyMem (
798 (UINT8 *) NameStr + NameStringLen,
799 DevicePath,
800 DevicePathSize
801 );
802 if (Signature != NULL) {
803 CopyMem (
804 (UINT8 *) NameStr + NameStringLen + DevicePathSize,
805 Signature,
806 SignatureSize
807 );
808 }
809 //
810 // Update/replace the image execution table.
811 //
812 gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);
813
814 //
815 // Free Old table data!
816 //
817 if (ImageExeInfoTable != NULL) {
818 FreePool (ImageExeInfoTable);
819 }
820 }
821
822 /**
823 Check whether the hash of an given X.509 certificate is in forbidden database (DBX).
824
825 @param[in] Certificate Pointer to X.509 Certificate that is searched for.
826 @param[in] CertSize Size of X.509 Certificate.
827 @param[in] SignatureList Pointer to the Signature List in forbidden database.
828 @param[in] SignatureListSize Size of Signature List.
829 @param[out] RevocationTime Return the time that the certificate was revoked.
830
831 @return TRUE The certificate hash is found in the forbidden database.
832 @return FALSE The certificate hash is not found in the forbidden database.
833
834 **/
835 BOOLEAN
836 IsCertHashFoundInDatabase (
837 IN UINT8 *Certificate,
838 IN UINTN CertSize,
839 IN EFI_SIGNATURE_LIST *SignatureList,
840 IN UINTN SignatureListSize,
841 OUT EFI_TIME *RevocationTime
842 )
843 {
844 BOOLEAN IsFound;
845 BOOLEAN Status;
846 EFI_SIGNATURE_LIST *DbxList;
847 UINTN DbxSize;
848 EFI_SIGNATURE_DATA *CertHash;
849 UINTN CertHashCount;
850 UINTN Index;
851 UINT32 HashAlg;
852 VOID *HashCtx;
853 UINT8 CertDigest[MAX_DIGEST_SIZE];
854 UINT8 *DbxCertHash;
855 UINTN SiglistHeaderSize;
856 UINT8 *TBSCert;
857 UINTN TBSCertSize;
858
859 IsFound = FALSE;
860 DbxList = SignatureList;
861 DbxSize = SignatureListSize;
862 HashCtx = NULL;
863 HashAlg = HASHALG_MAX;
864
865 if ((RevocationTime == NULL) || (DbxList == NULL)) {
866 return FALSE;
867 }
868
869 //
870 // Retrieve the TBSCertificate from the X.509 Certificate.
871 //
872 if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {
873 return FALSE;
874 }
875
876 while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) {
877 //
878 // Determine Hash Algorithm of Certificate in the forbidden database.
879 //
880 if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {
881 HashAlg = HASHALG_SHA256;
882 } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {
883 HashAlg = HASHALG_SHA384;
884 } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {
885 HashAlg = HASHALG_SHA512;
886 } else {
887 DbxSize -= DbxList->SignatureListSize;
888 DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
889 continue;
890 }
891
892 //
893 // Calculate the hash value of current TBSCertificate for comparision.
894 //
895 if (mHash[HashAlg].GetContextSize == NULL) {
896 goto Done;
897 }
898 ZeroMem (CertDigest, MAX_DIGEST_SIZE);
899 HashCtx = AllocatePool (mHash[HashAlg].GetContextSize ());
900 if (HashCtx == NULL) {
901 goto Done;
902 }
903 Status = mHash[HashAlg].HashInit (HashCtx);
904 if (!Status) {
905 goto Done;
906 }
907 Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);
908 if (!Status) {
909 goto Done;
910 }
911 Status = mHash[HashAlg].HashFinal (HashCtx, CertDigest);
912 if (!Status) {
913 goto Done;
914 }
915
916 SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;
917 CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);
918 CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;
919 for (Index = 0; Index < CertHashCount; Index++) {
920 //
921 // Iterate each Signature Data Node within this CertList for verify.
922 //
923 DbxCertHash = CertHash->SignatureData;
924 if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {
925 //
926 // Hash of Certificate is found in forbidden database.
927 //
928 IsFound = TRUE;
929
930 //
931 // Return the revocation time.
932 //
933 CopyMem (RevocationTime, (EFI_TIME *)(DbxCertHash + mHash[HashAlg].DigestLength), sizeof (EFI_TIME));
934 goto Done;
935 }
936 CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);
937 }
938
939 DbxSize -= DbxList->SignatureListSize;
940 DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
941 }
942
943 Done:
944 if (HashCtx != NULL) {
945 FreePool (HashCtx);
946 }
947
948 return IsFound;
949 }
950
951 /**
952 Check whether signature is in specified database.
953
954 @param[in] VariableName Name of database variable that is searched in.
955 @param[in] Signature Pointer to signature that is searched for.
956 @param[in] CertType Pointer to hash algrithom.
957 @param[in] SignatureSize Size of Signature.
958
959 @return TRUE Found the signature in the variable database.
960 @return FALSE Not found the signature in the variable database.
961
962 **/
963 BOOLEAN
964 IsSignatureFoundInDatabase (
965 IN CHAR16 *VariableName,
966 IN UINT8 *Signature,
967 IN EFI_GUID *CertType,
968 IN UINTN SignatureSize
969 )
970 {
971 EFI_STATUS Status;
972 EFI_SIGNATURE_LIST *CertList;
973 EFI_SIGNATURE_DATA *Cert;
974 UINTN DataSize;
975 UINT8 *Data;
976 UINTN Index;
977 UINTN CertCount;
978 BOOLEAN IsFound;
979
980 //
981 // Read signature database variable.
982 //
983 IsFound = FALSE;
984 Data = NULL;
985 DataSize = 0;
986 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
987 if (Status != EFI_BUFFER_TOO_SMALL) {
988 return FALSE;
989 }
990
991 Data = (UINT8 *) AllocateZeroPool (DataSize);
992 if (Data == NULL) {
993 return FALSE;
994 }
995
996 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
997 if (EFI_ERROR (Status)) {
998 goto Done;
999 }
1000 //
1001 // Enumerate all signature data in SigDB to check if executable's signature exists.
1002 //
1003 CertList = (EFI_SIGNATURE_LIST *) Data;
1004 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
1005 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1006 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1007 if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {
1008 for (Index = 0; Index < CertCount; Index++) {
1009 if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {
1010 //
1011 // Find the signature in database.
1012 //
1013 IsFound = TRUE;
1014 //
1015 // Entries in UEFI_IMAGE_SECURITY_DATABASE that are used to validate image should be measured
1016 //
1017 if (StrCmp(VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) {
1018 SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);
1019 }
1020 break;
1021 }
1022
1023 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1024 }
1025
1026 if (IsFound) {
1027 break;
1028 }
1029 }
1030
1031 DataSize -= CertList->SignatureListSize;
1032 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1033 }
1034
1035 Done:
1036 if (Data != NULL) {
1037 FreePool (Data);
1038 }
1039
1040 return IsFound;
1041 }
1042
1043 /**
1044 Check whether the timestamp is valid by comparing the signing time and the revocation time.
1045
1046 @param SigningTime A pointer to the signing time.
1047 @param RevocationTime A pointer to the revocation time.
1048
1049 @retval TRUE The SigningTime is not later than the RevocationTime.
1050 @retval FALSE The SigningTime is later than the RevocationTime.
1051
1052 **/
1053 BOOLEAN
1054 IsValidSignatureByTimestamp (
1055 IN EFI_TIME *SigningTime,
1056 IN EFI_TIME *RevocationTime
1057 )
1058 {
1059 if (SigningTime->Year != RevocationTime->Year) {
1060 return (BOOLEAN) (SigningTime->Year < RevocationTime->Year);
1061 } else if (SigningTime->Month != RevocationTime->Month) {
1062 return (BOOLEAN) (SigningTime->Month < RevocationTime->Month);
1063 } else if (SigningTime->Day != RevocationTime->Day) {
1064 return (BOOLEAN) (SigningTime->Day < RevocationTime->Day);
1065 } else if (SigningTime->Hour != RevocationTime->Hour) {
1066 return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour);
1067 } else if (SigningTime->Minute != RevocationTime->Minute) {
1068 return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute);
1069 }
1070
1071 return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second);
1072 }
1073
1074 /**
1075 Check if the given time value is zero.
1076
1077 @param[in] Time Pointer of a time value.
1078
1079 @retval TRUE The Time is Zero.
1080 @retval FALSE The Time is not Zero.
1081
1082 **/
1083 BOOLEAN
1084 IsTimeZero (
1085 IN EFI_TIME *Time
1086 )
1087 {
1088 if ((Time->Year == 0) && (Time->Month == 0) && (Time->Day == 0) &&
1089 (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) {
1090 return TRUE;
1091 }
1092
1093 return FALSE;
1094 }
1095
1096 /**
1097 Check whether the timestamp signature is valid and the signing time is also earlier than
1098 the revocation time.
1099
1100 @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.
1101 @param[in] AuthDataSize Size of the Authenticode signature in bytes.
1102 @param[in] RevocationTime The time that the certificate was revoked.
1103
1104 @retval TRUE Timestamp signature is valid and signing time is no later than the
1105 revocation time.
1106 @retval FALSE Timestamp signature is not valid or the signing time is later than the
1107 revocation time.
1108
1109 **/
1110 BOOLEAN
1111 PassTimestampCheck (
1112 IN UINT8 *AuthData,
1113 IN UINTN AuthDataSize,
1114 IN EFI_TIME *RevocationTime
1115 )
1116 {
1117 EFI_STATUS Status;
1118 BOOLEAN VerifyStatus;
1119 EFI_SIGNATURE_LIST *CertList;
1120 EFI_SIGNATURE_DATA *Cert;
1121 UINT8 *DbtData;
1122 UINTN DbtDataSize;
1123 UINT8 *RootCert;
1124 UINTN RootCertSize;
1125 UINTN Index;
1126 UINTN CertCount;
1127 EFI_TIME SigningTime;
1128
1129 //
1130 // Variable Initialization
1131 //
1132 VerifyStatus = FALSE;
1133 DbtData = NULL;
1134 CertList = NULL;
1135 Cert = NULL;
1136 RootCert = NULL;
1137 RootCertSize = 0;
1138
1139 //
1140 // If RevocationTime is zero, the certificate shall be considered to always be revoked.
1141 //
1142 if (IsTimeZero (RevocationTime)) {
1143 return FALSE;
1144 }
1145
1146 //
1147 // RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards.
1148 // Using the dbt to get the trusted TSA certificates.
1149 //
1150 DbtDataSize = 0;
1151 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, NULL);
1152 if (Status != EFI_BUFFER_TOO_SMALL) {
1153 goto Done;
1154 }
1155 DbtData = (UINT8 *) AllocateZeroPool (DbtDataSize);
1156 if (DbtData == NULL) {
1157 goto Done;
1158 }
1159 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, (VOID *) DbtData);
1160 if (EFI_ERROR (Status)) {
1161 goto Done;
1162 }
1163
1164 CertList = (EFI_SIGNATURE_LIST *) DbtData;
1165 while ((DbtDataSize > 0) && (DbtDataSize >= CertList->SignatureListSize)) {
1166 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
1167 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1168 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1169 for (Index = 0; Index < CertCount; Index++) {
1170 //
1171 // Iterate each Signature Data Node within this CertList for verify.
1172 //
1173 RootCert = Cert->SignatureData;
1174 RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
1175 //
1176 // Get the signing time if the timestamp signature is valid.
1177 //
1178 if (ImageTimestampVerify (AuthData, AuthDataSize, RootCert, RootCertSize, &SigningTime)) {
1179 //
1180 // The signer signature is valid only when the signing time is earlier than revocation time.
1181 //
1182 if (IsValidSignatureByTimestamp (&SigningTime, RevocationTime)) {
1183 VerifyStatus = TRUE;
1184 goto Done;
1185 }
1186 }
1187 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1188 }
1189 }
1190 DbtDataSize -= CertList->SignatureListSize;
1191 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1192 }
1193
1194 Done:
1195 if (DbtData != NULL) {
1196 FreePool (DbtData);
1197 }
1198
1199 return VerifyStatus;
1200 }
1201
1202 /**
1203 Check whether the image signature is forbidden by the forbidden database (dbx).
1204 The image is forbidden to load if any certificates for signing are revoked before signing time.
1205
1206 @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image.
1207 @param[in] AuthDataSize Size of the Authenticode signature in bytes.
1208
1209 @retval TRUE Image is forbidden by dbx.
1210 @retval FALSE Image is not forbidden by dbx.
1211
1212 **/
1213 BOOLEAN
1214 IsForbiddenByDbx (
1215 IN UINT8 *AuthData,
1216 IN UINTN AuthDataSize
1217 )
1218 {
1219 EFI_STATUS Status;
1220 BOOLEAN IsForbidden;
1221 UINT8 *Data;
1222 UINTN DataSize;
1223 EFI_SIGNATURE_LIST *CertList;
1224 UINTN CertListSize;
1225 EFI_SIGNATURE_DATA *CertData;
1226 UINT8 *RootCert;
1227 UINTN RootCertSize;
1228 UINTN CertCount;
1229 UINTN Index;
1230 UINT8 *CertBuffer;
1231 UINTN BufferLength;
1232 UINT8 *TrustedCert;
1233 UINTN TrustedCertLength;
1234 UINT8 CertNumber;
1235 UINT8 *CertPtr;
1236 UINT8 *Cert;
1237 UINTN CertSize;
1238 EFI_TIME RevocationTime;
1239 //
1240 // Variable Initialization
1241 //
1242 IsForbidden = FALSE;
1243 Data = NULL;
1244 CertList = NULL;
1245 CertData = NULL;
1246 RootCert = NULL;
1247 RootCertSize = 0;
1248 Cert = NULL;
1249 CertBuffer = NULL;
1250 BufferLength = 0;
1251 TrustedCert = NULL;
1252 TrustedCertLength = 0;
1253
1254 //
1255 // The image will not be forbidden if dbx can't be got.
1256 //
1257 DataSize = 0;
1258 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1259 if (Status != EFI_BUFFER_TOO_SMALL) {
1260 return IsForbidden;
1261 }
1262 Data = (UINT8 *) AllocateZeroPool (DataSize);
1263 if (Data == NULL) {
1264 return IsForbidden;
1265 }
1266
1267 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);
1268 if (EFI_ERROR (Status)) {
1269 return IsForbidden;
1270 }
1271
1272 //
1273 // Verify image signature with RAW X509 certificates in DBX database.
1274 // If passed, the image will be forbidden.
1275 //
1276 CertList = (EFI_SIGNATURE_LIST *) Data;
1277 CertListSize = DataSize;
1278 while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) {
1279 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
1280 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1281 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1282
1283 for (Index = 0; Index < CertCount; Index++) {
1284 //
1285 // Iterate each Signature Data Node within this CertList for verify.
1286 //
1287 RootCert = CertData->SignatureData;
1288 RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
1289
1290 //
1291 // Call AuthenticodeVerify library to Verify Authenticode struct.
1292 //
1293 IsForbidden = AuthenticodeVerify (
1294 AuthData,
1295 AuthDataSize,
1296 RootCert,
1297 RootCertSize,
1298 mImageDigest,
1299 mImageDigestSize
1300 );
1301 if (IsForbidden) {
1302 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is forbidden by DBX.\n"));
1303 goto Done;
1304 }
1305
1306 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);
1307 }
1308 }
1309
1310 CertListSize -= CertList->SignatureListSize;
1311 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1312 }
1313
1314 //
1315 // Check X.509 Certificate Hash & Possible Timestamp.
1316 //
1317
1318 //
1319 // Retrieve the certificate stack from AuthData
1320 // The output CertStack format will be:
1321 // UINT8 CertNumber;
1322 // UINT32 Cert1Length;
1323 // UINT8 Cert1[];
1324 // UINT32 Cert2Length;
1325 // UINT8 Cert2[];
1326 // ...
1327 // UINT32 CertnLength;
1328 // UINT8 Certn[];
1329 //
1330 Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);
1331 if ((BufferLength == 0) || (CertBuffer == NULL)) {
1332 IsForbidden = TRUE;
1333 goto Done;
1334 }
1335
1336 //
1337 // Check if any hash of certificates embedded in AuthData is in the forbidden database.
1338 //
1339 CertNumber = (UINT8) (*CertBuffer);
1340 CertPtr = CertBuffer + 1;
1341 for (Index = 0; Index < CertNumber; Index++) {
1342 CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);
1343 Cert = (UINT8 *)CertPtr + sizeof (UINT32);
1344 //
1345 // Advance CertPtr to the next cert in image signer's cert list
1346 //
1347 CertPtr = CertPtr + sizeof (UINT32) + CertSize;
1348
1349 if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {
1350 //
1351 // Check the timestamp signature and signing time to determine if the image can be trusted.
1352 //
1353 IsForbidden = TRUE;
1354 if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) {
1355 IsForbidden = FALSE;
1356 //
1357 // Pass DBT check. Continue to check other certs in image signer's cert list against DBX, DBT
1358 //
1359 continue;
1360 }
1361 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature failed the timestamp check.\n"));
1362 goto Done;
1363 }
1364
1365 }
1366
1367 Done:
1368 if (Data != NULL) {
1369 FreePool (Data);
1370 }
1371
1372 Pkcs7FreeSigners (CertBuffer);
1373 Pkcs7FreeSigners (TrustedCert);
1374
1375 return IsForbidden;
1376 }
1377
1378
1379 /**
1380 Check whether the image signature can be verified by the trusted certificates in DB database.
1381
1382 @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.
1383 @param[in] AuthDataSize Size of the Authenticode signature in bytes.
1384
1385 @retval TRUE Image passed verification using certificate in db.
1386 @retval FALSE Image didn't pass verification using certificate in db.
1387
1388 **/
1389 BOOLEAN
1390 IsAllowedByDb (
1391 IN UINT8 *AuthData,
1392 IN UINTN AuthDataSize
1393 )
1394 {
1395 EFI_STATUS Status;
1396 BOOLEAN VerifyStatus;
1397 EFI_SIGNATURE_LIST *CertList;
1398 EFI_SIGNATURE_DATA *CertData;
1399 UINTN DataSize;
1400 UINT8 *Data;
1401 UINT8 *RootCert;
1402 UINTN RootCertSize;
1403 UINTN Index;
1404 UINTN CertCount;
1405 UINTN DbxDataSize;
1406 UINT8 *DbxData;
1407 EFI_TIME RevocationTime;
1408
1409 Data = NULL;
1410 CertList = NULL;
1411 CertData = NULL;
1412 RootCert = NULL;
1413 DbxData = NULL;
1414 RootCertSize = 0;
1415 VerifyStatus = FALSE;
1416
1417 DataSize = 0;
1418 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1419 if (Status == EFI_BUFFER_TOO_SMALL) {
1420 Data = (UINT8 *) AllocateZeroPool (DataSize);
1421 if (Data == NULL) {
1422 return VerifyStatus;
1423 }
1424
1425 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);
1426 if (EFI_ERROR (Status)) {
1427 goto Done;
1428 }
1429
1430 //
1431 // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.
1432 //
1433 CertList = (EFI_SIGNATURE_LIST *) Data;
1434 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
1435 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
1436 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1437 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1438
1439 for (Index = 0; Index < CertCount; Index++) {
1440 //
1441 // Iterate each Signature Data Node within this CertList for verify.
1442 //
1443 RootCert = CertData->SignatureData;
1444 RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
1445
1446 //
1447 // Call AuthenticodeVerify library to Verify Authenticode struct.
1448 //
1449 VerifyStatus = AuthenticodeVerify (
1450 AuthData,
1451 AuthDataSize,
1452 RootCert,
1453 RootCertSize,
1454 mImageDigest,
1455 mImageDigestSize
1456 );
1457 if (VerifyStatus) {
1458 //
1459 // Here We still need to check if this RootCert's Hash is revoked
1460 //
1461 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL);
1462 if (Status == EFI_BUFFER_TOO_SMALL) {
1463 goto Done;
1464 }
1465 DbxData = (UINT8 *) AllocateZeroPool (DbxDataSize);
1466 if (DbxData == NULL) {
1467 goto Done;
1468 }
1469
1470 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData);
1471 if (EFI_ERROR (Status)) {
1472 goto Done;
1473 }
1474
1475 if (IsCertHashFoundInDatabase (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime)) {
1476 //
1477 // Check the timestamp signature and signing time to determine if the RootCert can be trusted.
1478 //
1479 VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);
1480 if (!VerifyStatus) {
1481 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed and signature is accepted by DB, but its root cert failed the timestamp check.\n"));
1482 }
1483 }
1484
1485 goto Done;
1486 }
1487
1488 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);
1489 }
1490 }
1491
1492 DataSize -= CertList->SignatureListSize;
1493 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1494 }
1495 }
1496
1497 Done:
1498
1499 if (VerifyStatus) {
1500 SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);
1501 }
1502
1503 if (Data != NULL) {
1504 FreePool (Data);
1505 }
1506 if (DbxData != NULL) {
1507 FreePool (DbxData);
1508 }
1509
1510 return VerifyStatus;
1511 }
1512
1513 /**
1514 Provide verification service for signed images, which include both signature validation
1515 and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
1516 MSFT Authenticode type signatures are supported.
1517
1518 In this implementation, only verify external executables when in USER MODE.
1519 Executables from FV is bypass, so pass in AuthenticationStatus is ignored.
1520
1521 The image verification policy is:
1522 If the image is signed,
1523 At least one valid signature or at least one hash value of the image must match a record
1524 in the security database "db", and no valid signature nor any hash value of the image may
1525 be reflected in the security database "dbx".
1526 Otherwise, the image is not signed,
1527 The SHA256 hash value of the image must match a record in the security database "db", and
1528 not be reflected in the security data base "dbx".
1529
1530 Caution: This function may receive untrusted input.
1531 PE/COFF image is external input, so this function will validate its data structure
1532 within this image buffer before use.
1533
1534 @param[in] AuthenticationStatus
1535 This is the authentication status returned from the security
1536 measurement services for the input file.
1537 @param[in] File This is a pointer to the device path of the file that is
1538 being dispatched. This will optionally be used for logging.
1539 @param[in] FileBuffer File buffer matches the input file device path.
1540 @param[in] FileSize Size of File buffer matches the input file device path.
1541 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
1542
1543 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
1544 FileBuffer did authenticate, and the platform policy dictates
1545 that the DXE Foundation may use the file.
1546 @retval EFI_SUCCESS The device path specified by NULL device path DevicePath
1547 and non-NULL FileBuffer did authenticate, and the platform
1548 policy dictates that the DXE Foundation may execute the image in
1549 FileBuffer.
1550 @retval EFI_OUT_RESOURCE Fail to allocate memory.
1551 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
1552 the platform policy dictates that File should be placed
1553 in the untrusted state. The image has been added to the file
1554 execution table.
1555 @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
1556 authenticate, and the platform policy dictates that the DXE
1557 Foundation many not use File.
1558
1559 **/
1560 EFI_STATUS
1561 EFIAPI
1562 DxeImageVerificationHandler (
1563 IN UINT32 AuthenticationStatus,
1564 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
1565 IN VOID *FileBuffer,
1566 IN UINTN FileSize,
1567 IN BOOLEAN BootPolicy
1568 )
1569 {
1570 EFI_STATUS Status;
1571 EFI_IMAGE_DOS_HEADER *DosHdr;
1572 EFI_STATUS VerifyStatus;
1573 EFI_SIGNATURE_LIST *SignatureList;
1574 UINTN SignatureListSize;
1575 EFI_SIGNATURE_DATA *Signature;
1576 EFI_IMAGE_EXECUTION_ACTION Action;
1577 WIN_CERTIFICATE *WinCertificate;
1578 UINT32 Policy;
1579 UINT8 *SecureBoot;
1580 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
1581 UINT32 NumberOfRvaAndSizes;
1582 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
1583 WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;
1584 UINT8 *AuthData;
1585 UINTN AuthDataSize;
1586 EFI_IMAGE_DATA_DIRECTORY *SecDataDir;
1587 UINT32 OffSet;
1588 CHAR16 *NameStr;
1589
1590 SignatureList = NULL;
1591 SignatureListSize = 0;
1592 WinCertificate = NULL;
1593 SecDataDir = NULL;
1594 PkcsCertData = NULL;
1595 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
1596 Status = EFI_ACCESS_DENIED;
1597 VerifyStatus = EFI_ACCESS_DENIED;
1598
1599
1600 //
1601 // Check the image type and get policy setting.
1602 //
1603 switch (GetImageType (File)) {
1604
1605 case IMAGE_FROM_FV:
1606 Policy = ALWAYS_EXECUTE;
1607 break;
1608
1609 case IMAGE_FROM_OPTION_ROM:
1610 Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);
1611 break;
1612
1613 case IMAGE_FROM_REMOVABLE_MEDIA:
1614 Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);
1615 break;
1616
1617 case IMAGE_FROM_FIXED_MEDIA:
1618 Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);
1619 break;
1620
1621 default:
1622 Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
1623 break;
1624 }
1625 //
1626 // If policy is always/never execute, return directly.
1627 //
1628 if (Policy == ALWAYS_EXECUTE) {
1629 return EFI_SUCCESS;
1630 } else if (Policy == NEVER_EXECUTE) {
1631 return EFI_ACCESS_DENIED;
1632 }
1633
1634 //
1635 // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION
1636 // violates the UEFI spec and has been removed.
1637 //
1638 ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);
1639 if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {
1640 CpuDeadLoop ();
1641 }
1642
1643 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);
1644 //
1645 // Skip verification if SecureBoot variable doesn't exist.
1646 //
1647 if (SecureBoot == NULL) {
1648 return EFI_SUCCESS;
1649 }
1650
1651 //
1652 // Skip verification if SecureBoot is disabled but not AuditMode
1653 //
1654 if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
1655 FreePool (SecureBoot);
1656 return EFI_SUCCESS;
1657 }
1658 FreePool (SecureBoot);
1659
1660 //
1661 // Read the Dos header.
1662 //
1663 if (FileBuffer == NULL) {
1664 return EFI_INVALID_PARAMETER;
1665 }
1666
1667 mImageBase = (UINT8 *) FileBuffer;
1668 mImageSize = FileSize;
1669
1670 ZeroMem (&ImageContext, sizeof (ImageContext));
1671 ImageContext.Handle = (VOID *) FileBuffer;
1672 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;
1673
1674 //
1675 // Get information about the image being loaded
1676 //
1677 Status = PeCoffLoaderGetImageInfo (&ImageContext);
1678 if (EFI_ERROR (Status)) {
1679 //
1680 // The information can't be got from the invalid PeImage
1681 //
1682 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information.\n"));
1683 goto Done;
1684 }
1685
1686 Status = EFI_ACCESS_DENIED;
1687
1688 DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;
1689 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1690 //
1691 // DOS image header is present,
1692 // so read the PE header after the DOS image header.
1693 //
1694 mPeCoffHeaderOffset = DosHdr->e_lfanew;
1695 } else {
1696 mPeCoffHeaderOffset = 0;
1697 }
1698 //
1699 // Check PE/COFF image.
1700 //
1701 mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);
1702 if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1703 //
1704 // It is not a valid Pe/Coff file.
1705 //
1706 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Not a valid PE/COFF image.\n"));
1707 goto Done;
1708 }
1709
1710 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1711 //
1712 // Use PE32 offset.
1713 //
1714 NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1715 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
1716 SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
1717 }
1718 } else {
1719 //
1720 // Use PE32+ offset.
1721 //
1722 NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1723 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
1724 SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
1725 }
1726 }
1727
1728 //
1729 // Start Image Validation.
1730 //
1731 if (SecDataDir == NULL || SecDataDir->Size == 0) {
1732 //
1733 // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",
1734 // and not be reflected in the security data base "dbx".
1735 //
1736 if (!HashPeImage (HASHALG_SHA256)) {
1737 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", mHashTypeStr));
1738 goto Done;
1739 }
1740
1741 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
1742 //
1743 // Image Hash is in forbidden database (DBX).
1744 //
1745 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX.\n", mHashTypeStr));
1746 goto Done;
1747 }
1748
1749 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
1750 //
1751 // Image Hash is in allowed database (DB).
1752 //
1753 return EFI_SUCCESS;
1754 }
1755
1756 //
1757 // Image Hash is not found in both forbidden and allowed database.
1758 //
1759 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));
1760 goto Done;
1761 }
1762
1763 //
1764 // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7
1765 // "Attribute Certificate Table".
1766 // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.
1767 //
1768 for (OffSet = SecDataDir->VirtualAddress;
1769 OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);
1770 OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) {
1771 WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);
1772 if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||
1773 (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {
1774 break;
1775 }
1776
1777 //
1778 // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.
1779 //
1780 if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
1781 //
1782 // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the
1783 // Authenticode specification.
1784 //
1785 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;
1786 if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {
1787 break;
1788 }
1789 AuthData = PkcsCertData->CertData;
1790 AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);
1791 } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
1792 //
1793 // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.
1794 //
1795 WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;
1796 if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
1797 break;
1798 }
1799 if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {
1800 continue;
1801 }
1802 AuthData = WinCertUefiGuid->CertData;
1803 AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
1804 } else {
1805 if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {
1806 break;
1807 }
1808 continue;
1809 }
1810
1811 Status = HashPeImageByType (AuthData, AuthDataSize);
1812 if (EFI_ERROR (Status)) {
1813 continue;
1814 }
1815
1816 //
1817 // Check the digital signature against the revoked certificate in forbidden database (dbx).
1818 //
1819 if (IsForbiddenByDbx (AuthData, AuthDataSize)) {
1820 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
1821 VerifyStatus = EFI_ACCESS_DENIED;
1822 break;
1823 }
1824
1825 //
1826 // Check the digital signature against the valid certificate in allowed database (db).
1827 //
1828 if (EFI_ERROR (VerifyStatus)) {
1829 if (IsAllowedByDb (AuthData, AuthDataSize)) {
1830 VerifyStatus = EFI_SUCCESS;
1831 }
1832 }
1833
1834 //
1835 // Check the image's hash value.
1836 //
1837 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
1838 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;
1839 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but %s hash of image is found in DBX.\n", mHashTypeStr));
1840 VerifyStatus = EFI_ACCESS_DENIED;
1841 break;
1842 } else if (EFI_ERROR (VerifyStatus)) {
1843 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
1844 VerifyStatus = EFI_SUCCESS;
1845 } else {
1846 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is not allowed by DB and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));
1847 }
1848 }
1849 }
1850
1851 if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {
1852 //
1853 // The Size in Certificate Table or the attribute certicate table is corrupted.
1854 //
1855 VerifyStatus = EFI_ACCESS_DENIED;
1856 }
1857
1858 if (!EFI_ERROR (VerifyStatus)) {
1859 return EFI_SUCCESS;
1860 } else {
1861 Status = EFI_ACCESS_DENIED;
1862 if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {
1863 //
1864 // Get image hash value as executable's signature.
1865 //
1866 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;
1867 SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);
1868 if (SignatureList == NULL) {
1869 Status = EFI_OUT_OF_RESOURCES;
1870 goto Done;
1871 }
1872 SignatureList->SignatureHeaderSize = 0;
1873 SignatureList->SignatureListSize = (UINT32) SignatureListSize;
1874 SignatureList->SignatureSize = (UINT32) (sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize);
1875 CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));
1876 Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));
1877 CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);
1878 }
1879 }
1880
1881 Done:
1882 if (Status != EFI_SUCCESS) {
1883 //
1884 // Policy decides to defer or reject the image; add its information in image executable information table.
1885 //
1886 NameStr = ConvertDevicePathToText (File, FALSE, TRUE);
1887 AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize);
1888 if (NameStr != NULL) {
1889 DEBUG((EFI_D_INFO, "The image doesn't pass verification: %s\n", NameStr));
1890 FreePool(NameStr);
1891 }
1892 Status = EFI_SECURITY_VIOLATION;
1893 }
1894
1895 if (SignatureList != NULL) {
1896 FreePool (SignatureList);
1897 }
1898
1899 return Status;
1900 }
1901
1902 /**
1903 On Ready To Boot Services Event notification handler.
1904
1905 Add the image execution information table if it is not in system configuration table.
1906
1907 @param[in] Event Event whose notification function is being invoked
1908 @param[in] Context Pointer to the notification function's context
1909
1910 **/
1911 VOID
1912 EFIAPI
1913 OnReadyToBoot (
1914 IN EFI_EVENT Event,
1915 IN VOID *Context
1916 )
1917 {
1918 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;
1919 UINTN ImageExeInfoTableSize;
1920
1921 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);
1922 if (ImageExeInfoTable != NULL) {
1923 return;
1924 }
1925
1926 ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
1927 ImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize);
1928 if (ImageExeInfoTable == NULL) {
1929 return ;
1930 }
1931
1932 ImageExeInfoTable->NumberOfImages = 0;
1933 gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) ImageExeInfoTable);
1934
1935 }
1936
1937 /**
1938 Register security measurement handler.
1939
1940 @param ImageHandle ImageHandle of the loaded driver.
1941 @param SystemTable Pointer to the EFI System Table.
1942
1943 @retval EFI_SUCCESS The handlers were registered successfully.
1944 **/
1945 EFI_STATUS
1946 EFIAPI
1947 DxeImageVerificationLibConstructor (
1948 IN EFI_HANDLE ImageHandle,
1949 IN EFI_SYSTEM_TABLE *SystemTable
1950 )
1951 {
1952 EFI_EVENT Event;
1953
1954 //
1955 // Register the event to publish the image execution table.
1956 //
1957 EfiCreateEventReadyToBootEx (
1958 TPL_CALLBACK,
1959 OnReadyToBoot,
1960 NULL,
1961 &Event
1962 );
1963
1964 return RegisterSecurity2Handler (
1965 DxeImageVerificationHandler,
1966 EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
1967 );
1968 }