static void init_vboot(int bootmode) { u32 result; u8 response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; #ifdef UBOOT_DOES_TPM_STARTUP /* Doing TPM startup when we're not coming in on the S3 resume path * saves us roughly 20ms in boot time only. This does not seem to * be worth an API change to vboot_reference-firmware right now, so * let's keep the code around, but just bail out early: */ if (bootmode != 2) return; #endif printk(BIOS_DEBUG, "Verified boot TPM initialization.\n"); printk(BIOS_SPEW, "TPM: Init\n"); if (tis_init()) return; printk(BIOS_SPEW, "TPM: Open\n"); if (tis_open()) return; if (bootmode == 2) { /* S3 Resume */ printk(BIOS_SPEW, "TPM: Resume\n"); result = TlclSendReceive(tpm_resume_cmd.buffer, response, sizeof(response)); if (result == TPM_E_INVALID_POSTINIT) { /* We're on a platform where the TPM maintains power * in S3, so it's already initialized. */ printk(BIOS_DEBUG, "TPM: Already initialized.\n"); return; } } else { printk(BIOS_SPEW, "TPM: Startup\n"); result = TlclSendReceive(tpm_startup_cmd.buffer, response, sizeof(response)); } if (result == TPM_SUCCESS) { printk(BIOS_SPEW, "TPM: OK.\n"); return; } #if !MOCK_TPM printk(BIOS_ERR, "TPM: Error code 0x%x. Hard reset!\n", result); hard_reset(); #endif }
/** * Test assorted tlcl functions */ static void TlclTest(void) { uint8_t buf[32], buf2[32]; ResetMocks(); TEST_EQ(TlclLibInit(), VBERROR_SUCCESS, "Init"); ResetMocks(); mock_retval = VBERROR_SIMULATED; TEST_EQ(TlclLibInit(), mock_retval, "Init bad"); ResetMocks(); TEST_EQ(TlclLibClose(), VBERROR_SUCCESS, "Close"); ResetMocks(); mock_retval = VBERROR_SIMULATED; TEST_EQ(TlclLibClose(), mock_retval, "Close bad"); ResetMocks(); ToTpmUint32(buf + 2, 123); TEST_EQ(TlclPacketSize(buf), 123, "TlclPacketSize"); ResetMocks(); ToTpmUint32(buf + 2, 10); TEST_EQ(TlclSendReceive(buf, buf2, sizeof(buf2)), 0, "SendReceive"); TEST_PTR_EQ(calls[0].req, buf, "SendReceive req ptr"); TEST_EQ(calls[0].req_size, 10, "SendReceive size"); ResetMocks(); calls[0].retval = VBERROR_SIMULATED; ToTpmUint32(buf + 2, 10); TEST_EQ(TlclSendReceive(buf, buf2, sizeof(buf2)), VBERROR_SIMULATED, "SendReceive fail"); ResetMocks(); SetResponse(0, 123, 10); ToTpmUint32(buf + 2, 10); TEST_EQ(TlclSendReceive(buf, buf2, sizeof(buf2)), 123, "SendReceive error response"); // TODO: continue self test (if needed or doing) // TODO: then retry doing self test }
/**************************************************************************** * * Open an OSAP session * Object Specific Authorization Protocol, returned handle must manipulate * a single object given as a parameter (can introduce AuthData). * * ****************************************************************************/ uint32_t TSS_OSAPopen(struct tss_osapsess *sess, const uint8_t *key, uint16_t etype, uint32_t evalue) { struct s_tpm_osap_open_cmd cmd; uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; uint32_t nonceSize; uint32_t result; debug("TPM: TSS_OSAPopen\n"); /* check input arguments */ if (key == NULL || sess == NULL) { return TPM_E_NULL_ARG; } TlclGetRandom(sess->ononceOSAP, TPM_NONCE_SIZE, &nonceSize); memcpy(&cmd, &tpm_osap_open_cmd, sizeof(cmd)); ToTpmUint16(cmd.buffer + tpm_osap_open_cmd.type, etype); ToTpmUint32(cmd.buffer + tpm_osap_open_cmd.value, evalue); memcpy(cmd.buffer + tpm_osap_open_cmd.nonce, sess->ononceOSAP, TPM_NONCE_SIZE); result = TlclSendReceive(cmd.buffer, response, sizeof(response)); if (result == TPM_SUCCESS) { FromTpmUint32(response + kTpmResponseHeaderLength, &(sess->handle)); memcpy(sess->enonce, response + kTpmResponseHeaderLength + sizeof(uint32_t), TPM_NONCE_SIZE); memcpy(sess->enonceOSAP, response + kTpmResponseHeaderLength + sizeof(uint32_t) + TPM_NONCE_SIZE, TPM_NONCE_SIZE); debug("TPM: TSS_OSAPopen success, calculating HMAC\n"); /*DATA_DEBUG("key", key, TPM_HASH_SIZE); DATA_DEBUG("enonceOSAP", sess->enonceOSAP, TPM_NONCE_SIZE); DATA_DEBUG("ononceOSAP", sess->ononceOSAP, TPM_NONCE_SIZE);*/ /* not implemented */ SHA1_CTX hmac; hmac_starts(&hmac, key, TPM_HASH_SIZE); hmac_update(&hmac, sess->enonceOSAP, TPM_NONCE_SIZE); hmac_update(&hmac, sess->ononceOSAP, TPM_NONCE_SIZE); hmac_finish(&hmac, key, TPM_HASH_SIZE, sess->ssecret); } return result; }
/**************************************************************************** * * Open an OIAP session * Object Independent Authorization Protocol, will not work on commands * that introduce new AuthData to the TPM * ****************************************************************************/ uint32_t TSS_OIAPopen(uint32_t *handle, uint8_t *enonce) { struct s_tpm_oiap_open_cmd cmd; uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; uint32_t result; debug("TPM: TSS_OIAPopen\n"); /* check input arguments */ if (handle == NULL || enonce == NULL) { return TPM_E_NULL_ARG; } memcpy(&cmd, &tpm_oiap_open_cmd, sizeof(cmd)); result = TlclSendReceive(cmd.buffer, response, sizeof(response)); if (result == TPM_SUCCESS) { FromTpmUint32(response + kTpmResponseHeaderLength, handle); memcpy(enonce, response + kTpmResponseHeaderLength + sizeof(uint32_t), TPM_NONCE_SIZE); } return result; }
void init_tpm(int s3resume) { u32 result; u8 response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; if (CONFIG_TPM_DEACTIVATE) { printk(BIOS_SPEW, "TPM: Deactivate\n"); result = TlclSendReceive(tpm_deactivate_cmd.buffer, response, sizeof(response)); if (result == TPM_SUCCESS) { printk(BIOS_SPEW, "TPM: OK.\n"); return; } printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); return; } /* Doing TPM startup when we're not coming in on the S3 resume path * saves us roughly 20ms in boot time only. This does not seem to * be worth an API change to vboot_reference-firmware right now, so * let's keep the code around, but just bail out early: */ if (s3resume ? CONFIG_NO_TPM_RESUME : CONFIG_SKIP_TPM_STARTUP_ON_NORMAL_BOOT) return; printk(BIOS_DEBUG, "TPM initialization.\n"); printk(BIOS_SPEW, "TPM: Init\n"); if (tis_init()) return; printk(BIOS_SPEW, "TPM: Open\n"); if (tis_open()) return; if (s3resume) { /* S3 Resume */ printk(BIOS_SPEW, "TPM: Resume\n"); result = TlclSendReceive(tpm_resume_cmd.buffer, response, sizeof(response)); if (result == TPM_E_INVALID_POSTINIT) { /* We're on a platform where the TPM maintains power * in S3, so it's already initialized. */ printk(BIOS_DEBUG, "TPM: Already initialized.\n"); return; } } else { printk(BIOS_SPEW, "TPM: Startup\n"); result = TlclSendReceive(tpm_startup_cmd.buffer, response, sizeof(response)); } if (result == TPM_SUCCESS) { printk(BIOS_SPEW, "TPM: OK.\n"); return; } printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); if (CONFIG_TPM_INIT_FAILURE_IS_FATAL) { printk(BIOS_ERR, "Hard reset!\n"); post_code(POST_TPM_FAILURE); if (IS_ENABLED(CONFIG_CONSOLE_CBMEM_DUMP_TO_UART)) cbmem_dump_console(); hard_reset(); } }