1010 lines
34 KiB
C
1010 lines
34 KiB
C
/* IBM_PROLOG_BEGIN_TAG */
|
|
/* This is an automatically generated prolog. */
|
|
/* */
|
|
/* $Source: src/usr/secureboot/trusted/trustedbootCmds.C $ */
|
|
/* */
|
|
/* OpenPOWER HostBoot Project */
|
|
/* */
|
|
/* Contributors Listed Below - COPYRIGHT 2015,2016 */
|
|
/* [+] International Business Machines Corp. */
|
|
/* */
|
|
/* */
|
|
/* Licensed under the Apache License, Version 2.0 (the "License"); */
|
|
/* you may not use this file except in compliance with the License. */
|
|
/* You may obtain a copy of the License at */
|
|
/* */
|
|
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
|
/* */
|
|
/* Unless required by applicable law or agreed to in writing, software */
|
|
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
|
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
|
|
/* implied. See the License for the specific language governing */
|
|
/* permissions and limitations under the License. */
|
|
/* */
|
|
/* IBM_PROLOG_END_TAG */
|
|
/**
|
|
* @file trustedbootCmds.C
|
|
*
|
|
* @brief Trusted boot TPM command interfaces
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// NOTE: This file is exportable as TSS-Lite for skiboot/PHYP //
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------
|
|
// Includes
|
|
// ----------------------------------------------
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#ifdef __HOSTBOOT_MODULE
|
|
#include <secureboot/trustedboot_reasoncodes.H>
|
|
#else
|
|
#include "trustedboot_reasoncodes.H"
|
|
#endif
|
|
#include "trustedbootCmds.H"
|
|
#include "trustedbootUtils.H"
|
|
#include "trustedboot.H"
|
|
#include "trustedTypes.H"
|
|
|
|
#ifdef __cplusplus
|
|
namespace TRUSTEDBOOT
|
|
{
|
|
#endif
|
|
|
|
errlHndl_t tpmTransmitCommand(TpmTarget * io_target,
|
|
uint8_t* io_buffer,
|
|
size_t i_bufsize )
|
|
{
|
|
errlHndl_t err = TB_SUCCESS;
|
|
uint8_t* transmitBuf = NULL;
|
|
size_t cmdSize = 0;
|
|
size_t dataSize = 0;
|
|
TPM2_BaseIn* cmd = (TPM2_BaseIn*)io_buffer;
|
|
TPM2_BaseOut* resp = (TPM2_BaseOut*)io_buffer;
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
">>TPM TRANSMIT CMD START : BufLen %d : %016llx",
|
|
(int)i_bufsize,
|
|
*((uint64_t*)io_buffer) );
|
|
|
|
do
|
|
{
|
|
transmitBuf = (uint8_t*)malloc(MAX_TRANSMIT_SIZE);
|
|
|
|
// Marshal the data into a byte array for transfer to the TPM
|
|
err = tpmMarshalCommandData(cmd,
|
|
transmitBuf,
|
|
MAX_TRANSMIT_SIZE,
|
|
&cmdSize);
|
|
if (TB_SUCCESS != err)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Send to the TPM
|
|
dataSize = MAX_TRANSMIT_SIZE;
|
|
err = tpmTransmit(io_target,
|
|
transmitBuf,
|
|
cmdSize,
|
|
dataSize);
|
|
|
|
if (TB_SUCCESS != err)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Unmarshal the response
|
|
err = tpmUnmarshalResponseData(cmd->commandCode,
|
|
transmitBuf,
|
|
dataSize,
|
|
resp,
|
|
i_bufsize);
|
|
|
|
|
|
} while ( 0 );
|
|
|
|
|
|
free(transmitBuf);
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"<<tpmTransmitCommand() - %s",
|
|
((TB_SUCCESS == err) ? "No Error" : "With Error") );
|
|
return err;
|
|
}
|
|
|
|
errlHndl_t tpmMarshalCommandData(TPM2_BaseIn* i_cmd,
|
|
uint8_t* o_outbuf,
|
|
size_t i_bufsize,
|
|
size_t* o_cmdSize)
|
|
{
|
|
errlHndl_t err = TB_SUCCESS;
|
|
uint8_t* sBuf = o_outbuf;
|
|
uint32_t* sSizePtr = NULL;
|
|
size_t curSize = 0;
|
|
int stage = 0;
|
|
TPM2_BaseIn* baseCmd =
|
|
(TPM2_BaseIn*)o_outbuf;
|
|
TPMS_AUTH_COMMAND cmdAuth;
|
|
|
|
*o_cmdSize = 0;
|
|
|
|
TRACDCOMP( g_trac_trustedboot,
|
|
">>tpmMarshalCommandData()" );
|
|
do
|
|
{
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"TPM MARSHAL START : BufLen %d : %016llx",
|
|
(int)i_bufsize,
|
|
*((uint64_t*)i_cmd) );
|
|
|
|
// Start with the command header
|
|
sBuf = TPM2_BaseIn_marshal(i_cmd, sBuf, i_bufsize, o_cmdSize);
|
|
if (NULL == sBuf)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Marshal the handles
|
|
stage = 1;
|
|
if (TPM_CC_PCR_Extend == i_cmd->commandCode)
|
|
{
|
|
TPM2_ExtendIn* cmdPtr = (TPM2_ExtendIn*)i_cmd;
|
|
sBuf = TPM2_ExtendIn_marshalHandle(cmdPtr,
|
|
sBuf,
|
|
i_bufsize,
|
|
o_cmdSize);
|
|
if (NULL == sBuf)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Marshal the authorizations
|
|
stage = 2;
|
|
if (TPM_CC_PCR_Extend == i_cmd->commandCode)
|
|
{
|
|
// Insert a password authorization with a null pw
|
|
// Make room for the 4 byte size field at the beginning
|
|
sSizePtr = (uint32_t*)sBuf;
|
|
sBuf += sizeof(uint32_t);
|
|
*o_cmdSize += sizeof(uint32_t);
|
|
i_bufsize -= sizeof(uint32_t);
|
|
curSize = *o_cmdSize;
|
|
|
|
cmdAuth.sessionHandle = TPM_RS_PW;
|
|
cmdAuth.nonceSize = 0;
|
|
cmdAuth.sessionAttributes = 0;
|
|
cmdAuth.hmacSize = 0;
|
|
|
|
sBuf = TPMS_AUTH_COMMAND_marshal(&cmdAuth, sBuf, i_bufsize,
|
|
o_cmdSize);
|
|
|
|
if (NULL == sBuf)
|
|
{
|
|
break;
|
|
}
|
|
// Put in the size of the auth area
|
|
*sSizePtr = (*o_cmdSize - curSize);
|
|
|
|
}
|
|
|
|
// Marshal the command parameters
|
|
stage = 3;
|
|
switch (i_cmd->commandCode)
|
|
{
|
|
// Two byte parm fields
|
|
case TPM_CC_Startup:
|
|
{
|
|
TPM2_2ByteIn* cmdPtr =
|
|
(TPM2_2ByteIn*)i_cmd;
|
|
sBuf = TPM2_2ByteIn_marshal(cmdPtr, sBuf,
|
|
i_bufsize, o_cmdSize);
|
|
}
|
|
break;
|
|
|
|
case TPM_CC_GetCapability:
|
|
{
|
|
TPM2_GetCapabilityIn* cmdPtr =
|
|
(TPM2_GetCapabilityIn*)i_cmd;
|
|
sBuf = TPM2_GetCapabilityIn_marshal(cmdPtr,sBuf,
|
|
i_bufsize, o_cmdSize);
|
|
}
|
|
break;
|
|
case TPM_CC_PCR_Read:
|
|
{
|
|
TPM2_PcrReadIn* cmdPtr = (TPM2_PcrReadIn*)i_cmd;
|
|
sBuf = TPM2_PcrReadIn_marshal(cmdPtr, sBuf,
|
|
i_bufsize - (sBuf - o_outbuf),
|
|
o_cmdSize);
|
|
}
|
|
break;
|
|
|
|
case TPM_CC_PCR_Extend:
|
|
{
|
|
TPM2_ExtendIn* cmdPtr = (TPM2_ExtendIn*)i_cmd;
|
|
sBuf = TPM2_ExtendIn_marshalParms(cmdPtr, sBuf,
|
|
i_bufsize, o_cmdSize);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
// Command code not supported
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM MARSHAL INVALID COMMAND : %X",
|
|
i_cmd->commandCode );
|
|
sBuf = NULL;
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_MARSHAL_INVALID_CMD
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_MARSHALCMDDATA
|
|
* @userdata1 Command Code
|
|
* @userdata2 0
|
|
* @devdesc Unsupported command code during marshal
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_MARSHALCMDDATA,
|
|
RC_TPM_MARSHAL_INVALID_CMD,
|
|
i_cmd->commandCode,
|
|
0);
|
|
}
|
|
break;
|
|
};
|
|
|
|
if (TB_SUCCESS != err || NULL == sBuf)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Do a verification that the cmdSize equals what we used
|
|
if (((size_t)(sBuf - o_outbuf)) != *o_cmdSize)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM MARSHAL MARSHAL SIZE MISMATCH : %d %d",
|
|
(int)(sBuf - o_outbuf), (int)(*o_cmdSize) );
|
|
sBuf = NULL;
|
|
}
|
|
|
|
// Lastly now that we know the size update the byte stream
|
|
baseCmd->commandSize = *o_cmdSize;
|
|
|
|
} while ( 0 );
|
|
|
|
if (NULL == sBuf && TB_SUCCESS == err)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM MARSHAL FAILURE : Stage %d", stage);
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_MARSHALING_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_MARSHALCMDDATA
|
|
* @userdata1 stage
|
|
* @userdata2 0
|
|
* @devdesc Marshaling error detected
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_MARSHALCMDDATA,
|
|
RC_TPM_MARSHALING_FAIL,
|
|
stage,
|
|
0 );
|
|
|
|
}
|
|
|
|
TRACUBIN(g_trac_trustedboot, "Marshal Out",
|
|
o_outbuf, *o_cmdSize);
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"TPM MARSHAL END : CmdSize: %d : %016llx ",
|
|
(int)(*o_cmdSize),
|
|
*((uint64_t*)o_outbuf) );
|
|
|
|
TRACDCOMP( g_trac_trustedboot,
|
|
"<<tpmMarshalCommandData()" );
|
|
|
|
return err;
|
|
}
|
|
|
|
errlHndl_t tpmUnmarshalResponseData(uint32_t i_commandCode,
|
|
uint8_t* i_respBuf,
|
|
size_t i_respBufSize,
|
|
TPM2_BaseOut* o_outBuf,
|
|
size_t i_outBufSize)
|
|
{
|
|
errlHndl_t err = TB_SUCCESS;
|
|
const uint8_t* sBuf = i_respBuf;
|
|
int stage = 0;
|
|
|
|
TRACDCOMP( g_trac_trustedboot,
|
|
">>tpmUnmarshalResponseData()" );
|
|
|
|
do {
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"TPM UNMARSHAL START : RespBufLen %d : OutBufLen %d",
|
|
(int)i_respBufSize, (int)i_outBufSize);
|
|
TRACUBIN(g_trac_trustedboot,"Unmarshal In",
|
|
i_respBuf, i_respBufSize);
|
|
|
|
|
|
// Start with the response header
|
|
stage = 1;
|
|
sBuf = TPM2_BaseOut_unmarshal(o_outBuf, sBuf,
|
|
&i_respBufSize, i_outBufSize);
|
|
if (NULL == sBuf)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// If the TPM returned a failure it will not send the rest
|
|
// Let the caller deal with the RC
|
|
if (TPM_SUCCESS != o_outBuf->responseCode)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
// Unmarshal the parameters
|
|
stage = 2;
|
|
switch (i_commandCode)
|
|
{
|
|
// Empty response commands
|
|
case TPM_CC_Startup:
|
|
case TPM_CC_PCR_Extend:
|
|
// Nothing to do
|
|
break;
|
|
|
|
case TPM_CC_GetCapability:
|
|
{
|
|
TPM2_GetCapabilityOut* respPtr =
|
|
(TPM2_GetCapabilityOut*)o_outBuf;
|
|
sBuf = TPM2_GetCapabilityOut_unmarshal(respPtr, sBuf,
|
|
&i_respBufSize,
|
|
i_outBufSize);
|
|
|
|
}
|
|
break;
|
|
|
|
case TPM_CC_PCR_Read:
|
|
{
|
|
TPM2_PcrReadOut* respPtr = (TPM2_PcrReadOut*)o_outBuf;
|
|
sBuf = TPM2_PcrReadOut_unmarshal(respPtr, sBuf,
|
|
&i_respBufSize,
|
|
i_outBufSize);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
// Command code not supported
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM UNMARSHAL INVALID COMMAND : %X",
|
|
i_commandCode );
|
|
sBuf = NULL;
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_UNMARSHAL_INVALID_CMD
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_UNMARSHALRESPDATA
|
|
* @userdata1 commandcode
|
|
* @userdata2 stage
|
|
* @devdesc Unsupported command code during unmarshal
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_UNMARSHALRESPDATA,
|
|
RC_TPM_UNMARSHAL_INVALID_CMD,
|
|
i_commandCode,
|
|
stage);
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
} while ( 0 );
|
|
|
|
if (NULL == sBuf && TB_SUCCESS == err)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM UNMARSHAL FAILURE : Stage %d", stage);
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_UNMARSHALING_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_UNMARSHALRESPDATA
|
|
* @userdata1 Stage
|
|
* @userdata2 Remaining response buffer size
|
|
* @devdesc Unmarshaling error detected
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_UNMARSHALRESPDATA,
|
|
RC_TPM_UNMARSHALING_FAIL,
|
|
stage,
|
|
i_respBufSize);
|
|
|
|
|
|
|
|
}
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"TPM UNMARSHAL END : %016llx ",
|
|
*((uint64_t*)o_outBuf) );
|
|
|
|
TRACDCOMP( g_trac_trustedboot,
|
|
"<<tpmUnmarshalResponseData()" );
|
|
|
|
return err;
|
|
}
|
|
|
|
errlHndl_t tpmCmdStartup(TpmTarget* io_target)
|
|
{
|
|
errlHndl_t err = TB_SUCCESS;
|
|
uint8_t dataBuf[BUFSIZE];
|
|
|
|
TPM2_BaseOut* resp =
|
|
(TPM2_BaseOut*)(dataBuf);
|
|
|
|
TPM2_2ByteIn* cmd =
|
|
(TPM2_2ByteIn*)(dataBuf);
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
">>tpmCmdStartup()" );
|
|
|
|
do
|
|
{
|
|
// Send the TPM startup command
|
|
// Build our command block for a startup
|
|
memset(dataBuf, 0, sizeof(dataBuf));
|
|
|
|
|
|
cmd->base.tag = TPM_ST_NO_SESSIONS;
|
|
cmd->base.commandCode = TPM_CC_Startup;
|
|
cmd->param = TPM_SU_CLEAR;
|
|
|
|
err = tpmTransmitCommand(io_target,
|
|
dataBuf,
|
|
sizeof(dataBuf));
|
|
|
|
if (TB_SUCCESS != err)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM STARTUP transmit Fail");
|
|
break;
|
|
|
|
}
|
|
else if (TPM_SUCCESS != resp->responseCode)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM STARTUP OP Fail %X : ",
|
|
resp->responseCode);
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_START_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_STARTUP
|
|
* @userdata1 responseCode
|
|
* @userdata2 0
|
|
* @devdesc Invalid operation type.
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_STARTUP,
|
|
RC_TPM_START_FAIL,
|
|
resp->responseCode,
|
|
0);
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
} while ( 0 );
|
|
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"<<tpmCmdStartup() - %s",
|
|
((TB_SUCCESS == err) ? "No Error" : "With Error") );
|
|
return err;
|
|
}
|
|
|
|
errlHndl_t tpmCmdGetCapFwVersion(TpmTarget* io_target)
|
|
{
|
|
errlHndl_t err = TB_SUCCESS;
|
|
uint8_t dataBuf[BUFSIZE];
|
|
size_t dataSize = BUFSIZE;
|
|
uint16_t fwVersion[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
|
TPM2_GetCapabilityOut* resp =
|
|
(TPM2_GetCapabilityOut*)dataBuf;
|
|
TPM2_GetCapabilityIn* cmd =
|
|
(TPM2_GetCapabilityIn*)dataBuf;
|
|
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
">>tpmCmdGetCapFwVersion()" );
|
|
|
|
do
|
|
{
|
|
|
|
// Build our command block for a get capability of the FW version
|
|
memset(dataBuf, 0, dataSize);
|
|
|
|
cmd->base.tag = TPM_ST_NO_SESSIONS;
|
|
cmd->base.commandCode = TPM_CC_GetCapability;
|
|
cmd->capability = TPM_CAP_TPM_PROPERTIES;
|
|
cmd->property = TPM_PT_FIRMWARE_VERSION_1;
|
|
cmd->propertyCount = 1;
|
|
|
|
err = tpmTransmitCommand(io_target,
|
|
dataBuf,
|
|
sizeof(dataBuf));
|
|
|
|
if (TB_SUCCESS != err)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM GETCAP Transmit Fail");
|
|
break;
|
|
|
|
}
|
|
|
|
if (TPM_SUCCESS != resp->base.responseCode)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM GETCAP OP Fail %X Size(%d) ",
|
|
resp->base.responseCode,
|
|
(int)dataSize);
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_GETCAP_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_GETCAPFWVERSION
|
|
* @userdata1 responseCode
|
|
* @userdata2 0
|
|
* @devdesc Command failure reading TPM FW version.
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_GETCAPFWVERSION,
|
|
RC_TPM_GETCAP_FAIL,
|
|
resp->base.responseCode,
|
|
0);
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Walk the reponse data to pull the high order bytes out
|
|
|
|
if (resp->capData.capability != TPM_CAP_TPM_PROPERTIES ||
|
|
resp->capData.data.tpmProperties.count != 1 ||
|
|
resp->capData.data.tpmProperties.tpmProperty[0].property !=
|
|
TPM_PT_FIRMWARE_VERSION_1) {
|
|
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM GETCAP FW INVALID DATA "
|
|
"Cap(%X) Cnt(%X) Prop(%X)",
|
|
resp->capData.capability,
|
|
resp->capData.data.tpmProperties.count,
|
|
resp->capData.data.tpmProperties.
|
|
tpmProperty[0].property);
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_GETCAP_FW_INVALID_RESP
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_GETCAPFWVERSION
|
|
* @userdata1 capability
|
|
* @userdata2 property
|
|
* @devdesc Command failure reading TPM FW version.
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_GETCAPFWVERSION,
|
|
RC_TPM_GETCAP_FW_INVALID_RESP,
|
|
resp->capData.capability,
|
|
resp->capData.data.tpmProperties.
|
|
tpmProperty[0].property);
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
fwVersion[0] =
|
|
(resp->capData.data.
|
|
tpmProperties.tpmProperty[0].value >> 16);
|
|
fwVersion[1] =
|
|
(resp->capData.data.
|
|
tpmProperties.tpmProperty[0].value & 0xFFFF);
|
|
}
|
|
|
|
}
|
|
|
|
// Read part 2 of the version
|
|
dataSize = BUFSIZE;
|
|
memset(dataBuf, 0, dataSize);
|
|
|
|
cmd->base.tag = TPM_ST_NO_SESSIONS;
|
|
cmd->base.commandCode = TPM_CC_GetCapability;
|
|
cmd->capability = TPM_CAP_TPM_PROPERTIES;
|
|
cmd->property = TPM_PT_FIRMWARE_VERSION_2;
|
|
cmd->propertyCount = 1;
|
|
|
|
|
|
err = tpmTransmitCommand(io_target,
|
|
dataBuf,
|
|
sizeof(dataBuf));
|
|
|
|
if (TB_SUCCESS != err)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM GETCAP2 Transmit Fail");
|
|
break;
|
|
|
|
}
|
|
|
|
if ((sizeof(TPM2_GetCapabilityOut) > dataSize) ||
|
|
(TPM_SUCCESS != resp->base.responseCode))
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM GETCAP2 OP Fail %X Size(%d) ",
|
|
resp->base.responseCode,
|
|
(int)dataSize);
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_GETCAP2_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_GETCAPFWVERSION
|
|
* @userdata1 responseCode
|
|
* @userdata2 0
|
|
* @devdesc Command failure reading TPM FW version.
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_GETCAPFWVERSION,
|
|
RC_TPM_GETCAP2_FAIL,
|
|
resp->base.responseCode,
|
|
0);
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Walk the reponse data to pull the high order bytes out
|
|
|
|
if (resp->capData.capability != TPM_CAP_TPM_PROPERTIES ||
|
|
resp->capData.data.tpmProperties.count != 1 ||
|
|
resp->capData.data.tpmProperties.tpmProperty[0].property !=
|
|
TPM_PT_FIRMWARE_VERSION_2) {
|
|
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM GETCAP2 FW INVALID DATA "
|
|
"Cap(%X) Cnt(%X) Prop(%X)",
|
|
resp->capData.capability,
|
|
resp->capData.data.tpmProperties.count,
|
|
resp->capData.data.tpmProperties.
|
|
tpmProperty[0].property);
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_GETCAP2_FW_INVALID_RESP
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_GETCAPFWVERSION
|
|
* @userdata1 capability
|
|
* @userdata2 property
|
|
* @devdesc Command failure reading TPM FW version.
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_GETCAPFWVERSION,
|
|
RC_TPM_GETCAP2_FW_INVALID_RESP,
|
|
resp->capData.capability,
|
|
resp->capData.data.tpmProperties.
|
|
tpmProperty[0].property);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
fwVersion[2] =
|
|
(resp->capData.data.tpmProperties.
|
|
tpmProperty[0].value >> 16);
|
|
fwVersion[3] =
|
|
(resp->capData.data.tpmProperties.
|
|
tpmProperty[0].value & 0xFFFF);
|
|
}
|
|
// Trace the response
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM GETCAP FW Level %d.%d.%d.%d",
|
|
fwVersion[0],fwVersion[1],fwVersion[2],fwVersion[3]
|
|
);
|
|
}
|
|
|
|
|
|
} while ( 0 );
|
|
|
|
|
|
TRACDCOMP( g_trac_trustedboot,
|
|
"<<tpmCmdGetCapFwVersion() - %s",
|
|
((TB_SUCCESS == err) ? "No Error" : "With Error") );
|
|
return err;
|
|
}
|
|
|
|
|
|
errlHndl_t tpmCmdPcrExtend(TpmTarget * io_target,
|
|
TPM_Pcr i_pcr,
|
|
TPM_Alg_Id i_algId,
|
|
const uint8_t* i_digest,
|
|
size_t i_digestSize)
|
|
{
|
|
return tpmCmdPcrExtend2Hash(io_target, i_pcr,
|
|
i_algId, i_digest, i_digestSize,
|
|
TPM_ALG_INVALID_ID, NULL, 0);
|
|
}
|
|
|
|
errlHndl_t tpmCmdPcrExtend2Hash(TpmTarget * io_target,
|
|
TPM_Pcr i_pcr,
|
|
TPM_Alg_Id i_algId_1,
|
|
const uint8_t* i_digest_1,
|
|
size_t i_digestSize_1,
|
|
TPM_Alg_Id i_algId_2,
|
|
const uint8_t* i_digest_2,
|
|
size_t i_digestSize_2)
|
|
{
|
|
errlHndl_t err = 0;
|
|
uint8_t dataBuf[sizeof(TPM2_ExtendIn)];
|
|
size_t dataSize = sizeof(dataBuf);
|
|
size_t fullDigestSize_1 = 0;
|
|
size_t fullDigestSize_2 = 0;
|
|
TPM2_BaseOut* resp = (TPM2_BaseOut*)dataBuf;
|
|
TPM2_ExtendIn* cmd = (TPM2_ExtendIn*)dataBuf;
|
|
|
|
|
|
TRACDCOMP( g_trac_trustedboot,
|
|
">>tpmCmdPcrExtend2Hash()" );
|
|
if (NULL == i_digest_2)
|
|
{
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
">>tpmCmdPcrExtend2Hash() Pcr(%d) Alg(%X) DS(%d)",
|
|
i_pcr, i_algId_1, (int)i_digestSize_1);
|
|
}
|
|
else
|
|
{
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
">>tpmCmdPcrExtend2Hash() Pcr(%d) Alg(%X:%X) DS(%d:%d)",
|
|
i_pcr, i_algId_1, i_algId_2,
|
|
(int)i_digestSize_1, (int)i_digestSize_2);
|
|
}
|
|
|
|
do
|
|
{
|
|
|
|
fullDigestSize_1 = getDigestSize(i_algId_1);
|
|
if (NULL != i_digest_2)
|
|
{
|
|
fullDigestSize_2 = getDigestSize(i_algId_2);
|
|
}
|
|
|
|
// Build our command block
|
|
memset(dataBuf, 0, sizeof(dataBuf));
|
|
|
|
// Argument verification
|
|
if (fullDigestSize_1 == 0 ||
|
|
NULL == i_digest_1 ||
|
|
IMPLEMENTATION_PCR < i_pcr ||
|
|
(NULL != i_digest_2 && fullDigestSize_2 == 0)
|
|
)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM PCR EXTEND ARG FAILURE FDS(%d:%d) DS(%d:%d) "
|
|
"PCR(%d)",
|
|
(int)fullDigestSize_1, (int)fullDigestSize_2,
|
|
(int)i_digestSize_1, (int)i_digestSize_2, i_pcr);
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_INVALID_ARGS
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_PCREXTEND
|
|
* @userdata1 Digest Ptr
|
|
* @userdata2[0:15] Full Digest Size 1
|
|
* @userdata2[16:31] Full Digest Size 2
|
|
* @userdata2[32:63] PCR
|
|
* @devdesc Unmarshaling error detected
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_PCREXTEND,
|
|
RC_TPM_INVALID_ARGS,
|
|
(uint64_t)i_digest_1,
|
|
(fullDigestSize_1 << 48) |
|
|
(fullDigestSize_2 << 32) |
|
|
i_pcr);
|
|
break;
|
|
}
|
|
|
|
// Log the input PCR value
|
|
TRACUBIN(g_trac_trustedboot, "PCR In",
|
|
i_digest_1, fullDigestSize_1);
|
|
|
|
cmd->base.tag = TPM_ST_SESSIONS;
|
|
cmd->base.commandCode = TPM_CC_PCR_Extend;
|
|
cmd->pcrHandle = i_pcr;
|
|
cmd->digests.count = 1;
|
|
cmd->digests.digests[0].algorithmId = i_algId_1;
|
|
memcpy(&(cmd->digests.digests[0].digest), i_digest_1,
|
|
(i_digestSize_1 < fullDigestSize_1 ?
|
|
i_digestSize_1 : fullDigestSize_1) );
|
|
if (NULL != i_digest_2)
|
|
{
|
|
cmd->digests.count = 2;
|
|
cmd->digests.digests[1].algorithmId = i_algId_2;
|
|
memcpy(&(cmd->digests.digests[1].digest), i_digest_2,
|
|
(i_digestSize_2 < fullDigestSize_2 ?
|
|
i_digestSize_2 : fullDigestSize_2));
|
|
}
|
|
|
|
err = tpmTransmitCommand(io_target,
|
|
dataBuf,
|
|
sizeof(dataBuf));
|
|
|
|
if (TB_SUCCESS != err)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM PCRExtend Transmit Fail");
|
|
break;
|
|
|
|
}
|
|
else if ((sizeof(TPM2_BaseOut) > dataSize)
|
|
|| (TPM_SUCCESS != resp->responseCode))
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM PCRExtend OP Fail Ret(%X) ExSize(%d) Size(%d) ",
|
|
resp->responseCode,
|
|
(int)sizeof(TPM2_BaseOut),
|
|
(int)dataSize);
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_COMMAND_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_PCREXTEND
|
|
* @userdata1 responseCode
|
|
* @userdata2 dataSize
|
|
* @devdesc Command failure reading TPM FW version.
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_PCREXTEND,
|
|
RC_TPM_COMMAND_FAIL,
|
|
resp->responseCode,
|
|
dataSize);
|
|
break;
|
|
|
|
}
|
|
|
|
} while ( 0 );
|
|
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"<<tpmCmdPcrExtend() - %s",
|
|
((TB_SUCCESS == err) ? "No Error" : "With Error") );
|
|
return err;
|
|
|
|
}
|
|
|
|
errlHndl_t tpmCmdPcrRead(TpmTarget* io_target,
|
|
TPM_Pcr i_pcr,
|
|
TPM_Alg_Id i_algId,
|
|
uint8_t* o_digest,
|
|
size_t i_digestSize)
|
|
{
|
|
errlHndl_t err = 0;
|
|
uint8_t dataBuf[sizeof(TPM2_PcrReadOut)];
|
|
size_t dataSize = sizeof(dataBuf);
|
|
size_t fullDigestSize = 0;
|
|
TPM2_PcrReadOut* resp = (TPM2_PcrReadOut*)dataBuf;
|
|
TPM2_PcrReadIn* cmd = (TPM2_PcrReadIn*)dataBuf;
|
|
|
|
|
|
TRACDCOMP( g_trac_trustedboot,
|
|
">>tpmCmdPcrRead()" );
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
">>tpmCmdPcrRead() Pcr(%d) DS(%d)",
|
|
i_pcr, (int)i_digestSize);
|
|
|
|
do
|
|
{
|
|
|
|
fullDigestSize = getDigestSize(i_algId);
|
|
|
|
// Build our command block
|
|
memset(dataBuf, 0, sizeof(dataBuf));
|
|
|
|
// Argument verification
|
|
if (fullDigestSize > i_digestSize ||
|
|
NULL == o_digest ||
|
|
IMPLEMENTATION_PCR < i_pcr
|
|
)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM PCR READ ARG FAILURE FDS(%d) DS(%d) PCR(%d)",
|
|
(int)fullDigestSize, (int)i_digestSize, i_pcr);
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_INVALID_ARGS
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_PCRREAD
|
|
* @userdata1 Digest Ptr
|
|
* @userdata2[0:31] Full Digest Size
|
|
* @userdata2[32:63] PCR
|
|
* @devdesc Unmarshaling error detected
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_PCRREAD,
|
|
RC_TPM_INVALID_ARGS,
|
|
(uint64_t)o_digest,
|
|
(fullDigestSize << 32) |
|
|
i_pcr);
|
|
|
|
break;
|
|
}
|
|
|
|
cmd->base.tag = TPM_ST_NO_SESSIONS;
|
|
cmd->base.commandCode = TPM_CC_PCR_Read;
|
|
cmd->pcrSelectionIn.count = 1; // One algorithm
|
|
cmd->pcrSelectionIn.pcrSelections[0].algorithmId = i_algId;
|
|
cmd->pcrSelectionIn.pcrSelections[0].sizeOfSelect = PCR_SELECT_MAX;
|
|
memset(cmd->pcrSelectionIn.pcrSelections[0].pcrSelect, 0,
|
|
sizeof(cmd->pcrSelectionIn.pcrSelections[0].pcrSelect));
|
|
cmd->pcrSelectionIn.pcrSelections[0].pcrSelect[i_pcr / 8] =
|
|
0x01 << (i_pcr % 8);
|
|
|
|
err = tpmTransmitCommand(io_target,
|
|
dataBuf,
|
|
sizeof(dataBuf));
|
|
|
|
if (TB_SUCCESS != err)
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM PCRRead Transmit Fail ");
|
|
break;
|
|
|
|
}
|
|
else if ((sizeof(TPM2_BaseOut) > dataSize) ||
|
|
(TPM_SUCCESS != resp->base.responseCode) ||
|
|
(resp->pcrValues.count != 1) ||
|
|
(resp->pcrValues.digests[0].size != fullDigestSize))
|
|
{
|
|
TRACFCOMP( g_trac_trustedboot,
|
|
"TPM PCRRead OP Fail Ret(%X) ExSize(%d) "
|
|
"Size(%d) Cnt(%d) DSize(%d)",
|
|
resp->base.responseCode,
|
|
(int)sizeof(TPM2_BaseOut),
|
|
(int)dataSize,
|
|
resp->pcrValues.count,
|
|
resp->pcrValues.digests[0].size);
|
|
|
|
/*@
|
|
* @errortype
|
|
* @reasoncode RC_TPM_COMMAND_FAIL
|
|
* @severity ERRL_SEV_UNRECOVERABLE
|
|
* @moduleid MOD_TPM_CMD_PCRREAD
|
|
* @userdata1 responseCode
|
|
* @userdata2 dataSize
|
|
* @devdesc Command failure reading TPM FW version.
|
|
*/
|
|
err = tpmCreateErrorLog(MOD_TPM_CMD_PCRREAD,
|
|
RC_TPM_COMMAND_FAIL,
|
|
resp->base.responseCode,
|
|
dataSize);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
|
|
memcpy(o_digest, resp->pcrValues.digests[0].buffer, fullDigestSize);
|
|
|
|
// Log the PCR value
|
|
TRACUBIN(g_trac_trustedboot, "PCR Out",
|
|
o_digest, fullDigestSize);
|
|
|
|
}
|
|
|
|
} while ( 0 );
|
|
|
|
|
|
TRACUCOMP( g_trac_trustedboot,
|
|
"<<tpmCmdPcrRead() - %s",
|
|
((TB_SUCCESS == err) ? "No Error" : "With Error") );
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
#ifdef __cplusplus
|
|
} // end TRUSTEDBOOT
|
|
#endif
|