• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 - 2015, 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
DxeImageVerificationLibImageRead(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINTN * ReadSize,OUT VOID * Buffer)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
GetImageType(IN CONST EFI_DEVICE_PATH_PROTOCOL * File)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
HashPeImage(IN UINT32 HashAlg)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
HashPeImageByType(IN UINT8 * AuthData,IN UINTN AuthDataSize)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
GetImageExeInfoTableSize(EFI_IMAGE_EXECUTION_INFO_TABLE * ImageExeInfoTable)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 signature list based on input signature data and certificate type GUID. Caller is reposible
716   to free new created SignatureList.
717 
718   @param[in]   SignatureData           Signature data in SignatureList.
719   @param[in]   SignatureDataSize       Signature data size.
720   @param[in]   CertType                Certificate Type.
721   @param[out]  SignatureList           Created SignatureList.
722   @param[out]  SignatureListSize       Created SignatureListSize.
723 
724   @return EFI_OUT_OF_RESOURCES         The operation is failed due to lack of resources.
725   @retval EFI_SUCCESS          Successfully create signature list.
726 
727 **/
728 EFI_STATUS
CreateSignatureList(IN UINT8 * SignatureData,IN UINTN SignatureDataSize,IN EFI_GUID * CertType,OUT EFI_SIGNATURE_LIST ** SignatureList,OUT UINTN * SignatureListSize)729 CreateSignatureList(
730   IN UINT8                *SignatureData,
731   IN UINTN                SignatureDataSize,
732   IN EFI_GUID             *CertType,
733   OUT EFI_SIGNATURE_LIST  **SignatureList,
734   OUT UINTN               *SignatureListSize
735   )
736 {
737   EFI_SIGNATURE_LIST   *SignList;
738   UINTN                SignListSize;
739   EFI_SIGNATURE_DATA   *Signature;
740 
741   SignList       = NULL;
742   *SignatureList = NULL;
743 
744   SignListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + SignatureDataSize;
745   SignList     = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignListSize);
746   if (SignList == NULL) {
747     return EFI_OUT_OF_RESOURCES;
748   }
749 
750   SignList->SignatureHeaderSize = 0;
751   SignList->SignatureListSize   = (UINT32) SignListSize;
752   SignList->SignatureSize       = (UINT32) SignatureDataSize + sizeof (EFI_SIGNATURE_DATA) - 1;
753   CopyMem (&SignList->SignatureType, CertType, sizeof (EFI_GUID));
754 
755   DEBUG((EFI_D_INFO, "SignatureDataSize %x\n", SignatureDataSize));
756   Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignList + sizeof (EFI_SIGNATURE_LIST));
757   CopyMem (Signature->SignatureData, SignatureData, SignatureDataSize);
758 
759   *SignatureList     = SignList;
760   *SignatureListSize = SignListSize;
761 
762   return EFI_SUCCESS;
763 
764 }
765 
766 /**
767   Create an Image Execution Information Table entry and add it to system configuration table.
768 
769   @param[in]  Action          Describes the action taken by the firmware regarding this image.
770   @param[in]  Name            Input a null-terminated, user-friendly name.
771   @param[in]  DevicePath      Input device path pointer.
772   @param[in]  Signature       Input signature info in EFI_SIGNATURE_LIST data structure.
773   @param[in]  SignatureSize   Size of signature.
774 
775 **/
776 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)777 AddImageExeInfo (
778   IN       EFI_IMAGE_EXECUTION_ACTION       Action,
779   IN       CHAR16                           *Name OPTIONAL,
780   IN CONST EFI_DEVICE_PATH_PROTOCOL         *DevicePath,
781   IN       EFI_SIGNATURE_LIST               *Signature OPTIONAL,
782   IN       UINTN                            SignatureSize
783   )
784 {
785   EFI_IMAGE_EXECUTION_INFO_TABLE  *ImageExeInfoTable;
786   EFI_IMAGE_EXECUTION_INFO_TABLE  *NewImageExeInfoTable;
787   EFI_IMAGE_EXECUTION_INFO        *ImageExeInfoEntry;
788   UINTN                           ImageExeInfoTableSize;
789   UINTN                           NewImageExeInfoEntrySize;
790   UINTN                           NameStringLen;
791   UINTN                           DevicePathSize;
792   CHAR16                          *NameStr;
793 
794   ImageExeInfoTable     = NULL;
795   NewImageExeInfoTable  = NULL;
796   ImageExeInfoEntry     = NULL;
797   NameStringLen         = 0;
798   NameStr               = NULL;
799 
800   if (DevicePath == NULL) {
801     return ;
802   }
803 
804   if (Name != NULL) {
805     NameStringLen = StrSize (Name);
806   } else {
807     NameStringLen = sizeof (CHAR16);
808   }
809 
810   EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);
811   if (ImageExeInfoTable != NULL) {
812     //
813     // The table has been found!
814     // We must enlarge the table to accomodate the new exe info entry.
815     //
816     ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);
817   } else {
818     //
819     // Not Found!
820     // We should create a new table to append to the configuration table.
821     //
822     ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
823   }
824 
825   DevicePathSize            = GetDevicePathSize (DevicePath);
826 
827   //
828   // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align
829   //
830   NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
831 
832   NewImageExeInfoTable      = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);
833   if (NewImageExeInfoTable == NULL) {
834     return ;
835   }
836 
837   if (ImageExeInfoTable != NULL) {
838     CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);
839   } else {
840     NewImageExeInfoTable->NumberOfImages = 0;
841   }
842   NewImageExeInfoTable->NumberOfImages++;
843   ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);
844   //
845   // Update new item's information.
846   //
847   WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);
848   WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);
849 
850   NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);
851   if (Name != NULL) {
852     CopyMem ((UINT8 *) NameStr, Name, NameStringLen);
853   } else {
854     ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16));
855   }
856 
857   CopyMem (
858     (UINT8 *) NameStr + NameStringLen,
859     DevicePath,
860     DevicePathSize
861     );
862   if (Signature != NULL) {
863     CopyMem (
864       (UINT8 *) NameStr + NameStringLen + DevicePathSize,
865       Signature,
866       SignatureSize
867       );
868   }
869   //
870   // Update/replace the image execution table.
871   //
872   gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);
873 
874   //
875   // Free Old table data!
876   //
877   if (ImageExeInfoTable != NULL) {
878     FreePool (ImageExeInfoTable);
879   }
880 }
881 
882 /**
883   Check whether the hash of an given X.509 certificate is in forbidden database (DBX).
884 
885   @param[in]  Certificate       Pointer to X.509 Certificate that is searched for.
886   @param[in]  CertSize          Size of X.509 Certificate.
887   @param[in]  SignatureList     Pointer to the Signature List in forbidden database.
888   @param[in]  SignatureListSize Size of Signature List.
889   @param[out] RevocationTime    Return the time that the certificate was revoked.
890 
891   @return TRUE   The certificate hash is found in the forbidden database.
892   @return FALSE  The certificate hash is not found in the forbidden database.
893 
894 **/
895 BOOLEAN
IsCertHashFoundInDatabase(IN UINT8 * Certificate,IN UINTN CertSize,IN EFI_SIGNATURE_LIST * SignatureList,IN UINTN SignatureListSize,OUT EFI_TIME * RevocationTime)896 IsCertHashFoundInDatabase (
897   IN  UINT8               *Certificate,
898   IN  UINTN               CertSize,
899   IN  EFI_SIGNATURE_LIST  *SignatureList,
900   IN  UINTN               SignatureListSize,
901   OUT EFI_TIME            *RevocationTime
902   )
903 {
904   BOOLEAN             IsFound;
905   BOOLEAN             Status;
906   EFI_SIGNATURE_LIST  *DbxList;
907   UINTN               DbxSize;
908   EFI_SIGNATURE_DATA  *CertHash;
909   UINTN               CertHashCount;
910   UINTN               Index;
911   UINT32              HashAlg;
912   VOID                *HashCtx;
913   UINT8               CertDigest[MAX_DIGEST_SIZE];
914   UINT8               *DbxCertHash;
915   UINTN               SiglistHeaderSize;
916   UINT8               *TBSCert;
917   UINTN               TBSCertSize;
918 
919   IsFound  = FALSE;
920   DbxList  = SignatureList;
921   DbxSize  = SignatureListSize;
922   HashCtx  = NULL;
923   HashAlg  = HASHALG_MAX;
924 
925   if ((RevocationTime == NULL) || (DbxList == NULL)) {
926     return FALSE;
927   }
928 
929   //
930   // Retrieve the TBSCertificate from the X.509 Certificate.
931   //
932   if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {
933     return FALSE;
934   }
935 
936   while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) {
937     //
938     // Determine Hash Algorithm of Certificate in the forbidden database.
939     //
940     if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {
941       HashAlg = HASHALG_SHA256;
942     } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {
943       HashAlg = HASHALG_SHA384;
944     } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {
945       HashAlg = HASHALG_SHA512;
946     } else {
947       DbxSize -= DbxList->SignatureListSize;
948       DbxList  = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
949       continue;
950     }
951 
952     //
953     // Calculate the hash value of current TBSCertificate for comparision.
954     //
955     if (mHash[HashAlg].GetContextSize == NULL) {
956       goto Done;
957     }
958     ZeroMem (CertDigest, MAX_DIGEST_SIZE);
959     HashCtx = AllocatePool (mHash[HashAlg].GetContextSize ());
960     if (HashCtx == NULL) {
961       goto Done;
962     }
963     Status = mHash[HashAlg].HashInit (HashCtx);
964     if (!Status) {
965       goto Done;
966     }
967     Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);
968     if (!Status) {
969       goto Done;
970     }
971     Status = mHash[HashAlg].HashFinal (HashCtx, CertDigest);
972     if (!Status) {
973       goto Done;
974     }
975 
976     SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;
977     CertHash          = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);
978     CertHashCount     = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;
979     for (Index = 0; Index < CertHashCount; Index++) {
980       //
981       // Iterate each Signature Data Node within this CertList for verify.
982       //
983       DbxCertHash = CertHash->SignatureData;
984       if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {
985         //
986         // Hash of Certificate is found in forbidden database.
987         //
988         IsFound = TRUE;
989 
990         //
991         // Return the revocation time.
992         //
993         CopyMem (RevocationTime, (EFI_TIME *)(DbxCertHash + mHash[HashAlg].DigestLength), sizeof (EFI_TIME));
994         goto Done;
995       }
996       CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);
997     }
998 
999     DbxSize -= DbxList->SignatureListSize;
1000     DbxList  = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
1001   }
1002 
1003 Done:
1004   if (HashCtx != NULL) {
1005     FreePool (HashCtx);
1006   }
1007 
1008   return IsFound;
1009 }
1010 
1011 /**
1012   Check whether signature is in specified database.
1013 
1014   @param[in]  VariableName        Name of database variable that is searched in.
1015   @param[in]  Signature           Pointer to signature that is searched for.
1016   @param[in]  CertType            Pointer to hash algrithom.
1017   @param[in]  SignatureSize       Size of Signature.
1018 
1019   @return TRUE                    Found the signature in the variable database.
1020   @return FALSE                   Not found the signature in the variable database.
1021 
1022 **/
1023 BOOLEAN
IsSignatureFoundInDatabase(IN CHAR16 * VariableName,IN UINT8 * Signature,IN EFI_GUID * CertType,IN UINTN SignatureSize)1024 IsSignatureFoundInDatabase (
1025   IN CHAR16             *VariableName,
1026   IN UINT8              *Signature,
1027   IN EFI_GUID           *CertType,
1028   IN UINTN              SignatureSize
1029   )
1030 {
1031   EFI_STATUS          Status;
1032   EFI_SIGNATURE_LIST  *CertList;
1033   EFI_SIGNATURE_DATA  *Cert;
1034   UINTN               DataSize;
1035   UINT8               *Data;
1036   UINTN               Index;
1037   UINTN               CertCount;
1038   BOOLEAN             IsFound;
1039 
1040   //
1041   // Read signature database variable.
1042   //
1043   IsFound   = FALSE;
1044   Data      = NULL;
1045   DataSize  = 0;
1046   Status    = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1047   if (Status != EFI_BUFFER_TOO_SMALL) {
1048     return FALSE;
1049   }
1050 
1051   Data = (UINT8 *) AllocateZeroPool (DataSize);
1052   if (Data == NULL) {
1053     return FALSE;
1054   }
1055 
1056   Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1057   if (EFI_ERROR (Status)) {
1058     goto Done;
1059   }
1060   //
1061   // Enumerate all signature data in SigDB to check if executable's signature exists.
1062   //
1063   CertList = (EFI_SIGNATURE_LIST *) Data;
1064   while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
1065     CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1066     Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1067     if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {
1068       for (Index = 0; Index < CertCount; Index++) {
1069         if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {
1070           //
1071           // Find the signature in database.
1072           //
1073           IsFound = TRUE;
1074           SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);
1075           break;
1076         }
1077 
1078         Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1079       }
1080 
1081       if (IsFound) {
1082         break;
1083       }
1084     }
1085 
1086     DataSize -= CertList->SignatureListSize;
1087     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1088   }
1089 
1090 Done:
1091   if (Data != NULL) {
1092     FreePool (Data);
1093   }
1094 
1095   return IsFound;
1096 }
1097 
1098 /**
1099   Check whether the timestamp is valid by comparing the signing time and the revocation time.
1100 
1101   @param SigningTime         A pointer to the signing time.
1102   @param RevocationTime      A pointer to the revocation time.
1103 
1104   @retval  TRUE              The SigningTime is not later than the RevocationTime.
1105   @retval  FALSE             The SigningTime is later than the RevocationTime.
1106 
1107 **/
1108 BOOLEAN
IsValidSignatureByTimestamp(IN EFI_TIME * SigningTime,IN EFI_TIME * RevocationTime)1109 IsValidSignatureByTimestamp (
1110   IN EFI_TIME               *SigningTime,
1111   IN EFI_TIME               *RevocationTime
1112   )
1113 {
1114   if (SigningTime->Year != RevocationTime->Year) {
1115     return (BOOLEAN) (SigningTime->Year < RevocationTime->Year);
1116   } else if (SigningTime->Month != RevocationTime->Month) {
1117     return (BOOLEAN) (SigningTime->Month < RevocationTime->Month);
1118   } else if (SigningTime->Day != RevocationTime->Day) {
1119     return (BOOLEAN) (SigningTime->Day < RevocationTime->Day);
1120   } else if (SigningTime->Hour != RevocationTime->Hour) {
1121     return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour);
1122   } else if (SigningTime->Minute != RevocationTime->Minute) {
1123     return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute);
1124   }
1125 
1126   return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second);
1127 }
1128 
1129 /**
1130   Check if the given time value is zero.
1131 
1132   @param[in]  Time      Pointer of a time value.
1133 
1134   @retval     TRUE      The Time is Zero.
1135   @retval     FALSE     The Time is not Zero.
1136 
1137 **/
1138 BOOLEAN
IsTimeZero(IN EFI_TIME * Time)1139 IsTimeZero (
1140   IN EFI_TIME               *Time
1141   )
1142 {
1143   if ((Time->Year == 0) && (Time->Month == 0) &&  (Time->Day == 0) &&
1144       (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) {
1145     return TRUE;
1146   }
1147 
1148   return FALSE;
1149 }
1150 
1151 /**
1152   Record multiple certificate list & verification state of a verified image to
1153   IMAGE_EXECUTION_TABLE.
1154 
1155   @param[in]  CertBuf              Certificate list buffer.
1156   @param[in]  CertBufLength        Certificate list buffer.
1157   @param[in]  Action               Certificate list action to be record.
1158   @param[in]  ImageName            Image name.
1159   @param[in]  ImageDevicePath      Image device path.
1160 
1161 **/
1162 VOID
RecordCertListToImageExeuctionTable(IN UINT8 * CertBuf,IN UINTN CertBufLength,IN EFI_IMAGE_EXECUTION_ACTION Action,IN CHAR16 * ImageName OPTIONAL,IN CONST EFI_DEVICE_PATH_PROTOCOL * ImageDevicePath OPTIONAL)1163 RecordCertListToImageExeuctionTable(
1164   IN UINT8                          *CertBuf,
1165   IN UINTN                           CertBufLength,
1166   IN EFI_IMAGE_EXECUTION_ACTION      Action,
1167   IN CHAR16                         *ImageName OPTIONAL,
1168   IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
1169   )
1170 {
1171   UINT8               CertNumber;
1172   UINT8               *CertPtr;
1173   UINTN               Index;
1174   UINT8               *Cert;
1175   UINTN               CertSize;
1176   EFI_STATUS          Status;
1177   EFI_SIGNATURE_LIST  *SignatureList;
1178   UINTN               SignatureListSize;
1179 
1180   CertNumber = (UINT8) (*CertBuf);
1181   CertPtr    = CertBuf + 1;
1182   for (Index = 0; Index < CertNumber; Index++) {
1183     CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);
1184     Cert     = (UINT8 *)CertPtr + sizeof (UINT32);
1185 
1186     //
1187     // Record all cert in cert chain to be passed
1188     //
1189     Status = CreateSignatureList(Cert, CertSize, &gEfiCertX509Guid, &SignatureList, &SignatureListSize);
1190     if (!EFI_ERROR(Status)) {
1191       AddImageExeInfo (Action, ImageName, ImageDevicePath, SignatureList, SignatureListSize);
1192       FreePool (SignatureList);
1193     }
1194   }
1195 }
1196 
1197 
1198 /**
1199   Check whether the timestamp signature is valid and the signing time is also earlier than
1200   the revocation time.
1201 
1202   @param[in]  AuthData        Pointer to the Authenticode signature retrieved from signed image.
1203   @param[in]  AuthDataSize    Size of the Authenticode signature in bytes.
1204   @param[in]  RevocationTime  The time that the certificate was revoked.
1205 
1206   @retval TRUE      Timestamp signature is valid and signing time is no later than the
1207                     revocation time.
1208   @retval FALSE     Timestamp signature is not valid or the signing time is later than the
1209                     revocation time.
1210 
1211 **/
1212 BOOLEAN
PassTimestampCheck(IN UINT8 * AuthData,IN UINTN AuthDataSize,IN EFI_TIME * RevocationTime)1213 PassTimestampCheck (
1214   IN UINT8                  *AuthData,
1215   IN UINTN                  AuthDataSize,
1216   IN EFI_TIME               *RevocationTime
1217   )
1218 {
1219   EFI_STATUS                Status;
1220   BOOLEAN                   VerifyStatus;
1221   EFI_SIGNATURE_LIST        *CertList;
1222   EFI_SIGNATURE_DATA        *Cert;
1223   UINT8                     *DbtData;
1224   UINTN                     DbtDataSize;
1225   UINT8                     *RootCert;
1226   UINTN                     RootCertSize;
1227   UINTN                     Index;
1228   UINTN                     CertCount;
1229   EFI_TIME                  SigningTime;
1230 
1231   //
1232   // Variable Initialization
1233   //
1234   VerifyStatus      = FALSE;
1235   DbtData           = NULL;
1236   CertList          = NULL;
1237   Cert              = NULL;
1238   RootCert          = NULL;
1239   RootCertSize      = 0;
1240 
1241   //
1242   // If RevocationTime is zero, the certificate shall be considered to always be revoked.
1243   //
1244   if (IsTimeZero (RevocationTime)) {
1245     return FALSE;
1246   }
1247 
1248   //
1249   // RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards.
1250   // Using the dbt to get the trusted TSA certificates.
1251   //
1252   DbtDataSize = 0;
1253   Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, NULL);
1254   if (Status != EFI_BUFFER_TOO_SMALL) {
1255     goto Done;
1256   }
1257   DbtData = (UINT8 *) AllocateZeroPool (DbtDataSize);
1258   if (DbtData == NULL) {
1259     goto Done;
1260   }
1261   Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, (VOID *) DbtData);
1262   if (EFI_ERROR (Status)) {
1263     goto Done;
1264   }
1265 
1266   CertList = (EFI_SIGNATURE_LIST *) DbtData;
1267   while ((DbtDataSize > 0) && (DbtDataSize >= CertList->SignatureListSize)) {
1268     if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
1269       Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1270       CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1271       for (Index = 0; Index < CertCount; Index++) {
1272         //
1273         // Iterate each Signature Data Node within this CertList for verify.
1274         //
1275         RootCert     = Cert->SignatureData;
1276         RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
1277         //
1278         // Get the signing time if the timestamp signature is valid.
1279         //
1280         if (ImageTimestampVerify (AuthData, AuthDataSize, RootCert, RootCertSize, &SigningTime)) {
1281           //
1282           // The signer signature is valid only when the signing time is earlier than revocation time.
1283           //
1284           if (IsValidSignatureByTimestamp (&SigningTime, RevocationTime)) {
1285             VerifyStatus = TRUE;
1286             goto Done;
1287           }
1288         }
1289         Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1290       }
1291     }
1292     DbtDataSize -= CertList->SignatureListSize;
1293     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1294   }
1295 
1296 Done:
1297   if (DbtData != NULL) {
1298     FreePool (DbtData);
1299   }
1300 
1301   return VerifyStatus;
1302 }
1303 
1304 /**
1305   Check whether the image signature is forbidden by the forbidden database (dbx).
1306   The image is forbidden to load if any certificates for signing are revoked before signing time.
1307 
1308   @param[in]  AuthData             Pointer to the Authenticode signature retrieved from the signed image.
1309   @param[in]  AuthDataSize         Size of the Authenticode signature in bytes.
1310   @param[in]  IsAuditMode          Whether system Secure Boot Mode is in AuditMode.
1311   @param[in]  ImageName            Name of the image to verify.
1312   @param[in]  ImageDevicePath      DevicePath of the image to verify.
1313 
1314   @retval TRUE              Image is forbidden by dbx.
1315   @retval FALSE             Image is not forbidden by dbx.
1316 
1317 **/
1318 BOOLEAN
IsForbiddenByDbx(IN UINT8 * AuthData,IN UINTN AuthDataSize,IN BOOLEAN IsAuditMode,IN CHAR16 * ImageName OPTIONAL,IN CONST EFI_DEVICE_PATH_PROTOCOL * ImageDevicePath OPTIONAL)1319 IsForbiddenByDbx (
1320   IN UINT8                          *AuthData,
1321   IN UINTN                          AuthDataSize,
1322   IN BOOLEAN                        IsAuditMode,
1323   IN CHAR16                         *ImageName OPTIONAL,
1324   IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
1325   )
1326 {
1327   EFI_STATUS                Status;
1328   BOOLEAN                   IsForbidden;
1329   UINT8                     *Data;
1330   UINTN                     DataSize;
1331   EFI_SIGNATURE_LIST        *CertList;
1332   UINTN                     CertListSize;
1333   EFI_SIGNATURE_DATA        *CertData;
1334   UINT8                     *RootCert;
1335   UINTN                     RootCertSize;
1336   UINTN                     CertCount;
1337   UINTN                     Index;
1338   UINT8                     *CertBuffer;
1339   UINTN                     BufferLength;
1340   UINT8                     *TrustedCert;
1341   UINTN                     TrustedCertLength;
1342   UINT8                     CertNumber;
1343   UINT8                     *CertPtr;
1344   UINT8                     *Cert;
1345   UINTN                     CertSize;
1346   EFI_TIME                  RevocationTime;
1347   UINT8                     *SignerCert;
1348   UINTN                     SignerCertLength;
1349   UINT8                     *UnchainCert;
1350   UINTN                     UnchainCertLength;
1351   //
1352   // Variable Initialization
1353   //
1354   IsForbidden       = FALSE;
1355   Data              = NULL;
1356   CertList          = NULL;
1357   CertData          = NULL;
1358   RootCert          = NULL;
1359   RootCertSize      = 0;
1360   Cert              = NULL;
1361   CertBuffer        = NULL;
1362   BufferLength      = 0;
1363   TrustedCert       = NULL;
1364   TrustedCertLength = 0;
1365   SignerCert        = NULL;
1366   SignerCertLength  = 0;
1367   UnchainCert       = NULL;
1368   UnchainCertLength = 0;
1369 
1370   //
1371   // The image will not be forbidden if dbx can't be got.
1372   //
1373   DataSize = 0;
1374   Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1375   if (Status != EFI_BUFFER_TOO_SMALL) {
1376     return IsForbidden;
1377   }
1378   Data = (UINT8 *) AllocateZeroPool (DataSize);
1379   if (Data == NULL) {
1380     return IsForbidden;
1381   }
1382 
1383   Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);
1384   if (EFI_ERROR (Status)) {
1385     return IsForbidden;
1386   }
1387 
1388   //
1389   // Verify image signature with RAW X509 certificates in DBX database.
1390   // If passed, the image will be forbidden.
1391   //
1392   CertList     = (EFI_SIGNATURE_LIST *) Data;
1393   CertListSize = DataSize;
1394   while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) {
1395     if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
1396       CertData  = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1397       CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1398 
1399       for (Index = 0; Index < CertCount; Index++) {
1400         //
1401         // Iterate each Signature Data Node within this CertList for verify.
1402         //
1403         RootCert     = CertData->SignatureData;
1404         RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
1405 
1406         //
1407         // Call AuthenticodeVerify library to Verify Authenticode struct.
1408         //
1409         IsForbidden = AuthenticodeVerify (
1410                         AuthData,
1411                         AuthDataSize,
1412                         RootCert,
1413                         RootCertSize,
1414                         mImageDigest,
1415                         mImageDigestSize
1416                         );
1417         if (IsForbidden) {
1418           SecureBootHook (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);
1419           goto Done;
1420         }
1421 
1422         CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);
1423       }
1424     }
1425 
1426     CertListSize -= CertList->SignatureListSize;
1427     CertList      = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1428   }
1429 
1430   //
1431   // Check X.509 Certificate Hash & Possible Timestamp.
1432   //
1433 
1434   //
1435   // Retrieve the certificate stack from AuthData
1436   // The output CertStack format will be:
1437   //       UINT8  CertNumber;
1438   //       UINT32 Cert1Length;
1439   //       UINT8  Cert1[];
1440   //       UINT32 Cert2Length;
1441   //       UINT8  Cert2[];
1442   //       ...
1443   //       UINT32 CertnLength;
1444   //       UINT8  Certn[];
1445   //
1446   Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);
1447   if ((BufferLength == 0) || (CertBuffer == NULL)) {
1448     IsForbidden = TRUE;
1449     goto Done;
1450   }
1451 
1452   //
1453   // Check if any hash of certificates embedded in AuthData is in the forbidden database.
1454   //
1455   CertNumber = (UINT8) (*CertBuffer);
1456   CertPtr    = CertBuffer + 1;
1457   for (Index = 0; Index < CertNumber; Index++) {
1458     CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);
1459     Cert     = (UINT8 *)CertPtr + sizeof (UINT32);
1460 
1461     if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {
1462       //
1463       // Check the timestamp signature and signing time to determine if the image can be trusted.
1464       //
1465       IsForbidden = TRUE;
1466       if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) {
1467         IsForbidden = FALSE;
1468       }
1469       goto Done;
1470     }
1471 
1472     CertPtr = CertPtr + sizeof (UINT32) + CertSize;
1473   }
1474 
1475 Done:
1476   if (IsForbidden && IsAuditMode) {
1477     Pkcs7GetCertificatesList(AuthData, AuthDataSize, &SignerCert, &SignerCertLength, &UnchainCert, &UnchainCertLength);
1478 
1479     //
1480     // Record all certs in image to be failed
1481     //
1482     if ((SignerCertLength != 0) && (SignerCert != NULL)) {
1483       RecordCertListToImageExeuctionTable(
1484         SignerCert,
1485         SignerCertLength,
1486         EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
1487         ImageName,
1488         ImageDevicePath
1489         );
1490     }
1491 
1492     if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
1493       RecordCertListToImageExeuctionTable(
1494         UnchainCert,
1495         UnchainCertLength,
1496         EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
1497         ImageName,
1498         ImageDevicePath
1499         );
1500     }
1501   }
1502 
1503   if (Data != NULL) {
1504     FreePool (Data);
1505   }
1506 
1507   Pkcs7FreeSigners (CertBuffer);
1508   Pkcs7FreeSigners (TrustedCert);
1509   Pkcs7FreeSigners (SignerCert);
1510   Pkcs7FreeSigners (UnchainCert);
1511 
1512   return IsForbidden;
1513 }
1514 
1515 
1516 /**
1517   Check whether the image signature can be verified by the trusted certificates in DB database.
1518 
1519   @param[in]  AuthData              Pointer to the Authenticode signature retrieved from signed image.
1520   @param[in]  AuthDataSize          Size of the Authenticode signature in bytes.
1521   @param[in]  IsAuditMode           Whether system Secure Boot Mode is in AuditMode.
1522   @param[in]  ImageName             Name of the image to verify.
1523   @param[in]  ImageDevicePath       DevicePath of the image to verify.
1524 
1525   @retval TRUE         Image passed verification using certificate in db.
1526   @retval FALSE        Image didn't pass verification using certificate in db.
1527 
1528 **/
1529 BOOLEAN
IsAllowedByDb(IN UINT8 * AuthData,IN UINTN AuthDataSize,IN BOOLEAN IsAuditMode,IN CHAR16 * ImageName OPTIONAL,IN CONST EFI_DEVICE_PATH_PROTOCOL * ImageDevicePath OPTIONAL)1530 IsAllowedByDb (
1531   IN UINT8                          *AuthData,
1532   IN UINTN                          AuthDataSize,
1533   IN BOOLEAN                        IsAuditMode,
1534   IN CHAR16                         *ImageName OPTIONAL,
1535   IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
1536   )
1537 {
1538   EFI_STATUS                Status;
1539   BOOLEAN                   VerifyStatus;
1540   EFI_SIGNATURE_LIST        *CertList;
1541   EFI_SIGNATURE_DATA        *CertData;
1542   UINTN                     DataSize;
1543   UINT8                     *Data;
1544   UINT8                     *RootCert;
1545   UINTN                     RootCertSize;
1546   UINTN                     Index;
1547   UINTN                     CertCount;
1548   UINTN                     DbxDataSize;
1549   UINT8                     *DbxData;
1550   EFI_TIME                  RevocationTime;
1551   UINT8                     *SignerCert;
1552   UINTN                     SignerCertLength;
1553   UINT8                     *UnchainCert;
1554   UINTN                     UnchainCertLength;
1555 
1556   Data              = NULL;
1557   CertList          = NULL;
1558   CertData          = NULL;
1559   RootCert          = NULL;
1560   DbxData           = NULL;
1561   RootCertSize      = 0;
1562   VerifyStatus      = FALSE;
1563   SignerCert        = NULL;
1564   SignerCertLength  = 0;
1565   UnchainCert       = NULL;
1566   UnchainCertLength = 0;
1567 
1568   DataSize = 0;
1569   Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1570   if (Status == EFI_BUFFER_TOO_SMALL) {
1571     Data = (UINT8 *) AllocateZeroPool (DataSize);
1572     if (Data == NULL) {
1573       return VerifyStatus;
1574     }
1575 
1576     Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);
1577     if (EFI_ERROR (Status)) {
1578       goto Done;
1579     }
1580 
1581     //
1582     // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.
1583     //
1584     CertList = (EFI_SIGNATURE_LIST *) Data;
1585     while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
1586       if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
1587         CertData  = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1588         CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1589 
1590         for (Index = 0; Index < CertCount; Index++) {
1591           //
1592           // Iterate each Signature Data Node within this CertList for verify.
1593           //
1594           RootCert     = CertData->SignatureData;
1595           RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
1596 
1597           //
1598           // Call AuthenticodeVerify library to Verify Authenticode struct.
1599           //
1600           VerifyStatus = AuthenticodeVerify (
1601                            AuthData,
1602                            AuthDataSize,
1603                            RootCert,
1604                            RootCertSize,
1605                            mImageDigest,
1606                            mImageDigestSize
1607                            );
1608           if (VerifyStatus) {
1609             //
1610             // Here We still need to check if this RootCert's Hash is revoked
1611             //
1612             Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL);
1613             if (Status == EFI_BUFFER_TOO_SMALL) {
1614               goto Done;
1615             }
1616             DbxData = (UINT8 *) AllocateZeroPool (DbxDataSize);
1617             if (DbxData == NULL) {
1618               goto Done;
1619             }
1620 
1621             Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData);
1622             if (EFI_ERROR (Status)) {
1623               goto Done;
1624             }
1625 
1626             if (IsCertHashFoundInDatabase (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime)) {
1627               //
1628               // Check the timestamp signature and signing time to determine if the image can be trusted.
1629               //
1630               VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);
1631             }
1632 
1633             goto Done;
1634           }
1635 
1636           CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);
1637         }
1638       }
1639 
1640       DataSize -= CertList->SignatureListSize;
1641       CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1642     }
1643   }
1644 
1645 Done:
1646 
1647   if (VerifyStatus) {
1648     SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);
1649   }
1650 
1651   if (IsAuditMode) {
1652 
1653     Pkcs7GetCertificatesList(AuthData, AuthDataSize, &SignerCert, &SignerCertLength, &UnchainCert, &UnchainCertLength);
1654     if (VerifyStatus) {
1655       if ((SignerCertLength != 0) && (SignerCert != NULL)) {
1656         //
1657         // Record all cert in signer's cert chain to be passed
1658         //
1659         RecordCertListToImageExeuctionTable(
1660           SignerCert,
1661           SignerCertLength,
1662           EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED,
1663           ImageName,
1664           ImageDevicePath
1665           );
1666       }
1667 
1668       if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
1669         //
1670         // Record all certs in unchained certificates lists to be failed
1671         //
1672         RecordCertListToImageExeuctionTable(
1673           UnchainCert,
1674           UnchainCertLength,
1675           EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
1676           ImageName,
1677           ImageDevicePath
1678           );
1679       }
1680     } else {
1681       //
1682       // Record all certs in image to be failed
1683       //
1684       if ((SignerCertLength != 0) && (SignerCert != NULL)) {
1685         RecordCertListToImageExeuctionTable(
1686           SignerCert,
1687           SignerCertLength,
1688           EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
1689           ImageName,
1690           ImageDevicePath
1691           );
1692       }
1693 
1694       if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
1695         RecordCertListToImageExeuctionTable(
1696           UnchainCert,
1697           UnchainCertLength,
1698           EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
1699           ImageName,
1700           ImageDevicePath
1701           );
1702       }
1703     }
1704   }
1705 
1706 
1707   if (Data != NULL) {
1708     FreePool (Data);
1709   }
1710   if (DbxData != NULL) {
1711     FreePool (DbxData);
1712   }
1713 
1714   Pkcs7FreeSigners (SignerCert);
1715   Pkcs7FreeSigners (UnchainCert);
1716 
1717   return VerifyStatus;
1718 }
1719 
1720 /**
1721   Provide verification service for signed images in AuditMode, which include both signature validation
1722   and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
1723   MSFT Authenticode type signatures are supported.
1724 
1725   In this implementation, only verify external executables when in AuditMode.
1726   Executables from FV is bypass, so pass in AuthenticationStatus is ignored. Other authentication status
1727   are record into IMAGE_EXECUTION_TABLE.
1728 
1729   The image verification policy is:
1730     If the image is signed,
1731       At least one valid signature or at least one hash value of the image must match a record
1732       in the security database "db", and no valid signature nor any hash value of the image may
1733       be reflected in the security database "dbx".
1734     Otherwise, the image is not signed,
1735       The SHA256 hash value of the image must match a record in the security database "db", and
1736       not be reflected in the security data base "dbx".
1737 
1738   Caution: This function may receive untrusted input.
1739   PE/COFF image is external input, so this function will validate its data structure
1740   within this image buffer before use.
1741 
1742   @param[in]    AuthenticationStatus
1743                            This is the authentication status returned from the security
1744                            measurement services for the input file.
1745   @param[in]    File       This is a pointer to the device path of the file that is
1746                            being dispatched. This will optionally be used for logging.
1747   @param[in]    FileBuffer File buffer matches the input file device path.
1748   @param[in]    FileSize   Size of File buffer matches the input file device path.
1749   @param[in]    BootPolicy A boot policy that was used to call LoadImage() UEFI service.
1750 
1751   @retval EFI_SUCCESS            The authenticate info is sucessfully stored for the file
1752                                  specified by DevicePath and non-NULL FileBuffer
1753   @retval EFI_ACCESS_DENIED      The file specified by File and FileBuffer did not
1754                                  authenticate, and the platform policy dictates that the DXE
1755                                  Foundation many not use File.
1756 
1757 **/
1758 EFI_STATUS
1759 EFIAPI
ImageVerificationInAuditMode(IN UINT32 AuthenticationStatus,IN CONST EFI_DEVICE_PATH_PROTOCOL * File,IN VOID * FileBuffer,IN UINTN FileSize,IN BOOLEAN BootPolicy)1760 ImageVerificationInAuditMode (
1761   IN  UINT32                           AuthenticationStatus,
1762   IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,
1763   IN  VOID                             *FileBuffer,
1764   IN  UINTN                            FileSize,
1765   IN  BOOLEAN                          BootPolicy
1766   )
1767 {
1768   EFI_STATUS                           Status;
1769   UINT16                               Magic;
1770   EFI_IMAGE_DOS_HEADER                 *DosHdr;
1771   EFI_SIGNATURE_LIST                   *SignatureList;
1772   EFI_IMAGE_EXECUTION_ACTION           Action;
1773   WIN_CERTIFICATE                      *WinCertificate;
1774   UINT32                               Policy;
1775   PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;
1776   UINT32                               NumberOfRvaAndSizes;
1777   WIN_CERTIFICATE_EFI_PKCS             *PkcsCertData;
1778   WIN_CERTIFICATE_UEFI_GUID            *WinCertUefiGuid;
1779   UINT8                                *AuthData;
1780   UINTN                                AuthDataSize;
1781   EFI_IMAGE_DATA_DIRECTORY             *SecDataDir;
1782   UINT32                               OffSet;
1783   CHAR16                               *FilePathStr;
1784   UINTN                                SignatureListSize;
1785 
1786   SignatureList     = NULL;
1787   WinCertificate    = NULL;
1788   SecDataDir        = NULL;
1789   PkcsCertData      = NULL;
1790   FilePathStr       = NULL;
1791   Action            = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED;
1792   Status            = EFI_ACCESS_DENIED;
1793 
1794 
1795   //
1796   // Check the image type and get policy setting.
1797   //
1798   switch (GetImageType (File)) {
1799 
1800   case IMAGE_FROM_FV:
1801     Policy = ALWAYS_EXECUTE;
1802     break;
1803 
1804   case IMAGE_FROM_OPTION_ROM:
1805     Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);
1806     break;
1807 
1808   case IMAGE_FROM_REMOVABLE_MEDIA:
1809     Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);
1810     break;
1811 
1812   case IMAGE_FROM_FIXED_MEDIA:
1813     Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);
1814     break;
1815 
1816   default:
1817     Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
1818     break;
1819   }
1820 
1821   //
1822   // If policy is always/never execute, return directly.
1823   //
1824   if (Policy == ALWAYS_EXECUTE) {
1825     return EFI_SUCCESS;
1826   }
1827 
1828   //
1829   // Get Image Device Path Str
1830   //
1831   FilePathStr = ConvertDevicePathToText (File, FALSE, TRUE);
1832 
1833   //
1834   // Authentication failed because of (unspecified) firmware security policy
1835   //
1836   if (Policy == NEVER_EXECUTE) {
1837     //
1838     // No signature, record FilePath/FilePathStr only
1839     //
1840     AddImageExeInfo (EFI_IMAGE_EXECUTION_POLICY_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED, FilePathStr, File, NULL, 0);
1841     goto END;
1842   }
1843 
1844   //
1845   // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION
1846   // violates the UEFI spec and has been removed.
1847   //
1848   ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);
1849   if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {
1850     CpuDeadLoop ();
1851   }
1852 
1853   //
1854   // Read the Dos header.
1855   //
1856   if (FileBuffer == NULL) {
1857     Status = EFI_INVALID_PARAMETER;
1858     goto END;
1859   }
1860 
1861   mImageBase  = (UINT8 *) FileBuffer;
1862   mImageSize  = FileSize;
1863 
1864   ZeroMem (&ImageContext, sizeof (ImageContext));
1865   ImageContext.Handle    = (VOID *) FileBuffer;
1866   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;
1867 
1868   //
1869   // Get information about the image being loaded
1870   //
1871   Status = PeCoffLoaderGetImageInfo (&ImageContext);
1872   if (EFI_ERROR (Status)) {
1873     //
1874     // The information can't be got from the invalid PeImage
1875     //
1876     goto END;
1877   }
1878 
1879 
1880   DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;
1881   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1882     //
1883     // DOS image header is present,
1884     // so read the PE header after the DOS image header.
1885     //
1886     mPeCoffHeaderOffset = DosHdr->e_lfanew;
1887   } else {
1888     mPeCoffHeaderOffset = 0;
1889   }
1890 
1891   //
1892   // Check PE/COFF image.
1893   //
1894   mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);
1895   if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1896     //
1897     // It is not a valid Pe/Coff file.
1898     //
1899     Status = EFI_ACCESS_DENIED;
1900     goto END;
1901   }
1902 
1903   if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1904     //
1905     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
1906     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
1907     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
1908     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
1909     //
1910     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1911   } else {
1912     //
1913     // Get the magic value from the PE/COFF Optional Header
1914     //
1915     Magic = mNtHeader.Pe32->OptionalHeader.Magic;
1916   }
1917 
1918   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1919     //
1920     // Use PE32 offset.
1921     //
1922     NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1923     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
1924       SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
1925     }
1926   } else {
1927     //
1928     // Use PE32+ offset.
1929     //
1930     NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1931     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
1932       SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
1933     }
1934   }
1935 
1936   //
1937   // Start Image Validation.
1938   //
1939   if (SecDataDir == NULL || SecDataDir->Size == 0) {
1940     //
1941     // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",
1942     // and not be reflected in the security data base "dbx".
1943     //
1944     if (!HashPeImage (HASHALG_SHA256)) {
1945       Status = EFI_ACCESS_DENIED;
1946       goto END;
1947     }
1948 
1949     //
1950     // Image Hash is in forbidden database (DBX).
1951     //
1952     if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
1953       //
1954       // Image Hash is in allowed database (DB).
1955       //
1956       if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
1957         Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED;
1958       }
1959     }
1960 
1961     //
1962     // Add HASH digest for image without signature
1963     //
1964     Status = CreateSignatureList(mImageDigest, mImageDigestSize, &mCertType, &SignatureList, &SignatureListSize);
1965     if (!EFI_ERROR(Status)) {
1966       AddImageExeInfo (Action, FilePathStr, File, SignatureList, SignatureListSize);
1967       FreePool (SignatureList);
1968     }
1969     goto END;
1970   }
1971 
1972   //
1973   // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7
1974   // "Attribute Certificate Table".
1975   // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.
1976   //
1977   for (OffSet = SecDataDir->VirtualAddress;
1978        OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);
1979        OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) {
1980     WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);
1981     if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||
1982         (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {
1983       break;
1984     }
1985 
1986     //
1987     // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.
1988     //
1989     if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
1990       //
1991       // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the
1992       // Authenticode specification.
1993       //
1994       PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;
1995       if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {
1996         break;
1997       }
1998       AuthData   = PkcsCertData->CertData;
1999       AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);
2000     } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
2001       //
2002       // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.
2003       //
2004       WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;
2005       if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
2006         break;
2007       }
2008       if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {
2009         continue;
2010       }
2011       AuthData = WinCertUefiGuid->CertData;
2012       AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
2013     } else {
2014       if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {
2015         break;
2016       }
2017       continue;
2018     }
2019 
2020     Status = HashPeImageByType (AuthData, AuthDataSize);
2021     if (EFI_ERROR (Status)) {
2022       continue;
2023     }
2024 
2025     Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED;
2026 
2027     //
2028     // Check the digital signature against the revoked certificate in forbidden database (dbx).
2029     // Check the digital signature against the valid certificate in allowed database (db).
2030     //
2031     if (!IsForbiddenByDbx (AuthData, AuthDataSize, TRUE, FilePathStr, File)) {
2032       IsAllowedByDb (AuthData, AuthDataSize, TRUE, FilePathStr, File);
2033     }
2034 
2035     //
2036     // Check the image's hash value.
2037     //
2038     if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
2039       if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
2040         Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED;
2041       }
2042     }
2043 
2044     //
2045     // Add HASH digest for image with signature
2046     //
2047     Status = CreateSignatureList(mImageDigest, mImageDigestSize, &mCertType, &SignatureList, &SignatureListSize);
2048 
2049     if (!EFI_ERROR(Status)) {
2050       AddImageExeInfo (Action, FilePathStr, File, SignatureList, SignatureListSize);
2051       FreePool (SignatureList);
2052     } else {
2053       goto END;
2054     }
2055   }
2056 
2057 
2058   if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {
2059     //
2060     // The Size in Certificate Table or the attribute certicate table is corrupted.
2061     //
2062     Status = EFI_ACCESS_DENIED;
2063   } else {
2064     Status = EFI_SUCCESS;
2065   }
2066 
2067 END:
2068 
2069   if (FilePathStr != NULL) {
2070     FreePool(FilePathStr);
2071     FilePathStr = NULL;
2072   }
2073 
2074   return Status;
2075 }
2076 
2077 /**
2078   Provide verification service for signed images, which include both signature validation
2079   and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
2080   MSFT Authenticode type signatures are supported.
2081 
2082   In this implementation, only verify external executables when in USER MODE.
2083   Executables from FV is bypass, so pass in AuthenticationStatus is ignored.
2084 
2085   The image verification policy is:
2086     If the image is signed,
2087       At least one valid signature or at least one hash value of the image must match a record
2088       in the security database "db", and no valid signature nor any hash value of the image may
2089       be reflected in the security database "dbx".
2090     Otherwise, the image is not signed,
2091       The SHA256 hash value of the image must match a record in the security database "db", and
2092       not be reflected in the security data base "dbx".
2093 
2094   Caution: This function may receive untrusted input.
2095   PE/COFF image is external input, so this function will validate its data structure
2096   within this image buffer before use.
2097 
2098   @param[in]    AuthenticationStatus
2099                            This is the authentication status returned from the security
2100                            measurement services for the input file.
2101   @param[in]    File       This is a pointer to the device path of the file that is
2102                            being dispatched. This will optionally be used for logging.
2103   @param[in]    FileBuffer File buffer matches the input file device path.
2104   @param[in]    FileSize   Size of File buffer matches the input file device path.
2105   @param[in]    BootPolicy A boot policy that was used to call LoadImage() UEFI service.
2106 
2107   @retval EFI_SUCCESS            The file specified by DevicePath and non-NULL
2108                                  FileBuffer did authenticate, and the platform policy dictates
2109                                  that the DXE Foundation may use the file.
2110   @retval EFI_SUCCESS            The device path specified by NULL device path DevicePath
2111                                  and non-NULL FileBuffer did authenticate, and the platform
2112                                  policy dictates that the DXE Foundation may execute the image in
2113                                  FileBuffer.
2114   @retval EFI_OUT_RESOURCE       Fail to allocate memory.
2115   @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
2116                                  the platform policy dictates that File should be placed
2117                                  in the untrusted state. The image has been added to the file
2118                                  execution table.
2119   @retval EFI_ACCESS_DENIED      The file specified by File and FileBuffer did not
2120                                  authenticate, and the platform policy dictates that the DXE
2121                                  Foundation many not use File.
2122 
2123 **/
2124 EFI_STATUS
2125 EFIAPI
DxeImageVerificationHandler(IN UINT32 AuthenticationStatus,IN CONST EFI_DEVICE_PATH_PROTOCOL * File,IN VOID * FileBuffer,IN UINTN FileSize,IN BOOLEAN BootPolicy)2126 DxeImageVerificationHandler (
2127   IN  UINT32                           AuthenticationStatus,
2128   IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,
2129   IN  VOID                             *FileBuffer,
2130   IN  UINTN                            FileSize,
2131   IN  BOOLEAN                          BootPolicy
2132   )
2133 {
2134   EFI_STATUS                           Status;
2135   UINT16                               Magic;
2136   EFI_IMAGE_DOS_HEADER                 *DosHdr;
2137   EFI_STATUS                           VerifyStatus;
2138   EFI_SIGNATURE_LIST                   *SignatureList;
2139   UINTN                                SignatureListSize;
2140   EFI_SIGNATURE_DATA                   *Signature;
2141   EFI_IMAGE_EXECUTION_ACTION           Action;
2142   WIN_CERTIFICATE                      *WinCertificate;
2143   UINT32                               Policy;
2144   UINT8                                *VarData;
2145   UINT8                                SecureBoot;
2146   UINT8                                AuditMode;
2147   PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;
2148   UINT32                               NumberOfRvaAndSizes;
2149   WIN_CERTIFICATE_EFI_PKCS             *PkcsCertData;
2150   WIN_CERTIFICATE_UEFI_GUID            *WinCertUefiGuid;
2151   UINT8                                *AuthData;
2152   UINTN                                AuthDataSize;
2153   EFI_IMAGE_DATA_DIRECTORY             *SecDataDir;
2154   UINT32                               OffSet;
2155   CHAR16                               *NameStr;
2156 
2157   SignatureList     = NULL;
2158   SignatureListSize = 0;
2159   WinCertificate    = NULL;
2160   SecDataDir        = NULL;
2161   PkcsCertData      = NULL;
2162   Action            = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
2163   Status            = EFI_ACCESS_DENIED;
2164   VerifyStatus      = EFI_ACCESS_DENIED;
2165 
2166   GetEfiGlobalVariable2 (EFI_AUDIT_MODE_NAME, (VOID**)&VarData, NULL);
2167   //
2168   // Skip verification if AuditMode variable doesn't exist. AuditMode should always exist
2169   //
2170   if (VarData == NULL) {
2171     return EFI_SUCCESS;
2172   }
2173   AuditMode = *VarData;
2174   FreePool(VarData);
2175 
2176   if (AuditMode == AUDIT_MODE_ENABLE) {
2177     return ImageVerificationInAuditMode(AuthenticationStatus, File, FileBuffer, FileSize, BootPolicy);
2178   }
2179 
2180   //
2181   // Check the image type and get policy setting.
2182   //
2183   switch (GetImageType (File)) {
2184 
2185   case IMAGE_FROM_FV:
2186     Policy = ALWAYS_EXECUTE;
2187     break;
2188 
2189   case IMAGE_FROM_OPTION_ROM:
2190     Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);
2191     break;
2192 
2193   case IMAGE_FROM_REMOVABLE_MEDIA:
2194     Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);
2195     break;
2196 
2197   case IMAGE_FROM_FIXED_MEDIA:
2198     Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);
2199     break;
2200 
2201   default:
2202     Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
2203     break;
2204   }
2205   //
2206   // If policy is always/never execute, return directly.
2207   //
2208   if (Policy == ALWAYS_EXECUTE) {
2209     return EFI_SUCCESS;
2210   } else if (Policy == NEVER_EXECUTE) {
2211     return EFI_ACCESS_DENIED;
2212   }
2213 
2214   //
2215   // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION
2216   // violates the UEFI spec and has been removed.
2217   //
2218   ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);
2219   if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {
2220     CpuDeadLoop ();
2221   }
2222 
2223   GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&VarData, NULL);
2224   //
2225   // Skip verification if SecureBoot variable doesn't exist.
2226   //
2227   if (VarData == NULL) {
2228     return EFI_SUCCESS;
2229   }
2230   SecureBoot = *VarData;
2231   FreePool(VarData);
2232 
2233   //
2234   // Skip verification if SecureBoot is disabled but not AuditMode
2235   //
2236   if (SecureBoot == SECURE_BOOT_MODE_DISABLE) {
2237     return EFI_SUCCESS;
2238   }
2239 
2240   //
2241   // Read the Dos header.
2242   //
2243   if (FileBuffer == NULL) {
2244     return EFI_INVALID_PARAMETER;
2245   }
2246 
2247   mImageBase  = (UINT8 *) FileBuffer;
2248   mImageSize  = FileSize;
2249 
2250   ZeroMem (&ImageContext, sizeof (ImageContext));
2251   ImageContext.Handle    = (VOID *) FileBuffer;
2252   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;
2253 
2254   //
2255   // Get information about the image being loaded
2256   //
2257   Status = PeCoffLoaderGetImageInfo (&ImageContext);
2258   if (EFI_ERROR (Status)) {
2259     //
2260     // The information can't be got from the invalid PeImage
2261     //
2262     goto Done;
2263   }
2264 
2265   Status = EFI_ACCESS_DENIED;
2266 
2267   DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;
2268   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
2269     //
2270     // DOS image header is present,
2271     // so read the PE header after the DOS image header.
2272     //
2273     mPeCoffHeaderOffset = DosHdr->e_lfanew;
2274   } else {
2275     mPeCoffHeaderOffset = 0;
2276   }
2277   //
2278   // Check PE/COFF image.
2279   //
2280   mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);
2281   if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
2282     //
2283     // It is not a valid Pe/Coff file.
2284     //
2285     goto Done;
2286   }
2287 
2288   if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2289     //
2290     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
2291     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
2292     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
2293     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
2294     //
2295     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2296   } else {
2297     //
2298     // Get the magic value from the PE/COFF Optional Header
2299     //
2300     Magic = mNtHeader.Pe32->OptionalHeader.Magic;
2301   }
2302 
2303   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2304     //
2305     // Use PE32 offset.
2306     //
2307     NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
2308     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
2309       SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
2310     }
2311   } else {
2312     //
2313     // Use PE32+ offset.
2314     //
2315     NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
2316     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
2317       SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
2318     }
2319   }
2320 
2321   //
2322   // Start Image Validation.
2323   //
2324   if (SecDataDir == NULL || SecDataDir->Size == 0) {
2325     //
2326     // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",
2327     // and not be reflected in the security data base "dbx".
2328     //
2329     if (!HashPeImage (HASHALG_SHA256)) {
2330       goto Done;
2331     }
2332 
2333     if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
2334       //
2335       // Image Hash is in forbidden database (DBX).
2336       //
2337       goto Done;
2338     }
2339 
2340     if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
2341       //
2342       // Image Hash is in allowed database (DB).
2343       //
2344       return EFI_SUCCESS;
2345     }
2346 
2347     //
2348     // Image Hash is not found in both forbidden and allowed database.
2349     //
2350     goto Done;
2351   }
2352 
2353   //
2354   // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7
2355   // "Attribute Certificate Table".
2356   // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.
2357   //
2358   for (OffSet = SecDataDir->VirtualAddress;
2359        OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);
2360        OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) {
2361     WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);
2362     if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||
2363         (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {
2364       break;
2365     }
2366 
2367     //
2368     // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.
2369     //
2370     if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
2371       //
2372       // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the
2373       // Authenticode specification.
2374       //
2375       PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;
2376       if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {
2377         break;
2378       }
2379       AuthData   = PkcsCertData->CertData;
2380       AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);
2381     } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
2382       //
2383       // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.
2384       //
2385       WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;
2386       if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
2387         break;
2388       }
2389       if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {
2390         continue;
2391       }
2392       AuthData = WinCertUefiGuid->CertData;
2393       AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
2394     } else {
2395       if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {
2396         break;
2397       }
2398       continue;
2399     }
2400 
2401     Status = HashPeImageByType (AuthData, AuthDataSize);
2402     if (EFI_ERROR (Status)) {
2403       continue;
2404     }
2405 
2406     //
2407     // Check the digital signature against the revoked certificate in forbidden database (dbx).
2408     //
2409     if (IsForbiddenByDbx (AuthData, AuthDataSize, FALSE, NULL, NULL)) {
2410       Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
2411       VerifyStatus = EFI_ACCESS_DENIED;
2412       break;
2413     }
2414 
2415     //
2416     // Check the digital signature against the valid certificate in allowed database (db).
2417     //
2418     if (EFI_ERROR (VerifyStatus)) {
2419       if (IsAllowedByDb (AuthData, AuthDataSize, FALSE, NULL, NULL)) {
2420         VerifyStatus = EFI_SUCCESS;
2421       }
2422     }
2423 
2424     //
2425     // Check the image's hash value.
2426     //
2427     if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
2428       Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;
2429       VerifyStatus = EFI_ACCESS_DENIED;
2430       break;
2431     } else if (EFI_ERROR (VerifyStatus)) {
2432       if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
2433         VerifyStatus = EFI_SUCCESS;
2434       }
2435     }
2436   }
2437 
2438   if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {
2439     //
2440     // The Size in Certificate Table or the attribute certicate table is corrupted.
2441     //
2442     VerifyStatus = EFI_ACCESS_DENIED;
2443   }
2444 
2445   if (!EFI_ERROR (VerifyStatus)) {
2446     return EFI_SUCCESS;
2447   } else {
2448     Status = EFI_ACCESS_DENIED;
2449     if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {
2450       //
2451       // Get image hash value as executable's signature.
2452       //
2453       SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;
2454       SignatureList     = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);
2455       if (SignatureList == NULL) {
2456         Status = EFI_OUT_OF_RESOURCES;
2457         goto Done;
2458       }
2459       SignatureList->SignatureHeaderSize  = 0;
2460       SignatureList->SignatureListSize    = (UINT32) SignatureListSize;
2461       SignatureList->SignatureSize        = (UINT32) (sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize);
2462       CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));
2463       Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));
2464       CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);
2465     }
2466   }
2467 
2468 Done:
2469   if (Status != EFI_SUCCESS) {
2470     //
2471     // Policy decides to defer or reject the image; add its information in image executable information table.
2472     //
2473     NameStr = ConvertDevicePathToText (File, FALSE, TRUE);
2474     AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize);
2475     if (NameStr != NULL) {
2476       DEBUG((EFI_D_INFO, "The image doesn't pass verification: %s\n", NameStr));
2477       FreePool(NameStr);
2478     }
2479     Status = EFI_SECURITY_VIOLATION;
2480   }
2481 
2482   if (SignatureList != NULL) {
2483     FreePool (SignatureList);
2484   }
2485 
2486   return Status;
2487 }
2488 
2489 /**
2490   On Ready To Boot Services Event notification handler.
2491 
2492   Add the image execution information table if it is not in system configuration table.
2493 
2494   @param[in]  Event     Event whose notification function is being invoked
2495   @param[in]  Context   Pointer to the notification function's context
2496 
2497 **/
2498 VOID
2499 EFIAPI
OnReadyToBoot(IN EFI_EVENT Event,IN VOID * Context)2500 OnReadyToBoot (
2501   IN      EFI_EVENT               Event,
2502   IN      VOID                    *Context
2503   )
2504 {
2505   EFI_IMAGE_EXECUTION_INFO_TABLE  *ImageExeInfoTable;
2506   UINTN                           ImageExeInfoTableSize;
2507 
2508   EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);
2509   if (ImageExeInfoTable != NULL) {
2510     return;
2511   }
2512 
2513   ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
2514   ImageExeInfoTable     = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize);
2515   if (ImageExeInfoTable == NULL) {
2516     return ;
2517   }
2518 
2519   ImageExeInfoTable->NumberOfImages = 0;
2520   gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) ImageExeInfoTable);
2521 
2522 }
2523 
2524 /**
2525   Register security measurement handler.
2526 
2527   @param  ImageHandle   ImageHandle of the loaded driver.
2528   @param  SystemTable   Pointer to the EFI System Table.
2529 
2530   @retval EFI_SUCCESS   The handlers were registered successfully.
2531 **/
2532 EFI_STATUS
2533 EFIAPI
DxeImageVerificationLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)2534 DxeImageVerificationLibConstructor (
2535   IN EFI_HANDLE        ImageHandle,
2536   IN EFI_SYSTEM_TABLE  *SystemTable
2537   )
2538 {
2539   EFI_EVENT            Event;
2540 
2541   //
2542   // Register the event to publish the image execution table.
2543   //
2544   EfiCreateEventReadyToBootEx (
2545     TPL_CALLBACK,
2546     OnReadyToBoot,
2547     NULL,
2548     &Event
2549     );
2550 
2551   return RegisterSecurity2Handler (
2552           DxeImageVerificationHandler,
2553           EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
2554           );
2555 }
2556