Validate some fields in PE image to make sure not access violation for later code.
[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
28186d45
ED
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
0c18794e 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
45bf2c47 106 being dispatched.\r
0c18794e 107\r
45bf2c47 108 @return UINT32 Image Type\r
0c18794e 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
45bf2c47 117 EFI_HANDLE DeviceHandle;\r
0c18794e 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
45bf2c47 125 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 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
45bf2c47 149 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 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
45bf2c47 183 // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r
0c18794e 184 // the device path supports the Simple File System Protocol.\r
185 //\r
186 DeviceHandle = NULL;\r
45bf2c47 187 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 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
45bf2c47 202 // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r
0c18794e 203 //\r
45bf2c47 204 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
0c18794e 205 while (!IsDevicePathEndType (TempDevicePath)) {\r
206 switch (DevicePathType (TempDevicePath)) {\r
45bf2c47 207\r
0c18794e 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
45bf2c47 217 }\r
0c18794e 218 break;\r
219\r
220 default:\r
221 break;\r
222 }\r
223 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
224 }\r
45bf2c47 225 return IMAGE_UNKNOWN;\r
0c18794e 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
45bf2c47 233\r
0c18794e 234 @retval TRUE Successfully hash image.\r
235 @retval FALSE Fail in hash image.\r
236\r
237**/\r
45bf2c47 238BOOLEAN\r
0c18794e 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
570b3d1a 254 UINTN SumOfSectionBytes;\r
45bf2c47 255 EFI_IMAGE_SECTION_HEADER *SectionCache;\r
256\r
0c18794e 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
45bf2c47 264\r
0c18794e 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
45bf2c47 281\r
0c18794e 282 HashCtx = AllocatePool (CtxSize);\r
570b3d1a 283 if (HashCtx == NULL) {\r
284 return FALSE;\r
285 }\r
0c18794e 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
45bf2c47 291\r
0c18794e 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
570b3d1a 310 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
0c18794e 311 //\r
312 // Use PE32+ offset.\r
313 //\r
314 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
570b3d1a 315 } else {\r
316 //\r
317 // Invalid header magic number.\r
318 //\r
319 Status = FALSE;\r
320 goto Done;\r
0c18794e 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
45bf2c47 341 //\r
0c18794e 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
570b3d1a 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
45bf2c47 400\r
570b3d1a 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
0c18794e 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
570b3d1a 417 if (SectionHeader == NULL) {\r
418 Status = FALSE;\r
419 goto Done;\r
420 }\r
0c18794e 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
0c18794e 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
28186d45
ED
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
0c18794e 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
28186d45
ED
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
0c18794e 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
45bf2c47 491 SumOfBytesHashed);\r
0c18794e 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
45bf2c47 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
0c18794e 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
45bf2c47 520EFI_STATUS\r
0c18794e 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
45bf2c47 530 for (Index = 0; Index < HASHALG_MAX; Index++) {\r
0c18794e 531 //\r
532 // Check the Hash algorithm in PE/COFF Authenticode.\r
45bf2c47 533 // According to PKCS#7 Definition:\r
0c18794e 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
bd0de396 541 // Fixed offset (+32) is calculated based on two bytes of length encoding.\r
45bf2c47 542 //\r
bd0de396 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
0c18794e 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
45bf2c47 577\r
0c18794e 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
45bf2c47 613\r
0c18794e 614**/\r
615VOID\r
616AddImageExeInfo (\r
45bf2c47 617 IN EFI_IMAGE_EXECUTION_ACTION Action,\r
618 IN CHAR16 *Name OPTIONAL,\r
0c18794e 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
0c18794e 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
0c18794e 632 ImageExeInfoTable = NULL;\r
633 NewImageExeInfoTable = NULL;\r
634 ImageExeInfoEntry = NULL;\r
635 NameStringLen = 0;\r
636\r
570b3d1a 637 if (DevicePath == NULL) {\r
638 return ;\r
639 }\r
45bf2c47 640\r
0c18794e 641 if (Name != NULL) {\r
642 NameStringLen = StrSize (Name);\r
643 }\r
644\r
645 ImageExeInfoTable = NULL;\r
45bf2c47 646 EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);\r
0c18794e 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
570b3d1a 664 if (NewImageExeInfoTable == NULL) {\r
665 return ;\r
666 }\r
0c18794e 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
570b3d1a 699 gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);\r
45bf2c47 700\r
0c18794e 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
45bf2c47 712 @param[in] Policy Specify platform's policy setting.\r
0c18794e 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
45bf2c47 730\r
0c18794e 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
45bf2c47 778 IN UINT8 *Signature,\r
0c18794e 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
570b3d1a 803 if (Data == NULL) {\r
804 return FALSE;\r
805 }\r
0c18794e 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
45bf2c47 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
0c18794e 851\r
45bf2c47 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
0c18794e 857\r
858**/\r
45bf2c47 859BOOLEAN\r
860IsPkcsSignedDataVerifiedBySignatureList (\r
861 IN CHAR16 *VariableName,\r
862 IN EFI_GUID *VendorGuid\r
0c18794e 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
45bf2c47 871 UINT8 *Data;\r
0c18794e 872 UINT8 *RootCert;\r
873 UINTN RootCertSize;\r
874 UINTN Index;\r
875 UINTN CertCount;\r
876\r
45bf2c47 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
0c18794e 884\r
0c18794e 885 DataSize = 0;\r
45bf2c47 886 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);\r
0c18794e 887 if (Status == EFI_BUFFER_TOO_SMALL) {\r
45bf2c47 888 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
889 if (Data == NULL) {\r
890 return VerifyStatus;\r
570b3d1a 891 }\r
0c18794e 892\r
45bf2c47 893 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, (VOID *) Data);\r
0c18794e 894 if (EFI_ERROR (Status)) {\r
895 goto Done;\r
896 }\r
45bf2c47 897\r
898 //\r
899 // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.\r
0c18794e 900 //\r
45bf2c47 901 CertList = (EFI_SIGNATURE_LIST *) Data;\r
0c18794e 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
45bf2c47 908 // Iterate each Signature Data Node within this CertList for verify.\r
909 //\r
0c18794e 910 RootCert = Cert->SignatureData;\r
911 RootCertSize = CertList->SignatureSize;\r
45bf2c47 912\r
0c18794e 913 //\r
45bf2c47 914 // Call AuthenticodeVerify library to Verify Authenticode struct.\r
0c18794e 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
0c18794e 924 if (VerifyStatus) {\r
925 goto Done;\r
926 }\r
927 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
45bf2c47 928 }\r
0c18794e 929 }\r
930 DataSize -= CertList->SignatureListSize;\r
931 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
932 }\r
933 }\r
934\r
45bf2c47 935Done:\r
936 if (Data != NULL) {\r
937 FreePool (Data);\r
938 }\r
0c18794e 939\r
45bf2c47 940 return VerifyStatus;\r
941}\r
0c18794e 942\r
45bf2c47 943/**\r
944 Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format.\r
0c18794e 945\r
45bf2c47 946 @retval EFI_SUCCESS Image pass verification.\r
947 @retval EFI_SECURITY_VIOLATION Image fail verification.\r
0c18794e 948\r
45bf2c47 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
570b3d1a 964 }\r
965\r
45bf2c47 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
0c18794e 971 }\r
972\r
45bf2c47 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
0c18794e 977 return EFI_SUCCESS;\r
978 } else {\r
979 return EFI_SECURITY_VIOLATION;\r
980 }\r
981}\r
982\r
983/**\r
45bf2c47 984 Verify certificate in WIN_CERTIFICATE_UEFI_GUID format.\r
0c18794e 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
45bf2c47 991EFI_STATUS\r
0c18794e 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
45bf2c47 1041\r
0c18794e 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
45bf2c47 1061\r
0c18794e 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
570b3d1a 1074 if (Rsa == NULL) {\r
1075 Status = FALSE;\r
1076 goto Done;\r
1077 }\r
45bf2c47 1078\r
1079 //\r
0c18794e 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
45bf2c47 1095 Rsa,\r
1096 mImageDigest,\r
1097 mImageDigestSize,\r
1098 CertBlock->Signature,\r
0c18794e 1099 EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
1100 );\r
45bf2c47 1101\r
0c18794e 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
45bf2c47 1118 and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and\r
0c18794e 1119 MSFT Authenticode type signatures are supported.\r
0c18794e 1120\r
45bf2c47 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
0c18794e 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
570b3d1a 1152 @retval EFI_INVALID_PARAMETER Input argument is incorrect.\r
1153 @retval EFI_OUT_RESOURCE Fail to allocate memory.\r
0c18794e 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
0c18794e 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
beda2356 1184 UINT8 *SecureBootEnable;\r
28186d45 1185 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
0c18794e 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
45bf2c47 1200\r
0c18794e 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
45bf2c47 1218 Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;\r
0c18794e 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
beda2356 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
45bf2c47 1244 }\r
1245\r
0c18794e 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
570b3d1a 1266 if (FileBuffer == NULL) {\r
1267 FreePool (SetupMode);\r
1268 return EFI_INVALID_PARAMETER;\r
1269 }\r
0c18794e 1270 mImageBase = (UINT8 *) FileBuffer;\r
1271 mImageSize = FileSize;\r
28186d45
ED
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
45bf2c47 1288 DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;\r
0c18794e 1289 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1290 //\r
45bf2c47 1291 // DOS image header is present,\r
0c18794e 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
45bf2c47 1314 mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
570b3d1a 1315 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
0c18794e 1316 //\r
1317 // Use PE32+ offset.\r
1318 //\r
45bf2c47 1319 mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
570b3d1a 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
0c18794e 1334 }\r
1335\r
1336 if (mSecDataDir->Size == 0) {\r
1337 //\r
1338 // This image is not signed.\r
1339 //\r
45bf2c47 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
0c18794e 1363 Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
45bf2c47 1364 Status = EFI_ACCESS_DENIED;\r
1365 goto Done;\r
0c18794e 1366 }\r
45bf2c47 1367\r
0c18794e 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
45bf2c47 1374\r
0c18794e 1375 case WIN_CERT_TYPE_EFI_GUID:\r
1376 //\r
1377 // Verify UEFI GUID type.\r
45bf2c47 1378 //\r
0c18794e 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
45bf2c47 1391 if (EFI_ERROR (Status)) {\r
0c18794e 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
45bf2c47 1402 if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {\r
1403 return EFI_SUCCESS;\r
1404 }\r
0c18794e 1405 }\r
45bf2c47 1406 break;\r
0c18794e 1407\r
1408 default:\r
45bf2c47 1409 Status = EFI_ACCESS_DENIED;\r
1410 goto Done;\r
0c18794e 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
570b3d1a 1417 if (SignatureList == NULL) {\r
1418 Status = EFI_OUT_OF_RESOURCES;\r
1419 goto Done;\r
1420 }\r
0c18794e 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
45bf2c47 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
0c18794e 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
45bf2c47 1484\r
0c18794e 1485 @param[in] Event Event whose notification function is being invoked.\r
1486 @param[in] Context Pointer to the notification function's context.\r
45bf2c47 1487\r
0c18794e 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
45bf2c47 1505\r
0c18794e 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
45bf2c47 1527}\r
0c18794e 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
45bf2c47 1548 //\r
0c18794e 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
45bf2c47 1560 );\r
0c18794e 1561}\r