/* 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_helpers.h" #include "ifapi_policy_instantiate.h" #include "ifapi_json_deserialize.h" #include "tpm_json_deserialize.h" #define LOGMODULE fapi #include "util/log.h" #include "util/aux_util.h" static TSS2_RC get_policy_elements(TPML_POLICYELEMENTS *policy, NODE_OBJECT_T **policy_element_list); /** Compute linked list with a list of policy elements which could be instantiated. * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. */ static TSS2_RC get_policy_elements(TPML_POLICYELEMENTS *policy, NODE_OBJECT_T **policy_element_list) { TSS2_RC r = TSS2_RC_SUCCESS; size_t i, j; for (i = 0; i < policy->count; i++) { if (policy->elements[i].type == POLICYOR) { /* Policy with sub policies */ TPML_POLICYBRANCHES *branches = policy->elements[i].element.PolicyOr.branches; for (j = 0; j < branches->count; j++) { r = get_policy_elements(branches->authorizations[j].policy, policy_element_list); goto_if_error(r, "Get policy elements.", error_cleanup); } } else { r = push_object_to_list(&policy->elements[i], policy_element_list); goto_if_error(r, "Get policy elements.", error_cleanup); } } return r; error_cleanup: ifapi_free_node_list(*policy_element_list); return r; } /** Prepare instantiation a policy template. * * Parts of policies which are referenced by object paths will be replaced with * the appropriate values of the referenced objects. * * @param[in] context The context storing information for re-entry after try again. * @param[in] policy The policy to be instantiated. * @param[in] callbacks The needed callback functions with the corresponding user data * which will be passed to the callback. * @retval TSS2_RC_SUCCESS on success. * @retval FAPI error codes on failure * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. */ TSS2_RC ifapi_policyeval_instantiate_async( IFAPI_POLICY_EVAL_INST_CTX *context, /* For re-entry after try_again for offsets and such */ TPMS_POLICY *policy, /* in */ ifapi_policyeval_INST_CB *callbacks) { TSS2_RC r; /* Store callbacks and their parameters in context */ context->callbacks = *callbacks; /* Compute list of all policy elements which have to be instantiated */ if (context->policy_elements) { ifapi_free_object_list(context->policy_elements); context->policy_elements = NULL; } r = get_policy_elements(policy->policy, &context->policy_elements); return r; } /** Compute name and public information format a PEM key. * * @param[in] keyPEM The key in PEM format. * @param[out] keyPublic The public information of the PEM key. * @param[out] name the name computed from the public information. * @param[in] hash_alg The name alg of the key has to passed. * @retval TSS2_RC_SUCCESS on success. */ static TSS2_RC set_pem_key_param( const char *keyPEM, TPMT_PUBLIC *keyPublic, TPM2B_NAME *name, TPMI_ALG_HASH hash_alg) { TSS2_RC r; TPM2B_PUBLIC public; if (!keyPEM || strlen(keyPEM) == 0) { /* No PEM key used. Parameters are already set in policy. */ return TSS2_RC_SUCCESS; } /* Use PEM key to compute public information and name */ name->size = 0; TPM2_ALG_ID rsaOrEcc = ifapi_get_signature_algorithm_from_pem(keyPEM); r = ifapi_initialize_sign_public(rsaOrEcc, &public); return_if_error(r, "Could not initialize public info of key"); r = ifapi_get_tpm2b_public_from_pem(keyPEM, &public); return_if_error(r, "Invalid PEM key."); *keyPublic = public.publicArea; keyPublic->nameAlg = hash_alg; r = ifapi_get_name(&public.publicArea, name); return_if_error(r, "Compute key name."); return TSS2_RC_SUCCESS; } #define CHECK_TEMPLATE_PATH(path, template) \ if (!path) { \ return_error2(TSS2_FAPI_RC_BAD_TEMPLATE, "No path for policy %s", template); \ } /** Finalize instantiation a policy template. * * All needed asyncroous callbacks will be executed for all policy elements offset * The policy. * * @param[in] context The context storing information for re-entry after try again. * @retval TSS2_RC_SUCCESS on success. * @retval TSS2_FAPI_RC_BAD_TEMPLATE If the templayte is not complete for instantiation. * @retval FAPI error codes on failure * @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_REFERENCE a invalid null pointer is passed. * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into * the function. * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred. * @retval TSS2_FAPI_RC_BAD_SEQUENCE if the context has an asynchronous * operation already pending. * @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_IO_ERROR if an error occurred while accessing the * object store. * @retval TSS2_ESYS_RC_* possible error codes of ESAPI. */ TSS2_RC ifapi_policyeval_instantiate_finish( IFAPI_POLICY_EVAL_INST_CTX *context) { TSS2_RC r = TSS2_RC_SUCCESS; NODE_OBJECT_T *first_in_pol_list = context->policy_elements; size_t i_last; /* While not all policy elements are instantiated */ while (first_in_pol_list) { TPMT_POLICYELEMENT *pol_element = first_in_pol_list->object; switch (pol_element->type) { case POLICYSIGNED: if (pol_element->element.PolicySigned.keyPublic.type) { /* Public info found in template, key path will not be needed. */ SAFE_FREE(pol_element->element.PolicySigned.keyPath); break; } if (pol_element->element.PolicySigned.keyPEM && strlen(pol_element->element.PolicySigned.keyPEM) > 0) { /* Determine name and public info for PEM key. */ r = set_pem_key_param(pol_element->element.PolicySigned.keyPEM, &pol_element->element.PolicySigned.keyPublic, &pol_element->element.PolicySigned.publicKey, pol_element->element.PolicySigned.keyPEMhashAlg); return_if_error(r, "Set parameter of pem key."); /* Clear pem key, will be recreated during execution. */ SAFE_FREE(pol_element->element.PolicySigned.keyPEM); break; } CHECK_TEMPLATE_PATH(pol_element->element.PolicySigned.keyPath, "PolicySigned"); /* Public info will be added to policy. */ r = context->callbacks.cbpublic(pol_element->element.PolicySigned.keyPath, &pol_element->element.PolicySigned.keyPublic, context->callbacks.cbpublic_userdata); return_try_again(r); return_if_error(r, "read_finish failed"); /* Clear keypath, only public data will be needed */ SAFE_FREE(pol_element->element.PolicySigned.keyPath); break; case POLICYNAMEHASH: /* Set index of last name to be computed. */ i_last = pol_element->element.PolicyNameHash.count - 1; while (!pol_element->element.PolicyNameHash.objectNames[i_last].size) { /* Not all object names have been computed or were initialized */ size_t i = pol_element->element.PolicyNameHash.i; r = context->callbacks.cbname(pol_element->element.PolicyNameHash.namePaths[i], &pol_element->element.PolicyNameHash.objectNames[i], context->callbacks.cbname_userdata); return_try_again(r); return_if_error(r, "get object name."); pol_element->element.PolicyNameHash.i++; SAFE_FREE(pol_element->element.PolicyNameHash.namePaths[i]); } break; case POLICYSECRET: if (pol_element->element.PolicySecret.objectName.size) { /* Name found in template, object path will not be needed. */ SAFE_FREE(pol_element->element.PolicySecret.objectPath); break; } CHECK_TEMPLATE_PATH(pol_element->element.PolicySecret.objectPath, "PolicySecret"); /* Object name will be added to policy. */ r = context->callbacks.cbname(pol_element->element.PolicySecret.objectPath, &pol_element->element.PolicySecret.objectName, context->callbacks.cbname_userdata); return_try_again(r); return_if_error(r, "read_finish failed"); SAFE_FREE(pol_element->element.PolicySecret.objectPath); break; case POLICYPCR: if (pol_element->element.PolicyPCR.pcrs && pol_element->element.PolicyPCR.pcrs->count) { /* PCR values already defined */ break; } /* Current values of PCRs will be used for policy */ r = context->callbacks.cbpcr(&pol_element->element.PolicyPCR.currentPCRs, &pol_element->element.PolicyPCR.currentPCRandBanks, &pol_element->element.PolicyPCR.pcrs, context->callbacks.cbpcr_userdata); return_try_again(r); return_if_error(r, "read_finish failed"); pol_element->element.PolicyPCR.currentPCRs.sizeofSelect = 0; pol_element->element.PolicyPCR.currentPCRandBanks.count = 0; break; case POLICYNV: if (pol_element->element.PolicyNV.nvPublic.nvPublic.nvIndex) { /* nvIndex is already set in policy. Path will not be needed */ pol_element->element.PolicyNV.nvIndex = pol_element->element.PolicyNV.nvPublic.nvPublic.nvIndex; SAFE_FREE(pol_element->element.PolicyNV.nvPath); break; } CHECK_TEMPLATE_PATH(pol_element->element.PolicyNV.nvPath, "PolicyNv"); /* Object name will be added to policy. */ r = context->callbacks.cbnvpublic(pol_element->element.PolicyNV.nvPath, &pol_element->element.PolicyNV.nvPublic, context->callbacks.cbnvpublic_userdata); return_try_again(r); return_if_error(r, "read_finish failed"); pol_element->element.PolicyNV.nvIndex = pol_element->element.PolicyNV.nvPublic.nvPublic.nvIndex; /* Clear NV path, only public data will be needed */ SAFE_FREE(pol_element->element.PolicyNV.nvPath); break; case POLICYDUPLICATIONSELECT: if (pol_element->element.PolicyDuplicationSelect.newParentPublic.publicArea.type) { /* public data is already set in policy. Path will not be needed. */ SAFE_FREE(pol_element->element.PolicyDuplicationSelect.newParentPath); break; } CHECK_TEMPLATE_PATH(pol_element->element.PolicyDuplicationSelect.newParentPath, "PolicyDuplicationselect"); /* Public info will be added to policy. */ r = context->callbacks.cbpublic( pol_element->element.PolicyDuplicationSelect.newParentPath, &pol_element->element.PolicyDuplicationSelect.newParentPublic.publicArea, context->callbacks.cbpublic_userdata); return_try_again(r); return_if_error(r, "read_finish failed"); r = ifapi_get_name( &pol_element->element.PolicyDuplicationSelect.newParentPublic.publicArea, &pol_element->element.PolicyDuplicationSelect.newParentName); return_if_error(r, "Compute key name"); /* Clear keypath, only public data will be needed */ SAFE_FREE(pol_element->element.PolicyDuplicationSelect.newParentPath); break; case POLICYAUTHORIZENV: if (pol_element->element.PolicyAuthorizeNv.nvPublic.nvPublic.nvIndex) { /* nvIndex is already set in policy. Path will not be needed */ SAFE_FREE(pol_element->element.PolicyAuthorizeNv.nvPath); break; } CHECK_TEMPLATE_PATH(pol_element->element.PolicyAuthorizeNv.nvPath, "PolicyAuthorizeNv"); /* Object name will be added to policy. */ r = context->callbacks.cbnvpublic(pol_element->element.PolicyAuthorizeNv.nvPath, &pol_element->element.PolicyAuthorizeNv.nvPublic, context->callbacks.cbnvpublic_userdata); return_try_again(r); return_if_error(r, "read_finish failed"); /* Clear NV path, only public data will be needed */ SAFE_FREE(pol_element->element.PolicyAuthorizeNv.nvPath); break; case POLICYAUTHORIZE: if (pol_element->element.PolicyAuthorize.keyPublic.type) { /* Public info found in template, key path will not be needed. */ SAFE_FREE(pol_element->element.PolicyAuthorize.keyPath); r = ifapi_get_name(&pol_element->element.PolicyAuthorize.keyPublic, &pol_element->element.PolicyAuthorize.keyName); return_if_error(r, "Compute key name"); break; } if (pol_element->element.PolicyAuthorize.keyPEM && strlen(pol_element->element.PolicyAuthorize.keyPEM) > 0) { /* Determine name and public info for PEM key. */ r = set_pem_key_param(pol_element->element.PolicyAuthorize.keyPEM, &pol_element->element.PolicyAuthorize.keyPublic, &pol_element->element.PolicyAuthorize.keyName, pol_element->element.PolicyAuthorize.keyPEMhashAlg); return_if_error(r, "Set parameter of pem key."); pol_element->element.PolicyAuthorize.keyPEM = NULL; break; } CHECK_TEMPLATE_PATH(pol_element->element.PolicyAuthorize.keyPath, "PolicyAuthorize"); /* Object public data will be added to policy. */ r = context->callbacks.cbpublic(pol_element->element.PolicyAuthorize.keyPath, &pol_element->element.PolicyAuthorize.keyPublic, context->callbacks.cbpublic_userdata); return_try_again(r); return_if_error(r, "read_finish failed"); /* Compute key name from public info */ r = ifapi_get_name(&pol_element->element.PolicyAuthorize.keyPublic, &pol_element->element.PolicyAuthorize.keyName); return_if_error(r, "Compute key name"); /* Clear key path, only public data will be needed */ SAFE_FREE(pol_element->element.PolicyAuthorize.keyPath); break; } /* Cleanup head of list and use next policy element */ context->policy_elements = first_in_pol_list->next; SAFE_FREE(first_in_pol_list); } return r; }