From 98bee5bbab00b1fcb8c6b6255ac07e62e2800b60 Mon Sep 17 00:00:00 2001 From: Jaymes Wilks Date: Tue, 24 Apr 2018 10:01:59 -0500 Subject: New API to Retrieve Random Number from the TPM A new programming interface allows us to obtain random numbers from the TPM more easily (i.e. in a more high-level way). Change-Id: Ibd3d3b320411bea146d6eab4d1a59ca760bc726c RTC:191000 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/57802 Reviewed-by: ILYA SMIRNOV Tested-by: Jenkins Server Reviewed-by: Michael Baiocchi Tested-by: Jenkins OP Build CI Tested-by: FSP CI Jenkins Reviewed-by: Nicholas E. Bofferding Tested-by: Jenkins OP HW Reviewed-by: Daniel M. Crowell --- src/usr/secureboot/trusted/base/trustedbootMsg.H | 9 +- src/usr/secureboot/trusted/base/trustedboot_base.C | 73 +++++++++++ src/usr/secureboot/trusted/test/trustedbootTest.H | 50 +++++++- src/usr/secureboot/trusted/trustedTypes.H | 19 ++- src/usr/secureboot/trusted/trustedboot.C | 137 ++++++++++++++++++++- src/usr/secureboot/trusted/trustedbootCmds.C | 18 ++- 6 files changed, 297 insertions(+), 9 deletions(-) (limited to 'src/usr') diff --git a/src/usr/secureboot/trusted/base/trustedbootMsg.H b/src/usr/secureboot/trusted/base/trustedbootMsg.H index 45821f9f4..260fe094a 100644 --- a/src/usr/secureboot/trusted/base/trustedbootMsg.H +++ b/src/usr/secureboot/trusted/base/trustedbootMsg.H @@ -55,7 +55,8 @@ namespace TRUSTEDBOOT MSG_TYPE_SEPARATOR, MSG_TYPE_SHUTDOWN, MSG_TYPE_INIT_BACKUP_TPM, - MSG_TYPE_LAST = MSG_TYPE_INIT_BACKUP_TPM + MSG_TYPE_GETRANDOM, + MSG_TYPE_LAST = MSG_TYPE_GETRANDOM, }; /// PCREXTEND message data @@ -69,6 +70,12 @@ namespace TRUSTEDBOOT char mLogMsg[MAX_TPM_LOG_MSG]; }; + struct GetRandomMsgData + { + TARGETING::Target* i_pTpm; // the TPM to obtain random data from + uint64_t o_randNum; // the random data is populated here + }; + // Trustedboot message class class Message { diff --git a/src/usr/secureboot/trusted/base/trustedboot_base.C b/src/usr/secureboot/trusted/base/trustedboot_base.C index c4929faef..9aba765f5 100644 --- a/src/usr/secureboot/trusted/base/trustedboot_base.C +++ b/src/usr/secureboot/trusted/base/trustedboot_base.C @@ -794,4 +794,77 @@ errlHndl_t testCmpPrimaryAndBackupTpm() return l_err; } +#ifdef CONFIG_TPMDD +errlHndl_t GetRandom(const TpmTarget* i_pTpm, uint64_t& o_randNum) +{ + errlHndl_t err = nullptr; + Message* msg = nullptr; + + do { + + auto pData = new struct GetRandomMsgData; + memset(pData, 0, sizeof(*pData)); + + pData->i_pTpm = const_cast(i_pTpm); + + msg = Message::factory(MSG_TYPE_GETRANDOM, sizeof(*pData), + reinterpret_cast(pData), MSG_MODE_SYNC); + + assert(msg != nullptr, "BUG! Message is null"); + pData = nullptr; // Message owns msgData now + + int rc = msg_sendrecv(systemData.msgQ, msg->iv_msg); + if (0 == rc) + { + err = msg->iv_errl; + msg->iv_errl = nullptr; // taking over ownership of error log + if (err != nullptr) + { + break; + } + } + else // sendrecv failure + { + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_TPM_GETRANDOM + * @reasoncode RC_SENDRECV_FAIL + * @userdata1 rc from msq_sendrecv() + * @userdata2 TPM HUID if it's not nullptr + * @devdesc msg_sendrecv() failed + * @custdesc Trusted boot failure + */ + err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + MOD_TPM_GETRANDOM, + RC_SENDRECV_FAIL, + rc, + TARGETING::get_huid(i_pTpm), + true); + break; + } + + pData = reinterpret_cast(msg->iv_data); + assert(pData != nullptr, + "BUG! Completed send/recv to random num generator has null data ptr!"); + + o_randNum = pData->o_randNum; + + } while (0); + + if (msg != nullptr) + { + delete msg; // also deletes the msg->iv_data + msg = nullptr; + } + + if (err) + { + err->collectTrace(SECURE_COMP_NAME); + err->collectTrace(TRBOOT_COMP_NAME); + } + + return err; +} +#endif // CONFIG_TPMDD + } // end TRUSTEDBOOT diff --git a/src/usr/secureboot/trusted/test/trustedbootTest.H b/src/usr/secureboot/trusted/test/trustedbootTest.H index 0a8e181ca..0d293f41a 100755 --- a/src/usr/secureboot/trusted/test/trustedbootTest.H +++ b/src/usr/secureboot/trusted/test/trustedbootTest.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -45,6 +45,7 @@ #include "../trustedboot.H" #include "../trustedbootCmds.H" #include "../tpmLogMgr.H" +#include using namespace TRUSTEDBOOT; @@ -885,6 +886,53 @@ class TrustedBootTest: public CxxTest::TestSuite EXIT_MRK "testReadPCR: %d/%d fails", fails, num_ops ); } + + /** + * @brief TPM GetRandom + */ + void testGetRandom ( void ) + { + TRACFCOMP( g_trac_trustedboot, + ENTER_MRK "testGetRandom" ); + + errlHndl_t err = nullptr; + size_t fails = 0; + size_t num_ops = 0; + + // Just for fun generate random numbers for each of the TPMs + TARGETING::TargetHandleList tpmList; + TRUSTEDBOOT::getTPMs(tpmList, TRUSTEDBOOT::TPM_FILTER::ALL_FUNCTIONAL); + for (auto pTpm: tpmList) + { + uint64_t randNum = 0; + err = TRUSTEDBOOT::GetRandom(pTpm, randNum); + num_ops ++; + if(err) + { + fails++; + TS_FAIL( "testGetRandom: Error detected" ); + errlCommit( err, + TRBOOT_COMP_ID ); + delete err; + err = nullptr; + } + else if (randNum == 0) // if random number is zero still + { + fails++; + TS_FAIL( "testGetRandom: got zero for a random number"); + } + else + { + + TRACUCOMP(g_trac_trustedboot, "testGetRandom: GetRandom returned as expected. Random number 0x%.16llX",randNum); + } + + } + + TRACFCOMP( g_trac_trustedboot, + EXIT_MRK "testGetRandom: %d/%d fails", + fails, num_ops ); + } }; #endif diff --git a/src/usr/secureboot/trusted/trustedTypes.H b/src/usr/secureboot/trusted/trustedTypes.H index 0798295c5..34fc0fff5 100644 --- a/src/usr/secureboot/trusted/trustedTypes.H +++ b/src/usr/secureboot/trusted/trustedTypes.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -105,6 +105,7 @@ namespace TRUSTEDBOOT // Command Codes TPM_CC_Startup = 0x00000144, TPM_CC_GetCapability = 0x0000017A, + TPM_CC_GetRandom = 0x0000017B, TPM_CC_PCR_Read = 0x0000017E, TPM_CC_PCR_Extend = 0x00000182, @@ -453,6 +454,22 @@ namespace TRUSTEDBOOT size_t* io_tpmBufSize, size_t i_outBufSize); + /// Incoming GetRandom structure + struct _TPM2_GetRandomIn + { + TPM2_BaseIn base; + uint16_t bytesRequested; + } PACKED; + typedef struct _TPM2_GetRandomIn TPM2_GetRandomIn; + + /// Outgoing GetRandom structure + struct _TPM2_GetRandomOut + { + TPM2_BaseOut base; + TPM2B_DIGEST randomBytes; + } PACKED; + typedef struct _TPM2_GetRandomOut TPM2_GetRandomOut; + /// TPM Authorization structure /// This is not the full structure and only works for PW auth with NULL PW struct _TPMS_AUTH_COMMAND diff --git a/src/usr/secureboot/trusted/trustedboot.C b/src/usr/secureboot/trusted/trustedboot.C index 00935f68a..de4222e41 100644 --- a/src/usr/secureboot/trusted/trustedboot.C +++ b/src/usr/secureboot/trusted/trustedboot.C @@ -1471,11 +1471,79 @@ void* tpmDaemon(void* unused) NoTpmShutdownPolicy::BACKGROUND_SHUTDOWN); } break; - case TRUSTEDBOOT::MSG_TYPE_INIT_BACKUP_TPM: - { - doInitBackupTpm(); - } - break; + case TRUSTEDBOOT::MSG_TYPE_INIT_BACKUP_TPM: + { + doInitBackupTpm(); + } + break; + case TRUSTEDBOOT::MSG_TYPE_GETRANDOM: + { + errlHndl_t err = nullptr; + tb_msg = static_cast(msg->extra_data); + assert(tb_msg != nullptr, + "Trusted boot message pointer absent in the extra data"); + tb_msg->iv_errl = nullptr; + + auto msgData = + reinterpret_cast + (tb_msg->iv_data); + assert(msgData != nullptr, + "Trusted boot message data pointer is null"); + auto l_pTpm = msgData->i_pTpm; + + err = validateTpmHandle(l_pTpm); + if (err) + { + tb_msg->iv_errl = err; + err = nullptr; + break; + } + uint8_t dataBuf[sizeof(TPM2_GetRandomOut)] = {0}; + size_t dataSize = sizeof(dataBuf); + auto cmd = reinterpret_cast(dataBuf); + auto resp = reinterpret_cast(dataBuf); + uint64_t randNum = 0; + + cmd->base.tag = TPM_ST_NO_SESSIONS; + cmd->base.commandCode = TPM_CC_GetRandom; + cmd->bytesRequested = sizeof(randNum); + + err = tpmTransmitCommand(l_pTpm, dataBuf, dataSize, + TPM_LOCALITY_0); + + if (err != nullptr) + { + TRACFCOMP( g_trac_trustedboot, + ERR_MRK"TPM GetRandom Transmit Fail! huid = 0x%08X", + TARGETING::get_huid(l_pTpm)); + auto l_errPlid = err->plid(); + tpmMarkFailed(l_pTpm, err); + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_TPM_TPMDAEMON + * @reasoncode RC_UNREACHABLE_TPM + * @userdata1 TPM HUID or nullptr + * @devdesc Unable to reach the TPM + * @custdesc Trusted boot failure + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + MOD_TPM_TPMDAEMON, + RC_UNREACHABLE_TPM, + TARGETING::get_huid(l_pTpm), + 0, + true); + err->plid(l_errPlid); + tb_msg->iv_errl = err; + err = nullptr; + } + else + { + memcpy(&randNum, resp->randomBytes.buffer,sizeof(randNum)); + msgData->o_randNum = randNum; + } + } + break; default: assert(false, "Invalid msg command"); break; @@ -1529,6 +1597,65 @@ void* tpmDaemon(void* unused) return nullptr; } +errlHndl_t validateTpmHandle(const TpmTarget* i_pTpm) +{ + errlHndl_t err = nullptr; + + do { + + if (i_pTpm == nullptr || + i_pTpm->getAttr() != TARGETING::TYPE_TPM) + { + TRACFCOMP(g_trac_trustedboot, + ERR_MRK"Invalid TPM handle passed to GetRandom() huid = 0x%08X", + TARGETING::get_huid(i_pTpm)); + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_VALIDATE_TPM_HANDLE + * @reasoncode RC_INVALID_TPM_HANDLE + * @userdata1 TPM HUID if it's not nullptr + * @devdesc Caller attempted to get a random number from a TPM + * using an invalid TPM target. + * @custdesc Trusted boot failure + */ + err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + MOD_VALIDATE_TPM_HANDLE, + RC_INVALID_TPM_HANDLE, + TARGETING::get_huid(i_pTpm), + 0, + true); + + break; + } + + auto l_tpmHwasState = i_pTpm->getAttr(); + if (!l_tpmHwasState.functional) + { + TRACFCOMP(g_trac_trustedboot, + ERR_MRK"Non functional TPM handle passed to GetRandom() huid = 0x%08X", + TARGETING::get_huid(i_pTpm)); + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_VALIDATE_TPM_HANDLE + * @reasoncode RC_NON_FUNCTIONAL_TPM_HANDLE + * @userdata1 TPM HUID if it's not nullptr + * @devdesc Call attempted to get a random number from a TPM + * that was not functional + * @custdesc Trusted boot failure + */ + err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + MOD_VALIDATE_TPM_HANDLE, + RC_NON_FUNCTIONAL_TPM_HANDLE, + TARGETING::get_huid(i_pTpm), + 0, + true); + break; + } + + } while(0); + return err; +} + bool isTpmRequired() { bool retVal = false; diff --git a/src/usr/secureboot/trusted/trustedbootCmds.C b/src/usr/secureboot/trusted/trustedbootCmds.C index 709675c2d..9a73a7052 100644 --- a/src/usr/secureboot/trusted/trustedbootCmds.C +++ b/src/usr/secureboot/trusted/trustedbootCmds.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -237,6 +237,14 @@ errlHndl_t tpmMarshalCommandData(TPM2_BaseIn* i_cmd, } break; + case TPM_CC_GetRandom: + { + auto cmdPtr = reinterpret_cast(i_cmd); + sBuf = TPM2_2ByteIn_marshal(cmdPtr, sBuf, + i_bufsize, o_cmdSize); + } + break; + default: { // Command code not supported @@ -385,6 +393,14 @@ errlHndl_t tpmUnmarshalResponseData(uint32_t i_commandCode, } break; + case TPM_CC_GetRandom: + { + auto respPtr = reinterpret_cast(o_outBuf); + sBuf = TPM2B_DIGEST_unmarshal(&respPtr->randomBytes, sBuf, + &i_respBufSize); + } + break; + default: { // Command code not supported -- cgit v1.2.1