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