/** @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;
}