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