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