diff --git a/Makefile-test.am b/Makefile-test.am index bdcc2e6c4..26398d157 100644 --- a/Makefile-test.am +++ b/Makefile-test.am @@ -1141,12 +1141,13 @@ test_tpmclient_tpmclient_int_LDADD = $(TESTS_LDADD) test_tpmclient_tpmclient_int_SOURCES = \ test/tpmclient/tpmclient.int.c test/integration/main-sys.c -test_integration_libtest_utils_la_CFLAGS = $(AM_CFLAGS) $(TESTS_CFLAGS) +test_integration_libtest_utils_la_CFLAGS = $(AM_CFLAGS) $(TESTS_CFLAGS) $(JSONC_CFLAGS) test_integration_libtest_utils_la_SOURCES = \ test/integration/sys-util.c test/integration/sys-util.h \ test/integration/sys-session-util.c test/integration/session-util.h \ test/integration/sys-entity-util.c test/integration/test.h \ test/integration/test-common.c test/integration/test-common.h \ + test/integration/test-common-tcti.c test/integration/test-common-tcti.h \ src/util/log.c test_integration_sys_asymmetric_encrypt_decrypt_int_CFLAGS = $(AM_CFLAGS) $(TESTS_CFLAGS) diff --git a/src/tss2-tcti/tcti-tbs.h b/src/tss2-tcti/tcti-tbs.h index 1a09bd603..722beecc2 100644 --- a/src/tss2-tcti/tcti-tbs.h +++ b/src/tss2-tcti/tcti-tbs.h @@ -11,6 +11,10 @@ #define TCTI_TBS_MAGIC 0xfbf2afa3761e188aULL +#ifndef WINVER +typedef BYTE *PBYTE; +#endif /* WINVER */ + typedef struct { TSS2_TCTI_COMMON_CONTEXT common; void *hContext; diff --git a/test/integration/fapi-key-create-null-key-sign.int.c b/test/integration/fapi-key-create-null-key-sign.int.c index a6565d1c1..2fdee1016 100644 --- a/test/integration/fapi-key-create-null-key-sign.int.c +++ b/test/integration/fapi-key-create-null-key-sign.int.c @@ -8,19 +8,21 @@ #include "config.h" // IWYU pragma: keep #endif -#include // for json_object_new_string, json_object -#include // for uint8_t -#include // for NULL, size_t, sprintf -#include // for EXIT_FAILURE, EXIT_SUCCESS -#include // for strncmp - -#include "test-fapi.h" // for init_fapi, fapi_profile, test_invoke_fapi -#include "tss2_common.h" // for TSS2_FAPI_RC_BAD_VALUE, TSS2_RC_SUCCESS -#include "tss2_fapi.h" // for Fapi_CreateKey, Fapi_Delete, Fapi_Finalize -#include "tss2_tpm2_types.h" // for TPM2B_DIGEST +#include // for json_object_new_string +#include // for uint8_t +#include // for NULL, size_t, sprintf +#include // for EXIT_FAILURE, EXIT_SU... +#include // for strncmp + +#include "test-fapi.h" // for init_fapi, fapi_profile +#include "test/integration/test-common-tcti.h" // for tcti_is_volatile, tct... +#include "tss2_common.h" // for TSS2_FAPI_RC_BAD_VALUE +#include "tss2_fapi.h" // for Fapi_CreateKey, Fapi_... +#include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT +#include "tss2_tpm2_types.h" // for TPM2B_DIGEST #define LOGMODULE test -#include "util/log.h" // for goto_if_error, SAFE_FREE, UNUSED, retur... +#include "util/log.h" // for goto_if_error, SAFE_FREE #define PASSWORD "abc" #define SIGN_TEMPLATE "sign,noDa" @@ -75,11 +77,14 @@ auth_callback( int test_fapi_key_create_null_sign(FAPI_CONTEXT *context) { - TSS2_RC r; - char *sigscheme = NULL; - uint8_t *signature = NULL; - char *publicKey = NULL; - char *path_list = NULL; + TSS2_RC r; + int ret; + TSS2_TCTI_CONTEXT *tcti; + libtpms_state libtpms_state; + char *sigscheme = NULL; + uint8_t *signature = NULL; + char *publicKey = NULL; + char *path_list = NULL; if (strncmp("P_ECC", fapi_profile, 5) != 0) sigscheme = "RSA_PSS"; @@ -87,6 +92,11 @@ test_fapi_key_create_null_sign(FAPI_CONTEXT *context) r = Fapi_Provision(context, NULL, NULL, NULL); goto_if_error(r, "Error Fapi_Provision", error); + r = Fapi_GetTcti(context, &tcti); + if (tcti_is_volatile(tcti) && !tcti_state_backup_supported(tcti)) { + return EXIT_SKIP; + } + r = Fapi_SetAuthCB(context, auth_callback, NULL); goto_if_error(r, "Error SetPolicyAuthCallback", error); @@ -140,11 +150,17 @@ test_fapi_key_create_null_sign(FAPI_CONTEXT *context) &digest.buffer[0], digest.size, signature, signatureSize); goto_if_error(r, "Error Fapi_VerifySignature", error); + ret = tcti_state_backup_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_backup_if_necessary", error); + Fapi_Finalize(&context); int rc = init_fapi(fapi_profile, &context); if (rc) goto error; + ret = tcti_state_restore_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_restore_if_necessary", error); + /* Test the creation of a primary in the storage hierarchy. */ r = Fapi_CreateKey(context, "HS/myPrimary", "noDa", "", PASSWORD); diff --git a/test/integration/fapi-second-provisioning.int.c b/test/integration/fapi-second-provisioning.int.c index 07cecbf57..b71a198e9 100644 --- a/test/integration/fapi-second-provisioning.int.c +++ b/test/integration/fapi-second-provisioning.int.c @@ -8,15 +8,17 @@ #include "config.h" // IWYU pragma: keep #endif -#include // for NULL, EXIT_FAILURE, EXIT_SUCCESS -#include // for strcmp, strncmp +#include // for NULL, EXIT_FAILURE +#include // for strcmp, strncmp -#include "test-fapi.h" // for init_fapi, FAPI_PROFILE, pcr_reset, EXIT_SKIP -#include "tss2_common.h" // for TSS2_RC, TSS2_RC_SUCCESS, TSS2_FAPI_RC_AUTH... -#include "tss2_fapi.h" // for Fapi_Provision, Fapi_Delete, Fapi_Finalize +#include "test-fapi.h" // for init_fapi, FAPI_PROFILE +#include "test/integration/test-common-tcti.h" // for tcti_state_backup_if_... +#include "tss2_common.h" // for TSS2_RC, TSS2_RC_SUCCESS +#include "tss2_fapi.h" // for Fapi_Provision, Fapi_... +#include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT #define LOGMODULE test -#include "util/log.h" // for goto_if_error, UNUSED, LOG_ERROR, LOG_WARNING +#include "util/log.h" // for goto_if_error, UNUSED #define PASSWORD "abc" @@ -55,6 +57,9 @@ int test_fapi_test_second_provisioning(FAPI_CONTEXT *context) { TSS2_RC r; + int ret; + TSS2_TCTI_CONTEXT *tcti; + libtpms_state libtpms_state; if (strncmp(FAPI_PROFILE, "P_RSA", 5) == 0) { LOG_WARNING("Default ECC profile needed for this test %s is used", FAPI_PROFILE); @@ -65,6 +70,11 @@ test_fapi_test_second_provisioning(FAPI_CONTEXT *context) r = Fapi_Provision(context, PASSWORD, PASSWORD, NULL); goto_if_error(r, "Error Fapi_Provision", error); + r = Fapi_GetTcti(context, &tcti); + if (tcti_is_volatile(tcti) && !tcti_state_backup_supported(tcti)) { + return EXIT_SKIP; + } + r = pcr_reset(context, 16); goto_if_error(r, "Error pcr_reset", error); @@ -73,12 +83,18 @@ test_fapi_test_second_provisioning(FAPI_CONTEXT *context) goto_if_error(r, "Error Fapi_NV_Undefine", error); + ret = tcti_state_backup_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_backup_if_necessary", error); + Fapi_Finalize(&context); int rc = init_fapi("P_RSA2", &context); if (rc) goto error; + ret = tcti_state_restore_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_restore_if_necessary", error); + /* Authentication should not work due to auth for hierarchy was set. */ r = Fapi_Provision(context, NULL, NULL, NULL); @@ -101,11 +117,17 @@ test_fapi_test_second_provisioning(FAPI_CONTEXT *context) r = Fapi_Delete(context, "/"); goto_if_error(r, "Error Fapi_Delete", error); + ret = tcti_state_backup_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_backup_if_necessary", error); + Fapi_Finalize(&context); rc = init_fapi("P_RSA2", &context); if (rc) goto error; + ret = tcti_state_restore_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_restore_if_necessary", error); + /* Correct Provisioning with auth value for hierarchy from previous provisioning. Non information whether auth value is needed is available. */ @@ -126,6 +148,9 @@ test_fapi_test_second_provisioning(FAPI_CONTEXT *context) r = Fapi_Delete(context, "/"); goto_if_error(r, "Error Fapi_Delete", error); + ret = tcti_state_backup_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_backup_if_necessary", error); + Fapi_Finalize(&context); if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { @@ -137,11 +162,17 @@ test_fapi_test_second_provisioning(FAPI_CONTEXT *context) if (rc) goto error; + ret = tcti_state_restore_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_restore_if_necessary", error); + /* A policy will be assigned to owner and endorsement hierarchy. */ r = Fapi_Provision(context, NULL, NULL, NULL); goto_if_error(r, "Error Fapi_Provision", error); + ret = tcti_state_backup_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_backup_if_necessary", error); + Fapi_Finalize(&context); if (strcmp(FAPI_PROFILE, "P_ECC") == 0) { rc = init_fapi("P_ECC", &context); @@ -156,6 +187,9 @@ test_fapi_test_second_provisioning(FAPI_CONTEXT *context) if (rc) goto error; + ret = tcti_state_restore_if_necessary(context, &libtpms_state); + goto_if_error(ret, "Error tcti_state_restore_if_necessary", error); + /* Owner and endorsement hierarchy will be authorized via policy and policy will be reset. */ r = Fapi_Provision(context, NULL, NULL, NULL); diff --git a/test/integration/test-common-tcti.c b/test/integration/test-common-tcti.c new file mode 100644 index 000000000..1c25a14b9 --- /dev/null +++ b/test/integration/test-common-tcti.c @@ -0,0 +1,507 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/*********************************************************************** + * Copyright (c) 2024, Infineon Technologies AG + * + * All rights reserved. + ***********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" // for TCTI_LIBTPMS, TCTI_MSSIM +#endif + +#include // for PRIx64 +#include // for TPMLIB_STATE_PERMANENT, TPM... +#include // for true, false, bool +#include // for free, EXIT_SUCCESS +#include // for memset, memcpy + +#include "test-common-tcti.h" +#include "test-fapi.h" // for EXIT_ERROR, EXIT_SKIP +#include "test/fuzz/tcti/tcti-fuzzing.h" // for TCTI_FUZZING_MAGIC +#include "tss2-tcti/tcti-cmd.h" // for TCTI_CMD_MAGIC +#include "tss2-tcti/tcti-device.h" // for TCTI_DEVICE_MAGIC +#include "tss2-tcti/tcti-i2c-helper.h" // for TCTI_I2C_HELPER_MAGIC +#include "tss2-tcti/tcti-libtpms.h" // for TSS2_TCTI_LIBTPMS_CONTEXT +#include "tss2-tcti/tcti-mssim.h" // for TCTI_MSSIM_MAGIC +#include "tss2-tcti/tcti-pcap.h" // for TCTI_PCAP_MAGIC, TSS2_TCTI_... +#include "tss2-tcti/tcti-spi-helper.h" // for TCTI_SPI_HELPER_MAGIC +#include "tss2-tcti/tcti-start-sim.h" // for TCTI_START_SIM_MAGIC, TSS2_... +#include "tss2-tcti/tcti-swtpm.h" // for TCTI_SWTPM_MAGIC +#include "tss2-tcti/tcti-tbs.h" // for TCTI_TBS_MAGIC +#include "tss2-tcti/tctildr.h" // for TCTILDR_MAGIC, TSS2_TCTILDR... +#include "tss2_common.h" // for TSS2_RC, TSS2_RC_SUCCESS +#include "tss2_tcti_libtpms.h" // for Tss2_Tcti_Libtpms_Reset +#include "tss2_tcti_mssim.h" // for tcti_platform_command, MS_S... +#include "tss2_tcti_swtpm.h" // for Tss2_Tcti_Swtpm_Reset +#include "util/aux_util.h" // for ARRAY_LEN + +#define LOGMODULE test +#include "util/log.h" // for LOG_ERROR, LOG_DEBUG, LOG_T... + + +/** Define a proxy tcti that returns yielded on every second invocation + * thus the corresponding handling code in ESYS can be tested. + * The first invocation will be Tss2_Sys_StartUp. + */ +#ifdef TEST_ESYS + +TSS2_RC +(*transmit_hook) (const uint8_t *command_buffer, size_t command_size) = NULL; + +#define TCTI_PROXY_MAGIC 0x5250584f0a000000ULL /* 'PROXY\0\0\0' */ +#define TCTI_PROXY_VERSION 0x1 + + +TSS2_TCTI_CONTEXT_PROXY* +tcti_proxy_cast (TSS2_TCTI_CONTEXT *ctx) +{ + TSS2_TCTI_CONTEXT_PROXY *ctxi = (TSS2_TCTI_CONTEXT_PROXY*)ctx; + if (ctxi == NULL || ctxi->magic != TCTI_PROXY_MAGIC) { + LOG_ERROR("Bad tcti passed."); + return NULL; + } + return ctxi; +} + +TSS2_RC +tcti_proxy_transmit( + TSS2_TCTI_CONTEXT *tctiContext, + size_t command_size, + const uint8_t *command_buffer + ) +{ + TSS2_RC rval; + TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext); + + if (tcti_proxy->state == intercepting) { + return TSS2_RC_SUCCESS; + } + + if (transmit_hook != NULL) { + rval = transmit_hook(command_buffer, command_size); + if (rval != TSS2_RC_SUCCESS) { + LOG_ERROR("transmit hook requested error"); + return rval; + } + } + + rval = Tss2_Tcti_Transmit(tcti_proxy->tctiInner, command_size, + command_buffer); + if (rval != TSS2_RC_SUCCESS) { + LOG_ERROR("Calling TCTI Transmit"); + return rval; + } + + return rval; +} + +uint8_t yielded_response[] = { + 0x80, 0x01, /* TPM_ST_NO_SESSION */ + 0x00, 0x00, 0x00, 0x0A, /* Response Size 10 */ + 0x00, 0x00, 0x09, 0x08 /* TPM_RC_YIELDED */ +}; + +TSS2_RC +tcti_proxy_receive( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *response_size, + uint8_t *response_buffer, + int32_t timeout + ) +{ + TSS2_RC rval; + TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext); + + if (tcti_proxy->state == intercepting) { + *response_size = sizeof(yielded_response); + + if (response_buffer != NULL) { + memcpy(response_buffer, &yielded_response[0], sizeof(yielded_response)); + tcti_proxy->state = forwarding; + } + return TSS2_RC_SUCCESS; + } + + rval = Tss2_Tcti_Receive(tcti_proxy->tctiInner, response_size, + response_buffer, timeout); + if (rval != TSS2_RC_SUCCESS) { + LOG_ERROR("Calling TCTI Transmit"); + return rval; + } + + /* First read with response buffer == NULL is to get the size of the + * response. The subsequent read needs to be forwarded also */ + if (response_buffer != NULL) + tcti_proxy->state = intercepting; + + return rval; +} + +void +tcti_proxy_finalize( + TSS2_TCTI_CONTEXT *tctiContext) +{ + memset(tctiContext, 0, sizeof(TSS2_TCTI_CONTEXT_PROXY)); +} + +TSS2_RC +tcti_proxy_initialize( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *contextSize, + TSS2_TCTI_CONTEXT *tctiInner) +{ + TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = + (TSS2_TCTI_CONTEXT_PROXY*) tctiContext; + + if (tctiContext == NULL && contextSize == NULL) { + return TSS2_TCTI_RC_BAD_VALUE; + } else if (tctiContext == NULL) { + *contextSize = sizeof(*tcti_proxy); + return TSS2_RC_SUCCESS; + } + + /* Init TCTI context */ + memset(tcti_proxy, 0, sizeof(*tcti_proxy)); + TSS2_TCTI_MAGIC (tctiContext) = TCTI_PROXY_MAGIC; + TSS2_TCTI_VERSION (tctiContext) = TCTI_PROXY_VERSION; + TSS2_TCTI_TRANSMIT (tctiContext) = tcti_proxy_transmit; + TSS2_TCTI_RECEIVE (tctiContext) = tcti_proxy_receive; + TSS2_TCTI_FINALIZE (tctiContext) = tcti_proxy_finalize; + TSS2_TCTI_CANCEL (tctiContext) = NULL; + TSS2_TCTI_GET_POLL_HANDLES (tctiContext) = NULL; + TSS2_TCTI_SET_LOCALITY (tctiContext) = NULL; + tcti_proxy->tctiInner = tctiInner; + tcti_proxy->state = forwarding; + + return TSS2_RC_SUCCESS; +} +#endif /* TEST_ESYS */ + +static TSS2_TCTI_CONTEXT *tcti_unwrap_max_depth(TSS2_TCTI_CONTEXT *tcti, int max_depth) { + uint64_t magic; + + for (int i = 0; max_depth < 0 || i < max_depth; i++) { + magic = TSS2_TCTI_MAGIC(tcti); + + switch (magic) { + case TCTILDR_MAGIC: + LOG_TRACE("TCTI is tctildr (0x%" PRIx64 "). Unwrapping...", magic); + tcti = ((TSS2_TCTILDR_CONTEXT *) tcti)->tcti; + break; + case TCTI_PCAP_MAGIC: + LOG_TRACE("TCTI is tcti-pcap (0x%" PRIx64 "). Unwrapping...", magic); + tcti = ((TSS2_TCTI_PCAP_CONTEXT *) tcti)->tcti_child; + break; + case TCTI_START_SIM_MAGIC: + LOG_TRACE("TCTI is tcti-start-sim (0x%" PRIx64 "). Unwrapping...", magic); + tcti = ((TSS2_TCTI_START_SIM_CONTEXT *) tcti)->tcti_child; + break; + case TCTI_PROXY_MAGIC: + LOG_TRACE("TCTI is tcti-proxy (0x%" PRIx64 "). Unwrapping...", magic); + tcti = ((TSS2_TCTI_CONTEXT_PROXY *) tcti)->tctiInner; + break; + default: + return tcti; + } + } + + return tcti; +} + +TSS2_TCTI_CONTEXT *tcti_unwrap(TSS2_TCTI_CONTEXT *tcti) { + return tcti_unwrap_max_depth(tcti, -1); +} + +typedef struct { + const char *name; + uint64_t magic; +} tcti_type; + +/* grep -rhPo '(?<=#define) TCTI_.*_MAGIC.*' | sort | uniq */ +tcti_type tcti_types[] = { + {.name = "ldr", .magic = TCTILDR_MAGIC }, + {.name = "cmd", .magic = TCTI_CMD_MAGIC }, + {.name = "device", .magic = TCTI_DEVICE_MAGIC }, + {.name = "fuzzing", .magic = TCTI_FUZZING_MAGIC }, + {.name = "libtpms", .magic = TCTI_LIBTPMS_MAGIC }, + {.name = "mssim", .magic = TCTI_MSSIM_MAGIC }, + {.name = "pcap", .magic = TCTI_PCAP_MAGIC }, + {.name = "proxy", .magic = TCTI_PROXY_MAGIC }, + {.name = "spi-helper", .magic = TCTI_SPI_HELPER_MAGIC }, + {.name = "i2c-helper", .magic = TCTI_I2C_HELPER_MAGIC }, + {.name = "start-sim", .magic = TCTI_START_SIM_MAGIC }, + {.name = "swtpm", .magic = TCTI_SWTPM_MAGIC }, + {.name = "tbs", .magic = TCTI_TBS_MAGIC }, + {.name = "fake", .magic = 0x46414b4500000000ULL }, + {.name = "tpmerror", .magic = 0x5441455252000000ULL }, + {.name = "tryagainerror", .magic = 0x5441455252000000ULL }, + {.name = "yielder", .magic = 0x5949454c44455200ULL }, + + /* from https://github.com/tpm2-software/tpm2-abrmd */ + {.name = "tabrmd", .magic = 0x1c8e03ff00db0f92 }, +}; + +void tcti_print(TSS2_TCTI_CONTEXT *tcti) { + uint64_t magic = TSS2_TCTI_MAGIC(tcti); + bool found = false; + + for (size_t i = 0; i < ARRAY_LEN(tcti_types); i++) { + if (magic == tcti_types[i].magic) { + LOG_DEBUG("TCTI dump: %s", tcti_types[i].name); + found = true; + } + } + + if (!found) { + LOG_DEBUG("TCTI dump: UNKNOWN (0x%" PRIx64 ")", magic); + } +} + +void tcti_dump(TSS2_TCTI_CONTEXT *tcti) { + TSS2_TCTI_CONTEXT *tcti_next; + + while (true) { + tcti_print(tcti); + + tcti_next = tcti_unwrap_max_depth(tcti, 1); + if (tcti_next == tcti) { + /* tcti unwrap could not get a child tcti */ + return; + } + tcti = tcti_next; + } +} + +/* Return true if the TCTI (considering its children) loses its state after finalize */ +int +tcti_is_volatile (TSS2_TCTI_CONTEXT *tcti) { + uint64_t magic; + TSS2_TCTI_CONTEXT *tcti_next; + + while (true) { + magic = TSS2_TCTI_MAGIC(tcti); + if (magic == TCTI_START_SIM_MAGIC || magic == TCTI_LIBTPMS_MAGIC) { + return true; + } + + tcti_next = tcti_unwrap_max_depth(tcti, 1); + if (tcti_next == tcti) { + /* tcti unwrap could not get a child tcti */ + break; + } + tcti = tcti_next; + } + + return false; +} + +/* Return true if the TCTI state can be backed up */ +int +tcti_state_backup_supported (TSS2_TCTI_CONTEXT *tcti) { + uint64_t magic; + + tcti = tcti_unwrap(tcti); + magic = TSS2_TCTI_MAGIC(tcti); + + if (!tcti_is_volatile(tcti)) { + return false; + } + + return magic == TCTI_LIBTPMS_MAGIC; +} + +/* Backup TCTI state and return alloced buffer. */ +int +tcti_state_backup(FAPI_CONTEXT *fapi_context, libtpms_state *state) { + TSS2_RC rc; + TSS2_TCTI_CONTEXT *tcti; + TSS2_TCTI_LIBTPMS_CONTEXT *tcti_libtpms; + + LOG_DEBUG("TCTI state backup called."); + + rc = Fapi_GetTcti(fapi_context, &tcti); + if (rc != 0) { + return EXIT_ERROR; + } + tcti = tcti_unwrap(tcti); + + if (! tcti_state_backup_supported(tcti)) { + LOG_ERROR("TCTI state backup: state not supported"); + return EXIT_ERROR; + } + + if (TSS2_TCTI_MAGIC(tcti) != TCTI_LIBTPMS_MAGIC) { + LOG_ERROR("TCTI state backup: only implemented for tcti-libtpms so far"); + return EXIT_ERROR; + } + + tcti_libtpms = (TSS2_TCTI_LIBTPMS_CONTEXT*) tcti; + + /* get states */ + rc = tcti_libtpms->TPMLIB_GetState(TPMLIB_STATE_PERMANENT, &state->permanent_buf, &state->permanent_buf_len); + if (rc != 0) { + LOG_ERROR("TCTI state backup: TPMLIB_GetState(TPMLIB_STATE_PERMANENT) failed"); + return EXIT_ERROR; + } + tcti_libtpms->TPMLIB_GetState(TPMLIB_STATE_VOLATILE, &state->volatile_buf, &state->volatile_buf_len); + if (rc != 0) { + LOG_ERROR("TCTI state backup: TPMLIB_GetState(TPMLIB_STATE_VOLATILE) failed"); + free(state->permanent_buf); + return EXIT_ERROR; + } + + return EXIT_SUCCESS; +} + +/* Restore TCTI state and free the buffer. */ +int tcti_state_restore(FAPI_CONTEXT *fapi_context, libtpms_state *state) { + TSS2_RC rc; + TSS2_TCTI_CONTEXT *tcti; + TSS2_TCTI_LIBTPMS_CONTEXT *tcti_libtpms; + + LOG_DEBUG("TCTI state restore called."); + + rc = Fapi_GetTcti(fapi_context, &tcti); + if (rc != 0) { + return EXIT_ERROR; + } + tcti = tcti_unwrap(tcti); + + if (! tcti_state_backup_supported(tcti)) { + LOG_ERROR("TCTI state restore: not supported"); + return EXIT_SKIP; + } + + if (TSS2_TCTI_MAGIC(tcti) != TCTI_LIBTPMS_MAGIC) { + LOG_ERROR("TCTI state restore: only implemented for tcti-libtpms so far"); + return EXIT_ERROR; + } + + tcti_libtpms = (TSS2_TCTI_LIBTPMS_CONTEXT*) tcti; + + tcti_libtpms->TPMLIB_Terminate(); + + /* set states */ + rc = tcti_libtpms->TPMLIB_SetState(TPMLIB_STATE_PERMANENT, state->permanent_buf, state->permanent_buf_len); + if (rc != 0) { + LOG_ERROR("TCTI state restore: TPMLIB_SetState(TPMLIB_STATE_PERMANENT) failed"); + return EXIT_ERROR; + } + rc = tcti_libtpms->TPMLIB_SetState(TPMLIB_STATE_VOLATILE, state->volatile_buf, state->volatile_buf_len); + if (rc != 0) { + LOG_ERROR("TCTI state restore: TPMLIB_SetState(TPMLIB_STATE_VOLATILE) failed"); + return EXIT_ERROR; + } + + rc = tcti_libtpms->TPMLIB_MainInit(); + if (rc != 0) { + LOG_ERROR("TCTI state restore: TPMLIB_MainInit() failed"); + return EXIT_ERROR; + } + + free(state->permanent_buf); + free(state->volatile_buf); + + return EXIT_SUCCESS; +} + +/* Backup TCTI state and return alloced buffer. Does nothing if tcti is not volatile and returns skip if backup is necessary but not supported */ +int tcti_state_backup_if_necessary(FAPI_CONTEXT *fapi_context, libtpms_state *state) { + TSS2_RC rc; + TSS2_TCTI_CONTEXT *tcti; + + rc = Fapi_GetTcti(fapi_context, &tcti); + if (rc != 0) { + return EXIT_ERROR; + } + tcti = tcti_unwrap(tcti); + + if (!tcti_is_volatile(tcti)) { + LOG_TRACE("TCTI state backup: is not necessary, TCTI is not volatile"); + return EXIT_SUCCESS; + } + + if (!tcti_state_backup_supported(tcti)) { + LOG_WARNING("TCTI state backup: is necessary but not supported"); + return EXIT_SKIP; + } + + return tcti_state_backup(fapi_context, state); +} + +/* Restore TCTI state and free the buffer. Does nothing if tcti is not volatile and returns skip if backup is necessary but not supported */ +int tcti_state_restore_if_necessary(FAPI_CONTEXT *fapi_context, libtpms_state *state) { + TSS2_RC rc; + TSS2_TCTI_CONTEXT *tcti; + + rc = Fapi_GetTcti(fapi_context, &tcti); + if (rc != 0) { + return EXIT_ERROR; + } + tcti = tcti_unwrap(tcti); + + if (!tcti_is_volatile(tcti)) { + LOG_TRACE("TCTI state restore: is not necessary, TCTI is not volatile"); + return EXIT_SUCCESS; + } + + if (!tcti_state_backup_supported(tcti)) { + LOG_WARNING("TCTI state restore: is necessary but not supported"); + return EXIT_SKIP; + } + + return tcti_state_restore(fapi_context, state); +} + +TSS2_RC tcti_reset_tpm(TSS2_TCTI_CONTEXT *tcti) { + TSS2_RC rval = TSS2_RC_SUCCESS; + uint64_t magic; + + tcti = tcti_unwrap(tcti); + magic = TSS2_TCTI_MAGIC(tcti); + + switch (magic) { +#ifdef TCTI_LIBTPMS + case TCTI_LIBTPMS_MAGIC: + LOG_DEBUG("Calling Tss2_Tcti_Libtpms_Reset()"); + rval = Tss2_Tcti_Libtpms_Reset(tcti); + break; +#endif /* TCTI_LIBTPMS */ + +#ifdef TCTI_SWTPM + case TCTI_SWTPM_MAGIC: + LOG_DEBUG("Calling Tss2_Tcti_Swtpm_Reset()"); + rval = Tss2_Tcti_Swtpm_Reset(tcti); + break; +#endif /* TCTI_SWTPM */ + +#ifdef TCTI_MSSIM + case TCTI_MSSIM_MAGIC: + LOG_DEBUG("Calling tcti_platform_command()"); + rval = (TSS2_RC)tcti_platform_command( tcti, MS_SIM_POWER_OFF ); + if (rval == TSS2_RC_SUCCESS) { + rval = (TSS2_RC)tcti_platform_command( tcti, MS_SIM_POWER_ON ); + } + break; +#endif /* TCTI_MSSIM */ + + default: + LOG_WARNING("TPM reset failed. TCTI unknown. Got TCTI magic: 0x%" PRIx64 ". Enabled TCTIs with reset support: " +#ifdef TCTI_LIBTPMS + "libtpms (" xstr(TCTI_LIBTPMS_MAGIC) "), " +#endif /* TCTI_LIBTPMS */ +#ifdef TCTI_SWTPM + "swtpm (" xstr(TCTI_SWTPM_MAGIC) "), " +#endif /* TCTI_SWTPM */ +#ifdef TCTI_MSSIM + "mssim (" xstr(TCTI_MSSIM_MAGIC) "), " +#endif /* TCTI_MSSIM */ + "", magic); + return EXIT_SKIP; + } + + if (rval != TSS2_RC_SUCCESS) { + LOG_WARNING("TPM reset failed: 0x%08x", rval); + } + + return rval; +} diff --git a/test/integration/test-common-tcti.h b/test/integration/test-common-tcti.h new file mode 100644 index 000000000..628f89a27 --- /dev/null +++ b/test/integration/test-common-tcti.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/*********************************************************************** + * Copyright (c) 2024, Infineon Technologies AG + * + * All rights reserved. + ***********************************************************************/ +#ifndef TEST_COMMON_TCTI_H +#define TEST_COMMON_TCTI_H + +#include // for size_t +#include // for uint32_t, uint8_t, int32_t, uint64_t + +#include "tss2_common.h" // for TSS2_RC +#include "tss2_fapi.h" // for FAPI_CONTEXT +#include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, TSS2_TCTI_POLL_HANDLE + +enum TSS2_TCTI_CONTEXT_PROXY_STATE { + forwarding, + intercepting +}; + +typedef struct { + uint64_t magic; + uint32_t version; + TSS2_TCTI_TRANSMIT_FCN transmit; + TSS2_TCTI_RECEIVE_FCN receive; + TSS2_RC (*finalize) (TSS2_TCTI_CONTEXT *tctiContext); + TSS2_RC (*cancel) (TSS2_TCTI_CONTEXT *tctiContext); + TSS2_RC (*getPollHandles) (TSS2_TCTI_CONTEXT *tctiContext, + TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles); + TSS2_RC (*setLocality) (TSS2_TCTI_CONTEXT *tctiContext, uint8_t locality); + TSS2_TCTI_CONTEXT *tctiInner; + enum TSS2_TCTI_CONTEXT_PROXY_STATE state; +} TSS2_TCTI_CONTEXT_PROXY; + +typedef struct { + unsigned char *permanent_buf; + unsigned char *volatile_buf; + uint32_t permanent_buf_len; + uint32_t volatile_buf_len; +} libtpms_state; + +TSS2_RC tcti_proxy_transmit(TSS2_TCTI_CONTEXT *tctiContext, size_t command_size, const uint8_t *command_buffer); +TSS2_RC tcti_proxy_receive(TSS2_TCTI_CONTEXT *tctiContext, size_t *response_size, uint8_t *response_buffer, int32_t timeout); +TSS2_RC tcti_proxy_initialize(TSS2_TCTI_CONTEXT *tctiContext, size_t *contextSize, TSS2_TCTI_CONTEXT *tctiInner); +void tcti_proxy_finalize(TSS2_TCTI_CONTEXT *tctiContext); + +TSS2_TCTI_CONTEXT *tcti_unwrap(TSS2_TCTI_CONTEXT *tcti); +void tcti_dump(TSS2_TCTI_CONTEXT *tcti); +int tcti_is_volatile (TSS2_TCTI_CONTEXT *tcti); +int tcti_state_backup_supported (TSS2_TCTI_CONTEXT *tcti); +int tcti_state_backup(FAPI_CONTEXT *fapi_context, libtpms_state *state); +int tcti_state_restore(FAPI_CONTEXT *fapi_context, libtpms_state *state); +int tcti_state_backup_if_necessary(FAPI_CONTEXT *fapi_context, libtpms_state *state); +int tcti_state_restore_if_necessary(FAPI_CONTEXT *fapi_context, libtpms_state *state); +TSS2_RC tcti_reset_tpm(TSS2_TCTI_CONTEXT *tcti); + +#endif /* TEST_COMMON_TCTI_H */ diff --git a/test/integration/test-common.c b/test/integration/test-common.c index bc459569a..1033d79c8 100644 --- a/test/integration/test-common.c +++ b/test/integration/test-common.c @@ -23,6 +23,7 @@ #endif #define LOGMODULE test #include "test-common.h" +#include "test-common-tcti.h" #include "util/log.h" // for LOG_ERROR, LOG_DEBUG, LOGBLOB_ERROR @@ -47,162 +48,6 @@ struct tpm_state { TPMS_CAPABILITY_DATA capabilities[7]; }; -/** Define a proxy tcti that returns yielded on every second invocation - * thus the corresponding handling code in ESYS can be tested. - * The first invocation will be Tss2_Sys_StartUp. - */ -#ifdef TEST_ESYS - -TSS2_RC -(*transmit_hook) (const uint8_t *command_buffer, size_t command_size) = NULL; - -#define TCTI_PROXY_MAGIC 0x5250584f0a000000ULL /* 'PROXY\0\0\0' */ -#define TCTI_PROXY_VERSION 0x1 - -enum state { - forwarding, - intercepting -}; - -typedef struct { - uint64_t magic; - uint32_t version; - TSS2_TCTI_TRANSMIT_FCN transmit; - TSS2_TCTI_RECEIVE_FCN receive; - TSS2_RC (*finalize) (TSS2_TCTI_CONTEXT *tctiContext); - TSS2_RC (*cancel) (TSS2_TCTI_CONTEXT *tctiContext); - TSS2_RC (*getPollHandles) (TSS2_TCTI_CONTEXT *tctiContext, - TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles); - TSS2_RC (*setLocality) (TSS2_TCTI_CONTEXT *tctiContext, uint8_t locality); - TSS2_TCTI_CONTEXT *tctiInner; - enum state state; -} TSS2_TCTI_CONTEXT_PROXY; - -static TSS2_TCTI_CONTEXT_PROXY* -tcti_proxy_cast (TSS2_TCTI_CONTEXT *ctx) -{ - TSS2_TCTI_CONTEXT_PROXY *ctxi = (TSS2_TCTI_CONTEXT_PROXY*)ctx; - if (ctxi == NULL || ctxi->magic != TCTI_PROXY_MAGIC) { - LOG_ERROR("Bad tcti passed."); - return NULL; - } - return ctxi; -} - -static TSS2_RC -tcti_proxy_transmit( - TSS2_TCTI_CONTEXT *tctiContext, - size_t command_size, - const uint8_t *command_buffer - ) -{ - TSS2_RC rval; - TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext); - - if (tcti_proxy->state == intercepting) { - return TSS2_RC_SUCCESS; - } - - if (transmit_hook != NULL) { - rval = transmit_hook(command_buffer, command_size); - if (rval != TSS2_RC_SUCCESS) { - LOG_ERROR("transmit hook requested error"); - return rval; - } - } - - rval = Tss2_Tcti_Transmit(tcti_proxy->tctiInner, command_size, - command_buffer); - if (rval != TSS2_RC_SUCCESS) { - LOG_ERROR("Calling TCTI Transmit"); - return rval; - } - - return rval; -} - -uint8_t yielded_response[] = { - 0x80, 0x01, /* TPM_ST_NO_SESSION */ - 0x00, 0x00, 0x00, 0x0A, /* Response Size 10 */ - 0x00, 0x00, 0x09, 0x08 /* TPM_RC_YIELDED */ -}; - -static TSS2_RC -tcti_proxy_receive( - TSS2_TCTI_CONTEXT *tctiContext, - size_t *response_size, - uint8_t *response_buffer, - int32_t timeout - ) -{ - TSS2_RC rval; - TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext); - - if (tcti_proxy->state == intercepting) { - *response_size = sizeof(yielded_response); - - if (response_buffer != NULL) { - memcpy(response_buffer, &yielded_response[0], sizeof(yielded_response)); - tcti_proxy->state = forwarding; - } - return TSS2_RC_SUCCESS; - } - - rval = Tss2_Tcti_Receive(tcti_proxy->tctiInner, response_size, - response_buffer, timeout); - if (rval != TSS2_RC_SUCCESS) { - LOG_ERROR("Calling TCTI Transmit"); - return rval; - } - - /* First read with response buffer == NULL is to get the size of the - * response. The subsequent read needs to be forwarded also */ - if (response_buffer != NULL) - tcti_proxy->state = intercepting; - - return rval; -} - -static void -tcti_proxy_finalize( - TSS2_TCTI_CONTEXT *tctiContext) -{ - memset(tctiContext, 0, sizeof(TSS2_TCTI_CONTEXT_PROXY)); -} - -static TSS2_RC -tcti_proxy_initialize( - TSS2_TCTI_CONTEXT *tctiContext, - size_t *contextSize, - TSS2_TCTI_CONTEXT *tctiInner) -{ - TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = - (TSS2_TCTI_CONTEXT_PROXY*) tctiContext; - - if (tctiContext == NULL && contextSize == NULL) { - return TSS2_TCTI_RC_BAD_VALUE; - } else if (tctiContext == NULL) { - *contextSize = sizeof(*tcti_proxy); - return TSS2_RC_SUCCESS; - } - - /* Init TCTI context */ - memset(tcti_proxy, 0, sizeof(*tcti_proxy)); - TSS2_TCTI_MAGIC (tctiContext) = TCTI_PROXY_MAGIC; - TSS2_TCTI_VERSION (tctiContext) = TCTI_PROXY_VERSION; - TSS2_TCTI_TRANSMIT (tctiContext) = tcti_proxy_transmit; - TSS2_TCTI_RECEIVE (tctiContext) = tcti_proxy_receive; - TSS2_TCTI_FINALIZE (tctiContext) = tcti_proxy_finalize; - TSS2_TCTI_CANCEL (tctiContext) = NULL; - TSS2_TCTI_GET_POLL_HANDLES (tctiContext) = NULL; - TSS2_TCTI_SET_LOCALITY (tctiContext) = NULL; - tcti_proxy->tctiInner = tctiInner; - tcti_proxy->state = forwarding; - - return TSS2_RC_SUCCESS; -} -#endif /* TEST_ESYS */ - int transient_empty(TSS2_SYS_CONTEXT *sys_ctx) { diff --git a/test/tpmclient/tpmclient.int.c b/test/tpmclient/tpmclient.int.c index 7aec89ee5..23c01d391 100644 --- a/test/tpmclient/tpmclient.int.c +++ b/test/tpmclient/tpmclient.int.c @@ -15,29 +15,16 @@ #include // for free, calloc, exit #include // for memcpy, strcpy, memcmp, strlen -#include "tss2-tcti/tcti-pcap.h" // for TCTI_PCAP_MAGIC, TSS2_TCTI_... -#include "tss2-tcti/tctildr.h" // for TCTILDR_MAGIC, TSS2_TCTILDR... #include "tss2_common.h" // for BYTE, UINT32, TSS2_RC, UINT8 #include "tss2_sys.h" // for TSS2L_SYS_AUTH_COMMAND, Tss... #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, Tss2_Tct... #include "tss2_tpm2_types.h" // for TPM2_RC_SUCCESS, TPMS_PCR_S... #include "util/tpm2b.h" // for TPM2B -#ifdef TCTI_MSSIM -#include "tss2_tcti_mssim.h" // for tcti_platform_command, MS_S... -#include "tss2-tcti/tcti-mssim.h" // for TCTI_MSSIM_MAGIC -#endif /* TCTI_MSSIM */ -#ifdef TCTI_SWTPM -#include "tss2_tcti_swtpm.h" // for Tss2_Tcti_Swtpm_Reset -#include "tss2-tcti/tcti-swtpm.h" // for TCTI_SWTPM_MAGIC -#endif /* TCTI_SWTPM */ -#ifdef TCTI_LIBTPMS -#include "tss2_tcti_libtpms.h" // for Tss2_Tcti_Libtpms_Reset -#include "tss2-tcti/tcti-libtpms.h" // for TCTI_LIBTPMS_MAGIC -#endif /* TCTI_LIBTPMS */ #include "../integration/session-util.h" // for SESSION, create_auth_session #include "../integration/sys-util.h" // for CopySizedByteBuffer, Define... #include "../integration/test-common.h" // for TEST_ABI_VERSION +#include "../integration/test-common-tcti.h" // for tcti_reset_tpm #include "sysapi_util.h" // for _TSS2_SYS_CONTEXT_BLOB, res... #include "util/tss2_endian.h" // for BE_TO_HOST_32 @@ -163,75 +150,6 @@ static void InitSysContextFailure() } \ } -static TSS2_RC TpmReset() -{ - TSS2_RC rval = TSS2_RC_SUCCESS; - TSS2_TCTI_CONTEXT *tcti = resMgrTctiContext; - - /* - * Try to unwrap tctildr/pcap. It would be better to provide an API call for - * reset by tctildr, but for now, use this instead. - */ - uint64_t magic = 0; - while (magic == 0 || magic == TCTILDR_MAGIC || magic == TCTI_PCAP_MAGIC) { - magic = *((uint64_t*) tcti); - if (magic == TCTILDR_MAGIC) { - LOG_TRACE("TCTI is tctildr (0x%" PRIx64 "). Unwrapping...", magic); - tcti = ((TSS2_TCTILDR_CONTEXT *) tcti)->tcti; - } else if (magic == TCTI_PCAP_MAGIC) { - LOG_TRACE("TCTI is tcti-pcap (0x%" PRIx64 "). Unwrapping...", magic); - tcti = ((TSS2_TCTI_PCAP_CONTEXT *) tcti)->tcti_child; - } - } - - switch (magic) { - -#ifdef TCTI_LIBTPMS - case TCTI_LIBTPMS_MAGIC: - LOG_DEBUG("Calling Tss2_Tcti_Libtpms_Reset()"); - rval = Tss2_Tcti_Libtpms_Reset(tcti); - break; -#endif /* TCTI_LIBTPMS */ - -#ifdef TCTI_SWTPM - case TCTI_SWTPM_MAGIC: - LOG_DEBUG("Calling Tss2_Tcti_Swtpm_Reset()"); - rval = Tss2_Tcti_Swtpm_Reset(tcti); - break; -#endif /* TCTI_SWTPM */ - -#ifdef TCTI_MSSIM - case TCTI_MSSIM_MAGIC: - LOG_DEBUG("Calling tcti_platform_command()"); - rval = (TSS2_RC)tcti_platform_command( tcti, MS_SIM_POWER_OFF ); - if (rval == TSS2_RC_SUCCESS) { - rval = (TSS2_RC)tcti_platform_command( tcti, MS_SIM_POWER_ON ); - } - break; -#endif /* TCTI_MSSIM */ - - default: - LOG_WARNING("TPM reset failed. TCTI unknown. Got TCTI magic: 0x%" PRIx64 ". Enabled TCTIs with reset support: " -#ifdef TCTI_LIBTPMS - "libtpms (" xstr(TCTI_LIBTPMS_MAGIC) "), " -#endif /* TCTI_LIBTPMS */ -#ifdef TCTI_SWTPM - "swtpm (" xstr(TCTI_SWTPM_MAGIC) "), " -#endif /* TCTI_SWTPM */ -#ifdef TCTI_MSSIM - "mssim (" xstr(TCTI_MSSIM_MAGIC) "), " -#endif /* TCTI_MSSIM */ - "", magic); - return EXIT_SKIP; - } - - if (rval != TSS2_RC_SUCCESS) { - LOG_WARNING("TPM reset failed: 0x%08x", rval); - } - - return rval; -} - /* * Initialize a SYS context using the TCTI context provided by the caller. * This function allocates memory for the SYS context and returns it to the @@ -289,7 +207,7 @@ static void TestTpmStartup() */ /* First must do TPM reset. */ - rval = TpmReset(); + rval = tcti_reset_tpm(resMgrTctiContext); CheckPassed(rval); /* This one should pass. */ @@ -302,7 +220,7 @@ static void TestTpmStartup() /* Cycle power using simulator interface. */ - rval = TpmReset(); + rval = tcti_reset_tpm(resMgrTctiContext); CheckPassed(rval); @@ -317,7 +235,7 @@ static void TestTpmStartup() CheckPassed( rval ); /* Cycle power using simulator interface. */ - rval = TpmReset(); + rval = tcti_reset_tpm(resMgrTctiContext); CheckPassed(rval); @@ -948,7 +866,7 @@ static void TestHierarchyControl() CheckFailed( rval, TPM2_RC_1 + TPM2_RC_HIERARCHY ); /* Need to do TPM reset and Startup to re-enable platform hierarchy. */ - rval = TpmReset(); + rval = tcti_reset_tpm(resMgrTctiContext); CheckPassed(rval); rval = Tss2_Sys_Startup ( sysContext, TPM2_SU_CLEAR ); @@ -2252,7 +2170,7 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) nullSessionNonceOut.size = 0; nullSessionNonce.size = 0; - rval = TpmReset(); + rval = tcti_reset_tpm(resMgrTctiContext); CheckPassed(rval); SysFinalizeTests();