]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
Shouldn't free the PciDev structure because the PciDev needs to be saved to RemovedPc...
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
... / ...
CommitLineData
1/** @file\r
2 Implement image verification services for secure boot service in UEFI2.3.1.\r
3\r
4 Caution: This file requires additional review when modified.\r
5 This library will have external input - PE/COFF image.\r
6 This external input must be validated carefully to avoid security issue like\r
7 buffer overflow, integer overflow.\r
8\r
9 DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content\r
10 read is within the image buffer.\r
11\r
12 DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept\r
13 untrusted PE/COFF image and validate its data structure within this image buffer before use.\r
14\r
15Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
16This program and the accompanying materials\r
17are licensed and made available under the terms and conditions of the BSD License\r
18which accompanies this distribution. The full text of the license may be found at\r
19http://opensource.org/licenses/bsd-license.php\r
20\r
21THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
22WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
23\r
24**/\r
25\r
26#include "DxeImageVerificationLib.h"\r
27\r
28//\r
29// Caution: This is used by a function which may receive untrusted input.\r
30// These global variables hold PE/COFF image data, and they should be validated before use.\r
31//\r
32EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
33UINT32 mPeCoffHeaderOffset;\r
34EFI_GUID mCertType;\r
35\r
36//\r
37// Information on current PE/COFF image\r
38//\r
39UINTN mImageSize;\r
40UINT8 *mImageBase = NULL;\r
41UINT8 mImageDigest[MAX_DIGEST_SIZE];\r
42UINTN mImageDigestSize;\r
43\r
44//\r
45// Notify string for authorization UI.\r
46//\r
47CHAR16 mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"Image verification pass but not found in authorized database!";\r
48CHAR16 mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"Launch this image anyway? (Yes/Defer/No)";\r
49//\r
50// Public Exponent of RSA Key.\r
51//\r
52CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
53\r
54\r
55//\r
56// OID ASN.1 Value for Hash Algorithms\r
57//\r
58UINT8 mHashOidValue[] = {\r
59 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1\r
60 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224\r
61 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256\r
62 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384\r
63 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512\r
64 };\r
65\r
66HASH_TABLE mHash[] = {\r
67 { L"SHA1", 20, &mHashOidValue[0], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },\r
68 { L"SHA224", 28, &mHashOidValue[5], 9, NULL, NULL, NULL, NULL },\r
69 { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize,Sha256Init, Sha256Update, Sha256Final},\r
70 { L"SHA384", 48, &mHashOidValue[23], 9, NULL, NULL, NULL, NULL },\r
71 { L"SHA512", 64, &mHashOidValue[32], 9, NULL, NULL, NULL, NULL }\r
72};\r
73\r
74/**\r
75 Reads contents of a PE/COFF image in memory buffer.\r
76\r
77 Caution: This function may receive untrusted input.\r
78 PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
79 read is within the image buffer.\r
80\r
81 @param FileHandle Pointer to the file handle to read the PE/COFF image.\r
82 @param FileOffset Offset into the PE/COFF image to begin the read operation.\r
83 @param ReadSize On input, the size in bytes of the requested read operation. \r
84 On output, the number of bytes actually read.\r
85 @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
86 \r
87 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size \r
88**/\r
89EFI_STATUS\r
90EFIAPI\r
91DxeImageVerificationLibImageRead (\r
92 IN VOID *FileHandle,\r
93 IN UINTN FileOffset,\r
94 IN OUT UINTN *ReadSize,\r
95 OUT VOID *Buffer\r
96 )\r
97{\r
98 UINTN EndPosition;\r
99\r
100 if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
101 return EFI_INVALID_PARAMETER; \r
102 }\r
103\r
104 if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
105 return EFI_INVALID_PARAMETER;\r
106 }\r
107\r
108 EndPosition = FileOffset + *ReadSize;\r
109 if (EndPosition > mImageSize) {\r
110 *ReadSize = (UINT32)(mImageSize - FileOffset);\r
111 }\r
112\r
113 if (FileOffset >= mImageSize) {\r
114 *ReadSize = 0;\r
115 }\r
116\r
117 CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
118\r
119 return EFI_SUCCESS;\r
120}\r
121\r
122\r
123/**\r
124 Get the image type.\r
125\r
126 @param[in] File This is a pointer to the device path of the file that is\r
127 being dispatched.\r
128\r
129 @return UINT32 Image Type\r
130\r
131**/\r
132UINT32\r
133GetImageType (\r
134 IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
135 )\r
136{\r
137 EFI_STATUS Status;\r
138 EFI_HANDLE DeviceHandle;\r
139 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
140 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
141\r
142 if (File == NULL) {\r
143 return IMAGE_UNKNOWN;\r
144 }\r
145\r
146 //\r
147 // First check to see if File is from a Firmware Volume\r
148 //\r
149 DeviceHandle = NULL;\r
150 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
151 Status = gBS->LocateDevicePath (\r
152 &gEfiFirmwareVolume2ProtocolGuid,\r
153 &TempDevicePath,\r
154 &DeviceHandle\r
155 );\r
156 if (!EFI_ERROR (Status)) {\r
157 Status = gBS->OpenProtocol (\r
158 DeviceHandle,\r
159 &gEfiFirmwareVolume2ProtocolGuid,\r
160 NULL,\r
161 NULL,\r
162 NULL,\r
163 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
164 );\r
165 if (!EFI_ERROR (Status)) {\r
166 return IMAGE_FROM_FV;\r
167 }\r
168 }\r
169\r
170 //\r
171 // Next check to see if File is from a Block I/O device\r
172 //\r
173 DeviceHandle = NULL;\r
174 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
175 Status = gBS->LocateDevicePath (\r
176 &gEfiBlockIoProtocolGuid,\r
177 &TempDevicePath,\r
178 &DeviceHandle\r
179 );\r
180 if (!EFI_ERROR (Status)) {\r
181 BlockIo = NULL;\r
182 Status = gBS->OpenProtocol (\r
183 DeviceHandle,\r
184 &gEfiBlockIoProtocolGuid,\r
185 (VOID **) &BlockIo,\r
186 NULL,\r
187 NULL,\r
188 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
189 );\r
190 if (!EFI_ERROR (Status) && BlockIo != NULL) {\r
191 if (BlockIo->Media != NULL) {\r
192 if (BlockIo->Media->RemovableMedia) {\r
193 //\r
194 // Block I/O is present and specifies the media is removable\r
195 //\r
196 return IMAGE_FROM_REMOVABLE_MEDIA;\r
197 } else {\r
198 //\r
199 // Block I/O is present and specifies the media is not removable\r
200 //\r
201 return IMAGE_FROM_FIXED_MEDIA;\r
202 }\r
203 }\r
204 }\r
205 }\r
206\r
207 //\r
208 // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r
209 // the device path supports the Simple File System Protocol.\r
210 //\r
211 DeviceHandle = NULL;\r
212 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
213 Status = gBS->LocateDevicePath (\r
214 &gEfiSimpleFileSystemProtocolGuid,\r
215 &TempDevicePath,\r
216 &DeviceHandle\r
217 );\r
218 if (!EFI_ERROR (Status)) {\r
219 //\r
220 // Simple File System is present without Block I/O, so assume media is fixed.\r
221 //\r
222 return IMAGE_FROM_FIXED_MEDIA;\r
223 }\r
224\r
225 //\r
226 // File is not from an FV, Block I/O or Simple File System, so the only options\r
227 // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r
228 //\r
229 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
230 while (!IsDevicePathEndType (TempDevicePath)) {\r
231 switch (DevicePathType (TempDevicePath)) {\r
232\r
233 case MEDIA_DEVICE_PATH:\r
234 if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
235 return IMAGE_FROM_OPTION_ROM;\r
236 }\r
237 break;\r
238\r
239 case MESSAGING_DEVICE_PATH:\r
240 if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
241 return IMAGE_FROM_REMOVABLE_MEDIA;\r
242 }\r
243 break;\r
244\r
245 default:\r
246 break;\r
247 }\r
248 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
249 }\r
250 return IMAGE_UNKNOWN;\r
251}\r
252\r
253/**\r
254 Caculate hash of Pe/Coff image based on the authenticode image hashing in\r
255 PE/COFF Specification 8.0 Appendix A\r
256\r
257 Caution: This function may receive untrusted input.\r
258 PE/COFF image is external input, so this function will validate its data structure\r
259 within this image buffer before use.\r
260\r
261 @param[in] HashAlg Hash algorithm type.\r
262\r
263 @retval TRUE Successfully hash image.\r
264 @retval FALSE Fail in hash image.\r
265\r
266**/\r
267BOOLEAN\r
268HashPeImage (\r
269 IN UINT32 HashAlg\r
270 )\r
271{\r
272 BOOLEAN Status;\r
273 UINT16 Magic;\r
274 EFI_IMAGE_SECTION_HEADER *Section;\r
275 VOID *HashCtx;\r
276 UINTN CtxSize;\r
277 UINT8 *HashBase;\r
278 UINTN HashSize;\r
279 UINTN SumOfBytesHashed;\r
280 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
281 UINTN Index;\r
282 UINTN Pos;\r
283 UINT32 CertSize;\r
284 UINT32 NumberOfRvaAndSizes;\r
285\r
286 HashCtx = NULL;\r
287 SectionHeader = NULL;\r
288 Status = FALSE;\r
289\r
290 if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {\r
291 return FALSE;\r
292 }\r
293\r
294 //\r
295 // Initialize context of hash.\r
296 //\r
297 ZeroMem (mImageDigest, MAX_DIGEST_SIZE);\r
298\r
299 if (HashAlg == HASHALG_SHA1) {\r
300 mImageDigestSize = SHA1_DIGEST_SIZE;\r
301 mCertType = gEfiCertSha1Guid;\r
302 } else if (HashAlg == HASHALG_SHA256) {\r
303 mImageDigestSize = SHA256_DIGEST_SIZE;\r
304 mCertType = gEfiCertSha256Guid;\r
305 } else {\r
306 return FALSE;\r
307 }\r
308\r
309 CtxSize = mHash[HashAlg].GetContextSize();\r
310\r
311 HashCtx = AllocatePool (CtxSize);\r
312 if (HashCtx == NULL) {\r
313 return FALSE;\r
314 }\r
315\r
316 // 1. Load the image header into memory.\r
317\r
318 // 2. Initialize a SHA hash context.\r
319 Status = mHash[HashAlg].HashInit(HashCtx);\r
320\r
321 if (!Status) {\r
322 goto Done;\r
323 }\r
324\r
325 //\r
326 // Measuring PE/COFF Image Header;\r
327 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
328 //\r
329 if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
330 //\r
331 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
332 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
333 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
334 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
335 //\r
336 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
337 } else {\r
338 //\r
339 // Get the magic value from the PE/COFF Optional Header\r
340 //\r
341 Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
342 }\r
343 \r
344 //\r
345 // 3. Calculate the distance from the base of the image header to the image checksum address.\r
346 // 4. Hash the image header from its base to beginning of the image checksum.\r
347 //\r
348 HashBase = mImageBase;\r
349 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
350 //\r
351 // Use PE32 offset.\r
352 //\r
353 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);\r
354 NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
355 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
356 //\r
357 // Use PE32+ offset.\r
358 //\r
359 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
360 NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
361 } else {\r
362 //\r
363 // Invalid header magic number.\r
364 //\r
365 Status = FALSE;\r
366 goto Done;\r
367 }\r
368\r
369 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
370 if (!Status) {\r
371 goto Done;\r
372 }\r
373\r
374 //\r
375 // 5. Skip over the image checksum (it occupies a single ULONG).\r
376 //\r
377 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
378 //\r
379 // 6. Since there is no Cert Directory in optional header, hash everything\r
380 // from the end of the checksum to the end of image header.\r
381 //\r
382 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
383 //\r
384 // Use PE32 offset.\r
385 //\r
386 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
387 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
388 } else {\r
389 //\r
390 // Use PE32+ offset.\r
391 //\r
392 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
393 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
394 }\r
395\r
396 if (HashSize != 0) {\r
397 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
398 if (!Status) {\r
399 goto Done;\r
400 }\r
401 }\r
402 } else {\r
403 //\r
404 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
405 //\r
406 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
407 //\r
408 // Use PE32 offset.\r
409 //\r
410 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
411 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
412 } else {\r
413 //\r
414 // Use PE32+ offset.\r
415 //\r
416 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
417 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
418 }\r
419\r
420 if (HashSize != 0) {\r
421 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
422 if (!Status) {\r
423 goto Done;\r
424 }\r
425 }\r
426\r
427 //\r
428 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
429 // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
430 //\r
431 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
432 //\r
433 // Use PE32 offset\r
434 //\r
435 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
436 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
437 } else {\r
438 //\r
439 // Use PE32+ offset.\r
440 //\r
441 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
442 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);\r
443 }\r
444\r
445 if (HashSize != 0) {\r
446 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
447 if (!Status) {\r
448 goto Done;\r
449 }\r
450 } \r
451 }\r
452\r
453 //\r
454 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
455 //\r
456 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
457 //\r
458 // Use PE32 offset.\r
459 //\r
460 SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;\r
461 } else {\r
462 //\r
463 // Use PE32+ offset\r
464 //\r
465 SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
466 }\r
467\r
468\r
469 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
470 mImageBase +\r
471 mPeCoffHeaderOffset +\r
472 sizeof (UINT32) +\r
473 sizeof (EFI_IMAGE_FILE_HEADER) +\r
474 mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r
475 );\r
476\r
477 //\r
478 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
479 // structures in the image. The 'NumberOfSections' field of the image\r
480 // header indicates how big the table should be. Do not include any\r
481 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
482 //\r
483 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);\r
484 if (SectionHeader == NULL) {\r
485 Status = FALSE;\r
486 goto Done;\r
487 }\r
488 //\r
489 // 12. Using the 'PointerToRawData' in the referenced section headers as\r
490 // a key, arrange the elements in the table in ascending order. In other\r
491 // words, sort the section headers according to the disk-file offset of\r
492 // the section.\r
493 //\r
494 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
495 Pos = Index;\r
496 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
497 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));\r
498 Pos--;\r
499 }\r
500 CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));\r
501 Section += 1;\r
502 }\r
503\r
504 //\r
505 // 13. Walk through the sorted table, bring the corresponding section\r
506 // into memory, and hash the entire section (using the 'SizeOfRawData'\r
507 // field in the section header to determine the amount of data to hash).\r
508 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
509 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r
510 //\r
511 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
512 Section = &SectionHeader[Index];\r
513 if (Section->SizeOfRawData == 0) {\r
514 continue;\r
515 }\r
516 HashBase = mImageBase + Section->PointerToRawData;\r
517 HashSize = (UINTN) Section->SizeOfRawData;\r
518\r
519 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
520 if (!Status) {\r
521 goto Done;\r
522 }\r
523\r
524 SumOfBytesHashed += HashSize;\r
525 }\r
526\r
527 //\r
528 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
529 // data in the file that needs to be added to the hash. This data begins\r
530 // at file offset SUM_OF_BYTES_HASHED and its length is:\r
531 // FileSize - (CertDirectory->Size)\r
532 //\r
533 if (mImageSize > SumOfBytesHashed) {\r
534 HashBase = mImageBase + SumOfBytesHashed;\r
535\r
536 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
537 CertSize = 0;\r
538 } else {\r
539 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
540 //\r
541 // Use PE32 offset.\r
542 //\r
543 CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
544 } else {\r
545 //\r
546 // Use PE32+ offset.\r
547 //\r
548 CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
549 }\r
550 }\r
551\r
552 if (mImageSize > CertSize + SumOfBytesHashed) {\r
553 HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed);\r
554\r
555 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
556 if (!Status) {\r
557 goto Done;\r
558 }\r
559 } else if (mImageSize < CertSize + SumOfBytesHashed) {\r
560 Status = FALSE;\r
561 goto Done;\r
562 }\r
563 }\r
564\r
565 Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
566\r
567Done:\r
568 if (HashCtx != NULL) {\r
569 FreePool (HashCtx);\r
570 }\r
571 if (SectionHeader != NULL) {\r
572 FreePool (SectionHeader);\r
573 }\r
574 return Status;\r
575}\r
576\r
577/**\r
578 Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of\r
579 Pe/Coff image based on the authenticode image hashing in PE/COFF Specification\r
580 8.0 Appendix A\r
581\r
582 Caution: This function may receive untrusted input.\r
583 PE/COFF image is external input, so this function will validate its data structure\r
584 within this image buffer before use.\r
585\r
586 @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.\r
587 @param[in] AuthDataSize Size of the Authenticode Signature in bytes.\r
588 \r
589 @retval EFI_UNSUPPORTED Hash algorithm is not supported.\r
590 @retval EFI_SUCCESS Hash successfully.\r
591\r
592**/\r
593EFI_STATUS\r
594HashPeImageByType (\r
595 IN UINT8 *AuthData,\r
596 IN UINTN AuthDataSize\r
597 )\r
598{\r
599 UINT8 Index;\r
600\r
601 for (Index = 0; Index < HASHALG_MAX; Index++) {\r
602 //\r
603 // Check the Hash algorithm in PE/COFF Authenticode.\r
604 // According to PKCS#7 Definition:\r
605 // SignedData ::= SEQUENCE {\r
606 // version Version,\r
607 // digestAlgorithms DigestAlgorithmIdentifiers,\r
608 // contentInfo ContentInfo,\r
609 // .... }\r
610 // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r
611 // This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
612 // Fixed offset (+32) is calculated based on two bytes of length encoding.\r
613 //\r
614 if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
615 //\r
616 // Only support two bytes of Long Form of Length Encoding.\r
617 //\r
618 continue;\r
619 }\r
620\r
621 if (AuthDataSize < 32 + mHash[Index].OidLength) {\r
622 return EFI_UNSUPPORTED;\r
623 }\r
624\r
625 if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
626 break;\r
627 }\r
628 }\r
629\r
630 if (Index == HASHALG_MAX) {\r
631 return EFI_UNSUPPORTED;\r
632 }\r
633\r
634 //\r
635 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.\r
636 //\r
637 if (!HashPeImage(Index)) {\r
638 return EFI_UNSUPPORTED;\r
639 }\r
640\r
641 return EFI_SUCCESS;\r
642}\r
643\r
644\r
645/**\r
646 Returns the size of a given image execution info table in bytes.\r
647\r
648 This function returns the size, in bytes, of the image execution info table specified by\r
649 ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.\r
650\r
651 @param ImageExeInfoTable A pointer to a image execution info table structure.\r
652\r
653 @retval 0 If ImageExeInfoTable is NULL.\r
654 @retval Others The size of a image execution info table in bytes.\r
655\r
656**/\r
657UINTN\r
658GetImageExeInfoTableSize (\r
659 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable\r
660 )\r
661{\r
662 UINTN Index;\r
663 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem;\r
664 UINTN TotalSize;\r
665\r
666 if (ImageExeInfoTable == NULL) {\r
667 return 0;\r
668 }\r
669\r
670 ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE));\r
671 TotalSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
672 for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) {\r
673 TotalSize += ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize);\r
674 ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoItem + ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize));\r
675 }\r
676\r
677 return TotalSize;\r
678}\r
679\r
680/**\r
681 Create an Image Execution Information Table entry and add it to system configuration table.\r
682\r
683 @param[in] Action Describes the action taken by the firmware regarding this image.\r
684 @param[in] Name Input a null-terminated, user-friendly name.\r
685 @param[in] DevicePath Input device path pointer.\r
686 @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.\r
687 @param[in] SignatureSize Size of signature.\r
688\r
689**/\r
690VOID\r
691AddImageExeInfo (\r
692 IN EFI_IMAGE_EXECUTION_ACTION Action,\r
693 IN CHAR16 *Name OPTIONAL,\r
694 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
695 IN EFI_SIGNATURE_LIST *Signature OPTIONAL,\r
696 IN UINTN SignatureSize\r
697 )\r
698{\r
699 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;\r
700 EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable;\r
701 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry;\r
702 UINTN ImageExeInfoTableSize;\r
703 UINTN NewImageExeInfoEntrySize;\r
704 UINTN NameStringLen;\r
705 UINTN DevicePathSize;\r
706\r
707 ImageExeInfoTable = NULL;\r
708 NewImageExeInfoTable = NULL;\r
709 ImageExeInfoEntry = NULL;\r
710 NameStringLen = 0;\r
711\r
712 if (DevicePath == NULL) {\r
713 return ;\r
714 }\r
715\r
716 if (Name != NULL) {\r
717 NameStringLen = StrSize (Name);\r
718 } else {\r
719 NameStringLen = sizeof (CHAR16);\r
720 }\r
721\r
722 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
723 if (ImageExeInfoTable != NULL) {\r
724 //\r
725 // The table has been found!\r
726 // We must enlarge the table to accomodate the new exe info entry.\r
727 //\r
728 ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);\r
729 } else {\r
730 //\r
731 // Not Found!\r
732 // We should create a new table to append to the configuration table.\r
733 //\r
734 ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
735 }\r
736\r
737 DevicePathSize = GetDevicePathSize (DevicePath);\r
738 NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;\r
739 NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);\r
740 if (NewImageExeInfoTable == NULL) {\r
741 return ;\r
742 }\r
743\r
744 if (ImageExeInfoTable != NULL) {\r
745 CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);\r
746 } else {\r
747 NewImageExeInfoTable->NumberOfImages = 0;\r
748 }\r
749 NewImageExeInfoTable->NumberOfImages++;\r
750 ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);\r
751 //\r
752 // Update new item's infomation.\r
753 //\r
754 WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->Action, Action);\r
755 WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->InfoSize, (UINT32) NewImageExeInfoEntrySize);\r
756\r
757 if (Name != NULL) {\r
758 CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen);\r
759 } else {\r
760 ZeroMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), sizeof (CHAR16));\r
761 }\r
762 CopyMem (\r
763 (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen,\r
764 DevicePath,\r
765 DevicePathSize\r
766 );\r
767 if (Signature != NULL) {\r
768 CopyMem (\r
769 (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize,\r
770 Signature,\r
771 SignatureSize\r
772 );\r
773 }\r
774 //\r
775 // Update/replace the image execution table.\r
776 //\r
777 gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);\r
778\r
779 //\r
780 // Free Old table data!\r
781 //\r
782 if (ImageExeInfoTable != NULL) {\r
783 FreePool (ImageExeInfoTable);\r
784 }\r
785}\r
786\r
787/**\r
788 Check whether signature is in specified database.\r
789\r
790 @param[in] VariableName Name of database variable that is searched in.\r
791 @param[in] Signature Pointer to signature that is searched for.\r
792 @param[in] CertType Pointer to hash algrithom.\r
793 @param[in] SignatureSize Size of Signature.\r
794\r
795 @return TRUE Found the signature in the variable database.\r
796 @return FALSE Not found the signature in the variable database.\r
797\r
798**/\r
799BOOLEAN\r
800IsSignatureFoundInDatabase (\r
801 IN CHAR16 *VariableName,\r
802 IN UINT8 *Signature,\r
803 IN EFI_GUID *CertType,\r
804 IN UINTN SignatureSize\r
805 )\r
806{\r
807 EFI_STATUS Status;\r
808 EFI_SIGNATURE_LIST *CertList;\r
809 EFI_SIGNATURE_DATA *Cert;\r
810 UINTN DataSize;\r
811 UINT8 *Data;\r
812 UINTN Index;\r
813 UINTN CertCount;\r
814 BOOLEAN IsFound;\r
815 //\r
816 // Read signature database variable.\r
817 //\r
818 IsFound = FALSE;\r
819 Data = NULL;\r
820 DataSize = 0;\r
821 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
822 if (Status != EFI_BUFFER_TOO_SMALL) {\r
823 return FALSE;\r
824 }\r
825\r
826 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
827 if (Data == NULL) {\r
828 return FALSE;\r
829 }\r
830\r
831 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
832 if (EFI_ERROR (Status)) {\r
833 goto Done;\r
834 }\r
835 //\r
836 // Enumerate all signature data in SigDB to check if executable's signature exists.\r
837 //\r
838 CertList = (EFI_SIGNATURE_LIST *) Data;\r
839 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
840 CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
841 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
842 if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {\r
843 for (Index = 0; Index < CertCount; Index++) {\r
844 if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {\r
845 //\r
846 // Find the signature in database.\r
847 //\r
848 IsFound = TRUE;\r
849 break;\r
850 }\r
851\r
852 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
853 }\r
854\r
855 if (IsFound) {\r
856 break;\r
857 }\r
858 }\r
859\r
860 DataSize -= CertList->SignatureListSize;\r
861 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
862 }\r
863\r
864Done:\r
865 if (Data != NULL) {\r
866 FreePool (Data);\r
867 }\r
868\r
869 return IsFound;\r
870}\r
871\r
872/**\r
873 Verify PKCS#7 SignedData using certificate found in Variable which formatted\r
874 as EFI_SIGNATURE_LIST. The Variable may be PK, KEK, DB or DBX.\r
875\r
876 @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.\r
877 @param[in] AuthDataSize Size of the Authenticode Signature in bytes.\r
878 @param[in] VariableName Name of Variable to search for Certificate.\r
879 @param[in] VendorGuid Variable vendor GUID.\r
880\r
881 @retval TRUE Image pass verification.\r
882 @retval FALSE Image fail verification.\r
883\r
884**/\r
885BOOLEAN\r
886IsPkcsSignedDataVerifiedBySignatureList (\r
887 IN UINT8 *AuthData,\r
888 IN UINTN AuthDataSize,\r
889 IN CHAR16 *VariableName,\r
890 IN EFI_GUID *VendorGuid\r
891 )\r
892{\r
893 EFI_STATUS Status;\r
894 BOOLEAN VerifyStatus;\r
895 EFI_SIGNATURE_LIST *CertList;\r
896 EFI_SIGNATURE_DATA *Cert;\r
897 UINTN DataSize;\r
898 UINT8 *Data;\r
899 UINT8 *RootCert;\r
900 UINTN RootCertSize;\r
901 UINTN Index;\r
902 UINTN CertCount;\r
903\r
904 Data = NULL;\r
905 CertList = NULL;\r
906 Cert = NULL;\r
907 RootCert = NULL;\r
908 RootCertSize = 0;\r
909 VerifyStatus = FALSE;\r
910\r
911 DataSize = 0;\r
912 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);\r
913 if (Status == EFI_BUFFER_TOO_SMALL) {\r
914 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
915 if (Data == NULL) {\r
916 return VerifyStatus;\r
917 }\r
918\r
919 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, (VOID *) Data);\r
920 if (EFI_ERROR (Status)) {\r
921 goto Done;\r
922 }\r
923\r
924 //\r
925 // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.\r
926 //\r
927 CertList = (EFI_SIGNATURE_LIST *) Data;\r
928 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
929 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
930 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
931 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
932 for (Index = 0; Index < CertCount; Index++) {\r
933 //\r
934 // Iterate each Signature Data Node within this CertList for verify.\r
935 //\r
936 RootCert = Cert->SignatureData;\r
937 RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
938\r
939 //\r
940 // Call AuthenticodeVerify library to Verify Authenticode struct.\r
941 //\r
942 VerifyStatus = AuthenticodeVerify (\r
943 AuthData,\r
944 AuthDataSize,\r
945 RootCert,\r
946 RootCertSize,\r
947 mImageDigest,\r
948 mImageDigestSize\r
949 );\r
950 if (VerifyStatus) {\r
951 goto Done;\r
952 }\r
953 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
954 }\r
955 }\r
956 DataSize -= CertList->SignatureListSize;\r
957 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
958 }\r
959 }\r
960\r
961Done:\r
962 if (Data != NULL) {\r
963 FreePool (Data);\r
964 }\r
965\r
966 return VerifyStatus;\r
967}\r
968\r
969/**\r
970 Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format.\r
971\r
972 @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.\r
973 @param[in] AuthDataSize Size of the Authenticode Signature in bytes.\r
974\r
975 @retval EFI_SUCCESS Image pass verification.\r
976 @retval EFI_SECURITY_VIOLATION Image fail verification.\r
977\r
978**/\r
979EFI_STATUS\r
980VerifyCertPkcsSignedData (\r
981 IN UINT8 *AuthData,\r
982 IN UINTN AuthDataSize\r
983 )\r
984{\r
985 //\r
986 // 1: Find certificate from DBX forbidden database for revoked certificate.\r
987 //\r
988 if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {\r
989 //\r
990 // DBX is forbidden database, if Authenticode verification pass with\r
991 // one of the certificate in DBX, this image should be rejected.\r
992 //\r
993 return EFI_SECURITY_VIOLATION;\r
994 }\r
995\r
996 //\r
997 // 2: Find certificate from DB database and try to verify authenticode struct.\r
998 //\r
999 if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {\r
1000 return EFI_SUCCESS;\r
1001 } else {\r
1002 return EFI_SECURITY_VIOLATION;\r
1003 }\r
1004}\r
1005\r
1006/**\r
1007 Provide verification service for signed images, which include both signature validation\r
1008 and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and\r
1009 MSFT Authenticode type signatures are supported.\r
1010\r
1011 In this implementation, only verify external executables when in USER MODE.\r
1012 Executables from FV is bypass, so pass in AuthenticationStatus is ignored.\r
1013\r
1014 The image verification process is:\r
1015 If the image is signed,\r
1016 If the image's certificate verifies against a certificate (root or intermediate) in the allowed \r
1017 database (DB) and not in the forbidden database (DBX), the certificate verification is passed.\r
1018 If the image's hash digest is in DBX,\r
1019 deny execution.\r
1020 If not,\r
1021 run it.\r
1022 If the Image's certificate verification failed.\r
1023 If the Image's Hash is in DB and not in DBX,\r
1024 run it.\r
1025 Otherwise,\r
1026 deny execution.\r
1027 Otherwise, the image is not signed,\r
1028 Is the Image's Hash in DBX?\r
1029 If yes, deny execution.\r
1030 If not, is the Image's Hash in DB?\r
1031 If yes, run it.\r
1032 If not, deny execution.\r
1033\r
1034 Caution: This function may receive untrusted input.\r
1035 PE/COFF image is external input, so this function will validate its data structure\r
1036 within this image buffer before use.\r
1037\r
1038 @param[in] AuthenticationStatus\r
1039 This is the authentication status returned from the security\r
1040 measurement services for the input file.\r
1041 @param[in] File This is a pointer to the device path of the file that is\r
1042 being dispatched. This will optionally be used for logging.\r
1043 @param[in] FileBuffer File buffer matches the input file device path.\r
1044 @param[in] FileSize Size of File buffer matches the input file device path.\r
1045 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
1046\r
1047 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
1048 FileBuffer did authenticate, and the platform policy dictates\r
1049 that the DXE Foundation may use the file.\r
1050 @retval EFI_SUCCESS The device path specified by NULL device path DevicePath\r
1051 and non-NULL FileBuffer did authenticate, and the platform\r
1052 policy dictates that the DXE Foundation may execute the image in\r
1053 FileBuffer.\r
1054 @retval EFI_OUT_RESOURCE Fail to allocate memory.\r
1055 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
1056 the platform policy dictates that File should be placed\r
1057 in the untrusted state. The image has been added to the file\r
1058 execution table.\r
1059 @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r
1060 authenticate, and the platform policy dictates that the DXE\r
1061 Foundation many not use File.\r
1062\r
1063**/\r
1064EFI_STATUS\r
1065EFIAPI\r
1066DxeImageVerificationHandler (\r
1067 IN UINT32 AuthenticationStatus,\r
1068 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
1069 IN VOID *FileBuffer,\r
1070 IN UINTN FileSize,\r
1071 IN BOOLEAN BootPolicy\r
1072 )\r
1073{\r
1074 EFI_STATUS Status;\r
1075 UINT16 Magic;\r
1076 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1077 EFI_STATUS VerifyStatus;\r
1078 EFI_SIGNATURE_LIST *SignatureList;\r
1079 UINTN SignatureListSize;\r
1080 EFI_SIGNATURE_DATA *Signature;\r
1081 EFI_IMAGE_EXECUTION_ACTION Action;\r
1082 WIN_CERTIFICATE *WinCertificate;\r
1083 UINT32 Policy;\r
1084 UINT8 *SecureBoot;\r
1085 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
1086 UINT32 NumberOfRvaAndSizes;\r
1087 UINT32 CertSize;\r
1088 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
1089 WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;\r
1090 UINT8 *AuthData;\r
1091 UINTN AuthDataSize;\r
1092 EFI_IMAGE_DATA_DIRECTORY *SecDataDir;\r
1093\r
1094 SignatureList = NULL;\r
1095 SignatureListSize = 0;\r
1096 WinCertificate = NULL;\r
1097 SecDataDir = NULL;\r
1098 PkcsCertData = NULL;\r
1099 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
1100 Status = EFI_ACCESS_DENIED;\r
1101 //\r
1102 // Check the image type and get policy setting.\r
1103 //\r
1104 switch (GetImageType (File)) {\r
1105\r
1106 case IMAGE_FROM_FV:\r
1107 Policy = ALWAYS_EXECUTE;\r
1108 break;\r
1109\r
1110 case IMAGE_FROM_OPTION_ROM:\r
1111 Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);\r
1112 break;\r
1113\r
1114 case IMAGE_FROM_REMOVABLE_MEDIA:\r
1115 Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);\r
1116 break;\r
1117\r
1118 case IMAGE_FROM_FIXED_MEDIA:\r
1119 Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);\r
1120 break;\r
1121\r
1122 default:\r
1123 Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;\r
1124 break;\r
1125 }\r
1126 //\r
1127 // If policy is always/never execute, return directly.\r
1128 //\r
1129 if (Policy == ALWAYS_EXECUTE) {\r
1130 return EFI_SUCCESS;\r
1131 } else if (Policy == NEVER_EXECUTE) {\r
1132 return EFI_ACCESS_DENIED;\r
1133 }\r
1134\r
1135 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
1136 //\r
1137 // Skip verification if SecureBoot variable doesn't exist.\r
1138 //\r
1139 if (SecureBoot == NULL) {\r
1140 return EFI_SUCCESS;\r
1141 }\r
1142\r
1143 //\r
1144 // Skip verification if SecureBoot is disabled.\r
1145 //\r
1146 if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
1147 FreePool (SecureBoot);\r
1148 return EFI_SUCCESS;\r
1149 }\r
1150 FreePool (SecureBoot);\r
1151\r
1152 //\r
1153 // Read the Dos header.\r
1154 //\r
1155 if (FileBuffer == NULL) {\r
1156 return EFI_INVALID_PARAMETER;\r
1157 }\r
1158\r
1159 mImageBase = (UINT8 *) FileBuffer;\r
1160 mImageSize = FileSize;\r
1161\r
1162 ZeroMem (&ImageContext, sizeof (ImageContext));\r
1163 ImageContext.Handle = (VOID *) FileBuffer;\r
1164 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;\r
1165\r
1166 //\r
1167 // Get information about the image being loaded\r
1168 //\r
1169 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
1170 if (EFI_ERROR (Status)) {\r
1171 //\r
1172 // The information can't be got from the invalid PeImage\r
1173 //\r
1174 goto Done;\r
1175 }\r
1176\r
1177 Status = EFI_ACCESS_DENIED;\r
1178\r
1179 DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;\r
1180 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1181 //\r
1182 // DOS image header is present,\r
1183 // so read the PE header after the DOS image header.\r
1184 //\r
1185 mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
1186 } else {\r
1187 mPeCoffHeaderOffset = 0;\r
1188 }\r
1189 //\r
1190 // Check PE/COFF image.\r
1191 //\r
1192 mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);\r
1193 if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1194 //\r
1195 // It is not a valid Pe/Coff file.\r
1196 //\r
1197 goto Done;\r
1198 }\r
1199\r
1200 if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1201 //\r
1202 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
1203 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
1204 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
1205 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
1206 //\r
1207 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1208 } else {\r
1209 //\r
1210 // Get the magic value from the PE/COFF Optional Header\r
1211 //\r
1212 Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
1213 }\r
1214 \r
1215 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1216 //\r
1217 // Use PE32 offset.\r
1218 //\r
1219 NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1220 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
1221 SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
1222 } \r
1223 } else {\r
1224 //\r
1225 // Use PE32+ offset.\r
1226 //\r
1227 NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1228 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
1229 SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
1230 }\r
1231 }\r
1232\r
1233 if ((SecDataDir == NULL) || ((SecDataDir != NULL) && (SecDataDir->Size == 0))) {\r
1234 //\r
1235 // This image is not signed.\r
1236 //\r
1237 if (!HashPeImage (HASHALG_SHA256)) {\r
1238 goto Done;\r
1239 }\r
1240\r
1241 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1242 //\r
1243 // Image Hash is in forbidden database (DBX).\r
1244 //\r
1245 goto Done;\r
1246 }\r
1247\r
1248 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
1249 //\r
1250 // Image Hash is in allowed database (DB).\r
1251 //\r
1252 return EFI_SUCCESS;\r
1253 }\r
1254\r
1255 //\r
1256 // Image Hash is not found in both forbidden and allowed database.\r
1257 //\r
1258 goto Done;\r
1259 }\r
1260\r
1261 //\r
1262 // Verify signature of executables.\r
1263 //\r
1264 WinCertificate = (WIN_CERTIFICATE *) (mImageBase + SecDataDir->VirtualAddress);\r
1265\r
1266 CertSize = sizeof (WIN_CERTIFICATE);\r
1267\r
1268 if ((SecDataDir->Size <= CertSize) || (SecDataDir->Size < WinCertificate->dwLength)) {\r
1269 goto Done;\r
1270 }\r
1271\r
1272 //\r
1273 // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.\r
1274 //\r
1275 if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
1276 //\r
1277 // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the \r
1278 // Authenticode specification.\r
1279 //\r
1280 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;\r
1281 if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {\r
1282 goto Done;\r
1283 }\r
1284 AuthData = PkcsCertData->CertData;\r
1285 AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);\r
1286 \r
1287 Status = HashPeImageByType (AuthData, AuthDataSize);\r
1288 if (EFI_ERROR (Status)) {\r
1289 goto Done;\r
1290 }\r
1291\r
1292 VerifyStatus = VerifyCertPkcsSignedData (AuthData, AuthDataSize);\r
1293 } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
1294 //\r
1295 // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.\r
1296 //\r
1297 WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;\r
1298 if (!CompareGuid(&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid) ||\r
1299 (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData))) {\r
1300 goto Done;\r
1301 }\r
1302 AuthData = WinCertUefiGuid->CertData;\r
1303 AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);\r
1304 \r
1305 Status = HashPeImageByType (AuthData, AuthDataSize);\r
1306 if (EFI_ERROR (Status)) {\r
1307 goto Done;\r
1308 }\r
1309 VerifyStatus = VerifyCertPkcsSignedData (AuthData, AuthDataSize);\r
1310 } else {\r
1311 goto Done;\r
1312 }\r
1313\r
1314 if (!EFI_ERROR (VerifyStatus)) {\r
1315 //\r
1316 // Verification is passed.\r
1317 // Continue to check the image digest in signature database.\r
1318 //\r
1319 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1320 //\r
1321 // Executable signature verification passes, but is found in forbidden signature database.\r
1322 //\r
1323 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
1324 Status = EFI_ACCESS_DENIED;\r
1325 } else {\r
1326 //\r
1327 // For image verification against enrolled X.509 certificate(root or intermediate),\r
1328 // no need to check image's hash in the allowed database.\r
1329 //\r
1330 return EFI_SUCCESS;\r
1331 }\r
1332 } else {\r
1333 //\r
1334 // Verification failure.\r
1335 //\r
1336 if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize) &&\r
1337 IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
1338 //\r
1339 // Verification fail, Image Hash is not in forbidden database (DBX),\r
1340 // and Image Hash is in allowed database (DB).\r
1341 //\r
1342 Status = EFI_SUCCESS;\r
1343 } else {\r
1344 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
1345 Status = EFI_ACCESS_DENIED;\r
1346 }\r
1347 }\r
1348\r
1349 if (EFI_ERROR (Status)) {\r
1350 //\r
1351 // Get image hash value as executable's signature.\r
1352 //\r
1353 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
1354 SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
1355 if (SignatureList == NULL) {\r
1356 Status = EFI_OUT_OF_RESOURCES;\r
1357 goto Done;\r
1358 }\r
1359 SignatureList->SignatureHeaderSize = 0;\r
1360 SignatureList->SignatureListSize = (UINT32) SignatureListSize;\r
1361 SignatureList->SignatureSize = (UINT32) mImageDigestSize;\r
1362 CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
1363 Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
1364 CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
1365 }\r
1366\r
1367Done:\r
1368 if (Status != EFI_SUCCESS) {\r
1369 //\r
1370 // Policy decides to defer or reject the image; add its information in image executable information table.\r
1371 //\r
1372 AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);\r
1373 Status = EFI_SECURITY_VIOLATION;\r
1374 }\r
1375\r
1376 if (SignatureList != NULL) {\r
1377 FreePool (SignatureList);\r
1378 }\r
1379\r
1380 return Status;\r
1381}\r
1382\r
1383/**\r
1384 When VariableWriteArchProtocol install, create "SecureBoot" variable.\r
1385\r
1386 @param[in] Event Event whose notification function is being invoked.\r
1387 @param[in] Context Pointer to the notification function's context.\r
1388\r
1389**/\r
1390VOID\r
1391EFIAPI\r
1392VariableWriteCallBack (\r
1393 IN EFI_EVENT Event,\r
1394 IN VOID *Context\r
1395 )\r
1396{\r
1397 UINT8 SecureBootMode;\r
1398 UINT8 *SecureBootModePtr;\r
1399 EFI_STATUS Status;\r
1400 VOID *ProtocolPointer;\r
1401\r
1402 Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, &ProtocolPointer);\r
1403 if (EFI_ERROR (Status)) {\r
1404 return;\r
1405 }\r
1406\r
1407 //\r
1408 // Check whether "SecureBoot" variable exists.\r
1409 // If this library is built-in, it means firmware has capability to perform\r
1410 // driver signing verification.\r
1411 //\r
1412 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBootModePtr, NULL);\r
1413 if (SecureBootModePtr == NULL) {\r
1414 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
1415 //\r
1416 // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable.\r
1417 //\r
1418 gRT->SetVariable (\r
1419 EFI_SECURE_BOOT_MODE_NAME,\r
1420 &gEfiGlobalVariableGuid,\r
1421 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1422 sizeof (UINT8),\r
1423 &SecureBootMode\r
1424 );\r
1425 } else {\r
1426 FreePool (SecureBootModePtr);\r
1427 }\r
1428}\r
1429\r
1430/**\r
1431 Register security measurement handler.\r
1432\r
1433 @param ImageHandle ImageHandle of the loaded driver.\r
1434 @param SystemTable Pointer to the EFI System Table.\r
1435\r
1436 @retval EFI_SUCCESS The handlers were registered successfully.\r
1437**/\r
1438EFI_STATUS\r
1439EFIAPI\r
1440DxeImageVerificationLibConstructor (\r
1441 IN EFI_HANDLE ImageHandle,\r
1442 IN EFI_SYSTEM_TABLE *SystemTable\r
1443 )\r
1444{\r
1445 VOID *Registration;\r
1446\r
1447 //\r
1448 // Register callback function upon VariableWriteArchProtocol.\r
1449 //\r
1450 EfiCreateProtocolNotifyEvent (\r
1451 &gEfiVariableWriteArchProtocolGuid,\r
1452 TPL_CALLBACK,\r
1453 VariableWriteCallBack,\r
1454 NULL,\r
1455 &Registration\r
1456 );\r
1457\r
1458 return RegisterSecurity2Handler (\r
1459 DxeImageVerificationHandler,\r
1460 EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
1461 );\r
1462}\r