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