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