blob: 0cb22726946667f0a2a6097ae192e4727797e61d [file] [log] [blame]
/* SPDX-License-Identifier: BSD-2-Clause */
/*******************************************************************************
* Copyright 2018-2019, Fraunhofer SIT sponsored by Infineon Technologies AG
* All rights reserved.
*******************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include "tss2_mu.h"
#include "fapi_util.h"
#include "fapi_crypto.h"
//#include "fapi_policy.h"
#include "ifapi_policy_execute.h"
#include "ifapi_helpers.h"
#include "ifapi_json_deserialize.h"
#include "tpm_json_deserialize.h"
#include "ifapi_policy_callbacks.h"
#define LOGMODULE fapi
#include "util/log.h"
#include "util/aux_util.h"
/** Copy the policy digests from a branch list to a digest list.
*
* @param[in] branches The list of policy branches.
* @param[in] current_hash_alg The hash algorithm used for computation.
* @param[out] digest_list The list of policies computed for every branch.
* @retval TSS2_RC_SUCCESS on success.
* @retval TSS2_FAPI_RC_BAD_VALUE If no appropriate digest was found in
* the branch list.
*/
static TSS2_RC
compute_or_digest_list(
TPML_POLICYBRANCHES *branches,
TPMI_ALG_HASH current_hash_alg,
TPML_DIGEST *digest_list)
{
size_t i;
size_t digest_idx, hash_size;
bool digest_found = false;
if (!(hash_size = ifapi_hash_get_digest_size(current_hash_alg))) {
return_error2(TSS2_FAPI_RC_BAD_VALUE,
"Unsupported hash algorithm (%" PRIu16 ")",
current_hash_alg);
}
/* Determine digest values with appropriate hash alg */
TPML_DIGEST_VALUES *branch_digests = &branches->authorizations[0].policyDigests;
for (i = 0; i < branch_digests->count; i++) {
if (branch_digests->digests[i].hashAlg == current_hash_alg) {
digest_idx = i;
digest_found = true;
break;
}
}
if (!digest_found) {
return_error(TSS2_FAPI_RC_BAD_VALUE, "No digest found for hash alg");
}
digest_list->count = branches->count;
for (i = 0; i < branches->count; i++) {
if (i > 7) {
return_error(TSS2_FAPI_RC_BAD_VALUE, "Too much or branches.");
}
digest_list->digests[i].size = hash_size;
memcpy(&digest_list->digests[i].buffer[0],
&branches->authorizations[i].policyDigests.
digests[digest_idx].digest, hash_size);
LOGBLOB_DEBUG(&digest_list->digests[i].buffer[0],
digest_list->digests[i].size, "Compute digest list");
}
return TSS2_RC_SUCCESS;
}
/** Add a new authorization to a policy.
*
* The the signed hash computed from the policy digest and the policyRef together with
* the public key of the key used for signing will be stored in the policy.
*
* @param[in,out] policy The policy to be authorized.
* @param[in] authorization The structure with the signature, the policyRef and
* the public key.
*
* @retval TSS2_RC_SUCCESS on success.
* @retval TSS2_FAPI_RC_MEMORY If the memory for the authorization list cannot be
* allocated.
*/
TSS2_RC
ifapi_extend_authorization(
TPMS_POLICY *policy,
TPMS_POLICYAUTHORIZATION *authorization)
{
TPML_POLICYAUTHORIZATIONS *save = NULL;
size_t n = 0;
size_t i;
if (policy->policyAuthorizations) {
/* Extend old authorizations */
n = policy->policyAuthorizations->count;
save = policy->policyAuthorizations;
policy->policyAuthorizations =
malloc((n + 1) * sizeof(TPMS_POLICYAUTHORIZATION)
+ sizeof(TPML_POLICYAUTHORIZATIONS));
return_if_null(policy->policyAuthorizations->authorizations,
"Out of memory.", TSS2_FAPI_RC_MEMORY);
for (i = 0; i < n; i++)
policy->policyAuthorizations->authorizations[i] =
save->authorizations[i];
policy->policyAuthorizations->authorizations[n] = *authorization;
policy->policyAuthorizations->count = n + 1;
SAFE_FREE(save);
} else {
/* No old authorizations exits */
policy->policyAuthorizations = malloc(sizeof(TPMS_POLICYAUTHORIZATION)
+ sizeof(TPML_POLICYAUTHORIZATIONS));
return_if_null(policy->policyAuthorizations->authorizations,
"Out of memory.", TSS2_FAPI_RC_MEMORY);
policy->policyAuthorizations->count = 1;
policy->policyAuthorizations->authorizations[0] = *authorization;
}
return TSS2_RC_SUCCESS;
}
/** Compute the index for the current digest list and clear the digest.
*
* The list entry with the appropriate hash algorithm will be searched.
* The found digest will be set to zero.
*
* @param[in,out] digest_values The list of policy digests and corresponding
* hash algorithms.
* @param[in] hashAlg The hash algorithm to be searched.
* @param[out] idx The index of the found digest.
* @retval TSS2_RC_SUCCESS on success.
* @retval TSS2_FAPI_RC_BAD_VALUE If no appropriate digest was found in
* the digest list.
*/
TSS2_RC
get_policy_digest_idx(TPML_DIGEST_VALUES *digest_values, TPMI_ALG_HASH hashAlg,
size_t *idx)
{
size_t i;
for (i = 0; i < digest_values->count; i++) {
/* Check whether current hashAlg is appropriate. */
if (digest_values->digests[i].hashAlg == hashAlg) {
*idx = i;
return TSS2_RC_SUCCESS;
}
}
if (i >= TPM2_NUM_PCR_BANKS) {
return_error(TSS2_FAPI_RC_BAD_VALUE, "Table overflow");
}
digest_values->digests[i].hashAlg = hashAlg;
memset(&digest_values->digests[i].digest, 0, sizeof(TPMU_HA));
*idx = i;
digest_values->count += 1;
return TSS2_RC_SUCCESS;
}
/** Execute policy PCR.
*
* This command is used to cause conditional gating of a policy based on PCR.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The PCR policy which will be executed. The policy
* digest will be added to the policy.
* @param[in] current_hash_alg The hash algorithm wich will be used for
* policy computation.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
* @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
* the function.
* @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_GENERAL_FAILURE if an internal error occured.
*/
static TSS2_RC
execute_policy_pcr(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYPCR *policy,
TPMI_ALG_HASH current_hash_alg,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
TPML_PCR_SELECTION pcr_selection;
TPM2B_DIGEST pcr_digest;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Compute PCR selection and pcr digest */
r = ifapi_compute_policy_digest(policy->pcrs, &pcr_selection,
current_hash_alg, &pcr_digest);
return_if_error(r, "Compute policy digest and selection.");
LOGBLOB_DEBUG(&pcr_digest.buffer[0], pcr_digest.size, "PCR Digest");
/* Prepare the policy execution. */
r = Esys_PolicyPCR_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
&pcr_digest, &pcr_selection);
return_if_error(r, "Execute PolicyPCR.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyPCR_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyPCR_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute policy duplicate.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The duplicate policy which will be executed. The policy
* digest will be added to the policy.
* @param[in] current_hash_alg The hash algorithm wich will be used for
* policy computation.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_duplicate(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYDUPLICATIONSELECT *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
ifapi_policyeval_EXEC_CB *cb = &current_policy->callbacks;
r = cb->cbdup(&policy->objectName, cb->cbdup_userdata);
return_if_error(r, "Get name for policy duplicate select.");
/* Prepare the policy execution. */
r = Esys_PolicyDuplicationSelect_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE,
ESYS_TR_NONE,
&policy->objectName,
&policy->newParentName,
policy->includeObject);
return_if_error(r, "Execute PolicyDuplicatonSelect_Async.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyDuplicationSelect_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyDuplicationselect_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute policy NV.
*
* A policy based on the contents of an NV Index will be executed. The
* NV authorization is done by a callback. For an example callback
* implementation see ifapi_policyeval_cbauth()
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The NV policy which will be executed. The policy
* digest will be added to the policy.
* @param[in] current_hash_alg The hash algorithm wich will be used for
* policy computation.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
* @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 occured.
* @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_BAD_PATH if the path is used in inappropriate context
* or contains illegal characters.
* @retval TSS2_FAPI_RC_NOT_PROVISIONED FAPI was not provisioned.
* @retval TSS2_FAPI_RC_IO_ERROR if an error occured while accessing the
* object store.
* @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_POLICY_UNKNOWN if policy search for a certain policy digest
* was not successful.
*/
static TSS2_RC
execute_policy_nv(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYNV *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
r = ifapi_nv_get_name(&policy->nvPublic, &current_policy->name);
return_if_error(r, "Compute NV name");
fallthrough;
statecase(current_policy->state, POLICY_AUTH_CALLBACK)
ifapi_policyeval_EXEC_CB *cb = &current_policy->callbacks;
/* Authorize NV object. */
r = cb->cbauth(&current_policy->name,
&current_policy->object_handle,
&current_policy->auth_handle,
&current_policy->auth_session, cb->cbauth_userdata);
return_try_again(r);
return_if_error(r, "Execute authorized policy.");
/* Prepare the policy execution. */
r = Esys_PolicyNV_Async(esys_ctx,
current_policy->object_handle,
current_policy->auth_handle,
current_policy->session,
current_policy->auth_session, ESYS_TR_NONE, ESYS_TR_NONE,
&policy->operandB, policy->offset,
policy->operation);
return_if_error(r, "Execute PolicyNV_Async.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyNV_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyNV_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute policy for signature based authorization.
*
* A signed authorization is included in this policy. The authorization hash
* of the policy data will be signed via a callback. For an example callback
* implementation see ifapi_sign_buffer()
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy to be signed which will be executed. The policy
* digest will be added to the policy.
* @param[in] current_hash_alg The hash algorithm wich will be used for
* policy computation.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
* @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_AUTHORIZATION_UNKNOWN if a required authorization callback
* is not set.
* @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
* @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 occured.
*/
static TSS2_RC
execute_policy_signed(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYSIGNED *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
size_t offset = 0;
//TPMT_SIGNATURE signature_tpm;
size_t signature_size;
const uint8_t *signature_ossl = NULL;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT);
current_policy->pem_key = NULL;
current_policy->object_handle = ESYS_TR_NONE;
current_policy->buffer_size = sizeof(INT32) + sizeof(TPM2B_NONCE)
+ policy->cpHashA.size + policy->policyRef.size;
current_policy->buffer = malloc(current_policy->buffer_size);
return_if_null(current_policy->buffer, "Out of memory.", TSS2_FAPI_RC_MEMORY);
r = Esys_TRSess_GetNonceTPM(esys_ctx, current_policy->session,
&current_policy->nonceTPM);
return_if_error(r, "Get TPM nonce.");
/* Concatenate objects needed for the authorization hash */
memcpy(&current_policy->buffer[offset], &current_policy->nonceTPM->buffer[0],
current_policy->nonceTPM->size);
offset += current_policy->nonceTPM->size;
memset(&current_policy->buffer[offset], 0, sizeof(INT32));
offset += sizeof(INT32);
memcpy(&current_policy->buffer[offset], &policy->cpHashA.buffer[0],
policy->cpHashA.size);
offset += policy->cpHashA.size;
memcpy(&current_policy->buffer[offset], &policy->policyRef.buffer[0],
policy->policyRef.size);
offset += policy->policyRef.size;
current_policy->buffer_size = offset;
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_CALLBACK);
ifapi_policyeval_EXEC_CB *cb = &current_policy->callbacks;
int pem_key_size;
TPM2B_PUBLIC tpm_public;
/* Recreate pem key from tpm public key */
if (!current_policy->pem_key) {
tpm_public.publicArea = policy->keyPublic;
tpm_public.size = 0;
r = ifapi_pub_pem_key_from_tpm(&tpm_public, &current_policy->pem_key,
&pem_key_size);
return_if_error(r, "Convert TPM public key into PEM key.");
}
/* Callback for signing the autorization hash. */
r = cb->cbsign(current_policy->pem_key, policy->publicKeyHint,
policy->keyPEMhashAlg, current_policy->buffer,
current_policy->buffer_size,
&signature_ossl, &signature_size,
cb->cbsign_userdata);
SAFE_FREE(current_policy->pem_key);
SAFE_FREE(current_policy->buffer);
try_again_or_error_goto(r, "Execute policy signature callback.", cleanup);
/* Convert signature into TPM format */
r = ifapi_der_sig_to_tpm(&policy->keyPublic, signature_ossl,
signature_size, policy->keyPEMhashAlg,
&policy->signature_tpm);
goto_if_error2(r, "Convert der signature into TPM format", cleanup);
TPM2B_PUBLIC inPublic;
inPublic.size = 0;
inPublic.publicArea = policy->keyPublic;
/* Prepare the loading of the external public key, user for verificaton. */
r = Esys_LoadExternal_Async(esys_ctx,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
NULL, &inPublic, ESYS_TR_RH_OWNER);
goto_if_error(r, "LoadExternal_Async", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_LOAD_KEY);
r = Esys_LoadExternal_Finish(esys_ctx, &current_policy->object_handle);
try_again_or_error(r, "Load external key.");
/* Prepare the policy execution. */
r = Esys_PolicySigned_Async(esys_ctx,
current_policy->object_handle,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
current_policy->nonceTPM,
&policy->cpHashA,
&policy->policyRef, 0, &policy->signature_tpm);
SAFE_FREE(current_policy->nonceTPM);
goto_if_error(r, "Execute PolicySigned.", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH);
/* Finalize the policy execution if possible. */
r = Esys_PolicySigned_Finish(esys_ctx, NULL, NULL);
try_again_or_error(r, "Execute PolicySigned_Finish.");
r = Esys_FlushContext_Async(esys_ctx, current_policy->object_handle);
goto_if_error(r, "FlushContext_Async", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_FLUSH_KEY);
r = Esys_FlushContext_Finish(esys_ctx);
try_again_or_error(r, "Flush key finish.");
current_policy->object_handle = ESYS_TR_NONE;
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
cleanup:
SAFE_FREE(current_policy->nonceTPM);
SAFE_FREE(current_policy->pem_key);
SAFE_FREE(signature_ossl);
SAFE_FREE(current_policy->buffer);
SAFE_FREE(current_policy->pem_key);
/* In error cases object might not have been flushed. */
if (current_policy->object_handle != ESYS_TR_NONE)
Esys_FlushContext(esys_ctx, current_policy->object_handle);
return r;
}
/** Execute a policy that was signed by a certain key.
*
* All policies authorized by the key stored in the policy will be
* retrieved and one policy will be selected via a branch selection callback
* (see Fapi_SetBranchCB()) if more then one policy was found.
* The selected policy will be executed via a callback. For an example callback
* implementation see ifapi_exec_auth_policy().
*
* For an example callback implementation to executie of an authorized policy
* ifapi_exec_auth_policy()
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy which defines the signing key and several
* additional parameters (nonce, policyRef ...). The policy
* digest will be added to the policy.
* @param[in] current_hash_alg The hash algorithm wich will be used for
* policy computation.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
* the function.
* @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_GENERAL_FAILURE if an internal error occured.
* @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
* @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
* was not successful.
* @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
* is not set.
* @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
* @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
* @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_BAD_PATH if the path is used in inappropriate context
* or contains illegal characters.
* @retval TSS2_FAPI_RC_NOT_PROVISIONED FAPI was not provisioned.
* @retval TSS2_FAPI_RC_IO_ERROR if an error occured while accessing the
* object store.
* @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
*/
static TSS2_RC
execute_policy_authorize(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYAUTHORIZE *policy,
TPMI_ALG_HASH hash_alg,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
TPM2B_PUBLIC public2b;
TPM2B_DIGEST aHash;
IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext;
size_t hash_size;
size_t size;
TPMT_TK_VERIFIED *ticket;
TPM2B_NAME *tmp_name = NULL;
LOG_TRACE("call");
public2b.size = 0;
if (!(hash_size = ifapi_hash_get_digest_size(hash_alg))) {
goto_error(r, TSS2_FAPI_RC_BAD_VALUE,
"Unsupported hash algorithm (%" PRIu16 ")", cleanup,
hash_alg);
}
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT);
current_policy->object_handle = ESYS_TR_NONE;
/* Execute authorized policy. */
ifapi_policyeval_EXEC_CB *cb = &current_policy->callbacks;
r = cb->cbauthpol(&policy->keyPublic, hash_alg, &policy->approvedPolicy,
&policy->policyRef,
&policy->signature, cb->cbauthpol_userdata);
return_try_again(r);
goto_if_error(r, "Execute authorized policy.", cleanup);
public2b.size = 0;
public2b.publicArea = policy->keyPublic;
r = Esys_LoadExternal_Async(esys_ctx,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
NULL, &public2b, ESYS_TR_RH_OWNER);
goto_if_error(r, "LoadExternal_Async", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_LOAD_KEY);
r = Esys_LoadExternal_Finish(esys_ctx, &current_policy->object_handle);
try_again_or_error(r, "Load external key.");
/* Save key name for policy execution */
r = Esys_TR_GetName(esys_ctx, current_policy->object_handle, &tmp_name);
return_if_error(r, "Get key name.");
policy->keyName = *tmp_name;
SAFE_FREE(tmp_name);
/* Use policyRef and policy to compute authorization hash */
r = ifapi_crypto_hash_start(&cryptoContext, hash_alg);
return_if_error(r, "crypto hash start");
HASH_UPDATE_BUFFER(cryptoContext, &policy->approvedPolicy.buffer[0],
hash_size, r, cleanup);
HASH_UPDATE_BUFFER(cryptoContext, &policy->policyRef.buffer[0],
policy->policyRef.size, r, cleanup);
r = ifapi_crypto_hash_finish(&cryptoContext,
(uint8_t *) &aHash.buffer[0],
&size);
return_if_error(r, "crypto hash finish");
aHash.size = size;
LOGBLOB_TRACE(&policy->policyRef.buffer[0], policy->policyRef.size, "policyRef");
LOGBLOB_TRACE(&aHash.buffer[0], aHash.size, "aHash");
/* Verify the signature retrieved from the authorized policy against
the computed ahash. */
r = Esys_VerifySignature_Async(esys_ctx, current_policy->object_handle,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
&aHash,
&policy->signature);
goto_if_error(r, "Verify signature", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_VERIFY);
r = Esys_VerifySignature_Finish(esys_ctx, &ticket);
try_again_or_error(r, "Load external key.");
/* Execute policy authorize */
policy->checkTicket = *ticket;
SAFE_FREE(ticket);
r = Esys_PolicyAuthorize_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
&policy->approvedPolicy,
&policy->policyRef,
&policy->keyName,
&policy->checkTicket);
goto_if_error(r, "Policy Authorize", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH);
r = Esys_PolicyAuthorize_Finish(esys_ctx);
try_again_or_error(r, "Load external key.");
r = Esys_FlushContext_Async(esys_ctx, current_policy->object_handle);
goto_if_error(r, "FlushContext_Async", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_FLUSH_KEY);
/* Flush key used for verification. */
r = Esys_FlushContext_Finish(esys_ctx);
try_again_or_error(r, "Flush key finish.");
current_policy->object_handle = ESYS_TR_NONE;
current_policy->state = POLICY_EXECUTE_INIT;
break;
statecasedefault(current_policy->state);
}
cleanup:
/* In error cases object might not have been flushed. */
if (current_policy->object_handle != ESYS_TR_NONE)
Esys_FlushContext(esys_ctx, current_policy->object_handle);
return r;
}
/** Execute a policy whose digest is stored in the NV ram.
*
* The policy will be retrieved from policy store based on the policy digest
* stored in NV ram.
* The authorization for the NV object, the policy retrieval, and the execution
* is done via a callback. For an example callback implementation see
* ifapi_exec_auth_nv_policy().
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy which defines the policy to be authorized
* and the used NV object.
* The policy digest will be added to the policy.
* @param[in] current_hash_alg The hash algorithm wich will be used for
* policy computation.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_BAD_VALUE if an invalid value was passed into
* the function.
* @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
* was not successful.
* @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
* @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
* @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occured.
* @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_BAD_PATH if the path is used in inappropriate context
* or contains illegal characters.
* @retval TSS2_FAPI_RC_NOT_PROVISIONED FAPI was not provisioned.
* @retval TSS2_FAPI_RC_IO_ERROR if an error occured while accessing the
* object store.
* @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.
*/
static TSS2_RC
execute_policy_authorize_nv(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYAUTHORIZENV *policy,
TPMI_ALG_HASH hash_alg,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
ifapi_policyeval_EXEC_CB *cb;
LOG_DEBUG("call");
cb = &current_policy->callbacks;
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Execute the policy stored in the NV object. */
r = cb->cbauthnv(&policy->nvPublic, hash_alg, cb->cbauthpol_userdata);
try_again_or_error(r, "Execute policy authorize nv callback.");
r = ifapi_nv_get_name(&policy->nvPublic, &current_policy->name);
return_if_error(r, "Compute NV name");
fallthrough;
statecase(current_policy->state, POLICY_AUTH_CALLBACK)
/* Authorize the NV object for policy execution. */
r = cb->cbauth(&current_policy->name,
&current_policy->object_handle,
&current_policy->auth_handle,
&current_policy->auth_session, cb->cbauth_userdata);
return_try_again(r);
goto_if_error(r, "Execute authorized policy.", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_EXEC_ESYS)
LOG_DEBUG("**STATE** POLICY_EXEC_ESYS");
/* Prepare the policy execution. */
r = Esys_PolicyAuthorizeNV_Async(esys_ctx,
current_policy->auth_handle,
current_policy->object_handle,
current_policy->session,
current_policy->auth_session, ESYS_TR_NONE,
ESYS_TR_NONE);
goto_if_error(r, "PolicyAuthorizeNV_Async", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_AUTH_SENT)
/* Finalize the policy execution if possible. */
r = Esys_PolicyAuthorizeNV_Finish(esys_ctx);
return_try_again(r);
goto_if_error(r, "FAPI PolicyAuthorizeNV_Finish", cleanup);
current_policy->state = POLICY_EXECUTE_INIT;
break;
statecasedefault(current_policy->state);
}
cleanup:
return r;
}
/** Execute a policy based on a secret-based authorization.
*
* The policy defines an object whose secret is needed for policy execution.
* The authorization of the object is done via a callback.
* For an example callback implementation see ifapi_policyeval_cbauth;().
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy which defines the object whose secret
* is needed for policy execution.
* The policy digest will be added to the policy.
* @param[in] current_hash_alg The hash algorithm wich will be used for
* policy computation.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
* @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
* during authorization.
* @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
* @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
* @retval TSS2_FAPI_RC_BAD_PATH if the path is used in inappropriate context
* or contains illegal characters.
* @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
* the function.
* @retval TSS2_FAPI_RC_NOT_PROVISIONED FAPI was not provisioned.
* @retval TSS2_FAPI_RC_IO_ERROR if an error occured while accessing the
* object store.
* @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occured.
* @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_POLICY_UNKNOWN if policy search for a certain policy digest
* was not successful.
*/
static TSS2_RC
execute_policy_secret(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYSECRET *policy,
TPMI_ALG_HASH hash_alg,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
(void)hash_alg;
LOG_DEBUG("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
ifapi_policyeval_EXEC_CB *cb = &current_policy->callbacks;
/* Callback for the object authorization. */
r = cb->cbauth(&policy->objectName,
&current_policy->object_handle,
&current_policy->auth_handle,
&current_policy->auth_session, cb->cbauth_userdata);
return_try_again(r);
goto_if_error(r, "Authorize object callback.", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_EXEC_ESYS)
r = Esys_TRSess_GetNonceTPM(esys_ctx, current_policy->session,
&current_policy->nonceTPM);
goto_if_error(r, "Get TPM nonce.", cleanup);
policy->nonceTPM = *(current_policy->nonceTPM);
SAFE_FREE(current_policy->nonceTPM);
/* Prepare the policy execution. */
r = Esys_PolicySecret_Async(esys_ctx,
current_policy->auth_handle,
current_policy->session,
current_policy->auth_session, ESYS_TR_NONE,
ESYS_TR_NONE, &policy->nonceTPM,
&policy->cpHashA, &policy->policyRef,
0);
goto_if_error(r, "PolicySecret_Async", cleanup);
fallthrough;
statecase(current_policy->state, POLICY_AUTH_SENT)
/* Finalize the policy execution if possible. */
r = Esys_PolicySecret_Finish(esys_ctx, NULL,
NULL);
return_try_again(r);
goto_if_error(r, "FAPI PolicyAuthorizeNV_Finish", error_cleanup);
current_policy->state = POLICY_EXECUTE_INIT;
break;
statecasedefault(current_policy->state);
}
cleanup:
return r;
error_cleanup:
SAFE_FREE(current_policy->nonceTPM);
return r;
}
/** Execute a policy depending on the TPM timers.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy which defines the values for the comparision
* with the TPM timers and the comparision operation.
* The policy digest will be added to the policy.
* @param[in] current_hash_alg The hash algorithm wich will be used for
* policy computation.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_counter_timer(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYCOUNTERTIMER *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyCounterTimer_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE,
ESYS_TR_NONE,
&policy->operandB,
policy->offset,
policy->operation);
return_if_error(r, "Execute PolicyCounter.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyCounterTimer_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyCounterTImer_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute a policy depending on physical presence.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy indicating that physical presence is needed.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_physical_presence(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYPHYSICALPRESENCE *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
(void)policy;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyPhysicalPresence_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE,
ESYS_TR_NONE);
return_if_error(r, "Execute PolicyPhysicalpresence.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyPhysicalPresence_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyPhysicalPresence_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute a policy for binding a authorization value of the authorized entity.
*
* The authValue will be included in hmacKey of the session.
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy indicating that a auth value is needed.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_auth_value(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYAUTHVALUE *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
(void)policy;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyAuthValue_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE,
ESYS_TR_NONE);
return_if_error(r, "Execute PolicyAuthValue.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyAuthValue_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyAuthValue_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute a policy for binding a authorization value of the authorized object.
*
* The authValue of the authorized object will be checked when the session is used
* for authorization..
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy indicating that a auth value is needed.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_password(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYPASSWORD *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
(void)policy;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyPassword_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE,
ESYS_TR_NONE);
return_if_error(r, "Execute PolicyPassword.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyPassword_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyPassword_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute a policy to limit an authorization to a specific command code.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy with the command code used fo limitting.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_command_code(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYCOMMANDCODE *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyCommandCode_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
policy->code);
return_if_error(r, "Execute PolicyCommandCode.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyCommandCode_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyCommandCode_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state)
}
return r;
}
/** Execute a policy for binding the policy to a specific set of TPM entities.
*
* Up to three entity names can be defined in the policy.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy with the entity names.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_name_hash(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYNAMEHASH *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyNameHash_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
&policy->nameHash);
return_if_error(r, "Execute PolicyNameH.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyNameHash_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyNameHash_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state)
}
return r;
}
/** Execute a policy for binding the policy to command parameters.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy with the cp hash.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_cp_hash(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYCPHASH *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyCpHash_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
&policy->cpHash);
return_if_error(r, "Execute PolicyNameH.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyCpHash_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyCpHash_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute a policy for binding the policy to a certain locality.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy with the locality.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_locality(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYLOCALITY *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyLocality_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
policy->locality);
return_if_error(r, "Execute PolicyLocality.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyLocality_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyNV_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute a policy for binding the policy to the NV written state.
*
* The state NV written yes or NV written no can be defined in the policy.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy with the NV written switch YES or NO.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
*/
static TSS2_RC
execute_policy_nv_written(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYNVWRITTEN *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = Esys_PolicyNvWritten_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
policy->writtenSet);
return_if_error(r, "Execute PolicyNvWritten.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyNvWritten_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyNV_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
return r;
}
/** Execute a policy for binding the policy to the NV written state.
*
* The state NV written yes or NV written no can be defined in the policy.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy with the NV written switch YES or NO.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_ESYS_RC_* possible error codes of ESAPI.
* @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
* the function.
*/
static TSS2_RC
execute_policy_or(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYOR *policy,
TPMI_ALG_HASH current_hash_alg,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT)
/* Prepare the policy execution. */
r = compute_or_digest_list(policy->branches, current_hash_alg,
&current_policy->digest_list);
return_if_error(r, "Compute policy or digest list.");
r = Esys_PolicyOR_Async(esys_ctx,
current_policy->session,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
&current_policy->digest_list);
return_if_error(r, "Execute PolicyPCR.");
fallthrough;
statecase(current_policy->state, POLICY_EXECUTE_FINISH)
/* Finalize the policy execution if possible. */
r = Esys_PolicyOR_Finish(esys_ctx);
try_again_or_error(r, "Execute PolicyPCR_Finish.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
}
/** Execute a policy for executing a callback during policy execution.
*
* The action name stored in the policy name will be passed do the callback
* function. The policy action callback has to be set with the function:
* Fapi_SetPolicyActionCB().
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy with action name.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @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_AUTHORIZATION_UNKNOWN if a required authorization callback
* is not set.
*/
static TSS2_RC
execute_policy_action(
ESYS_CONTEXT *esys_ctx,
TPMS_POLICYACTION *policy,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
(void)(esys_ctx);
LOG_TRACE("call");
switch (current_policy->state) {
statecase(current_policy->state, POLICY_EXECUTE_INIT);
ifapi_policyeval_EXEC_CB *cb = &current_policy->callbacks;
/* Execute the callback and try it again if the callback is not finished. */
r = cb->cbaction(policy->action, cb->cbaction_userdata);
try_again_or_error(r, "Execute policy action callback.");
current_policy->state = POLICY_EXECUTE_INIT;
return r;
statecasedefault(current_policy->state);
}
}
/** Execute a policy element depending on the type.
*
* @param[in,out] *esys_ctx The ESAPI context which is needed to execute the
* policy command.
* @param[in,out] policy The policy element with the policy to be executed and
* the type of the policy.
* @param[in,out] current_policy The policy context which stores the state
* of the policy execution.
* @retval TSS2_RC_SUCCESS on success.
* @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occured.
* @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_MEMORY if not enough memory can be allocated.
* @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
* @retval TSS2_FAPI_RC_BAD_PATH if the path is used in inappropriate context
* or contains illegal characters.
* @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
* the function.
* @retval TSS2_FAPI_RC_NOT_PROVISIONED FAPI was not provisioned.
* @retval TSS2_FAPI_RC_IO_ERROR if an error occured while accessing the
* object store.
* @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_POLICY_UNKNOWN if policy search for a certain policy digest
* was not successful.
*/
static TSS2_RC
execute_policy_element(
ESYS_CONTEXT *esys_ctx,
TPMT_POLICYELEMENT *policy,
TPMI_ALG_HASH hash_alg,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
LOG_TRACE("call");
switch (policy->type) {
case POLICYSECRET:
r = execute_policy_secret(esys_ctx,
&policy->element.PolicySecret,
hash_alg,
current_policy);
try_again_or_error_goto(r, "Execute policy authorize", error);
break;
case POLICYPCR:
r = execute_policy_pcr(esys_ctx,
&policy->element.PolicyPCR,
hash_alg, current_policy);
try_again_or_error_goto(r, "Execute policy pcr", error);
break;
case POLICYAUTHVALUE:
r = execute_policy_auth_value(esys_ctx,
&policy->element.PolicyAuthValue,
current_policy);
try_again_or_error_goto(r, "Execute policy auth value", error);
break;
case POLICYOR:
r = execute_policy_or(esys_ctx,
&policy->element.PolicyOr,
hash_alg, current_policy);
try_again_or_error_goto(r, "Execute policy or", error);
break;
case POLICYSIGNED:
r = execute_policy_signed(esys_ctx,
&policy->element.PolicySigned,
current_policy);
try_again_or_error_goto(r, "Execute policy signed", error);
break;
case POLICYAUTHORIZE:
r = execute_policy_authorize(esys_ctx,
&policy->element.PolicyAuthorize,
hash_alg,
current_policy);
try_again_or_error_goto(r, "Execute policy authorize", error);
break;
case POLICYAUTHORIZENV:
r = execute_policy_authorize_nv(esys_ctx,
&policy->element.PolicyAuthorizeNv,
hash_alg,
current_policy);
try_again_or_error_goto(r, "Execute policy authorize", error);
break;
case POLICYNV:
r = execute_policy_nv(esys_ctx,
&policy->element.PolicyNV,
current_policy);
try_again_or_error_goto(r, "Execute policy nv", error);
break;
case POLICYDUPLICATIONSELECT:
r = execute_policy_duplicate(esys_ctx,
&policy->element.PolicyDuplicationSelect,
current_policy);
try_again_or_error_goto(r, "Execute policy duplicate", error);
break;
case POLICYNVWRITTEN:
r = execute_policy_nv_written(esys_ctx,
&policy->element.PolicyNvWritten,
current_policy);
try_again_or_error_goto(r, "Execute policy nv written", error);
break;
case POLICYLOCALITY:
r = execute_policy_locality(esys_ctx,
&policy->element.PolicyLocality,
current_policy);
try_again_or_error_goto(r, "Execute policy locality", error);
break;
case POLICYCOMMANDCODE:
r = execute_policy_command_code(esys_ctx,
&policy->element.PolicyCommandCode,
current_policy);
try_again_or_error_goto(r, "Execute policy command code", error);
break;
case POLICYNAMEHASH:
r = execute_policy_name_hash(esys_ctx,
&policy->element.PolicyNameHash,
current_policy);
try_again_or_error_goto(r, "Execute policy name hash", error);
break;
case POLICYCPHASH:
r = execute_policy_cp_hash(esys_ctx,
&policy->element.PolicyCpHash,
current_policy);
try_again_or_error_goto(r, "Execute policy cp hash", error);
break;
case POLICYPHYSICALPRESENCE:
r = execute_policy_physical_presence(esys_ctx,
&policy->element.PolicyPhysicalPresence,
current_policy);
try_again_or_error_goto(r, "Execute policy physical presence", error);
break;
case POLICYPASSWORD:
r = execute_policy_password(esys_ctx,
&policy->element.PolicyPassword,
current_policy);
try_again_or_error_goto(r, "Execute policy password", error);
break;
case POLICYCOUNTERTIMER:
r = execute_policy_counter_timer(esys_ctx,
&policy->element.PolicyCounterTimer,
current_policy);
try_again_or_error_goto(r, "Execute policy counter timer", error);
break;
case POLICYACTION:
r = execute_policy_action(esys_ctx,
&policy->element.PolicyAction,
current_policy);
try_again_or_error_goto(r, "Execute policy action", error);
break;
default:
return_error(TSS2_FAPI_RC_GENERAL_FAILURE,
"Policy not implemented");
}
return r;
error:
return r;
/* All policies executed successfully */
return r;
}
/** Compute execution order for policies based on branch selection.
*
* To simplify asynncronous policy executiion a linked list of the policy structures
* needed for execution based on the result of the branch selection callbacks
* is computed.
* @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
* @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
* @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.
*/
static TSS2_RC
compute_policy_list(
IFAPI_POLICY_EXEC_CTX *pol_ctx,
TPML_POLICYELEMENTS *elements)
{
TSS2_RC r = TSS2_RC_SUCCESS;
TPML_POLICYBRANCHES *branches;
TPML_POLICYELEMENTS *or_elements;
size_t branch_idx, i;
for (i = 0; i < elements->count; i++) {
if (elements->elements[i].type == POLICYOR) {
branches = elements->elements[i].element.PolicyOr.branches;
r = pol_ctx->callbacks.cbpolsel(branches, &branch_idx,
pol_ctx->callbacks.cbpolsel_userdata);
return_if_error(r, "Select policy branch.");
or_elements = branches->authorizations[branch_idx].policy;
r = compute_policy_list(pol_ctx, or_elements);
return_if_error(r, "Compute policy digest list for policy or.");
}
r = append_object_to_list(&elements->elements[i], &pol_ctx->policy_elements);
return_if_error(r, "Extend policy list.");
}
return r;
}
/** Initialize policy element list to be executed and store policy in context.
*
* @param[in] pol_ctx Context for execution of a list of policy elements.
* @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_MEMORY if not enough memory can be allocated.
* @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
* @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
*/
TSS2_RC
ifapi_policyeval_execute_prepare(
IFAPI_POLICY_EXEC_CTX *pol_ctx,
TPMI_ALG_HASH hash_alg,
TPMS_POLICY *policy)
{
TSS2_RC r;
pol_ctx->policy = policy;
pol_ctx->hash_alg = hash_alg;
r = compute_policy_list(pol_ctx, policy->policy);
return_if_error(r, "Compute list of policy elements to be executed.");
return TSS2_RC_SUCCESS;
}
/** Execute all policy commands defined by a list of policy elements.
*
* @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 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_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.
* @retval TSS2_FAPI_RC_BAD_PATH if the path is used in inappropriate context
* or contains illegal characters.
* @retval TSS2_FAPI_RC_NOT_PROVISIONED FAPI was not provisioned.
*/
TSS2_RC
ifapi_policyeval_execute(
ESYS_CONTEXT *esys_ctx,
IFAPI_POLICY_EXEC_CTX *current_policy)
{
TSS2_RC r = TSS2_RC_SUCCESS;
NODE_OBJECT_T *current_policy_element;
LOG_DEBUG("call");
while (current_policy->policy_elements) {
r = execute_policy_element(esys_ctx,
(TPMT_POLICYELEMENT *)
current_policy->policy_elements->object,
current_policy->hash_alg,
current_policy);
return_try_again(r);
if (r != TSS2_RC_SUCCESS) {
Esys_FlushContext(esys_ctx, current_policy->session);
current_policy->session = ESYS_TR_NONE;
ifapi_free_node_list(current_policy->policy_elements);
}
return_if_error(r, "Execute policy.");
current_policy_element = current_policy->policy_elements;
current_policy->policy_elements = current_policy->policy_elements->next;
SAFE_FREE(current_policy_element);
}
return r;
}