]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
SCR_EL3 is the control register for setting the security state
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
CommitLineData
0c18794e 1/** @file\r
2 Implement image verification services for secure boot service in UEFI2.3.1.\r
3\r
dc204d5a
JY
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
6de4c35f 15Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>\r
45bf2c47 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
0c18794e 19http://opensource.org/licenses/bsd-license.php\r
20\r
45bf2c47 21THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
0c18794e 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
dc204d5a
JY
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
0c18794e 32EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
45bf2c47 33UINT32 mPeCoffHeaderOffset;\r
0c18794e 34EFI_GUID mCertType;\r
35\r
dc204d5a
JY
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
0c18794e 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
0c18794e 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
64470c17 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
0c18794e 72};\r
73\r
28186d45
ED
74/**\r
75 Reads contents of a PE/COFF image in memory buffer.\r
76\r
dc204d5a
JY
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
28186d45
ED
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
e0192326 91DxeImageVerificationLibImageRead (\r
28186d45
ED
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
0c18794e 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
45bf2c47 127 being dispatched.\r
0c18794e 128\r
45bf2c47 129 @return UINT32 Image Type\r
0c18794e 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
45bf2c47 138 EFI_HANDLE DeviceHandle;\r
0c18794e 139 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
140 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
141\r
5db28a67
LG
142 if (File == NULL) {\r
143 return IMAGE_UNKNOWN;\r
144 }\r
145\r
0c18794e 146 //\r
147 // First check to see if File is from a Firmware Volume\r
148 //\r
149 DeviceHandle = NULL;\r
45bf2c47 150 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 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
45bf2c47 174 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 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
45bf2c47 208 // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r
0c18794e 209 // the device path supports the Simple File System Protocol.\r
210 //\r
211 DeviceHandle = NULL;\r
45bf2c47 212 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 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
45bf2c47 227 // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r
0c18794e 228 //\r
45bf2c47 229 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 230 while (!IsDevicePathEndType (TempDevicePath)) {\r
231 switch (DevicePathType (TempDevicePath)) {\r
45bf2c47 232\r
0c18794e 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
45bf2c47 242 }\r
0c18794e 243 break;\r
244\r
245 default:\r
246 break;\r
247 }\r
248 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
249 }\r
45bf2c47 250 return IMAGE_UNKNOWN;\r
0c18794e 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
dc204d5a
JY
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
0c18794e 261 @param[in] HashAlg Hash algorithm type.\r
45bf2c47 262\r
0c18794e 263 @retval TRUE Successfully hash image.\r
264 @retval FALSE Fail in hash image.\r
265\r
266**/\r
45bf2c47 267BOOLEAN\r
0c18794e 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
551d8081 283 UINT32 CertSize;\r
284 UINT32 NumberOfRvaAndSizes;\r
45bf2c47 285\r
0c18794e 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
45bf2c47 293\r
0c18794e 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
45bf2c47 310\r
0c18794e 311 HashCtx = AllocatePool (CtxSize);\r
570b3d1a 312 if (HashCtx == NULL) {\r
313 return FALSE;\r
314 }\r
0c18794e 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
45bf2c47 320\r
0c18794e 321 if (!Status) {\r
322 goto Done;\r
323 }\r
551d8081 324\r
0c18794e 325 //\r
326 // Measuring PE/COFF Image Header;\r
327 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
328 //\r
de2447dd 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
0c18794e 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
551d8081 354 NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
570b3d1a 355 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
0c18794e 356 //\r
357 // Use PE32+ offset.\r
358 //\r
359 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
551d8081 360 NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
570b3d1a 361 } else {\r
362 //\r
363 // Invalid header magic number.\r
364 //\r
365 Status = FALSE;\r
366 goto Done;\r
0c18794e 367 }\r
368\r
369 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
370 if (!Status) {\r
371 goto Done;\r
372 }\r
551d8081 373\r
0c18794e 374 //\r
375 // 5. Skip over the image checksum (it occupies a single ULONG).\r
0c18794e 376 //\r
551d8081 377 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
0c18794e 378 //\r
551d8081 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
0c18794e 381 //\r
551d8081 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
0c18794e 402 } else {\r
403 //\r
551d8081 404 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
45bf2c47 405 //\r
551d8081 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
0c18794e 426\r
0c18794e 427 //\r
551d8081 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
0c18794e 430 //\r
551d8081 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
0c18794e 444\r
551d8081 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
0c18794e 451 }\r
551d8081 452\r
0c18794e 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
570b3d1a 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
0c18794e 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
570b3d1a 484 if (SectionHeader == NULL) {\r
485 Status = FALSE;\r
486 goto Done;\r
487 }\r
0c18794e 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
0c18794e 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
551d8081 535\r
536 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
537 CertSize = 0;\r
0c18794e 538 } else {\r
551d8081 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
28186d45 549 }\r
0c18794e 550 }\r
551\r
551d8081 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
0c18794e 561 goto Done;\r
562 }\r
563 }\r
551d8081 564\r
0c18794e 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
45bf2c47 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
0c18794e 580 8.0 Appendix A\r
581\r
dc204d5a
JY
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
f6f9031f 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
0c18794e 589 @retval EFI_UNSUPPORTED Hash algorithm is not supported.\r
590 @retval EFI_SUCCESS Hash successfully.\r
591\r
592**/\r
45bf2c47 593EFI_STATUS\r
0c18794e 594HashPeImageByType (\r
f6f9031f 595 IN UINT8 *AuthData,\r
596 IN UINTN AuthDataSize\r
0c18794e 597 )\r
598{\r
599 UINT8 Index;\r
badd40f9 600\r
45bf2c47 601 for (Index = 0; Index < HASHALG_MAX; Index++) {\r
0c18794e 602 //\r
603 // Check the Hash algorithm in PE/COFF Authenticode.\r
45bf2c47 604 // According to PKCS#7 Definition:\r
0c18794e 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
bd0de396 612 // Fixed offset (+32) is calculated based on two bytes of length encoding.\r
45bf2c47 613 //\r
f6f9031f 614 if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
bd0de396 615 //\r
616 // Only support two bytes of Long Form of Length Encoding.\r
617 //\r
618 continue;\r
619 }\r
620\r
f6f9031f 621 if (AuthDataSize < 32 + mHash[Index].OidLength) {\r
badd40f9 622 return EFI_UNSUPPORTED;\r
623 }\r
624\r
f6f9031f 625 if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
0c18794e 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
45bf2c47 652\r
0c18794e 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
45bf2c47 688\r
0c18794e 689**/\r
690VOID\r
691AddImageExeInfo (\r
45bf2c47 692 IN EFI_IMAGE_EXECUTION_ACTION Action,\r
693 IN CHAR16 *Name OPTIONAL,\r
0c18794e 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
0c18794e 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
0c18794e 707 ImageExeInfoTable = NULL;\r
708 NewImageExeInfoTable = NULL;\r
709 ImageExeInfoEntry = NULL;\r
710 NameStringLen = 0;\r
711\r
570b3d1a 712 if (DevicePath == NULL) {\r
713 return ;\r
714 }\r
45bf2c47 715\r
0c18794e 716 if (Name != NULL) {\r
717 NameStringLen = StrSize (Name);\r
b3d42170 718 } else {\r
719 NameStringLen = sizeof (CHAR16);\r
0c18794e 720 }\r
721\r
45bf2c47 722 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
0c18794e 723 if (ImageExeInfoTable != NULL) {\r
724 //\r
725 // The table has been found!\r
b3d42170 726 // We must enlarge the table to accomodate the new exe info entry.\r
0c18794e 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
570b3d1a 740 if (NewImageExeInfoTable == NULL) {\r
741 return ;\r
742 }\r
0c18794e 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
b3d42170 759 } else {\r
760 ZeroMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), sizeof (CHAR16));\r
0c18794e 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
570b3d1a 777 gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);\r
45bf2c47 778\r
0c18794e 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
0c18794e 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
45bf2c47 802 IN UINT8 *Signature,\r
0c18794e 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
570b3d1a 827 if (Data == NULL) {\r
828 return FALSE;\r
829 }\r
0c18794e 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
7403ff5b 840 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
0c18794e 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
45bf2c47 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
0c18794e 875\r
f6f9031f 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
45bf2c47 880\r
881 @retval TRUE Image pass verification.\r
882 @retval FALSE Image fail verification.\r
0c18794e 883\r
884**/\r
45bf2c47 885BOOLEAN\r
886IsPkcsSignedDataVerifiedBySignatureList (\r
f6f9031f 887 IN UINT8 *AuthData,\r
888 IN UINTN AuthDataSize,\r
45bf2c47 889 IN CHAR16 *VariableName,\r
890 IN EFI_GUID *VendorGuid\r
0c18794e 891 )\r
892{\r
893 EFI_STATUS Status;\r
894 BOOLEAN VerifyStatus;\r
0c18794e 895 EFI_SIGNATURE_LIST *CertList;\r
896 EFI_SIGNATURE_DATA *Cert;\r
897 UINTN DataSize;\r
45bf2c47 898 UINT8 *Data;\r
0c18794e 899 UINT8 *RootCert;\r
900 UINTN RootCertSize;\r
901 UINTN Index;\r
902 UINTN CertCount;\r
903\r
45bf2c47 904 Data = NULL;\r
905 CertList = NULL;\r
906 Cert = NULL;\r
907 RootCert = NULL;\r
908 RootCertSize = 0;\r
909 VerifyStatus = FALSE;\r
0c18794e 910\r
0c18794e 911 DataSize = 0;\r
45bf2c47 912 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);\r
0c18794e 913 if (Status == EFI_BUFFER_TOO_SMALL) {\r
45bf2c47 914 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
915 if (Data == NULL) {\r
916 return VerifyStatus;\r
570b3d1a 917 }\r
0c18794e 918\r
45bf2c47 919 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, (VOID *) Data);\r
0c18794e 920 if (EFI_ERROR (Status)) {\r
921 goto Done;\r
922 }\r
45bf2c47 923\r
924 //\r
925 // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.\r
0c18794e 926 //\r
45bf2c47 927 CertList = (EFI_SIGNATURE_LIST *) Data;\r
0c18794e 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
45bf2c47 934 // Iterate each Signature Data Node within this CertList for verify.\r
935 //\r
0c18794e 936 RootCert = Cert->SignatureData;\r
3277a4e5 937 RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
45bf2c47 938\r
0c18794e 939 //\r
45bf2c47 940 // Call AuthenticodeVerify library to Verify Authenticode struct.\r
0c18794e 941 //\r
942 VerifyStatus = AuthenticodeVerify (\r
f6f9031f 943 AuthData,\r
944 AuthDataSize,\r
0c18794e 945 RootCert,\r
946 RootCertSize,\r
947 mImageDigest,\r
948 mImageDigestSize\r
949 );\r
0c18794e 950 if (VerifyStatus) {\r
951 goto Done;\r
952 }\r
953 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
45bf2c47 954 }\r
0c18794e 955 }\r
956 DataSize -= CertList->SignatureListSize;\r
957 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
958 }\r
959 }\r
960\r
45bf2c47 961Done:\r
962 if (Data != NULL) {\r
963 FreePool (Data);\r
964 }\r
0c18794e 965\r
45bf2c47 966 return VerifyStatus;\r
967}\r
0c18794e 968\r
0c18794e 969/**\r
970 Provide verification service for signed images, which include both signature validation\r
45bf2c47 971 and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and\r
0c18794e 972 MSFT Authenticode type signatures are supported.\r
0c18794e 973\r
45bf2c47 974 In this implementation, only verify external executables when in USER MODE.\r
975 Executables from FV is bypass, so pass in AuthenticationStatus is ignored.\r
976\r
6de4c35f 977 The image verification policy is:\r
50fe73a1 978 If the image is signed,\r
6de4c35f 979 At least one valid signature or at least one hash value of the image must match a record\r
980 in the security database "db", and no valid signature nor any hash value of the image may\r
981 be reflected in the security database "dbx".\r
50fe73a1 982 Otherwise, the image is not signed,\r
6de4c35f 983 The SHA256 hash value of the image must match a record in the security database "db", and\r
984 not be reflected in the security data base "dbx".\r
45bf2c47 985\r
dc204d5a
JY
986 Caution: This function may receive untrusted input.\r
987 PE/COFF image is external input, so this function will validate its data structure\r
988 within this image buffer before use.\r
989\r
45bf2c47 990 @param[in] AuthenticationStatus\r
0c18794e 991 This is the authentication status returned from the security\r
992 measurement services for the input file.\r
993 @param[in] File This is a pointer to the device path of the file that is\r
994 being dispatched. This will optionally be used for logging.\r
995 @param[in] FileBuffer File buffer matches the input file device path.\r
996 @param[in] FileSize Size of File buffer matches the input file device path.\r
5db28a67
LG
997 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
998\r
999 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
1000 FileBuffer did authenticate, and the platform policy dictates\r
1001 that the DXE Foundation may use the file.\r
1002 @retval EFI_SUCCESS The device path specified by NULL device path DevicePath\r
1003 and non-NULL FileBuffer did authenticate, and the platform\r
1004 policy dictates that the DXE Foundation may execute the image in\r
1005 FileBuffer.\r
570b3d1a 1006 @retval EFI_OUT_RESOURCE Fail to allocate memory.\r
0c18794e 1007 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
1008 the platform policy dictates that File should be placed\r
5db28a67
LG
1009 in the untrusted state. The image has been added to the file\r
1010 execution table.\r
1011 @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r
1012 authenticate, and the platform policy dictates that the DXE\r
1013 Foundation many not use File.\r
0c18794e 1014\r
1015**/\r
1016EFI_STATUS\r
1017EFIAPI\r
1018DxeImageVerificationHandler (\r
1019 IN UINT32 AuthenticationStatus,\r
1020 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
1021 IN VOID *FileBuffer,\r
5db28a67
LG
1022 IN UINTN FileSize,\r
1023 IN BOOLEAN BootPolicy\r
0c18794e 1024 )\r
0c18794e 1025{\r
551d8081 1026 EFI_STATUS Status;\r
1027 UINT16 Magic;\r
1028 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1029 EFI_STATUS VerifyStatus;\r
551d8081 1030 EFI_SIGNATURE_LIST *SignatureList;\r
1031 UINTN SignatureListSize;\r
1032 EFI_SIGNATURE_DATA *Signature;\r
1033 EFI_IMAGE_EXECUTION_ACTION Action;\r
1034 WIN_CERTIFICATE *WinCertificate;\r
1035 UINT32 Policy;\r
8f8ca22e 1036 UINT8 *SecureBoot;\r
551d8081 1037 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
1038 UINT32 NumberOfRvaAndSizes;\r
f6f9031f 1039 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
1040 WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;\r
1041 UINT8 *AuthData;\r
1042 UINTN AuthDataSize;\r
1043 EFI_IMAGE_DATA_DIRECTORY *SecDataDir;\r
6de4c35f 1044 UINT32 OffSet;\r
0c18794e 1045\r
0c18794e 1046 SignatureList = NULL;\r
1047 SignatureListSize = 0;\r
1048 WinCertificate = NULL;\r
f6f9031f 1049 SecDataDir = NULL;\r
1050 PkcsCertData = NULL;\r
0c18794e 1051 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
1052 Status = EFI_ACCESS_DENIED;\r
6de4c35f 1053 VerifyStatus = EFI_ACCESS_DENIED;\r
1054\r
0c18794e 1055 //\r
1056 // Check the image type and get policy setting.\r
1057 //\r
1058 switch (GetImageType (File)) {\r
45bf2c47 1059\r
0c18794e 1060 case IMAGE_FROM_FV:\r
1061 Policy = ALWAYS_EXECUTE;\r
1062 break;\r
1063\r
1064 case IMAGE_FROM_OPTION_ROM:\r
1065 Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);\r
1066 break;\r
1067\r
1068 case IMAGE_FROM_REMOVABLE_MEDIA:\r
1069 Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);\r
1070 break;\r
1071\r
1072 case IMAGE_FROM_FIXED_MEDIA:\r
1073 Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);\r
1074 break;\r
1075\r
1076 default:\r
45bf2c47 1077 Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;\r
0c18794e 1078 break;\r
1079 }\r
1080 //\r
1081 // If policy is always/never execute, return directly.\r
1082 //\r
1083 if (Policy == ALWAYS_EXECUTE) {\r
1084 return EFI_SUCCESS;\r
1085 } else if (Policy == NEVER_EXECUTE) {\r
1086 return EFI_ACCESS_DENIED;\r
1087 }\r
beda2356 1088\r
8f8ca22e 1089 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
beda2356 1090 //\r
8f8ca22e 1091 // Skip verification if SecureBoot variable doesn't exist.\r
beda2356 1092 //\r
8f8ca22e 1093 if (SecureBoot == NULL) {\r
beda2356 1094 return EFI_SUCCESS;\r
1095 }\r
1096\r
1097 //\r
8f8ca22e 1098 // Skip verification if SecureBoot is disabled.\r
beda2356 1099 //\r
8f8ca22e 1100 if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
1101 FreePool (SecureBoot);\r
beda2356 1102 return EFI_SUCCESS;\r
45bf2c47 1103 }\r
8f8ca22e 1104 FreePool (SecureBoot);\r
551d8081 1105\r
0c18794e 1106 //\r
1107 // Read the Dos header.\r
1108 //\r
570b3d1a 1109 if (FileBuffer == NULL) {\r
570b3d1a 1110 return EFI_INVALID_PARAMETER;\r
1111 }\r
551d8081 1112\r
0c18794e 1113 mImageBase = (UINT8 *) FileBuffer;\r
1114 mImageSize = FileSize;\r
28186d45
ED
1115\r
1116 ZeroMem (&ImageContext, sizeof (ImageContext));\r
1117 ImageContext.Handle = (VOID *) FileBuffer;\r
e0192326 1118 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;\r
28186d45
ED
1119\r
1120 //\r
1121 // Get information about the image being loaded\r
1122 //\r
1123 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
1124 if (EFI_ERROR (Status)) {\r
1125 //\r
1126 // The information can't be got from the invalid PeImage\r
1127 //\r
1128 goto Done;\r
1129 }\r
1130\r
badd40f9 1131 Status = EFI_ACCESS_DENIED;\r
1132\r
1133 DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;\r
0c18794e 1134 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1135 //\r
45bf2c47 1136 // DOS image header is present,\r
0c18794e 1137 // so read the PE header after the DOS image header.\r
1138 //\r
1139 mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
1140 } else {\r
1141 mPeCoffHeaderOffset = 0;\r
1142 }\r
1143 //\r
1144 // Check PE/COFF image.\r
1145 //\r
1146 mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);\r
1147 if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1148 //\r
1149 // It is not a valid Pe/Coff file.\r
1150 //\r
551d8081 1151 goto Done;\r
0c18794e 1152 }\r
1153\r
de2447dd 1154 if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1155 //\r
1156 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
1157 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
1158 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
1159 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
1160 //\r
1161 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1162 } else {\r
1163 //\r
1164 // Get the magic value from the PE/COFF Optional Header\r
1165 //\r
1166 Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
1167 }\r
1168 \r
0c18794e 1169 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1170 //\r
1171 // Use PE32 offset.\r
1172 //\r
551d8081 1173 NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1174 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
f6f9031f 1175 SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
551d8081 1176 } \r
570b3d1a 1177 } else {\r
1178 //\r
551d8081 1179 // Use PE32+ offset.\r
570b3d1a 1180 //\r
551d8081 1181 NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1182 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
f6f9031f 1183 SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
551d8081 1184 }\r
0c18794e 1185 }\r
1186\r
6de4c35f 1187 //\r
1188 // Start Image Validation.\r
1189 //\r
1190 if (SecDataDir == NULL || SecDataDir->Size == 0) {\r
0c18794e 1191 //\r
6de4c35f 1192 // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db", \r
1193 // and not be reflected in the security data base "dbx".\r
0c18794e 1194 //\r
45bf2c47 1195 if (!HashPeImage (HASHALG_SHA256)) {\r
1196 goto Done;\r
1197 }\r
1198\r
1199 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1200 //\r
1201 // Image Hash is in forbidden database (DBX).\r
1202 //\r
45bf2c47 1203 goto Done;\r
1204 }\r
1205\r
1206 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
1207 //\r
1208 // Image Hash is in allowed database (DB).\r
1209 //\r
1210 return EFI_SUCCESS;\r
1211 }\r
1212\r
1213 //\r
1214 // Image Hash is not found in both forbidden and allowed database.\r
1215 //\r
45bf2c47 1216 goto Done;\r
0c18794e 1217 }\r
45bf2c47 1218\r
0c18794e 1219 //\r
6de4c35f 1220 // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7 \r
1221 // "Attribute Certificate Table".\r
1222 // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.\r
0c18794e 1223 //\r
6de4c35f 1224 for (OffSet = SecDataDir->VirtualAddress;\r
1225 OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);\r
1226 OffSet += WinCertificate->dwLength, OffSet += ALIGN_SIZE (OffSet)) {\r
1227 WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);\r
1228 if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||\r
1229 (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {\r
1230 break;\r
1231 }\r
1232 \r
0c18794e 1233 //\r
6de4c35f 1234 // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.\r
0c18794e 1235 //\r
6de4c35f 1236 if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
1237 //\r
1238 // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the \r
1239 // Authenticode specification.\r
1240 //\r
1241 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;\r
1242 if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {\r
1243 break;\r
1244 }\r
1245 AuthData = PkcsCertData->CertData;\r
1246 AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);\r
1247 } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
1248 //\r
1249 // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.\r
1250 //\r
1251 WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;\r
1252 if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
1253 break;\r
1254 }\r
1255 if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {\r
1256 continue;\r
1257 }\r
1258 AuthData = WinCertUefiGuid->CertData;\r
1259 AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);\r
1260 } else {\r
1261 if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {\r
1262 break;\r
1263 }\r
1264 continue;\r
84bce75b 1265 }\r
6de4c35f 1266\r
f6f9031f 1267 Status = HashPeImageByType (AuthData, AuthDataSize);\r
45bf2c47 1268 if (EFI_ERROR (Status)) {\r
6de4c35f 1269 continue;\r
0c18794e 1270 }\r
6de4c35f 1271 \r
f6f9031f 1272 //\r
6de4c35f 1273 // Check the digital signature against the revoked certificate in forbidden database (dbx).\r
f6f9031f 1274 //\r
6de4c35f 1275 if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {\r
1276 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
1277 VerifyStatus = EFI_ACCESS_DENIED;\r
1278 break;\r
f6f9031f 1279 }\r
0c18794e 1280\r
1281 //\r
6de4c35f 1282 // Check the digital signature against the valid certificate in allowed database (db).\r
0c18794e 1283 //\r
6de4c35f 1284 if (EFI_ERROR (VerifyStatus)) {\r
1285 if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {\r
1286 VerifyStatus = EFI_SUCCESS;\r
1287 }\r
0c18794e 1288 }\r
6de4c35f 1289\r
0c18794e 1290 //\r
6de4c35f 1291 // Check the image's hash value.\r
0c18794e 1292 //\r
6de4c35f 1293 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1294 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
1295 VerifyStatus = EFI_ACCESS_DENIED;\r
1296 break;\r
1297 } else if (EFI_ERROR (VerifyStatus)) {\r
1298 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
1299 VerifyStatus = EFI_SUCCESS;\r
1300 }\r
45bf2c47 1301 }\r
50fe73a1 1302 }\r
1303\r
6de4c35f 1304 if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {\r
0c18794e 1305 //\r
6de4c35f 1306 // The Size in Certificate Table or the attribute certicate table is corrupted.\r
0c18794e 1307 //\r
6de4c35f 1308 VerifyStatus = EFI_ACCESS_DENIED;\r
1309 }\r
1310 \r
1311 if (!EFI_ERROR (VerifyStatus)) {\r
1312 return EFI_SUCCESS;\r
1313 } else {\r
1314 Status = EFI_ACCESS_DENIED;\r
1315 if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {\r
1316 //\r
1317 // Get image hash value as executable's signature.\r
1318 //\r
1319 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
1320 SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
1321 if (SignatureList == NULL) {\r
1322 Status = EFI_OUT_OF_RESOURCES;\r
1323 goto Done;\r
1324 }\r
1325 SignatureList->SignatureHeaderSize = 0;\r
1326 SignatureList->SignatureListSize = (UINT32) SignatureListSize;\r
1327 SignatureList->SignatureSize = (UINT32) mImageDigestSize;\r
1328 CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
1329 Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
1330 CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
50fe73a1 1331 }\r
0c18794e 1332 }\r
1333\r
1334Done:\r
1335 if (Status != EFI_SUCCESS) {\r
1336 //\r
1337 // Policy decides to defer or reject the image; add its information in image executable information table.\r
1338 //\r
1339 AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);\r
5db28a67 1340 Status = EFI_SECURITY_VIOLATION;\r
0c18794e 1341 }\r
1342\r
1343 if (SignatureList != NULL) {\r
1344 FreePool (SignatureList);\r
1345 }\r
1346\r
0c18794e 1347 return Status;\r
1348}\r
1349\r
0c18794e 1350/**\r
1351 Register security measurement handler.\r
1352\r
1353 @param ImageHandle ImageHandle of the loaded driver.\r
1354 @param SystemTable Pointer to the EFI System Table.\r
1355\r
1356 @retval EFI_SUCCESS The handlers were registered successfully.\r
1357**/\r
1358EFI_STATUS\r
1359EFIAPI\r
1360DxeImageVerificationLibConstructor (\r
1361 IN EFI_HANDLE ImageHandle,\r
1362 IN EFI_SYSTEM_TABLE *SystemTable\r
1363 )\r
1364{\r
5db28a67 1365 return RegisterSecurity2Handler (\r
0c18794e 1366 DxeImageVerificationHandler,\r
1367 EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
45bf2c47 1368 );\r
0c18794e 1369}\r