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