diff --git a/SecurityPkg/Applications/TpmShellApp/TpmShellApp.c b/SecurityPkg/Applications/TpmShellApp/TpmShellApp.c new file mode 100644 index 0000000000..239db169f6 --- /dev/null +++ b/SecurityPkg/Applications/TpmShellApp/TpmShellApp.c @@ -0,0 +1,1007 @@ +/** @file + +A UEFI shell application for testing TPM 2.0 Physical Presence Interface +operations, including querying and configuring PCR banks. + +Copyright (C) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Largest supported digest size (SHA-512). +#define MAX_DIGEST_SIZE SHA512_DIGEST_SIZE + +// TPM2_PCR_Read command size (tag + size + code + pcrSelectionIn). +#define TPM2_PCR_READ_CMD_SIZE 20 + +// Offset to the first digest byte in a TPM2_PCR_Read response. +#define TPM2_PCR_READ_RSP_DIGEST_OFFSET 30 + +typedef struct { + UINT32 HashMask; + UINT16 AlgId; + CONST CHAR8 *Name; +} HASH_ALG_INFO; + +STATIC CONST HASH_ALG_INFO mHashAlgTable[] = { + { EFI_TCG2_BOOT_HASH_ALG_SHA1, TPM_ALG_SHA1, "SHA1" }, + { EFI_TCG2_BOOT_HASH_ALG_SHA256, TPM_ALG_SHA256, "SHA256" }, + { EFI_TCG2_BOOT_HASH_ALG_SHA384, TPM_ALG_SHA384, "SHA384" }, + { EFI_TCG2_BOOT_HASH_ALG_SHA512, TPM_ALG_SHA512, "SHA512" }, + { EFI_TCG2_BOOT_HASH_ALG_SM3_256, TPM_ALG_SM3_256, "SM3_256" }, +}; + +// Event type name lookup table. +typedef struct { + UINT32 EventType; + CONST CHAR8 *Name; +} EVENT_TYPE_INFO; + +STATIC CONST EVENT_TYPE_INFO mEventTypeTable[] = { + { EV_POST_CODE, "EV_POST_CODE" }, + { EV_NO_ACTION, "EV_NO_ACTION" }, + { EV_SEPARATOR, "EV_SEPARATOR" }, + { EV_ACTION, "EV_ACTION" }, + { EV_S_CRTM_CONTENTS, "EV_S_CRTM_CONTENTS" }, + { EV_S_CRTM_VERSION, "EV_S_CRTM_VERSION" }, + { EV_TABLE_OF_DEVICES, "EV_TABLE_OF_DEVICES" }, + { EV_EFI_VARIABLE_DRIVER_CONFIG, "EV_EFI_VARIABLE_DRIVER_CONFIG" }, + { EV_EFI_VARIABLE_BOOT, "EV_EFI_VARIABLE_BOOT" }, + { EV_EFI_BOOT_SERVICES_APPLICATION, "EV_EFI_BOOT_SERVICES_APPLICATION" }, + { EV_EFI_BOOT_SERVICES_DRIVER, "EV_EFI_BOOT_SERVICES_DRIVER" }, + { EV_EFI_RUNTIME_SERVICES_DRIVER, "EV_EFI_RUNTIME_SERVICES_DRIVER" }, + { EV_EFI_GPT_EVENT, "EV_EFI_GPT_EVENT" }, + { EV_EFI_ACTION, "EV_EFI_ACTION" }, + { EV_EFI_PLATFORM_FIRMWARE_BLOB, "EV_EFI_PLATFORM_FIRMWARE_BLOB" }, + { EV_EFI_HANDOFF_TABLES, "EV_EFI_HANDOFF_TABLES" }, + { EV_EFI_PLATFORM_FIRMWARE_BLOB2, "EV_EFI_PLATFORM_FIRMWARE_BLOB2" }, + { EV_EFI_HANDOFF_TABLES2, "EV_EFI_HANDOFF_TABLES2" }, + { EV_EFI_VARIABLE_AUTHORITY, "EV_EFI_VARIABLE_AUTHORITY" }, +}; + +/** + Print a bitmask of hash algorithms as human-readable names. + + @param[in] AlgBitmap Bitmask of HASH_ALG_* values. +**/ +STATIC +VOID +PrintAlgorithms ( + IN UINT32 AlgBitmap + ) +{ + UINTN Index; + + for (Index = 0; Index < ARRAY_SIZE (mHashAlgTable); Index++) { + if ((AlgBitmap & mHashAlgTable[Index].HashMask) != 0) { + Print (L" * %a\n", mHashAlgTable[Index].Name); + } + } +} + +/** + Query and display TPM PCR bank information via TCG2 Protocol. + + Retrieves the supported and currently active PCR banks from the + TCG2 Protocol capability structure. + + @param[in] Tcg2Protocol Pointer to the TCG2 Protocol instance. + + @retval EFI_SUCCESS Information retrieved and displayed. + @retval Others Error querying the protocol. +**/ +STATIC +EFI_STATUS +ShowPcrBanks ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol + ) +{ + EFI_STATUS Status; + EFI_TCG2_BOOT_SERVICE_CAPABILITY Capability; + + Capability.Size = sizeof (Capability); + Status = Tcg2Protocol->GetCapability (Tcg2Protocol, &Capability); + if (EFI_ERROR (Status)) { + Print (L"GetCapability failed - %r\n", Status); + return Status; + } + + Print (L"Supported PCR banks bitmap: 0x%x\n", Capability.HashAlgorithmBitmap); + PrintAlgorithms (Capability.HashAlgorithmBitmap); + Print (L"\n"); + + Print (L"Active PCR banks: 0x%x\n", Capability.ActivePcrBanks); + PrintAlgorithms (Capability.ActivePcrBanks); + + return EFI_SUCCESS; +} + +/** + Submit a request to set specific PCR banks via TCG2 Protocol. + + This calls TCG2 Protocol SetActivePcrBanks which submits a Physical + Presence request internally. The change will take effect on the next + reboot. + + @param[in] Tcg2Protocol Pointer to the TCG2 Protocol instance. + @param[in] DesiredBanks Bitmask of desired PCR banks + (EFI_TCG2_BOOT_HASH_ALG_* values). + + @retval EFI_SUCCESS Request submitted successfully. + @retval Others Error submitting the request. +**/ +STATIC +EFI_STATUS +RequestSetPcrBanks ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol, + IN UINT32 DesiredBanks + ) +{ + EFI_STATUS Status; + + Print (L"Submitting SetActivePcrBanks with parameter 0x%x\n", DesiredBanks); + + Status = Tcg2Protocol->SetActivePcrBanks (Tcg2Protocol, DesiredBanks); + + Print (L"Status: %r\n", Status); + + if (EFI_ERROR (Status)) { + Print (L"SetActivePcrBanks failed.\n"); + return Status; + } + + Print (L"Request submitted. Changes will take effect after reboot.\n"); + return EFI_SUCCESS; +} + +/** + Submit a request to enable all supported PCR banks via TCG2 Protocol. + + @param[in] Tcg2Protocol Pointer to the TCG2 Protocol instance. + + @retval EFI_SUCCESS Request submitted successfully. + @retval Others Error submitting the request. +**/ +STATIC +EFI_STATUS +RequestEnableAllPcrBanks ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol + ) +{ + EFI_STATUS Status; + EFI_TCG2_BOOT_SERVICE_CAPABILITY Capability; + + Capability.Size = sizeof (Capability); + Status = Tcg2Protocol->GetCapability (Tcg2Protocol, &Capability); + if (EFI_ERROR (Status)) { + Print (L"GetCapability failed - %r\n", Status); + return Status; + } + + Print (L"Requesting all supported PCR banks: 0x%x\n", Capability.HashAlgorithmBitmap); + + Status = Tcg2Protocol->SetActivePcrBanks (Tcg2Protocol, Capability.HashAlgorithmBitmap); + + Print (L"Status: %r\n", Status); + + if (EFI_ERROR (Status)) { + Print (L"SetActivePcrBanks failed.\n"); + return Status; + } + + Print (L"Request submitted. All supported PCR banks will be enabled after reboot.\n"); + return EFI_SUCCESS; +} + +/** + Return a human-readable name for a TPM algorithm ID. + + @param[in] AlgId TPM_ALG_ID value. + + @return Static string name, or "UNKNOWN" if not recognized. +**/ +STATIC +CONST CHAR8 * +GetAlgName ( + IN UINT16 AlgId + ) +{ + UINTN Index; + + for (Index = 0; Index < ARRAY_SIZE (mHashAlgTable); Index++) { + if (mHashAlgTable[Index].AlgId == AlgId) { + return mHashAlgTable[Index].Name; + } + } + + return "UNKNOWN"; +} + +/** + Return a human-readable name for a TCG event type. + + @param[in] EventType TCG_EVENTTYPE value. + + @return Static string name, or "UNKNOWN" if not recognized. +**/ +STATIC +CONST CHAR8 * +GetEventTypeName ( + IN UINT32 EventType + ) +{ + UINTN Index; + + for (Index = 0; Index < ARRAY_SIZE (mEventTypeTable); Index++) { + if (mEventTypeTable[Index].EventType == EventType) { + return mEventTypeTable[Index].Name; + } + } + + return "UNKNOWN"; +} + +/** + Print a byte buffer as a hexadecimal string. + + @param[in] Data Pointer to the byte buffer. + @param[in] Size Number of bytes to print. +**/ +STATIC +VOID +PrintHexDump ( + IN UINT8 *Data, + IN UINT16 Size + ) +{ + UINT16 Index; + + for (Index = 0; Index < Size; Index++) { + Print (L"%02x ", Data[Index]); + } +} + +/** + Retrieve and parse the TCG2 crypto-agile event log header. + + Calls GetEventLog(), validates the Spec ID Event, and extracts the + algorithm list. On success the caller receives pointers to the first + TCG_PCR_EVENT2 entry and the last entry, plus the algorithm table. + + @param[in] Tcg2Protocol Pointer to the TCG2 Protocol instance. + @param[out] FirstEvent Receives pointer to the first TCG_PCR_EVENT2. + @param[out] LastEvent Receives pointer to the last TCG_PCR_EVENT2. + @param[out] AlgList Receives the algorithm/digest-size table. + @param[out] NumberOfAlgorithms Receives the number of algorithms. + @param[out] WasTruncated Receives TRUE if the log was truncated. + + @retval EFI_SUCCESS Event log parsed successfully. + @retval EFI_NOT_FOUND Event log is empty. + @retval EFI_UNSUPPORTED Event log format is not recognized. + @retval Others Error from GetEventLog. +**/ +STATIC +EFI_STATUS +GetParsedEventLog ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol, + OUT UINT8 **FirstEvent, + OUT UINT8 **LastEvent, + OUT TCG_EfiSpecIdEventAlgorithmSize *AlgList, + OUT UINT32 *NumberOfAlgorithms, + OUT BOOLEAN *WasTruncated + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS LogLocation; + EFI_PHYSICAL_ADDRESS LogLastEntry; + TCG_PCR_EVENT_HDR *SpecIdHdr; + TCG_EfiSpecIDEventStruct *SpecId; + UINT8 *LogData; + UINT32 AlgIndex; + TCG_EfiSpecIdEventAlgorithmSize *AlgEntry; + + Status = Tcg2Protocol->GetEventLog ( + Tcg2Protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, + &LogLocation, + &LogLastEntry, + WasTruncated + ); + if (EFI_ERROR (Status)) { + Print (L"GetEventLog failed - %r\n", Status); + return Status; + } + + if ((LogLocation == 0) || (LogLastEntry == 0)) { + Print (L"Event log is empty.\n"); + return EFI_NOT_FOUND; + } + + // The first entry is a v1 TCG_PCR_EVENT containing the Spec ID Event. + SpecIdHdr = (TCG_PCR_EVENT_HDR *)(UINTN)LogLocation; + if (SpecIdHdr->EventType != EV_NO_ACTION) { + Print (L"First event is not a Spec ID Event (type 0x%x).\n", SpecIdHdr->EventType); + return EFI_UNSUPPORTED; + } + + SpecId = (TCG_EfiSpecIDEventStruct *)((UINT8 *)SpecIdHdr + sizeof (TCG_PCR_EVENT_HDR)); + + if (AsciiStrCmp ( + (CONST CHAR8 *)SpecId->signature, + TCG_EfiSpecIDEventStruct_SIGNATURE_03 + ) != 0) + { + Print (L"Unsupported event log format (expected crypto-agile).\n"); + return EFI_UNSUPPORTED; + } + + // Read the algorithm list from the variable-length portion of the Spec ID Event. + LogData = (UINT8 *)SpecId + sizeof (TCG_EfiSpecIDEventStruct); + *NumberOfAlgorithms = *(UINT32 *)LogData; + LogData += sizeof (UINT32); + + if ((*NumberOfAlgorithms == 0) || (*NumberOfAlgorithms > ARRAY_SIZE (mHashAlgTable))) { + Print (L"Invalid algorithm count in Spec ID Event (%u).\n", *NumberOfAlgorithms); + return EFI_UNSUPPORTED; + } + + for (AlgIndex = 0; AlgIndex < *NumberOfAlgorithms; AlgIndex++) { + AlgEntry = (TCG_EfiSpecIdEventAlgorithmSize *)LogData; + AlgList[AlgIndex] = *AlgEntry; + LogData += sizeof (TCG_EfiSpecIdEventAlgorithmSize); + } + + *FirstEvent = (UINT8 *)(UINTN)LogLocation + sizeof (TCG_PCR_EVENT_HDR) + SpecIdHdr->EventSize; + *LastEvent = (UINT8 *)(UINTN)LogLastEntry; + + return EFI_SUCCESS; +} + +/** + Retrieve, parse, and display the TCG2 crypto-agile event log. + + Retrieves the event log via GetParsedEventLog(), then walks each + subsequent TCG_PCR_EVENT2 entry displaying the PCR index, event + type, and digest values. + + @param[in] Tcg2Protocol Pointer to the TCG2 Protocol instance. + + @retval EFI_SUCCESS Event log retrieved and displayed. + @retval EFI_NOT_FOUND Event log is empty. + @retval EFI_UNSUPPORTED Event log format is not recognized. + @retval EFI_ABORTED Event log entry is malformed. + @retval Others Error from GetEventLog. +**/ +STATIC +EFI_STATUS +DumpEventLog ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol + ) +{ + EFI_STATUS Status; + BOOLEAN Truncated; + UINT32 NumberOfAlgorithms; + TCG_EfiSpecIdEventAlgorithmSize AlgList[ARRAY_SIZE (mHashAlgTable)]; + UINT32 AlgIndex; + UINT8 *CurrentEvent; + UINT8 *LastEvent; + UINTN EventNum; + UINT32 PcrIndex; + UINT32 EventType; + UINT32 DigestCount; + UINT16 AlgId; + UINT16 DigestSize; + UINT32 EventDataSize; + UINT32 DigestIndex; + UINT32 MatchIndex; + UINT8 *Digest; + + Status = GetParsedEventLog ( + Tcg2Protocol, + &CurrentEvent, + &LastEvent, + AlgList, + &NumberOfAlgorithms, + &Truncated + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Truncated) { + Print (L"Warning: Event log was truncated.\n\n"); + } + + Print (L"Spec ID Event: %u algorithm(s)\n", NumberOfAlgorithms); + for (AlgIndex = 0; AlgIndex < NumberOfAlgorithms; AlgIndex++) { + Print ( + L" %a (alg 0x%x, digest %u bytes)\n", + GetAlgName (AlgList[AlgIndex].algorithmId), + AlgList[AlgIndex].algorithmId, + AlgList[AlgIndex].digestSize + ); + } + + Print (L"\n"); + EventNum = 0; + + while (CurrentEvent <= LastEvent) { + EventNum++; + + // Read fixed fields: PCRIndex, EventType, DigestCount. + PcrIndex = *(UINT32 *)CurrentEvent; + EventType = *(UINT32 *)(CurrentEvent + sizeof (UINT32)); + DigestCount = *(UINT32 *)(CurrentEvent + 2 * sizeof (UINT32)); + + Print ( + L"Event %u: PCR %u %a (0x%x)\n", + EventNum, + PcrIndex, + GetEventTypeName (EventType), + EventType + ); + + if (DigestCount > NumberOfAlgorithms) { + Print (L" ERROR: DigestCount (%u) exceeds algorithm count. Stopping.\n", DigestCount); + return EFI_ABORTED; + } + + // Walk the digest list: each digest has a UINT16 AlgId followed by digest bytes. + Digest = CurrentEvent + 3 * sizeof (UINT32); + for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { + AlgId = *(UINT16 *)Digest; + Digest += sizeof (UINT16); + + // Look up the digest size from the Spec ID Event algorithm list. + DigestSize = 0; + for (MatchIndex = 0; MatchIndex < NumberOfAlgorithms; MatchIndex++) { + if (AlgList[MatchIndex].algorithmId == AlgId) { + DigestSize = AlgList[MatchIndex].digestSize; + break; + } + } + + if (DigestSize == 0) { + Print (L" ERROR: Unknown algorithm 0x%x. Stopping.\n", AlgId); + return EFI_ABORTED; + } + + Print (L" %a: ", GetAlgName (AlgId)); + PrintHexDump (Digest, DigestSize); + Print (L"\n"); + + Digest += DigestSize; + } + + // Read EventSize and advance past the event data. + EventDataSize = *(UINT32 *)Digest; + Print (L" Event data: %u bytes\n", EventDataSize); + + CurrentEvent = Digest + sizeof (UINT32) + EventDataSize; + } + + Print (L"\nTotal: %u event(s)\n", EventNum); + + return EFI_SUCCESS; +} + +/** + Extend a PCR accumulator with a new digest. + + Computes NewPcr = Hash(CurrentPcr || Digest) using the hash algorithm + identified by AlgId. CurrentPcr and NewPcr may point to the same buffer. + + @param[in] AlgId TPM_ALG_ID identifying the hash algorithm. + @param[in] CurrentPcr Current PCR value (DigestSize bytes). + @param[in] Digest Digest to extend with (DigestSize bytes). + @param[in] DigestSize Size of CurrentPcr and Digest in bytes. + @param[out] NewPcr Receives the extended PCR value (DigestSize bytes). + + @retval EFI_SUCCESS Extension computed. + @retval EFI_UNSUPPORTED Algorithm not supported for replay. + @retval EFI_DEVICE_ERROR Hash computation failed. +**/ +STATIC +EFI_STATUS +HashExtend ( + IN UINT16 AlgId, + IN UINT8 *CurrentPcr, + IN UINT8 *Digest, + IN UINT16 DigestSize, + OUT UINT8 *NewPcr + ) +{ + UINT8 Buffer[MAX_DIGEST_SIZE * 2]; + BOOLEAN Result; + + CopyMem (Buffer, CurrentPcr, DigestSize); + CopyMem (Buffer + DigestSize, Digest, DigestSize); + + switch (AlgId) { + case TPM_ALG_SHA1: + Result = Sha1HashAll (Buffer, (UINTN)DigestSize * 2, NewPcr); + break; + case TPM_ALG_SHA256: + Result = Sha256HashAll (Buffer, (UINTN)DigestSize * 2, NewPcr); + break; + case TPM_ALG_SHA384: + Result = Sha384HashAll (Buffer, (UINTN)DigestSize * 2, NewPcr); + break; + case TPM_ALG_SHA512: + Result = Sha512HashAll (Buffer, (UINTN)DigestSize * 2, NewPcr); + break; + default: + return EFI_UNSUPPORTED; + } + + return Result ? EFI_SUCCESS : EFI_DEVICE_ERROR; +} + +/** + Read a single PCR value from the TPM via SubmitCommand. + + Builds a TPM2_PCR_Read command and sends it through + Tcg2Protocol->SubmitCommand(), avoiding any dependency on + Tpm2CommandLib. + + @param[in] Tcg2Protocol Pointer to the TCG2 Protocol instance. + @param[in] AlgId TPM_ALG_ID for the PCR bank to read. + @param[in] PcrIndex PCR index (0..23). + @param[in] DigestSize Expected digest size in bytes. + @param[out] PcrValue Receives the PCR digest (DigestSize bytes). + + @retval EFI_SUCCESS PCR value read successfully. + @retval EFI_INVALID_PARAMETER PcrIndex out of range. + @retval EFI_DEVICE_ERROR TPM returned a non-zero response code. + @retval Others Error from SubmitCommand. +**/ +STATIC +EFI_STATUS +ReadPcrValue ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol, + IN UINT16 AlgId, + IN UINT32 PcrIndex, + IN UINT16 DigestSize, + OUT UINT8 *PcrValue + ) +{ + EFI_STATUS Status; + UINT8 CmdBuffer[TPM2_PCR_READ_CMD_SIZE]; + UINT8 RspBuffer[TPM2_PCR_READ_RSP_DIGEST_OFFSET + MAX_DIGEST_SIZE]; + UINT32 RspSize; + UINT32 ResponseCode; + UINT8 *Ptr; + + if (PcrIndex > MAX_PCR_INDEX) { + return EFI_INVALID_PARAMETER; + } + + // Build TPM2_PCR_Read command (big-endian wire format). + // Layout (20 bytes total): + // [0-1] tag = TPM_ST_NO_SESSIONS + // [2-5] commandSize = 20 + // [6-9] commandCode = TPM_CC_PCR_Read + // [10-13] count = 1 + // [14-15] hash = AlgId + // [16] sizeofSelect = 3 + // [17-19] pcrSelect[3] = bit for PcrIndex + Ptr = CmdBuffer; + + *(UINT16 *)Ptr = SwapBytes16 (TPM_ST_NO_SESSIONS); + Ptr += sizeof (UINT16); + + *(UINT32 *)Ptr = SwapBytes32 ((UINT32)TPM2_PCR_READ_CMD_SIZE); + Ptr += sizeof (UINT32); + + *(UINT32 *)Ptr = SwapBytes32 (TPM_CC_PCR_Read); + Ptr += sizeof (UINT32); + + *(UINT32 *)Ptr = SwapBytes32 (1); + Ptr += sizeof (UINT32); + + *(UINT16 *)Ptr = SwapBytes16 (AlgId); + Ptr += sizeof (UINT16); + + *Ptr = 3; + Ptr++; + + Ptr[0] = 0; + Ptr[1] = 0; + Ptr[2] = 0; + Ptr[PcrIndex / 8] = (UINT8)(1 << (PcrIndex % 8)); + + // Send command and read response. + RspSize = sizeof (RspBuffer); + Status = Tcg2Protocol->SubmitCommand ( + Tcg2Protocol, + TPM2_PCR_READ_CMD_SIZE, + CmdBuffer, + RspSize, + RspBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Response layout (for a single PCR): + // [0-1] tag + // [2-5] responseSize + // [6-9] responseCode + // [10-13] pcrUpdateCounter + // [14-17] pcrSelectionOut.count + // [18-19] hash + // [20] sizeofSelect + // [21-23] pcrSelect[3] + // [24-27] digests.count + // [28-29] digests[0].size + // [30+] digests[0].buffer + ResponseCode = SwapBytes32 (*(UINT32 *)(RspBuffer + 6)); + if (ResponseCode != 0) { + return EFI_DEVICE_ERROR; + } + + CopyMem (PcrValue, RspBuffer + TPM2_PCR_READ_RSP_DIGEST_OFFSET, DigestSize); + + return EFI_SUCCESS; +} + +/** + Replay the TCG2 event log and verify against actual TPM PCR values. + + Retrieves the event log, replays all extend operations locally to + compute expected PCR values, reads the actual PCR values from the + TPM via SubmitCommand, and compares them. + + @param[in] Tcg2Protocol Pointer to the TCG2 Protocol instance. + + @retval EFI_SUCCESS All replayed PCRs match the TPM. + @retval EFI_NOT_FOUND Event log is empty. + @retval EFI_UNSUPPORTED Event log format not recognized. + @retval EFI_ABORTED Replay completed but one or more PCRs did not match. + @retval Others Error from GetEventLog or SubmitCommand. +**/ +STATIC +EFI_STATUS +ReplayAndVerifyEventLog ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol + ) +{ + EFI_STATUS Status; + BOOLEAN Truncated; + UINT32 NumberOfAlgorithms; + TCG_EfiSpecIdEventAlgorithmSize AlgList[ARRAY_SIZE (mHashAlgTable)]; + BOOLEAN AlgReplayable[ARRAY_SIZE (mHashAlgTable)]; + UINT32 AlgIndex; + UINT8 *CurrentEvent; + UINT8 *LastEvent; + UINTN EventNum; + UINT32 PcrIndex; + UINT32 DigestCount; + UINT16 AlgId; + UINT16 DigestSize; + UINT32 EventDataSize; + UINT32 DigestIndex; + UINT32 MatchIndex; + UINT8 ReplayedPcrs[ARRAY_SIZE (mHashAlgTable)][MAX_PCR_INDEX + 1][MAX_DIGEST_SIZE]; + BOOLEAN PcrUsed[MAX_PCR_INDEX + 1]; + UINT8 TpmPcrValue[MAX_DIGEST_SIZE]; + UINTN PcrIdx; + UINTN PassCount; + UINTN FailCount; + UINTN VerifiedCount; + BOOLEAN Match; + UINT8 *Digest; + + Status = GetParsedEventLog ( + Tcg2Protocol, + &CurrentEvent, + &LastEvent, + AlgList, + &NumberOfAlgorithms, + &Truncated + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Truncated) { + Print (L"Warning: Event log was truncated. Replay may not match.\n\n"); + } + + for (AlgIndex = 0; AlgIndex < NumberOfAlgorithms; AlgIndex++) { + AlgReplayable[AlgIndex] = TRUE; + } + + // Initialize PCR accumulators to zero. + ZeroMem (ReplayedPcrs, sizeof (ReplayedPcrs)); + ZeroMem (PcrUsed, sizeof (PcrUsed)); + + // Walk events and replay PCR extensions. + EventNum = 0; + + while (CurrentEvent <= LastEvent) { + EventNum++; + + PcrIndex = *(UINT32 *)CurrentEvent; + DigestCount = *(UINT32 *)(CurrentEvent + 2 * sizeof (UINT32)); + + if (DigestCount > NumberOfAlgorithms) { + Print (L"Event %u: DigestCount (%u) exceeds algorithm count. Stopping.\n", EventNum, DigestCount); + return EFI_ABORTED; + } + + if (PcrIndex <= MAX_PCR_INDEX) { + PcrUsed[PcrIndex] = TRUE; + } + + Digest = CurrentEvent + 3 * sizeof (UINT32); + for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { + AlgId = *(UINT16 *)Digest; + Digest += sizeof (UINT16); + + DigestSize = 0; + MatchIndex = 0; + for (MatchIndex = 0; MatchIndex < NumberOfAlgorithms; MatchIndex++) { + if (AlgList[MatchIndex].algorithmId == AlgId) { + DigestSize = AlgList[MatchIndex].digestSize; + break; + } + } + + if (DigestSize == 0) { + Print (L"Event %u: Unknown algorithm 0x%x. Stopping.\n", EventNum, AlgId); + return EFI_ABORTED; + } + + if ((PcrIndex <= MAX_PCR_INDEX) && AlgReplayable[MatchIndex]) { + Status = HashExtend ( + AlgId, + ReplayedPcrs[MatchIndex][PcrIndex], + Digest, + DigestSize, + ReplayedPcrs[MatchIndex][PcrIndex] + ); + if (Status == EFI_UNSUPPORTED) { + AlgReplayable[MatchIndex] = FALSE; + } else if (EFI_ERROR (Status)) { + Print (L"Event %u: Hash extend failed for %a - %r\n", EventNum, GetAlgName (AlgId), Status); + return Status; + } + } + + Digest += DigestSize; + } + + EventDataSize = *(UINT32 *)Digest; + CurrentEvent = Digest + sizeof (UINT32) + EventDataSize; + } + + Print (L"Replayed %u event(s) across %u algorithm(s).\n\n", EventNum, NumberOfAlgorithms); + + // Verify replayed PCRs against actual TPM values. + PassCount = 0; + FailCount = 0; + VerifiedCount = 0; + + for (PcrIdx = 0; PcrIdx <= MAX_PCR_INDEX; PcrIdx++) { + if (!PcrUsed[PcrIdx]) { + continue; + } + + Print (L"PCR %u:\n", PcrIdx); + + for (AlgIndex = 0; AlgIndex < NumberOfAlgorithms; AlgIndex++) { + AlgId = AlgList[AlgIndex].algorithmId; + DigestSize = AlgList[AlgIndex].digestSize; + + if (!AlgReplayable[AlgIndex]) { + Print (L" %a: (replay not supported, skipped)\n", GetAlgName (AlgId)); + continue; + } + + Print (L" %a Replayed: ", GetAlgName (AlgId)); + PrintHexDump (ReplayedPcrs[AlgIndex][PcrIdx], DigestSize); + Print (L"\n"); + + Status = ReadPcrValue (Tcg2Protocol, AlgId, (UINT32)PcrIdx, DigestSize, TpmPcrValue); + if (EFI_ERROR (Status)) { + Print (L" %a Actual: (read failed - %r)\n", GetAlgName (AlgId), Status); + FailCount++; + VerifiedCount++; + continue; + } + + Print (L" %a Actual: ", GetAlgName (AlgId)); + PrintHexDump (TpmPcrValue, DigestSize); + Print (L"\n"); + + Match = (CompareMem (ReplayedPcrs[AlgIndex][PcrIdx], TpmPcrValue, DigestSize) == 0); + Print (L" Result: %a\n", Match ? "PASS" : "FAIL"); + + if (Match) { + PassCount++; + } else { + FailCount++; + } + + VerifiedCount++; + } + + Print (L"\n"); + } + + Print (L"Summary: %u PCR bank(s) verified, %u PASS, %u FAIL\n", VerifiedCount, PassCount, FailCount); + + return (FailCount > 0) ? EFI_ABORTED : EFI_SUCCESS; +} + +/** + Print usage information. +**/ +STATIC +VOID +PrintUsage ( + VOID + ) +{ + Print (L"TpmShellApp - TPM 2.0 Physical Presence Test Utility\n"); + Print (L"\n"); + Print (L"Usage:\n"); + Print (L" TpmShellApp help - Show usage\n"); + Print (L" TpmShellApp get_active_pcr_banks - Display active PCR banks\n"); + Print (L" TpmShellApp set_active_pcr_banks - Request active PCR bank change (hex bitmask)\n"); + Print (L" TpmShellApp enable_all_pcr_banks - Enable all supported PCR banks\n"); + Print (L" TpmShellApp dump_event_log - Dump the TCG2 event log\n"); + Print (L" TpmShellApp replay_event_log - Replay event log and verify PCRs\n"); + Print (L" TpmShellApp get_last_result - Show last SetActivePcrBanks result\n"); + Print (L"\n"); + Print (L"PCR bank bitmask values:\n"); + Print (L" 0x00000001 = SHA1\n"); + Print (L" 0x00000002 = SHA256\n"); + Print (L" 0x00000004 = SHA384\n"); + Print (L" 0x00000008 = SHA512\n"); + Print (L" 0x00000010 = SM3_256\n"); + Print (L"\n"); + Print (L"Example: TpmShellApp set_active_pcr_banks 0x2 (enable SHA256 only)\n"); + Print (L"Example: TpmShellApp set_active_pcr_banks 0x6 (enable SHA256 + SHA384)\n"); +} + +/** + Entry point for the TPM Test UEFI Shell Application. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS Application executed successfully. + @retval Others An error occurred. +**/ +EFI_STATUS +EFIAPI +TpmShellAppEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN Argc; + LIST_ENTRY *ParamPackage; + CONST CHAR16 *Command; + CONST CHAR16 *PcrMaskStr; + UINT64 PcrMaskVal; + EFI_TCG2_PROTOCOL *Tcg2Protocol; + UINT32 OperationPresent; + UINT32 Response; + + // Initialize the Shell library. + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + Print (L"ShellInitialize failed - %r\n", Status); + return Status; + } + + // Parse command line. + Status = ShellCommandLineParse (EmptyParamList, &ParamPackage, NULL, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + + // Validate number of input parameters. + Argc = ShellCommandLineGetCount (ParamPackage); + if (Argc < 2) { + Print (L"\n[Invalid Usage]\n"); + Print (L" Use 'TpmShellApp help' for usage.\n"); + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // Acquire the command value. + Command = ShellCommandLineGetRawValue (ParamPackage, 1); + if (Command == NULL) { + Print (L"\n[Invalid Usage]\n"); + Print (L" Use 'TpmShellApp help' for usage.\n"); + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // Locate TCG2 Protocol it is required for this test app to function + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **)&Tcg2Protocol); + if (EFI_ERROR (Status)) { + Print (L"TCG2 Protocol not found - %r\n", Status); + Print (L" TPM 2.0 may not be enabled on this platform.\n"); + goto Exit; + } + + // Dispatch based on command. + if (StrCmp (Command, L"help") == 0) { + Print (L"\n[TPM 2.0 Help]\n\n"); + PrintUsage (); + goto Exit; + } else if (StrCmp (Command, L"get_active_pcr_banks") == 0) { + Print (L"\n[TPM 2.0 Information]\n\n"); + ShowPcrBanks (Tcg2Protocol); + } else if (StrCmp (Command, L"set_active_pcr_banks") == 0) { + Print (L"\n[Set PCR Banks]\n\n"); + if (Argc < 3) { + Print (L"set_active_pcr_banks requires a hex bitmask parameter.\n"); + Print (L" Example: TpmShellApp set_active_pcr_banks 0x2\n"); + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + PcrMaskStr = ShellCommandLineGetRawValue (ParamPackage, 2); + Status = ShellConvertStringToUint64 ( + PcrMaskStr, + &PcrMaskVal, + TRUE, + FALSE + ); + if (EFI_ERROR (Status)) { + Print (L"Invalid hex value.\n"); + goto Exit; + } + + Status = RequestSetPcrBanks (Tcg2Protocol, (UINT32)PcrMaskVal); + } else if (StrCmp (Command, L"enable_all_pcr_banks") == 0) { + Print (L"\n[Enable All PCR Banks]\n\n"); + Status = RequestEnableAllPcrBanks (Tcg2Protocol); + } else if (StrCmp (Command, L"dump_event_log") == 0) { + Print (L"\n[TCG2 Event Log]\n\n"); + Status = DumpEventLog (Tcg2Protocol); + } else if (StrCmp (Command, L"replay_event_log") == 0) { + Print (L"\n[Event Log Replay]\n\n"); + Status = ReplayAndVerifyEventLog (Tcg2Protocol); + } else if (StrCmp (Command, L"get_last_result") == 0) { + Print (L"\n[Last SetActivePcrBanks Result]\n\n"); + Status = Tcg2Protocol->GetResultOfSetActivePcrBanks (Tcg2Protocol, &OperationPresent, &Response); + if (EFI_ERROR (Status)) { + Print (L" GetResultOfSetActivePcrBanks failed - %r\n", Status); + goto Exit; + } + + Print (L" Operation present: %a\n", OperationPresent ? "YES" : "NO"); + Print (L" Response code: %u\n", Response); + } else { + Print (L"\n[Invalid Input Command]\n\n"); + Print (L" Unknown command '%s'\n", Command); + Print (L" Use 'TpmShellApp help' for usage.\n"); + Status = EFI_INVALID_PARAMETER; + } + +Exit: + Print (L"\n"); + ShellCommandLineFreeVarList (ParamPackage); + return Status; +} diff --git a/SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf b/SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf new file mode 100644 index 0000000000..943d28e1dd --- /dev/null +++ b/SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf @@ -0,0 +1,46 @@ +## @file +# TpmShellApp.inf +# +# UEFI shell application for testing TPM 2.0 Physical Presence Interface +# operations, including querying and configuring PCR banks. +# +# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = TpmShellApp + FILE_GUID = A3B2D4F1-7E6C-4A89-B5D0-3C1F8E2A9D07 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = TpmShellAppEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 AARCH64 +# + +[Sources] + TpmShellApp.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseCryptLib + BaseMemoryLib + IntrinsicLib + ShellLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiLib + +[Protocols] + gEfiTcg2ProtocolGuid ## CONSUMES diff --git a/SecurityPkg/Applications/TpmShellApp/TpmShellApp.md b/SecurityPkg/Applications/TpmShellApp/TpmShellApp.md new file mode 100644 index 0000000000..9b3a5fe5a5 --- /dev/null +++ b/SecurityPkg/Applications/TpmShellApp/TpmShellApp.md @@ -0,0 +1,230 @@ +# TpmShellApp + +A UEFI shell application for testing TPM 2.0 Physical Presence Interface operations, +including querying and configuring PCR banks. The app communicates exclusively through the +`EFI_TCG2_PROTOCOL` — it has no direct dependencies on TPM command libraries, physical +presence libraries, or TPM hardware. + +## Table of Contents + +- [Overview](#overview) +- [Commands](#commands) +- [Build Integration](#build-integration) +- [Protocol Dependency](#protocol-dependency) +- [Output and Debugging](#output-and-debugging) + +## Overview + +TpmShellApp is a `UEFI_APPLICATION` that validates TPM 2.0 PCR bank operations via the +TCG2 Protocol. It is designed to test that a platform's Physical Presence Interface +correctly handles PCR bank change requests, including verifying that unsupported operations +are gracefully rejected. + +The app uses positional command-line arguments (no flags or switches) and outputs all +results through `Print()` (from `UefiLib`), which writes directly to the UEFI shell +console. + +## Commands + +```text +TpmShellApp help Show usage information +TpmShellApp get_active_pcr_banks Show supported and active PCR banks +TpmShellApp set_active_pcr_banks Request a PCR bank configuration change +TpmShellApp enable_all_pcr_banks Request enabling all supported PCR banks +TpmShellApp dump_event_log Dump the TCG2 event log +TpmShellApp replay_event_log Replay event log and verify PCRs +TpmShellApp get_last_result Show the result of the last SetActivePcrBanks call +``` + +### `help` + +Prints usage information, PCR bank bitmask values, and examples. + +### `get_active_pcr_banks` + +Calls `Tcg2Protocol->GetCapability()` and displays: + +- **Supported PCR banks** — algorithms the TPM hardware supports (`HashAlgorithmBitmap`). +- **Active PCR banks** — algorithms currently enabled (`ActivePcrBanks`). + +Both are filtered by the firmware's registered hash algorithms (see +[Hash Algorithm Filtering](#hash-algorithm-filtering) below). + +Example output: + +```text +[TPM 2.0 Information] + +Supported PCR banks: 2 + * SHA256 + +Active PCR banks: 2 + * SHA256 +``` + +### `set_active_pcr_banks ` + +Calls `Tcg2Protocol->SetActivePcrBanks()` with the provided hex bitmask. The mask is a +combination of `EFI_TCG2_BOOT_HASH_ALG_*` values: + +| Value | Algorithm | +| ----- | --------- | +| `0x01` | SHA1 | +| `0x02` | SHA256 | +| `0x04` | SHA384 | +| `0x08` | SHA512 | +| `0x10` | SM3_256 | + +Values can be combined: `0x06` = SHA256 + SHA384. + +The mask parameter accepts hex with or without a `0x` prefix. + +```text +TpmShellApp set_active_pcr_banks 0x2 Enable SHA256 only +TpmShellApp set_active_pcr_banks 0x6 Enable SHA256 + SHA384 +TpmShellApp set_active_pcr_banks 2 Also valid (no prefix) +``` + +> **Note**: `SetActivePcrBanks` submits a Physical Presence request. The actual bank +> change takes effect on the next reboot, processed by +> `Tcg2PhysicalPresenceLibProcessRequest()` during BDS. + +### `enable_all_pcr_banks` + +Calls `GetCapability()` to discover all supported hash algorithms, then calls +`SetActivePcrBanks()` with the full `HashAlgorithmBitmap`. This is equivalent to +requesting that all supported PCR banks be enabled. + +### `dump_event_log` + +Calls `Tcg2Protocol->GetEventLog()` with `EFI_TCG2_EVENT_LOG_FORMAT_TCG_2` (crypto-agile +format) to retrieve the firmware's TCG2 event log. Parses the Spec ID Event header to +discover the hash algorithms and digest sizes, then walks each `TCG_PCR_EVENT2` entry +displaying: + +- **PCR index** — which PCR was extended. +- **Event type** — the TCG event type (e.g., `EV_EFI_VARIABLE_DRIVER_CONFIG`, + `EV_SEPARATOR`). +- **Digest(s)** — the full hex digest for each algorithm in the event. +- **Event data size** — the number of bytes in the event payload. + +Prints a total event count at the end. + +### `replay_event_log` + +Replays the TCG2 event log to compute expected PCR values, then reads the +actual PCR values from the TPM via `SubmitCommand` (TPM2_PCR_Read) and +compares them. + +For each PCR that was extended in the log, the command displays: + +- **Replayed digest** — the PCR value computed locally by replaying all + extend operations. +- **Actual digest** — the current PCR value read from the TPM. +- **Result** — `PASS` if they match, `FAIL` if they differ. + +Prints a summary with total verified, passed, and failed counts. + +Supports SHA1, SHA256, SHA384, and SHA512 for replay hashing. Algorithms +not supported by `BaseCryptLib` (e.g., SM3_256) are skipped. + +### `get_last_result` + +Calls `Tcg2Protocol->GetResultOfSetActivePcrBanks()` which queries the Physical Presence +library for the result of the most recent `SetActivePcrBanks` operation. Displays: + +- **Operation present** — whether a previous operation result exists (`YES` / `NO`). +- **Response code** — the TCG PP return code (0 = success). + +## Build Integration + +### INF + +The app is defined in `SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf`: + +| Property | Value | +| -------- | ----- | +| `MODULE_TYPE` | `UEFI_APPLICATION` | +| `ENTRY_POINT` | `TpmShellAppEntry` | +| `FILE_GUID` | `A3B2D4F1-7E6C-4A89-B5D0-3C1F8E2A9D07` | + +Dependencies: + +| Section | Items | +| ------- | ----- | +| Packages | `MdePkg`, `MdeModulePkg`, `CryptoPkg`, `ShellPkg` | +| LibraryClasses | `BaseLib`, `BaseCryptLib`, `BaseMemoryLib`, `IntrinsicLib`, `ShellLib`, `UefiApplicationEntryPoint`, `UefiBootServicesTableLib`, `UefiLib` | +| Protocols | `gEfiTcg2ProtocolGuid` | + +The app intentionally has **no dependency** on `SecurityPkg`, TPM command libraries, +physical presence libraries, or runtime services. All TPM interaction goes through the +TCG2 Protocol. + +### DSC + +Add the INF to the platform DSC components section: + +```ini +SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf +``` + +The platform DSC must also map `IntrinsicLib` for the `UEFI_APPLICATION` module type. +`IntrinsicLib` provides compiler-generated `memcpy`/`memset` intrinsics that the VS2022 +toolchain emits for large memory operations such as CopyMem and ZeroMem: + +```ini +[LibraryClasses.common.UEFI_APPLICATION] + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf +``` + +The app is typically included unconditionally (outside any TPM enable guard) so it can be +built regardless of TPM enablement. It will report a clear error when the TCG2 Protocol is +not available. + +### FDF + +Add the INF to the appropriate firmware volume in the platform FDF: + +```ini +INF SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf +``` + +## Protocol Dependency + +TpmShellApp uses only `EFI_TCG2_PROTOCOL` (`gEfiTcg2ProtocolGuid`). This protocol is +installed by `Tcg2Dxe.efi`, which requires TPM to be enabled in the platform +configuration. + +If the protocol is not found, the app prints: + +```text +TCG2 Protocol not found - Not Found + TPM 2.0 may not be enabled on this platform. +``` + +### Protocol Functions Used + +| Function | Command | Purpose | +| -------- | ------- | ------- | +| `GetCapability` | `get_active_pcr_banks`, `enable_all_pcr_banks` | Query supported/active PCR banks | +| `SetActivePcrBanks` | `set_active_pcr_banks`, `enable_all_pcr_banks` | Submit PP request for bank change | +| `GetEventLog` | `dump_event_log`, `replay_event_log` | Retrieve the crypto-agile event log | +| `SubmitCommand` | `replay_event_log` | Send TPM2_PCR_Read to read actual PCR values | +| `GetResultOfSetActivePcrBanks` | `get_last_result` | Query result of last bank change request | + +### Hash Algorithm Filtering + +The `HashAlgorithmBitmap` and `ActivePcrBanks` reported by `GetCapability` are already +filtered by the firmware's hash library configuration. The chain is: + +1. `PcdTpm2HashMask` gates which `HashInstanceLib` modules register. +2. `Tcg2Dxe` intersects the registered hash bitmap with the TPM's hardware capabilities. +3. `GetCapability` only reports the intersection. + +This means the app may not see all algorithms the TPM hardware supports. To expose +additional algorithms, update `PcdTpm2HashMask` in the platform DSC. + +## Output and Debugging + +All output uses `Print()` from `UefiLib`, so it appears directly on the UEFI shell +console — no serial log or `AdvancedLogger` configuration is required to see results. diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml index f144e38923..4eb31123d6 100644 --- a/SecurityPkg/SecurityPkg.ci.yaml +++ b/SecurityPkg/SecurityPkg.ci.yaml @@ -61,7 +61,9 @@ # For host based unit tests "AcceptableDependencies-HOST_APPLICATION":[], # For UEFI shell based apps - "AcceptableDependencies-UEFI_APPLICATION":[], + "AcceptableDependencies-UEFI_APPLICATION":[ + "ShellPkg/ShellPkg.dec" + ], "IgnoreInf": [] }, "DscCompleteCheck": { diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 9f9e67cafc..a43b25871f 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -173,6 +173,12 @@ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf +[LibraryClasses.common.UEFI_APPLICATION] + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + [LibraryClasses.common.DXE_SMM_DRIVER] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf @@ -264,6 +270,8 @@ UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf } + SecurityPkg/Applications/TpmShellApp/TpmShellApp.inf + # # TCG Storage. #