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