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