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