diff --git a/DasharoModulePkg/Library/DasharoVariablesLib/DasharoVariablesLib.c b/DasharoModulePkg/Library/DasharoVariablesLib/DasharoVariablesLib.c index 8eed0d8e25..fa42bfd3ff 100644 --- a/DasharoModulePkg/Library/DasharoVariablesLib/DasharoVariablesLib.c +++ b/DasharoModulePkg/Library/DasharoVariablesLib/DasharoVariablesLib.c @@ -338,6 +338,27 @@ MeasureVariable ( return Status; } +/** + A comparison function for sorting an array of variable names. + + @param Buffer1 Pointer to pointer of the first variable name. + @param Buffer2 Pointer to pointer of the second variable name. + + @retval <0 The first variable name is less than the second one. + @retval =0 The names are equal. + @retval >0 The first variable name is greater than the second one. +**/ +STATIC +INTN +EFIAPI +CompareVariableNames ( + IN CONST VOID *Buffer1, + IN CONST VOID *Buffer2 + ) +{ + return StrCmp (*(CONST CHAR16 **) Buffer1, *(CONST CHAR16 **) Buffer2); +} + /** Measures single all existing variables with the specified GUID. @@ -357,12 +378,25 @@ MeasureVariables ( UINTN MaxNameSize; UINTN NameSize; EFI_GUID Guid; + CHAR16 **Names; + UINTN NameCount; + CHAR16 SortBuf; + UINTN MaxNameCount; + UINTN Index; - MaxNameSize = 32*sizeof (CHAR16); + MaxNameSize = 32 * sizeof (CHAR16); Name = AllocateZeroPool (MaxNameSize); if (Name == NULL) return EFI_OUT_OF_RESOURCES; + MaxNameCount = 32; + NameCount = 0; + Names = AllocatePool (MaxNameCount * sizeof (*Names)); + if (Names == NULL) { + FreePool(Name); + return EFI_OUT_OF_RESOURCES; + } + while (TRUE) { NameSize = MaxNameSize; Status = gRT->GetNextVariableName (&NameSize, Name, &Guid); @@ -373,7 +407,7 @@ MeasureVariables ( break; } - StrnCpyS (NewBuf, NameSize/sizeof (CHAR16), Name, MaxNameSize/sizeof (CHAR16)); + StrnCpyS (NewBuf, NameSize / sizeof (CHAR16), Name, MaxNameSize / sizeof (CHAR16)); FreePool (Name); Name = NewBuf; @@ -390,11 +424,59 @@ MeasureVariables ( if (EFI_ERROR (Status)) break; - if (CompareGuid (&Guid, Vendor)) - MeasureVariable (Name, Vendor); + if (!CompareGuid (&Guid, Vendor)) + continue; + + if (NameCount == MaxNameCount - 1) { + Names = ReallocatePool ( + MaxNameCount * sizeof (*Names), + 2 * MaxNameCount * sizeof (*Names), + Names + ); + if (Names == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + MaxNameCount *= 2; + } + + Names[NameCount] = AllocateCopyPool (NameSize, Name); + if (Names[NameCount] == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + NameCount++; } + if (Status == EFI_SUCCESS) { + // + // Achieve predictable ordering of variables by sorting them by name within + // a particular vendor. + // + QuickSort ( + Names, + NameCount, + sizeof (*Names), + CompareVariableNames, + &SortBuf + ); + + for (Index = 0; Index < NameCount; Index++) { + Status = MeasureVariable (Names[Index], Vendor); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "%a(): Failed to measure variable: %g:%s.\n", + __FUNCTION__, Vendor, Name)); + } + } + } + + for (Index = 0; Index < NameCount; Index++) + FreePool (Names[Index]); + FreePool (Name); + FreePool (Names); return Status; } diff --git a/DasharoPayloadPkg/BlSupportPei/BlSupportPei.c b/DasharoPayloadPkg/BlSupportPei/BlSupportPei.c index df0bdc9daa..d46f749457 100644 --- a/DasharoPayloadPkg/BlSupportPei/BlSupportPei.c +++ b/DasharoPayloadPkg/BlSupportPei/BlSupportPei.c @@ -8,6 +8,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "BlSupportPei.h" +#include +#include + #define LEGACY_8259_MASK_REGISTER_MASTER 0x21 #define LEGACY_8259_MASK_REGISTER_SLAVE 0xA1 @@ -496,6 +499,139 @@ ValidateFvHeader ( return EFI_SUCCESS; } +STATIC +EFI_STATUS +ParseAndPublishTPM1Log ( + CONST struct tcpa_spec_entry *SpecEntry, + UINTN Size +) +{ + UINT8 ZeroBlock[sizeof (struct tcpa_spec_entry)]; + struct tcpa_log_entry *Entry; + EFI_PHYSICAL_ADDRESS Start; + EFI_PHYSICAL_ADDRESS Current; + UINTN EntrySize; + + // This must hold to avoid integer overflow below. + ASSERT (Size >= sizeof (*Entry)); + + ZeroMem (ZeroBlock, sizeof (ZeroBlock)); + + Start = (EFI_PHYSICAL_ADDRESS)(UINTN) SpecEntry; + Current = Start; + while (Current - Start < Size - sizeof (*Entry) && + CompareMem ((VOID *)(UINTN) Current, (VOID *) ZeroBlock, sizeof (ZeroBlock)) != 0) { + Entry = (VOID *)(UINTN) Current; + EntrySize = sizeof (*Entry) + Entry->event_data_size; + + BuildGuidDataHob (&gTcgEventEntryHobGuid, Entry, EntrySize); + Current += EntrySize; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ParseAndPublishTPM2Log ( + CONST struct tcg_efi_spec_id_event *SpecEntry, + UINTN Size +) +{ + UINT8 ZeroBlock[sizeof (struct tcg_pcr_event2_header)]; + struct tcg_pcr_event2_header *Header; + EFI_PHYSICAL_ADDRESS Start; + EFI_PHYSICAL_ADDRESS Current; + UINTN EntrySize; + UINTN DigestsSize; + UINTN Idx; + + // This must hold to avoid integer overflow below. + ASSERT (Size >= sizeof (*Header)); + + ZeroMem (ZeroBlock, sizeof (ZeroBlock)); + + DigestsSize = 0; + for (Idx = 0; Idx < SpecEntry->num_of_algorithms; ++Idx) { + DigestsSize += sizeof (UINT16) + SpecEntry->digest_sizes[Idx].digest_size; + } + + Start = (EFI_PHYSICAL_ADDRESS)(UINTN) SpecEntry; + + // Not adding Spec ID Event for TPM2 because Tcg2Dxe adds one, coreboot's + // event would have to be modified to be suitable due to the list of + // algorithms there. + Current = Start + sizeof (struct tcpa_log_entry) + SpecEntry->event_size; + + while (Current - Start < Size - sizeof (*Header) && + CompareMem ((VOID *)(UINTN) Current, (VOID *) ZeroBlock, sizeof (ZeroBlock)) != 0) { + Header = (VOID *)(UINTN) Current; + EntrySize = sizeof (*Header) + DigestsSize; + + // Event data size field and data itself. + EntrySize += sizeof (UINT32) + *(CONST UINT32 *)(UINTN) (Current + EntrySize); + + BuildGuidDataHob (&gTcgEvent2EntryHobGuid, Header, EntrySize); + Current += EntrySize; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ParseAndPublishTPMLog ( + VOID +) +{ + RETURN_STATUS Status; + VOID *LogBase; + UINTN LogSize; + + const struct tcpa_spec_entry *Tcg1Entry; + const struct tcg_efi_spec_id_event *Tcg2Entry; + + Status = ParseTPMLog (&LogBase, &LogSize); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "%a: Not publishing coreboot's TPM log entries because: %r.\n", + __FUNCTION__, Status + )); + return Status; + } + + Tcg1Entry = LogBase; + if (AsciiStrCmp((CONST CHAR8 *)Tcg1Entry->signature, TCPA_SPEC_ID_EVENT_SIGNATURE) == 0) { + if (Tcg1Entry->spec_version_major == 1 && + Tcg1Entry->spec_version_minor == 2 && + Tcg1Entry->spec_errata >= 1 && + Tcg1Entry->entry.event_type == EV_NO_ACTION) { + return ParseAndPublishTPM1Log (Tcg1Entry, LogSize); + } + + DEBUG ((DEBUG_WARN, "%a: Unknown TPM1.2 log specification.\n", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + Tcg2Entry = LogBase; + if (AsciiStrCmp((CONST CHAR8 *)Tcg1Entry->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE) == 0) { + if (Tcg2Entry->spec_version_major == 2 && + Tcg2Entry->spec_version_minor == 0 && + Tcg2Entry->event_type == EV_NO_ACTION) { + return ParseAndPublishTPM2Log (Tcg2Entry, LogSize); + } + + DEBUG ((DEBUG_WARN, "%a: Unknown TPM2 log specification.\n", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + DEBUG ((DEBUG_WARN, + "%a: Unknown TPM log specification %.*s.\n", + __FUNCTION__, (int)sizeof(Tcg2Entry->signature), (CONST CHAR8 *)Tcg2Entry->signature)); + return EFI_UNSUPPORTED; +} + /** This is the entrypoint of PEIM @@ -767,6 +903,15 @@ BlPeiEntryPoint ( IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF); IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF); + // + // Parse coreboot's log. + // + Status = ParseAndPublishTPMLog (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error when parsing platform info, Status = %r\n", Status)); + return Status; + } + return EFI_SUCCESS; } diff --git a/DasharoPayloadPkg/BlSupportPei/BlSupportPei.inf b/DasharoPayloadPkg/BlSupportPei/BlSupportPei.inf index 08a14e0040..74540e655d 100644 --- a/DasharoPayloadPkg/BlSupportPei/BlSupportPei.inf +++ b/DasharoPayloadPkg/BlSupportPei/BlSupportPei.inf @@ -34,6 +34,7 @@ EmbeddedPkg/EmbeddedPkg.dec IntelFsp2Pkg/IntelFsp2Pkg.dec IntelFsp2WrapperPkg/IntelFsp2WrapperPkg.dec + SecurityPkg/SecurityPkg.dec DasharoPayloadPkg/DasharoPayloadPkg.dec UefiCpuPkg/UefiCpuPkg.dec @@ -64,6 +65,8 @@ gEfiVariableGuid gEfiAuthenticatedVariableGuid gEdkiiNvVarStoreFormattedGuid + gTcgEventEntryHobGuid + gTcgEvent2EntryHobGuid [Ppis] gEfiPeiMasterBootModePpiGuid diff --git a/DasharoPayloadPkg/Include/Coreboot.h b/DasharoPayloadPkg/Include/Coreboot.h index e3a624f9d3..c98ac4a88a 100644 --- a/DasharoPayloadPkg/Include/Coreboot.h +++ b/DasharoPayloadPkg/Include/Coreboot.h @@ -264,6 +264,7 @@ struct cb_smmstorev2 { UINT8 unused[3]; /* Set to zero */ }; +#define CB_TAG_CBMEM_ENTRY 0x0031 #define CB_TAG_VBOOT_WORKBUF 0x0034 struct cb_cbmem_entry { @@ -762,4 +763,67 @@ struct cb_range { UINT32 range_size; } __attribute__((packed)); +#define CBMEM_ID_TCPA_TCG_LOG 0x54445041 /* TPM log per TPM 1.2 specification */ +#define CBMEM_ID_TPM2_TCG_LOG 0x54504d32 /* TPM log per TPM 2.0 specification */ + +#define TCPA_SPEC_ID_EVENT_SIGNATURE "Spec ID Event00" +#define TCG_EFI_SPEC_ID_EVENT_SIGNATURE "Spec ID Event03" + +struct tcpa_log_entry { + UINT32 pcr; + UINT32 event_type; + UINT8 digest[20]; + UINT32 event_data_size; + UINT8 event[0]; +} __attribute__ ((packed)); + +struct tcpa_spec_entry { + struct tcpa_log_entry entry; + UINT8 signature[16]; + UINT32 platform_class; + UINT8 spec_version_minor; + UINT8 spec_version_major; + UINT8 spec_errata; + UINT8 reserved; + UINT8 vendor_info_size; + UINT8 vendor_info[0]; +} __attribute__ ((packed)); + +#define TPM2_ALG_SHA1 0x0004 +#define TPM2_ALG_SHA256 0x000B +#define TPM2_ALG_SHA384 0x000C +#define TPM2_ALG_SHA512 0x000D +#define TPM2_ALG_SM3_256 0x0012 + +struct tcg_pcr_event2_header { + UINT32 pcr_index; + UINT32 event_type; + UINT32 digest_count; + UINT8 digests[0]; + /* UINT32 event_size; */ + /* UINT8 event[0]; */ +} __attribute__ ((packed)); + +struct tpm_digest_sizes { + UINT16 alg_id; + UINT16 digest_size; +} __attribute__ ((packed)); + +struct tcg_efi_spec_id_event { + UINT32 pcr_index; + UINT32 event_type; + UINT8 digest[20]; + UINT32 event_size; + UINT8 signature[16]; + UINT32 platform_class; + UINT8 spec_version_minor; + UINT8 spec_version_major; + UINT8 spec_errata; + UINT8 uintn_size; + UINT32 num_of_algorithms; + struct tpm_digest_sizes digest_sizes[0]; /* variable number of members */ + /* UINT8 vendor_info_size; */ + /* UINT8 vendor_info[vendor_info_size]; */ +} __attribute__ ((packed)); + #endif // _COREBOOT_PEI_H_INCLUDED_ diff --git a/DasharoPayloadPkg/Include/Library/BlParseLib.h b/DasharoPayloadPkg/Include/Library/BlParseLib.h index 353e0a0eaa..b6130cb715 100644 --- a/DasharoPayloadPkg/Include/Library/BlParseLib.h +++ b/DasharoPayloadPkg/Include/Library/BlParseLib.h @@ -153,6 +153,26 @@ ParseTPMPPIInfo ( OUT TCG_PHYSICAL_PRESENCE_INFO *PPIInfo ); +/** + Find TPM log in TCG format if any. + + The caller is expected to parse the first event of the log to determine its + version. + + @param Base Pointer the start of the log + @param Size Size of the log + + @retval RETURN_SUCCESS Successfully found TPM log. + @retval RETURN_NOT_FOUND Failed to find TPM log. + +**/ +RETURN_STATUS +EFIAPI +ParseTPMLog ( + OUT VOID **Base, + OUT UINTN *Size + ); + /** Acquire Vboot recovery information from coreboot diff --git a/DasharoPayloadPkg/Library/CbParseLib/CbParseLib.c b/DasharoPayloadPkg/Library/CbParseLib/CbParseLib.c index d51a2473d8..67d2012187 100644 --- a/DasharoPayloadPkg/Library/CbParseLib/CbParseLib.c +++ b/DasharoPayloadPkg/Library/CbParseLib/CbParseLib.c @@ -239,6 +239,42 @@ FindCbTag ( } +/** + Find location and size of a coreboot record of the given type. + + @param Tag The tag id to be found + @param Size Optionally (if not NULL) set to size of the tag + + @retval NULL The Tag is not found. + @retval Others The pointer to the record found. + +**/ +STATIC +struct cb_cbmem_entry * +FindCbEntry ( + IN UINT32 Id + ) +{ + struct cb_header *Header; + struct cb_cbmem_entry *Entry; + UINT8 *TmpPtr; + UINTN Idx; + + Header = (struct cb_header *) GetParameterBase (); + + TmpPtr = (UINT8 *)Header + Header->header_bytes; + for (Idx = 0; Idx < Header->table_entries; Idx++) { + Entry = (struct cb_cbmem_entry *)TmpPtr; + if (Entry->tag == CB_TAG_CBMEM_ENTRY && Entry->id == Id) { + return Entry; + } + TmpPtr += Entry->size; + } + + return NULL; +} + + /** Find the given table with TableId from the given coreboot memory Root. @@ -693,6 +729,49 @@ ParseTPMPPIInfo ( return RETURN_SUCCESS; } +/** + Find TPM log in TCG format if any. + + The caller is expected to parse the first event of the log to determine its + version. + + @param Base Pointer the start of the log + @param Size Size of the log + + @retval RETURN_SUCCESS Successfully found TPM log. + @retval RETURN_NOT_FOUND Failed to find TPM log. + +**/ +RETURN_STATUS +EFIAPI +ParseTPMLog ( + OUT VOID **Base, + OUT UINTN *Size + ) +{ + struct cb_cbmem_entry *Entry; + + // + // TPM2 format is the more capable "agile" format, so start with it like some + // other parts of EDK test for TPM2 before testing for TPM1. + // + // Could return log version, but the caller should probably validate that the + // buffer isn't empty and checking for correct Spec ID Event is a good way of + // going about it. + // + + Entry = FindCbEntry (CBMEM_ID_TPM2_TCG_LOG); + if (Entry == NULL) + Entry = FindCbEntry (CBMEM_ID_TCPA_TCG_LOG); + + if (Entry == NULL) + return RETURN_NOT_FOUND; + + *Base = (void *)(UINTN) Entry->address; + *Size = Entry->entry_size; + return RETURN_SUCCESS; +} + STATIC CONST CHAR8 * GetRecoveryReasonString( diff --git a/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c b/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c index 6eb04c0144..122a3b6848 100644 --- a/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c +++ b/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c @@ -724,31 +724,43 @@ FillBufferWithBootHashAlg ( /** Set ConfigInfo according to TpmAlgHash. - @param[in,out] Tcg2ConfigInfo TCG2 config info. - @param[in] TpmAlgHash TpmAlgHash. + @param[in,out] Tcg2ConfigInfo TCG2 config info. + @param[in] TpmAlgHash TpmAlgHash. + @param[in] SupportedHashAlgorithms Mask of supported hash algorithms. **/ VOID SetConfigInfo ( - IN OUT TCG2_CONFIGURATION_INFO *Tcg2ConfigInfo, - IN UINT32 TpmAlgHash + IN OUT TCG2_CONFIGURATION_INFO *Tcg2ConfigInfo, + IN UINT32 TpmAlgHash, + EFI_TCG2_EVENT_ALGORITHM_BITMAP SupportedHashAlgorithms ) { switch (TpmAlgHash) { case TPM_ALG_SHA1: - Tcg2ConfigInfo->Sha1Supported = TRUE; + if (SupportedHashAlgorithms & HASH_ALG_SHA1) { + Tcg2ConfigInfo->Sha1Supported = TRUE; + } break; case TPM_ALG_SHA256: - Tcg2ConfigInfo->Sha256Supported = TRUE; + if (SupportedHashAlgorithms & HASH_ALG_SHA256) { + Tcg2ConfigInfo->Sha256Supported = TRUE; + } break; case TPM_ALG_SHA384: - Tcg2ConfigInfo->Sha384Supported = TRUE; + if (SupportedHashAlgorithms & HASH_ALG_SHA384) { + Tcg2ConfigInfo->Sha384Supported = TRUE; + } break; case TPM_ALG_SHA512: - Tcg2ConfigInfo->Sha512Supported = TRUE; + if (SupportedHashAlgorithms & HASH_ALG_SHA512) { + Tcg2ConfigInfo->Sha512Supported = TRUE; + } break; case TPM_ALG_SM3_256: - Tcg2ConfigInfo->Sm3Supported = TRUE; + if (SupportedHashAlgorithms & HASH_ALG_SM3_256) { + Tcg2ConfigInfo->Sm3Supported = TRUE; + } break; } } @@ -809,16 +821,17 @@ InstallTcg2ConfigForm ( IN OUT TCG2_CONFIG_PRIVATE_DATA *PrivateData ) { - EFI_STATUS Status; - EFI_HII_HANDLE HiiHandle; - EFI_HANDLE DriverHandle; - EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - UINTN Index; - TPML_PCR_SELECTION Pcrs; - CHAR16 TempBuffer[1024]; - TCG2_CONFIGURATION_INFO Tcg2ConfigInfo; - TPM2_PTP_INTERFACE_TYPE TpmDeviceInterfaceDetected; - BOOLEAN IsCmdImp = FALSE; + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + UINTN Index; + TPML_PCR_SELECTION Pcrs; + CHAR16 TempBuffer[1024]; + TCG2_CONFIGURATION_INFO Tcg2ConfigInfo; + TPM2_PTP_INTERFACE_TYPE TpmDeviceInterfaceDetected; + BOOLEAN IsCmdImp = FALSE; + EFI_TCG2_EVENT_ALGORITHM_BITMAP SupportedHashAlgorithms; DriverHandle = NULL; ConfigAccess = &PrivateData->ConfigAccess; @@ -879,6 +892,8 @@ InstallTcg2ConfigForm ( break; } + SupportedHashAlgorithms = PcdGet32 (PcdTcg2HashAlgorithmBitmap); + ZeroMem (&Tcg2ConfigInfo, sizeof (Tcg2ConfigInfo)); Status = Tpm2GetCapabilityPcrs (&Pcrs); if (EFI_ERROR (Status)) { @@ -897,7 +912,7 @@ InstallTcg2ConfigForm ( TempBuffer[0] = 0; for (Index = 0; Index < Pcrs.count; Index++) { AppendBufferWithTpmAlgHash (TempBuffer, sizeof (TempBuffer), Pcrs.pcrSelections[Index].hash); - SetConfigInfo (&Tcg2ConfigInfo, Pcrs.pcrSelections[Index].hash); + SetConfigInfo (&Tcg2ConfigInfo, Pcrs.pcrSelections[Index].hash, SupportedHashAlgorithms); } HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT), TempBuffer, NULL); @@ -910,7 +925,7 @@ InstallTcg2ConfigForm ( Tcg2ConfigInfo.ChangeEPSSupported = IsCmdImp; - FillBufferWithBootHashAlg (TempBuffer, sizeof (TempBuffer), PcdGet32 (PcdTcg2HashAlgorithmBitmap)); + FillBufferWithBootHashAlg (TempBuffer, sizeof (TempBuffer), SupportedHashAlgorithms); HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_BIOS_HASH_ALGO_CONTENT), TempBuffer, NULL); // diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index 0a6a34986f..81b4c298cf 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -11,6 +11,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include @@ -20,6 +21,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include +#include #include #include #include @@ -45,6 +47,40 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include + +#pragma pack(1) + +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + // Flags field is replaced in version 4 and above + // BIT0~15: PlatformClass This field is only valid for version 4 and above + // BIT16~31: Reserved + UINT32 Flags; + UINT64 AddressOfControlArea; + UINT32 StartMethod; + UINT8 PlatformSpecificParameters[12]; // size up to 12 + UINT32 Laml; // Optional + UINT64 Lasa; // Optional +} EFI_TPM2_ACPI_TABLE_V4; + +EFI_TPM2_ACPI_TABLE_V4 mTpm2AcpiTemplate = { + { + EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE, + sizeof (mTpm2AcpiTemplate), + EFI_TPM2_ACPI_TABLE_REVISION, + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 0, // BIT0~15: PlatformClass + // BIT16~31: Reserved + 0, // Control Area + EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod +}; + +#pragma pack() #define PERF_ID_TCG2_DXE 0x3120 @@ -1046,13 +1082,37 @@ GetDigestListBinSize ( return TotalSize; } +STATIC VOID * +FindHashInDigestListBin ( + IN VOID *DigestListBin, + TPMI_ALG_HASH HashAlg + ) +{ + UINTN Index; + UINT32 Count; + TPMI_ALG_HASH Alg; + + Count = ReadUnaligned32 (DigestListBin); + DigestListBin = (UINT8 *)DigestListBin + sizeof(Count); + for (Index = 0; Index < Count; Index++) { + Alg = ReadUnaligned16 (DigestListBin); + DigestListBin = (UINT8 *)DigestListBin + sizeof(Alg); + + if (Alg == HashAlg) + return DigestListBin; + + DigestListBin = (UINT8 *)DigestListBin + GetHashSizeFromAlgo (Alg); + } + + return NULL; +} + /** Copy TPML_DIGEST_VALUES compact binary into a buffer @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary. @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy. - @param[out] HashAlgorithmMaskCopied Pointer to HASH bits corresponding to the digests copied. @return The end of buffer to hold TPML_DIGEST_VALUES compact binary. **/ @@ -1060,41 +1120,64 @@ VOID * CopyDigestListBinToBuffer ( IN OUT VOID *Buffer, IN VOID *DigestListBin, - IN UINT32 HashAlgorithmMask, - OUT UINT32 *HashAlgorithmMaskCopied + IN UINT32 HashAlgorithmMask ) { UINTN Index; UINT16 DigestSize; - UINT32 Count; TPMI_ALG_HASH HashAlg; UINT32 DigestListCount; UINT32 *DigestListCountPtr; + TPMI_ALG_HASH HashAlgs[5]; + VOID *Digest; + + HashAlgs[0] = TPM_ALG_SHA1; + HashAlgs[1] = TPM_ALG_SHA256; + HashAlgs[2] = TPM_ALG_SM3_256; + HashAlgs[3] = TPM_ALG_SHA384; + HashAlgs[4] = TPM_ALG_SHA512; DigestListCountPtr = (UINT32 *)Buffer; + Buffer = (UINT8 *)Buffer + sizeof(UINT32); + DigestListCount = 0; - (*HashAlgorithmMaskCopied) = 0; + // + // Make sure output buffer conforms to HashAlgorithmMask. + // + // Copy digests from the entry if they are present, otherwise add missing + // digests filled as what's called "OneDigest" in TXT Software + // Development Guide (not really related, but alternatives are zeroes or + // 0xFFs, might as well use a value documented somewhere). + // + for (Index = 0; Index < ARRAY_SIZE (HashAlgs); Index++) { + HashAlg = HashAlgs[Index]; + Digest = FindHashInDigestListBin (DigestListBin, HashAlg); + DigestSize = GetHashSizeFromAlgo (HashAlg); + + if (!(HashAlgorithmMask & GetHashMaskFromAlgo (HashAlg))) { + // Not active. + if (Digest != NULL) + DEBUG ((DEBUG_WARN, "%a(): Event log entry includes HashAlg (0x%x) unsupported by PCR bank\n", + __FUNCTION__, HashAlg)); + continue; + } - Count = ReadUnaligned32 (DigestListBin); - Buffer = (UINT8 *)Buffer + sizeof (Count); - DigestListBin = (UINT8 *)DigestListBin + sizeof (Count); - for (Index = 0; Index < Count; Index++) { - HashAlg = ReadUnaligned16 (DigestListBin); - DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg); - DigestSize = GetHashSizeFromAlgo (HashAlg); + CopyMem (Buffer, &HashAlg, sizeof(HashAlg)); + Buffer = (UINT8 *)Buffer + sizeof(HashAlg); - if (IsHashAlgSupportedInHashAlgorithmMask (HashAlg, HashAlgorithmMask)) { - CopyMem (Buffer, &HashAlg, sizeof (HashAlg)); - Buffer = (UINT8 *)Buffer + sizeof (HashAlg); - CopyMem (Buffer, DigestListBin, DigestSize); - Buffer = (UINT8 *)Buffer + DigestSize; - DigestListCount++; - (*HashAlgorithmMaskCopied) |= GetHashMaskFromAlgo (HashAlg); + if (Digest == NULL) { + // Missing, use "OneDigest". + ZeroMem (Buffer, DigestSize); + *(UINT8 *)Buffer = 1; + DEBUG ((DEBUG_WARN, "%a(): Event log entry is missing HashAlg (0x%x) supported by PCR bank\n", + __FUNCTION__, HashAlg)); } else { - DEBUG ((DEBUG_ERROR, "WARNING: CopyDigestListBinToBuffer Event log has HashAlg unsupported by PCR bank (0x%x)\n", HashAlg)); + CopyMem (Buffer, Digest, DigestSize); } - DigestListBin = (UINT8 *)DigestListBin + DigestSize; + Buffer = (UINT8 *)Buffer + DigestSize; + + DigestListCount++; } WriteUnaligned32 (DigestListCountPtr, DigestListCount); @@ -1554,12 +1637,10 @@ SetupEventLog ( EFI_PHYSICAL_ADDRESS Lasa; UINTN Index; VOID *DigestListBin; - TPML_DIGEST_VALUES TempDigestListBin; UINT32 DigestListBinSize; UINT8 *Event; UINT32 EventSize; UINT32 *EventSizePtr; - UINT32 HashAlgorithmMaskCopied; TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; UINT8 TempBuf[sizeof (TCG_EfiSpecIDEventStruct) + sizeof (UINT32) + (HASH_COUNT * sizeof (TCG_EfiSpecIdEventAlgorithmSize)) + sizeof (UINT8)]; TCG_PCR_EVENT_HDR SpecIdEvent; @@ -1825,11 +1906,11 @@ SetupEventLog ( while (!EFI_ERROR (Status) && (GuidHob.Raw = GetNextGuidHob (mTcg2EventInfo[Index].EventGuid, GuidHob.Raw)) != NULL) { - TcgEvent = AllocateCopyPool (GET_GUID_HOB_DATA_SIZE (GuidHob.Guid), GET_GUID_HOB_DATA (GuidHob.Guid)); - ASSERT (TcgEvent != NULL); - GuidHob.Raw = GET_NEXT_HOB (GuidHob); switch (mTcg2EventInfo[Index].LogFormat) { case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: + TcgEvent = AllocateCopyPool (GET_GUID_HOB_DATA_SIZE (GuidHob.Guid), GET_GUID_HOB_DATA (GuidHob.Guid)); + ASSERT (TcgEvent != NULL); + Status = TcgDxeLogEvent ( mTcg2EventInfo[Index].LogFormat, TcgEvent, @@ -1839,8 +1920,15 @@ SetupEventLog ( ); break; case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: - DigestListBin = (UINT8 *)TcgEvent + sizeof (TCG_PCRINDEX) + sizeof (TCG_EVENTTYPE); + // + // This is a storage for new header. + // + TcgEvent = AllocatePool (sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE) + sizeof(TPML_DIGEST_VALUES) + sizeof(UINT32)); + ASSERT (TcgEvent != NULL); + + DigestListBin = (UINT8 *)GET_GUID_HOB_DATA (GuidHob.Guid) + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE); DigestListBinSize = GetDigestListBinSize (DigestListBin); + CopyMem (TcgEvent, GET_GUID_HOB_DATA (GuidHob.Guid), sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE)); // // Save event size. // @@ -1849,27 +1937,19 @@ SetupEventLog ( // // Filter inactive digest in the event2 log from PEI HOB. // - CopyMem (&TempDigestListBin, DigestListBin, GetDigestListBinSize (DigestListBin)); EventSizePtr = CopyDigestListBinToBuffer ( + TcgEvent + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE), DigestListBin, - &TempDigestListBin, - mTcgDxeData.BsCap.ActivePcrBanks, - &HashAlgorithmMaskCopied + mTcgDxeData.BsCap.ActivePcrBanks ); - if (HashAlgorithmMaskCopied != mTcgDxeData.BsCap.ActivePcrBanks) { - DEBUG (( - DEBUG_ERROR, - "ERROR: The event2 log includes digest hash mask 0x%x, but required digest hash mask is 0x%x\n", - HashAlgorithmMaskCopied, - mTcgDxeData.BsCap.ActivePcrBanks - )); - } // // Restore event size. // CopyMem (EventSizePtr, &EventSize, sizeof (UINT32)); - DigestListBinSize = GetDigestListBinSize (DigestListBin); + DigestListBinSize = GetDigestListBinSize (TcgEvent + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE)); + + DEBUG ((DEBUG_INFO, "%a: DigestListBinSize = %d\n", __FUNCTION__, DigestListBinSize)); Status = TcgDxeLogEvent ( mTcg2EventInfo[Index].LogFormat, @@ -1882,6 +1962,7 @@ SetupEventLog ( } FreePool (TcgEvent); + GuidHob.Raw = GET_NEXT_HOB (GuidHob); } } } @@ -2665,6 +2746,106 @@ InstallTcg2 ( return Status; } +/** + Publish TPM2 ACPI table + + @retval EFI_SUCCESS The TPM2 ACPI table is published successfully. + @retval Others The TPM2 ACPI table is not published. + +**/ +EFI_STATUS +PublishTpm2 ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN TableKey; + UINT64 OemTableId; + EFI_TPM2_ACPI_CONTROL_AREA *ControlArea; + TPM2_PTP_INTERFACE_TYPE InterfaceType; + + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA. + // The measurement has to be done before any update. + // Otherwise, the PCR record would be different after event log update + // or the PCD configuration change. + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + &mTpm2AcpiTemplate, + mTpm2AcpiTemplate.Header.Length + ); + + mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev); + DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision)); + + // + // PlatformClass is only valid for version 4 and above + // BIT0~15: PlatformClass + // BIT16~31: Reserved + // + if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) { + mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass); + DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF))); + } + + mTpm2AcpiTemplate.Laml = PcdGet32(PcdTpm2AcpiTableLaml); + mTpm2AcpiTemplate.Lasa = PcdGet64(PcdTpm2AcpiTableLasa); + if ((mTpm2AcpiTemplate.Header.Revision < EFI_TPM2_ACPI_TABLE_REVISION_4) || + (mTpm2AcpiTemplate.Laml == 0) || (mTpm2AcpiTemplate.Lasa == 0)) { + // + // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length. + // + mTpm2AcpiTemplate.Header.Length = sizeof(EFI_TPM2_ACPI_TABLE); + } + + InterfaceType = PcdGet8(PcdActiveTpmInterfaceType); + switch (InterfaceType) { + case Tpm2PtpInterfaceCrb: + mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE; + mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40; + ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea; + ControlArea->CommandSize = 0xF80; + ControlArea->ResponseSize = 0xF80; + ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80; + ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80; + break; + case Tpm2PtpInterfaceFifo: + case Tpm2PtpInterfaceTis: + break; + default: + DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType)); + break; + } + + CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId)); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64)); + mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); + mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + + // + // Construct ACPI table + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); + ASSERT_EFI_ERROR (Status); + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTpm2AcpiTemplate, + mTpm2AcpiTemplate.Header.Length, + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + /** The driver's entry point. It publishes EFI Tcg2 Protocol. @@ -2783,13 +2964,10 @@ DriverEntry ( } } - mTcgDxeData.BsCap.SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; - if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) == 0) { - // - // No need to expose TCG1.2 event log if SHA1 bank does not exist. - // - mTcgDxeData.BsCap.SupportedEventLogs &= ~EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; - } + // + // Only expose TCG2 event log for TPM2. + // + mTcgDxeData.BsCap.SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; DEBUG ((DEBUG_INFO, "Tcg2.SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs)); DEBUG ((DEBUG_INFO, "Tcg2.HashAlgorithmBitmap - 0x%08x\n", mTcgDxeData.BsCap.HashAlgorithmBitmap)); @@ -2853,5 +3031,11 @@ DriverEntry ( Status = InstallTcg2 (); DEBUG ((DEBUG_INFO, "InstallTcg2 - %r\n", Status)); + // + // Set TPM2 ACPI table + // + Status = PublishTpm2 (); + ASSERT_EFI_ERROR (Status); + return Status; } diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf index 9c54695efa..31d8a01b90 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf @@ -66,6 +66,7 @@ Tcg2PhysicalPresenceLib PeCoffLib DasharoVariablesLib + TpmMeasurementLib [Guids] ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" @@ -95,8 +96,14 @@ gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES gEfiVariableWriteArchProtocolGuid ## NOTIFY gEfiResetNotificationProtocolGuid ## CONSUMES + gEfiAcpiTableProtocolGuid ## CONSUMES [Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES @@ -109,8 +116,11 @@ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLaml ## PRODUCES gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLasa ## PRODUCES gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES [Depex] + gEfiAcpiTableProtocolGuid AND # According to PcdTpm2AcpiTableRev definition in SecurityPkg.dec # This PCD should be configured at DynamicHii or DynamicHiiEx. # So, this PCD read operation depends on GetVariable service. diff --git a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c index 1caaa4e319..ca448b04d1 100644 --- a/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c +++ b/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c @@ -307,7 +307,7 @@ SyncPcrAllocationsAndPcrMask ( { DEBUG ((DEBUG_INFO, "TpmActivePcrBanks & Tpm2PcrMask = 0x%08x\n", (TpmActivePcrBanks & Tpm2PcrMask))); DEBUG ((DEBUG_INFO, "TpmActivePcrBanks & BiosHashAlgorithmBitmap = 0x%08x\n", (TpmActivePcrBanks & BiosHashAlgorithmBitmap))); - NewTpmActivePcrBanks = TpmActivePcrBanks; + NewTpmActivePcrBanks = TpmHashAlgorithmBitmap; NewTpmActivePcrBanks &= Tpm2PcrMask; NewTpmActivePcrBanks &= BiosHashAlgorithmBitmap; DEBUG ((DEBUG_INFO, "NewTpmActivePcrBanks 0x%08x\n", NewTpmActivePcrBanks));