| /** @file -- Tpm2DeviceLibDTpmDump.c | |
| This file contains helper functions to perform a detailed debugging of | |
| TPM transactions as they go to and from the TPM device. | |
| Copyright (c) Microsoft Corporation. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Uefi.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/BaseLib.h> | |
| #include <IndustryStandard/Tpm20.h> | |
| #include "Tpm2Ptp.h" | |
| #define MAX_TPM_BUFFER_DUMP 240 // If printing an entire buffer, only print up to MAX bytes. | |
| #pragma pack(1) | |
| // TPM2_PCR_COMMON_COMMAND - The common fields shared between the PCR Extend | |
| // and PCR Event commands. | |
| typedef struct { | |
| TPM2_COMMAND_HEADER Header; | |
| TPMI_DH_PCR PcrHandle; | |
| UINT32 AuthorizationSize; | |
| TPMS_AUTH_COMMAND AuthSessionPcr; | |
| } TPM2_PCR_COMMON_COMMAND; | |
| typedef struct { | |
| TPM2_COMMAND_HEADER Header; | |
| TPMI_RH_HIERARCHY_AUTH AuthHandle; | |
| UINT32 AuthorizationSize; | |
| TPMS_AUTH_COMMAND AuthSession; | |
| TPM2B_AUTH NewAuth; | |
| } TPM2_HIERARCHY_CHANGE_AUTH_COMMAND; | |
| typedef struct { | |
| TPM2_COMMAND_HEADER Header; | |
| TPMI_SH_POLICY PolicySession; | |
| TPML_DIGEST HashList; | |
| } TPM2_POLICY_OR_COMMAND; | |
| typedef struct { | |
| TPM2_COMMAND_HEADER Header; | |
| TPMI_DH_OBJECT TpmKey; | |
| TPMI_DH_ENTITY Bind; | |
| TPM2B_NONCE NonceCaller; | |
| TPM2B_ENCRYPTED_SECRET Salt; | |
| TPM_SE SessionType; | |
| TPMT_SYM_DEF Symmetric; | |
| TPMI_ALG_HASH AuthHash; | |
| } TPM2_START_AUTH_SESSION_COMMAND; | |
| typedef struct { | |
| TPM2_RESPONSE_HEADER Header; | |
| TPMI_SH_AUTH_SESSION SessionHandle; | |
| TPM2B_NONCE NonceTPM; | |
| } TPM2_START_AUTH_SESSION_RESPONSE; | |
| #pragma pack() | |
| typedef struct { | |
| UINT32 Code; | |
| CHAR8 *Text; | |
| } TPM2_CODE_STRING; | |
| TPM2_CODE_STRING CommandCodeStrings[] = { | |
| { TPM_CC_NV_UndefineSpaceSpecial, "TPM_CC_NV_UndefineSpaceSpecial" }, | |
| { TPM_CC_EvictControl, "TPM_CC_EvictControl" }, | |
| { TPM_CC_HierarchyControl, "TPM_CC_HierarchyControl" }, | |
| { TPM_CC_NV_UndefineSpace, "TPM_CC_NV_UndefineSpace" }, | |
| { TPM_CC_ChangeEPS, "TPM_CC_ChangeEPS" }, | |
| { TPM_CC_ChangePPS, "TPM_CC_ChangePPS" }, | |
| { TPM_CC_Clear, "TPM_CC_Clear" }, | |
| { TPM_CC_ClearControl, "TPM_CC_ClearControl" }, | |
| { TPM_CC_ClockSet, "TPM_CC_ClockSet" }, | |
| { TPM_CC_HierarchyChangeAuth, "TPM_CC_HierarchyChangeAuth" }, | |
| { TPM_CC_NV_DefineSpace, "TPM_CC_NV_DefineSpace" }, | |
| { TPM_CC_PCR_Allocate, "TPM_CC_PCR_Allocate" }, | |
| { TPM_CC_PCR_SetAuthPolicy, "TPM_CC_PCR_SetAuthPolicy" }, | |
| { TPM_CC_PP_Commands, "TPM_CC_PP_Commands" }, | |
| { TPM_CC_SetPrimaryPolicy, "TPM_CC_SetPrimaryPolicy" }, | |
| { TPM_CC_FieldUpgradeStart, "TPM_CC_FieldUpgradeStart" }, | |
| { TPM_CC_ClockRateAdjust, "TPM_CC_ClockRateAdjust" }, | |
| { TPM_CC_CreatePrimary, "TPM_CC_CreatePrimary" }, | |
| { TPM_CC_NV_GlobalWriteLock, "TPM_CC_NV_GlobalWriteLock" }, | |
| { TPM_CC_PP_LAST, "TPM_CC_PP_LAST" }, | |
| { TPM_CC_GetCommandAuditDigest, "TPM_CC_GetCommandAuditDigest" }, | |
| { TPM_CC_NV_Increment, "TPM_CC_NV_Increment" }, | |
| { TPM_CC_NV_SetBits, "TPM_CC_NV_SetBits" }, | |
| { TPM_CC_NV_Extend, "TPM_CC_NV_Extend" }, | |
| { TPM_CC_NV_Write, "TPM_CC_NV_Write" }, | |
| { TPM_CC_NV_WriteLock, "TPM_CC_NV_WriteLock" }, | |
| { TPM_CC_DictionaryAttackLockReset, "TPM_CC_DictionaryAttackLockReset" }, | |
| { TPM_CC_DictionaryAttackParameters, "TPM_CC_DictionaryAttackParameters" }, | |
| { TPM_CC_NV_ChangeAuth, "TPM_CC_NV_ChangeAuth" }, | |
| { TPM_CC_PCR_Event, "TPM_CC_PCR_Event" }, | |
| { TPM_CC_PCR_Reset, "TPM_CC_PCR_Reset" }, | |
| { TPM_CC_SequenceComplete, "TPM_CC_SequenceComplete" }, | |
| { TPM_CC_SetAlgorithmSet, "TPM_CC_SetAlgorithmSet" }, | |
| { TPM_CC_SetCommandCodeAuditStatus, "TPM_CC_SetCommandCodeAuditStatus" }, | |
| { TPM_CC_FieldUpgradeData, "TPM_CC_FieldUpgradeData" }, | |
| { TPM_CC_IncrementalSelfTest, "TPM_CC_IncrementalSelfTest" }, | |
| { TPM_CC_SelfTest, "TPM_CC_SelfTest" }, | |
| { TPM_CC_Startup, "TPM_CC_Startup" }, | |
| { TPM_CC_Shutdown, "TPM_CC_Shutdown" }, | |
| { TPM_CC_StirRandom, "TPM_CC_StirRandom" }, | |
| { TPM_CC_ActivateCredential, "TPM_CC_ActivateCredential" }, | |
| { TPM_CC_Certify, "TPM_CC_Certify" }, | |
| { TPM_CC_PolicyNV, "TPM_CC_PolicyNV" }, | |
| { TPM_CC_CertifyCreation, "TPM_CC_CertifyCreation" }, | |
| { TPM_CC_Duplicate, "TPM_CC_Duplicate" }, | |
| { TPM_CC_GetTime, "TPM_CC_GetTime" }, | |
| { TPM_CC_GetSessionAuditDigest, "TPM_CC_GetSessionAuditDigest" }, | |
| { TPM_CC_NV_Read, "TPM_CC_NV_Read" }, | |
| { TPM_CC_NV_ReadLock, "TPM_CC_NV_ReadLock" }, | |
| { TPM_CC_ObjectChangeAuth, "TPM_CC_ObjectChangeAuth" }, | |
| { TPM_CC_PolicySecret, "TPM_CC_PolicySecret" }, | |
| { TPM_CC_Rewrap, "TPM_CC_Rewrap" }, | |
| { TPM_CC_Create, "TPM_CC_Create" }, | |
| { TPM_CC_ECDH_ZGen, "TPM_CC_ECDH_ZGen" }, | |
| { TPM_CC_HMAC, "TPM_CC_HMAC" }, | |
| { TPM_CC_Import, "TPM_CC_Import" }, | |
| { TPM_CC_Load, "TPM_CC_Load" }, | |
| { TPM_CC_Quote, "TPM_CC_Quote" }, | |
| { TPM_CC_RSA_Decrypt, "TPM_CC_RSA_Decrypt" }, | |
| { TPM_CC_HMAC_Start, "TPM_CC_HMAC_Start" }, | |
| { TPM_CC_SequenceUpdate, "TPM_CC_SequenceUpdate" }, | |
| { TPM_CC_Sign, "TPM_CC_Sign" }, | |
| { TPM_CC_Unseal, "TPM_CC_Unseal" }, | |
| { TPM_CC_PolicySigned, "TPM_CC_PolicySigned" }, | |
| { TPM_CC_ContextLoad, "TPM_CC_ContextLoad" }, | |
| { TPM_CC_ContextSave, "TPM_CC_ContextSave" }, | |
| { TPM_CC_ECDH_KeyGen, "TPM_CC_ECDH_KeyGen" }, | |
| { TPM_CC_EncryptDecrypt, "TPM_CC_EncryptDecrypt" }, | |
| { TPM_CC_FlushContext, "TPM_CC_FlushContext" }, | |
| { TPM_CC_LoadExternal, "TPM_CC_LoadExternal" }, | |
| { TPM_CC_MakeCredential, "TPM_CC_MakeCredential" }, | |
| { TPM_CC_NV_ReadPublic, "TPM_CC_NV_ReadPublic" }, | |
| { TPM_CC_PolicyAuthorize, "TPM_CC_PolicyAuthorize" }, | |
| { TPM_CC_PolicyAuthValue, "TPM_CC_PolicyAuthValue" }, | |
| { TPM_CC_PolicyCommandCode, "TPM_CC_PolicyCommandCode" }, | |
| { TPM_CC_PolicyCounterTimer, "TPM_CC_PolicyCounterTimer" }, | |
| { TPM_CC_PolicyCpHash, "TPM_CC_PolicyCpHash" }, | |
| { TPM_CC_PolicyLocality, "TPM_CC_PolicyLocality" }, | |
| { TPM_CC_PolicyNameHash, "TPM_CC_PolicyNameHash" }, | |
| { TPM_CC_PolicyOR, "TPM_CC_PolicyOR" }, | |
| { TPM_CC_PolicyTicket, "TPM_CC_PolicyTicket" }, | |
| { TPM_CC_ReadPublic, "TPM_CC_ReadPublic" }, | |
| { TPM_CC_RSA_Encrypt, "TPM_CC_RSA_Encrypt" }, | |
| { TPM_CC_StartAuthSession, "TPM_CC_StartAuthSession" }, | |
| { TPM_CC_VerifySignature, "TPM_CC_VerifySignature" }, | |
| { TPM_CC_ECC_Parameters, "TPM_CC_ECC_Parameters" }, | |
| { TPM_CC_FirmwareRead, "TPM_CC_FirmwareRead" }, | |
| { TPM_CC_GetCapability, "TPM_CC_GetCapability" }, | |
| { TPM_CC_GetRandom, "TPM_CC_GetRandom" }, | |
| { TPM_CC_GetTestResult, "TPM_CC_GetTestResult" }, | |
| { TPM_CC_Hash, "TPM_CC_Hash" }, | |
| { TPM_CC_PCR_Read, "TPM_CC_PCR_Read" }, | |
| { TPM_CC_PolicyPCR, "TPM_CC_PolicyPCR" }, | |
| { TPM_CC_PolicyRestart, "TPM_CC_PolicyRestart" }, | |
| { TPM_CC_ReadClock, "TPM_CC_ReadClock" }, | |
| { TPM_CC_PCR_Extend, "TPM_CC_PCR_Extend" }, | |
| { TPM_CC_PCR_SetAuthValue, "TPM_CC_PCR_SetAuthValue" }, | |
| { TPM_CC_NV_Certify, "TPM_CC_NV_Certify" }, | |
| { TPM_CC_EventSequenceComplete, "TPM_CC_EventSequenceComplete" }, | |
| { TPM_CC_HashSequenceStart, "TPM_CC_HashSequenceStart" }, | |
| { TPM_CC_PolicyPhysicalPresence, "TPM_CC_PolicyPhysicalPresence" }, | |
| { TPM_CC_PolicyDuplicationSelect, "TPM_CC_PolicyDuplicationSelect" }, | |
| { TPM_CC_PolicyGetDigest, "TPM_CC_PolicyGetDigest" }, | |
| { TPM_CC_TestParms, "TPM_CC_TestParms" }, | |
| { TPM_CC_Commit, "TPM_CC_Commit" }, | |
| { TPM_CC_PolicyPassword, "TPM_CC_PolicyPassword" }, | |
| { TPM_CC_ZGen_2Phase, "TPM_CC_ZGen_2Phase" }, | |
| { TPM_CC_EC_Ephemeral, "TPM_CC_EC_Ephemeral" }, | |
| }; | |
| UINTN CommandCodeStringsCount = sizeof (CommandCodeStrings) / sizeof (CommandCodeStrings[0]); | |
| TPM2_CODE_STRING ResponseCodeStrings[] = { | |
| { TPM_RC_SUCCESS, "TPM_RC_SUCCESS" }, | |
| { TPM_RC_BAD_TAG, "TPM_RC_BAD_TAG" }, | |
| { TPM_RC_INITIALIZE, "TPM_RC_INITIALIZE" }, | |
| { TPM_RC_FAILURE, "TPM_RC_FAILURE" }, | |
| { TPM_RC_SEQUENCE, "TPM_RC_SEQUENCE" }, | |
| { TPM_RC_PRIVATE, "TPM_RC_PRIVATE" }, | |
| { TPM_RC_HMAC, "TPM_RC_HMAC" }, | |
| { TPM_RC_DISABLED, "TPM_RC_DISABLED" }, | |
| { TPM_RC_EXCLUSIVE, "TPM_RC_EXCLUSIVE" }, | |
| { TPM_RC_AUTH_TYPE, "TPM_RC_AUTH_TYPE" }, | |
| { TPM_RC_AUTH_MISSING, "TPM_RC_AUTH_MISSING" }, | |
| { TPM_RC_POLICY, "TPM_RC_POLICY" }, | |
| { TPM_RC_PCR, "TPM_RC_PCR" }, | |
| { TPM_RC_PCR_CHANGED, "TPM_RC_PCR_CHANGED" }, | |
| { TPM_RC_UPGRADE, "TPM_RC_UPGRADE" }, | |
| { TPM_RC_TOO_MANY_CONTEXTS, "TPM_RC_TOO_MANY_CONTEXTS" }, | |
| { TPM_RC_AUTH_UNAVAILABLE, "TPM_RC_AUTH_UNAVAILABLE" }, | |
| { TPM_RC_REBOOT, "TPM_RC_REBOOT" }, | |
| { TPM_RC_UNBALANCED, "TPM_RC_UNBALANCED" }, | |
| { TPM_RC_COMMAND_SIZE, "TPM_RC_COMMAND_SIZE" }, | |
| { TPM_RC_COMMAND_CODE, "TPM_RC_COMMAND_CODE" }, | |
| { TPM_RC_AUTHSIZE, "TPM_RC_AUTHSIZE" }, | |
| { TPM_RC_AUTH_CONTEXT, "TPM_RC_AUTH_CONTEXT" }, | |
| { TPM_RC_NV_RANGE, "TPM_RC_NV_RANGE" }, | |
| { TPM_RC_NV_SIZE, "TPM_RC_NV_SIZE" }, | |
| { TPM_RC_NV_LOCKED, "TPM_RC_NV_LOCKED" }, | |
| { TPM_RC_NV_AUTHORIZATION, "TPM_RC_NV_AUTHORIZATION" }, | |
| { TPM_RC_NV_UNINITIALIZED, "TPM_RC_NV_UNINITIALIZED" }, | |
| { TPM_RC_NV_SPACE, "TPM_RC_NV_SPACE" }, | |
| { TPM_RC_NV_DEFINED, "TPM_RC_NV_DEFINED" }, | |
| { TPM_RC_BAD_CONTEXT, "TPM_RC_BAD_CONTEXT" }, | |
| { TPM_RC_CPHASH, "TPM_RC_CPHASH" }, | |
| { TPM_RC_PARENT, "TPM_RC_PARENT" }, | |
| { TPM_RC_NEEDS_TEST, "TPM_RC_NEEDS_TEST" }, | |
| { TPM_RC_NO_RESULT, "TPM_RC_NO_RESULT" }, | |
| { TPM_RC_SENSITIVE, "TPM_RC_SENSITIVE" }, | |
| }; | |
| UINTN ResponseCodeStringsCount = sizeof (ResponseCodeStrings) / sizeof (ResponseCodeStrings[0]); | |
| /** | |
| This simple function will dump up to MAX_TPM_BUFFER_DUMP bytes | |
| of a TPM data buffer and apppend '...' if buffer is larger. | |
| @param[in] Preamble [Optional] A string to print before the buffer dump. | |
| @param[in] BufferSize The actual size of the provided buffer. | |
| @param[in] Buffer A pointer to the buffer in question. | |
| **/ | |
| VOID | |
| DumpTpmBuffer ( | |
| IN CHAR8 *Preamble OPTIONAL, | |
| IN UINTN BufferSize, | |
| IN CONST UINT8 *Buffer | |
| ) | |
| { | |
| UINTN DebugBufferCount, Index; | |
| // TODO: Don't even evaluate if below required debugging level. | |
| // TODO: Pass in max buffer size? Format nicely? | |
| // Determine max buffer size. | |
| DebugBufferCount = MIN (BufferSize, MAX_TPM_BUFFER_DUMP); | |
| // Print the preamble, if supplied. | |
| if (Preamble) { | |
| DEBUG ((DEBUG_SECURITY, "%a", Preamble)); | |
| } | |
| // Dump them bytes. | |
| for (Index = 0; Index < DebugBufferCount; Index++) { | |
| DEBUG ((DEBUG_SECURITY, "%02X ", Buffer[Index])); | |
| } | |
| // FINISH HIM!!! | |
| if (DebugBufferCount != BufferSize) { | |
| DEBUG ((DEBUG_SECURITY, "...\n")); | |
| } else { | |
| DEBUG ((DEBUG_SECURITY, "\n")); | |
| } | |
| return; | |
| } | |
| /** | |
| This abstract function takes in a list of codes and strings and returns either | |
| a string matching the code or the supplied "default" string. | |
| @param[in] Code TPM2 Command or Response Code in little-endian format. | |
| @param[in] List Pointer to the start of a TPM2_CODE_STRING list. | |
| @param[in] ListCount Number of items in the given list. | |
| @param[in] DefaultString A string to be returned if no matching string is found. | |
| @retval CHAR8* of a human-readable string for the code (as defined in the spec). | |
| **/ | |
| STATIC | |
| CHAR8 * | |
| GetTpmCodeString ( | |
| IN UINT32 Code, | |
| IN TPM2_CODE_STRING *List, | |
| IN UINTN ListCount, | |
| IN CHAR8 *DefaultString | |
| ) | |
| { | |
| UINTN Index; | |
| CHAR8 *Result = DefaultString; | |
| // Find the code in the string array. | |
| for (Index = 0; Index < ListCount; Index++) { | |
| if (List[Index].Code == Code) { | |
| Result = List[Index].Text; | |
| break; | |
| } | |
| } | |
| return Result; | |
| } | |
| /** | |
| Simple wrapper function to use GetTpmCodeString() to search for a command code. | |
| @param[in] Code TPM2 Command Code in marshalled (generally big-endian) format. | |
| @retval CHAR8* of a human-readable string for the code (as defined in the spec). | |
| **/ | |
| CHAR8 * | |
| GetTpm2CommandString ( | |
| IN TPM_CC Code | |
| ) | |
| { | |
| return GetTpmCodeString (SwapBytes32 (Code), CommandCodeStrings, CommandCodeStringsCount, "TPM_CC_UNKNOWN"); | |
| } | |
| /** | |
| Simple wrapper function to use GetTpmCodeString() to search for a response code. | |
| @param[in] Code TPM2 Response Code in marshalled (generally big-endian) format. | |
| @retval CHAR8* of a human-readable string for the code (as defined in the spec). | |
| **/ | |
| CHAR8 * | |
| GetTpm2ResponseString ( | |
| IN TPM_RC Code | |
| ) | |
| { | |
| return GetTpmCodeString (SwapBytes32 (Code), ResponseCodeStrings, ResponseCodeStringsCount, "TPM_RC_UNKNOWN"); | |
| } | |
| /** | |
| This function dumps a TPM2B_DIGEST structure. | |
| @param[in] Preamble [Optional] A string to print before the digest dump. | |
| @param[in] Digest Pointer to the TPM2B_DIGEST structure to be printed. | |
| **/ | |
| STATIC | |
| VOID | |
| Dump2bDigest ( | |
| IN CHAR8 *Preamble OPTIONAL, | |
| IN CONST TPM2B_DIGEST *Digest | |
| ) | |
| { | |
| UINT16 DigestSize; | |
| DigestSize = SwapBytes16 (Digest->size); | |
| if (DigestSize) { | |
| DumpTpmBuffer (Preamble, SwapBytes16 (Digest->size), Digest->buffer); | |
| } else { | |
| DEBUG ((DEBUG_SECURITY, "%a<EMPTY>\n", Preamble)); | |
| } | |
| return; | |
| } | |
| /** | |
| This function dumps an AuthSession structure from a command or response. | |
| @param[in] IsCommand Indicates that the auth session structure starts with a session handle. | |
| @param[in] AuthSessionPtr Pointer to the auth session to be printed. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpAuthSession ( | |
| IN BOOLEAN IsCommand, | |
| IN CONST UINT8 *AuthSession | |
| ) | |
| { | |
| CONST UINT8 *FloatingPtr; | |
| CONST TPM2B_DIGEST *Digest; | |
| FloatingPtr = AuthSession; | |
| DEBUG ((DEBUG_SECURITY, "== Auth Session ==\n")); | |
| // If we're pointing to a command auth session, | |
| // we need to print the session handle. | |
| if (IsCommand) { | |
| DEBUG ((DEBUG_SECURITY, "- SHand: 0x%8X\n", SwapBytes32 (*(UINT32 *)FloatingPtr))); | |
| FloatingPtr += sizeof (UINT32); | |
| } | |
| // Print the common parts of an auth session. | |
| Digest = (TPM2B_DIGEST *)FloatingPtr; | |
| Dump2bDigest ("- Nonce: ", Digest); | |
| FloatingPtr += sizeof (UINT16) + SwapBytes16 (Digest->size); // Add the size field and the digest size. | |
| DEBUG ((DEBUG_SECURITY, "- Attr: 0x%2X\n", *FloatingPtr)); | |
| FloatingPtr++; | |
| Digest = (TPM2B_DIGEST *)FloatingPtr; | |
| Dump2bDigest ("- HMAC: ", Digest); | |
| return; | |
| } | |
| /** | |
| This function dumps additional information about TPM PCR Extend | |
| and Event operations. | |
| @param[in] Command Little-endian format of the command being issued. | |
| @param[in] InputBlockSize Size of the input buffer. | |
| @param[in] InputBlock Pointer to the input buffer itself. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpTpmPcrCommand ( | |
| IN TPM_CC Command, | |
| IN UINT32 InputBlockSize, | |
| IN CONST UINT8 *InputBlock | |
| ) | |
| { | |
| CONST TPM2_PCR_COMMON_COMMAND *PcrHeader; | |
| TPMI_DH_PCR PcrHandle; | |
| // If this is an unrecognized command, we can't go much further. | |
| if ((Command != TPM_CC_PCR_Extend) && (Command != TPM_CC_PCR_Event)) { | |
| DEBUG ((DEBUG_SECURITY, "%a - Unrecognized command! 0x%X\n", __func__, Command)); | |
| return; | |
| } | |
| // Start the debugging by mapping some stuff. | |
| PcrHeader = (TPM2_PCR_COMMON_COMMAND *)InputBlock; | |
| PcrHandle = SwapBytes32 (PcrHeader->PcrHandle); | |
| DEBUG ((DEBUG_SECURITY, "- PCR: %d (0x%08X)\n", PcrHandle, PcrHandle)); | |
| // Now handle any command-specific debugging. | |
| if (Command == TPM_CC_PCR_Extend) { | |
| CONST TPML_DIGEST_VALUES *DigestValues; | |
| CONST TPMT_HA *CurrentDigest; | |
| UINT32 DigestCount; | |
| // Move the dump data to the start of the digest section. | |
| DigestValues = (TPML_DIGEST_VALUES *)(InputBlock + OFFSET_OF (TPM2_PCR_COMMON_COMMAND, AuthSessionPcr) + SwapBytes32 (PcrHeader->AuthorizationSize)); | |
| // Determine the digest count and locate the first digest. | |
| DigestCount = SwapBytes32 (DigestValues->count); | |
| CurrentDigest = &DigestValues->digests[0]; | |
| // Print each digest. | |
| do { | |
| // Print the current digest. | |
| switch (SwapBytes16 (CurrentDigest->hashAlg)) { | |
| case TPM_ALG_SHA1: | |
| DumpTpmBuffer ("- SHA1: ", SHA1_DIGEST_SIZE, CurrentDigest->digest.sha1); | |
| CurrentDigest = (TPMT_HA *)((UINT8 *)CurrentDigest + OFFSET_OF (TPMT_HA, digest) + SHA1_DIGEST_SIZE); | |
| DigestCount--; // Account for this digest. | |
| break; | |
| case TPM_ALG_SHA256: | |
| DumpTpmBuffer ("- SHA256: ", SHA256_DIGEST_SIZE, CurrentDigest->digest.sha256); | |
| CurrentDigest = (TPMT_HA *)((UINT8 *)CurrentDigest + OFFSET_OF (TPMT_HA, digest) + SHA256_DIGEST_SIZE); | |
| DigestCount--; // Account for this digest. | |
| break; | |
| default: | |
| // This algorithm hasn't been programmed yet. We need to bail. | |
| DEBUG ((DEBUG_SECURITY, "%a - Unknown hash algorithm! 0x%04X\n", __func__, SwapBytes16 (CurrentDigest->hashAlg))); | |
| // Zero the count so we can get out of here. | |
| DigestCount = 0; | |
| break; | |
| } | |
| } while (DigestCount > 0); | |
| } | |
| return; | |
| } | |
| /** | |
| This function dumps additional information about TPM Hierarchy Change Auth operations. | |
| @param[in] InputBlockSize Size of the input buffer. | |
| @param[in] InputBlock Pointer to the input buffer itself. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpTpmHierarchyChangeAuthCommand ( | |
| IN UINT32 InputBlockSize, | |
| IN CONST UINT8 *InputBlock | |
| ) | |
| { | |
| CONST TPM2_HIERARCHY_CHANGE_AUTH_COMMAND *ChangeAuthCommand; | |
| CONST TPM2B_DIGEST *Digest; | |
| // Start the debugging by mapping some stuff. | |
| ChangeAuthCommand = (TPM2_HIERARCHY_CHANGE_AUTH_COMMAND *)InputBlock; | |
| // Print the auth handle (the handle being authorized against). | |
| DEBUG ((DEBUG_SECURITY, "- AHand: 0x%8X\n", SwapBytes32 (ChangeAuthCommand->AuthHandle))); | |
| // Print the auth session. | |
| DumpAuthSession (TRUE, (UINT8 *)&ChangeAuthCommand->AuthSession); | |
| // Print the new auth. | |
| Digest = (TPM2B_DIGEST *)(InputBlock + OFFSET_OF (TPM2_HIERARCHY_CHANGE_AUTH_COMMAND, AuthSession) + SwapBytes32 (ChangeAuthCommand->AuthorizationSize)); | |
| Dump2bDigest ("- NAuth: ", Digest); | |
| return; | |
| } | |
| /** | |
| This function dumps additional information about Policy OR operations. | |
| @param[in] InputBlockSize Size of the input buffer. | |
| @param[in] InputBlock Pointer to the input buffer itself. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpTpmPolicyOrCommand ( | |
| IN UINT32 InputBlockSize, | |
| IN CONST UINT8 *InputBlock | |
| ) | |
| { | |
| CONST TPM2_POLICY_OR_COMMAND *PolicyOrCommand; | |
| CONST TPM2B_DIGEST *Digest; | |
| UINT32 Index; | |
| // Start the debugging by mapping some stuff. | |
| PolicyOrCommand = (TPM2_POLICY_OR_COMMAND *)InputBlock; | |
| // Print the policy session token. | |
| DEBUG ((DEBUG_SECURITY, "- PSess: 0x%8X\n", SwapBytes32 (PolicyOrCommand->PolicySession))); | |
| // Print out all of the digests. | |
| Digest = &PolicyOrCommand->HashList.digests[0]; | |
| for (Index = 0; Index < SwapBytes32 (PolicyOrCommand->HashList.count); Index++) { | |
| Dump2bDigest ("- Digest: ", Digest); | |
| // Add the size field and the digest size. | |
| Digest = (TPM2B_DIGEST *)((UINT8 *)Digest + sizeof (UINT16) + SwapBytes16 (Digest->size)); | |
| } | |
| return; | |
| } | |
| /** | |
| This function dumps additional information about Start Auth Session operations. | |
| @param[in] InputBlockSize Size of the input buffer. | |
| @param[in] InputBlock Pointer to the input buffer itself. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpTpmStartAuthSessionCommand ( | |
| IN UINT32 InputBlockSize, | |
| IN CONST UINT8 *InputBlock | |
| ) | |
| { | |
| CONST UINT8 *FloatingPtr; | |
| CONST TPM2_START_AUTH_SESSION_COMMAND *StartAuthSessionCommand; | |
| CONST TPM2B_DIGEST *Digest; | |
| // Start the debugging by mapping some stuff. | |
| StartAuthSessionCommand = (TPM2_START_AUTH_SESSION_COMMAND *)InputBlock; | |
| // Print as many of the simple fields as possible. | |
| DEBUG ((DEBUG_SECURITY, "- TpmKey: 0x%8X\n", SwapBytes32 (StartAuthSessionCommand->TpmKey))); | |
| DEBUG ((DEBUG_SECURITY, "- Bind: 0x%8X\n", SwapBytes32 (StartAuthSessionCommand->Bind))); | |
| Digest = (TPM2B_DIGEST *)&StartAuthSessionCommand->NonceCaller; | |
| Dump2bDigest ("- NonceC: ", Digest); | |
| // Add the size field and the digest size. | |
| FloatingPtr = (UINT8 *)Digest + sizeof (UINT16) + SwapBytes16 (Digest->size); | |
| // Skip the Salt for now. | |
| Digest = (TPM2B_DIGEST *)FloatingPtr; | |
| Dump2bDigest ("- Salt: ", Digest); | |
| FloatingPtr += sizeof (UINT16) + SwapBytes16 (Digest->size); | |
| // Print the remaining things. | |
| DEBUG ((DEBUG_SECURITY, "- SesTyp: 0x%2X\n", *FloatingPtr)); | |
| FloatingPtr++; | |
| // Skip Symmetric for now. | |
| // NOTE: Symmetric is an interpreted structure, so just jump to the end. | |
| FloatingPtr = InputBlock + (InputBlockSize - sizeof (UINT16)); | |
| DEBUG ((DEBUG_SECURITY, "- AHash: 0x%4X\n", SwapBytes16 (*(UINT16 *)FloatingPtr))); | |
| return; | |
| } | |
| /** | |
| This function dumps additional information about Start Auth Session operations. | |
| @param[in] OutputBlockSize Size of the output buffer. | |
| @param[in] OutputBlock Pointer to the output buffer itself. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpTpmStartAuthSessionResponse ( | |
| IN UINT32 OutputBlockSize, | |
| IN CONST UINT8 *OutputBlock | |
| ) | |
| { | |
| CONST TPM2_START_AUTH_SESSION_RESPONSE *StartAuthSessionResponse; | |
| CONST TPM2B_DIGEST *Digest; | |
| // Start the debugging by mapping some stuff. | |
| StartAuthSessionResponse = (TPM2_START_AUTH_SESSION_RESPONSE *)OutputBlock; | |
| // Dump the handle and the nonce. | |
| DEBUG ((DEBUG_SECURITY, "- SHand: 0x%8X\n", SwapBytes32 (StartAuthSessionResponse->SessionHandle))); | |
| Digest = (TPM2B_DIGEST *)&StartAuthSessionResponse->NonceTPM; | |
| Dump2bDigest ("- NonceT: ", Digest); | |
| return; | |
| } | |
| /** | |
| This function dumps as much information as possible about | |
| a command being sent to the TPM for maximum user-readability. | |
| @param[in] InputBlockSize Size of the input buffer. | |
| @param[in] InputBlock Pointer to the input buffer itself. | |
| **/ | |
| VOID | |
| EFIAPI | |
| DumpTpmInputBlock ( | |
| IN UINT32 InputBlockSize, | |
| IN CONST UINT8 *InputBlock | |
| ) | |
| { | |
| CONST TPM2_COMMAND_HEADER *CommHeader; | |
| TPM_ST NativeTag; | |
| UINT32 NativeSize; | |
| TPM_CC NativeCode; | |
| DEBUG ((DEBUG_SECURITY, "\n=== BEGIN TPM COMMAND ===\n")); | |
| DEBUG ((DEBUG_SECURITY, "Size: %d (0x%X), Address: 0x%X\n", InputBlockSize, InputBlockSize, InputBlock)); | |
| // Make sure we've got at least enough data for a valid header. | |
| if (InputBlockSize < sizeof (*CommHeader)) { | |
| DEBUG ((DEBUG_SECURITY, "%a - Invalid buffer size!\n", __func__)); | |
| return; | |
| } | |
| // Start the debugging by mapping some stuff. | |
| CommHeader = (TPM2_COMMAND_HEADER *)InputBlock; | |
| NativeTag = SwapBytes16 (CommHeader->tag); | |
| NativeSize = SwapBytes32 (CommHeader->paramSize); | |
| NativeCode = SwapBytes32 (CommHeader->commandCode); | |
| DEBUG ((DEBUG_SECURITY, "Command: %a (0x%08X)\n", GetTpm2CommandString (CommHeader->commandCode), NativeCode)); | |
| DEBUG ((DEBUG_SECURITY, "Tag: 0x%04X\n", NativeTag)); | |
| DEBUG ((DEBUG_SECURITY, "Size: %d (0x%X)\n", NativeSize, NativeSize)); | |
| // Debug anything else. | |
| switch (NativeCode) { | |
| case TPM_CC_PCR_Event: | |
| case TPM_CC_PCR_Extend: | |
| DumpTpmPcrCommand (NativeCode, InputBlockSize, InputBlock); | |
| break; | |
| case TPM_CC_HierarchyChangeAuth: | |
| DumpTpmHierarchyChangeAuthCommand (InputBlockSize, InputBlock); | |
| break; | |
| case TPM_CC_PolicyOR: | |
| DumpTpmPolicyOrCommand (InputBlockSize, InputBlock); | |
| break; | |
| case TPM_CC_StartAuthSession: | |
| DumpTpmStartAuthSessionCommand (InputBlockSize, InputBlock); | |
| break; | |
| default: | |
| break; | |
| } | |
| // If verbose, dump all of the buffer contents for deeper analysis. | |
| DumpTpmBuffer ("DATA: ", MIN (InputBlockSize, NativeSize), InputBlock); | |
| return; | |
| } | |
| /** | |
| This function dumps as much information as possible about | |
| a response from the TPM for maximum user-readability. | |
| @param[in] OutputBlockSize Size of the output buffer. | |
| @param[in] OutputBlock Pointer to the output buffer itself. | |
| @param[in] CommandCode Command code for the input block. | |
| **/ | |
| VOID | |
| EFIAPI | |
| DumpTpmOutputBlock ( | |
| IN UINT32 OutputBlockSize, | |
| IN CONST UINT8 *OutputBlock, | |
| IN UINT32 CommandCode | |
| ) | |
| { | |
| CONST TPM2_RESPONSE_HEADER *RespHeader; | |
| TPM_ST NativeTag; | |
| UINT32 NativeSize; | |
| TPM_CC NativeCode; | |
| DEBUG ((DEBUG_SECURITY, "Size: %d (0x%X), Address: 0x%X\n", OutputBlockSize, OutputBlockSize, OutputBlock)); | |
| // Start the debugging by mapping some stuff. | |
| RespHeader = (TPM2_RESPONSE_HEADER *)OutputBlock; | |
| NativeTag = SwapBytes16 (RespHeader->tag); | |
| NativeSize = SwapBytes32 (RespHeader->paramSize); | |
| NativeCode = SwapBytes32 (RespHeader->responseCode); | |
| DEBUG ((DEBUG_SECURITY, "Response: %a (0x%08X)\n", GetTpm2ResponseString (RespHeader->responseCode), NativeCode)); | |
| DEBUG ((DEBUG_SECURITY, "Tag: 0x%04X\n", NativeTag)); | |
| DEBUG ((DEBUG_SECURITY, "Size: %d (0x%X)\n", NativeSize, NativeSize)); | |
| // Debug anything else based on the Command context. | |
| if (CommandCode != 0x00) { | |
| switch (CommandCode) { | |
| case TPM_CC_StartAuthSession: | |
| DumpTpmStartAuthSessionResponse (OutputBlockSize, OutputBlock); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| // If verbose, dump all of the buffer contents for deeper analysis. | |
| DumpTpmBuffer ("DATA: ", MIN (OutputBlockSize, NativeSize), OutputBlock); | |
| DEBUG ((DEBUG_SECURITY, "=== END TPM COMMAND ===\n\n")); | |
| return; | |
| } |