1. Add more error handling code to DxeImageVerificationLib and BaseCryptLib.
[mirror_edk2.git] / SecurityPkg / Library / DxeImageVerificationLib / DxeImageVerificationLib.c
CommitLineData
0c18794e 1/** @file\r
2 Implement image verification services for secure boot service in UEFI2.3.1.\r
3\r
bd0de396 4Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
45bf2c47 5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
0c18794e 8http://opensource.org/licenses/bsd-license.php\r
9\r
45bf2c47 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
0c18794e 11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "DxeImageVerificationLib.h"\r
16\r
17EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
18UINTN mImageSize;\r
45bf2c47 19UINT32 mPeCoffHeaderOffset;\r
0c18794e 20UINT8 mImageDigest[MAX_DIGEST_SIZE];\r
21UINTN mImageDigestSize;\r
22EFI_IMAGE_DATA_DIRECTORY *mSecDataDir = NULL;\r
23UINT8 *mImageBase = NULL;\r
24EFI_GUID mCertType;\r
25\r
26//\r
27// Notify string for authorization UI.\r
28//\r
29CHAR16 mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"Image verification pass but not found in authorized database!";\r
30CHAR16 mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"Launch this image anyway? (Yes/Defer/No)";\r
31//\r
32// Public Exponent of RSA Key.\r
33//\r
34CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
35\r
36\r
37//\r
38// OID ASN.1 Value for Hash Algorithms\r
39//\r
40UINT8 mHashOidValue[] = {\r
41 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, // OBJ_md5\r
42 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1\r
43 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224\r
44 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256\r
45 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384\r
46 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512\r
47 };\r
48\r
49HASH_TABLE mHash[] = {\r
50 { L"SHA1", 20, &mHashOidValue[8], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },\r
51 { L"SHA224", 28, &mHashOidValue[13], 9, NULL, NULL, NULL, NULL },\r
52 { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize,Sha256Init, Sha256Update, Sha256Final},\r
53 { L"SHA384", 48, &mHashOidValue[31], 9, NULL, NULL, NULL, NULL },\r
54 { L"SHA512", 64, &mHashOidValue[40], 9, NULL, NULL, NULL, NULL }\r
55};\r
56\r
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
bd0de396 489 // Fixed offset (+32) is calculated based on two bytes of length encoding.\r
45bf2c47 490 //\r
bd0de396 491 if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
492 //\r
493 // Only support two bytes of Long Form of Length Encoding.\r
494 //\r
495 continue;\r
496 }\r
497\r
0c18794e 498 if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
499 break;\r
500 }\r
501 }\r
502\r
503 if (Index == HASHALG_MAX) {\r
504 return EFI_UNSUPPORTED;\r
505 }\r
506\r
507 //\r
508 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.\r
509 //\r
510 if (!HashPeImage(Index)) {\r
511 return EFI_UNSUPPORTED;\r
512 }\r
513\r
514 return EFI_SUCCESS;\r
515}\r
516\r
517\r
518/**\r
519 Returns the size of a given image execution info table in bytes.\r
520\r
521 This function returns the size, in bytes, of the image execution info table specified by\r
522 ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.\r
523\r
524 @param ImageExeInfoTable A pointer to a image execution info table structure.\r
45bf2c47 525\r
0c18794e 526 @retval 0 If ImageExeInfoTable is NULL.\r
527 @retval Others The size of a image execution info table in bytes.\r
528\r
529**/\r
530UINTN\r
531GetImageExeInfoTableSize (\r
532 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable\r
533 )\r
534{\r
535 UINTN Index;\r
536 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem;\r
537 UINTN TotalSize;\r
538\r
539 if (ImageExeInfoTable == NULL) {\r
540 return 0;\r
541 }\r
542\r
543 ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE));\r
544 TotalSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
545 for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) {\r
546 TotalSize += ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize);\r
547 ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoItem + ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize));\r
548 }\r
549\r
550 return TotalSize;\r
551}\r
552\r
553/**\r
554 Create an Image Execution Information Table entry and add it to system configuration table.\r
555\r
556 @param[in] Action Describes the action taken by the firmware regarding this image.\r
557 @param[in] Name Input a null-terminated, user-friendly name.\r
558 @param[in] DevicePath Input device path pointer.\r
559 @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.\r
560 @param[in] SignatureSize Size of signature.\r
45bf2c47 561\r
0c18794e 562**/\r
563VOID\r
564AddImageExeInfo (\r
45bf2c47 565 IN EFI_IMAGE_EXECUTION_ACTION Action,\r
566 IN CHAR16 *Name OPTIONAL,\r
0c18794e 567 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
568 IN EFI_SIGNATURE_LIST *Signature OPTIONAL,\r
569 IN UINTN SignatureSize\r
570 )\r
571{\r
0c18794e 572 EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;\r
573 EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable;\r
574 EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry;\r
575 UINTN ImageExeInfoTableSize;\r
576 UINTN NewImageExeInfoEntrySize;\r
577 UINTN NameStringLen;\r
578 UINTN DevicePathSize;\r
579\r
0c18794e 580 ImageExeInfoTable = NULL;\r
581 NewImageExeInfoTable = NULL;\r
582 ImageExeInfoEntry = NULL;\r
583 NameStringLen = 0;\r
584\r
570b3d1a 585 if (DevicePath == NULL) {\r
586 return ;\r
587 }\r
45bf2c47 588\r
0c18794e 589 if (Name != NULL) {\r
590 NameStringLen = StrSize (Name);\r
591 }\r
592\r
593 ImageExeInfoTable = NULL;\r
45bf2c47 594 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
0c18794e 595 if (ImageExeInfoTable != NULL) {\r
596 //\r
597 // The table has been found!\r
598 // We must enlarge the table to accmodate the new exe info entry.\r
599 //\r
600 ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);\r
601 } else {\r
602 //\r
603 // Not Found!\r
604 // We should create a new table to append to the configuration table.\r
605 //\r
606 ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
607 }\r
608\r
609 DevicePathSize = GetDevicePathSize (DevicePath);\r
610 NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;\r
611 NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);\r
570b3d1a 612 if (NewImageExeInfoTable == NULL) {\r
613 return ;\r
614 }\r
0c18794e 615\r
616 if (ImageExeInfoTable != NULL) {\r
617 CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);\r
618 } else {\r
619 NewImageExeInfoTable->NumberOfImages = 0;\r
620 }\r
621 NewImageExeInfoTable->NumberOfImages++;\r
622 ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);\r
623 //\r
624 // Update new item's infomation.\r
625 //\r
626 WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->Action, Action);\r
627 WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->InfoSize, (UINT32) NewImageExeInfoEntrySize);\r
628\r
629 if (Name != NULL) {\r
630 CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen);\r
631 }\r
632 CopyMem (\r
633 (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen,\r
634 DevicePath,\r
635 DevicePathSize\r
636 );\r
637 if (Signature != NULL) {\r
638 CopyMem (\r
639 (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize,\r
640 Signature,\r
641 SignatureSize\r
642 );\r
643 }\r
644 //\r
645 // Update/replace the image execution table.\r
646 //\r
570b3d1a 647 gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);\r
45bf2c47 648\r
0c18794e 649 //\r
650 // Free Old table data!\r
651 //\r
652 if (ImageExeInfoTable != NULL) {\r
653 FreePool (ImageExeInfoTable);\r
654 }\r
655}\r
656\r
657/**\r
658 Discover if the UEFI image is authorized by user's policy setting.\r
659\r
45bf2c47 660 @param[in] Policy Specify platform's policy setting.\r
0c18794e 661\r
662 @retval EFI_ACCESS_DENIED Image is not allowed to run.\r
663 @retval EFI_SECURITY_VIOLATION Image is deferred.\r
664 @retval EFI_SUCCESS Image is authorized to run.\r
665\r
666**/\r
667EFI_STATUS\r
668ImageAuthorization (\r
669 IN UINT32 Policy\r
670 )\r
671{\r
672 EFI_STATUS Status;\r
673 EFI_INPUT_KEY Key;\r
674\r
675 Status = EFI_ACCESS_DENIED;\r
676\r
677 switch (Policy) {\r
45bf2c47 678\r
0c18794e 679 case QUERY_USER_ON_SECURITY_VIOLATION:\r
680 do {\r
681 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL);\r
682 if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {\r
683 Status = EFI_SUCCESS;\r
684 break;\r
685 } else if (Key.UnicodeChar == L'N' || Key.UnicodeChar == L'n') {\r
686 Status = EFI_ACCESS_DENIED;\r
687 break;\r
688 } else if (Key.UnicodeChar == L'D' || Key.UnicodeChar == L'd') {\r
689 Status = EFI_SECURITY_VIOLATION;\r
690 break;\r
691 }\r
692 } while (TRUE);\r
693 break;\r
694\r
695 case ALLOW_EXECUTE_ON_SECURITY_VIOLATION:\r
696 Status = EFI_SUCCESS;\r
697 break;\r
698\r
699 case DEFER_EXECUTE_ON_SECURITY_VIOLATION:\r
700 Status = EFI_SECURITY_VIOLATION;\r
701 break;\r
702\r
703 case DENY_EXECUTE_ON_SECURITY_VIOLATION:\r
704 Status = EFI_ACCESS_DENIED;\r
705 break;\r
706 }\r
707\r
708 return Status;\r
709}\r
710\r
711/**\r
712 Check whether signature is in specified database.\r
713\r
714 @param[in] VariableName Name of database variable that is searched in.\r
715 @param[in] Signature Pointer to signature that is searched for.\r
716 @param[in] CertType Pointer to hash algrithom.\r
717 @param[in] SignatureSize Size of Signature.\r
718\r
719 @return TRUE Found the signature in the variable database.\r
720 @return FALSE Not found the signature in the variable database.\r
721\r
722**/\r
723BOOLEAN\r
724IsSignatureFoundInDatabase (\r
725 IN CHAR16 *VariableName,\r
45bf2c47 726 IN UINT8 *Signature,\r
0c18794e 727 IN EFI_GUID *CertType,\r
728 IN UINTN SignatureSize\r
729 )\r
730{\r
731 EFI_STATUS Status;\r
732 EFI_SIGNATURE_LIST *CertList;\r
733 EFI_SIGNATURE_DATA *Cert;\r
734 UINTN DataSize;\r
735 UINT8 *Data;\r
736 UINTN Index;\r
737 UINTN CertCount;\r
738 BOOLEAN IsFound;\r
739 //\r
740 // Read signature database variable.\r
741 //\r
742 IsFound = FALSE;\r
743 Data = NULL;\r
744 DataSize = 0;\r
745 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
746 if (Status != EFI_BUFFER_TOO_SMALL) {\r
747 return FALSE;\r
748 }\r
749\r
750 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
570b3d1a 751 if (Data == NULL) {\r
752 return FALSE;\r
753 }\r
0c18794e 754\r
755 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
756 if (EFI_ERROR (Status)) {\r
757 goto Done;\r
758 }\r
759 //\r
760 // Enumerate all signature data in SigDB to check if executable's signature exists.\r
761 //\r
762 CertList = (EFI_SIGNATURE_LIST *) Data;\r
763 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
764 CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
765 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
766 if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {\r
767 for (Index = 0; Index < CertCount; Index++) {\r
768 if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {\r
769 //\r
770 // Find the signature in database.\r
771 //\r
772 IsFound = TRUE;\r
773 break;\r
774 }\r
775\r
776 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
777 }\r
778\r
779 if (IsFound) {\r
780 break;\r
781 }\r
782 }\r
783\r
784 DataSize -= CertList->SignatureListSize;\r
785 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
786 }\r
787\r
788Done:\r
789 if (Data != NULL) {\r
790 FreePool (Data);\r
791 }\r
792\r
793 return IsFound;\r
794}\r
795\r
796/**\r
45bf2c47 797 Verify PKCS#7 SignedData using certificate found in Variable which formatted\r
798 as EFI_SIGNATURE_LIST. The Variable may be PK, KEK, DB or DBX.\r
0c18794e 799\r
45bf2c47 800 @param VariableName Name of Variable to search for Certificate.\r
801 @param VendorGuid Variable vendor GUID.\r
802\r
803 @retval TRUE Image pass verification.\r
804 @retval FALSE Image fail verification.\r
0c18794e 805\r
806**/\r
45bf2c47 807BOOLEAN\r
808IsPkcsSignedDataVerifiedBySignatureList (\r
809 IN CHAR16 *VariableName,\r
810 IN EFI_GUID *VendorGuid\r
0c18794e 811 )\r
812{\r
813 EFI_STATUS Status;\r
814 BOOLEAN VerifyStatus;\r
815 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
816 EFI_SIGNATURE_LIST *CertList;\r
817 EFI_SIGNATURE_DATA *Cert;\r
818 UINTN DataSize;\r
45bf2c47 819 UINT8 *Data;\r
0c18794e 820 UINT8 *RootCert;\r
821 UINTN RootCertSize;\r
822 UINTN Index;\r
823 UINTN CertCount;\r
824\r
45bf2c47 825 Data = NULL;\r
826 CertList = NULL;\r
827 Cert = NULL;\r
828 RootCert = NULL;\r
829 RootCertSize = 0;\r
830 VerifyStatus = FALSE;\r
831 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);\r
0c18794e 832\r
0c18794e 833 DataSize = 0;\r
45bf2c47 834 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);\r
0c18794e 835 if (Status == EFI_BUFFER_TOO_SMALL) {\r
45bf2c47 836 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
837 if (Data == NULL) {\r
838 return VerifyStatus;\r
570b3d1a 839 }\r
0c18794e 840\r
45bf2c47 841 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, (VOID *) Data);\r
0c18794e 842 if (EFI_ERROR (Status)) {\r
843 goto Done;\r
844 }\r
45bf2c47 845\r
846 //\r
847 // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.\r
0c18794e 848 //\r
45bf2c47 849 CertList = (EFI_SIGNATURE_LIST *) Data;\r
0c18794e 850 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
851 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
852 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
853 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
854 for (Index = 0; Index < CertCount; Index++) {\r
855 //\r
45bf2c47 856 // Iterate each Signature Data Node within this CertList for verify.\r
857 //\r
0c18794e 858 RootCert = Cert->SignatureData;\r
859 RootCertSize = CertList->SignatureSize;\r
45bf2c47 860\r
0c18794e 861 //\r
45bf2c47 862 // Call AuthenticodeVerify library to Verify Authenticode struct.\r
0c18794e 863 //\r
864 VerifyStatus = AuthenticodeVerify (\r
865 PkcsCertData->CertData,\r
866 mSecDataDir->Size - sizeof(PkcsCertData->Hdr),\r
867 RootCert,\r
868 RootCertSize,\r
869 mImageDigest,\r
870 mImageDigestSize\r
871 );\r
0c18794e 872 if (VerifyStatus) {\r
873 goto Done;\r
874 }\r
875 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
45bf2c47 876 }\r
0c18794e 877 }\r
878 DataSize -= CertList->SignatureListSize;\r
879 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
880 }\r
881 }\r
882\r
45bf2c47 883Done:\r
884 if (Data != NULL) {\r
885 FreePool (Data);\r
886 }\r
0c18794e 887\r
45bf2c47 888 return VerifyStatus;\r
889}\r
0c18794e 890\r
45bf2c47 891/**\r
892 Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format.\r
0c18794e 893\r
45bf2c47 894 @retval EFI_SUCCESS Image pass verification.\r
895 @retval EFI_SECURITY_VIOLATION Image fail verification.\r
0c18794e 896\r
45bf2c47 897**/\r
898EFI_STATUS\r
899VerifyCertPkcsSignedData (\r
900 VOID\r
901 )\r
902{\r
903 //\r
904 // 1: Find certificate from DBX forbidden database for revoked certificate.\r
905 //\r
906 if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {\r
907 //\r
908 // DBX is forbidden database, if Authenticode verification pass with\r
909 // one of the certificate in DBX, this image should be rejected.\r
910 //\r
911 return EFI_SECURITY_VIOLATION;\r
570b3d1a 912 }\r
913\r
45bf2c47 914 //\r
915 // 2: Find certificate from KEK database and try to verify authenticode struct.\r
916 //\r
917 if (IsPkcsSignedDataVerifiedBySignatureList (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid)) {\r
918 return EFI_SUCCESS;\r
0c18794e 919 }\r
920\r
45bf2c47 921 //\r
922 // 3: Find certificate from DB database and try to verify authenticode struct.\r
923 //\r
924 if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {\r
0c18794e 925 return EFI_SUCCESS;\r
926 } else {\r
927 return EFI_SECURITY_VIOLATION;\r
928 }\r
929}\r
930\r
931/**\r
45bf2c47 932 Verify certificate in WIN_CERTIFICATE_UEFI_GUID format.\r
0c18794e 933\r
934 @retval EFI_SUCCESS Image pass verification.\r
935 @retval EFI_SECURITY_VIOLATION Image fail verification.\r
936 @retval other error value\r
937\r
938**/\r
45bf2c47 939EFI_STATUS\r
0c18794e 940VerifyCertUefiGuid (\r
941 VOID\r
942 )\r
943{\r
944 BOOLEAN Status;\r
945 WIN_CERTIFICATE_UEFI_GUID *EfiCert;\r
946 EFI_SIGNATURE_LIST *KekList;\r
947 EFI_SIGNATURE_DATA *KekItem;\r
948 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
949 VOID *Rsa;\r
950 UINTN KekCount;\r
951 UINTN Index;\r
952 UINTN KekDataSize;\r
953 BOOLEAN IsFound;\r
954 EFI_STATUS Result;\r
955\r
956 EfiCert = NULL;\r
957 KekList = NULL;\r
958 KekItem = NULL;\r
959 CertBlock = NULL;\r
960 Rsa = NULL;\r
961 Status = FALSE;\r
962 IsFound = FALSE;\r
963 KekDataSize = 0;\r
964\r
965 EfiCert = (WIN_CERTIFICATE_UEFI_GUID *) (mImageBase + mSecDataDir->VirtualAddress);\r
966 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) EfiCert->CertData;\r
967 if (!CompareGuid (&EfiCert->CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r
968 //\r
969 // Invalid Certificate Data Type.\r
970 //\r
971 return EFI_SECURITY_VIOLATION;\r
972 }\r
973\r
974 //\r
975 // Get KEK database variable data size\r
976 //\r
977 Result = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &KekDataSize, NULL);\r
978 if (Result != EFI_BUFFER_TOO_SMALL) {\r
979 return EFI_SECURITY_VIOLATION;\r
980 }\r
981\r
982 //\r
983 // Get KEK database variable.\r
984 //\r
985 KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME);\r
986 if (KekList == NULL) {\r
987 return EFI_SECURITY_VIOLATION;\r
988 }\r
45bf2c47 989\r
0c18794e 990 //\r
991 // Enumerate all Kek items in this list to verify the variable certificate data.\r
992 // If anyone is authenticated successfully, it means the variable is correct!\r
993 //\r
994 while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
995 if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
996 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
997 KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
998 for (Index = 0; Index < KekCount; Index++) {\r
999 if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
1000 IsFound = TRUE;\r
1001 break;\r
1002 }\r
1003 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
1004 }\r
1005 }\r
1006 KekDataSize -= KekList->SignatureListSize;\r
1007 KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
1008 }\r
45bf2c47 1009\r
0c18794e 1010 if (!IsFound) {\r
1011 //\r
1012 // Signed key is not a trust one.\r
1013 //\r
1014 goto Done;\r
1015 }\r
1016\r
1017 //\r
1018 // Now, we found the corresponding security policy.\r
1019 // Verify the data payload.\r
1020 //\r
1021 Rsa = RsaNew ();\r
570b3d1a 1022 if (Rsa == NULL) {\r
1023 Status = FALSE;\r
1024 goto Done;\r
1025 }\r
45bf2c47 1026\r
1027 //\r
0c18794e 1028 // Set RSA Key Components.\r
1029 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
1030 //\r
1031 Status = RsaSetKey (Rsa, RsaKeyN, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
1032 if (!Status) {\r
1033 goto Done;\r
1034 }\r
1035 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
1036 if (!Status) {\r
1037 goto Done;\r
1038 }\r
1039 //\r
1040 // Verify the signature.\r
1041 //\r
1042 Status = RsaPkcs1Verify (\r
45bf2c47 1043 Rsa,\r
1044 mImageDigest,\r
1045 mImageDigestSize,\r
1046 CertBlock->Signature,\r
0c18794e 1047 EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
1048 );\r
45bf2c47 1049\r
0c18794e 1050Done:\r
1051 if (KekList != NULL) {\r
1052 FreePool (KekList);\r
1053 }\r
1054 if (Rsa != NULL ) {\r
1055 RsaFree (Rsa);\r
1056 }\r
1057 if (Status) {\r
1058 return EFI_SUCCESS;\r
1059 } else {\r
1060 return EFI_SECURITY_VIOLATION;\r
1061 }\r
1062}\r
1063\r
1064/**\r
1065 Provide verification service for signed images, which include both signature validation\r
45bf2c47 1066 and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and\r
0c18794e 1067 MSFT Authenticode type signatures are supported.\r
0c18794e 1068\r
45bf2c47 1069 In this implementation, only verify external executables when in USER MODE.\r
1070 Executables from FV is bypass, so pass in AuthenticationStatus is ignored.\r
1071\r
1072 The image verification process is:\r
1073 Is the Image signed?\r
1074 If yes,\r
1075 Does the image verify against a certificate (root or intermediate) in the allowed db?\r
1076 Run it\r
1077 Image verification fail\r
1078 Is the Image's Hash not in forbidden database and the Image's Hash in allowed db?\r
1079 Run it\r
1080 If no,\r
1081 Is the Image's Hash in the forbidden database (DBX)?\r
1082 if yes,\r
1083 Error out\r
1084 Is the Image's Hash in the allowed database (DB)?\r
1085 If yes,\r
1086 Run it\r
1087 If no,\r
1088 Error out\r
1089\r
1090 @param[in] AuthenticationStatus\r
0c18794e 1091 This is the authentication status returned from the security\r
1092 measurement services for the input file.\r
1093 @param[in] File This is a pointer to the device path of the file that is\r
1094 being dispatched. This will optionally be used for logging.\r
1095 @param[in] FileBuffer File buffer matches the input file device path.\r
1096 @param[in] FileSize Size of File buffer matches the input file device path.\r
1097\r
1098 @retval EFI_SUCCESS The file specified by File did authenticate, and the\r
1099 platform policy dictates that the DXE Core may use File.\r
570b3d1a 1100 @retval EFI_INVALID_PARAMETER Input argument is incorrect.\r
1101 @retval EFI_OUT_RESOURCE Fail to allocate memory.\r
0c18794e 1102 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
1103 the platform policy dictates that File should be placed\r
1104 in the untrusted state. A file may be promoted from\r
1105 the untrusted to the trusted state at a future time\r
1106 with a call to the Trust() DXE Service.\r
1107 @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
1108 the platform policy dictates that File should not be\r
1109 used for any purpose.\r
1110\r
1111**/\r
1112EFI_STATUS\r
1113EFIAPI\r
1114DxeImageVerificationHandler (\r
1115 IN UINT32 AuthenticationStatus,\r
1116 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
1117 IN VOID *FileBuffer,\r
1118 IN UINTN FileSize\r
1119 )\r
0c18794e 1120{\r
1121 EFI_STATUS Status;\r
1122 UINT16 Magic;\r
1123 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1124 EFI_STATUS VerifyStatus;\r
1125 UINT8 *SetupMode;\r
1126 EFI_SIGNATURE_LIST *SignatureList;\r
1127 UINTN SignatureListSize;\r
1128 EFI_SIGNATURE_DATA *Signature;\r
1129 EFI_IMAGE_EXECUTION_ACTION Action;\r
1130 WIN_CERTIFICATE *WinCertificate;\r
1131 UINT32 Policy;\r
beda2356 1132 UINT8 *SecureBootEnable;\r
0c18794e 1133\r
1134 if (File == NULL) {\r
1135 return EFI_INVALID_PARAMETER;\r
1136 }\r
1137\r
1138 SignatureList = NULL;\r
1139 SignatureListSize = 0;\r
1140 WinCertificate = NULL;\r
1141 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
1142 Status = EFI_ACCESS_DENIED;\r
1143 //\r
1144 // Check the image type and get policy setting.\r
1145 //\r
1146 switch (GetImageType (File)) {\r
45bf2c47 1147\r
0c18794e 1148 case IMAGE_FROM_FV:\r
1149 Policy = ALWAYS_EXECUTE;\r
1150 break;\r
1151\r
1152 case IMAGE_FROM_OPTION_ROM:\r
1153 Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);\r
1154 break;\r
1155\r
1156 case IMAGE_FROM_REMOVABLE_MEDIA:\r
1157 Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);\r
1158 break;\r
1159\r
1160 case IMAGE_FROM_FIXED_MEDIA:\r
1161 Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);\r
1162 break;\r
1163\r
1164 default:\r
45bf2c47 1165 Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;\r
0c18794e 1166 break;\r
1167 }\r
1168 //\r
1169 // If policy is always/never execute, return directly.\r
1170 //\r
1171 if (Policy == ALWAYS_EXECUTE) {\r
1172 return EFI_SUCCESS;\r
1173 } else if (Policy == NEVER_EXECUTE) {\r
1174 return EFI_ACCESS_DENIED;\r
1175 }\r
beda2356 1176\r
1177 SecureBootEnable = GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid);\r
1178 //\r
1179 // Skip verification if SecureBootEnable variable doesn't exist.\r
1180 //\r
1181 if (SecureBootEnable == NULL) {\r
1182 return EFI_SUCCESS;\r
1183 }\r
1184\r
1185 //\r
1186 // Skip verification if SecureBootEnable is disabled.\r
1187 //\r
1188 if (*SecureBootEnable == SECURE_BOOT_DISABLE) {\r
1189 FreePool (SecureBootEnable);\r
1190 return EFI_SUCCESS;\r
45bf2c47 1191 }\r
1192\r
0c18794e 1193 SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);\r
1194\r
1195 //\r
1196 // SetupMode doesn't exist means no AuthVar driver is dispatched,\r
1197 // skip verification.\r
1198 //\r
1199 if (SetupMode == NULL) {\r
1200 return EFI_SUCCESS;\r
1201 }\r
1202\r
1203 //\r
1204 // If platform is in SETUP MODE, skip verification.\r
1205 //\r
1206 if (*SetupMode == SETUP_MODE) {\r
1207 FreePool (SetupMode);\r
1208 return EFI_SUCCESS;\r
1209 }\r
1210 //\r
1211 // Read the Dos header.\r
1212 //\r
570b3d1a 1213 if (FileBuffer == NULL) {\r
1214 FreePool (SetupMode);\r
1215 return EFI_INVALID_PARAMETER;\r
1216 }\r
0c18794e 1217 mImageBase = (UINT8 *) FileBuffer;\r
1218 mImageSize = FileSize;\r
45bf2c47 1219 DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;\r
0c18794e 1220 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1221 //\r
45bf2c47 1222 // DOS image header is present,\r
0c18794e 1223 // so read the PE header after the DOS image header.\r
1224 //\r
1225 mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
1226 } else {\r
1227 mPeCoffHeaderOffset = 0;\r
1228 }\r
1229 //\r
1230 // Check PE/COFF image.\r
1231 //\r
1232 mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);\r
1233 if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1234 //\r
1235 // It is not a valid Pe/Coff file.\r
1236 //\r
1237 return EFI_ACCESS_DENIED;\r
1238 }\r
1239\r
1240 Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
1241 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1242 //\r
1243 // Use PE32 offset.\r
1244 //\r
45bf2c47 1245 mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
570b3d1a 1246 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
0c18794e 1247 //\r
1248 // Use PE32+ offset.\r
1249 //\r
45bf2c47 1250 mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
570b3d1a 1251 } else {\r
1252 //\r
1253 // Invalid header magic number.\r
1254 //\r
1255 Status = EFI_INVALID_PARAMETER;\r
1256 goto Done;\r
1257 }\r
1258\r
1259 if (mSecDataDir->VirtualAddress >= mImageSize) {\r
1260 //\r
1261 // Sanity check to see if this file is corrupted.\r
1262 //\r
1263 Status = EFI_INVALID_PARAMETER;\r
1264 goto Done;\r
0c18794e 1265 }\r
1266\r
1267 if (mSecDataDir->Size == 0) {\r
1268 //\r
1269 // This image is not signed.\r
1270 //\r
45bf2c47 1271 if (!HashPeImage (HASHALG_SHA256)) {\r
1272 goto Done;\r
1273 }\r
1274\r
1275 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1276 //\r
1277 // Image Hash is in forbidden database (DBX).\r
1278 //\r
1279 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
1280 Status = EFI_ACCESS_DENIED;\r
1281 goto Done;\r
1282 }\r
1283\r
1284 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
1285 //\r
1286 // Image Hash is in allowed database (DB).\r
1287 //\r
1288 return EFI_SUCCESS;\r
1289 }\r
1290\r
1291 //\r
1292 // Image Hash is not found in both forbidden and allowed database.\r
1293 //\r
0c18794e 1294 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
45bf2c47 1295 Status = EFI_ACCESS_DENIED;\r
1296 goto Done;\r
0c18794e 1297 }\r
45bf2c47 1298\r
0c18794e 1299 //\r
1300 // Verify signature of executables.\r
1301 //\r
1302 WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);\r
1303\r
1304 switch (WinCertificate->wCertificateType) {\r
45bf2c47 1305\r
0c18794e 1306 case WIN_CERT_TYPE_EFI_GUID:\r
1307 //\r
1308 // Verify UEFI GUID type.\r
45bf2c47 1309 //\r
0c18794e 1310 if (!HashPeImage (HASHALG_SHA256)) {\r
1311 goto Done;\r
1312 }\r
1313\r
1314 VerifyStatus = VerifyCertUefiGuid ();\r
1315 break;\r
1316\r
1317 case WIN_CERT_TYPE_PKCS_SIGNED_DATA:\r
1318 //\r
1319 // Verify Pkcs signed data type.\r
1320 //\r
1321 Status = HashPeImageByType();\r
45bf2c47 1322 if (EFI_ERROR (Status)) {\r
0c18794e 1323 goto Done;\r
1324 }\r
1325\r
1326 VerifyStatus = VerifyCertPkcsSignedData ();\r
1327\r
1328 //\r
1329 // For image verification against enrolled certificate(root or intermediate),\r
1330 // no need to check image's hash in the allowed database.\r
1331 //\r
1332 if (!EFI_ERROR (VerifyStatus)) {\r
45bf2c47 1333 if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1334 return EFI_SUCCESS;\r
1335 }\r
0c18794e 1336 }\r
45bf2c47 1337 break;\r
0c18794e 1338\r
1339 default:\r
45bf2c47 1340 Status = EFI_ACCESS_DENIED;\r
1341 goto Done;\r
0c18794e 1342 }\r
1343 //\r
1344 // Get image hash value as executable's signature.\r
1345 //\r
1346 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
1347 SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
570b3d1a 1348 if (SignatureList == NULL) {\r
1349 Status = EFI_OUT_OF_RESOURCES;\r
1350 goto Done;\r
1351 }\r
0c18794e 1352 SignatureList->SignatureHeaderSize = 0;\r
1353 SignatureList->SignatureListSize = (UINT32) SignatureListSize;\r
1354 SignatureList->SignatureSize = (UINT32) mImageDigestSize;\r
1355 CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
1356 Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
1357 CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
1358 //\r
1359 // Signature database check after verification.\r
1360 //\r
1361 if (EFI_ERROR (VerifyStatus)) {\r
1362 //\r
1363 // Verification failure.\r
1364 //\r
45bf2c47 1365 if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize) &&\r
1366 IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {\r
1367 //\r
1368 // Verification fail, Image Hash is not in forbidden database (DBX),\r
1369 // and Image Hash is in allowed database (DB).\r
1370 //\r
1371 Status = EFI_SUCCESS;\r
1372 } else {\r
1373 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
1374 Status = EFI_ACCESS_DENIED;\r
1375 }\r
0c18794e 1376 } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
1377 //\r
1378 // Executable signature verification passes, but is found in forbidden signature database.\r
1379 //\r
1380 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
1381 Status = EFI_ACCESS_DENIED;\r
1382 } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
1383 //\r
1384 // Executable signature is found in authorized signature database.\r
1385 //\r
1386 Status = EFI_SUCCESS;\r
1387 } else {\r
1388 //\r
1389 // Executable signature verification passes, but cannot be found in authorized signature database.\r
1390 // Get platform policy to determine the action.\r
1391 //\r
1392 Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED;\r
1393 Status = ImageAuthorization (Policy);\r
1394 }\r
1395\r
1396Done:\r
1397 if (Status != EFI_SUCCESS) {\r
1398 //\r
1399 // Policy decides to defer or reject the image; add its information in image executable information table.\r
1400 //\r
1401 AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);\r
1402 }\r
1403\r
1404 if (SignatureList != NULL) {\r
1405 FreePool (SignatureList);\r
1406 }\r
1407\r
1408 FreePool (SetupMode);\r
1409\r
1410 return Status;\r
1411}\r
1412\r
1413/**\r
1414 When VariableWriteArchProtocol install, create "SecureBoot" variable.\r
45bf2c47 1415\r
0c18794e 1416 @param[in] Event Event whose notification function is being invoked.\r
1417 @param[in] Context Pointer to the notification function's context.\r
45bf2c47 1418\r
0c18794e 1419**/\r
1420VOID\r
1421EFIAPI\r
1422VariableWriteCallBack (\r
1423 IN EFI_EVENT Event,\r
1424 IN VOID *Context\r
1425 )\r
1426{\r
1427 UINT8 SecureBootMode;\r
1428 UINT8 *SecureBootModePtr;\r
1429 EFI_STATUS Status;\r
1430 VOID *ProtocolPointer;\r
1431\r
1432 Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, &ProtocolPointer);\r
1433 if (EFI_ERROR (Status)) {\r
1434 return;\r
1435 }\r
45bf2c47 1436\r
0c18794e 1437 //\r
1438 // Check whether "SecureBoot" variable exists.\r
1439 // If this library is built-in, it means firmware has capability to perform\r
1440 // driver signing verification.\r
1441 //\r
1442 SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME);\r
1443 if (SecureBootModePtr == NULL) {\r
1444 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
1445 //\r
1446 // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable.\r
1447 //\r
1448 gRT->SetVariable (\r
1449 EFI_SECURE_BOOT_MODE_NAME,\r
1450 &gEfiGlobalVariableGuid,\r
1451 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1452 sizeof (UINT8),\r
1453 &SecureBootMode\r
1454 );\r
1455 } else {\r
1456 FreePool (SecureBootModePtr);\r
1457 }\r
45bf2c47 1458}\r
0c18794e 1459\r
1460/**\r
1461 Register security measurement handler.\r
1462\r
1463 @param ImageHandle ImageHandle of the loaded driver.\r
1464 @param SystemTable Pointer to the EFI System Table.\r
1465\r
1466 @retval EFI_SUCCESS The handlers were registered successfully.\r
1467**/\r
1468EFI_STATUS\r
1469EFIAPI\r
1470DxeImageVerificationLibConstructor (\r
1471 IN EFI_HANDLE ImageHandle,\r
1472 IN EFI_SYSTEM_TABLE *SystemTable\r
1473 )\r
1474{\r
1475 VOID *Registration;\r
1476\r
1477 //\r
1478 // Register callback function upon VariableWriteArchProtocol.\r
45bf2c47 1479 //\r
0c18794e 1480 EfiCreateProtocolNotifyEvent (\r
1481 &gEfiVariableWriteArchProtocolGuid,\r
1482 TPL_CALLBACK,\r
1483 VariableWriteCallBack,\r
1484 NULL,\r
1485 &Registration\r
1486 );\r
1487\r
1488 return RegisterSecurityHandler (\r
1489 DxeImageVerificationHandler,\r
1490 EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
45bf2c47 1491 );\r
0c18794e 1492}\r