diff options
author | Jaymes Wilks <mjwilks@us.ibm.com> | 2018-05-01 15:33:32 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2018-05-23 17:55:09 -0400 |
commit | e9eacec8bad1e2dade70ebed0fc3d00b5ab59232 (patch) | |
tree | bc1a5a5e462e4816159338930f994538adb1f9da /src/usr/secureboot/trusted | |
parent | 11b5f7d2b616da7ba3ac2cacb52bd2b762872b9c (diff) | |
download | talos-hostboot-e9eacec8bad1e2dade70ebed0fc3d00b5ab59232.tar.gz talos-hostboot-e9eacec8bad1e2dade70ebed0fc3d00b5ab59232.zip |
Support TPM PCR Poisoning
To support Fleetwood secure inter-node communication, we need to
“poison” the PCRs of all still functional non-master node TPMs
just prior to transferring control to PHyp, and report that
poisoned state to HDAT.
Change-Id: Ic104ef2e44fc98895b9b435fdf8ba4c5e4972818
RTC:191001
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/58244
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com>
Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com>
Reviewed-by: ILYA SMIRNOV <ismirno@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/secureboot/trusted')
-rw-r--r-- | src/usr/secureboot/trusted/base/trustedbootMsg.H | 14 | ||||
-rw-r--r-- | src/usr/secureboot/trusted/base/trustedboot_base.C | 87 | ||||
-rwxr-xr-x | src/usr/secureboot/trusted/test/trustedbootTest.H | 155 | ||||
-rw-r--r-- | src/usr/secureboot/trusted/trustedboot.C | 165 |
4 files changed, 325 insertions, 96 deletions
diff --git a/src/usr/secureboot/trusted/base/trustedbootMsg.H b/src/usr/secureboot/trusted/base/trustedbootMsg.H index 260fe094a..ededabdcf 100644 --- a/src/usr/secureboot/trusted/base/trustedbootMsg.H +++ b/src/usr/secureboot/trusted/base/trustedbootMsg.H @@ -62,12 +62,14 @@ namespace TRUSTEDBOOT /// PCREXTEND message data struct PcrExtendMsgData { - TPM_Pcr mPcrIndex; - TPM_Alg_Id mAlgId; - EventTypes mEventType; - size_t mDigestSize; - uint8_t mDigest[TPM_ALG_SHA256_SIZE]; - char mLogMsg[MAX_TPM_LOG_MSG]; + TPM_Pcr mPcrIndex; + TPM_Alg_Id mAlgId; + EventTypes mEventType; + size_t mDigestSize; + uint8_t mDigest[TPM_ALG_SHA256_SIZE]; + char mLogMsg[MAX_TPM_LOG_MSG]; + const TpmTarget* mSingleTpm; + bool mMirrorToLog; }; struct GetRandomMsgData diff --git a/src/usr/secureboot/trusted/base/trustedboot_base.C b/src/usr/secureboot/trusted/base/trustedboot_base.C index 9aba765f5..5050c9a99 100644 --- a/src/usr/secureboot/trusted/base/trustedboot_base.C +++ b/src/usr/secureboot/trusted/base/trustedboot_base.C @@ -200,7 +200,9 @@ errlHndl_t pcrExtend(TPM_Pcr i_pcr, const uint8_t* i_digest, size_t i_digestSize, const char* i_logMsg, - bool i_sendAsync) + bool i_sendAsync, + const TpmTarget* i_pTpm, + const bool i_mirrorToLog) { errlHndl_t err = NULL; #ifdef CONFIG_TPMDD @@ -208,7 +210,8 @@ errlHndl_t pcrExtend(TPM_Pcr i_pcr, TRACDCOMP( g_trac_trustedboot, ENTER_MRK"pcrExtend()" ); TRACUCOMP( g_trac_trustedboot, - ENTER_MRK"pcrExtend() pcr=%d msg='%s'", i_pcr, i_logMsg); + ENTER_MRK"pcrExtend() pcr=%d msg='%s'", + i_pcr, i_logMsg? i_logMsg: "(null)"); TRACUBIN(g_trac_trustedboot, "pcrExtend() digest:", i_digest, i_digestSize); // msgData will be freed when message is freed @@ -219,16 +222,21 @@ errlHndl_t pcrExtend(TPM_Pcr i_pcr, msgData->mEventType = i_eventType; msgData->mDigestSize = (i_digestSize < sizeof(msgData->mDigest) ? i_digestSize : sizeof(msgData->mDigest)); + msgData->mSingleTpm = i_pTpm; + msgData->mMirrorToLog = i_mirrorToLog; // copy over the incoming digest and truncate to what we need memcpy(msgData->mDigest, i_digest, msgData->mDigestSize); // Truncate logMsg if required - memcpy(msgData->mLogMsg, i_logMsg, + if (i_logMsg) + { + memcpy(msgData->mLogMsg, i_logMsg, (strlen(i_logMsg) < sizeof(msgData->mLogMsg) ? strlen(i_logMsg) : sizeof(msgData->mLogMsg)-1) // Leave room for NULL termination ); + } if (!i_sendAsync) { @@ -794,77 +802,4 @@ 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<TpmTarget*>(i_pTpm); - - msg = Message::factory(MSG_TYPE_GETRANDOM, sizeof(*pData), - reinterpret_cast<uint8_t*>(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<struct GetRandomMsgData*>(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 0d293f41a..1b39a7267 100755 --- a/src/usr/secureboot/trusted/test/trustedbootTest.H +++ b/src/usr/secureboot/trusted/test/trustedbootTest.H @@ -933,6 +933,161 @@ class TrustedBootTest: public CxxTest::TestSuite EXIT_MRK "testGetRandom: %d/%d fails", fails, num_ops ); } + + /** + * @brief Poison TPM test + */ + void testPoisonTpm ( void ) + { + TRACFCOMP( g_trac_trustedboot, + ENTER_MRK "testPoisonTpm" ); + + errlHndl_t err = nullptr; + size_t fails = 0; + size_t num_ops = 0; + + // used for looping thru all the PCRs + const TPM_Pcr l_pcrRegs[] = {PCR_0, PCR_1, PCR_2, PCR_3, + PCR_4, PCR_5, PCR_6, PCR_7}; + + const TPM_Alg_Id l_algIds[] = {TPM_ALG_SHA1, TPM_ALG_SHA256}; + + auto pcrReadFail = false; + // loop through all the TPMs + TARGETING::TargetHandleList tpmList; + TRUSTEDBOOT::getTPMs(tpmList, TRUSTEDBOOT::TPM_FILTER::ALL_FUNCTIONAL); + for (auto pTpm: tpmList) + { + size_t l_digestSize = 0; + + auto * const pTpmLogMgr = getTpmLogMgr(pTpm); + if (pTpmLogMgr == nullptr) + { + TS_FAIL("testPoisonTpm: log manager does not exist"); + break; + } + auto l_initialLogSize = TpmLogMgr_getLogSize(pTpmLogMgr); + + // save the PCR values for later comparison + std::vector<uint8_t*> savedPcrs; + + // loop thru all algorithms and all pcr regs and save off values + for(const auto l_algId : l_algIds) + { + l_digestSize = getDigestSize(l_algId); + + for(const auto l_pcrReg : l_pcrRegs) + { + auto l_pDigest = new uint8_t[l_digestSize](); + err = tpmCmdPcrRead(pTpm, + l_pcrReg, + l_algId, + l_pDigest, + l_digestSize); + if(err) + { + TRACFCOMP(g_trac_trustedboot, + ERR_MRK"testPoisonTpm: failed to read PCR %d" + " of Tpm with HUID = 0x%08X; algId = 0x%.04x", + l_pcrReg, + TARGETING::get_huid(pTpm), + l_algId); + errlCommit(err, TRBOOT_COMP_ID); + TS_FAIL("testPoisonTpm: can't read PCR "); + pcrReadFail = true; + delete [] l_pDigest; + l_pDigest = nullptr; + break; + } + savedPcrs.push_back(l_pDigest); + } + if (pcrReadFail) + { + break; + } + } + + if (pcrReadFail) + { + break; + } + + err = TRUSTEDBOOT::poisonTpm(pTpm); + num_ops ++; + if(err) + { + fails++; + TS_FAIL( "testPoisonTpm: Error return from poisonTpm" ); + errlCommit( err, TRBOOT_COMP_ID ); + break; + } + + auto l_postPoisonLogSize = TpmLogMgr_getLogSize(pTpmLogMgr); + + if (l_initialLogSize != l_postPoisonLogSize) + { + TS_FAIL("testPoisonTpm: Log size mismatch"); + break; + } + + auto savedPcrItr = savedPcrs.begin(); + // loop thru all algorithms/regs and compare with previous values + for(const auto l_algId : l_algIds) + { + l_digestSize = getDigestSize(l_algId); + + for(const auto l_pcrReg : l_pcrRegs) + { + auto l_pDigest = new uint8_t[l_digestSize](); + err = tpmCmdPcrRead(pTpm, + l_pcrReg, + l_algId, + l_pDigest, + l_digestSize); + if(err) + { + TRACFCOMP(g_trac_trustedboot, + "testPoisonTpm: failed to read PCR %d" + " of Tpm with HUID = 0x%08X; algId = 0x%.04x", + l_pcrReg, + TARGETING::get_huid(pTpm), + l_algId); + errlCommit(err, TRBOOT_COMP_ID); + TS_FAIL("testPoisonTpm: failed to read PCR"); + pcrReadFail = true; + delete [] l_pDigest; + l_pDigest = nullptr; + break; + } + + if (memcmp(l_pDigest,*savedPcrItr, l_digestSize) == 0) + { + fails++; + TS_FAIL("testPoisonTpm: Digest unchanged"); + } + delete [] l_pDigest; + l_pDigest = nullptr; + + ++savedPcrItr; + } + if (pcrReadFail) + { + break; + } + } + + for (const auto savedPcr : savedPcrs) + { + delete [] savedPcr; + } + + } + + TRACFCOMP( g_trac_trustedboot, + EXIT_MRK "testPoisonTpm: %d/%d fails", + fails, num_ops ); + } + }; #endif diff --git a/src/usr/secureboot/trusted/trustedboot.C b/src/usr/secureboot/trusted/trustedboot.C index f4262bcf1..d8a380ed7 100644 --- a/src/usr/secureboot/trusted/trustedboot.C +++ b/src/usr/secureboot/trusted/trustedboot.C @@ -812,20 +812,24 @@ void pcrExtendSingleTpm(TpmTarget* const i_pTpm, if (hwasState.present && hwasState.functional) { - // Fill in TCG_PCR_EVENT2 and add to log - eventLog = TpmLogMgr_genLogEventPcrExtend(pcr, i_eventType, - i_algId, i_digest, - i_digestSize, - TPM_ALG_SHA1, i_digest, - i_digestSize, - i_logMsg); - if(useStaticLog) + if (i_logMsg != nullptr) // null log indicates we don't log { - auto * const pTpmLogMgr = getTpmLogMgr(i_pTpm); - err = TpmLogMgr_addEvent(pTpmLogMgr,&eventLog); - if (nullptr != err) + // Fill in TCG_PCR_EVENT2 and add to log + eventLog = TpmLogMgr_genLogEventPcrExtend(pcr, i_eventType, + i_algId, i_digest, + i_digestSize, + TPM_ALG_SHA1, + i_digest, + i_digestSize, + i_logMsg); + if(useStaticLog) { - break; + auto * const pTpmLogMgr = getTpmLogMgr(i_pTpm); + err = TpmLogMgr_addEvent(pTpmLogMgr,&eventLog); + if (nullptr != err) + { + break; + } } } @@ -1440,7 +1444,17 @@ void* tpmDaemon(void* unused) && msgData != nullptr, "Invalid PCRExtend Message"); TARGETING::TargetHandleList tpmList; - getTPMs(tpmList); + // if null TPM was passed extend all TPMs. Otherwise, extend + // only the TPM that was passed + if (msgData->mSingleTpm == nullptr) + { + getTPMs(tpmList); + } + else + { + tpmList.push_back(const_cast<TpmTarget*>( + msgData->mSingleTpm)); + } for (auto tpm : tpmList) { // Add the event to this TPM, @@ -1453,7 +1467,8 @@ void* tpmDaemon(void* unused) msgData->mAlgId, msgData->mDigest, msgData->mDigestSize, - msgData->mLogMsg); + msgData->mMirrorToLog? msgData->mLogMsg: + nullptr); } // Lastly make sure we are in a state @@ -1819,4 +1834,126 @@ errlHndl_t tpmDrtmReset(TpmTarget* const i_pTpm) } #endif +#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<TpmTarget*>(i_pTpm); + + msg = Message::factory(MSG_TYPE_GETRANDOM, sizeof(*pData), + reinterpret_cast<uint8_t*>(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<struct GetRandomMsgData*>(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 + +errlHndl_t poisonTpm(const TpmTarget* i_pTpm) +{ + uint64_t l_randNum = 0; + errlHndl_t l_errl = nullptr; + +#ifdef CONFIG_TPMDD + + do { + + // Note: GetRandom validates the TPM handle internally and returns an + // error log if invalid + l_errl = GetRandom(i_pTpm, l_randNum); + + if (l_errl) + { + break; + } + + const TPM_Pcr l_pcrRegs[] = {PCR_0, PCR_1, PCR_2, PCR_3, + PCR_4, PCR_5, PCR_6, PCR_7}; + + // poison all PCR banks + for (const auto l_pcrReg : l_pcrRegs) + { + l_errl = pcrExtend(l_pcrReg, + TRUSTEDBOOT::EV_INVALID, + reinterpret_cast<sha2_byte*>(&l_randNum), + sizeof(l_randNum), + nullptr, // log not needed for poison operation + false, // call synchronously to daemon + i_pTpm, // only extend to pcr banks for this TPM + false); // don't add PCR measurement to the log + if (l_errl) + { + break; + } + + } + + } while (0); + + TRACFCOMP(g_trac_trustedboot, "%ssuccessfully poisoned TPM with huid 0x%X", + l_errl? "Un":"", TARGETING::get_huid(i_pTpm)); + +#endif + return l_errl; +} + + } // end TRUSTEDBOOT |