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