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