| /******************************************************************************* |
| * Copyright 2017, Fraunhofer SIT sponsored by Infineon Technologies AG |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| *******************************************************************************/ |
| |
| #include <stdbool.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "tss2_esys.h" |
| |
| #include "test-esapi.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 ESAPI can be tested. |
| * The first invocation will be Tss2_Sys_StartUp. |
| */ |
| |
| #define TCTI_PROXY_MAGIC 0x5250584f0a000000ULL /* 'PROXY\0\0\0' */ |
| #define TCTI_PROXY_VERSION 0x1 |
| |
| 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; |
| uint8_t count; |
| } 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->count == 2) { |
| tcti_proxy->count = 1; |
| return TSS2_RC_SUCCESS; |
| } |
| tcti_proxy->count++; |
| |
| 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->count == 2) { |
| *response_size = sizeof(yielded_response); |
| if (response_buffer != NULL) |
| memcpy(response_buffer, &yielded_response[0], sizeof(yielded_response)); |
| |
| 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; |
| } |
| |
| 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->count = 0; |
| |
| return TSS2_RC_SUCCESS; |
| } |
| |
| /** Override the gcrypt random functions in order to not screw over valgrind. */ |
| TSS2_RC iesys_cryptogcry_random2b(TPM2B_NONCE *nonce, size_t num_bytes) |
| { |
| nonce->size = num_bytes; |
| for (int i = 0; i < num_bytes; i++) |
| nonce->buffer[i] = i % 256; |
| return 0; |
| } |
| |
| /** |
| * This program is a template for integration tests (ones that use the TCTI |
| * and the ESAPI 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 && rc != TPM2_RC_INITIALIZE) { |
| LOG_ERROR("Esys_Initialize FAILED! Response Code : 0x%x", rc); |
| return 1; |
| } |
| rc = Esys_SetTimeout(esys_context, TSS2_TCTI_TIMEOUT_BLOCK); |
| if (rc != TSS2_RC_SUCCESS && rc != TPM2_RC_INITIALIZE) { |
| LOG_ERROR("Esys_SetTimeout FAILED! Response Code : 0x%x", rc); |
| return 1; |
| } |
| rc = Tss2_Sys_Startup(esys_context->sys, TPM2_SU_CLEAR); |
| if (rc != TSS2_RC_SUCCESS && rc != TPM2_RC_INITIALIZE) { |
| LOG_ERROR("TPM Startup FAILED! Response Code : 0x%x", rc); |
| return 1; |
| } |
| ret = test_invoke_esapi(esys_context); |
| |
| Esys_Finalize(&esys_context); |
| tcti_teardown(tcti_context); |
| return ret; |
| } |