diff options
-rw-r--r-- | src/include/usr/secureboot/trustedboot_reasoncodes.H | 9 | ||||
-rw-r--r-- | src/include/usr/secureboot/trustedbootif.H | 77 | ||||
-rwxr-xr-x | src/usr/i2c/tpmdd.C | 5 | ||||
-rw-r--r-- | src/usr/secureboot/node_comm/node_comm_exchange.C | 4 | ||||
-rw-r--r-- | src/usr/secureboot/trusted/base/trustedbootMsg.H | 48 | ||||
-rw-r--r-- | src/usr/secureboot/trusted/base/trustedboot_base.C | 212 | ||||
-rwxr-xr-x | src/usr/secureboot/trusted/test/trustedbootTest.H | 4 | ||||
-rw-r--r-- | src/usr/secureboot/trusted/trustedTypes.H | 104 | ||||
-rw-r--r-- | src/usr/secureboot/trusted/trustedboot.C | 134 | ||||
-rw-r--r-- | src/usr/secureboot/trusted/trustedbootCmds.C | 357 | ||||
-rw-r--r-- | src/usr/secureboot/trusted/trustedbootCmds.H | 49 |
11 files changed, 973 insertions, 30 deletions
diff --git a/src/include/usr/secureboot/trustedboot_reasoncodes.H b/src/include/usr/secureboot/trustedboot_reasoncodes.H index 8c03fd272..60727239e 100644 --- a/src/include/usr/secureboot/trustedboot_reasoncodes.H +++ b/src/include/usr/secureboot/trustedboot_reasoncodes.H @@ -69,6 +69,14 @@ namespace TRUSTEDBOOT MOD_TEST_CMP_PRIMARY_AND_BACKUP_TPM = 0x17, MOD_TPM_GETRANDOM = 0x18, MOD_VALIDATE_TPM_HANDLE = 0x19, + MOD_TPM_CMD_CREATE_ATTEST = 0x1A, + MOD_CREATE_ATT_KEYS = 0x1B, + MOD_READ_AK_CERT = 0x1C, + MOD_TPM_CMD_READ_AK_CERT = 0x1D, + MOD_TPM_CMD_GEN_QUOTE = 0x1E, + MOD_GEN_QUOTE = 0x1F, + MOD_TPM_CMD_FLUSH_CONTEXT = 0x20, + MOD_FLUSH_CONTEXT = 0x21, }; enum TRUSTEDReasonCode @@ -104,6 +112,7 @@ namespace TRUSTEDBOOT RC_NON_FUNCTIONAL_TPM_HANDLE = TRBOOT_COMP_ID | 0xB9, RC_UNREACHABLE_TPM = TRBOOT_COMP_ID | 0xBA, RC_RAND_NUM_TOO_BIG = TRBOOT_COMP_ID | 0xBB, + RC_TPM_BAD_RESP = TRBOOT_COMP_ID | 0xBC, }; #ifdef __cplusplus } diff --git a/src/include/usr/secureboot/trustedbootif.H b/src/include/usr/secureboot/trustedbootif.H index 6038ac486..8be8e6448 100644 --- a/src/include/usr/secureboot/trustedbootif.H +++ b/src/include/usr/secureboot/trustedbootif.H @@ -50,10 +50,34 @@ namespace TRUSTEDBOOT struct _TpmLogMgr; + // Structure that contains the TPM quote data and the size thereof + struct _QuoteDataOut + { + size_t size; // the size (bytes) of the data pointer + uint8_t* data; // the actual quote data + } PACKED; + typedef struct _QuoteDataOut QuoteDataOut; + // Hostboot code just maps the TpmTarget type, which shared APIs use, as a // targeting target typedef TARGETING::Target TpmTarget; + enum + { + // The size of AK certificate from the TPM, in bytes + TPM_NV_DATA_SIZE = 0x1F4, + // The size of the master nonce, in bytes + TPM_NONCE_SIZE_BYTES = 0x20, + }; + + // The structure that defines the size of the TPM AK certificate + // (in bytes) + typedef uint8_t AKCertificate_t[TPM_NV_DATA_SIZE]; + + // The structure that defines the size of the master node nonce + // (in bytes) + typedef uint8_t MasterTpmNonce_t[TPM_NONCE_SIZE_BYTES]; + /** * @brief Enum used for the getTPMs API to specify scope of TPMs to return */ @@ -250,17 +274,17 @@ namespace TRUSTEDBOOT * be functional. All of these conditions must be met or an error * log will result. * - * @param[out] o_randNum A pointer to the array to be filled with random - * bits - * * @param[in] i_randNumSize The desired size (bytes) of the random number * to be requested from the TPM * + * @param[out] o_randNum A pointer to the array to be filled with random + * bits + * * @return errlHndl_t nullptr on success or an error log pointer on failure */ errlHndl_t GetRandom(const TpmTarget* i_pTpm, - uint8_t* o_randNum, - size_t i_randNumSize); + size_t i_randNumSize, + uint8_t* o_randNum); #endif /** @@ -355,6 +379,49 @@ namespace TRUSTEDBOOT */ errlHndl_t flushTpmQueue(); + /** + * @brief Send the command to the given TPM to create node attestation + * key pair + * + * @param[in] i_target the pointer to the TPM target to send the command to + * @return nullptr if success; non-nullptr on error + */ + errlHndl_t createAttestationKeys(TpmTarget* i_target); + + /** + * @brief Send the command to the given TPM to retrieve the AK certificate + * from its NVRAM + * + * @param[in] i_target the pointer to the TPM target to send the command to + * @param[out] o_data the buffer to store the contents of AK certificate + * @return nullptr if success; non-nullptr on error + */ + errlHndl_t readAKCertificate(TpmTarget* i_target, + AKCertificate_t* o_data); + + /** + * @brief Send the command to the given TPM to generate the quote + * + * @param[in] i_target the pointer to the TPM target to send the command to + * @param[in] i_masterNonce the 32-byte nonce from the master node + * @param[out] o_data a pointer to the data structure containing the size + * of the quote data from the TPM and the actual data + * @return nullptr if success; non-nullptr on error + */ + errlHndl_t generateQuote(TpmTarget* i_target, + MasterTpmNonce_t* i_masterNonce, + QuoteDataOut* o_data); + + /** + * @brief Send the command to the given TPM to remove all context associated + * with created objects + * + * @param[in] i_target the pointer to the TPM target to send the command to + * @return nullptr if success; non-nullptr on error + */ + errlHndl_t flushContext(TpmTarget* i_target); + + } // end TRUSTEDBOOT namespace diff --git a/src/usr/i2c/tpmdd.C b/src/usr/i2c/tpmdd.C index 0894653b3..11b14aa80 100755 --- a/src/usr/i2c/tpmdd.C +++ b/src/usr/i2c/tpmdd.C @@ -2262,8 +2262,9 @@ errlHndl_t tpmPollForDataAvail( const tpm_info_t & i_tpmInfo) tpm_sts_reg_t stsReg; errlHndl_t err = NULL; - // Operation TIMEOUT_A defined by TCG spec for data available - for (size_t delay = 0; delay < TPMDD::TPM_TIMEOUT_A; delay += 10) + // Use the longer timeout B here since some of the TPM commands may take + // more than timeout A to complete + for (size_t delay = 0; delay < TPMDD::TPM_TIMEOUT_B; delay += 10) { err = tpmReadSTSRegValid(i_tpmInfo, stsReg); diff --git a/src/usr/secureboot/node_comm/node_comm_exchange.C b/src/usr/secureboot/node_comm/node_comm_exchange.C index eb29413c6..9f7938dc6 100644 --- a/src/usr/secureboot/node_comm/node_comm_exchange.C +++ b/src/usr/secureboot/node_comm/node_comm_exchange.C @@ -173,8 +173,8 @@ errlHndl_t nodeCommAbusGetRandom(uint64_t & o_nonce) // far if CONFIG_TPMDD wasn't set #ifdef CONFIG_TPMDD err = TRUSTEDBOOT::GetRandom(tpm_tgt, - reinterpret_cast<uint8_t*>(&o_nonce), - sizeof(o_nonce)); + sizeof(o_nonce), + reinterpret_cast<uint8_t*>(&o_nonce)); #endif if (err) { diff --git a/src/usr/secureboot/trusted/base/trustedbootMsg.H b/src/usr/secureboot/trusted/base/trustedbootMsg.H index 95a52a6e4..9789c4fed 100644 --- a/src/usr/secureboot/trusted/base/trustedbootMsg.H +++ b/src/usr/secureboot/trusted/base/trustedbootMsg.H @@ -36,6 +36,7 @@ #include <errl/errlentry.H> #include <sys/msg.h> #include "../trustedTypes.H" +#include <secureboot/trustedbootif.H> namespace TRUSTEDBOOT { @@ -57,7 +58,11 @@ namespace TRUSTEDBOOT MSG_TYPE_SHUTDOWN, MSG_TYPE_INIT_BACKUP_TPM, MSG_TYPE_GETRANDOM, - MSG_TYPE_LAST = MSG_TYPE_GETRANDOM, + MSG_TYPE_CREATE_ATT_KEYS, + MSG_TYPE_READ_AK_CERT, + MSG_TYPE_GEN_QUOTE, + MSG_TYPE_FLUSH_CONTEXT, + MSG_TYPE_LAST = MSG_TYPE_FLUSH_CONTEXT, }; /// PCREXTEND message data @@ -80,6 +85,47 @@ namespace TRUSTEDBOOT uint8_t* o_randNum; // the random data is populated here }; + // Pure Target* cannot be sent as extra_data through a synchronous message + // because the act of deleting the sync mesage attempts to delete the ptr + // to the target as well, which causes hostboot crashes. This struct is + // a simple wrapper around the Target* for the messages requiring just the + // TPM target to be passed. + struct TpmTargetData + { + TpmTarget* tpm; + TpmTargetData(TpmTarget* i_tpm) : + tpm(i_tpm) + { + } + }; + + // The struct used to read the AK ceritificate from TPM's NVRAM + struct ReadAKCertData + { + TpmTarget* tpm; + AKCertificate_t* data; // The output of NVRAM read + ReadAKCertData(TpmTarget* i_tpm, AKCertificate_t* i_data) : + tpm(i_tpm), data(i_data) + { + } + }; + + // The struct used to generate TPM quote + struct GenQuoteData + { + TpmTarget* tpm; + MasterTpmNonce_t* masterNonce; // 32-byte nonce value + QuoteDataOut* data; // Output - the quote and signature fields + GenQuoteData(TpmTarget* i_tpm, + MasterTpmNonce_t* i_masterNonce, + QuoteDataOut* o_data) : + tpm(i_tpm), + masterNonce(i_masterNonce), + data(o_data) + { + } + }; + // 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 090cac160..5c68e3c2f 100644 --- a/src/usr/secureboot/trusted/base/trustedboot_base.C +++ b/src/usr/secureboot/trusted/base/trustedboot_base.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2018 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -850,4 +850,214 @@ errlHndl_t flushTpmQueue() return l_errl; } +errlHndl_t createAttestationKeys(TpmTarget* i_target) +{ + errlHndl_t l_errl = nullptr; +#ifdef CONFIG_TPMDD + Message* l_msg = nullptr; + + TpmTargetData* l_data = new TpmTargetData{i_target}; + + l_msg = Message::factory(MSG_TYPE_CREATE_ATT_KEYS, + sizeof(*l_data), + reinterpret_cast<uint8_t*>(l_data), + MSG_MODE_SYNC); + assert(l_msg != nullptr, "createAttestationKeys: l_msg is nullptr"); + l_data = nullptr; //l_msg now owns l_data + + int l_rc = msg_sendrecv(systemData.msgQ, l_msg->iv_msg); + if(l_rc) + { + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_CREATE_ATT_KEYS + * @reasoncode RC_SENDRECV_FAIL + * @userdata1 rc from msg_sendrecv + * @userdata2 TPM HUID + * @devdesc msg_sendrecv failed for createAttestationKeys + * @custdesc trustedboot failure + */ + l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + MOD_CREATE_ATT_KEYS, + RC_SENDRECV_FAIL, + l_rc, + TARGETING::get_huid(i_target), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + l_errl->collectTrace(SECURE_COMP_NAME); + l_errl->collectTrace(TRBOOT_COMP_NAME); + } + else + { + l_errl = l_msg->iv_errl; + l_msg->iv_errl = nullptr; + } + + if(l_msg) + { + delete l_msg; + l_msg = nullptr; + } + +#endif + return l_errl; +} + +errlHndl_t readAKCertificate(TpmTarget* i_target, AKCertificate_t* o_data) +{ + errlHndl_t l_errl = nullptr; +#ifdef CONFIG_TPMDD + Message* l_msg = nullptr; + + ReadAKCertData* l_data = new ReadAKCertData {i_target, o_data}; + + l_msg = Message::factory(MSG_TYPE_READ_AK_CERT, + sizeof(*l_data), + reinterpret_cast<uint8_t*>(l_data), + MSG_MODE_SYNC); + assert(l_msg != nullptr, "readAKCertificate: l_msg is nullptr"); + l_data = nullptr; // l_msg now owns l_data + + int l_rc = msg_sendrecv(systemData.msgQ, l_msg->iv_msg); + if(l_rc) + { + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_READ_AK_CERT + * @reasoncode RC_SENDRECV_FAIL + * @userdata1 rc from msg_sendrecv + * @userdata2 TPM HUID + * @devdesc msg_sendrecv failed for readAKCertificate + * @custdesc trustedboot failure + */ + l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + MOD_READ_AK_CERT, + RC_SENDRECV_FAIL, + l_rc, + TARGETING::get_huid(i_target), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + l_errl->collectTrace(SECURE_COMP_NAME); + l_errl->collectTrace(TRBOOT_COMP_NAME); + } + else + { + l_errl = l_msg->iv_errl; + l_msg->iv_errl = nullptr; + } + + if(l_msg) + { + delete l_msg; + l_msg = nullptr; + } + +#endif + return l_errl; +} + +errlHndl_t generateQuote(TpmTarget* i_target, + MasterTpmNonce_t* i_masterNonce, + QuoteDataOut* o_data) +{ + errlHndl_t l_errl = nullptr; +#ifdef CONFIG_TPMDD + Message* l_msg = nullptr; + + GenQuoteData* l_data = new GenQuoteData{i_target, i_masterNonce, o_data}; + + l_msg = Message::factory(MSG_TYPE_GEN_QUOTE, + sizeof(*l_data), + reinterpret_cast<uint8_t*>(l_data), + MSG_MODE_SYNC); + assert(l_msg != nullptr, "generateQuote: l_msg is nullptr"); + l_data = nullptr; //l_msg now owns l_data + + int l_rc = msg_sendrecv(systemData.msgQ, l_msg->iv_msg); + if(l_rc) + { + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_GEN_QUOTE + * @reasoncode RC_SENDRECV_FAIL + * @userdata1 rc from msg_sendrecv + * @userdata2 TPM HUID + * @devdesc msg_sendrecv failed for generateQuote + * @custdesc trustedboot failure + */ + l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + MOD_GEN_QUOTE, + RC_SENDRECV_FAIL, + l_rc, + TARGETING::get_huid(i_target), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + l_errl->collectTrace(SECURE_COMP_NAME); + l_errl->collectTrace(TRBOOT_COMP_NAME); + } + else + { + l_errl = l_msg->iv_errl; + l_msg->iv_errl = nullptr; + } + + if(l_msg) + { + delete l_msg; + l_msg = nullptr; + } + +#endif + return l_errl; +} + +errlHndl_t flushContext(TpmTarget* i_target) +{ + errlHndl_t l_errl = nullptr; +#ifdef CONFIG_TPMDD + Message* l_msg = nullptr; + + TpmTargetData* l_data = new TpmTargetData{i_target}; + + l_msg = Message::factory(MSG_TYPE_FLUSH_CONTEXT, + sizeof(*l_data), + reinterpret_cast<uint8_t*>(l_data), + MSG_MODE_SYNC); + assert(l_msg != nullptr, "flushContext: l_msg is nullptr"); + l_data = nullptr; + + int l_rc = msg_sendrecv(systemData.msgQ, l_msg->iv_msg); + if(l_rc) + { + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_FLUSH_CONTEXT + * @reasoncode RC_SENDRECV_FAIL + * @userdata1 rc from msg_sendrecv + * @userdata2 TPM HUID + * @devdesc msg_sendrecv failed for TPM2_FlushContext + * @custdesc trustedboot failure + */ + l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + MOD_FLUSH_CONTEXT, + RC_SENDRECV_FAIL, + l_rc, + TARGETING::get_huid(i_target), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + l_errl->collectTrace(SECURE_COMP_NAME); + l_errl->collectTrace(TRBOOT_COMP_NAME); + } + else + { + l_errl = l_msg->iv_errl; + l_msg->iv_errl = nullptr; + } + + if(l_msg) + { + delete l_msg; + l_msg = nullptr; + } + +#endif + return l_errl; +} + } // end TRUSTEDBOOT diff --git a/src/usr/secureboot/trusted/test/trustedbootTest.H b/src/usr/secureboot/trusted/test/trustedbootTest.H index 83792cba0..8c1655dd8 100755 --- a/src/usr/secureboot/trusted/test/trustedbootTest.H +++ b/src/usr/secureboot/trusted/test/trustedbootTest.H @@ -906,8 +906,8 @@ class TrustedBootTest: public CxxTest::TestSuite { uint64_t randNum = 0; err = TRUSTEDBOOT::GetRandom(pTpm, - reinterpret_cast<uint8_t*>(&randNum), - sizeof(randNum)); + sizeof(randNum), + reinterpret_cast<uint8_t*>(&randNum)); num_ops ++; if(err) { diff --git a/src/usr/secureboot/trusted/trustedTypes.H b/src/usr/secureboot/trusted/trustedTypes.H index 34fc0fff5..7efa1d901 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,2018 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -52,11 +52,18 @@ namespace TRUSTEDBOOT { #endif + // TPM Command buffer sizes + enum + { + BUFSIZE = 256, + MAX_TRANSMIT_SIZE = 1024, ///< Maximum send/receive transmit size + }; + /// TPM Algorithm defines typedef enum { - TPM_ALG_SHA1 = 0x0004, ///< SHA1 Id - TPM_ALG_SHA256 = 0x000B, ///< SHA256 Id + TPM_ALG_SHA1 = 0x0004, ///< SHA1 Id + TPM_ALG_SHA256 = 0x000B, ///< SHA256 Id TPM_ALG_INVALID_ID ///< Used for error checking } TPM_Alg_Id; @@ -103,7 +110,11 @@ namespace TRUSTEDBOOT TPM_ST_SESSIONS = 0x8002, ///< A command has sessions // Command Codes + TPM_CC_CreatePrimary = 0x00000131, TPM_CC_Startup = 0x00000144, + TPM_CC_NV_Read = 0x0000014E, + TPM_CC_Quote = 0x00000158, + TPM_CC_FlushContext = 0x00000165, TPM_CC_GetCapability = 0x0000017A, TPM_CC_GetRandom = 0x0000017B, TPM_CC_PCR_Read = 0x0000017E, @@ -130,12 +141,22 @@ namespace TRUSTEDBOOT // TPM Return Codes TPM_SUCCESS = 0x000, - TPM_RC_INITIALIZE = 0x100, // TPM Authorization types TPM_RS_PW = 0x40000009, + TPM_RH_PLATFORM = 0x4000000C, + + // TPM Command Sizes + TPM_CREATE_PRIMARY_SIZE = 0x00000041, + TPM_IN_SENSITIVE_SIZE = 0x00000009, + TPM_NV_READ_SIZE = 0x00000023, + TPM_QUOTE_SIZE = 0x0000004B, + TPM_FLUSH_CONTEXT_SIZE = 0x0000000E, + + // Transient Objects handle + TPM_HT_TRANSIENT = 0x80000000, }; @@ -484,6 +505,81 @@ namespace TRUSTEDBOOT uint8_t* o_tpmBuf, size_t i_tpmBufSize, size_t* io_cmdSize); + struct _TPMS_SENSITIVE_CREATE + { + uint32_t userAuth; + uint8_t data[43]; + } PACKED; + typedef struct _TPMS_SENSITIVE_CREATE TPMS_SENSITIVE_CREATE; + + // Structure that contains the sensitive creation data + struct _TPM2B_SENSITIVE_CREATE + { + uint32_t size; + TPMS_SENSITIVE_CREATE sensitive; + } PACKED; + typedef struct _TPM2B_SENSITIVE_CREATE TPM2B_SENSITIVE_CREATE; + + // Incoming CreatePrimary structure + struct _TPM2_CreatePrimaryIn + { + TPM2_BaseIn base; + uint32_t primaryHandle; + TPM2B_SENSITIVE_CREATE inSensitive; + } PACKED; + typedef struct _TPM2_CreatePrimaryIn TPM2_CreatePrimaryIn; + + // Incoming NV Read structure + struct _TPM2_NVReadIn + { + TPM2_BaseIn base; + uint8_t data[25]; + } PACKED; + typedef struct _TPM2_NVReadIn TPM2_NVReadIn; + + // Outgoing NV Read structure + struct _TPM2_NVReadOut + { + TPM2_BaseOut base; + uint8_t NVData[TPM_NV_DATA_SIZE]; + } PACKED; + typedef struct _TPM2_NVReadOut TPM2_NVReadOut; + + // Struct for the data portion of the Quote request + struct _TPM2_QuoteData + { + uint8_t tpmiDhObject[19]; + MasterTpmNonce_t masterNonce; + uint16_t data; + uint16_t inScheme; + TPML_PCR_SELECTION pcrSelection; + } PACKED; + typedef struct _TPM2_QuoteData TPM2_QuoteData; + + // Incoming TPM Quote structure + struct _TPM2_QuoteIn + { + TPM2_BaseIn base; + TPM2_QuoteData quoteData; + } PACKED; + typedef struct _TPM2_QuoteIn TPM2_QuoteIn; + + // Outgoing Quote structure + struct _TPM2_QuoteOut + { + TPM2_BaseOut base; + uint8_t quoteData[MAX_TRANSMIT_SIZE]; + } PACKED; + typedef struct _TPM2_QuoteOut TPM2_QuoteOut; + + // Incoming Context Flush structure + struct _TPM2_FlushContextIn + { + TPM2_BaseIn base; + uint32_t flushHandle; + } PACKED; + typedef struct _TPM2_FlushContextIn TPM2_FlushContextIn; + #ifdef __cplusplus } // end TRUSTEDBOOT namespace #endif diff --git a/src/usr/secureboot/trusted/trustedboot.C b/src/usr/secureboot/trusted/trustedboot.C index 0d9ae36c6..1f5e159a2 100644 --- a/src/usr/secureboot/trusted/trustedboot.C +++ b/src/usr/secureboot/trusted/trustedboot.C @@ -1479,6 +1479,93 @@ void doInitBackupTpm() } } +errlHndl_t doCreateAttKeys(TpmTarget* i_tpm) +{ + errlHndl_t l_errl = nullptr; + + do { + l_errl = validateTpmHandle(i_tpm); + if(l_errl) + { + break; + } + + l_errl = tpmCmdCreateAttestationKeys(i_tpm); + if(l_errl) + { + break; + } + + } while(0); + + return l_errl; +} + +errlHndl_t doReadAKCert(TpmTarget* i_tpm, AKCertificate_t* o_data) +{ + errlHndl_t l_errl = nullptr; + + do { + l_errl = validateTpmHandle(i_tpm); + if(l_errl) + { + break; + } + + l_errl = tpmCmdReadAKCertificate(i_tpm, o_data); + if(l_errl) + { + break; + } + } while(0); + + return l_errl; +} + +errlHndl_t doGenQuote(TpmTarget* i_tpm, + MasterTpmNonce_t* i_masterNonce, + QuoteDataOut* o_data) +{ + errlHndl_t l_errl = nullptr; + + do { + l_errl = validateTpmHandle(i_tpm); + if(l_errl) + { + break; + } + + l_errl = tpmCmdGenerateQuote(i_tpm, i_masterNonce, o_data); + if(l_errl) + { + break; + } + } while(0); + + return l_errl; +} + +errlHndl_t doFlushContext(TpmTarget* i_tpm) +{ + errlHndl_t l_errl = nullptr; + + do { + l_errl = validateTpmHandle(i_tpm); + if(l_errl) + { + break; + } + + l_errl = tpmCmdFlushContext(i_tpm); + if(l_errl) + { + break; + } + } while(0); + + return l_errl; +} + void* tpmDaemon(void* unused) { bool shutdownPending = false; @@ -1690,6 +1777,44 @@ void* tpmDaemon(void* unused) } break; + case TRUSTEDBOOT::MSG_TYPE_CREATE_ATT_KEYS: + { + tb_msg = static_cast<TRUSTEDBOOT::Message*>(msg->extra_data); + TpmTargetData* l_data = + reinterpret_cast<TpmTargetData*>(tb_msg->iv_data); + tb_msg->iv_errl = doCreateAttKeys(l_data->tpm); + } + break; + + case TRUSTEDBOOT::MSG_TYPE_READ_AK_CERT: + { + tb_msg = static_cast<TRUSTEDBOOT::Message*>(msg->extra_data); + ReadAKCertData* l_data = + reinterpret_cast<ReadAKCertData*>(tb_msg->iv_data); + tb_msg->iv_errl = doReadAKCert(l_data->tpm, l_data->data); + } + break; + + case TRUSTEDBOOT::MSG_TYPE_GEN_QUOTE: + { + tb_msg = static_cast<TRUSTEDBOOT::Message*>(msg->extra_data); + GenQuoteData* l_data = + reinterpret_cast<GenQuoteData*>(tb_msg->iv_data); + tb_msg->iv_errl = doGenQuote(l_data->tpm, + l_data->masterNonce, + l_data->data); + } + break; + + case TRUSTEDBOOT::MSG_TYPE_FLUSH_CONTEXT: + { + tb_msg = static_cast<TRUSTEDBOOT::Message*>(msg->extra_data); + TpmTargetData* l_data = + reinterpret_cast<TpmTargetData*>(tb_msg->iv_data); + tb_msg->iv_errl = doFlushContext(l_data->tpm); + } + break; + default: assert(false, "Invalid msg command"); break; @@ -1955,8 +2080,8 @@ errlHndl_t tpmDrtmReset(TpmTarget* const i_pTpm) #ifdef CONFIG_TPMDD errlHndl_t GetRandom(const TpmTarget* i_pTpm, - uint8_t* o_randNum, - const size_t i_randNumSize) + const size_t i_randNumSize, + uint8_t* o_randNum) { errlHndl_t err = nullptr; Message* msg = nullptr; @@ -2056,8 +2181,8 @@ errlHndl_t poisonTpm(const TpmTarget* i_pTpm) // Note: GetRandom validates the TPM handle internally and returns an // error log if invalid l_errl = GetRandom(i_pTpm, - reinterpret_cast<uint8_t*>(&l_randNum), - sizeof(l_randNum)); + sizeof(l_randNum), + reinterpret_cast<uint8_t*>(&l_randNum)); if (l_errl) { @@ -2094,5 +2219,4 @@ errlHndl_t poisonTpm(const TpmTarget* i_pTpm) return l_errl; } - } // end TRUSTEDBOOT diff --git a/src/usr/secureboot/trusted/trustedbootCmds.C b/src/usr/secureboot/trusted/trustedbootCmds.C index db1dca51e..1aeb387f9 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,2018 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -48,6 +48,7 @@ #include "trustedbootUtils.H" #include "trustedboot.H" #include "trustedTypes.H" +#include <secureboot/trustedbootif.H> #ifdef CONFIG_DRTM #include <secureboot/drtm.H> @@ -368,6 +369,8 @@ errlHndl_t tpmUnmarshalResponseData(uint32_t i_commandCode, switch (i_commandCode) { // Empty response commands + case TPM_CC_CreatePrimary: + case TPM_CC_FlushContext: case TPM_CC_Startup: case TPM_CC_PCR_Extend: // Nothing to do @@ -401,6 +404,32 @@ errlHndl_t tpmUnmarshalResponseData(uint32_t i_commandCode, } break; + case TPM_CC_NV_Read: + { + // Read out the TPM NV Data + TPM2_NVReadOut* l_respPtr = + reinterpret_cast<TPM2_NVReadOut*>(o_outBuf); + TPM2_NVReadOut* l_tpmRespData = + reinterpret_cast<TPM2_NVReadOut*>(i_respBuf); + memcpy(l_tpmRespData->NVData, + l_respPtr->NVData, + TPM_NV_DATA_SIZE); + } + break; + + case TPM_CC_Quote: + { + // Pass back the quote data + TPM2_QuoteOut* l_respPtr = + reinterpret_cast<TPM2_QuoteOut*>(o_outBuf); + TPM2_QuoteOut* l_tpmRespData = + reinterpret_cast<TPM2_QuoteOut*>(i_respBuf); + memcpy(l_respPtr->quoteData, + l_tpmRespData->quoteData, + sizeof(l_tpmRespData->base.responseSize)); + } + break; + default: { // Command code not supported @@ -1235,6 +1264,332 @@ errlHndl_t tpmCmdPcrRead(TpmTarget* io_target, } +errlHndl_t tpmCmdCreateAttestationKeys(TpmTarget* i_target) +{ + TRACFCOMP(g_trac_trustedboot, + ENTER_MRK"tpmCmdCreateAttestationKeys()"); + errlHndl_t l_errl = nullptr; + + uint8_t l_dataBuf[BUFSIZE] = {}; + TPM2_CreatePrimaryIn* l_cmd = + reinterpret_cast<TPM2_CreatePrimaryIn*>(l_dataBuf); + TPM2_BaseOut* l_resp = reinterpret_cast<TPM2_BaseOut*>(l_dataBuf); + + do { + uint64_t l_cmdData[] = { 0x0000000000000400, + 0x0000000018002300, + 0x0B00050472000000, + 0x100018000B000300, + 0x1000000000000000, + 0 }; + l_cmd->base.tag = TPM_ST_SESSIONS; + l_cmd->base.commandSize = TPM_CREATE_PRIMARY_SIZE; + l_cmd->base.commandCode = TPM_CC_CreatePrimary; + l_cmd->primaryHandle = TPM_RH_PLATFORM; + l_cmd->inSensitive.size = TPM_IN_SENSITIVE_SIZE; + l_cmd->inSensitive.sensitive.userAuth = TPM_RS_PW; + + memcpy(l_cmd->inSensitive.sensitive.data, l_cmdData, sizeof(l_cmdData)); + + size_t l_dataSize = MAX_TRANSMIT_SIZE; + + l_errl = tpmTransmit(i_target, + l_dataBuf, + l_cmd->base.commandSize, + l_dataSize, + TPM_LOCALITY_0); + if(l_errl) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdCreateAttestationKeys: could not transmit TPM command"); + break; + } + + l_errl = tpmUnmarshalResponseData(TPM_CC_CreatePrimary, + l_dataBuf, + l_dataSize, + l_resp, + l_dataSize); + if(l_errl) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdCreateAttestationKeys: could not unmarshal response data"); + break; + } + + // Check response return code + if(TPM_SUCCESS != l_resp->responseCode) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdCreateAttestationKeys: TPM (HUID 0x%x) returned a nonzero return code. Expected RC 0x%x, actual RC 0x%x", TARGETING::get_huid(i_target), TPM_SUCCESS, l_resp->responseCode); + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @reasoncode RC_TPM_BAD_RESP + * @moduleid MOD_TPM_CMD_CREATE_ATTEST + * @userdata1 TPM HUID + * @userdata2[0..31] Expected response RC + * @userdata2[32..63] Actual response RC + * @devdesc Incorrect response from TPM_CC_CreatePrimary + * command (see logs for TPM HUID) + * @custdesc Trusted boot failure + */ + l_errl = tpmCreateErrorLog(MOD_TPM_CMD_CREATE_ATTEST, + RC_TPM_BAD_RESP, + TARGETING::get_huid(i_target), + TWO_UINT32_TO_UINT64( + TPM_SUCCESS, + l_resp->responseCode)); + break; + } + + } while(0); + + TRACFCOMP(g_trac_trustedboot, + EXIT_MRK"tpmCmdCreateAttestationKeys()"); + return l_errl; +} + +errlHndl_t tpmCmdReadAKCertificate(TpmTarget* i_target, AKCertificate_t* o_data) +{ + TRACFCOMP(g_trac_trustedboot, ENTER_MRK"tpmCmdReadAKCertificate()"); + errlHndl_t l_errl = nullptr; + + size_t l_dataSize = MAX_TRANSMIT_SIZE; + + uint8_t l_dataBuf[l_dataSize] = {}; + TPM2_NVReadIn* l_cmd = reinterpret_cast<TPM2_NVReadIn*>(l_dataBuf); + TPM2_BaseOut* l_resp = reinterpret_cast<TPM2_BaseOut*>(l_dataBuf); + + do { + uint64_t l_cmdData[] = { 0x01C1018101C10181, + 0x0000000940000009, + 0x000000000001F400, + 0, }; + l_cmd->base.tag = TPM_ST_SESSIONS; + l_cmd->base.commandSize = TPM_NV_READ_SIZE; + l_cmd->base.commandCode = TPM_CC_NV_Read; + + memcpy(l_cmd->data, l_cmdData, sizeof(l_cmdData)); + + l_errl = tpmTransmit(i_target, + l_dataBuf, + l_cmd->base.commandSize, + l_dataSize, + TPM_LOCALITY_0); + if(l_errl) + { + break; + } + + l_errl = tpmUnmarshalResponseData(TPM_CC_NV_Read, + l_dataBuf, + l_dataSize, + l_resp, + l_dataSize); + if(l_errl) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdReadAKCertificate: could not unmarshal response data"); + break; + } + + if(TPM_SUCCESS != l_resp->responseCode) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdReadAKCertificate: TPM (HUID 0x%x) returned a nonzero return code. Expected RC 0x%x, actual RC 0x%x", TARGETING::get_huid(i_target), TPM_SUCCESS, l_resp->responseCode); + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @reasoncode RC_TPM_BAD_RESP + * @moduleid MOD_TPM_CMD_READ_AK_CERT + * @userdata1 TPM HUID + * @userdata2[0..31] Expected response RC + * @userdata2[32..63] Actual response RC + * @devdesc Incorrect response from TPM_CC_NV_Read + * command (see logs for TPM HUID) + * @custdesc Trusted boot failure + */ + l_errl = tpmCreateErrorLog(MOD_TPM_CMD_READ_AK_CERT, + RC_TPM_BAD_RESP, + TARGETING::get_huid(i_target), + TWO_UINT32_TO_UINT64( + TPM_SUCCESS, + l_resp->responseCode)); + break; + } + + TPM2_NVReadOut* l_read = reinterpret_cast<TPM2_NVReadOut*>(l_resp); + // NVRAM holds the AK certificate. Copy out a fixed size of 500 bytes + memcpy(*o_data, l_read->NVData, TPM_NV_DATA_SIZE); + + }while(0); + + TRACFCOMP(g_trac_trustedboot, EXIT_MRK"tpmCmdReadAKCertificate()"); + return l_errl; +} + +errlHndl_t tpmCmdGenerateQuote(TpmTarget* i_target, + MasterTpmNonce_t* i_masterNonce, + QuoteDataOut* o_data) +{ + TRACFCOMP(g_trac_trustedboot, ENTER_MRK"tpmCmdGenerateQuote()"); + errlHndl_t l_errl = nullptr; + + size_t l_dataSize = MAX_TRANSMIT_SIZE; + uint8_t l_dataBuf[l_dataSize] = {}; + TPM2_QuoteIn* l_cmd = reinterpret_cast<TPM2_QuoteIn*>(l_dataBuf); + TPM2_BaseOut* l_resp = reinterpret_cast<TPM2_BaseOut*>(l_dataBuf); + + do { + uint64_t l_tpmiDhObject[] = { 0x8000000000000009, + 0x4000000900000000, + 0x0000200000000000 }; + uint16_t l_data = 0x0018; + + l_cmd->base.tag = TPM_ST_SESSIONS; + l_cmd->base.commandSize = TPM_QUOTE_SIZE; + l_cmd->base.commandCode = TPM_CC_Quote; + + memcpy(l_cmd->quoteData.tpmiDhObject,l_tpmiDhObject,sizeof(l_tpmiDhObject)); + + memcpy(l_cmd->quoteData.masterNonce, + *i_masterNonce, + TPM_NONCE_SIZE_BYTES); + + l_cmd->quoteData.data = l_data; + l_cmd->quoteData.inScheme = TPM_ALG_SHA256; + + l_cmd->quoteData.pcrSelection.count = 1; + l_cmd->quoteData.pcrSelection.pcrSelections[0].algorithmId = TPM_ALG_SHA256; + l_cmd->quoteData.pcrSelection.pcrSelections[0].sizeOfSelect =PCR_SELECT_MAX; + + for(size_t i = PCR_0; i <= PCR_7 ; ++i) + { + l_cmd->quoteData.pcrSelection.pcrSelections[0].pcrSelect[i/8] = + 0x01 << (i % 8); + } + + l_errl = tpmTransmit(i_target, + l_dataBuf, + l_cmd->base.commandSize, + l_dataSize, + TPM_LOCALITY_0); + if(l_errl) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdGenerateQuote(): could not transmit TPM command"); + break; + } + + l_errl = tpmUnmarshalResponseData(TPM_CC_Quote, + l_dataBuf, + l_dataSize, + l_resp, + l_dataSize); + if(l_errl) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdGenerateQuote(): could not unmarshal response data"); + break; + } + + if(TPM_SUCCESS != l_resp->responseCode) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdGenerateQuote: TPM (HUID 0x%x) returned a nonzero return code. Expected RC 0x%x, actual RC 0x%x", TARGETING::get_huid(i_target), TPM_SUCCESS, l_resp->responseCode); + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @reasoncode RC_TPM_BAD_RESP + * @moduleid MOD_TPM_CMD_GEN_QUOTE + * @userdata1 TPM HUID + * @userdata2[0..31] Expected response RC + * @userdata2[32..63] Actual response RC + * @devdesc Incorrect response from TPM_CC_Quote + * command (see logs for TPM HUID) + * @custdesc Trusted boot failure + */ + l_errl = tpmCreateErrorLog(MOD_TPM_CMD_GEN_QUOTE, + RC_TPM_BAD_RESP, + TARGETING::get_huid(i_target), + TWO_UINT32_TO_UINT64( + TPM_SUCCESS, + l_resp->responseCode)); + break; + } + + TPM2_QuoteOut* l_read = reinterpret_cast<TPM2_QuoteOut*>(l_resp); + void* l_quoteDataPtr = &l_read->quoteData; + + // The response size contains the size of the base response structure too, + // so subtract that size from the size of the actual quote data. + o_data->size = l_read->base.responseSize-sizeof(l_read->base); + memcpy(o_data->data, l_quoteDataPtr, o_data->size); + + } while(0); + + TRACFCOMP(g_trac_trustedboot, EXIT_MRK"tpmCmdGenerateQuote()"); + return l_errl; +} + +errlHndl_t tpmCmdFlushContext(TpmTarget* i_target) +{ + TRACFCOMP(g_trac_trustedboot, ENTER_MRK"tpmCmdFlushContext()"); + errlHndl_t l_errl = nullptr; + + size_t l_dataSize = MAX_TRANSMIT_SIZE; + uint8_t l_dataBuf[l_dataSize] = {}; + + TPM2_FlushContextIn* l_cmd = + reinterpret_cast<TPM2_FlushContextIn*>(l_dataBuf); + TPM2_BaseOut* l_resp = reinterpret_cast<TPM2_BaseOut*>(l_dataBuf); + do { + l_cmd->base.tag = TPM_ST_NO_SESSIONS; + l_cmd->base.commandSize = TPM_FLUSH_CONTEXT_SIZE; + l_cmd->base.commandCode = TPM_CC_FlushContext; + + l_cmd->flushHandle = TPM_HT_TRANSIENT; + + l_errl = tpmTransmit(i_target, + l_dataBuf, + l_cmd->base.commandSize, + l_dataSize, + TPM_LOCALITY_0); + if(l_errl) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdFlushContext(): could not transmit TPM command"); + break; + } + + l_errl = tpmUnmarshalResponseData(TPM_CC_FlushContext, + l_dataBuf, + l_dataSize, + l_resp, + l_dataSize); + if(l_errl) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdFlushContext(): could not unmarshal response data"); + break; + } + + if(TPM_SUCCESS != l_resp->responseCode) + { + TRACFCOMP(g_trac_trustedboot, ERR_MRK"tpmCmdFlushContext: TPM (HUID 0x%x) returned a nonzero return code. Expected RC 0x%x, actual RC 0x%x", TARGETING::get_huid(i_target), TPM_SUCCESS, l_resp->responseCode); + /*@ + * @errortype ERRL_SEV_UNRECOVERABLE + * @reasoncode RC_TPM_BAD_RESP + * @moduleid MOD_TPM_CMD_FLUSH_CONTEXT + * @userdata1 TPM HUID + * @userdata2[0..31] Expected response RC + * @userdata2[32..63] Actual response RC + * @devdesc Incorrect response from TPM2_FlushContext + * command (see logs for TPM HUID) + * @custdesc Trusted boot failure + */ + l_errl = tpmCreateErrorLog(MOD_TPM_CMD_FLUSH_CONTEXT, + RC_TPM_BAD_RESP, + TARGETING::get_huid(i_target), + TWO_UINT32_TO_UINT64( + TPM_SUCCESS, + l_resp->responseCode)); + break; + } + + } while(0); + + TRACFCOMP(g_trac_trustedboot, EXIT_MRK"tpmCmdFlushContext()"); + return l_errl; +} #ifdef __cplusplus } // end TRUSTEDBOOT diff --git a/src/usr/secureboot/trusted/trustedbootCmds.H b/src/usr/secureboot/trusted/trustedbootCmds.H index 1c40bf80a..9b0e99aaa 100644 --- a/src/usr/secureboot/trusted/trustedbootCmds.H +++ b/src/usr/secureboot/trusted/trustedbootCmds.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -50,12 +50,6 @@ namespace TRUSTEDBOOT { #endif -enum -{ - BUFSIZE = 256, - MAX_TRANSMIT_SIZE = 1024, ///< Maximum send/receive transmit size -}; - /** * @brief Transmit the command to the TPM and perform marshaling * @param[in/out] io_target Current TPM target structure @@ -181,6 +175,47 @@ errlHndl_t tpmCmdPcrRead(TpmTarget* io_target, uint8_t* o_digest, size_t i_digestSize); + +/** + * @brief Send the TPM_CC_Create to the TPM + * @param[in] i_target the target TPM (must not be nullptr) + * @return nullptr if successful; non-nullptr if error + * + */ +errlHndl_t tpmCmdCreateAttestationKeys(TpmTarget* i_target); + +/** + * @brief Send the TPM_CC_NV_Read command to the given TPM to read the AK + * certificate from its NVRAM + * @param[in] i_target the TPM target (must not be nullptr) + * @param[out] o_data the pointer to the data contained within NVRAM of the TPM + * @return nullptr on success; non-nullptr on error + */ +errlHndl_t tpmCmdReadAKCertificate(TpmTarget* i_target, + AKCertificate_t* o_data); + +/** + * @brief Send the TPM_CC_Quote command to the given TPM to generate quote + * and signature information (returned in o_data) + * @param[in] i_target the TPM target (must not be nullptr) + * @param[in] i_masterNonce the 32-byte master nonce + * @param[out] o_data a pointer to the data structure containing the size of + * the quote data from the TPM and the actual data + * @return nullptr on success; non-nullptr on error + */ +errlHndl_t tpmCmdGenerateQuote(TpmTarget* i_target, + MasterTpmNonce_t* i_masterNonce, + QuoteDataOut* o_data); + +/** + * @brief Send the TPM2_FlushContext command to the given TPM to remove + * transient objects + * @param[in] i_target the TPM target (must not be nullptr) + * @return nullptr on success; non-nullptr on error + */ +errlHndl_t tpmCmdFlushContext(TpmTarget* i_target); + + #ifdef __cplusplus } // end TRUSTEDBOOT namespace #endif |