| /* SPDX-License-Identifier: BSD-2-Clause */ |
| /******************************************************************************* |
| * Copyright 2017, Fraunhofer SIT sponsored by Infineon Technologies AG |
| * All rights reserved. |
| *******************************************************************************/ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <stdbool.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "tss2_esys.h" |
| |
| #include "test-esys.h" |
| #include "test-options.h" |
| #include "context-util.h" |
| #include "tss2-esys/esys_int.h" |
| #define LOGMODULE test |
| #include "util/log.h" |
| |
| /** 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. |
| */ |
| |
| 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; |
| } |
| |
| /** |
| * This program is a template for integration tests (ones that use the TCTI |
| * and the ESYS contexts / API directly). It does nothing more than parsing |
| * command line options that allow the caller (likely a script) to specify |
| * which TCTI to use for the test. |
| */ |
| int |
| main(int argc, char *argv[]) |
| { |
| TSS2_RC rc; |
| size_t tcti_size; |
| TSS2_TCTI_CONTEXT *tcti_context; |
| TSS2_TCTI_CONTEXT *tcti_inner; |
| ESYS_CONTEXT *esys_context; |
| TSS2_ABI_VERSION abiVersion = |
| { TSSWG_INTEROP, TSS_SAPI_FIRST_FAMILY, TSS_SAPI_FIRST_LEVEL, |
| TSS_SAPI_FIRST_VERSION }; |
| |
| int ret; |
| test_opts_t opts = { |
| .tcti_type = TCTI_DEFAULT, |
| .device_file = DEVICE_PATH_DEFAULT, |
| .socket_address = HOSTNAME_DEFAULT, |
| .socket_port = PORT_DEFAULT, |
| }; |
| |
| get_test_opts_from_env(&opts); |
| if (sanity_check_test_opts(&opts) != 0) { |
| LOG_ERROR("TPM Startup FAILED! Error in sanity check"); |
| exit(1); |
| } |
| tcti_inner = tcti_init_from_opts(&opts); |
| if (tcti_inner == NULL) { |
| LOG_ERROR("TPM Startup FAILED! Error tcti init"); |
| exit(1); |
| } |
| rc = tcti_proxy_initialize(NULL, &tcti_size, tcti_inner); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG_ERROR("tcti initialization FAILED! Response Code : 0x%x", rc); |
| return 1; |
| } |
| tcti_context = calloc(1, tcti_size); |
| if (tcti_inner == NULL) { |
| LOG_ERROR("TPM Startup FAILED! Error tcti init"); |
| exit(1); |
| } |
| rc = tcti_proxy_initialize(tcti_context, &tcti_size, tcti_inner); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG_ERROR("tcti initialization FAILED! Response Code : 0x%x", rc); |
| return 1; |
| } |
| rc = Esys_Initialize(&esys_context, tcti_context, &abiVersion); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG_ERROR("Esys_Initialize FAILED! Response Code : 0x%x", rc); |
| return 1; |
| } |
| rc = Esys_Startup(esys_context, TPM2_SU_CLEAR); |
| if (rc != TSS2_RC_SUCCESS && rc != TPM2_RC_INITIALIZE) { |
| LOG_ERROR("Esys_Startup FAILED! Response Code : 0x%x", rc); |
| return 1; |
| } |
| |
| rc = Esys_SetTimeout(esys_context, TSS2_TCTI_TIMEOUT_BLOCK); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG_ERROR("Esys_SetTimeout FAILED! Response Code : 0x%x", rc); |
| return 1; |
| } |
| |
| ret = test_invoke_esys(esys_context); |
| |
| Esys_Finalize(&esys_context); |
| tcti_teardown(tcti_inner); |
| tcti_teardown(tcti_context); |
| return ret; |
| } |