MdeModulePkg: Enlarge timeout value to wait set_address request success for large...
[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
180 PartitionEntry++;\r
181 }\r
182\r
183 //\r
184 // Parepare Data for Measurement\r
185 // \r
186 EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) \r
187 + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);\r
188 TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));\r
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
213 (UINT8 *)&GptData->Partitions + NumberOfPartition * sizeof (EFI_PARTITION_ENTRY),\r
214 (UINT8 *)PartitionEntry,\r
215 sizeof (EFI_PARTITION_ENTRY)\r
216 );\r
217 NumberOfPartition++;\r
218 }\r
219 PartitionEntry++;\r
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
259 @retval other error value\r
260**/\r
261EFI_STATUS\r
262EFIAPI\r
263TcgMeasurePeImage (\r
264 IN EFI_TCG_PROTOCOL *TcgProtocol,\r
265 IN EFI_PHYSICAL_ADDRESS ImageAddress,\r
266 IN UINTN ImageSize,\r
267 IN UINTN LinkTimeBase,\r
268 IN UINT16 ImageType,\r
269 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
270 )\r
271{\r
272 EFI_STATUS Status;\r
273 TCG_PCR_EVENT *TcgEvent;\r
274 EFI_IMAGE_LOAD_EVENT *ImageLoad;\r
275 UINT32 FilePathSize;\r
276 VOID *Sha1Ctx;\r
277 UINTN CtxSize;\r
278 EFI_IMAGE_DOS_HEADER *DosHdr;\r
279 UINT32 PeCoffHeaderOffset;\r
280 EFI_IMAGE_SECTION_HEADER *Section;\r
281 UINT8 *HashBase;\r
282 UINTN HashSize;\r
283 UINTN SumOfBytesHashed;\r
284 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
285 UINTN Index, Pos;\r
286 UINT16 Magic;\r
287 UINT32 EventSize;\r
288 UINT32 EventNumber;\r
289 EFI_PHYSICAL_ADDRESS EventLogLastEntry;\r
290 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
291\r
292 Status = EFI_SUCCESS;\r
293 ImageLoad = NULL;\r
294 SectionHeader = NULL;\r
295 Sha1Ctx = NULL;\r
296 FilePathSize = (UINT32) GetDevicePathSize (FilePath);\r
297\r
298 //\r
299 // Determine destination PCR by BootPolicy\r
300 //\r
301 EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;\r
302 TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));\r
303 if (TcgEvent == NULL) {\r
304 return EFI_OUT_OF_RESOURCES;\r
305 }\r
306\r
307 TcgEvent->EventSize = EventSize;\r
308 ImageLoad = (EFI_IMAGE_LOAD_EVENT *) TcgEvent->Event;\r
309\r
310 switch (ImageType) {\r
311 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
312 TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION;\r
313 TcgEvent->PCRIndex = 4;\r
314 break;\r
315 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
316 TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER;\r
317 TcgEvent->PCRIndex = 2;\r
318 break;\r
319 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
320 TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;\r
321 TcgEvent->PCRIndex = 2;\r
322 break;\r
323 default:\r
324 DEBUG ((\r
325 EFI_D_ERROR,\r
326 "TcgMeasurePeImage: Unknown subsystem type %d",\r
327 ImageType\r
328 ));\r
0c18794e 329 Status = EFI_UNSUPPORTED;\r
330 goto Finish;\r
331 }\r
332\r
333 ImageLoad->ImageLocationInMemory = ImageAddress;\r
334 ImageLoad->ImageLengthInMemory = ImageSize;\r
335 ImageLoad->ImageLinkTimeAddress = LinkTimeBase;\r
336 ImageLoad->LengthOfDevicePath = FilePathSize;\r
337 CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);\r
338\r
339 //\r
340 // Check PE/COFF image\r
341 //\r
342 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
343 PeCoffHeaderOffset = 0;\r
344 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
345 PeCoffHeaderOffset = DosHdr->e_lfanew;\r
346 }\r
347 if (((EFI_TE_IMAGE_HEADER *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset))->Signature\r
348 == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
349 goto Finish;\r
350 }\r
351\r
352 //\r
353 // PE/COFF Image Measurement\r
354 //\r
355 // NOTE: The following codes/steps are based upon the authenticode image hashing in\r
356 // PE/COFF Specification 8.0 Appendix A.\r
357 //\r
358 //\r
359\r
360 // 1. Load the image header into memory.\r
361\r
362 // 2. Initialize a SHA hash context.\r
363 CtxSize = Sha1GetContextSize ();\r
364 Sha1Ctx = AllocatePool (CtxSize);\r
365 if (Sha1Ctx == NULL) {\r
366 Status = EFI_OUT_OF_RESOURCES;\r
367 goto Finish;\r
368 }\r
369\r
370 Sha1Init (Sha1Ctx);\r
371\r
372 //\r
373 // Measuring PE/COFF Image Header;\r
374 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
375 //\r
376 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
377 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
378 \r
379 //\r
380 // 3. Calculate the distance from the base of the image header to the image checksum address.\r
381 // 4. Hash the image header from its base to beginning of the image checksum.\r
382 //\r
383 HashBase = (UINT8 *) (UINTN) ImageAddress;\r
384 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
385 //\r
386 // Use PE32 offset\r
387 //\r
388 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);\r
389 } else {\r
390 //\r
391 // Use PE32+ offset\r
392 //\r
393 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
394 }\r
395\r
396 Sha1Update (Sha1Ctx, HashBase, HashSize);\r
397\r
398 //\r
399 // 5. Skip over the image checksum (it occupies a single ULONG).\r
400 // 6. Get the address of the beginning of the Cert Directory.\r
401 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
402 //\r
403 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
404 //\r
405 // Use PE32 offset\r
406 //\r
407 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
408 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
409 } else {\r
410 //\r
411 // Use PE32+ offset\r
412 // \r
413 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
414 HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
415 }\r
416\r
417 Sha1Update (Sha1Ctx, HashBase, HashSize);\r
418\r
419 //\r
420 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
421 // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
422 //\r
423 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
424 //\r
425 // Use PE32 offset\r
426 //\r
427 HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
428 HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders -\r
429 (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);\r
430 } else {\r
431 //\r
432 // Use PE32+ offset\r
433 //\r
434 HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
435 HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders -\r
436 (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);\r
437 }\r
438 \r
439 Sha1Update (Sha1Ctx, HashBase, HashSize);\r
440\r
441 //\r
442 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header\r
443 //\r
444 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
445 //\r
446 // Use PE32 offset\r
447 //\r
448 SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
449 } else {\r
450 //\r
451 // Use PE32+ offset\r
452 //\r
453 SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
454 }\r
455\r
456 //\r
457 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
458 // structures in the image. The 'NumberOfSections' field of the image\r
459 // header indicates how big the table should be. Do not include any\r
460 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
461 //\r
462 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
463 if (SectionHeader == NULL) {\r
464 Status = EFI_OUT_OF_RESOURCES;\r
465 goto Finish;\r
466 }\r
467\r
468 //\r
469 // 12. Using the 'PointerToRawData' in the referenced section headers as\r
470 // a key, arrange the elements in the table in ascending order. In other\r
471 // words, sort the section headers according to the disk-file offset of\r
472 // the section.\r
473 //\r
474 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
475 (UINT8 *) (UINTN) ImageAddress +\r
476 PeCoffHeaderOffset +\r
477 sizeof(UINT32) +\r
478 sizeof(EFI_IMAGE_FILE_HEADER) +\r
479 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
480 );\r
481 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
482 Pos = Index;\r
483 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
484 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));\r
485 Pos--;\r
486 }\r
487 CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));\r
488 Section += 1;\r
489 }\r
490\r
491 //\r
492 // 13. Walk through the sorted table, bring the corresponding section\r
493 // into memory, and hash the entire section (using the 'SizeOfRawData'\r
494 // field in the section header to determine the amount of data to hash).\r
495 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
496 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r
497 //\r
498 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
499 Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];\r
500 if (Section->SizeOfRawData == 0) {\r
501 continue;\r
502 }\r
503 HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;\r
504 HashSize = (UINTN) Section->SizeOfRawData;\r
505\r
506 Sha1Update (Sha1Ctx, HashBase, HashSize);\r
507\r
508 SumOfBytesHashed += HashSize;\r
509 }\r
510\r
511 //\r
512 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
513 // data in the file that needs to be added to the hash. This data begins\r
514 // at file offset SUM_OF_BYTES_HASHED and its length is:\r
515 // FileSize - (CertDirectory->Size)\r
516 //\r
517 if (ImageSize > SumOfBytesHashed) {\r
518 HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;\r
519 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
28186d45
ED
520 if (ImageSize - SumOfBytesHashed < Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
521 Status = EFI_INVALID_PARAMETER;\r
522 goto Finish;\r
523 }\r
0c18794e 524 //\r
525 // Use PE32 offset\r
526 //\r
527 HashSize = (UINTN)(ImageSize -\r
528 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
529 SumOfBytesHashed);\r
530 } else {\r
28186d45
ED
531 if (ImageSize - SumOfBytesHashed < Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {\r
532 Status = EFI_INVALID_PARAMETER;\r
533 goto Finish;\r
534 }\r
0c18794e 535 //\r
536 // Use PE32+ offset\r
537 //\r
538 HashSize = (UINTN)(ImageSize -\r
539 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
540 SumOfBytesHashed); \r
541 }\r
542\r
543 Sha1Update (Sha1Ctx, HashBase, HashSize);\r
544 }\r
545\r
546 //\r
547 // 17. Finalize the SHA hash.\r
548 //\r
549 Sha1Final (Sha1Ctx, (UINT8 *)&TcgEvent->Digest);\r
550\r
551 //\r
552 // Log the PE data\r
553 //\r
554 EventNumber = 1;\r
555 Status = TcgProtocol->HashLogExtendEvent (\r
556 TcgProtocol,\r
557 (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL,\r
558 0,\r
559 TPM_ALG_SHA,\r
560 TcgEvent,\r
561 &EventNumber,\r
562 &EventLogLastEntry\r
563 );\r
564\r
565Finish:\r
566 FreePool (TcgEvent);\r
567\r
568 if (SectionHeader != NULL) {\r
569 FreePool (SectionHeader);\r
570 }\r
571\r
572 if (Sha1Ctx != NULL ) {\r
573 FreePool (Sha1Ctx);\r
574 }\r
575 return Status;\r
576}\r
577\r
578/**\r
579 The security handler is used to abstract platform-specific policy \r
580 from the DXE core response to an attempt to use a file that returns a \r
581 given status for the authentication check from the section extraction protocol. \r
582\r
583 The possible responses in a given SAP implementation may include locking \r
584 flash upon failure to authenticate, attestation logging for all signed drivers, \r
585 and other exception operations. The File parameter allows for possible logging \r
586 within the SAP of the driver.\r
587\r
588 If File is NULL, then EFI_INVALID_PARAMETER is returned.\r
589\r
590 If the file specified by File with an authentication status specified by \r
591 AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.\r
592\r
593 If the file specified by File with an authentication status specified by \r
594 AuthenticationStatus is not safe for the DXE Core to use under any circumstances, \r
595 then EFI_ACCESS_DENIED is returned.\r
596\r
597 If the file specified by File with an authentication status specified by \r
598 AuthenticationStatus is not safe for the DXE Core to use right now, but it \r
599 might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is \r
600 returned.\r
601\r
602 @param[in, out] AuthenticationStatus This is the authentication status returned\r
603 from the securitymeasurement services for the\r
604 input file.\r
605 @param[in] File This is a pointer to the device path of the file that is\r
606 being dispatched. This will optionally be used for logging.\r
607 @param[in] FileBuffer File buffer matches the input file device path.\r
608 @param[in] FileSize Size of File buffer matches the input file device path.\r
609\r
610 @retval EFI_SUCCESS The file specified by File did authenticate, and the\r
611 platform policy dictates that the DXE Core may use File.\r
612 @retval EFI_INVALID_PARAMETER File is NULL.\r
613 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
614 the platform policy dictates that File should be placed\r
615 in the untrusted state. A file may be promoted from\r
616 the untrusted to the trusted state at a future time\r
617 with a call to the Trust() DXE Service.\r
618 @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
619 the platform policy dictates that File should not be\r
620 used for any purpose.\r
621\r
622**/\r
623EFI_STATUS\r
624EFIAPI\r
625DxeTpmMeasureBootHandler (\r
626 IN OUT UINT32 AuthenticationStatus,\r
627 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
628 IN VOID *FileBuffer OPTIONAL,\r
629 IN UINTN FileSize OPTIONAL\r
630 )\r
631{\r
632 EFI_TCG_PROTOCOL *TcgProtocol;\r
633 EFI_STATUS Status;\r
634 TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability;\r
635 UINT32 TCGFeatureFlags;\r
636 EFI_PHYSICAL_ADDRESS EventLogLocation;\r
637 EFI_PHYSICAL_ADDRESS EventLogLastEntry;\r
638 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
639 EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;\r
640 EFI_HANDLE Handle;\r
641 BOOLEAN ApplicationRequired;\r
642 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
643\r
644 if (File == NULL) {\r
645 return EFI_INVALID_PARAMETER;\r
646 }\r
647\r
648 Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);\r
649 if (EFI_ERROR (Status)) {\r
650 //\r
651 // TCG protocol is not installed. So, TPM is not present.\r
652 // Don't do any measurement, and directly return EFI_SUCCESS.\r
653 //\r
654 return EFI_SUCCESS;\r
655 }\r
656\r
657 ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);\r
658 Status = TcgProtocol->StatusCheck (\r
659 TcgProtocol, \r
660 &ProtocolCapability,\r
661 &TCGFeatureFlags,\r
662 &EventLogLocation,\r
663 &EventLogLastEntry\r
664 );\r
665 if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag) {\r
666 //\r
667 // TPM device doesn't work or activate.\r
668 //\r
669 return EFI_SUCCESS;\r
670 }\r
671\r
672 //\r
673 // Copy File Device Path\r
674 //\r
675 OrigDevicePathNode = DuplicateDevicePath (File);\r
676 ASSERT (OrigDevicePathNode != NULL);\r
677 \r
678 //\r
679 // 1. Check whether this device path support BlockIo protocol.\r
680 // Is so, this device path may be a GPT device path.\r
681 //\r
682 DevicePathNode = OrigDevicePathNode;\r
683 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);\r
684 if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) {\r
685 //\r
686 // Find the gpt partion on the given devicepath\r
687 //\r
688 DevicePathNode = OrigDevicePathNode;\r
689 while (!IsDevicePathEnd (DevicePathNode)) {\r
690 //\r
691 // Find the Gpt partition\r
692 //\r
693 if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&\r
694 DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {\r
695 //\r
696 // Check whether it is a gpt partition or not\r
697 // \r
698 if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER && \r
699 ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) {\r
700\r
701 //\r
702 // Change the partition device path to its parent device path (disk) and get the handle.\r
703 //\r
704 DevicePathNode->Type = END_DEVICE_PATH_TYPE;\r
705 DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
706 DevicePathNode = OrigDevicePathNode;\r
707 Status = gBS->LocateDevicePath (\r
708 &gEfiDiskIoProtocolGuid,\r
709 &DevicePathNode,\r
710 &Handle\r
711 );\r
712 if (!EFI_ERROR (Status)) {\r
713 //\r
714 // Measure GPT disk.\r
715 //\r
716 Status = TcgMeasureGptTable (TcgProtocol, Handle);\r
717 if (!EFI_ERROR (Status)) {\r
718 //\r
719 // GPT disk check done.\r
720 //\r
721 mMeasureGptTableFlag = TRUE;\r
722 }\r
723 }\r
724 FreePool (OrigDevicePathNode);\r
725 OrigDevicePathNode = DuplicateDevicePath (File);\r
726 ASSERT (OrigDevicePathNode != NULL);\r
727 break;\r
728 }\r
729 }\r
730 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
731 }\r
732 }\r
733 \r
734 //\r
735 // 2. Measure PE image.\r
736 //\r
737 ApplicationRequired = FALSE;\r
738\r
739 //\r
740 // Check whether this device path support FV2 protocol.\r
741 //\r
742 DevicePathNode = OrigDevicePathNode;\r
743 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);\r
744 if (!EFI_ERROR (Status)) {\r
745 //\r
746 // Don't check FV image, and directly return EFI_SUCCESS.\r
747 // It can be extended to the specific FV authentication according to the different requirement.\r
748 //\r
749 if (IsDevicePathEnd (DevicePathNode)) {\r
750 return EFI_SUCCESS;\r
751 }\r
752 //\r
753 // The image from Firmware image will not be mearsured.\r
754 // Current policy doesn't measure PeImage from Firmware if it is driver\r
755 // If the got PeImage is application, it will be still be measured.\r
756 //\r
757 ApplicationRequired = TRUE;\r
758 }\r
759 \r
760 //\r
761 // File is not found.\r
762 //\r
763 if (FileBuffer == NULL) {\r
764 Status = EFI_SECURITY_VIOLATION;\r
765 goto Finish;\r
766 }\r
767\r
28186d45
ED
768 mImageSize = FileSize;\r
769 mFileBuffer = FileBuffer;\r
770\r
0c18794e 771 //\r
772 // Measure PE Image\r
773 //\r
774 DevicePathNode = OrigDevicePathNode;\r
775 ZeroMem (&ImageContext, sizeof (ImageContext));\r
776 ImageContext.Handle = (VOID *) FileBuffer;\r
e0192326 777 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead;\r
0c18794e 778\r
779 //\r
780 // Get information about the image being loaded\r
781 //\r
782 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
783 if (EFI_ERROR (Status)) {\r
784 //\r
785 // The information can't be got from the invalid PeImage\r
786 //\r
787 goto Finish;\r
788 }\r
789 \r
790 //\r
791 // Measure only application if Application flag is set\r
792 // Measure drivers and applications if Application flag is not set\r
793 //\r
794 if ((!ApplicationRequired) || \r
795 (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { \r
796 //\r
797 // Print the image path to be measured.\r
798 // \r
799 DEBUG_CODE_BEGIN ();\r
800 CHAR16 *ToText;\r
801 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;\r
802 Status = gBS->LocateProtocol (\r
803 &gEfiDevicePathToTextProtocolGuid,\r
804 NULL,\r
805 (VOID **) &DevPathToText\r
806 );\r
807 if (!EFI_ERROR (Status)) {\r
808 ToText = DevPathToText->ConvertDevicePathToText (\r
809 DevicePathNode,\r
810 FALSE,\r
811 TRUE\r
812 );\r
813 if (ToText != NULL) {\r
814 DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));\r
815 }\r
816 }\r
817 DEBUG_CODE_END ();\r
818\r
819 //\r
820 // Measure PE image into TPM log.\r
821 //\r
822 Status = TcgMeasurePeImage (\r
823 TcgProtocol,\r
824 (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, \r
825 FileSize, \r
826 (UINTN) ImageContext.ImageAddress, \r
827 ImageContext.ImageType, \r
828 DevicePathNode\r
829 );\r
830 }\r
831\r
832 //\r
833 // Done, free the allocated resource.\r
834 //\r
835Finish:\r
836 FreePool (OrigDevicePathNode);\r
837\r
838 return Status;\r
839}\r
840\r
841/**\r
842 Register the security handler to provide TPM measure boot service.\r
843\r
844 @param ImageHandle ImageHandle of the loaded driver.\r
845 @param SystemTable Pointer to the EFI System Table.\r
846\r
847 @retval EFI_SUCCESS Register successfully.\r
848 @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.\r
849**/\r
850EFI_STATUS\r
851EFIAPI\r
852DxeTpmMeasureBootLibConstructor (\r
853 IN EFI_HANDLE ImageHandle,\r
854 IN EFI_SYSTEM_TABLE *SystemTable\r
855 )\r
856{\r
857 return RegisterSecurityHandler (\r
858 DxeTpmMeasureBootHandler,\r
859 EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
860 );\r
861}\r