Skip to content

Commit

Permalink
UefiPayloadPkg,SecurityPkg: import coreboot's TPM log
Browse files Browse the repository at this point in the history
Find the log using UefiPayloadPkg/CbParseLib in
UefiPayloadPkg/BlSupportPei and create HOBs like those produced by
TcgPei and Tcg2Pei all of which will be picked up by TcgDxe and Tcg2Dxe.

TPM1 case is quite simple:
 - use coreboot's Spec ID Event as EDK doesn't seem to add one of its
   own

TPM2 case is more advanced and is more complicated:
 - don't create a HOB for coreboot's Spec ID Event (the first entry)
   because TPM2 can have multiple digests and coreboot produces at most
   one
 - when importing HOBs in Tcg2Dxe add missing hashes of OneDigest kind
   from TXT spec (0x01 followed by 0x00 bytes) just to not come up with
   some custom placeholder

Signed-off-by: Sergii Dmytruk <[email protected]>
  • Loading branch information
SergiiDmytruk committed Jun 12, 2024
1 parent ea90d54 commit f5283a2
Show file tree
Hide file tree
Showing 6 changed files with 404 additions and 47 deletions.
137 changes: 91 additions & 46 deletions SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1057,55 +1057,105 @@ 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.
**/
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;

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);
//
// 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 (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 (!(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;
}

CopyMem (Buffer, &HashAlg, sizeof(HashAlg));
Buffer = (UINT8 *)Buffer + sizeof(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);

return Buffer;
Expand Down Expand Up @@ -1552,12 +1602,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;
Expand Down Expand Up @@ -1814,11 +1862,11 @@ SetupEventLog (
Status = EFI_SUCCESS;
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,
Expand All @@ -1828,8 +1876,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.
//
Expand All @@ -1838,26 +1893,18 @@ 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,
Expand All @@ -1869,6 +1916,7 @@ SetupEventLog (
break;
}
FreePool (TcgEvent);
GuidHob.Raw = GET_NEXT_HOB (GuidHob);
}
}
}
Expand Down Expand Up @@ -2863,13 +2911,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 ((EFI_D_INFO, "Tcg2.SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs));
DEBUG ((EFI_D_INFO, "Tcg2.HashAlgorithmBitmap - 0x%08x\n", mTcgDxeData.BsCap.HashAlgorithmBitmap));
Expand Down
146 changes: 146 additions & 0 deletions UefiPayloadPkg/BlSupportPei/BlSupportPei.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "BlSupportPei.h"

#include <Coreboot.h>
#include <IndustryStandard/UefiTcgPlatform.h>

#define LEGACY_8259_MASK_REGISTER_MASTER 0x21
#define LEGACY_8259_MASK_REGISTER_SLAVE 0xA1

Expand Down Expand Up @@ -495,6 +498,140 @@ 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
Expand Down Expand Up @@ -757,6 +894,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;
}

Loading

0 comments on commit f5283a2

Please sign in to comment.