Fix compatibility issue when using IPF image with PE32 magic value in the OptionalHeader.
[mirror_edk2.git] / SecurityPkg / Library / DxeTpmMeasureBootLib / DxeTpmMeasureBootLib.c
CommitLineData
0c18794e 1/** @file\r
2 The library instance provides security service of TPM measure boot. \r
3\r
65cc57fc 4Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
0c18794e 5This program and the accompanying materials \r
6are licensed and made available under the terms and conditions of the BSD License \r
7which accompanies this distribution. The full text of the license may be found at \r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiDxe.h>\r
16\r
17#include <Protocol/TcgService.h>\r
18#include <Protocol/FirmwareVolume2.h>\r
19#include <Protocol/BlockIo.h>\r
20#include <Protocol/DiskIo.h>\r
21#include <Protocol/DevicePathToText.h>\r
22\r
23#include <Library/BaseLib.h>\r
24#include <Library/DebugLib.h>\r
25#include <Library/BaseMemoryLib.h>\r
26#include <Library/MemoryAllocationLib.h>\r
27#include <Library/DevicePathLib.h>\r
28#include <Library/UefiBootServicesTableLib.h>\r
29#include <Library/BaseCryptLib.h>\r
30#include <Library/PeCoffLib.h>\r
31#include <Library/SecurityManagementLib.h>\r
32\r
33//\r
34// Flag to check GPT partition. It only need be measured once.\r
35//\r
36BOOLEAN mMeasureGptTableFlag = FALSE;\r
37EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
38UINTN mMeasureGptCount = 0;\r
28186d45
ED
39VOID *mFileBuffer;\r
40UINTN mImageSize;\r
0c18794e 41\r
42/**\r
43 Reads contents of a PE/COFF image in memory buffer.\r
44\r
45 @param FileHandle Pointer to the file handle to read the PE/COFF image.\r
46 @param FileOffset Offset into the PE/COFF image to begin the read operation.\r
47 @param ReadSize On input, the size in bytes of the requested read operation. \r
48 On output, the number of bytes actually read.\r
49 @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
50 \r
51 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size \r
52**/\r
53EFI_STATUS\r
54EFIAPI\r
e0192326 55DxeTpmMeasureBootLibImageRead (\r
0c18794e 56 IN VOID *FileHandle,\r
57 IN UINTN FileOffset,\r
58 IN OUT UINTN *ReadSize,\r
59 OUT VOID *Buffer\r
60 )\r
61{\r
28186d45
ED
62 UINTN EndPosition;\r
63\r
64 if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
65 return EFI_INVALID_PARAMETER;\r
66 }\r
67\r
68 if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
69 return EFI_INVALID_PARAMETER;\r
70 }\r
71\r
72 EndPosition = FileOffset + *ReadSize;\r
73 if (EndPosition > mImageSize) {\r
74 *ReadSize = (UINT32)(mImageSize - FileOffset);\r
75 }\r
76\r
77 if (FileOffset >= mImageSize) {\r
78 *ReadSize = 0;\r
79 }\r
80\r
0c18794e 81 CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
28186d45 82\r
0c18794e 83 return EFI_SUCCESS;\r
84}\r
85\r
86/**\r
87 Measure GPT table data into TPM log.\r
88\r
89 @param TcgProtocol Pointer to the located TCG protocol instance.\r
90 @param GptHandle Handle that GPT partition was installed.\r
91\r
92 @retval EFI_SUCCESS Successfully measure GPT table.\r
93 @retval EFI_UNSUPPORTED Not support GPT table on the given handle.\r
94 @retval EFI_DEVICE_ERROR Can't get GPT table because device error.\r
95 @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.\r
96 @retval other error value\r
97**/\r
98EFI_STATUS\r
99EFIAPI\r
100TcgMeasureGptTable (\r
101 IN EFI_TCG_PROTOCOL *TcgProtocol,\r
102 IN EFI_HANDLE GptHandle\r
103 )\r
104{\r
105 EFI_STATUS Status;\r
106 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
107 EFI_DISK_IO_PROTOCOL *DiskIo;\r
108 EFI_PARTITION_TABLE_HEADER *PrimaryHeader;\r
109 EFI_PARTITION_ENTRY *PartitionEntry;\r
110 UINT8 *EntryPtr;\r
111 UINTN NumberOfPartition;\r
112 UINT32 Index;\r
113 TCG_PCR_EVENT *TcgEvent;\r
114 EFI_GPT_DATA *GptData;\r
115 UINT32 EventSize;\r
116 UINT32 EventNumber;\r
117 EFI_PHYSICAL_ADDRESS EventLogLastEntry;\r
118\r
119 if (mMeasureGptCount > 0) {\r
120 return EFI_SUCCESS;\r
121 }\r
122\r
123 Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo);\r
124 if (EFI_ERROR (Status)) {\r
125 return EFI_UNSUPPORTED;\r
126 }\r
127 Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo);\r
128 if (EFI_ERROR (Status)) {\r
129 return EFI_UNSUPPORTED;\r
130 }\r
131 //\r
132 // Read the EFI Partition Table Header\r
133 // \r
134 PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize);\r
135 if (PrimaryHeader == NULL) {\r
136 return EFI_OUT_OF_RESOURCES;\r
137 } \r
138 Status = DiskIo->ReadDisk (\r
139 DiskIo,\r
140 BlockIo->Media->MediaId,\r
141 1 * BlockIo->Media->BlockSize,\r
142 BlockIo->Media->BlockSize,\r
143 (UINT8 *)PrimaryHeader\r
144 );\r
145 if (EFI_ERROR (Status)) {\r
146 DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n"));\r
147 FreePool (PrimaryHeader);\r
148 return EFI_DEVICE_ERROR;\r
149 } \r
150 //\r
151 // Read the partition entry.\r
152 //\r
153 EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
154 if (EntryPtr == NULL) {\r
155 FreePool (PrimaryHeader);\r
156 return EFI_OUT_OF_RESOURCES;\r
157 }\r
158 Status = DiskIo->ReadDisk (\r
159 DiskIo,\r
160 BlockIo->Media->MediaId,\r
161 MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),\r
162 PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,\r
163 EntryPtr\r
164 );\r
165 if (EFI_ERROR (Status)) {\r
166 FreePool (PrimaryHeader);\r
167 FreePool (EntryPtr);\r
168 return EFI_DEVICE_ERROR;\r
169 }\r
170 \r
171 //\r
172 // Count the valid partition\r
173 //\r
174 PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;\r
175 NumberOfPartition = 0;\r
176 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
177 if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {\r
178 NumberOfPartition++; \r
179 }\r
2ea3b920 180 PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
0c18794e 181 }\r
182\r
183 //\r
2ea3b920 184 // Prepare Data for Measurement\r
0c18794e 185 // \r
186 EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) \r
187 + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);\r
2ea3b920 188 TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR));\r
0c18794e 189 if (TcgEvent == NULL) {\r
190 FreePool (PrimaryHeader);\r
191 FreePool (EntryPtr);\r
192 return EFI_OUT_OF_RESOURCES;\r
193 }\r
194\r
195 TcgEvent->PCRIndex = 5;\r
196 TcgEvent->EventType = EV_EFI_GPT_EVENT;\r
197 TcgEvent->EventSize = EventSize;\r
198 GptData = (EFI_GPT_DATA *) TcgEvent->Event; \r
199\r
200 //\r
201 // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition\r
202 // \r
203 CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));\r
204 GptData->NumberOfPartitions = NumberOfPartition;\r
205 //\r
206 // Copy the valid partition entry\r
207 //\r
208 PartitionEntry = (EFI_PARTITION_ENTRY*)EntryPtr;\r
209 NumberOfPartition = 0;\r
210 for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
211 if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {\r
212 CopyMem (\r
2ea3b920 213 (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,\r
0c18794e 214 (UINT8 *)PartitionEntry,\r
2ea3b920 215 PrimaryHeader->SizeOfPartitionEntry\r
0c18794e 216 );\r
217 NumberOfPartition++;\r
218 }\r
2ea3b920 219 PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);\r
0c18794e 220 }\r
221\r
222 //\r
223 // Measure the GPT data\r
224 //\r
225 EventNumber = 1;\r
226 Status = TcgProtocol->HashLogExtendEvent (\r
227 TcgProtocol,\r
228 (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData,\r
229 (UINT64) TcgEvent->EventSize,\r
230 TPM_ALG_SHA,\r
231 TcgEvent,\r
232 &EventNumber,\r
233 &EventLogLastEntry\r
234 );\r
235 if (!EFI_ERROR (Status)) {\r
236 mMeasureGptCount++;\r
237 }\r
238\r
239 FreePool (PrimaryHeader);\r
240 FreePool (EntryPtr);\r
241 FreePool (TcgEvent);\r
242\r
243 return Status;\r
244}\r
245\r
246/**\r
247 Measure PE image into TPM log based on the authenticode image hashing in\r
248 PE/COFF Specification 8.0 Appendix A.\r
249\r
250 @param[in] TcgProtocol Pointer to the located TCG protocol instance.\r
251 @param[in] ImageAddress Start address of image buffer.\r
252 @param[in] ImageSize Image size\r
253 @param[in] LinkTimeBase Address that the image is loaded into memory.\r
254 @param[in] ImageType Image subsystem type.\r
255 @param[in] FilePath File path is corresponding to the input image.\r
256\r
257 @retval EFI_SUCCESS Successfully measure image.\r
258 @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.\r
551d8081 259 @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format. \r
0c18794e 260 @retval other error value\r
551d8081 261\r
0c18794e 262**/\r
263EFI_STATUS\r
264EFIAPI\r
265TcgMeasurePeImage (\r
266 IN EFI_TCG_PROTOCOL *TcgProtocol,\r
267 IN EFI_PHYSICAL_ADDRESS ImageAddress,\r
268 IN UINTN ImageSize,\r
269 IN UINTN LinkTimeBase,\r
270 IN UINT16 ImageType,\r
271 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
272 )\r
273{\r
551d8081 274 EFI_STATUS Status;\r
275 TCG_PCR_EVENT *TcgEvent;\r
276 EFI_IMAGE_LOAD_EVENT *ImageLoad;\r
277 UINT32 FilePathSize;\r
278 VOID *Sha1Ctx;\r
279 UINTN CtxSize;\r
280 EFI_IMAGE_DOS_HEADER *DosHdr;\r
281 UINT32 PeCoffHeaderOffset;\r
282 EFI_IMAGE_SECTION_HEADER *Section;\r
283 UINT8 *HashBase;\r
284 UINTN HashSize;\r
285 UINTN SumOfBytesHashed;\r
286 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
287 UINTN Index;\r
288 UINTN Pos;\r
289 UINT16 Magic;\r
290 UINT32 EventSize;\r
291 UINT32 EventNumber;\r
292 EFI_PHYSICAL_ADDRESS EventLogLastEntry;\r
0c18794e 293 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
551d8081 294 UINT32 NumberOfRvaAndSizes;\r
295 BOOLEAN HashStatus;\r
296 UINT32 CertSize;\r
0c18794e 297\r
551d8081 298 Status = EFI_UNSUPPORTED;\r
0c18794e 299 ImageLoad = NULL;\r
300 SectionHeader = NULL;\r
301 Sha1Ctx = NULL;\r
302 FilePathSize = (UINT32) GetDevicePathSize (FilePath);\r
303\r
304 //\r
305 // Determine destination PCR by BootPolicy\r
306 //\r
307 EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;\r
308 TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));\r
309 if (TcgEvent == NULL) {\r
310 return EFI_OUT_OF_RESOURCES;\r
311 }\r
312\r
313 TcgEvent->EventSize = EventSize;\r
314 ImageLoad = (EFI_IMAGE_LOAD_EVENT *) TcgEvent->Event;\r
315\r
316 switch (ImageType) {\r
317 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
318 TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION;\r
319 TcgEvent->PCRIndex = 4;\r
320 break;\r
321 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
322 TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER;\r
323 TcgEvent->PCRIndex = 2;\r
324 break;\r
325 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
326 TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;\r
327 TcgEvent->PCRIndex = 2;\r
328 break;\r
329 default:\r
330 DEBUG ((\r
331 EFI_D_ERROR,\r
332 "TcgMeasurePeImage: Unknown subsystem type %d",\r
333 ImageType\r
334 ));\r
0c18794e 335 goto Finish;\r
336 }\r
337\r
338 ImageLoad->ImageLocationInMemory = ImageAddress;\r
339 ImageLoad->ImageLengthInMemory = ImageSize;\r
340 ImageLoad->ImageLinkTimeAddress = LinkTimeBase;\r
341 ImageLoad->LengthOfDevicePath = FilePathSize;\r
342 CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);\r
343\r
344 //\r
345 // Check PE/COFF image\r
346 //\r
347 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
348 PeCoffHeaderOffset = 0;\r
349 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
350 PeCoffHeaderOffset = DosHdr->e_lfanew;\r
351 }\r
551d8081 352\r
353 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
354 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
0c18794e 355 goto Finish;\r
356 }\r
357\r
358 //\r
359 // PE/COFF Image Measurement\r
360 //\r
361 // NOTE: The following codes/steps are based upon the authenticode image hashing in\r
362 // PE/COFF Specification 8.0 Appendix A.\r
363 //\r
364 //\r
365\r
366 // 1. Load the image header into memory.\r
367\r
368 // 2. Initialize a SHA hash context.\r
369 CtxSize = Sha1GetContextSize ();\r
370 Sha1Ctx = AllocatePool (CtxSize);\r
371 if (Sha1Ctx == NULL) {\r
372 Status = EFI_OUT_OF_RESOURCES;\r
373 goto Finish;\r
374 }\r
375\r
551d8081 376 HashStatus = Sha1Init (Sha1Ctx);\r
377 if (!HashStatus) {\r
378 goto Finish;\r
379 }\r
0c18794e 380\r
381 //\r
382 // Measuring PE/COFF Image Header;\r
383 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
384 //\r
de2447dd 385 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
386 //\r
387 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
388 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
389 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
390 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
391 //\r
392 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
393 } else {\r
394 //\r
395 // Get the magic value from the PE/COFF Optional Header\r
396 //\r
397 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
398 }\r
0c18794e 399 \r
400 //\r
401 // 3. Calculate the distance from the base of the image header to the image checksum address.\r
402 // 4. Hash the image header from its base to beginning of the image checksum.\r
403 //\r
404 HashBase = (UINT8 *) (UINTN) ImageAddress;\r
405 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
406 //\r
407 // Use PE32 offset\r
408 //\r
551d8081 409 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
0c18794e 410 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);\r
411 } else {\r
412 //\r
413 // Use PE32+ offset\r
414 //\r
551d8081 415 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
0c18794e 416 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
417 }\r
418\r
551d8081 419 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
420 if (!HashStatus) {\r
421 goto Finish;\r
422 } \r
0c18794e 423\r
424 //\r
425 // 5. Skip over the image checksum (it occupies a single ULONG).\r
0c18794e 426 //\r
551d8081 427 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
0c18794e 428 //\r
551d8081 429 // 6. Since there is no Cert Directory in optional header, hash everything\r
430 // from the end of the checksum to the end of image header.\r
0c18794e 431 //\r
551d8081 432 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
433 //\r
434 // Use PE32 offset.\r
435 //\r
436 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
437 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
438 } else {\r
439 //\r
440 // Use PE32+ offset.\r
441 //\r
442 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
443 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
444 }\r
445\r
446 if (HashSize != 0) {\r
447 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
448 if (!HashStatus) {\r
449 goto Finish;\r
450 }\r
451 } \r
0c18794e 452 } else {\r
453 //\r
551d8081 454 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
455 //\r
456 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
457 //\r
458 // Use PE32 offset\r
459 //\r
460 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
461 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
462 } else {\r
463 //\r
464 // Use PE32+ offset\r
465 // \r
466 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
467 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
468 }\r
0c18794e 469\r
551d8081 470 if (HashSize != 0) {\r
471 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
472 if (!HashStatus) {\r
473 goto Finish;\r
474 }\r
475 }\r
0c18794e 476\r
0c18794e 477 //\r
551d8081 478 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
479 // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
0c18794e 480 //\r
551d8081 481 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
482 //\r
483 // Use PE32 offset\r
484 //\r
485 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
486 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
487 } else {\r
488 //\r
489 // Use PE32+ offset\r
490 //\r
491 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
492 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);\r
493 }\r
494 \r
495 if (HashSize != 0) {\r
496 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
497 if (!HashStatus) {\r
498 goto Finish;\r
499 }\r
500 }\r
0c18794e 501 }\r
0c18794e 502\r
503 //\r
504 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header\r
505 //\r
506 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
507 //\r
508 // Use PE32 offset\r
509 //\r
510 SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
511 } else {\r
512 //\r
513 // Use PE32+ offset\r
514 //\r
515 SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
516 }\r
517\r
518 //\r
519 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
520 // structures in the image. The 'NumberOfSections' field of the image\r
521 // header indicates how big the table should be. Do not include any\r
522 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
523 //\r
551d8081 524 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
0c18794e 525 if (SectionHeader == NULL) {\r
526 Status = EFI_OUT_OF_RESOURCES;\r
527 goto Finish;\r
528 }\r
529\r
530 //\r
531 // 12. Using the 'PointerToRawData' in the referenced section headers as\r
532 // a key, arrange the elements in the table in ascending order. In other\r
533 // words, sort the section headers according to the disk-file offset of\r
534 // the section.\r
535 //\r
536 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
537 (UINT8 *) (UINTN) ImageAddress +\r
538 PeCoffHeaderOffset +\r
539 sizeof(UINT32) +\r
540 sizeof(EFI_IMAGE_FILE_HEADER) +\r
541 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
542 );\r
543 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
544 Pos = Index;\r
545 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
546 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));\r
547 Pos--;\r
548 }\r
549 CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));\r
550 Section += 1;\r
551 }\r
552\r
553 //\r
554 // 13. Walk through the sorted table, bring the corresponding section\r
555 // into memory, and hash the entire section (using the 'SizeOfRawData'\r
556 // field in the section header to determine the amount of data to hash).\r
557 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
558 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r
559 //\r
560 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
561 Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];\r
562 if (Section->SizeOfRawData == 0) {\r
563 continue;\r
564 }\r
565 HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;\r
566 HashSize = (UINTN) Section->SizeOfRawData;\r
567\r
551d8081 568 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
569 if (!HashStatus) {\r
570 goto Finish;\r
571 }\r
0c18794e 572\r
573 SumOfBytesHashed += HashSize;\r
574 }\r
575\r
576 //\r
577 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
578 // data in the file that needs to be added to the hash. This data begins\r
579 // at file offset SUM_OF_BYTES_HASHED and its length is:\r
580 // FileSize - (CertDirectory->Size)\r
581 //\r
582 if (ImageSize > SumOfBytesHashed) {\r
583 HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;\r
551d8081 584\r
585 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r
586 CertSize = 0;\r
0c18794e 587 } else {\r
551d8081 588 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
589 //\r
590 // Use PE32 offset.\r
591 //\r
592 CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
593 } else {\r
594 //\r
595 // Use PE32+ offset.\r
596 //\r
597 CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r
28186d45 598 }\r
0c18794e 599 }\r
600\r
551d8081 601 if (ImageSize > CertSize + SumOfBytesHashed) {\r
602 HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);\r
603\r
604 HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);\r
605 if (!HashStatus) {\r
606 goto Finish;\r
607 }\r
608 } else if (ImageSize < CertSize + SumOfBytesHashed) {\r
609 goto Finish;\r
610 }\r
0c18794e 611 }\r
612\r
613 //\r
614 // 17. Finalize the SHA hash.\r
615 //\r
551d8081 616 HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest);\r
617 if (!HashStatus) {\r
618 goto Finish;\r
619 }\r
0c18794e 620\r
621 //\r
622 // Log the PE data\r
623 //\r
624 EventNumber = 1;\r
625 Status = TcgProtocol->HashLogExtendEvent (\r
626 TcgProtocol,\r
627 (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL,\r
628 0,\r
629 TPM_ALG_SHA,\r
630 TcgEvent,\r
631 &EventNumber,\r
632 &EventLogLastEntry\r
633 );\r
634\r
635Finish:\r
636 FreePool (TcgEvent);\r
637\r
638 if (SectionHeader != NULL) {\r
639 FreePool (SectionHeader);\r
640 }\r
641\r
642 if (Sha1Ctx != NULL ) {\r
643 FreePool (Sha1Ctx);\r
644 }\r
645 return Status;\r
646}\r
647\r
648/**\r
649 The security handler is used to abstract platform-specific policy \r
650 from the DXE core response to an attempt to use a file that returns a \r
651 given status for the authentication check from the section extraction protocol. \r
652\r
653 The possible responses in a given SAP implementation may include locking \r
654 flash upon failure to authenticate, attestation logging for all signed drivers, \r
655 and other exception operations. The File parameter allows for possible logging \r
656 within the SAP of the driver.\r
657\r
658 If File is NULL, then EFI_INVALID_PARAMETER is returned.\r
659\r
660 If the file specified by File with an authentication status specified by \r
661 AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.\r
662\r
663 If the file specified by File with an authentication status specified by \r
664 AuthenticationStatus is not safe for the DXE Core to use under any circumstances, \r
665 then EFI_ACCESS_DENIED is returned.\r
666\r
667 If the file specified by File with an authentication status specified by \r
668 AuthenticationStatus is not safe for the DXE Core to use right now, but it \r
669 might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is \r
670 returned.\r
671\r
672 @param[in, out] AuthenticationStatus This is the authentication status returned\r
673 from the securitymeasurement services for the\r
674 input file.\r
675 @param[in] File This is a pointer to the device path of the file that is\r
676 being dispatched. This will optionally be used for logging.\r
677 @param[in] FileBuffer File buffer matches the input file device path.\r
678 @param[in] FileSize Size of File buffer matches the input file device path.\r
679\r
680 @retval EFI_SUCCESS The file specified by File did authenticate, and the\r
681 platform policy dictates that the DXE Core may use File.\r
682 @retval EFI_INVALID_PARAMETER File is NULL.\r
683 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
684 the platform policy dictates that File should be placed\r
685 in the untrusted state. A file may be promoted from\r
686 the untrusted to the trusted state at a future time\r
687 with a call to the Trust() DXE Service.\r
688 @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
689 the platform policy dictates that File should not be\r
690 used for any purpose.\r
691\r
692**/\r
693EFI_STATUS\r
694EFIAPI\r
695DxeTpmMeasureBootHandler (\r
696 IN OUT UINT32 AuthenticationStatus,\r
697 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
698 IN VOID *FileBuffer OPTIONAL,\r
699 IN UINTN FileSize OPTIONAL\r
700 )\r
701{\r
702 EFI_TCG_PROTOCOL *TcgProtocol;\r
703 EFI_STATUS Status;\r
704 TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability;\r
705 UINT32 TCGFeatureFlags;\r
706 EFI_PHYSICAL_ADDRESS EventLogLocation;\r
707 EFI_PHYSICAL_ADDRESS EventLogLastEntry;\r
708 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
709 EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;\r
710 EFI_HANDLE Handle;\r
711 BOOLEAN ApplicationRequired;\r
712 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
713\r
714 if (File == NULL) {\r
715 return EFI_INVALID_PARAMETER;\r
716 }\r
717\r
718 Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);\r
719 if (EFI_ERROR (Status)) {\r
720 //\r
721 // TCG protocol is not installed. So, TPM is not present.\r
722 // Don't do any measurement, and directly return EFI_SUCCESS.\r
723 //\r
724 return EFI_SUCCESS;\r
725 }\r
726\r
727 ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);\r
728 Status = TcgProtocol->StatusCheck (\r
729 TcgProtocol, \r
730 &ProtocolCapability,\r
731 &TCGFeatureFlags,\r
732 &EventLogLocation,\r
733 &EventLogLastEntry\r
734 );\r
735 if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag) {\r
736 //\r
737 // TPM device doesn't work or activate.\r
738 //\r
739 return EFI_SUCCESS;\r
740 }\r
741\r
742 //\r
743 // Copy File Device Path\r
744 //\r
745 OrigDevicePathNode = DuplicateDevicePath (File);\r
746 ASSERT (OrigDevicePathNode != NULL);\r
747 \r
748 //\r
749 // 1. Check whether this device path support BlockIo protocol.\r
750 // Is so, this device path may be a GPT device path.\r
751 //\r
752 DevicePathNode = OrigDevicePathNode;\r
753 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);\r
754 if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) {\r
755 //\r
756 // Find the gpt partion on the given devicepath\r
757 //\r
758 DevicePathNode = OrigDevicePathNode;\r
759 while (!IsDevicePathEnd (DevicePathNode)) {\r
760 //\r
761 // Find the Gpt partition\r
762 //\r
763 if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&\r
764 DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {\r
765 //\r
766 // Check whether it is a gpt partition or not\r
767 // \r
768 if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER && \r
769 ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) {\r
770\r
771 //\r
772 // Change the partition device path to its parent device path (disk) and get the handle.\r
773 //\r
774 DevicePathNode->Type = END_DEVICE_PATH_TYPE;\r
775 DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
776 DevicePathNode = OrigDevicePathNode;\r
777 Status = gBS->LocateDevicePath (\r
778 &gEfiDiskIoProtocolGuid,\r
779 &DevicePathNode,\r
780 &Handle\r
781 );\r
782 if (!EFI_ERROR (Status)) {\r
783 //\r
784 // Measure GPT disk.\r
785 //\r
786 Status = TcgMeasureGptTable (TcgProtocol, Handle);\r
787 if (!EFI_ERROR (Status)) {\r
788 //\r
789 // GPT disk check done.\r
790 //\r
791 mMeasureGptTableFlag = TRUE;\r
792 }\r
793 }\r
794 FreePool (OrigDevicePathNode);\r
795 OrigDevicePathNode = DuplicateDevicePath (File);\r
796 ASSERT (OrigDevicePathNode != NULL);\r
797 break;\r
798 }\r
799 }\r
800 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
801 }\r
802 }\r
803 \r
804 //\r
805 // 2. Measure PE image.\r
806 //\r
807 ApplicationRequired = FALSE;\r
808\r
809 //\r
810 // Check whether this device path support FV2 protocol.\r
811 //\r
812 DevicePathNode = OrigDevicePathNode;\r
813 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);\r
814 if (!EFI_ERROR (Status)) {\r
815 //\r
816 // Don't check FV image, and directly return EFI_SUCCESS.\r
817 // It can be extended to the specific FV authentication according to the different requirement.\r
818 //\r
819 if (IsDevicePathEnd (DevicePathNode)) {\r
820 return EFI_SUCCESS;\r
821 }\r
822 //\r
823 // The image from Firmware image will not be mearsured.\r
824 // Current policy doesn't measure PeImage from Firmware if it is driver\r
825 // If the got PeImage is application, it will be still be measured.\r
826 //\r
827 ApplicationRequired = TRUE;\r
828 }\r
829 \r
830 //\r
831 // File is not found.\r
832 //\r
833 if (FileBuffer == NULL) {\r
834 Status = EFI_SECURITY_VIOLATION;\r
835 goto Finish;\r
836 }\r
837\r
28186d45
ED
838 mImageSize = FileSize;\r
839 mFileBuffer = FileBuffer;\r
840\r
0c18794e 841 //\r
842 // Measure PE Image\r
843 //\r
844 DevicePathNode = OrigDevicePathNode;\r
845 ZeroMem (&ImageContext, sizeof (ImageContext));\r
846 ImageContext.Handle = (VOID *) FileBuffer;\r
e0192326 847 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead;\r
0c18794e 848\r
849 //\r
850 // Get information about the image being loaded\r
851 //\r
852 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
853 if (EFI_ERROR (Status)) {\r
854 //\r
855 // The information can't be got from the invalid PeImage\r
856 //\r
857 goto Finish;\r
858 }\r
859 \r
860 //\r
861 // Measure only application if Application flag is set\r
862 // Measure drivers and applications if Application flag is not set\r
863 //\r
864 if ((!ApplicationRequired) || \r
865 (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { \r
866 //\r
867 // Print the image path to be measured.\r
868 // \r
869 DEBUG_CODE_BEGIN ();\r
870 CHAR16 *ToText;\r
871 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;\r
872 Status = gBS->LocateProtocol (\r
873 &gEfiDevicePathToTextProtocolGuid,\r
874 NULL,\r
875 (VOID **) &DevPathToText\r
876 );\r
877 if (!EFI_ERROR (Status)) {\r
878 ToText = DevPathToText->ConvertDevicePathToText (\r
879 DevicePathNode,\r
880 FALSE,\r
881 TRUE\r
882 );\r
883 if (ToText != NULL) {\r
884 DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));\r
885 }\r
886 }\r
887 DEBUG_CODE_END ();\r
888\r
889 //\r
890 // Measure PE image into TPM log.\r
891 //\r
892 Status = TcgMeasurePeImage (\r
893 TcgProtocol,\r
894 (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, \r
895 FileSize, \r
896 (UINTN) ImageContext.ImageAddress, \r
897 ImageContext.ImageType, \r
898 DevicePathNode\r
899 );\r
900 }\r
901\r
902 //\r
903 // Done, free the allocated resource.\r
904 //\r
905Finish:\r
906 FreePool (OrigDevicePathNode);\r
907\r
908 return Status;\r
909}\r
910\r
911/**\r
912 Register the security handler to provide TPM measure boot service.\r
913\r
914 @param ImageHandle ImageHandle of the loaded driver.\r
915 @param SystemTable Pointer to the EFI System Table.\r
916\r
917 @retval EFI_SUCCESS Register successfully.\r
918 @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.\r
919**/\r
920EFI_STATUS\r
921EFIAPI\r
922DxeTpmMeasureBootLibConstructor (\r
923 IN EFI_HANDLE ImageHandle,\r
924 IN EFI_SYSTEM_TABLE *SystemTable\r
925 )\r
926{\r
927 return RegisterSecurityHandler (\r
928 DxeTpmMeasureBootHandler,\r
929 EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
930 );\r
931}\r