diff --git a/Makefile-test.am b/Makefile-test.am index ecd759d80..229cbcd75 100644 --- a/Makefile-test.am +++ b/Makefile-test.am @@ -238,6 +238,7 @@ ESYS_TESTS_INTEGRATION_MANDATORY = \ test/integration/esys-clockset.int \ test/integration/esys-clockset-audit.int \ test/integration/esys-commit.int \ + test/integration/esys-cp-hash.int \ test/integration/esys-create-fail.int \ test/integration/esys-create-password-auth.int \ test/integration/esys-create-policy-auth.int \ @@ -1136,7 +1137,7 @@ if POLICY TESTS_UNIT += test/unit/tss2_policy test_unit_tss2_policy_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tss2_policy_LDADD = $(CMOCKA_LIBS) $(libtss2_policy) $(libtss2_esys) +test_unit_tss2_policy_LDADD = $(CMOCKA_LIBS) $(libtss2_policy) $(libtss2_esys) $(libtss2_sys) test_unit_tss2_policy_SOURCES = test/unit/tss2_policy.c src/util/log.c \ test/data/test-fapi-policies.h test/helper/cmocka_all.h endif # POLICY @@ -1593,6 +1594,13 @@ test_integration_esys_get_random_int_SOURCES = \ test/integration/esys-get-random.int.c \ test/integration/main-esys.c test/integration/test-esys.h +test_integration_esys_cp_hash_int_CFLAGS = $(TESTS_CFLAGS) +test_integration_esys_cp_hash_int_LDADD = $(TESTS_LDADD) +test_integration_esys_cp_hash_int_LDFLAGS = $(TESTS_LDFLAGS) +test_integration_esys_cp_hash_int_SOURCES = \ + test/integration/esys-cp-hash.int.c \ + test/integration/main-esys.c test/integration/test-esys.h + test_integration_esys_get_time_int_CFLAGS = $(TESTS_CFLAGS) $(TSS2_ESYS_CFLAGS_CRYPTO) test_integration_esys_get_time_int_LDADD = $(TESTS_LDADD) test_integration_esys_get_time_int_LDFLAGS = $(TESTS_LDFLAGS) $(TSS2_ESYS_LDFLAGS_CRYPTO) diff --git a/include/tss2/tss2_esys.h b/include/tss2/tss2_esys.h index eab4e4c25..1b13f2640 100644 --- a/include/tss2/tss2_esys.h +++ b/include/tss2/tss2_esys.h @@ -3808,6 +3808,24 @@ Esys_SetCryptoCallbacks( ESYS_CONTEXT *esysContext, ESYS_CRYPTO_CALLBACKS *callbacks); +TSS2_RC +Esys_GetCpHash( + ESYS_CONTEXT* esysContext, + TPMI_ALG_HASH hashAlg, + uint8_t **cpHash, + size_t *cpHash_size); + +TSS2_RC +Esys_GetRpHash( + ESYS_CONTEXT* esysContext, + TPMI_ALG_HASH hashAlg, + uint8_t **cpHash, + size_t *cpHash_size); + +TSS2_RC +Esys_Abort( + ESYS_CONTEXT* esysContext); + #ifdef __cplusplus } #endif diff --git a/lib/tss2-esys.def b/lib/tss2-esys.def index c6890d844..8c5be1bf1 100644 --- a/lib/tss2-esys.def +++ b/lib/tss2-esys.def @@ -1,5 +1,6 @@ LIBRARY tss2-esys EXPORTS + Esys_Abort Esys_AC_GetCapability Esys_AC_GetCapability_Async Esys_AC_GetCapability_Finish @@ -110,10 +111,12 @@ EXPORTS Esys_GetCommandAuditDigest Esys_GetCommandAuditDigest_Async Esys_GetCommandAuditDigest_Finish + Esys_GetCpHash Esys_GetPollHandles Esys_GetRandom Esys_GetRandom_Async Esys_GetRandom_Finish + Esys_GetRpHash Esys_GetSessionAuditDigest Esys_GetSessionAuditDigest_Async Esys_GetSessionAuditDigest_Finish diff --git a/lib/tss2-esys.map b/lib/tss2-esys.map index 2062cc324..e95739fde 100644 --- a/lib/tss2-esys.map +++ b/lib/tss2-esys.map @@ -1,5 +1,6 @@ { global: + Esys_Abort; Esys_AC_GetCapability; Esys_AC_GetCapability_Async; Esys_AC_GetCapability_Finish; @@ -109,9 +110,11 @@ Esys_GetCommandAuditDigest; Esys_GetCommandAuditDigest_Async; Esys_GetCommandAuditDigest_Finish; + Esys_GetCpHash; Esys_GetRandom; Esys_GetRandom_Async; Esys_GetRandom_Finish; + Esys_GetRpHash; Esys_GetSessionAuditDigest; Esys_GetSessionAuditDigest_Async; Esys_GetSessionAuditDigest_Finish; diff --git a/src/tss2-esys/esys_cp_rp_hash.c b/src/tss2-esys/esys_cp_rp_hash.c new file mode 100644 index 000000000..45d7ee3d0 --- /dev/null +++ b/src/tss2-esys/esys_cp_rp_hash.c @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/******************************************************************************* + * Copyright 2025, Juergen Repp + * All rights reserved. + ******************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" // IWYU pragma: keep +#endif + +#include // for PRIx32, uint8_t, SIZE_MAX, int32_t +#include // for bool, false, true +#include // for NULL, malloc, size_t, calloc +#include // for memcmp + +#include "esys_int.h" // for RSRC_NODE_T, ESYS_CONTEXT, _ESYS_ASSERT... +#include "esys_mu.h" // for iesys_MU_IESYS_RESOURCE_Marshal, iesys_... +#include "esys_types.h" // for IESYS_RESOURCE, IESYS_RSRC_UNION, IESYS... +#include "esys_iutil.h" // for iesys_compute_cp_hash ... +#include "tss2_common.h" // for TSS2_RC, TSS2_RC_SUCCESS, TSS2_ESYS_RC_... +#include "tss2_esys.h" // for ESYS_CONTEXT, ESYS_TR, ESYS_TR_NONE +#include "tss2_tpm2_types.h" // for TPM2B_NAME, TPM2_HANDLE, TPM2_HR_SHIFT + +#define LOGMODULE esys +#include "util/log.h" // for return_if_error, SAFE_FREE, goto_if_error + +/** Get the cpHash buffer computed by an ESYS async call. + * + * The buffer will be returned if the buffer is found for the passed hashAlg. + * @param esys_ctxt [in,out] The ESYS_CONTEXT. + * @param hashAlg [in] The hash alg used to compute the cp hash. + * @param cpHash [out] The buffer containing the cp hash. + * (caller-callocated) + * @param cpHash_size [out] The size of the cpHash buffer. + * @retval TSS2_RC_SUCCESS on Success. + * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if no cpHash has been computed. + * @retval TSS2_ESYS_RC_BAD_VALUE if hashAlg is not found. + * @retval TSS2_ESYS_RC_BAD_REFERENCE if esys_ctx is NULL. + * @retval TSS2_ESYS_RC_MEMORY if the buffer for the cpHash can't + * be allocated. + */ +TSS2_RC Esys_GetCpHash(ESYS_CONTEXT* esys_ctx, + TPMI_ALG_HASH hashAlg, uint8_t **cpHash, size_t *cpHash_size) { + + uint8_t cp_hash[sizeof(TPMU_HA)]; + TSS2_RC r; + + return_if_null(esys_ctx, "ESYS context is NULL", + TSS2_ESYS_RC_BAD_REFERENCE); + r = iesys_compute_cp_hash(esys_ctx, hashAlg, &cp_hash[0], cpHash_size); + return_if_error(r, "Compute cp hash"); + *cpHash = malloc(*cpHash_size); + return_if_null(*cpHash, "Buffer could not be allocated", + TSS2_ESYS_RC_MEMORY); + memcpy(*cpHash, &cp_hash[0], *cpHash_size); + return TSS2_RC_SUCCESS;} + +/** Get the rpHash buffer computed by an ESYS finalize call. + * + * The buffer will be returned if the buffer is found for the passed hashAlg. + * @param esys_ctx [in,out] The ESYS_CONTEXT. + * @param hashAlg [in] The hash alg used to compute the rp hash. + * @param cpHash [out] The buffer containing the rp hash. + * (caller-callocated) + * @param cpHash_size [out] The size of the cpHash buffer. + * @retval TSS2_RC_SUCCESS on Success. + * @retval TSS2_ESYS_RC_BAD_SEQUENCE: if no cpHash has been computed. + * @retval TSS2_ESYS_RC_BAD_VALUE if hashAlg is not found. + * @retval TSS2_ESYS_RC_BAD_REFERENCE if esys_ctx is NULL. + * @retval TSS2_ESYS_RC_MEMORY if the buffer for the cpHash can't + * be allocated. + */ +TSS2_RC Esys_GetRpHash(ESYS_CONTEXT* esys_ctx, + TPMI_ALG_HASH hashAlg, uint8_t **rpHash, size_t *rpHash_size) { + uint8_t rp_hash[sizeof(TPMU_HA)]; + TSS2_RC r; + + return_if_null(esys_ctx, "ESYS context is NULL", + TSS2_ESYS_RC_BAD_REFERENCE); + + r = iesys_compute_rp_hash(esys_ctx, hashAlg, &rp_hash[0], rpHash_size); + return_if_error(r, "Compute rp hash"); + *rpHash = malloc(*rpHash_size); + + return_if_null(*rpHash, "Buffer could not be allocated", + TSS2_ESYS_RC_MEMORY); + memcpy(*rpHash, &rp_hash[0], *rpHash_size); + return TSS2_RC_SUCCESS; +} + +/** Reset the ESYS state. + * + * If only the cp hash will be computed and there will no finish call + * after the async call the ESYS sate has to be reset to allow further ESYS calls. + * @param esys_ctx [in,out] The ESYS_CONTEXT. + * @param cpHash_size [out] The size of the cpHash buffer. + * @retval TSS2_RC_SUCCESS on Success. + * @retval TSS2_ESYS_RC_BAD_REFERENCE if esys_ctx is NULL. + */ +TSS2_RC Esys_Abort(ESYS_CONTEXT* esys_ctx) { + TSS2_SYS_CONTEXT *sys_ctx; + TSS2_RC r; + + return_if_null(esys_ctx, "ESYS context is NULL", + TSS2_ESYS_RC_BAD_REFERENCE); + esys_ctx->state = ESYS_STATE_INIT; + + r = Esys_GetSysContext(esys_ctx, &sys_ctx); + return_if_error(r, "Could not get Sys context"); + + return Tss2_Sys_Abort(sys_ctx); +} diff --git a/src/tss2-esys/esys_int.h b/src/tss2-esys/esys_int.h index 469534822..8bfe3c855 100644 --- a/src/tss2-esys/esys_int.h +++ b/src/tss2-esys/esys_int.h @@ -34,6 +34,13 @@ typedef struct RSRC_NODE_T { struct RSRC_NODE_T * next; /**< The next object in the linked list. */ } RSRC_NODE_T; +/** An entry in a cpHash or rpHash table. */ +typedef struct { + TPM2_ALG_ID alg; /**< The hash algorithm. */ + size_t size; /**< The digest size. */ + uint8_t digest[sizeof(TPMU_HA)]; /**< The digest. */ +} HASH_TAB_ITEM; + typedef struct { ESYS_TR tpmKey; ESYS_TR bind; @@ -177,6 +184,7 @@ struct ESYS_CONTEXT { current command execution. */ RSRC_NODE_T *session_tab[3]; /**< The list of TPM session meta data in the current command execution. */ + RSRC_NODE_T *auth_objects[3];/**< The list of objects to be authenticated */ int encryptNonceIdx; /**< The index of the encrypt session. */ TPM2B_NONCE *encryptNonce; /**< The nonce of the encrypt session, or NULL if no encrypt session exists. */ @@ -204,6 +212,7 @@ struct ESYS_CONTEXT { ESYS_CRYPTO_CALLBACKS crypto_backend; /**< The backend function pointers to use for crypto operations */ + HASH_TAB_ITEM hash_tab[3]; /**< Buffer for cp/rp hash values */ }; /** The number of authomatic resubmissions. diff --git a/src/tss2-esys/esys_iutil.c b/src/tss2-esys/esys_iutil.c index afad6e113..5fc4fc837 100644 --- a/src/tss2-esys/esys_iutil.c +++ b/src/tss2-esys/esys_iutil.c @@ -185,134 +185,6 @@ iesys_compute_encrypt_nonce(ESYS_CONTEXT * esys_context, return TSS2_RC_SUCCESS; } -/** Computation of the command parameter(cp) hashes. - * - * The command parameter(cp) hash of the command is computed for every - * session. If the sessions use different hash algorithms then different cp - * hashes must be calculated. - * The names of objects with an auth index and the command buffer are used - * to compute the cp hash with the hash algorithm of the corresponding session. - * The result is stored in table together with the used hash algorithm. - * @param[in] esys_context The ESYS_CONTEXT - * @param[in] name1 The name of the first object with an auth index. - * @param[in] name2 The name of the second object with an auth index. - * @param[in] name3 The name of the third object with an auth index. - * @param[3] [out] cp_hash_tab An array with all cp hashes. - * The used hash algorithm is stored in this table to find the - * appropriate values for a session. - * @param[out] cpHashNum Number of computed cp hash values. This value - * corresponds to the number of used hash algorithms. - * @retval TSS2_RC_SUCCESS on success, - * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters. - * @retval TSS2_ESYS_RC_NOT_IMPLEMENTED if a hash algorithm is not implemented. - * @retval TSS2_SYS_RC_* for SAPI errors. - */ -TSS2_RC -iesys_compute_cp_hashtab(ESYS_CONTEXT * esys_context, - const TPM2B_NAME * name1, - const TPM2B_NAME * name2, - const TPM2B_NAME * name3, - HASH_TAB_ITEM cp_hash_tab[3], uint8_t * cpHashNum) -{ - uint8_t ccBuffer[4]; - TSS2_RC r = Tss2_Sys_GetCommandCode(esys_context->sys, &ccBuffer[0]); - return_if_error(r, "Error: get command code"); - const uint8_t *cpBuffer; - size_t cpBuffer_size; - r = Tss2_Sys_GetCpBuffer(esys_context->sys, &cpBuffer_size, &cpBuffer); - return_if_error(r, "Error: get cp buffer"); - *cpHashNum = 0; - for (int i = 0; i < 3; i++) { - RSRC_NODE_T *session = esys_context->session_tab[i]; - bool cpHashFound = false; - if (session != NULL) { - /* We do not want to compute cpHashes multiple times for the same - algorithm to save time and space */ - for (int j = 0; j < *cpHashNum; j++) - /* Check if cpHash for this algorithm was already computed */ - if (cp_hash_tab[j].alg == - session->rsrc.misc.rsrc_session.authHash) { - cpHashFound = true; - break; - } - /* If not, we compute it and append it to the list */ - if (!cpHashFound) { - cp_hash_tab[*cpHashNum].size = sizeof(TPMU_HA); - r = iesys_crypto_cpHash(&esys_context->crypto_backend, session->rsrc.misc.rsrc_session. - authHash, ccBuffer, name1, name2, name3, - cpBuffer, cpBuffer_size, - &cp_hash_tab[*cpHashNum].digest[0], - &cp_hash_tab[*cpHashNum].size); - return_if_error(r, "crypto cpHash"); - - cp_hash_tab[*cpHashNum].alg = - session->rsrc.misc.rsrc_session.authHash; - *cpHashNum += 1; - } - } - } - return r; -} - -/** Computation of the response parameter (rp) hashes. - * The response parameter (rp) hash of the response is computed for every - * session. If the sessions use different hash algorithms then different rp - * hashes must be calculated. - * The names of objects with an auth index and the command buffer are used - * to compute the cp hash with the hash algorithm of the corresponding session. - * The result is stored in table together with the used hash algorithm. - * @param[in] esys_context The ESYS_CONTEXT - * @param[in] rspAuths List of response - * @param[in] const uint8_t * rpBuffer The pointer to the response buffer - * @param[in] size_t rpBuffer_size The size of the response. - * @param[out] HASH_TAB_ITEM rp_hash_tab[3] An array with all rp hashes. - * The used hash algorithm is stored in this table to find the - * appropriate values for a session. - * @param[out] uint8_t Number of computed rp hash values. This value - * corresponds to the number of used hash algorithms. - * @retval TSS2_RC_SUCCESS on success. - * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters. - * @retval TSS2_ESYS_RC_NOT_IMPLEMENTED if a hash algorithm is not implemented. - * @retval TSS2_SYS_RC_* for SAPI errors. - */ -TSS2_RC -iesys_compute_rp_hashtab(ESYS_CONTEXT * esys_context, - const uint8_t * rpBuffer, - size_t rpBuffer_size, - HASH_TAB_ITEM rp_hash_tab[3], uint8_t * rpHashNum) -{ - uint8_t rcBuffer[4] = { 0 }; - uint8_t ccBuffer[4]; - TSS2_RC r = Tss2_Sys_GetCommandCode(esys_context->sys, &ccBuffer[0]); - return_if_error(r, "Error: get command code"); - - for (int i = 0; i < esys_context->authsCount; i++) { - RSRC_NODE_T *session = esys_context->session_tab[i]; - if (session == NULL) - continue; - bool rpHashFound = false; - /* We do not want to compute cpHashes multiple times for the same - algorithm to save time and space */ - for (int j = 0; j < *rpHashNum; j++) - if (rp_hash_tab[j].alg == session->rsrc.misc.rsrc_session.authHash) { - rpHashFound = true; - break; - } - /* If not, we compute it and append it to the list */ - if (!rpHashFound) { - rp_hash_tab[*rpHashNum].size = sizeof(TPMU_HA); - r = iesys_crypto_rpHash(&esys_context->crypto_backend, session->rsrc.misc.rsrc_session.authHash, - rcBuffer, ccBuffer, rpBuffer, rpBuffer_size, - &rp_hash_tab[*rpHashNum].digest[0], - &rp_hash_tab[*rpHashNum].size); - return_if_error(r, "crypto rpHash"); - rp_hash_tab[*rpHashNum].alg = - session->rsrc.misc.rsrc_session.authHash; - *rpHashNum += 1; - } - } - return TPM2_RC_SUCCESS; -} /** Create an esys resource object corresponding to a TPM object. * * The esys object is appended to the resource list stored in the esys context @@ -968,6 +840,30 @@ iesys_decrypt_param(ESYS_CONTEXT * esys_context) return TSS2_RC_SUCCESS; } +TSS2_RC +iesys_compute_rp_hash(ESYS_CONTEXT *esys_context, TPMI_ALG_HASH hash_alg, uint8_t *rp_hash, size_t *rp_hash_size) { + TSS2_RC r; + uint8_t rcBuffer[4] = { 0 }; + uint8_t ccBuffer[4]; + const uint8_t *rpBuffer; + size_t rpBuffer_size; + + r = Tss2_Sys_GetCommandCode(esys_context->sys, &ccBuffer[0]); + return_if_error(r, "Error: get command code"); + + r = Tss2_Sys_GetRpBuffer(esys_context->sys, &rpBuffer_size, &rpBuffer); + return_if_error(r, "Error: get rp buffer"); + + *rp_hash_size = sizeof(TPMU_HA); + r = iesys_crypto_rpHash(&esys_context->crypto_backend, hash_alg, + rcBuffer, ccBuffer, rpBuffer, rpBuffer_size, + &rp_hash[0], + rp_hash_size); + return_if_error(r, "crypto rpHash"); + + return TSS2_RC_SUCCESS; +} + /** Check the HMAC values of the response for all sessions. * * The HMAC values are computed based on the session secrets, the used nonces, @@ -984,11 +880,11 @@ iesys_decrypt_param(ESYS_CONTEXT * esys_context) */ TSS2_RC iesys_check_rp_hmacs(ESYS_CONTEXT * esys_context, - TSS2L_SYS_AUTH_RESPONSE * rspAuths, - HASH_TAB_ITEM rp_hash_tab[3], - uint8_t rpHashNum) + TSS2L_SYS_AUTH_RESPONSE * rspAuths) { TSS2_RC r; + size_t rp_digest_size; + uint8_t rp_digest[sizeof(TPMU_HA)]; for (int i = 0; i < rspAuths->count; i++) { RSRC_NODE_T *session = esys_context->session_tab[i]; @@ -1005,18 +901,12 @@ iesys_check_rp_hmacs(ESYS_CONTEXT * esys_context, continue; } - /* Find the rpHash for the hash algorithm used by this session */ - int hi; - for (hi = 0; hi < rpHashNum; hi++) { - if (rsrc_session->authHash == rp_hash_tab[hi].alg) { - break; - } - } - if (hi == rpHashNum) { - LOG_ERROR("rpHash for alg %"PRIx16 " not found.", - rsrc_session->authHash); - return TSS2_ESYS_RC_GENERAL_FAILURE; - } + rp_digest_size = sizeof(TPMU_HA); + r = iesys_compute_rp_hash(esys_context, + session->rsrc.misc.rsrc_session.authHash, + &rp_digest[0], + &rp_digest_size); + return_if_error(r, "crypto rpHash"); TPM2B_AUTH rp_hmac; rp_hmac.size = sizeof(TPMU_HA); @@ -1026,8 +916,8 @@ iesys_check_rp_hmacs(ESYS_CONTEXT * esys_context, r = iesys_crypto_authHmac(&esys_context->crypto_backend, rsrc_session->authHash, &rsrc_session->sessionValue[0], rsrc_session->sizeHmacValue, - &rp_hash_tab[hi].digest[0], - rp_hash_tab[hi].size, + &rp_digest[0], + rp_digest_size, &rsrc_session->nonceTPM, &rsrc_session->nonceCaller, NULL, NULL, rspAuths->auths[i].sessionAttributes, @@ -1290,6 +1180,41 @@ check_session_feasibility(ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, return TPM2_RC_SUCCESS; } +TSS2_RC +iesys_compute_cp_hash(ESYS_CONTEXT *esys_context, TPMI_ALG_HASH hash_alg, uint8_t *cp_hash, size_t *cp_hash_size) { + TSS2_RC r; + uint8_t ccBuffer[4]; + const uint8_t *cpBuffer; + size_t cpBuffer_size; + + r = Tss2_Sys_GetCommandCode(esys_context->sys, &ccBuffer[0]); + return_if_error(r, "Error: get command code"); + + r = Tss2_Sys_GetCpBuffer(esys_context->sys, &cpBuffer_size, &cpBuffer); + return_if_error(r, "Error: get cp buffer"); + + const TPM2B_NAME * name1; + const TPM2B_NAME * name2; + const TPM2B_NAME * name3; + + name1 = (esys_context->auth_objects[0] != NULL) ? &esys_context->auth_objects[0]->rsrc.name : NULL; + name2 = (esys_context->auth_objects[1] != NULL) ? &esys_context->auth_objects[1]->rsrc.name : NULL; + name3 = (esys_context->auth_objects[2] != NULL) ? &esys_context->auth_objects[2]->rsrc.name : NULL; + + *cp_hash_size = sizeof(TPMU_HA); + + r = iesys_crypto_cpHash(&esys_context->crypto_backend, + hash_alg, + ccBuffer, + name1, name2, name3, + cpBuffer, cpBuffer_size, + &cp_hash[0], + cp_hash_size); + return_if_error(r, "crypto cpHash"); + + return TSS2_RC_SUCCESS; +} + /** Compute HMAC for a session. * * The HMAC is computed from the appropriate cp hash, the caller nonce, the TPM @@ -1320,8 +1245,12 @@ iesys_compute_hmac(ESYS_CONTEXT *esys_context, RSRC_NODE_T * session, TPM2B_NONCE * encryptNonce, TPMS_AUTH_COMMAND * auth) { + (void)cp_hash_tab; + (void)cpHashNum; TSS2_RC r; size_t authHash_size = 0; + uint8_t cp_hash[sizeof(TPMU_HA)]; + size_t cp_hash_size; if (session != NULL) { IESYS_SESSION *rsrc_session = &session->rsrc.misc.rsrc_session; @@ -1329,13 +1258,9 @@ iesys_compute_hmac(ESYS_CONTEXT *esys_context, RSRC_NODE_T * session, authHash, &authHash_size); return_if_error(r, "Initializing auth session"); - int hi = 0; - for (int j = 0; j < cpHashNum; j++) { - if (rsrc_session->authHash == cp_hash_tab[j].alg) { - hi = j; - break; - } - } + r = iesys_compute_cp_hash(esys_context, rsrc_session->authHash, cp_hash, &cp_hash_size); + return_if_error(r, "crypto cpHash"); + auth->hmac.size = sizeof(TPMU_HA); /* if other than first session is used for for parameter encryption the corresponding nonces have to be included into the hmac @@ -1343,8 +1268,8 @@ iesys_compute_hmac(ESYS_CONTEXT *esys_context, RSRC_NODE_T * session, r = iesys_crypto_authHmac(&esys_context->crypto_backend, rsrc_session->authHash, &rsrc_session->sessionValue[0], rsrc_session->sizeHmacValue, - &cp_hash_tab[hi].digest[0], - cp_hash_tab[hi].size, + &cp_hash[0], + cp_hash_size, &rsrc_session->nonceCaller, &rsrc_session->nonceTPM, decryptNonce, encryptNonce, @@ -1387,9 +1312,10 @@ iesys_gen_auths(ESYS_CONTEXT * esys_context, int encryptNonceIdx = 0; TPM2B_NONCE *encryptNonce = NULL; - RSRC_NODE_T *objects[] = { h1, h2, h3 }; + esys_context->auth_objects[0] = h1; + esys_context->auth_objects[1] = h2; + esys_context->auth_objects[2] = h3; - HASH_TAB_ITEM cp_hash_tab[3]; uint8_t cpHashNum = 0; auths->count = 0; @@ -1412,26 +1338,17 @@ iesys_gen_auths(ESYS_CONTEXT * esys_context, decryptNonceIdx = 0; } - - /* Compute cp hash values for command buffer for all used algorithms */ - - r = iesys_compute_cp_hashtab(esys_context, - (h1 != NULL) ? &h1->rsrc.name : NULL, - (h2 != NULL) ? &h2->rsrc.name : NULL, - (h3 != NULL) ? &h3->rsrc.name : NULL, - &cp_hash_tab[0], &cpHashNum); - return_if_error(r, "Error while computing cp hashes"); - for (int session_idx = 0; session_idx < 3; session_idx++) { auths->auths[auths->count].nonce.size = 0; auths->auths[auths->count].sessionAttributes = 0; if (esys_context->session_type[session_idx] == ESYS_TR_PASSWORD) { - if (objects[session_idx] == NULL) { + if (esys_context->auth_objects[session_idx] == NULL) { auths->auths[auths->count].hmac.size = 0; auths->count += 1; } else { auths->auths[auths->count].sessionHandle = TPM2_RH_PW; - auths->auths[auths->count].hmac = objects[session_idx]->auth; + auths->auths[auths->count].hmac = + esys_context->auth_objects[session_idx]->auth; auths->count += 1; } continue; @@ -1441,10 +1358,11 @@ iesys_gen_auths(ESYS_CONTEXT * esys_context, IESYS_SESSION *rsrc_session = &session->rsrc.misc.rsrc_session; if (rsrc_session->type_policy_session == POLICY_PASSWORD) { auths->auths[auths->count].sessionHandle = session->rsrc.handle; - if (objects[session_idx] == NULL) { + if (esys_context->auth_objects[session_idx] == NULL) { auths->auths[auths->count].hmac.size = 0; } else { - auths->auths[auths->count].hmac = objects[session_idx]->auth; + auths->auths[auths->count].hmac = + esys_context->auth_objects[session_idx]->auth; } auths->auths[auths->count].sessionAttributes = session->rsrc.misc.rsrc_session.sessionAttributes; @@ -1453,7 +1371,7 @@ iesys_gen_auths(ESYS_CONTEXT * esys_context, } } r = iesys_compute_hmac(esys_context, esys_context->session_tab[session_idx], - &cp_hash_tab[0], cpHashNum, + &esys_context->hash_tab[0], cpHashNum, (session_idx == 0 && decryptNonceIdx > 0) ? decryptNonce : NULL, (session_idx == 0 @@ -1494,8 +1412,6 @@ iesys_check_response(ESYS_CONTEXT * esys_context) const uint8_t *rpBuffer; size_t rpBuffer_size; TSS2L_SYS_AUTH_RESPONSE rspAuths; - HASH_TAB_ITEM rp_hash_tab[3]; - uint8_t rpHashNum = 0; if (esys_context->authsCount == 0) { LOG_TRACE("No auths to verify"); @@ -1521,13 +1437,7 @@ iesys_check_response(ESYS_CONTEXT * esys_context) r = Tss2_Sys_GetRpBuffer(esys_context->sys, &rpBuffer_size, &rpBuffer); return_if_error(r, "Error: get rp buffer"); - r = iesys_compute_rp_hashtab(esys_context, - rpBuffer, rpBuffer_size, - &rp_hash_tab[0], &rpHashNum); - return_if_error(r, "Error: while computing response hashes"); - - r = iesys_check_rp_hmacs(esys_context, &rspAuths, &rp_hash_tab[0], - rpHashNum); + r = iesys_check_rp_hmacs(esys_context, &rspAuths); return_if_error(r, "Error: response hmac check"); if (esys_context->encryptNonce == NULL) { diff --git a/src/tss2-esys/esys_iutil.h b/src/tss2-esys/esys_iutil.h index 6167a44a9..fa43c4f5e 100644 --- a/src/tss2-esys/esys_iutil.h +++ b/src/tss2-esys/esys_iutil.h @@ -33,13 +33,6 @@ extern "C" { */ #define ESYS_TR_MIN_OBJECT (TPM2_RH_LAST + 1 + 0x1000) -/** An entry in a cpHash or rpHash table. */ -typedef struct { - TPM2_ALG_ID alg; /**< The hash algorithm. */ - size_t size; /**< The digest size. */ - uint8_t digest[sizeof(TPMU_HA)]; /**< The digest. */ -} HASH_TAB_ITEM; - TSS2_RC init_session_tab( ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3); @@ -113,9 +106,7 @@ TSS2_RC iesys_decrypt_param( TSS2_RC iesys_check_rp_hmacs( ESYS_CONTEXT *esysContext, - TSS2L_SYS_AUTH_RESPONSE *rspAuths, - HASH_TAB_ITEM rp_hash_tab[3], - uint8_t rpHashNum); + TSS2L_SYS_AUTH_RESPONSE *rspAuths); void iesys_compute_bound_entity( const TPM2B_NAME *name, @@ -181,6 +172,18 @@ TSS2_RC iesys_adapt_auth_value( void iesys_strip_trailing_zeros( TPM2B_AUTH *auth_value); +TSS2_RC iesys_compute_cp_hash( + ESYS_CONTEXT *esys_context, + TPMI_ALG_HASH hash_alg, + uint8_t *cp_hash, + size_t *cp_hash_size); + + TSS2_RC iesys_compute_rp_hash( + ESYS_CONTEXT *esys_context, + TPMI_ALG_HASH hash_alg, + uint8_t *rp_hash, + size_t *rp_hash_size); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/tss2-esys/tss2-esys.vcxproj b/src/tss2-esys/tss2-esys.vcxproj index 39bcf15f0..0f9e8cfc7 100644 --- a/src/tss2-esys/tss2-esys.vcxproj +++ b/src/tss2-esys/tss2-esys.vcxproj @@ -243,6 +243,7 @@ + @@ -264,4 +265,4 @@ - \ No newline at end of file + diff --git a/test/integration/esys-cp-hash.int.c b/test/integration/esys-cp-hash.int.c new file mode 100644 index 000000000..3cc9c8e81 --- /dev/null +++ b/test/integration/esys-cp-hash.int.c @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/******************************************************************************* + * Copyright 2025, Juergen Repp + * All rights reserved. + *******************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" // IWYU pragma: keep +#endif + +#include // for free, NULL, EXIT_FAILURE, EXIT_SUCCESS + +#include "tss2_common.h" // for BYTE, TSS2_RC +#include "tss2_esys.h" // for ESYS_TR_NONE, Esys_GetRandom, Esys_Star... +#include "tss2_tpm2_types.h" // for TPM2B_DIGEST, TPM2_RC_SUCCESS, TPMA_SES... + +#define LOGMODULE test +#include "util/log.h" // for LOG_ERROR, LOGBLOB_DEBUG, LOG_INFO + + +/** Test the ESYS function Esys_GetRandom. + * + * Tested ESYS commands: + * - Esys_GetRandom() (M) + * - Esys_StartAuthSession() (M) + * + * @param[in,out] esys_context The ESYS_CONTEXT. + * @retval EXIT_FAILURE + * @retval EXIT_SUCCESS + */ +int +test_esyscp_hash(ESYS_CONTEXT * esys_context) +{ + + TSS2_RC r; + int i; + + TPM2B_DIGEST *randomBytes; + + uint8_t get_rand_cp_hash[32] = + { 0xc0, 0x75, 0xb7, 0xe6, 0x37, 0xa7, 0x13, 0x1b, 0x0c, 0x52, + 0x3c, 0xf1, 0x96, 0x5e, 0xba, 0xe2, 0xaf, 0xb1, 0x16, 0x0b, + 0x6e, 0xf7, 0xc7, 0xe9, 0x2d, 0x0d, 0x24, 0xce, 0x0a, 0x5d, + 0x94, 0x11 }; + + ESYS_TR session = ESYS_TR_NONE; + const TPMT_SYM_DEF symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits = {.aes = 128}, + .mode = {.aes = TPM2_ALG_CFB} + }; + uint8_t *cp_hash; + size_t cp_hash_size; + uint8_t *rp_hash; + size_t rp_hash_size; + + r = Esys_StartAuthSession(esys_context, ESYS_TR_NONE, ESYS_TR_NONE, + ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + NULL, + TPM2_SE_HMAC, &symmetric, TPM2_ALG_SHA256, + &session); + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("Esys_StartAuthSession FAILED! Response Code : 0x%x", r); + goto error; + } + + r = Esys_TRSess_SetAttributes(esys_context, session, TPMA_SESSION_CONTINUESESSION | TPMA_SESSION_AUDIT, + TPMA_SESSION_CONTINUESESSION | TPMA_SESSION_AUDIT); + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("SetAttributes on session FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + + r = Esys_GetRandom_Async(esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, 48); + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("GetRandom with session FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + + r = Esys_GetCpHash(esys_context, TPM2_ALG_SHA256, &cp_hash, &cp_hash_size); + + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("GetCpHash FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + + LOGBLOB_DEBUG(cp_hash, cp_hash_size, "cp hash"); + + /* Check cp hash for get_random with 48 bytes. */ + for (i = 0; i < 32; i++) { + if (cp_hash[i] != get_rand_cp_hash[i]) { + LOG_ERROR("Wrong cp hash value."); + free(cp_hash); + goto error_cleansession; + } + } + free(cp_hash); + + do { + /* Call call finish as long as retry return codes are returned. */ + r = Esys_GetRandom_Finish(esys_context, &randomBytes); + if (r == TSS2_RC_SUCCESS) { + break; + } else if ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN) { + continue; + } else{ + LOG_ERROR("GetRandom with session FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + } while (1); + + r = Esys_GetRpHash(esys_context, TPM2_ALG_SHA256, &rp_hash, &rp_hash_size); + + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("GetRpHash FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + free(rp_hash); + + LOGBLOB_DEBUG(&randomBytes->buffer[0], randomBytes->size, + "Randoms (count=%i):", randomBytes->size); + free(randomBytes); + + r = Esys_GetRandom_Async(esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, 48); + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("GetRandom with session FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + + r = Esys_GetCpHash(esys_context, TPM2_ALG_SHA256, &cp_hash, &cp_hash_size); + + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("GetCpHash FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + + free(cp_hash); + + /* Check whether call of Esys_GetRandom works after abort. */ + + r = Esys_Abort(esys_context); + + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("Abort FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + r = Esys_GetRandom(esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, 48, + &randomBytes); + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("GetRandom with session FAILED! Response Code : 0x%x", r); + goto error_cleansession; + } + + free(randomBytes); + + r = Esys_FlushContext(esys_context, session); + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("FlushContext FAILED! Response Code : 0x%x", r); + } + + return EXIT_SUCCESS; + + error_cleansession: + r = Esys_FlushContext(esys_context, session); + if (r != TPM2_RC_SUCCESS) { + LOG_ERROR("FlushContext FAILED! Response Code : 0x%x", r); + } + error: + return EXIT_FAILURE; +} + +int +test_invoke_esys(ESYS_CONTEXT * esys_context) { + return test_esyscp_hash(esys_context); +} diff --git a/tss2-dlopen/tss2-dlopen-esys.c b/tss2-dlopen/tss2-dlopen-esys.c index 3c261ed42..67a9c1d1c 100644 --- a/tss2-dlopen/tss2-dlopen-esys.c +++ b/tss2-dlopen/tss2-dlopen-esys.c @@ -2303,3 +2303,12 @@ MAKE_ESYS_1(Esys_GetSysContext, TSS2_SYS_CONTEXT **, sys_context); MAKE_ESYS_1(Esys_SetCryptoCallbacks, ESYS_CRYPTO_CALLBACKS *, callbacks); +MAKE_ESYS_3(Esys_GetCpHash, + TPMI_ALG_HASH, hashAlg, + uint8_t **, cpHash, + size_t, *cpHash_size); +MAKE_ESYS_3(Esys_GetRpHash, + TPMI_ALG_HASH, hashAlg, + uint8_t **, cpHash, + size_t, *cpHash_size); +MAKE_ESYS_0(Esys_Abort);