/* 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 "tss2_mu.h" #include "fapi_util.h" #include "fapi_crypto.h" //#include "fapi_policy.h" #include "ifapi_policy_execute.h" #include "ifapi_policyutil_execute.h" #include "ifapi_helpers.h" #include "ifapi_json_deserialize.h" #include "tpm_json_deserialize.h" #include "ifapi_policy_callbacks.h" #include "ifapi_policyutil_execute.h" #define LOGMODULE fapi #include "util/log.h" #include "util/aux_util.h" /** Create a new policy on policy stack. * * The structures for policy and callback execution are allocated * and the callbacks are assigned. * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. */ static TSS2_RC new_policy( FAPI_CONTEXT *context, TPMS_POLICY *policy, IFAPI_POLICYUTIL_STACK **current_policy) { LOG_DEBUG("ADD POLICY"); IFAPI_POLICY_EXEC_CTX *pol_exec_ctx; IFAPI_POLICY_EXEC_CB_CTX *pol_exec_cb_ctx; *current_policy = calloc(sizeof(IFAPI_POLICYUTIL_STACK), 1); if (!*current_policy) { return_error(TSS2_FAPI_RC_MEMORY, "Out of memory"); } pol_exec_ctx = calloc(sizeof(IFAPI_POLICY_EXEC_CTX), 1); if (!pol_exec_ctx) { return_error(TSS2_FAPI_RC_MEMORY, "Out of memory"); } (*current_policy)->pol_exec_ctx = pol_exec_ctx; pol_exec_ctx->callbacks.cbauth = ifapi_policyeval_cbauth; pol_exec_ctx->callbacks.cbauth_userdata = context; pol_exec_ctx->callbacks.cbpolsel = ifapi_branch_selection; pol_exec_ctx->callbacks.cbpolsel_userdata = context; pol_exec_ctx->callbacks.cbsign = ifapi_sign_buffer; pol_exec_ctx->callbacks.cbsign_userdata = context; pol_exec_ctx->callbacks.cbauthpol = ifapi_exec_auth_policy; pol_exec_ctx->callbacks.cbauthpol_userdata = context; pol_exec_ctx->callbacks.cbauthnv = ifapi_exec_auth_nv_policy; pol_exec_ctx->callbacks.cbauthnv_userdata = context; pol_exec_ctx->callbacks.cbdup = ifapi_get_duplicate_name; pol_exec_ctx->callbacks.cbdup_userdata = context; pol_exec_ctx->callbacks.cbaction = ifapi_policy_action; pol_exec_ctx->callbacks.cbaction_userdata = context; pol_exec_cb_ctx = calloc(sizeof(IFAPI_POLICY_EXEC_CB_CTX), 1); if (!pol_exec_cb_ctx) { return_error(TSS2_FAPI_RC_MEMORY, "Out of memory"); } pol_exec_ctx->app_data = pol_exec_cb_ctx; pol_exec_ctx->policy = policy; if (!context->policy.policyutil_stack) { context->policy.policyutil_stack = *current_policy; context->policy.util_current_policy = *current_policy; } else { context->policy.util_current_policy->next = *current_policy; (*current_policy)->prev = context->policy.util_current_policy; } return TSS2_RC_SUCCESS; } /** Compute a new session which will be uses as policy session. * @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_GENERAL_FAILURE if an internal error occurred. * @retval TSS2_ESYS_RC_* possible error codes of ESAPI. */ static TSS2_RC create_session( FAPI_CONTEXT *context, ESYS_TR *session, TPMI_ALG_HASH hash_alg) { TSS2_RC r = TSS2_RC_SUCCESS; switch (context->policy.create_session_state) { case CREATE_SESSION_INIT: r = Esys_StartAuthSession_Async(context->esys, context->srk_handle ? context->srk_handle : ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, NULL, TPM2_SE_POLICY, &context->profiles.default_profile.session_symmetric, hash_alg); return_if_error(r, "Creating session."); context->policy.create_session_state = WAIT_FOR_CREATE_SESSION; return TSS2_FAPI_RC_TRY_AGAIN; case WAIT_FOR_CREATE_SESSION: r = Esys_StartAuthSession_Finish(context->esys, session); if (r != TSS2_RC_SUCCESS) return r; context->policy.create_session_state = CREATE_SESSION_INIT; break; default: context->state = _FAPI_STATE_INTERNALERROR; goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Invalid state for create session.", cleanup); } cleanup: return r; } /** Cleanup the current policy and adapt the policy stack. * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred. */ static TSS2_RC clear_current_policy(FAPI_CONTEXT *context) { LOG_DEBUG("CLEAR POLICY"); IFAPI_POLICYUTIL_STACK *prev_pol; if (!context->policy.util_current_policy) { return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "No current policy."); } prev_pol = context->policy.util_current_policy->prev; SAFE_FREE(context->policy.util_current_policy->pol_exec_ctx->app_data); SAFE_FREE(context->policy.util_current_policy->pol_exec_ctx); SAFE_FREE(context->policy.util_current_policy); if (!prev_pol) { context->policy.policyutil_stack = NULL; } else { prev_pol->next = NULL; } return TSS2_RC_SUCCESS; } /** Cleanup the policy stack. * * Will be used if an error occurs. */ static void clear_all_policies(FAPI_CONTEXT *context) { LOG_DEBUG("CLEAR ALL POLICIES"); IFAPI_POLICYUTIL_STACK *policy = context->policy.policyutil_stack; IFAPI_POLICYUTIL_STACK *next_policy; while (policy) { next_policy = policy->next; SAFE_FREE(policy->pol_exec_ctx->app_data); if (policy->pol_exec_ctx->session) Esys_FlushContext(context->esys, policy->pol_exec_ctx->session); SAFE_FREE(policy->pol_exec_ctx); ; SAFE_FREE(policy); policy = next_policy; } context->policy.policyutil_stack = NULL; } /** Prepare the execution of a new policy on policy stack. * * The context for the policy utility, the policy execution and the needed * callbacks is initialized. * The policy execution will be prepared. In this step the list of policies * to be executed will be computed. * @param[in,out] context The fapi context with the pointer to the policy stack. * @param[in] hash_alg The hash algorithm used for the policy computation. * @param[in,out] policy The policy to be executed. Some policy elements will * be used to store computed parameters needed for policy * execution. * @retval TSS2_RC_SUCCESS on success. * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN If the callback for branch selection is * not defined. This callback will be needed of or policies have to be * executed. * @retval TSS2_FAPI_RC_BAD_VALUE If the computed branch index deliverd by the * callback does not identify a branch. * @retval TSS2_FAPI_RC_BAD_REFERENCE If no context is passed. * * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails. * @retval TSS2_ESYS_RC_* possible error codes of ESAPI. */ TSS2_RC ifapi_policyutil_execute_prepare( FAPI_CONTEXT *context, TPMI_ALG_HASH hash_alg, TPMS_POLICY *policy) { TSS2_RC r; IFAPI_POLICYUTIL_STACK *current_policy; return_if_null(context, "Bad context.", TSS2_FAPI_RC_BAD_REFERENCE); r = new_policy(context, policy, ¤t_policy); goto_if_error(r, "Create new policy.", error); r = ifapi_policyeval_execute_prepare(current_policy->pol_exec_ctx, hash_alg, policy); goto_if_error(r, "Prepare policy execution.", error); return r; error: while (context->policy.policyutil_stack) { clear_all_policies(context); } SAFE_FREE(current_policy); return r; } /** State machine to Execute the TPM policy commands needed for the current policy. * * In the first step a session will be created if no session is passed. * In the second step the policy engine will execute the policy. * * @param[in,out] context The fapi context with the pointer to the policy stack. * @param[in,out] session The policy session to be extended or if the value is * equal zero or ESYS_TR_NONE a new created session will been * be stored in this parameter. * @retval TSS2_RC_SUCCESS on success. * @retval TSS2_FAPI_RC_MEMORY: if not enough memory can be allocated. * @retval TSS2_FAPI_RC_BAD_VALUE If wrong values are detected during execution. * @retval TSS2_FAPI_RC_IO_ERROR If an error occurs during access to the policy * store. * @retval TSS2_FAPI_RC_POLICY_UNKNOWN If policy search for a certain policy digest was * not successful. * @retval TSS2_FAPI_RC_BAD_TEMPLATE In a invalid policy is loaded during execution. * @retval TPM2_RC_BAD_AUTH If the authentication for an object needed for policy * execution fails. * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred. * @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_SEQUENCE if the context has an asynchronous * operation already pending. * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed. * @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_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_ESYS_RC_* possible error codes of ESAPI. */ TSS2_RC ifapi_policyutil_execute(FAPI_CONTEXT *context, ESYS_TR *session) { TSS2_RC r; IFAPI_POLICYUTIL_STACK *pol_util_ctx; TPMI_ALG_HASH hash_alg; if (context->policy.util_current_policy) { pol_util_ctx = context->policy.util_current_policy->next; context->policy.util_current_policy = context->policy.util_current_policy->next; } else { pol_util_ctx = context->policy.policyutil_stack; context->policy.util_current_policy = pol_util_ctx; } LOG_TRACE("Util context: %p", pol_util_ctx); if (!pol_util_ctx) { return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "No policy util stack."); } switch (pol_util_ctx->state) { statecase(pol_util_ctx->state, POLICY_UTIL_INIT); LOG_DEBUG("Util session: %x", pol_util_ctx->policy_session); if (*session == ESYS_TR_NONE || *session == 0) { /* Create a new policy session for the current policy execution */ hash_alg = pol_util_ctx->pol_exec_ctx->hash_alg; r = create_session(context, &pol_util_ctx->policy_session, hash_alg); if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) { context->policy.util_current_policy = pol_util_ctx->prev; return TSS2_FAPI_RC_TRY_AGAIN; } goto_if_error(r, "Create policy session", error); pol_util_ctx->pol_exec_ctx->session = pol_util_ctx->policy_session; } else { pol_util_ctx->pol_exec_ctx->session = *session; } fallthrough; statecase(pol_util_ctx->state, POLICY_UTIL_EXEC_POLICY); r = ifapi_policyeval_execute(context->esys, pol_util_ctx->pol_exec_ctx); if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) { context->policy.util_current_policy = pol_util_ctx->prev; return TSS2_FAPI_RC_TRY_AGAIN; } goto_if_error(r, "Execute policy.", error); break; statecasedefault(pol_util_ctx->state); } *session = pol_util_ctx->policy_session; pol_util_ctx = pol_util_ctx->prev; r = clear_current_policy(context); goto_if_error(r, "Clear policy.", error); context->policy.util_current_policy = pol_util_ctx; LOG_TRACE("success"); return r; error: while (context->policy.policyutil_stack) { clear_all_policies(context); } return r; }