/* SPDX-License-Identifier: BSD-2-Clause */ /******************************************************************************* * Copyright 2018-2019, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. *******************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "fapi_util.h" #include "tss2_tcti.h" #include "tss2_esys.h" #include "tss2_fapi.h" #include "fapi_int.h" #include "fapi_crypto.h" #include "fapi_policy.h" #include "ifapi_get_intl_cert.h" #define LOGMODULE fapi #include "util/log.h" #include "util/aux_util.h" #define EK_CERT_RANGE (0x01c07fff) /** One-Call function for the initial FAPI provisioning. * * Provisions a TSS with its TPM. This includes the setting of important passwords * and policy settings as well as the readout of the EK and its certificate and * the initialization of the system-wide keystore. * * @param[in,out] context The FAPI_CONTEXT. * @param[in] authValueEh The authorization value for the endorsement * hierarchy. May be NULL * @param[in] authValueSh The authorization value for the storage hierarchy. * Should be NULL * @param[in] authValueLockout The authorization value for lockout. * * @retval TSS2_RC_SUCCESS: if the function call was a success. * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL. * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected. * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous * operation already pending. * @retval TSS2_FAPI_RC_NO_CERT: if no certificate was found for the computed EK. * @retval TSS2_FAPI_RC_BAD_KEY: if public key of the EK does not match the * configured certificate or the configured fingerprint does not match * the computed EK. * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved. * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for * internal operations or return parameters. * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its * config file. * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and * this function needs to be called again. * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into * the function. * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback * is not set. * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails. * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred. * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest * was not successful. * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found * during authorization. * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found. * @retval TSS2_ESYS_RC_* possible error codes of ESAPI. */ TSS2_RC Fapi_Provision( FAPI_CONTEXT *context, char const *authValueEh, char const *authValueSh, char const *authValueLockout) { LOG_TRACE("called for context:%p", context); TSS2_RC r, r2; /* Check for NULL parameters */ check_not_null(context); /* Check whether TCTI and ESYS are initialized */ return_if_null(context->esys, "Command can't be executed in none TPM mode.", TSS2_FAPI_RC_NO_TPM); /* If the async state automata of FAPI shall be tested, then we must not set the timeouts of ESYS to blocking mode. During testing, the mssim tcti will ensure multiple re-invocations. Usually however the synchronous invocations of FAPI shall instruct ESYS to block until a result is available. */ #ifndef TEST_FAPI_ASYNC r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK); return_if_error_reset_state(r, "Set Timeout to blocking"); #endif /* TEST_FAPI_ASYNC */ r = Fapi_Provision_Async(context, authValueEh, authValueSh, authValueLockout); return_if_error_reset_state(r, "Provision"); do { /* We wait for file I/O to be ready if the FAPI state automata are in a file I/O state. */ r = ifapi_io_poll(&context->io); return_if_error(r, "Something went wrong with IO polling"); /* Repeatedly call the finish function, until FAPI has transitioned through all execution stages / states of this invocation. */ r = Fapi_Provision_Finish(context); } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN); /* Reset the ESYS timeout to non-blocking, immediate response. */ r2 = Esys_SetTimeout(context->esys, 0); return_if_error(r2, "Set Timeout to non-blocking"); return_if_error_reset_state(r, "Provision"); LOG_TRACE("finished"); return TSS2_RC_SUCCESS; } /** Asynchronous function for the initial FAPI provisioning. * * Provisions a TSS with its TPM. This includes the setting of important passwords * and policy settings as well as the readout of the EK and its certificate and * the initialization of the system-wide keystore. * * Call Fapi_Provision_Finish to finish the execution of this command. * * @param[in,out] context The FAPI_CONTEXT. * @param[in] authValueEh The authorization value for the endorsement * hierarchy. May be NULL * @param[in] authValueSh The authorization value for the storage hierarchy. * Should be NULL * @param[in] authValueLockout The authorization value for lockout. * * @retval TSS2_RC_SUCCESS: if the function call was a success. * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL. * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected. * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous * operation already pending. * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved. * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for * internal operations or return parameters. * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its * config file. */ TSS2_RC Fapi_Provision_Async( FAPI_CONTEXT *context, char const *authValueEh, char const *authValueSh, char const *authValueLockout) { LOG_TRACE("called for context:%p", context); LOG_TRACE("authValueEh: %s", authValueEh); LOG_TRACE("authValueSh: %s", authValueSh); LOG_TRACE("authValueLockout: %s", authValueLockout); TSS2_RC r; /* Check for NULL parameters */ check_not_null(context); /* Helpful alias pointers */ IFAPI_Provision * command = &context->cmd.Provision; r = ifapi_session_init(context); goto_if_error(r, "Initialize Provision", end); /* Initialize context and duplicate parameters */ strdup_check(command->authValueLockout, authValueLockout, r, end); strdup_check(command->authValueEh, authValueEh, r, end); strdup_check(command->authValueSh, authValueSh, r, end); context->ek_handle = ESYS_TR_NONE; context->srk_handle = ESYS_TR_NONE; command->cert_nv_idx = MIN_EK_CERT_HANDLE; command->capabilityData = NULL; /* Set the initial state for the finish method. */ context->state = PROVISION_READ_PROFILE; LOG_TRACE("finished"); return TSS2_RC_SUCCESS; end: SAFE_FREE(command->authValueLockout); SAFE_FREE(command->authValueEh); SAFE_FREE(command->authValueSh); return r; } /** Asynchronous finish function for Fapi_Provision * * This function should be called after a previous Fapi_Provision_Async. * * @param[in,out] context The FAPI_CONTEXT * * @retval TSS2_RC_SUCCESS: if the function call was a success. * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL. * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected. * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous * operation already pending. * @retval TSS2_FAPI_RC_NO_CERT: if no certificate was found for the computed EK. * @retval TSS2_FAPI_RC_BAD_KEY: if public key of the EK does not match the * configured certificate or the configured fingerprint does not match * the computed EK. * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved. * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for * internal operations or return parameters. * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet * complete. Call this function again later. * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into * the function. * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback * is not set. * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails. * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred. * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest * was not successful. * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found * during authorization. * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found. * @retval TSS2_ESYS_RC_* possible error codes of ESAPI. */ TSS2_RC Fapi_Provision_Finish(FAPI_CONTEXT *context) { LOG_TRACE("called for context:%p", context); TSS2_RC r = TSS2_RC_SUCCESS; TPM2B_NV_PUBLIC *nvPublic = NULL; uint8_t *certData = NULL; size_t certSize; TPMI_YES_NO moreData; size_t hash_size; TPMI_ALG_HASH hash_alg; TPM2B_DIGEST ek_fingerprint; /* Check for NULL parameters */ check_not_null(context); /* Helpful alias pointers */ IFAPI_Provision * command = &context->cmd.Provision; IFAPI_OBJECT *hierarchy = &command->hierarchy; TPMS_CAPABILITY_DATA **capabilityData = &command->capabilityData; IFAPI_NV_Cmds * nvCmd = &context->nv_cmd; IFAPI_OBJECT * pkeyObject = &context->createPrimary.pkey_object; IFAPI_KEY * pkey = &pkeyObject->misc.key; IFAPI_PROFILE * defaultProfile = &context->profiles.default_profile; int curl_rc; switch (context->state) { statecase(context->state, PROVISION_READ_PROFILE); /* * The default values used for profiling will be used from * the default profile. */ command->root_crt = NULL; /* Generate template for SRK creation. */ r = ifapi_set_key_flags(defaultProfile->srk_template, context->profiles.default_profile.srk_policy ? true : false, &command->public_templ); goto_if_error(r, "Set key flags for SRK", error_cleanup); r = ifapi_merge_profile_into_template(&context->profiles.default_profile, &command->public_templ); goto_if_error(r, "Merging profile and template", error_cleanup); /* Prepare the setting of the dictionary attack parameters. */ r = Esys_DictionaryAttackParameters_Async(context->esys, ESYS_TR_RH_LOCKOUT, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, defaultProfile->newMaxTries, defaultProfile->newRecoveryTime, defaultProfile->lockoutRecovery); goto_if_error(r, "Error Esys_DictionaryAttackParameters", error_cleanup); fallthrough; statecase(context->state, PROVISION_WRITE_LOCKOUT_PARAM); r = Esys_DictionaryAttackParameters_Finish(context->esys); return_try_again(r); goto_if_error_reset_state(r, "DictionaryAttackParameters_Finish", error_cleanup); /* Prepare the command for reading the TPMs PCR capabilities. */ r = Esys_GetCapability_Async(context->esys, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_PCRS, 0, 1); goto_if_error(r, "Esys_GetCapability_Async", error_cleanup); fallthrough; statecase(context->state, PROVISION_WAIT_FOR_GET_CAP1); r = Esys_GetCapability_Finish(context->esys, &moreData, capabilityData); return_try_again(r); goto_if_error_reset_state(r, "GetCapablity_Finish", error_cleanup); /* Check whether the TPMs PCR capabilities are compatible with the profile. */ TPML_PCR_SELECTION pcr_capability = (*capabilityData)->data.assignedPCR; r = ifapi_check_profile_pcr_selection(&defaultProfile->pcr_selection, &pcr_capability); goto_if_error(r, "Invalid PCR selection in profile.", error_cleanup); SAFE_FREE(*capabilityData); fallthrough; statecase(context->state, PROVISION_INIT_SRK); /* Clear key object for the primary to be created */ memset(pkey, 0, sizeof(IFAPI_KEY)); /* Prepare the SRK generation. */ r = ifapi_init_primary_async(context, TSS2_SRK); goto_if_error(r, "Initialize primary", error_cleanup); context->state = PROVISION_AUTH_SRK_NO_AUTH_SENT; fallthrough; statecase(context->state, PROVISION_AUTH_SRK_AUTH_SENT); fallthrough; statecase(context->state, PROVISION_AUTH_SRK_NO_AUTH_SENT); r = ifapi_init_primary_finish(context, TSS2_SRK); return_try_again(r); goto_if_error(r, "Init primary finish.", error_cleanup); /* Check whether a persistent SRK handle was defined in profile. */ if (command->public_templ.persistent_handle) { /* Assign found handle to object */ pkey->persistent_handle = command->public_templ.persistent_handle; /* Initialize hierarchy object used for evict control. */ ifapi_init_hierarchy_object(hierarchy, ESYS_TR_RH_OWNER); /* Prepare making the SRK permanent. */ r = Esys_EvictControl_Async(context->esys, hierarchy->handle, pkeyObject->handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, pkey->persistent_handle); goto_if_error(r, "Error Esys EvictControl", error_cleanup); context->state = PROVISION_WAIT_FOR_SRK_PERSISTENT; return TSS2_FAPI_RC_TRY_AGAIN; } /* No further ESYS command is needed, the keystore object can be written. */ context->state = PROVISION_SRK_WRITE_PREPARE; fallthrough; statecase(context->state, PROVISION_SRK_WRITE_PREPARE); pkeyObject->objectType = IFAPI_KEY_OBJ; pkeyObject->system = command->public_templ.system; /* Perform esys serialization if necessary */ r = ifapi_esys_serialize_object(context->esys, pkeyObject); goto_if_error(r, "Prepare serialization", error_cleanup); /* Start writing the SRK to the key store */ r = ifapi_keystore_store_async(&context->keystore, &context->io, "HS/SRK", pkeyObject); goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup, "HS/SRK"); context->state = PROVISION_SRK_WRITE; fallthrough; statecase(context->state, PROVISION_SRK_WRITE); /* Finish writing the SRK to the key store */ r = ifapi_keystore_store_finish(&context->keystore, &context->io); return_try_again(r); goto_if_error_reset_state(r, "write_finish failed", error_cleanup); /* Clean objects used for SRK computation */ ifapi_cleanup_ifapi_object(pkeyObject); memset(&command->public_templ, 0, sizeof(IFAPI_KEY_TEMPLATE)); /* Generate template for EK creation. */ r = ifapi_set_key_flags(defaultProfile->ek_template, context->profiles.default_profile.ek_policy ? true : false, &command->public_templ); goto_if_error(r, "Set key flags for SRK", error_cleanup); r = ifapi_merge_profile_into_template(&context->profiles.default_profile, &command->public_templ); goto_if_error(r, "Merging profile", error_cleanup); /* Clear key object for the primary to be created */ memset(pkey, 0, sizeof(IFAPI_KEY)); /* Prepare the EK generation. */ r = ifapi_init_primary_async(context, TSS2_EK); goto_if_error(r, "Initialize primary", error_cleanup); fallthrough; statecase(context->state, PROVISION_AUTH_EK_AUTH_SENT); fallthrough; statecase(context->state, PROVISION_AUTH_EK_NO_AUTH_SENT); r = ifapi_init_primary_finish(context, TSS2_EK); return_try_again(r); goto_if_error(r, "Init primary finish", error_cleanup); /* Check whether a persistent EK handle was defined in profile. */ if (command->public_templ.persistent_handle) { /* Initialize hierarchy object used for EK processing. */ ifapi_init_hierarchy_object(hierarchy, ESYS_TR_RH_OWNER); pkey->persistent_handle = command->public_templ.persistent_handle; /* Prepare making the EK permanent. */ r = Esys_EvictControl_Async(context->esys, hierarchy->handle, pkeyObject->handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, pkey->persistent_handle); goto_if_error(r, "Error Esys EvictControl", error_cleanup); context->state = PROVISION_WAIT_FOR_EK_PERSISTENT; return TSS2_FAPI_RC_TRY_AGAIN; } fallthrough; statecase(context->state, PROVISION_INIT_GET_CAP2); if (context->config.ek_cert_less == TPM2_YES) { /* Skip certificate validation. */ context->state = PROVISION_EK_WRITE_PREPARE; return TSS2_FAPI_RC_TRY_AGAIN; } /* Check whether fingerprint for EK is defined in config file. */ hash_alg = context->config.ek_fingerprint.hashAlg; if (hash_alg) { LOG_DEBUG("Only fingerprint check for EK."); if (!(hash_size =ifapi_hash_get_digest_size(hash_alg))) { goto_error(r, TSS2_ESYS_RC_NOT_IMPLEMENTED, "Unsupported hash algorithm (%" PRIu16 ")", error_cleanup, hash_alg); } r = ifapi_get_tpm_key_fingerprint(&pkeyObject->misc.key.public, hash_alg, &ek_fingerprint); goto_if_error_reset_state(r, "Get fingerprint of EK", error_cleanup); if (hash_size != ek_fingerprint.size || memcmp(&context->config.ek_fingerprint.digest, &ek_fingerprint.buffer[0], hash_size) != 0) { goto_error(r, TSS2_FAPI_RC_BAD_KEY, "Fingerprint of EK not equal to fingerprint in config file.", error_cleanup); } /* The fingerprint was found no further certificate processing needed. */ context->state = PROVISION_EK_WRITE_PREPARE; return TSS2_FAPI_RC_TRY_AGAIN; } /* Check whether EK certificate has to be retrieved */ if (context->config.ek_cert_file) { size_t cert_size; TPM2B_PUBLIC public_key; /* Curl will be used to retrieve the certificate from a file or via HTTP. */ curl_rc = ifapi_get_curl_buffer((unsigned char *)context->config.ek_cert_file, (unsigned char **)&command->pem_cert, &cert_size); if (curl_rc != 0) { goto_error_reset_state(r, TSS2_FAPI_RC_NO_CERT, "Get certificate.", error_cleanup); } /* Get the public key from the certificate. */ r = ifapi_get_public_from_pem_cert(command->pem_cert, &public_key); goto_if_error_reset_state(r, "Get public key from pem certificate", error_cleanup); /* Compare public key of certificate with public data of EK */ if (ifapi_cmp_public_key(&pkeyObject->misc.key.public, &public_key)) { /* The retrieved certificate will be written to keystore, no further certificate processing needed. */ context->state = PROVISION_EK_WRITE_PREPARE; return TSS2_FAPI_RC_TRY_AGAIN; } goto_error(r, TSS2_FAPI_RC_BAD_KEY, "Public key of EK does not match certificate.", error_cleanup); } /* Prepare the search for certificates store in the NV ram of the TPM. */ r = Esys_GetCapability_Async(context->esys, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_HANDLES, MIN_EK_CERT_HANDLE, TPM2_MAX_CAP_HANDLES); goto_if_error(r, "Esys_GetCapability_Async", error_cleanup); fallthrough; statecase(context->state, PROVISION_WAIT_FOR_GET_CAP2); r = Esys_GetCapability_Finish(context->esys, &moreData, capabilityData); return_try_again(r); goto_if_error_reset_state(r, "GetCapablity_Finish", error_cleanup); if ((*capabilityData)->data.handles.count == 0) { /* No more certificate, the EK can be compared with the certificates. */ Esys_Free(*capabilityData); context->state = PROVISION_CHECK_FOR_VENDOR_CERT; return TSS2_FAPI_RC_TRY_AGAIN; } command->capabilityData = *capabilityData; command->cert_count = (*capabilityData)->data.handles.count; /* Filter out NV handles beyond the EK cert range */ for (size_t i = 0; i < command->cert_count; i++) { if (command->capabilityData->data.handles.handle[i] > EK_CERT_RANGE) { command->cert_count = i; } } if (command->cert_count == 0) { /* No certificates were found the cert range. */ Esys_Free(command->capabilityData); command->capabilityData = NULL; context->state = PROVISION_CHECK_FOR_VENDOR_CERT; return TSS2_FAPI_RC_TRY_AGAIN; } fallthrough; statecase(context->state, PROVISION_GET_CERT_NV); /* Detemine the NV index of the certifcate from the read capability data. */ command->cert_nv_idx = command->capabilityData->data.handles.handle[command->cert_count-1]; if ((command->cert_nv_idx % 2) || /**< Certificates will be stored at even address */ command->cert_nv_idx == 0x01c00004 || /**< RSA template */ command->cert_nv_idx == 0x01c0000c) { /**< ECC template */ if (command->cert_count > 1) { command->cert_count -= 1; /* Check next certificate */ context->state = PROVISION_GET_CERT_NV; return TSS2_FAPI_RC_TRY_AGAIN; } else { /* All certificates have been read, the EK can be written. */ context->state = PROVISION_EK_WRITE_PREPARE; return TSS2_FAPI_RC_TRY_AGAIN; } } ifapi_init_hierarchy_object(&nvCmd->auth_object, TPM2_RH_OWNER); /* Create esys object for the NV object of the certificate. */ r = Esys_TR_FromTPMPublic_Async(context->esys, command->cert_nv_idx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE); goto_if_error_reset_state(r, "Esys_TR_FromTPMPublic_Async", error_cleanup); context->state = PROVISION_GET_CERT_NV_FINISH; fallthrough; statecase(context->state, PROVISION_GET_CERT_NV_FINISH); r = Esys_TR_FromTPMPublic_Finish(context->esys, &command->esys_nv_cert_handle); return_try_again(r); goto_if_error_reset_state(r, "TR_FromTPMPublic_Finish", error_cleanup); /* Read public to get size of certificate */ r = Esys_NV_ReadPublic_Async(context->esys, command->esys_nv_cert_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE); goto_if_error_reset_state(r, "Esys_NV_ReadPublic_Async", error_cleanup); context->state = PROVISION_GET_CERT_READ_PUBLIC; fallthrough; statecase(context->state, PROVISION_GET_CERT_READ_PUBLIC); r = Esys_NV_ReadPublic_Finish(context->esys, &nvPublic, NULL); return_try_again(r); goto_if_error(r, "Error: nv read public", error_cleanup); /* TPMA_NV_NO_DA is set for NV certificate */ nvCmd->nv_object.misc.nv.public.nvPublic.attributes = TPMA_NV_NO_DA; /* Prepare context for nv read */ nvCmd->data_idx = 0; nvCmd->auth_index = ESYS_TR_RH_OWNER; nvCmd->numBytes = nvPublic->nvPublic.dataSize; nvCmd->esys_handle = command->esys_nv_cert_handle; nvCmd->offset = 0; command->pem_cert = NULL; context->session1 = ESYS_TR_PASSWORD; context->session2 = ESYS_TR_NONE; nvCmd->nv_read_state = NV_READ_INIT; memset(&nvCmd->nv_object, 0, sizeof(IFAPI_OBJECT)); SAFE_FREE(nvPublic); context->state = PROVISION_READ_CERT; fallthrough; statecase(context->state, PROVISION_READ_CERT); TPM2B_PUBLIC public_key; char * root_ca_file; /* The NV object of the certificate will be read asynchronous. */ r = ifapi_nv_read(context, &certData, &certSize); return_try_again(r); goto_if_error_reset_state(r, " FAPI NV_Read", error_cleanup); /* For storage in key store the certificate will be converted to PEM. */ r = ifapi_cert_to_pem(certData, certSize, &command->pem_cert, &command->cert_key_type, &public_key); SAFE_FREE(certData); goto_if_error(r, "Convert certificate to pem.", error_cleanup); /* Check whether the EKs public key corresponds to the certificate. */ if (ifapi_cmp_public_key(&pkeyObject->misc.key.public, &public_key)) { context->state = PROVISION_PREPARE_READ_ROOT_CERT; return TSS2_FAPI_RC_TRY_AGAIN; } else { /* Certificate not appropriate for current EK key type */ command->cert_count -= 1; SAFE_FREE(command->pem_cert); if (command->cert_count > 0) { /* Check next certificate */ context->state = PROVISION_GET_CERT_NV; return TSS2_FAPI_RC_TRY_AGAIN; } } goto_error(r, TSS2_FAPI_RC_NO_CERT, "No EK certificate found.", error_cleanup); statecase(context->state, PROVISION_PREPARE_READ_ROOT_CERT); /* Prepare reading of root certificate. */ root_ca_file = getenv("FAPI_TEST_ROOT_CERT"); if (!root_ca_file) { context->state = PROVISION_EK_CHECK_CERT; return TSS2_FAPI_RC_TRY_AGAIN; } r = ifapi_io_read_async(&context->io, root_ca_file); return_try_again(r); goto_if_error2(r, "Reading certificate %s", error_cleanup, root_ca_file); fallthrough; statecase(context->state, PROVISION_READ_ROOT_CERT); r = ifapi_io_read_finish(&context->io, (uint8_t **) &command->root_crt, NULL); return_try_again(r); goto_if_error(r, "Reading root certificate failed", error_cleanup); fallthrough; statecase(context->state, PROVISION_EK_CHECK_CERT); /* The EK certificate will be verified against the FAPI list of root certificates. */ r = ifapi_verify_ek_cert(command->root_crt, command->intermed_crt, command->pem_cert); SAFE_FREE(command->root_crt); SAFE_FREE(command->intermed_crt); goto_if_error2(r, "Verify EK certificate", error_cleanup); fallthrough; statecase(context->state, PROVISION_EK_WRITE_PREPARE); pkeyObject->objectType = IFAPI_KEY_OBJ; pkeyObject->system = command->public_templ.system; strdup_check(pkeyObject->misc.key.certificate, command->pem_cert, r, error_cleanup); SAFE_FREE(command->pem_cert); /* Perform esys serialization if necessary */ r = ifapi_esys_serialize_object(context->esys, pkeyObject); goto_if_error(r, "Prepare serialization", error_cleanup); /* Start writing the EK to the key store */ r = ifapi_keystore_store_async(&context->keystore, &context->io, "HE/EK", pkeyObject); goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup, "HE/EK"); fallthrough; statecase(context->state, PROVISION_EK_WRITE); /* Finish writing the EK to the key store */ r = ifapi_keystore_store_finish(&context->keystore, &context->io); return_try_again(r); goto_if_error_reset_state(r, "write_finish failed", error_cleanup); /* Clean objects used for EK computation */ ifapi_cleanup_ifapi_object(pkeyObject); memset(&command->public_templ, 0, sizeof(IFAPI_KEY_TEMPLATE)); SAFE_FREE(hierarchy->misc.hierarchy.description); /* * Adaption of the lockout hierarchy to the passed parameters * and the current profile. */ ifapi_init_hierarchy_object(hierarchy, ESYS_TR_RH_LOCKOUT); strdup_check(hierarchy->misc.hierarchy.description, "Lockout Hierarchy", r, error_cleanup); if (!command->authValueLockout || strcmp(command->authValueLockout, "") == 0) { context->state = PROVISION_LOCKOUT_CHANGE_POLICY; /* Auth value of lockout hierarchy will not be changed. */ return TSS2_FAPI_RC_TRY_AGAIN; } if (strlen(command->authValueLockout) > sizeof(TPMU_HA)) { goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Password too long.", error_cleanup); } /* Copy auth value into context. */ memcpy(&command->hierarchy_auth.buffer[0], command->authValueLockout, strlen(command->authValueLockout)); command->hierarchy_auth.size = strlen(command->authValueLockout); context->state = PROVISION_CHANGE_LOCKOUT_AUTH; return TSS2_FAPI_RC_TRY_AGAIN; statecase(context->state, PROVISION_WAIT_FOR_SRK_PERSISTENT); r = Esys_EvictControl_Finish(context->esys, &pkeyObject->handle); return_try_again(r); goto_if_error(r, "Evict control failed", error_cleanup); /* The SRK was made persistent and can be written to key store. */ context->state = PROVISION_SRK_WRITE_PREPARE; return TSS2_FAPI_RC_TRY_AGAIN; statecase(context->state, PROVISION_WAIT_FOR_EK_PERSISTENT); r = Esys_EvictControl_Finish(context->esys, &pkeyObject->handle); return_try_again(r); goto_if_error(r, "Evict control failed", error_cleanup); context->state = PROVISION_INIT_GET_CAP2; return TSS2_FAPI_RC_TRY_AGAIN; statecase(context->state, PROVISION_CHANGE_LOCKOUT_AUTH); /* If a lockout auth value is provided by profile, the auth value if the hierarchy will be changed asynchronous. */ r = ifapi_change_auth_hierarchy(context, ESYS_TR_RH_LOCKOUT, &command->hierarchy, &command->hierarchy_auth); return_try_again(r); goto_if_error(r, "Change auth hierarchy.", error_cleanup); context->state = PROVISION_LOCKOUT_CHANGE_POLICY; fallthrough; statecase(context->state, PROVISION_LOCKOUT_CHANGE_POLICY); /* If a lockout policy is provided by profile, the policy will be assigned to lockout hierarchy asynchronous. */ r = ifapi_change_policy_hierarchy(context, ESYS_TR_RH_LOCKOUT, hierarchy, defaultProfile->lockout_policy); return_try_again(r); goto_if_error(r, "Change policy LOCKOUT", error_cleanup); /* Start writing the lockout hierarchy object to the key store */ r = ifapi_keystore_store_async(&context->keystore, &context->io, "/LOCKOUT", &command->hierarchy); goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup, "/LOCKOUT"); context->state = PROVISION_WRITE_LOCKOUT; fallthrough; statecase(context->state, PROVISION_WRITE_LOCKOUT); /* Finish writing the lockout hierarchy to the key store */ r = ifapi_keystore_store_finish(&context->keystore, &context->io); return_try_again(r); goto_if_error_reset_state(r, "write_finish failed", error_cleanup); SAFE_FREE(hierarchy->misc.hierarchy.description); /* * Adaption of the Endorsement hierarchy to the passed parameters * and the current profile. */ ifapi_init_hierarchy_object(hierarchy, ESYS_TR_RH_ENDORSEMENT); strdup_check(hierarchy->misc.hierarchy.description, "Endorsement Hierarchy", r, error_cleanup); context->state = PROVISION_CHANGE_EH_CHECK; fallthrough; statecase(context->state, PROVISION_CHANGE_EH_CHECK); if (command->authValueEh) { context->state = PROVISION_CHANGE_EH_AUTH; /* Save auth value of endorsement hierarchy in context. */ memcpy(&command->hierarchy_auth.buffer[0], command->authValueEh, strlen(command->authValueEh)); command->hierarchy_auth.size = strlen(command->authValueEh); } else { /* Auth value of lockout hierarchy will not be changed. */ context->state = PROVISION_EH_CHANGE_POLICY; return TSS2_FAPI_RC_TRY_AGAIN; } context->state = PROVISION_CHANGE_EH_AUTH; fallthrough; statecase(context->state, PROVISION_CHANGE_EH_AUTH); /* If an endorsement hierarchy auth value is provided by profile, the auth value will be changed asynchronous. */ r = ifapi_change_auth_hierarchy(context, ESYS_TR_RH_ENDORSEMENT, &command->hierarchy, &command->hierarchy_auth); return_try_again(r); goto_if_error(r, "Change auth hierarchy.", error_cleanup); context->state = PROVISION_EH_CHANGE_POLICY; fallthrough; statecase(context->state, PROVISION_EH_CHANGE_POLICY); /* If an endorsement hierarchy policy is provided by profile, the policy will be assigned asynchronous. */ r = ifapi_change_policy_hierarchy(context, ESYS_TR_RH_ENDORSEMENT, hierarchy, defaultProfile->eh_policy); return_try_again(r); goto_if_error(r, "Change policy EH", error_cleanup); /* Start writing the endorsement hierarchy object to the key store */ r = ifapi_keystore_store_async(&context->keystore, &context->io, "/HE", &command->hierarchy); goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup, "/HE"); context->state = PROVISION_WRITE_EH; fallthrough; statecase(context->state, PROVISION_WRITE_EH); /* Finish writing the endorsement hierarchy to the key store */ r = ifapi_keystore_store_finish(&context->keystore, &context->io); return_try_again(r); return_if_error_reset_state(r, "write_finish failed"); SAFE_FREE(hierarchy->misc.hierarchy.description); /* * Adaption of the owner hierarchy to the passed parameters * and the current profile. */ ifapi_init_hierarchy_object(hierarchy, ESYS_TR_RH_OWNER); strdup_check(hierarchy->misc.hierarchy.description, "Owner Hierarchy", r, error_cleanup); context->state = PROVISION_CHANGE_SH_CHECK; fallthrough; statecase(context->state, PROVISION_CHANGE_SH_CHECK); if (command->authValueSh) { context->state = PROVISION_CHANGE_SH_AUTH; /* Save auth value of owner hierarchy in context. */ memcpy(&command->hierarchy_auth.buffer[0], command->authValueSh, strlen(command->authValueSh)); command->hierarchy_auth.size = strlen(command->authValueSh); context->state = PROVISION_CHANGE_SH_AUTH; } else { /* Auth value of owner hierarchy will not be changed. */ context->state = PROVISION_SH_CHANGE_POLICY; return TSS2_FAPI_RC_TRY_AGAIN; } context->state = PROVISION_CHANGE_SH_AUTH; fallthrough; statecase(context->state, PROVISION_CHANGE_SH_AUTH); /* If an owner hierarchy auth value is provided by profile, the auth value will be changed asynchronous. */ r = ifapi_change_auth_hierarchy(context, ESYS_TR_RH_OWNER, &command->hierarchy, &command->hierarchy_auth); return_try_again(r); goto_if_error(r, "Change auth hierarchy.", error_cleanup); context->state = PROVISION_SH_CHANGE_POLICY; fallthrough; statecase(context->state, PROVISION_SH_CHANGE_POLICY); /* If an owner hierarchy policy is provided by profile, the policy will be assigned asynchronous. */ r = ifapi_change_policy_hierarchy(context, ESYS_TR_RH_OWNER, hierarchy, defaultProfile->sh_policy); return_try_again(r); goto_if_error(r, "Change policy SH", error_cleanup); /* Start writing the owner hierarchy object to the key store */ r = ifapi_keystore_store_async(&context->keystore, &context->io, "/HS", &command->hierarchy); goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup, "/HS"); context->state = PROVISION_WRITE_SH; fallthrough; statecase(context->state, PROVISION_WRITE_SH); /* The onwer hierarchy object will be written to key store. */ r = ifapi_keystore_store_finish(&context->keystore, &context->io); return_try_again(r); goto_if_error_reset_state(r, "write_finish failed", error_cleanup); fallthrough; statecase(context->state, PROVISION_FINISHED); if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) { /* Prepare the flushing of a non persistent SRK. */ r = Esys_FlushContext_Async(context->esys, context->srk_handle); goto_if_error(r, "Flush SRK", error_cleanup); } fallthrough; /* Flush the SRK if not persistent */ statecase(context->state, PROVISION_FLUSH_SRK); if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) { r = Esys_FlushContext_Finish(context->esys); try_again_or_error_goto(r, "Flush SRK", error_cleanup); context->srk_handle = ESYS_TR_NONE; } if (!context->ek_persistent && context->ek_handle != ESYS_TR_NONE) { /* Prepare the flushing of a non persistent EK. */ r = Esys_FlushContext_Async(context->esys, context->ek_handle); goto_if_error(r, "Flush EK", error_cleanup); } fallthrough; /* Flush the EK if not persistent */ statecase(context->state, PROVISION_FLUSH_EK); if (!context->ek_persistent && context->ek_handle != ESYS_TR_NONE) { r = Esys_FlushContext_Finish(context->esys); try_again_or_error_goto(r, "Flush EK", error_cleanup); context->ek_handle = ESYS_TR_NONE; } context->state = _FAPI_STATE_INIT; break; /* * The vendor ID stored in the TPM has to be read to check whether * a special certificate handling is needed. */ statecase(context->state, PROVISION_CHECK_FOR_VENDOR_CERT); /* Prepare reading the vendor ID */ r = Esys_GetCapability_Async(context->esys, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_TPM_PROPERTIES, TPM2_PT_MANUFACTURER, 1); goto_if_error(r, "Esys_GetCapability_Async", error_cleanup); fallthrough; statecase(context->state, PROVISION_GET_VENDOR); /* Get the vendor ID asynchronous. */ r = Esys_GetCapability_Finish(context->esys, &moreData, capabilityData); return_try_again(r); goto_if_error_reset_state(r, "GetCapablity_Finish", error_cleanup); if ((*capabilityData)->data.tpmProperties.tpmProperty[0].value == VENDOR_INTC) { /* Get INTEL certificate for EK public hash via web */ uint8_t *cert_buffer = NULL; size_t cert_size; TPM2B_PUBLIC public; r = ifapi_get_intl_ek_certificate(context, &pkey->public, &cert_buffer, &cert_size); goto_if_error_reset_state(r, "Get certificates", error_cleanup); r = ifapi_cert_to_pem(cert_buffer, cert_size, &command->pem_cert, NULL, &public); SAFE_FREE(cert_buffer); goto_if_error_reset_state(r, "Convert certificate buffer to PEM.", error_cleanup); } SAFE_FREE(*capabilityData); context->state = PROVISION_EK_WRITE_PREPARE; return TSS2_FAPI_RC_TRY_AGAIN; statecasedefault(context->state); } error_cleanup: /* Primaries might not have been flushed in error cases */ ifapi_primary_clean(context); SAFE_FREE(command->root_crt); SAFE_FREE(*capabilityData); SAFE_FREE(hierarchy->misc.hierarchy.description); SAFE_FREE(command->authValueLockout); SAFE_FREE(command->authValueEh); SAFE_FREE(command->authValueSh); SAFE_FREE(command->pem_cert); SAFE_FREE(certData); SAFE_FREE(nvPublic); LOG_TRACE("finished"); return r; }