/** @file Implement TPM2 Sequences related command. Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #pragma pack(1) typedef struct { TPM2_COMMAND_HEADER Header; TPM2B_AUTH Auth; TPMI_ALG_HASH HashAlg; } TPM2_HASH_SEQUENCE_START_COMMAND; typedef struct { TPM2_RESPONSE_HEADER Header; TPMI_DH_OBJECT SequenceHandle; } TPM2_HASH_SEQUENCE_START_RESPONSE; typedef struct { TPM2_COMMAND_HEADER Header; TPMI_DH_OBJECT SequenceHandle; UINT32 AuthorizationSize; TPMS_AUTH_COMMAND AuthSessionSeq; TPM2B_MAX_BUFFER Buffer; } TPM2_SEQUENCE_UPDATE_COMMAND; typedef struct { TPM2_RESPONSE_HEADER Header; UINT32 ParameterSize; TPMS_AUTH_RESPONSE AuthSessionSeq; } TPM2_SEQUENCE_UPDATE_RESPONSE; typedef struct { TPM2_COMMAND_HEADER Header; TPMI_DH_PCR PcrHandle; TPMI_DH_OBJECT SequenceHandle; UINT32 AuthorizationSize; TPMS_AUTH_COMMAND AuthSessionPcr; TPMS_AUTH_COMMAND AuthSessionSeq; TPM2B_MAX_BUFFER Buffer; } TPM2_EVENT_SEQUENCE_COMPLETE_COMMAND; typedef struct { TPM2_RESPONSE_HEADER Header; UINT32 ParameterSize; TPML_DIGEST_VALUES Results; TPMS_AUTH_RESPONSE AuthSessionPcr; TPMS_AUTH_RESPONSE AuthSessionSeq; } TPM2_EVENT_SEQUENCE_COMPLETE_RESPONSE; typedef struct { TPM2_COMMAND_HEADER Header; TPMI_DH_OBJECT SequenceHandle; UINT32 AuthorizationSize; TPMS_AUTH_COMMAND AuthSessionSeq; TPM2B_MAX_BUFFER Buffer; TPMI_RH_HIERARCHY Hierarchy; } TPM2_SEQUENCE_COMPLETE_COMMAND; typedef struct { TPM2_RESPONSE_HEADER Header; UINT32 ParameterSize; TPM2B_DIGEST Digest; TPMS_AUTH_RESPONSE AuthSessionSeq; } TPM2_SEQUENCE_COMPLETE_RESPONSE; #pragma pack() /** This command starts a hash or an Event sequence. If hashAlg is an implemented hash, then a hash sequence is started. If hashAlg is TPM_ALG_NULL, then an Event sequence is started. @param[in] HashAlg The hash algorithm to use for the hash sequence An Event sequence starts if this is TPM_ALG_NULL. @param[out] SequenceHandle A handle to reference the sequence @retval EFI_SUCCESS Operation completed successfully. @retval EFI_DEVICE_ERROR Unexpected device behavior. **/ EFI_STATUS EFIAPI Tpm2HashSequenceStart ( IN TPMI_ALG_HASH HashAlg, OUT TPMI_DH_OBJECT *SequenceHandle ) { EFI_STATUS Status; TPM2_HASH_SEQUENCE_START_COMMAND Cmd; TPM2_HASH_SEQUENCE_START_RESPONSE Res; UINT32 CmdSize; UINT32 RespSize; UINT8 *Buffer; UINT32 ResultBufSize; ZeroMem (&Cmd, sizeof (Cmd)); // // Construct command // Cmd.Header.tag = SwapBytes16 (TPM_ST_NO_SESSIONS); Cmd.Header.commandCode = SwapBytes32 (TPM_CC_HashSequenceStart); Buffer = (UINT8 *)&Cmd.Auth; // auth = nullAuth WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (0)); Buffer += sizeof (UINT16); // hashAlg WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (HashAlg)); Buffer += sizeof (UINT16); CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); Cmd.Header.paramSize = SwapBytes32 (CmdSize); // // Call the TPM // ResultBufSize = sizeof (Res); Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); if (EFI_ERROR (Status)) { return Status; } if (ResultBufSize > sizeof (Res)) { DEBUG ((DEBUG_ERROR, "HashSequenceStart: Failed ExecuteCommand: Buffer Too Small\r\n")); return EFI_BUFFER_TOO_SMALL; } // // Validate response headers // RespSize = SwapBytes32 (Res.Header.paramSize); if (RespSize > sizeof (Res)) { DEBUG ((DEBUG_ERROR, "HashSequenceStart: Response size too large! %d\r\n", RespSize)); return EFI_BUFFER_TOO_SMALL; } // // Fail if command failed // if (SwapBytes32 (Res.Header.responseCode) != TPM_RC_SUCCESS) { DEBUG ((DEBUG_ERROR, "HashSequenceStart: Response Code error! 0x%08x\r\n", SwapBytes32 (Res.Header.responseCode))); return EFI_DEVICE_ERROR; } // // Unmarshal the response // // sequenceHandle *SequenceHandle = SwapBytes32 (Res.SequenceHandle); return EFI_SUCCESS; } /** This command is used to add data to a hash or HMAC sequence. The amount of data in buffer may be any size up to the limits of the TPM. NOTE: In all TPM, a buffer size of 1,024 octets is allowed. @param[in] SequenceHandle Handle for the sequence object @param[in] Buffer Data to be added to hash @retval EFI_SUCCESS Operation completed successfully. @retval EFI_DEVICE_ERROR Unexpected device behavior. **/ EFI_STATUS EFIAPI Tpm2SequenceUpdate ( IN TPMI_DH_OBJECT SequenceHandle, IN TPM2B_MAX_BUFFER *Buffer ) { EFI_STATUS Status; TPM2_SEQUENCE_UPDATE_COMMAND Cmd; TPM2_SEQUENCE_UPDATE_RESPONSE Res; UINT32 CmdSize; UINT32 RespSize; UINT8 *BufferPtr; UINT32 SessionInfoSize; UINT32 ResultBufSize; ZeroMem (&Cmd, sizeof (Cmd)); // // Construct command // Cmd.Header.tag = SwapBytes16 (TPM_ST_SESSIONS); Cmd.Header.commandCode = SwapBytes32 (TPM_CC_SequenceUpdate); Cmd.SequenceHandle = SwapBytes32 (SequenceHandle); // // Add in Auth session // BufferPtr = (UINT8 *)&Cmd.AuthSessionSeq; // sessionInfoSize SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); BufferPtr += SessionInfoSize; Cmd.AuthorizationSize = SwapBytes32 (SessionInfoSize); // buffer.size WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16 (Buffer->size)); BufferPtr += sizeof (UINT16); CopyMem (BufferPtr, &Buffer->buffer, Buffer->size); BufferPtr += Buffer->size; CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); Cmd.Header.paramSize = SwapBytes32 (CmdSize); // // Call the TPM // ResultBufSize = sizeof (Res); Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); if (EFI_ERROR (Status)) { return Status; } if (ResultBufSize > sizeof (Res)) { DEBUG ((DEBUG_ERROR, "SequenceUpdate: Failed ExecuteCommand: Buffer Too Small\r\n")); return EFI_BUFFER_TOO_SMALL; } // // Validate response headers // RespSize = SwapBytes32 (Res.Header.paramSize); if (RespSize > sizeof (Res)) { DEBUG ((DEBUG_ERROR, "SequenceUpdate: Response size too large! %d\r\n", RespSize)); return EFI_BUFFER_TOO_SMALL; } // // Fail if command failed // if (SwapBytes32 (Res.Header.responseCode) != TPM_RC_SUCCESS) { DEBUG ((DEBUG_ERROR, "SequenceUpdate: Response Code error! 0x%08x\r\n", SwapBytes32 (Res.Header.responseCode))); return EFI_DEVICE_ERROR; } // // Unmarshal the response // // None return EFI_SUCCESS; } /** This command adds the last part of data, if any, to an Event sequence and returns the result in a digest list. If pcrHandle references a PCR and not TPM_RH_NULL, then the returned digest list is processed in the same manner as the digest list input parameter to TPM2_PCR_Extend() with the pcrHandle in each bank extended with the associated digest value. @param[in] PcrHandle PCR to be extended with the Event data @param[in] SequenceHandle Authorization for the sequence @param[in] Buffer Data to be added to the Event @param[out] Results List of digests computed for the PCR @retval EFI_SUCCESS Operation completed successfully. @retval EFI_DEVICE_ERROR Unexpected device behavior. **/ EFI_STATUS EFIAPI Tpm2EventSequenceComplete ( IN TPMI_DH_PCR PcrHandle, IN TPMI_DH_OBJECT SequenceHandle, IN TPM2B_MAX_BUFFER *Buffer, OUT TPML_DIGEST_VALUES *Results ) { EFI_STATUS Status; TPM2_EVENT_SEQUENCE_COMPLETE_COMMAND Cmd; TPM2_EVENT_SEQUENCE_COMPLETE_RESPONSE Res; UINT32 CmdSize; UINT32 RespSize; UINT8 *BufferPtr; UINT32 SessionInfoSize; UINT32 SessionInfoSize2; UINT32 Index; UINT32 ResultBufSize; UINT16 DigestSize; ZeroMem (&Cmd, sizeof (Cmd)); // // Construct command // Cmd.Header.tag = SwapBytes16 (TPM_ST_SESSIONS); Cmd.Header.commandCode = SwapBytes32 (TPM_CC_EventSequenceComplete); Cmd.PcrHandle = SwapBytes32 (PcrHandle); Cmd.SequenceHandle = SwapBytes32 (SequenceHandle); // // Add in pcrHandle Auth session // BufferPtr = (UINT8 *)&Cmd.AuthSessionPcr; // sessionInfoSize SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); BufferPtr += SessionInfoSize; // sessionInfoSize SessionInfoSize2 = CopyAuthSessionCommand (NULL, BufferPtr); BufferPtr += SessionInfoSize2; Cmd.AuthorizationSize = SwapBytes32 (SessionInfoSize + SessionInfoSize2); // buffer.size WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16 (Buffer->size)); BufferPtr += sizeof (UINT16); CopyMem (BufferPtr, &Buffer->buffer[0], Buffer->size); BufferPtr += Buffer->size; CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); Cmd.Header.paramSize = SwapBytes32 (CmdSize); // // Call the TPM // ResultBufSize = sizeof (Res); Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); if (EFI_ERROR (Status)) { return Status; } if (ResultBufSize > sizeof (Res)) { DEBUG ((DEBUG_ERROR, "EventSequenceComplete: Failed ExecuteCommand: Buffer Too Small\r\n")); return EFI_BUFFER_TOO_SMALL; } // // Validate response headers // RespSize = SwapBytes32 (Res.Header.paramSize); if (RespSize > sizeof (Res)) { DEBUG ((DEBUG_ERROR, "EventSequenceComplete: Response size too large! %d\r\n", RespSize)); return EFI_BUFFER_TOO_SMALL; } // // Fail if command failed // if (SwapBytes32 (Res.Header.responseCode) != TPM_RC_SUCCESS) { DEBUG ((DEBUG_ERROR, "EventSequenceComplete: Response Code error! 0x%08x\r\n", SwapBytes32 (Res.Header.responseCode))); return EFI_DEVICE_ERROR; } // // Unmarshal the response // BufferPtr = (UINT8 *)&Res.Results; // count Results->count = SwapBytes32 (ReadUnaligned32 ((UINT32 *)BufferPtr)); if (Results->count > HASH_COUNT) { DEBUG ((DEBUG_ERROR, "Tpm2EventSequenceComplete - Results->count error %x\n", Results->count)); return EFI_DEVICE_ERROR; } BufferPtr += sizeof (UINT32); for (Index = 0; Index < Results->count; Index++) { Results->digests[Index].hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)BufferPtr)); BufferPtr += sizeof (UINT16); DigestSize = GetHashSizeFromAlgo (Results->digests[Index].hashAlg); if (DigestSize == 0) { DEBUG ((DEBUG_ERROR, "EventSequenceComplete: Unknown hash algorithm %d\r\n", Results->digests[Index].hashAlg)); return EFI_DEVICE_ERROR; } CopyMem ( &Results->digests[Index].digest, BufferPtr, DigestSize ); BufferPtr += DigestSize; } return EFI_SUCCESS; } /** This command adds the last part of data, if any, to a hash/HMAC sequence and returns the result. @param[in] SequenceHandle Authorization for the sequence @param[in] Buffer Data to be added to the hash/HMAC @param[out] Result The returned HMAC or digest in a sized buffer @retval EFI_SUCCESS Operation completed successfully. @retval EFI_DEVICE_ERROR Unexpected device behavior. **/ EFI_STATUS EFIAPI Tpm2SequenceComplete ( IN TPMI_DH_OBJECT SequenceHandle, IN TPM2B_MAX_BUFFER *Buffer, OUT TPM2B_DIGEST *Result ) { EFI_STATUS Status; TPM2_SEQUENCE_COMPLETE_COMMAND Cmd; TPM2_SEQUENCE_COMPLETE_RESPONSE Res; UINT32 CmdSize; UINT32 RespSize; UINT8 *BufferPtr; UINT32 SessionInfoSize; UINT32 ResultBufSize; ZeroMem (&Cmd, sizeof (Cmd)); // // Construct command // Cmd.Header.tag = SwapBytes16 (TPM_ST_SESSIONS); Cmd.Header.commandCode = SwapBytes32 (TPM_CC_SequenceComplete); Cmd.SequenceHandle = SwapBytes32 (SequenceHandle); // // Add in Auth session // BufferPtr = (UINT8 *)&Cmd.AuthSessionSeq; // sessionInfoSize SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); BufferPtr += SessionInfoSize; Cmd.AuthorizationSize = SwapBytes32 (SessionInfoSize); // buffer.size WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16 (Buffer->size)); BufferPtr += sizeof (UINT16); CopyMem (BufferPtr, &Buffer->buffer[0], Buffer->size); BufferPtr += Buffer->size; // Hierarchy WriteUnaligned32 ((UINT32 *)BufferPtr, SwapBytes32 (TPM_RH_NULL)); BufferPtr += sizeof (UINT32); CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); Cmd.Header.paramSize = SwapBytes32 (CmdSize); // // Call the TPM // ResultBufSize = sizeof (Res); Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); if (EFI_ERROR (Status)) { return Status; } if (ResultBufSize > sizeof (Res)) { DEBUG ((DEBUG_ERROR, "SequenceComplete: Failed ExecuteCommand: Buffer Too Small\r\n")); return EFI_BUFFER_TOO_SMALL; } // // Validate response headers // RespSize = SwapBytes32 (Res.Header.paramSize); if (RespSize > sizeof (Res)) { DEBUG ((DEBUG_ERROR, "SequenceComplete: Response size too large! %d\r\n", RespSize)); return EFI_BUFFER_TOO_SMALL; } // // Fail if command failed // if (SwapBytes32 (Res.Header.responseCode) != TPM_RC_SUCCESS) { DEBUG ((DEBUG_ERROR, "SequenceComplete: Response Code error! 0x%08x\r\n", SwapBytes32 (Res.Header.responseCode))); return EFI_DEVICE_ERROR; } // // Unmarshal the response // BufferPtr = (UINT8 *)&Res.Digest; // digestSize Result->size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)BufferPtr)); if (Result->size > sizeof (TPMU_HA)) { DEBUG ((DEBUG_ERROR, "Tpm2SequenceComplete - Result->size error %x\n", Result->size)); return EFI_DEVICE_ERROR; } BufferPtr += sizeof (UINT16); CopyMem ( Result->buffer, BufferPtr, Result->size ); return EFI_SUCCESS; }