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