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