SecurityPkg: remove PE/COFF header workaround for ELILO on IPF
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
CommitLineData
0c18794e 1/** @file\r
3cd2484e 2 Implement image verification services for secure boot service\r
0c18794e 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
b3548d32 15Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
531c89a1 16(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
45bf2c47 17This program and the accompanying materials\r
18are licensed and made available under the terms and conditions of the BSD License\r
19which accompanies this distribution. The full text of the license may be found at\r
0c18794e 20http://opensource.org/licenses/bsd-license.php\r
21\r
45bf2c47 22THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
0c18794e 23WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
24\r
25**/\r
26\r
27#include "DxeImageVerificationLib.h"\r
28\r
dc204d5a
JY
29//\r
30// Caution: This is used by a function which may receive untrusted input.\r
31// These global variables hold PE/COFF image data, and they should be validated before use.\r
32//\r
0c18794e 33EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
45bf2c47 34UINT32 mPeCoffHeaderOffset;\r
0c18794e 35EFI_GUID mCertType;\r
36\r
dc204d5a
JY
37//\r
38// Information on current PE/COFF image\r
39//\r
40UINTN mImageSize;\r
41UINT8 *mImageBase = NULL;\r
42UINT8 mImageDigest[MAX_DIGEST_SIZE];\r
43UINTN mImageDigestSize;\r
44\r
0c18794e 45//\r
46// Notify string for authorization UI.\r
47//\r
48CHAR16 mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"Image verification pass but not found in authorized database!";\r
49CHAR16 mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"Launch this image anyway? (Yes/Defer/No)";\r
50//\r
51// Public Exponent of RSA Key.\r
52//\r
53CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
54\r
55\r
56//\r
57// OID ASN.1 Value for Hash Algorithms\r
58//\r
59UINT8 mHashOidValue[] = {\r
0c18794e 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
20333c6d
QL
68 { L"SHA1", 20, &mHashOidValue[0], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },\r
69 { L"SHA224", 28, &mHashOidValue[5], 9, NULL, NULL, NULL, NULL },\r
70 { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},\r
71 { L"SHA384", 48, &mHashOidValue[23], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},\r
72 { L"SHA512", 64, &mHashOidValue[32], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}\r
0c18794e 73};\r
74\r
531c89a1
CS
75EFI_STRING mHashTypeStr;\r
76\r
c1d93242
JY
77/**\r
78 SecureBoot Hook for processing image verification.\r
79\r
80 @param[in] VariableName Name of Variable to be found.\r
81 @param[in] VendorGuid Variable vendor GUID.\r
82 @param[in] DataSize Size of Data found. If size is less than the\r
83 data, this value contains the required size.\r
84 @param[in] Data Data pointer.\r
85\r
86**/\r
87VOID\r
88EFIAPI\r
89SecureBootHook (\r
90 IN CHAR16 *VariableName,\r
91 IN EFI_GUID *VendorGuid,\r
92 IN UINTN DataSize,\r
93 IN VOID *Data\r
94 );\r
95\r
28186d45
ED
96/**\r
97 Reads contents of a PE/COFF image in memory buffer.\r
98\r
dc204d5a
JY
99 Caution: This function may receive untrusted input.\r
100 PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
101 read is within the image buffer.\r
102\r
28186d45
ED
103 @param FileHandle Pointer to the file handle to read the PE/COFF image.\r
104 @param FileOffset Offset into the PE/COFF image to begin the read operation.\r
20333c6d 105 @param ReadSize On input, the size in bytes of the requested read operation.\r
28186d45
ED
106 On output, the number of bytes actually read.\r
107 @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
20333c6d
QL
108\r
109 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size\r
28186d45
ED
110**/\r
111EFI_STATUS\r
112EFIAPI\r
e0192326 113DxeImageVerificationLibImageRead (\r
28186d45
ED
114 IN VOID *FileHandle,\r
115 IN UINTN FileOffset,\r
116 IN OUT UINTN *ReadSize,\r
117 OUT VOID *Buffer\r
118 )\r
119{\r
120 UINTN EndPosition;\r
121\r
122 if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
20333c6d 123 return EFI_INVALID_PARAMETER;\r
28186d45
ED
124 }\r
125\r
126 if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
127 return EFI_INVALID_PARAMETER;\r
128 }\r
129\r
130 EndPosition = FileOffset + *ReadSize;\r
131 if (EndPosition > mImageSize) {\r
132 *ReadSize = (UINT32)(mImageSize - FileOffset);\r
133 }\r
134\r
135 if (FileOffset >= mImageSize) {\r
136 *ReadSize = 0;\r
137 }\r
138\r
139 CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
140\r
141 return EFI_SUCCESS;\r
142}\r
143\r
0c18794e 144\r
145/**\r
146 Get the image type.\r
147\r
148 @param[in] File This is a pointer to the device path of the file that is\r
45bf2c47 149 being dispatched.\r
0c18794e 150\r
45bf2c47 151 @return UINT32 Image Type\r
0c18794e 152\r
153**/\r
154UINT32\r
155GetImageType (\r
156 IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
157 )\r
158{\r
159 EFI_STATUS Status;\r
45bf2c47 160 EFI_HANDLE DeviceHandle;\r
0c18794e 161 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
162 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
163\r
5db28a67
LG
164 if (File == NULL) {\r
165 return IMAGE_UNKNOWN;\r
166 }\r
167\r
0c18794e 168 //\r
169 // First check to see if File is from a Firmware Volume\r
170 //\r
171 DeviceHandle = NULL;\r
45bf2c47 172 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 173 Status = gBS->LocateDevicePath (\r
174 &gEfiFirmwareVolume2ProtocolGuid,\r
175 &TempDevicePath,\r
176 &DeviceHandle\r
177 );\r
178 if (!EFI_ERROR (Status)) {\r
179 Status = gBS->OpenProtocol (\r
180 DeviceHandle,\r
181 &gEfiFirmwareVolume2ProtocolGuid,\r
182 NULL,\r
183 NULL,\r
184 NULL,\r
185 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
186 );\r
187 if (!EFI_ERROR (Status)) {\r
188 return IMAGE_FROM_FV;\r
189 }\r
190 }\r
191\r
192 //\r
193 // Next check to see if File is from a Block I/O device\r
194 //\r
195 DeviceHandle = NULL;\r
45bf2c47 196 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 197 Status = gBS->LocateDevicePath (\r
198 &gEfiBlockIoProtocolGuid,\r
199 &TempDevicePath,\r
200 &DeviceHandle\r
201 );\r
202 if (!EFI_ERROR (Status)) {\r
203 BlockIo = NULL;\r
204 Status = gBS->OpenProtocol (\r
205 DeviceHandle,\r
206 &gEfiBlockIoProtocolGuid,\r
207 (VOID **) &BlockIo,\r
208 NULL,\r
209 NULL,\r
210 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
211 );\r
212 if (!EFI_ERROR (Status) && BlockIo != NULL) {\r
213 if (BlockIo->Media != NULL) {\r
214 if (BlockIo->Media->RemovableMedia) {\r
215 //\r
216 // Block I/O is present and specifies the media is removable\r
217 //\r
218 return IMAGE_FROM_REMOVABLE_MEDIA;\r
219 } else {\r
220 //\r
221 // Block I/O is present and specifies the media is not removable\r
222 //\r
223 return IMAGE_FROM_FIXED_MEDIA;\r
224 }\r
225 }\r
226 }\r
227 }\r
228\r
229 //\r
45bf2c47 230 // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r
0c18794e 231 // the device path supports the Simple File System Protocol.\r
232 //\r
233 DeviceHandle = NULL;\r
45bf2c47 234 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 235 Status = gBS->LocateDevicePath (\r
236 &gEfiSimpleFileSystemProtocolGuid,\r
237 &TempDevicePath,\r
238 &DeviceHandle\r
239 );\r
240 if (!EFI_ERROR (Status)) {\r
241 //\r
242 // Simple File System is present without Block I/O, so assume media is fixed.\r
243 //\r
244 return IMAGE_FROM_FIXED_MEDIA;\r
245 }\r
246\r
247 //\r
248 // File is not from an FV, Block I/O or Simple File System, so the only options\r
45bf2c47 249 // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r
0c18794e 250 //\r
45bf2c47 251 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 252 while (!IsDevicePathEndType (TempDevicePath)) {\r
253 switch (DevicePathType (TempDevicePath)) {\r
45bf2c47 254\r
0c18794e 255 case MEDIA_DEVICE_PATH:\r
256 if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
257 return IMAGE_FROM_OPTION_ROM;\r
258 }\r
259 break;\r
260\r
261 case MESSAGING_DEVICE_PATH:\r
262 if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
263 return IMAGE_FROM_REMOVABLE_MEDIA;\r
45bf2c47 264 }\r
0c18794e 265 break;\r
266\r
267 default:\r
268 break;\r
269 }\r
270 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
271 }\r
45bf2c47 272 return IMAGE_UNKNOWN;\r
0c18794e 273}\r
274\r
275/**\r
69f8bb52 276 Calculate hash of Pe/Coff image based on the authenticode image hashing in\r
0c18794e 277 PE/COFF Specification 8.0 Appendix A\r
b3548d32 278\r
dc204d5a
JY
279 Caution: This function may receive untrusted input.\r
280 PE/COFF image is external input, so this function will validate its data structure\r
281 within this image buffer before use.\r
282\r
b3548d32 283 Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in\r
89fb5aef
LG
284 its caller function DxeImageVerificationHandler().\r
285\r
0c18794e 286 @param[in] HashAlg Hash algorithm type.\r
45bf2c47 287\r
0c18794e 288 @retval TRUE Successfully hash image.\r
289 @retval FALSE Fail in hash image.\r
290\r
291**/\r
45bf2c47 292BOOLEAN\r
0c18794e 293HashPeImage (\r
294 IN UINT32 HashAlg\r
295 )\r
296{\r
297 BOOLEAN Status;\r
0c18794e 298 EFI_IMAGE_SECTION_HEADER *Section;\r
299 VOID *HashCtx;\r
300 UINTN CtxSize;\r
301 UINT8 *HashBase;\r
302 UINTN HashSize;\r
303 UINTN SumOfBytesHashed;\r
304 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
305 UINTN Index;\r
306 UINTN Pos;\r
551d8081 307 UINT32 CertSize;\r
308 UINT32 NumberOfRvaAndSizes;\r
45bf2c47 309\r
0c18794e 310 HashCtx = NULL;\r
311 SectionHeader = NULL;\r
312 Status = FALSE;\r
313\r
20333c6d 314 if ((HashAlg >= HASHALG_MAX)) {\r
0c18794e 315 return FALSE;\r
316 }\r
45bf2c47 317\r
0c18794e 318 //\r
319 // Initialize context of hash.\r
320 //\r
321 ZeroMem (mImageDigest, MAX_DIGEST_SIZE);\r
322\r
20333c6d
QL
323 switch (HashAlg) {\r
324 case HASHALG_SHA1:\r
325 mImageDigestSize = SHA1_DIGEST_SIZE;\r
326 mCertType = gEfiCertSha1Guid;\r
327 break;\r
328\r
329 case HASHALG_SHA256:\r
330 mImageDigestSize = SHA256_DIGEST_SIZE;\r
331 mCertType = gEfiCertSha256Guid;\r
332 break;\r
333\r
334 case HASHALG_SHA384:\r
335 mImageDigestSize = SHA384_DIGEST_SIZE;\r
336 mCertType = gEfiCertSha384Guid;\r
337 break;\r
338\r
339 case HASHALG_SHA512:\r
340 mImageDigestSize = SHA512_DIGEST_SIZE;\r
341 mCertType = gEfiCertSha512Guid;\r
342 break;\r
343\r
344 default:\r
0c18794e 345 return FALSE;\r
346 }\r
347\r
531c89a1 348 mHashTypeStr = mHash[HashAlg].Name;\r
0c18794e 349 CtxSize = mHash[HashAlg].GetContextSize();\r
45bf2c47 350\r
0c18794e 351 HashCtx = AllocatePool (CtxSize);\r
570b3d1a 352 if (HashCtx == NULL) {\r
353 return FALSE;\r
354 }\r
0c18794e 355\r
356 // 1. Load the image header into memory.\r
357\r
358 // 2. Initialize a SHA hash context.\r
359 Status = mHash[HashAlg].HashInit(HashCtx);\r
45bf2c47 360\r
0c18794e 361 if (!Status) {\r
362 goto Done;\r
363 }\r
551d8081 364\r
0c18794e 365 //\r
366 // Measuring PE/COFF Image Header;\r
367 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
368 //\r
20333c6d 369\r
0c18794e 370 //\r
371 // 3. Calculate the distance from the base of the image header to the image checksum address.\r
372 // 4. Hash the image header from its base to beginning of the image checksum.\r
373 //\r
374 HashBase = mImageBase;\r
f199664c 375 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
0c18794e 376 //\r
377 // Use PE32 offset.\r
378 //\r
4333b99d 379 HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
551d8081 380 NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
f199664c 381 } else if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
0c18794e 382 //\r
383 // Use PE32+ offset.\r
384 //\r
4333b99d 385 HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
551d8081 386 NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
570b3d1a 387 } else {\r
388 //\r
389 // Invalid header magic number.\r
390 //\r
391 Status = FALSE;\r
392 goto Done;\r
0c18794e 393 }\r
394\r
395 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
396 if (!Status) {\r
397 goto Done;\r
398 }\r
551d8081 399\r
0c18794e 400 //\r
401 // 5. Skip over the image checksum (it occupies a single ULONG).\r
0c18794e 402 //\r
551d8081 403 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
0c18794e 404 //\r
551d8081 405 // 6. Since there is no Cert Directory in optional header, hash everything\r
406 // from the end of the checksum to the end of image header.\r
0c18794e 407 //\r
f199664c 408 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
551d8081 409 //\r
410 // Use PE32 offset.\r
411 //\r
412 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
4333b99d 413 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);\r
551d8081 414 } else {\r
415 //\r
416 // Use PE32+ offset.\r
417 //\r
418 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
4333b99d 419 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);\r
551d8081 420 }\r
421\r
422 if (HashSize != 0) {\r
423 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
424 if (!Status) {\r
425 goto Done;\r
426 }\r
427 }\r
0c18794e 428 } else {\r
429 //\r
551d8081 430 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
45bf2c47 431 //\r
f199664c 432 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
551d8081 433 //\r
434 // Use PE32 offset.\r
435 //\r
436 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
4333b99d 437 HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
551d8081 438 } else {\r
439 //\r
440 // Use PE32+ offset.\r
441 //\r
442 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
4333b99d 443 HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
551d8081 444 }\r
445\r
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
0c18794e 453 //\r
551d8081 454 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
455 // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
0c18794e 456 //\r
f199664c 457 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
551d8081 458 //\r
459 // Use PE32 offset\r
460 //\r
461 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
4333b99d 462 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);\r
551d8081 463 } else {\r
464 //\r
465 // Use PE32+ offset.\r
466 //\r
467 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
4333b99d 468 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);\r
551d8081 469 }\r
0c18794e 470\r
551d8081 471 if (HashSize != 0) {\r
472 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
473 if (!Status) {\r
474 goto Done;\r
475 }\r
20333c6d 476 }\r
0c18794e 477 }\r
551d8081 478\r
0c18794e 479 //\r
480 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
481 //\r
f199664c 482 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
0c18794e 483 //\r
484 // Use PE32 offset.\r
485 //\r
486 SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;\r
487 } else {\r
488 //\r
489 // Use PE32+ offset\r
490 //\r
491 SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
492 }\r
493\r
570b3d1a 494\r
495 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
496 mImageBase +\r
497 mPeCoffHeaderOffset +\r
498 sizeof (UINT32) +\r
499 sizeof (EFI_IMAGE_FILE_HEADER) +\r
500 mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r
501 );\r
502\r
0c18794e 503 //\r
504 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
505 // structures in the image. The 'NumberOfSections' field of the image\r
506 // header indicates how big the table should be. Do not include any\r
507 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
508 //\r
509 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);\r
570b3d1a 510 if (SectionHeader == NULL) {\r
511 Status = FALSE;\r
512 goto Done;\r
513 }\r
0c18794e 514 //\r
515 // 12. Using the 'PointerToRawData' in the referenced section headers as\r
516 // a key, arrange the elements in the table in ascending order. In other\r
517 // words, sort the section headers according to the disk-file offset of\r
518 // the section.\r
519 //\r
0c18794e 520 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
521 Pos = Index;\r
522 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
523 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));\r
524 Pos--;\r
525 }\r
526 CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));\r
527 Section += 1;\r
528 }\r
529\r
530 //\r
531 // 13. Walk through the sorted table, bring the corresponding section\r
532 // into memory, and hash the entire section (using the 'SizeOfRawData'\r
533 // field in the section header to determine the amount of data to hash).\r
534 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
535 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r
536 //\r
537 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
538 Section = &SectionHeader[Index];\r
539 if (Section->SizeOfRawData == 0) {\r
540 continue;\r
541 }\r
542 HashBase = mImageBase + Section->PointerToRawData;\r
543 HashSize = (UINTN) Section->SizeOfRawData;\r
544\r
545 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
546 if (!Status) {\r
547 goto Done;\r
548 }\r
549\r
550 SumOfBytesHashed += HashSize;\r
551 }\r
552\r
553 //\r
554 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
555 // data in the file that needs to be added to the hash. This data begins\r
556 // at file offset SUM_OF_BYTES_HASHED and its length is:\r
557 // FileSize - (CertDirectory->Size)\r
558 //\r
559 if (mImageSize > SumOfBytesHashed) {\r
560 HashBase = mImageBase + SumOfBytesHashed;\r
551d8081 561\r
562 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
563 CertSize = 0;\r
0c18794e 564 } else {\r
f199664c 565 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
551d8081 566 //\r
567 // Use PE32 offset.\r
568 //\r
569 CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
570 } else {\r
571 //\r
572 // Use PE32+ offset.\r
573 //\r
574 CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
28186d45 575 }\r
0c18794e 576 }\r
577\r
551d8081 578 if (mImageSize > CertSize + SumOfBytesHashed) {\r
579 HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed);\r
580\r
581 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
582 if (!Status) {\r
583 goto Done;\r
584 }\r
585 } else if (mImageSize < CertSize + SumOfBytesHashed) {\r
586 Status = FALSE;\r
0c18794e 587 goto Done;\r
588 }\r
589 }\r
551d8081 590\r
0c18794e 591 Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
592\r
593Done:\r
594 if (HashCtx != NULL) {\r
595 FreePool (HashCtx);\r
596 }\r
597 if (SectionHeader != NULL) {\r
598 FreePool (SectionHeader);\r
599 }\r
600 return Status;\r
601}\r
602\r
603/**\r
69f8bb52 604 Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of\r
45bf2c47 605 Pe/Coff image based on the authenticode image hashing in PE/COFF Specification\r
0c18794e 606 8.0 Appendix A\r
607\r
dc204d5a
JY
608 Caution: This function may receive untrusted input.\r
609 PE/COFF image is external input, so this function will validate its data structure\r
610 within this image buffer before use.\r
611\r
f6f9031f 612 @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.\r
613 @param[in] AuthDataSize Size of the Authenticode Signature in bytes.\r
20333c6d 614\r
0c18794e 615 @retval EFI_UNSUPPORTED Hash algorithm is not supported.\r
616 @retval EFI_SUCCESS Hash successfully.\r
617\r
618**/\r
45bf2c47 619EFI_STATUS\r
0c18794e 620HashPeImageByType (\r
f6f9031f 621 IN UINT8 *AuthData,\r
622 IN UINTN AuthDataSize\r
0c18794e 623 )\r
624{\r
625 UINT8 Index;\r
badd40f9 626\r
45bf2c47 627 for (Index = 0; Index < HASHALG_MAX; Index++) {\r
0c18794e 628 //\r
629 // Check the Hash algorithm in PE/COFF Authenticode.\r
45bf2c47 630 // According to PKCS#7 Definition:\r
0c18794e 631 // SignedData ::= SEQUENCE {\r
632 // version Version,\r
633 // digestAlgorithms DigestAlgorithmIdentifiers,\r
634 // contentInfo ContentInfo,\r
635 // .... }\r
636 // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r
637 // This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
bd0de396 638 // Fixed offset (+32) is calculated based on two bytes of length encoding.\r
45bf2c47 639 //\r
f6f9031f 640 if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
bd0de396 641 //\r
642 // Only support two bytes of Long Form of Length Encoding.\r
643 //\r
644 continue;\r
645 }\r
646\r
f6f9031f 647 if (AuthDataSize < 32 + mHash[Index].OidLength) {\r
badd40f9 648 return EFI_UNSUPPORTED;\r
649 }\r
650\r
f6f9031f 651 if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
0c18794e 652 break;\r
653 }\r
654 }\r
655\r
656 if (Index == HASHALG_MAX) {\r
657 return EFI_UNSUPPORTED;\r
658 }\r
659\r
660 //\r
661 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.\r
662 //\r
663 if (!HashPeImage(Index)) {\r
664 return EFI_UNSUPPORTED;\r
665 }\r
666\r
667 return EFI_SUCCESS;\r
668}\r
669\r
670\r
671/**\r
672 Returns the size of a given image execution info table in bytes.\r
673\r
674 This function returns the size, in bytes, of the image execution info table specified by\r
675 ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.\r
676\r
677 @param ImageExeInfoTable A pointer to a image execution info table structure.\r
45bf2c47 678\r
0c18794e 679 @retval 0 If ImageExeInfoTable is NULL.\r
680 @retval Others The size of a image execution info table in bytes.\r
681\r
682**/\r
683UINTN\r
684GetImageExeInfoTableSize (\r
685 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable\r
686 )\r
687{\r
688 UINTN Index;\r
689 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem;\r
690 UINTN TotalSize;\r
691\r
692 if (ImageExeInfoTable == NULL) {\r
693 return 0;\r
694 }\r
695\r
696 ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE));\r
697 TotalSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
698 for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) {\r
699 TotalSize += ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize);\r
700 ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoItem + ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize));\r
701 }\r
702\r
703 return TotalSize;\r
704}\r
705\r
706/**\r
707 Create an Image Execution Information Table entry and add it to system configuration table.\r
708\r
709 @param[in] Action Describes the action taken by the firmware regarding this image.\r
710 @param[in] Name Input a null-terminated, user-friendly name.\r
711 @param[in] DevicePath Input device path pointer.\r
712 @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.\r
713 @param[in] SignatureSize Size of signature.\r
45bf2c47 714\r
0c18794e 715**/\r
716VOID\r
717AddImageExeInfo (\r
45bf2c47 718 IN EFI_IMAGE_EXECUTION_ACTION Action,\r
719 IN CHAR16 *Name OPTIONAL,\r
0c18794e 720 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
721 IN EFI_SIGNATURE_LIST *Signature OPTIONAL,\r
722 IN UINTN SignatureSize\r
723 )\r
724{\r
0c18794e 725 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;\r
726 EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable;\r
727 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry;\r
728 UINTN ImageExeInfoTableSize;\r
729 UINTN NewImageExeInfoEntrySize;\r
730 UINTN NameStringLen;\r
731 UINTN DevicePathSize;\r
4fc08e8d 732 CHAR16 *NameStr;\r
0c18794e 733\r
0c18794e 734 ImageExeInfoTable = NULL;\r
735 NewImageExeInfoTable = NULL;\r
736 ImageExeInfoEntry = NULL;\r
737 NameStringLen = 0;\r
4fc08e8d 738 NameStr = NULL;\r
0c18794e 739\r
570b3d1a 740 if (DevicePath == NULL) {\r
741 return ;\r
742 }\r
45bf2c47 743\r
0c18794e 744 if (Name != NULL) {\r
745 NameStringLen = StrSize (Name);\r
b3d42170 746 } else {\r
747 NameStringLen = sizeof (CHAR16);\r
0c18794e 748 }\r
749\r
45bf2c47 750 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
0c18794e 751 if (ImageExeInfoTable != NULL) {\r
752 //\r
753 // The table has been found!\r
b3d42170 754 // We must enlarge the table to accomodate the new exe info entry.\r
0c18794e 755 //\r
756 ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);\r
757 } else {\r
758 //\r
759 // Not Found!\r
760 // We should create a new table to append to the configuration table.\r
761 //\r
762 ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
763 }\r
764\r
765 DevicePathSize = GetDevicePathSize (DevicePath);\r
4fc08e8d
CZ
766\r
767 //\r
768 // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align\r
769 //\r
770 NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;\r
771\r
0c18794e 772 NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);\r
570b3d1a 773 if (NewImageExeInfoTable == NULL) {\r
774 return ;\r
775 }\r
0c18794e 776\r
777 if (ImageExeInfoTable != NULL) {\r
778 CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);\r
779 } else {\r
780 NewImageExeInfoTable->NumberOfImages = 0;\r
781 }\r
782 NewImageExeInfoTable->NumberOfImages++;\r
783 ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);\r
784 //\r
ffccb935 785 // Update new item's information.\r
0c18794e 786 //\r
1fee5304
ED
787 WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);\r
788 WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);\r
0c18794e 789\r
4fc08e8d 790 NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);\r
0c18794e 791 if (Name != NULL) {\r
4fc08e8d 792 CopyMem ((UINT8 *) NameStr, Name, NameStringLen);\r
b3d42170 793 } else {\r
4fc08e8d 794 ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16));\r
0c18794e 795 }\r
4fc08e8d 796\r
0c18794e 797 CopyMem (\r
4fc08e8d 798 (UINT8 *) NameStr + NameStringLen,\r
0c18794e 799 DevicePath,\r
800 DevicePathSize\r
801 );\r
802 if (Signature != NULL) {\r
803 CopyMem (\r
4fc08e8d 804 (UINT8 *) NameStr + NameStringLen + DevicePathSize,\r
0c18794e 805 Signature,\r
806 SignatureSize\r
807 );\r
808 }\r
809 //\r
810 // Update/replace the image execution table.\r
811 //\r
570b3d1a 812 gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);\r
45bf2c47 813\r
0c18794e 814 //\r
815 // Free Old table data!\r
816 //\r
817 if (ImageExeInfoTable != NULL) {\r
818 FreePool (ImageExeInfoTable);\r
819 }\r
820}\r
821\r
20333c6d
QL
822/**\r
823 Check whether the hash of an given X.509 certificate is in forbidden database (DBX).\r
824\r
825 @param[in] Certificate Pointer to X.509 Certificate that is searched for.\r
826 @param[in] CertSize Size of X.509 Certificate.\r
827 @param[in] SignatureList Pointer to the Signature List in forbidden database.\r
828 @param[in] SignatureListSize Size of Signature List.\r
829 @param[out] RevocationTime Return the time that the certificate was revoked.\r
830\r
831 @return TRUE The certificate hash is found in the forbidden database.\r
832 @return FALSE The certificate hash is not found in the forbidden database.\r
833\r
834**/\r
835BOOLEAN\r
836IsCertHashFoundInDatabase (\r
837 IN UINT8 *Certificate,\r
838 IN UINTN CertSize,\r
839 IN EFI_SIGNATURE_LIST *SignatureList,\r
840 IN UINTN SignatureListSize,\r
841 OUT EFI_TIME *RevocationTime\r
842 )\r
843{\r
844 BOOLEAN IsFound;\r
5789fe35 845 BOOLEAN Status;\r
20333c6d
QL
846 EFI_SIGNATURE_LIST *DbxList;\r
847 UINTN DbxSize;\r
848 EFI_SIGNATURE_DATA *CertHash;\r
849 UINTN CertHashCount;\r
850 UINTN Index;\r
851 UINT32 HashAlg;\r
852 VOID *HashCtx;\r
853 UINT8 CertDigest[MAX_DIGEST_SIZE];\r
854 UINT8 *DbxCertHash;\r
855 UINTN SiglistHeaderSize;\r
12d95665
LQ
856 UINT8 *TBSCert;\r
857 UINTN TBSCertSize;\r
20333c6d
QL
858\r
859 IsFound = FALSE;\r
860 DbxList = SignatureList;\r
861 DbxSize = SignatureListSize;\r
862 HashCtx = NULL;\r
863 HashAlg = HASHALG_MAX;\r
864\r
12d95665
LQ
865 if ((RevocationTime == NULL) || (DbxList == NULL)) {\r
866 return FALSE;\r
867 }\r
868\r
869 //\r
870 // Retrieve the TBSCertificate from the X.509 Certificate.\r
871 //\r
872 if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {\r
873 return FALSE;\r
874 }\r
20333c6d
QL
875\r
876 while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) {\r
877 //\r
878 // Determine Hash Algorithm of Certificate in the forbidden database.\r
879 //\r
880 if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {\r
881 HashAlg = HASHALG_SHA256;\r
882 } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {\r
883 HashAlg = HASHALG_SHA384;\r
884 } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {\r
885 HashAlg = HASHALG_SHA512;\r
886 } else {\r
887 DbxSize -= DbxList->SignatureListSize;\r
888 DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);\r
889 continue;\r
890 }\r
891\r
892 //\r
12d95665 893 // Calculate the hash value of current TBSCertificate for comparision.\r
20333c6d
QL
894 //\r
895 if (mHash[HashAlg].GetContextSize == NULL) {\r
896 goto Done;\r
897 }\r
898 ZeroMem (CertDigest, MAX_DIGEST_SIZE);\r
899 HashCtx = AllocatePool (mHash[HashAlg].GetContextSize ());\r
900 if (HashCtx == NULL) {\r
901 goto Done;\r
902 }\r
903 Status = mHash[HashAlg].HashInit (HashCtx);\r
904 if (!Status) {\r
905 goto Done;\r
906 }\r
12d95665 907 Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);\r
20333c6d
QL
908 if (!Status) {\r
909 goto Done;\r
910 }\r
911 Status = mHash[HashAlg].HashFinal (HashCtx, CertDigest);\r
912 if (!Status) {\r
913 goto Done;\r
914 }\r
915\r
916 SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;\r
917 CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);\r
918 CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;\r
919 for (Index = 0; Index < CertHashCount; Index++) {\r
920 //\r
921 // Iterate each Signature Data Node within this CertList for verify.\r
922 //\r
923 DbxCertHash = CertHash->SignatureData;\r
924 if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {\r
925 //\r
926 // Hash of Certificate is found in forbidden database.\r
927 //\r
928 IsFound = TRUE;\r
929\r
930 //\r
931 // Return the revocation time.\r
932 //\r
933 CopyMem (RevocationTime, (EFI_TIME *)(DbxCertHash + mHash[HashAlg].DigestLength), sizeof (EFI_TIME));\r
934 goto Done;\r
935 }\r
936 CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);\r
937 }\r
938\r
939 DbxSize -= DbxList->SignatureListSize;\r
940 DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);\r
941 }\r
942\r
943Done:\r
944 if (HashCtx != NULL) {\r
945 FreePool (HashCtx);\r
946 }\r
947\r
948 return IsFound;\r
949}\r
950\r
0c18794e 951/**\r
952 Check whether signature is in specified database.\r
953\r
954 @param[in] VariableName Name of database variable that is searched in.\r
955 @param[in] Signature Pointer to signature that is searched for.\r
956 @param[in] CertType Pointer to hash algrithom.\r
957 @param[in] SignatureSize Size of Signature.\r
958\r
959 @return TRUE Found the signature in the variable database.\r
960 @return FALSE Not found the signature in the variable database.\r
961\r
962**/\r
963BOOLEAN\r
964IsSignatureFoundInDatabase (\r
965 IN CHAR16 *VariableName,\r
45bf2c47 966 IN UINT8 *Signature,\r
0c18794e 967 IN EFI_GUID *CertType,\r
968 IN UINTN SignatureSize\r
969 )\r
970{\r
971 EFI_STATUS Status;\r
972 EFI_SIGNATURE_LIST *CertList;\r
973 EFI_SIGNATURE_DATA *Cert;\r
974 UINTN DataSize;\r
975 UINT8 *Data;\r
976 UINTN Index;\r
977 UINTN CertCount;\r
978 BOOLEAN IsFound;\r
20333c6d 979\r
0c18794e 980 //\r
981 // Read signature database variable.\r
982 //\r
983 IsFound = FALSE;\r
984 Data = NULL;\r
985 DataSize = 0;\r
986 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
987 if (Status != EFI_BUFFER_TOO_SMALL) {\r
988 return FALSE;\r
989 }\r
990\r
991 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
570b3d1a 992 if (Data == NULL) {\r
993 return FALSE;\r
994 }\r
0c18794e 995\r
996 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
997 if (EFI_ERROR (Status)) {\r
998 goto Done;\r
999 }\r
1000 //\r
1001 // Enumerate all signature data in SigDB to check if executable's signature exists.\r
1002 //\r
1003 CertList = (EFI_SIGNATURE_LIST *) Data;\r
1004 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
7403ff5b 1005 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
0c18794e 1006 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1007 if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {\r
1008 for (Index = 0; Index < CertCount; Index++) {\r
1009 if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {\r
1010 //\r
1011 // Find the signature in database.\r
1012 //\r
1013 IsFound = TRUE;\r
5b196b06
ZC
1014 //\r
1015 // Entries in UEFI_IMAGE_SECURITY_DATABASE that are used to validate image should be measured\r
1016 //\r
1017 if (StrCmp(VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) {\r
1018 SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
1019 }\r
0c18794e 1020 break;\r
1021 }\r
1022\r
1023 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1024 }\r
1025\r
1026 if (IsFound) {\r
1027 break;\r
1028 }\r
1029 }\r
1030\r
1031 DataSize -= CertList->SignatureListSize;\r
1032 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1033 }\r
1034\r
1035Done:\r
1036 if (Data != NULL) {\r
1037 FreePool (Data);\r
1038 }\r
1039\r
1040 return IsFound;\r
1041}\r
1042\r
1043/**\r
20333c6d 1044 Check whether the timestamp is valid by comparing the signing time and the revocation time.\r
0c18794e 1045\r
20333c6d
QL
1046 @param SigningTime A pointer to the signing time.\r
1047 @param RevocationTime A pointer to the revocation time.\r
45bf2c47 1048\r
20333c6d
QL
1049 @retval TRUE The SigningTime is not later than the RevocationTime.\r
1050 @retval FALSE The SigningTime is later than the RevocationTime.\r
0c18794e 1051\r
1052**/\r
45bf2c47 1053BOOLEAN\r
20333c6d
QL
1054IsValidSignatureByTimestamp (\r
1055 IN EFI_TIME *SigningTime,\r
1056 IN EFI_TIME *RevocationTime\r
1057 )\r
1058{\r
1059 if (SigningTime->Year != RevocationTime->Year) {\r
1060 return (BOOLEAN) (SigningTime->Year < RevocationTime->Year);\r
1061 } else if (SigningTime->Month != RevocationTime->Month) {\r
1062 return (BOOLEAN) (SigningTime->Month < RevocationTime->Month);\r
1063 } else if (SigningTime->Day != RevocationTime->Day) {\r
1064 return (BOOLEAN) (SigningTime->Day < RevocationTime->Day);\r
1065 } else if (SigningTime->Hour != RevocationTime->Hour) {\r
1066 return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour);\r
1067 } else if (SigningTime->Minute != RevocationTime->Minute) {\r
1068 return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute);\r
1069 }\r
1070\r
1071 return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second);\r
1072}\r
1073\r
1074/**\r
1075 Check if the given time value is zero.\r
1076\r
1077 @param[in] Time Pointer of a time value.\r
1078\r
1079 @retval TRUE The Time is Zero.\r
1080 @retval FALSE The Time is not Zero.\r
1081\r
1082**/\r
1083BOOLEAN\r
1084IsTimeZero (\r
1085 IN EFI_TIME *Time\r
1086 )\r
1087{\r
1088 if ((Time->Year == 0) && (Time->Month == 0) && (Time->Day == 0) &&\r
1089 (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) {\r
1090 return TRUE;\r
1091 }\r
1092\r
1093 return FALSE;\r
1094}\r
1095\r
1096/**\r
b3548d32 1097 Check whether the timestamp signature is valid and the signing time is also earlier than\r
20333c6d
QL
1098 the revocation time.\r
1099\r
1100 @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.\r
1101 @param[in] AuthDataSize Size of the Authenticode signature in bytes.\r
1102 @param[in] RevocationTime The time that the certificate was revoked.\r
1103\r
b3548d32 1104 @retval TRUE Timestamp signature is valid and signing time is no later than the\r
20333c6d
QL
1105 revocation time.\r
1106 @retval FALSE Timestamp signature is not valid or the signing time is later than the\r
1107 revocation time.\r
1108\r
1109**/\r
1110BOOLEAN\r
1111PassTimestampCheck (\r
1112 IN UINT8 *AuthData,\r
1113 IN UINTN AuthDataSize,\r
1114 IN EFI_TIME *RevocationTime\r
1115 )\r
1116{\r
1117 EFI_STATUS Status;\r
1118 BOOLEAN VerifyStatus;\r
1119 EFI_SIGNATURE_LIST *CertList;\r
1120 EFI_SIGNATURE_DATA *Cert;\r
1121 UINT8 *DbtData;\r
1122 UINTN DbtDataSize;\r
1123 UINT8 *RootCert;\r
1124 UINTN RootCertSize;\r
1125 UINTN Index;\r
1126 UINTN CertCount;\r
1127 EFI_TIME SigningTime;\r
1128\r
1129 //\r
1130 // Variable Initialization\r
1131 //\r
1132 VerifyStatus = FALSE;\r
1133 DbtData = NULL;\r
1134 CertList = NULL;\r
1135 Cert = NULL;\r
1136 RootCert = NULL;\r
1137 RootCertSize = 0;\r
1138\r
1139 //\r
1140 // If RevocationTime is zero, the certificate shall be considered to always be revoked.\r
1141 //\r
1142 if (IsTimeZero (RevocationTime)) {\r
1143 return FALSE;\r
1144 }\r
1145\r
1146 //\r
1147 // RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards.\r
1148 // Using the dbt to get the trusted TSA certificates.\r
1149 //\r
1150 DbtDataSize = 0;\r
1151 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, NULL);\r
7e0699c0
QL
1152 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1153 goto Done;\r
1154 }\r
1155 DbtData = (UINT8 *) AllocateZeroPool (DbtDataSize);\r
1156 if (DbtData == NULL) {\r
1157 goto Done;\r
1158 }\r
1159 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, (VOID *) DbtData);\r
1160 if (EFI_ERROR (Status)) {\r
1161 goto Done;\r
20333c6d
QL
1162 }\r
1163\r
1164 CertList = (EFI_SIGNATURE_LIST *) DbtData;\r
1165 while ((DbtDataSize > 0) && (DbtDataSize >= CertList->SignatureListSize)) {\r
1166 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
1167 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1168 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1169 for (Index = 0; Index < CertCount; Index++) {\r
1170 //\r
1171 // Iterate each Signature Data Node within this CertList for verify.\r
1172 //\r
1173 RootCert = Cert->SignatureData;\r
1174 RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
1175 //\r
1176 // Get the signing time if the timestamp signature is valid.\r
1177 //\r
1178 if (ImageTimestampVerify (AuthData, AuthDataSize, RootCert, RootCertSize, &SigningTime)) {\r
1179 //\r
1180 // The signer signature is valid only when the signing time is earlier than revocation time.\r
1181 //\r
1182 if (IsValidSignatureByTimestamp (&SigningTime, RevocationTime)) {\r
1183 VerifyStatus = TRUE;\r
1184 goto Done;\r
1185 }\r
1186 }\r
1187 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1188 }\r
1189 }\r
1190 DbtDataSize -= CertList->SignatureListSize;\r
1191 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1192 }\r
1193\r
1194Done:\r
1195 if (DbtData != NULL) {\r
1196 FreePool (DbtData);\r
1197 }\r
1198\r
1199 return VerifyStatus;\r
1200}\r
1201\r
1202/**\r
1203 Check whether the image signature is forbidden by the forbidden database (dbx).\r
1204 The image is forbidden to load if any certificates for signing are revoked before signing time.\r
1205\r
560ac77e
ZC
1206 @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image.\r
1207 @param[in] AuthDataSize Size of the Authenticode signature in bytes.\r
20333c6d
QL
1208\r
1209 @retval TRUE Image is forbidden by dbx.\r
1210 @retval FALSE Image is not forbidden by dbx.\r
1211\r
1212**/\r
1213BOOLEAN\r
b3548d32 1214IsForbiddenByDbx (\r
560ac77e 1215 IN UINT8 *AuthData,\r
b3548d32 1216 IN UINTN AuthDataSize\r
20333c6d
QL
1217 )\r
1218{\r
1219 EFI_STATUS Status;\r
1220 BOOLEAN IsForbidden;\r
1221 UINT8 *Data;\r
1222 UINTN DataSize;\r
27c93c06
LQ
1223 EFI_SIGNATURE_LIST *CertList;\r
1224 UINTN CertListSize;\r
1225 EFI_SIGNATURE_DATA *CertData;\r
1226 UINT8 *RootCert;\r
1227 UINTN RootCertSize;\r
1228 UINTN CertCount;\r
20333c6d
QL
1229 UINTN Index;\r
1230 UINT8 *CertBuffer;\r
1231 UINTN BufferLength;\r
1232 UINT8 *TrustedCert;\r
1233 UINTN TrustedCertLength;\r
1234 UINT8 CertNumber;\r
1235 UINT8 *CertPtr;\r
1236 UINT8 *Cert;\r
1237 UINTN CertSize;\r
1238 EFI_TIME RevocationTime;\r
20333c6d
QL
1239 //\r
1240 // Variable Initialization\r
1241 //\r
1242 IsForbidden = FALSE;\r
1243 Data = NULL;\r
27c93c06
LQ
1244 CertList = NULL;\r
1245 CertData = NULL;\r
1246 RootCert = NULL;\r
1247 RootCertSize = 0;\r
20333c6d
QL
1248 Cert = NULL;\r
1249 CertBuffer = NULL;\r
1250 BufferLength = 0;\r
1251 TrustedCert = NULL;\r
1252 TrustedCertLength = 0;\r
1253\r
1254 //\r
1255 // The image will not be forbidden if dbx can't be got.\r
1256 //\r
1257 DataSize = 0;\r
1258 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
7e0699c0
QL
1259 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1260 return IsForbidden;\r
20333c6d 1261 }\r
7e0699c0
QL
1262 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
1263 if (Data == NULL) {\r
1264 return IsForbidden;\r
1265 }\r
1266\r
1267 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);\r
20333c6d
QL
1268 if (EFI_ERROR (Status)) {\r
1269 return IsForbidden;\r
1270 }\r
1271\r
27c93c06
LQ
1272 //\r
1273 // Verify image signature with RAW X509 certificates in DBX database.\r
1274 // If passed, the image will be forbidden.\r
1275 //\r
1276 CertList = (EFI_SIGNATURE_LIST *) Data;\r
1277 CertListSize = DataSize;\r
1278 while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) {\r
1279 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
1280 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1281 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1282\r
1283 for (Index = 0; Index < CertCount; Index++) {\r
1284 //\r
1285 // Iterate each Signature Data Node within this CertList for verify.\r
1286 //\r
1287 RootCert = CertData->SignatureData;\r
1288 RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
1289\r
1290 //\r
1291 // Call AuthenticodeVerify library to Verify Authenticode struct.\r
1292 //\r
1293 IsForbidden = AuthenticodeVerify (\r
1294 AuthData,\r
1295 AuthDataSize,\r
1296 RootCert,\r
1297 RootCertSize,\r
1298 mImageDigest,\r
1299 mImageDigestSize\r
1300 );\r
1301 if (IsForbidden) {\r
531c89a1 1302 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is forbidden by DBX.\n"));\r
27c93c06
LQ
1303 goto Done;\r
1304 }\r
1305\r
1306 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);\r
1307 }\r
1308 }\r
1309\r
1310 CertListSize -= CertList->SignatureListSize;\r
1311 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1312 }\r
1313\r
1314 //\r
1315 // Check X.509 Certificate Hash & Possible Timestamp.\r
1316 //\r
1317\r
20333c6d
QL
1318 //\r
1319 // Retrieve the certificate stack from AuthData\r
1320 // The output CertStack format will be:\r
1321 // UINT8 CertNumber;\r
1322 // UINT32 Cert1Length;\r
1323 // UINT8 Cert1[];\r
1324 // UINT32 Cert2Length;\r
1325 // UINT8 Cert2[];\r
1326 // ...\r
1327 // UINT32 CertnLength;\r
1328 // UINT8 Certn[];\r
1329 //\r
1330 Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);\r
7e0699c0 1331 if ((BufferLength == 0) || (CertBuffer == NULL)) {\r
20333c6d
QL
1332 IsForbidden = TRUE;\r
1333 goto Done;\r
1334 }\r
1335\r
1336 //\r
27c93c06 1337 // Check if any hash of certificates embedded in AuthData is in the forbidden database.\r
20333c6d
QL
1338 //\r
1339 CertNumber = (UINT8) (*CertBuffer);\r
1340 CertPtr = CertBuffer + 1;\r
1341 for (Index = 0; Index < CertNumber; Index++) {\r
1342 CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);\r
1343 Cert = (UINT8 *)CertPtr + sizeof (UINT32);\r
91422384
ZC
1344 //\r
1345 // Advance CertPtr to the next cert in image signer's cert list\r
1346 //\r
1347 CertPtr = CertPtr + sizeof (UINT32) + CertSize;\r
20333c6d
QL
1348\r
1349 if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {\r
1350 //\r
1351 // Check the timestamp signature and signing time to determine if the image can be trusted.\r
1352 //\r
1353 IsForbidden = TRUE;\r
1354 if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) {\r
1355 IsForbidden = FALSE;\r
91422384
ZC
1356 //\r
1357 // Pass DBT check. Continue to check other certs in image signer's cert list against DBX, DBT\r
1358 //\r
1359 continue;\r
20333c6d 1360 }\r
531c89a1 1361 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature failed the timestamp check.\n"));\r
20333c6d
QL
1362 goto Done;\r
1363 }\r
1364\r
20333c6d
QL
1365 }\r
1366\r
1367Done:\r
1368 if (Data != NULL) {\r
1369 FreePool (Data);\r
1370 }\r
1371\r
1372 Pkcs7FreeSigners (CertBuffer);\r
1373 Pkcs7FreeSigners (TrustedCert);\r
1374\r
1375 return IsForbidden;\r
1376}\r
1377\r
4fc08e8d 1378\r
20333c6d
QL
1379/**\r
1380 Check whether the image signature can be verified by the trusted certificates in DB database.\r
1381\r
560ac77e
ZC
1382 @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.\r
1383 @param[in] AuthDataSize Size of the Authenticode signature in bytes.\r
20333c6d
QL
1384\r
1385 @retval TRUE Image passed verification using certificate in db.\r
1386 @retval FALSE Image didn't pass verification using certificate in db.\r
1387\r
1388**/\r
1389BOOLEAN\r
1390IsAllowedByDb (\r
560ac77e
ZC
1391 IN UINT8 *AuthData,\r
1392 IN UINTN AuthDataSize\r
0c18794e 1393 )\r
1394{\r
1395 EFI_STATUS Status;\r
1396 BOOLEAN VerifyStatus;\r
0c18794e 1397 EFI_SIGNATURE_LIST *CertList;\r
4fc08e8d 1398 EFI_SIGNATURE_DATA *CertData;\r
0c18794e 1399 UINTN DataSize;\r
45bf2c47 1400 UINT8 *Data;\r
0c18794e 1401 UINT8 *RootCert;\r
1402 UINTN RootCertSize;\r
1403 UINTN Index;\r
1404 UINTN CertCount;\r
27c93c06
LQ
1405 UINTN DbxDataSize;\r
1406 UINT8 *DbxData;\r
1407 EFI_TIME RevocationTime;\r
0c18794e 1408\r
4fc08e8d
CZ
1409 Data = NULL;\r
1410 CertList = NULL;\r
1411 CertData = NULL;\r
1412 RootCert = NULL;\r
1413 DbxData = NULL;\r
1414 RootCertSize = 0;\r
1415 VerifyStatus = FALSE;\r
0c18794e 1416\r
0c18794e 1417 DataSize = 0;\r
20333c6d 1418 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
0c18794e 1419 if (Status == EFI_BUFFER_TOO_SMALL) {\r
45bf2c47 1420 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
1421 if (Data == NULL) {\r
1422 return VerifyStatus;\r
570b3d1a 1423 }\r
0c18794e 1424\r
20333c6d 1425 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);\r
0c18794e 1426 if (EFI_ERROR (Status)) {\r
1427 goto Done;\r
1428 }\r
45bf2c47 1429\r
1430 //\r
1431 // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.\r
0c18794e 1432 //\r
45bf2c47 1433 CertList = (EFI_SIGNATURE_LIST *) Data;\r
0c18794e 1434 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
1435 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
4fc08e8d
CZ
1436 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1437 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
20333c6d 1438\r
0c18794e 1439 for (Index = 0; Index < CertCount; Index++) {\r
1440 //\r
45bf2c47 1441 // Iterate each Signature Data Node within this CertList for verify.\r
1442 //\r
4fc08e8d 1443 RootCert = CertData->SignatureData;\r
20333c6d 1444 RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
45bf2c47 1445\r
0c18794e 1446 //\r
45bf2c47 1447 // Call AuthenticodeVerify library to Verify Authenticode struct.\r
0c18794e 1448 //\r
1449 VerifyStatus = AuthenticodeVerify (\r
f6f9031f 1450 AuthData,\r
1451 AuthDataSize,\r
0c18794e 1452 RootCert,\r
1453 RootCertSize,\r
1454 mImageDigest,\r
1455 mImageDigestSize\r
1456 );\r
0c18794e 1457 if (VerifyStatus) {\r
27c93c06
LQ
1458 //\r
1459 // Here We still need to check if this RootCert's Hash is revoked\r
1460 //\r
1461 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL);\r
1462 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1463 goto Done;\r
1464 }\r
1ca3a099 1465 DbxData = (UINT8 *) AllocateZeroPool (DbxDataSize);\r
27c93c06
LQ
1466 if (DbxData == NULL) {\r
1467 goto Done;\r
1468 }\r
1469\r
1470 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData);\r
1471 if (EFI_ERROR (Status)) {\r
1472 goto Done;\r
1473 }\r
1474\r
1475 if (IsCertHashFoundInDatabase (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime)) {\r
1476 //\r
531c89a1 1477 // Check the timestamp signature and signing time to determine if the RootCert can be trusted.\r
27c93c06
LQ
1478 //\r
1479 VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);\r
531c89a1
CS
1480 if (!VerifyStatus) {\r
1481 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed and signature is accepted by DB, but its root cert failed the timestamp check.\n"));\r
1482 }\r
27c93c06
LQ
1483 }\r
1484\r
0c18794e 1485 goto Done;\r
1486 }\r
20333c6d 1487\r
4fc08e8d 1488 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);\r
45bf2c47 1489 }\r
0c18794e 1490 }\r
20333c6d 1491\r
0c18794e 1492 DataSize -= CertList->SignatureListSize;\r
1493 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1494 }\r
1495 }\r
1496\r
45bf2c47 1497Done:\r
4fc08e8d 1498\r
27c93c06 1499 if (VerifyStatus) {\r
4fc08e8d 1500 SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);\r
27c93c06
LQ
1501 }\r
1502\r
45bf2c47 1503 if (Data != NULL) {\r
1504 FreePool (Data);\r
1505 }\r
27c93c06
LQ
1506 if (DbxData != NULL) {\r
1507 FreePool (DbxData);\r
1508 }\r
0c18794e 1509\r
45bf2c47 1510 return VerifyStatus;\r
1511}\r
0c18794e 1512\r
0c18794e 1513/**\r
1514 Provide verification service for signed images, which include both signature validation\r
45bf2c47 1515 and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and\r
0c18794e 1516 MSFT Authenticode type signatures are supported.\r
0c18794e 1517\r
45bf2c47 1518 In this implementation, only verify external executables when in USER MODE.\r
1519 Executables from FV is bypass, so pass in AuthenticationStatus is ignored.\r
1520\r
6de4c35f 1521 The image verification policy is:\r
50fe73a1 1522 If the image is signed,\r
6de4c35f 1523 At least one valid signature or at least one hash value of the image must match a record\r
1524 in the security database "db", and no valid signature nor any hash value of the image may\r
1525 be reflected in the security database "dbx".\r
50fe73a1 1526 Otherwise, the image is not signed,\r
6de4c35f 1527 The SHA256 hash value of the image must match a record in the security database "db", and\r
1528 not be reflected in the security data base "dbx".\r
45bf2c47 1529\r
dc204d5a
JY
1530 Caution: This function may receive untrusted input.\r
1531 PE/COFF image is external input, so this function will validate its data structure\r
1532 within this image buffer before use.\r
1533\r
45bf2c47 1534 @param[in] AuthenticationStatus\r
0c18794e 1535 This is the authentication status returned from the security\r
1536 measurement services for the input file.\r
1537 @param[in] File This is a pointer to the device path of the file that is\r
1538 being dispatched. This will optionally be used for logging.\r
1539 @param[in] FileBuffer File buffer matches the input file device path.\r
1540 @param[in] FileSize Size of File buffer matches the input file device path.\r
5db28a67
LG
1541 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
1542\r
1543 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
1544 FileBuffer did authenticate, and the platform policy dictates\r
1545 that the DXE Foundation may use the file.\r
1546 @retval EFI_SUCCESS The device path specified by NULL device path DevicePath\r
1547 and non-NULL FileBuffer did authenticate, and the platform\r
1548 policy dictates that the DXE Foundation may execute the image in\r
1549 FileBuffer.\r
570b3d1a 1550 @retval EFI_OUT_RESOURCE Fail to allocate memory.\r
0c18794e 1551 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
1552 the platform policy dictates that File should be placed\r
5db28a67
LG
1553 in the untrusted state. The image has been added to the file\r
1554 execution table.\r
1555 @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r
1556 authenticate, and the platform policy dictates that the DXE\r
1557 Foundation many not use File.\r
0c18794e 1558\r
1559**/\r
1560EFI_STATUS\r
1561EFIAPI\r
1562DxeImageVerificationHandler (\r
1563 IN UINT32 AuthenticationStatus,\r
1564 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
1565 IN VOID *FileBuffer,\r
5db28a67
LG
1566 IN UINTN FileSize,\r
1567 IN BOOLEAN BootPolicy\r
0c18794e 1568 )\r
0c18794e 1569{\r
551d8081 1570 EFI_STATUS Status;\r
551d8081 1571 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1572 EFI_STATUS VerifyStatus;\r
551d8081 1573 EFI_SIGNATURE_LIST *SignatureList;\r
1574 UINTN SignatureListSize;\r
1575 EFI_SIGNATURE_DATA *Signature;\r
1576 EFI_IMAGE_EXECUTION_ACTION Action;\r
1577 WIN_CERTIFICATE *WinCertificate;\r
1578 UINT32 Policy;\r
560ac77e 1579 UINT8 *SecureBoot;\r
551d8081 1580 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
1581 UINT32 NumberOfRvaAndSizes;\r
f6f9031f 1582 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
1583 WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;\r
1584 UINT8 *AuthData;\r
1585 UINTN AuthDataSize;\r
1586 EFI_IMAGE_DATA_DIRECTORY *SecDataDir;\r
6de4c35f 1587 UINT32 OffSet;\r
213cc100 1588 CHAR16 *NameStr;\r
0c18794e 1589\r
0c18794e 1590 SignatureList = NULL;\r
1591 SignatureListSize = 0;\r
1592 WinCertificate = NULL;\r
f6f9031f 1593 SecDataDir = NULL;\r
1594 PkcsCertData = NULL;\r
0c18794e 1595 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
1596 Status = EFI_ACCESS_DENIED;\r
6de4c35f 1597 VerifyStatus = EFI_ACCESS_DENIED;\r
1598\r
4fc08e8d 1599\r
0c18794e 1600 //\r
1601 // Check the image type and get policy setting.\r
1602 //\r
1603 switch (GetImageType (File)) {\r
45bf2c47 1604\r
0c18794e 1605 case IMAGE_FROM_FV:\r
1606 Policy = ALWAYS_EXECUTE;\r
1607 break;\r
1608\r
1609 case IMAGE_FROM_OPTION_ROM:\r
1610 Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);\r
1611 break;\r
1612\r
1613 case IMAGE_FROM_REMOVABLE_MEDIA:\r
1614 Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);\r
1615 break;\r
1616\r
1617 case IMAGE_FROM_FIXED_MEDIA:\r
1618 Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);\r
1619 break;\r
1620\r
1621 default:\r
45bf2c47 1622 Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;\r
0c18794e 1623 break;\r
1624 }\r
1625 //\r
1626 // If policy is always/never execute, return directly.\r
1627 //\r
1628 if (Policy == ALWAYS_EXECUTE) {\r
1629 return EFI_SUCCESS;\r
1630 } else if (Policy == NEVER_EXECUTE) {\r
1631 return EFI_ACCESS_DENIED;\r
1632 }\r
beda2356 1633\r
db44ea6c 1634 //\r
20333c6d 1635 // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION\r
68fc0c73 1636 // violates the UEFI spec and has been removed.\r
db44ea6c 1637 //\r
68fc0c73
FS
1638 ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);\r
1639 if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {\r
db44ea6c
FS
1640 CpuDeadLoop ();\r
1641 }\r
1642\r
560ac77e 1643 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
beda2356 1644 //\r
8f8ca22e 1645 // Skip verification if SecureBoot variable doesn't exist.\r
beda2356 1646 //\r
560ac77e 1647 if (SecureBoot == NULL) {\r
beda2356 1648 return EFI_SUCCESS;\r
1649 }\r
1650\r
1651 //\r
4fc08e8d 1652 // Skip verification if SecureBoot is disabled but not AuditMode\r
beda2356 1653 //\r
560ac77e
ZC
1654 if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
1655 FreePool (SecureBoot);\r
beda2356 1656 return EFI_SUCCESS;\r
45bf2c47 1657 }\r
560ac77e 1658 FreePool (SecureBoot);\r
551d8081 1659\r
0c18794e 1660 //\r
1661 // Read the Dos header.\r
1662 //\r
570b3d1a 1663 if (FileBuffer == NULL) {\r
570b3d1a 1664 return EFI_INVALID_PARAMETER;\r
1665 }\r
551d8081 1666\r
0c18794e 1667 mImageBase = (UINT8 *) FileBuffer;\r
1668 mImageSize = FileSize;\r
28186d45
ED
1669\r
1670 ZeroMem (&ImageContext, sizeof (ImageContext));\r
1671 ImageContext.Handle = (VOID *) FileBuffer;\r
e0192326 1672 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;\r
28186d45
ED
1673\r
1674 //\r
1675 // Get information about the image being loaded\r
1676 //\r
1677 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
1678 if (EFI_ERROR (Status)) {\r
1679 //\r
1680 // The information can't be got from the invalid PeImage\r
1681 //\r
531c89a1 1682 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information.\n"));\r
28186d45
ED
1683 goto Done;\r
1684 }\r
1685\r
badd40f9 1686 Status = EFI_ACCESS_DENIED;\r
1687\r
1688 DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;\r
0c18794e 1689 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1690 //\r
45bf2c47 1691 // DOS image header is present,\r
0c18794e 1692 // so read the PE header after the DOS image header.\r
1693 //\r
1694 mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
1695 } else {\r
1696 mPeCoffHeaderOffset = 0;\r
1697 }\r
1698 //\r
1699 // Check PE/COFF image.\r
1700 //\r
1701 mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);\r
1702 if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1703 //\r
1704 // It is not a valid Pe/Coff file.\r
1705 //\r
531c89a1 1706 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Not a valid PE/COFF image.\n"));\r
551d8081 1707 goto Done;\r
0c18794e 1708 }\r
1709\r
f199664c 1710 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
0c18794e 1711 //\r
1712 // Use PE32 offset.\r
1713 //\r
551d8081 1714 NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1715 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
f6f9031f 1716 SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
20333c6d 1717 }\r
570b3d1a 1718 } else {\r
1719 //\r
551d8081 1720 // Use PE32+ offset.\r
570b3d1a 1721 //\r
551d8081 1722 NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1723 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
f6f9031f 1724 SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
551d8081 1725 }\r
0c18794e 1726 }\r
1727\r
6de4c35f 1728 //\r
1729 // Start Image Validation.\r
1730 //\r
1731 if (SecDataDir == NULL || SecDataDir->Size == 0) {\r
0c18794e 1732 //\r
20333c6d 1733 // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",\r
6de4c35f 1734 // and not be reflected in the security data base "dbx".\r
0c18794e 1735 //\r
45bf2c47 1736 if (!HashPeImage (HASHALG_SHA256)) {\r
531c89a1 1737 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", mHashTypeStr));\r
45bf2c47 1738 goto Done;\r
1739 }\r
1740\r
1741 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1742 //\r
1743 // Image Hash is in forbidden database (DBX).\r
1744 //\r
531c89a1 1745 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX.\n", mHashTypeStr));\r
45bf2c47 1746 goto Done;\r
1747 }\r
1748\r
1749 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
1750 //\r
1751 // Image Hash is in allowed database (DB).\r
1752 //\r
1753 return EFI_SUCCESS;\r
1754 }\r
1755\r
1756 //\r
1757 // Image Hash is not found in both forbidden and allowed database.\r
1758 //\r
531c89a1 1759 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));\r
45bf2c47 1760 goto Done;\r
0c18794e 1761 }\r
45bf2c47 1762\r
0c18794e 1763 //\r
20333c6d 1764 // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7\r
6de4c35f 1765 // "Attribute Certificate Table".\r
1766 // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.\r
0c18794e 1767 //\r
6de4c35f 1768 for (OffSet = SecDataDir->VirtualAddress;\r
1769 OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);\r
2bf41ed7 1770 OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) {\r
6de4c35f 1771 WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);\r
1772 if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||\r
1773 (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {\r
1774 break;\r
1775 }\r
20333c6d 1776\r
0c18794e 1777 //\r
6de4c35f 1778 // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.\r
0c18794e 1779 //\r
6de4c35f 1780 if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
1781 //\r
20333c6d 1782 // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the\r
6de4c35f 1783 // Authenticode specification.\r
1784 //\r
1785 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;\r
1786 if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {\r
1787 break;\r
1788 }\r
1789 AuthData = PkcsCertData->CertData;\r
1790 AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);\r
1791 } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
1792 //\r
1793 // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.\r
1794 //\r
1795 WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;\r
1796 if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
1797 break;\r
1798 }\r
1799 if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {\r
1800 continue;\r
1801 }\r
1802 AuthData = WinCertUefiGuid->CertData;\r
1803 AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);\r
1804 } else {\r
1805 if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {\r
1806 break;\r
1807 }\r
1808 continue;\r
84bce75b 1809 }\r
6de4c35f 1810\r
f6f9031f 1811 Status = HashPeImageByType (AuthData, AuthDataSize);\r
45bf2c47 1812 if (EFI_ERROR (Status)) {\r
6de4c35f 1813 continue;\r
0c18794e 1814 }\r
20333c6d 1815\r
f6f9031f 1816 //\r
6de4c35f 1817 // Check the digital signature against the revoked certificate in forbidden database (dbx).\r
f6f9031f 1818 //\r
560ac77e 1819 if (IsForbiddenByDbx (AuthData, AuthDataSize)) {\r
6de4c35f 1820 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
1821 VerifyStatus = EFI_ACCESS_DENIED;\r
1822 break;\r
f6f9031f 1823 }\r
0c18794e 1824\r
1825 //\r
6de4c35f 1826 // Check the digital signature against the valid certificate in allowed database (db).\r
0c18794e 1827 //\r
6de4c35f 1828 if (EFI_ERROR (VerifyStatus)) {\r
560ac77e 1829 if (IsAllowedByDb (AuthData, AuthDataSize)) {\r
6de4c35f 1830 VerifyStatus = EFI_SUCCESS;\r
1831 }\r
0c18794e 1832 }\r
6de4c35f 1833\r
0c18794e 1834 //\r
6de4c35f 1835 // Check the image's hash value.\r
0c18794e 1836 //\r
6de4c35f 1837 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1838 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
531c89a1 1839 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but %s hash of image is found in DBX.\n", mHashTypeStr));\r
6de4c35f 1840 VerifyStatus = EFI_ACCESS_DENIED;\r
1841 break;\r
1842 } else if (EFI_ERROR (VerifyStatus)) {\r
1843 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
1844 VerifyStatus = EFI_SUCCESS;\r
531c89a1
CS
1845 } else {\r
1846 DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is not allowed by DB and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));\r
6de4c35f 1847 }\r
45bf2c47 1848 }\r
50fe73a1 1849 }\r
1850\r
6de4c35f 1851 if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {\r
0c18794e 1852 //\r
6de4c35f 1853 // The Size in Certificate Table or the attribute certicate table is corrupted.\r
0c18794e 1854 //\r
6de4c35f 1855 VerifyStatus = EFI_ACCESS_DENIED;\r
1856 }\r
20333c6d 1857\r
6de4c35f 1858 if (!EFI_ERROR (VerifyStatus)) {\r
1859 return EFI_SUCCESS;\r
1860 } else {\r
1861 Status = EFI_ACCESS_DENIED;\r
1862 if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {\r
1863 //\r
1864 // Get image hash value as executable's signature.\r
1865 //\r
1866 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
1867 SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
1868 if (SignatureList == NULL) {\r
1869 Status = EFI_OUT_OF_RESOURCES;\r
1870 goto Done;\r
1871 }\r
1872 SignatureList->SignatureHeaderSize = 0;\r
1873 SignatureList->SignatureListSize = (UINT32) SignatureListSize;\r
13a220a9 1874 SignatureList->SignatureSize = (UINT32) (sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize);\r
6de4c35f 1875 CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
1876 Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
1877 CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
50fe73a1 1878 }\r
0c18794e 1879 }\r
1880\r
1881Done:\r
1882 if (Status != EFI_SUCCESS) {\r
1883 //\r
1884 // Policy decides to defer or reject the image; add its information in image executable information table.\r
1885 //\r
213cc100
DG
1886 NameStr = ConvertDevicePathToText (File, FALSE, TRUE);\r
1887 AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize);\r
1888 if (NameStr != NULL) {\r
1889 DEBUG((EFI_D_INFO, "The image doesn't pass verification: %s\n", NameStr));\r
1890 FreePool(NameStr);\r
1891 }\r
5db28a67 1892 Status = EFI_SECURITY_VIOLATION;\r
0c18794e 1893 }\r
1894\r
1895 if (SignatureList != NULL) {\r
1896 FreePool (SignatureList);\r
1897 }\r
1898\r
0c18794e 1899 return Status;\r
1900}\r
1901\r
ffccb935
DG
1902/**\r
1903 On Ready To Boot Services Event notification handler.\r
1904\r
1905 Add the image execution information table if it is not in system configuration table.\r
1906\r
1907 @param[in] Event Event whose notification function is being invoked\r
1908 @param[in] Context Pointer to the notification function's context\r
1909\r
1910**/\r
1911VOID\r
1912EFIAPI\r
1913OnReadyToBoot (\r
1914 IN EFI_EVENT Event,\r
1915 IN VOID *Context\r
1916 )\r
1917{\r
1918 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;\r
1919 UINTN ImageExeInfoTableSize;\r
1920\r
1921 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
1922 if (ImageExeInfoTable != NULL) {\r
1923 return;\r
1924 }\r
1925\r
1926 ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
1927 ImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize);\r
1928 if (ImageExeInfoTable == NULL) {\r
1929 return ;\r
1930 }\r
1931\r
20333c6d 1932 ImageExeInfoTable->NumberOfImages = 0;\r
ffccb935
DG
1933 gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) ImageExeInfoTable);\r
1934\r
1935}\r
1936\r
0c18794e 1937/**\r
1938 Register security measurement handler.\r
1939\r
1940 @param ImageHandle ImageHandle of the loaded driver.\r
1941 @param SystemTable Pointer to the EFI System Table.\r
1942\r
1943 @retval EFI_SUCCESS The handlers were registered successfully.\r
1944**/\r
1945EFI_STATUS\r
1946EFIAPI\r
1947DxeImageVerificationLibConstructor (\r
1948 IN EFI_HANDLE ImageHandle,\r
1949 IN EFI_SYSTEM_TABLE *SystemTable\r
1950 )\r
1951{\r
ffccb935
DG
1952 EFI_EVENT Event;\r
1953\r
1954 //\r
1955 // Register the event to publish the image execution table.\r
1956 //\r
1957 EfiCreateEventReadyToBootEx (\r
1958 TPL_CALLBACK,\r
20333c6d
QL
1959 OnReadyToBoot,\r
1960 NULL,\r
ffccb935 1961 &Event\r
20333c6d 1962 );\r
ffccb935 1963\r
5db28a67 1964 return RegisterSecurity2Handler (\r
0c18794e 1965 DxeImageVerificationHandler,\r
1966 EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
45bf2c47 1967 );\r
0c18794e 1968}\r