| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <inttypes.h> |
| #include <limits.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/time.h> |
| #include <unistd.h> |
| |
| #include "tcti-common.h" |
| #include "tcti-fuchsia.h" |
| #include "tss2_mu.h" |
| #include "tss2_tcti_fuchsia.h" |
| #include "util/tss2_endian.h" |
| #define LOGMODULE tcti |
| #include "src/security/lib/fuchsia-tcti/include/fuchsia-tcti.h" |
| #include "util/log.h" |
| |
| TSS2_TCTI_FUCHSIA_CONTEXT *tcti_fuchsia_context_cast(TSS2_TCTI_CONTEXT *tcti_ctx) { |
| return (TSS2_TCTI_FUCHSIA_CONTEXT *)tcti_ctx; |
| } |
| |
| TSS2_TCTI_COMMON_CONTEXT *tcti_fuchsia_down_cast(TSS2_TCTI_FUCHSIA_CONTEXT *tcti_fuchsia) { |
| if (tcti_fuchsia == NULL) { |
| return NULL; |
| } |
| return &tcti_fuchsia->common; |
| } |
| |
| TSS2_RC tcti_fuchsia_transmit(TSS2_TCTI_CONTEXT *tcti_ctx, size_t transmit_size, |
| const uint8_t *transmit_buf) { |
| TSS2_TCTI_FUCHSIA_CONTEXT *tcti_fuchsia = tcti_fuchsia_context_cast(tcti_ctx); |
| TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_fuchsia_down_cast(tcti_fuchsia); |
| tpm_header_t header; |
| TSS2_RC rc; |
| |
| rc = tcti_common_transmit_checks(tcti_common, transmit_buf, TCTI_FUCHSIA_MAGIC); |
| if (rc != TSS2_RC_SUCCESS) { |
| return rc; |
| } |
| rc = header_unmarshal(transmit_buf, &header); |
| if (rc != TSS2_RC_SUCCESS) { |
| return rc; |
| } |
| if (header.size != transmit_size) { |
| LOG_ERROR( |
| "Buffer size parameter: %zu, and TPM2 command header size " |
| "field: %" PRIu32 " disagree.", |
| transmit_size, header.size); |
| return TSS2_TCTI_RC_BAD_VALUE; |
| } |
| |
| LOG_DEBUG("Sending command with TPM_CC 0x%" PRIx32 " and size %" PRIu32, header.code, |
| header.size); |
| |
| rc = fuchsia_tpm_send(tcti_fuchsia->internal, header.code, transmit_buf, transmit_size); |
| if (rc != TSS2_RC_SUCCESS) { |
| return rc; |
| } |
| |
| tcti_common->state = TCTI_STATE_RECEIVE; |
| |
| return TSS2_RC_SUCCESS; |
| } |
| |
| TSS2_RC tcti_fuchsia_cancel(TSS2_TCTI_CONTEXT *tctiContext) { |
| UNUSED(tctiContext); |
| return TSS2_TCTI_RC_NOT_IMPLEMENTED; |
| } |
| |
| TSS2_RC tcti_fuchsia_set_locality(TSS2_TCTI_CONTEXT *tctiContext, uint8_t locality) { |
| TSS2_TCTI_FUCHSIA_CONTEXT *tcti_fuchsia = tcti_fuchsia_context_cast(tctiContext); |
| TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_fuchsia_down_cast(tcti_fuchsia); |
| TSS2_RC rc; |
| |
| rc = tcti_common_set_locality_checks(tcti_common, TCTI_FUCHSIA_MAGIC); |
| if (rc != TSS2_RC_SUCCESS) { |
| return rc; |
| } |
| tcti_common->locality = locality; |
| return TSS2_RC_SUCCESS; |
| } |
| |
| TSS2_RC tcti_fuchsia_get_poll_handles(TSS2_TCTI_CONTEXT *tctiContext, |
| TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles) { |
| UNUSED(tctiContext); |
| UNUSED(handles); |
| UNUSED(num_handles); |
| return TSS2_TCTI_RC_NOT_IMPLEMENTED; |
| } |
| |
| void tcti_fuchsia_finalize(TSS2_TCTI_CONTEXT *tctiContext) { |
| TSS2_TCTI_FUCHSIA_CONTEXT *tcti_fuchsia = tcti_fuchsia_context_cast(tctiContext); |
| TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_fuchsia_down_cast(tcti_fuchsia); |
| if (tcti_fuchsia == NULL) { |
| return; |
| } |
| fuchsia_tpm_finalize(tcti_fuchsia->internal); |
| tcti_common->state = TCTI_STATE_FINAL; |
| } |
| |
| TSS2_RC tcti_fuchsia_receive(TSS2_TCTI_CONTEXT *tctiContext, size_t *response_size, |
| unsigned char *response_buffer, int32_t timeout) { |
| TSS2_TCTI_FUCHSIA_CONTEXT *tcti_fuchsia = tcti_fuchsia_context_cast(tctiContext); |
| TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_fuchsia_down_cast(tcti_fuchsia); |
| TSS2_RC rc; |
| size_t ret = 0; |
| |
| rc = tcti_common_receive_checks(tcti_common, response_size, TCTI_FUCHSIA_MAGIC); |
| if (rc != TSS2_RC_SUCCESS) { |
| return rc; |
| } |
| |
| if (timeout != TSS2_TCTI_TIMEOUT_BLOCK) { |
| LOG_ERROR("Asynchronous I/O not implemented."); |
| } |
| |
| if (tcti_common->header.size == 0) { |
| LOG_DEBUG("Receiving header to determine the size of the response."); |
| uint8_t res_header[TPM_HEADER_SIZE]; |
| ret = fuchsia_tpm_recv(tcti_fuchsia->internal, &res_header[0], TPM_HEADER_SIZE); |
| if (ret != TPM_HEADER_SIZE) { |
| rc = TSS2_TCTI_RC_IO_ERROR; |
| goto out; |
| } |
| |
| rc = header_unmarshal(&res_header[0], &tcti_common->header); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG_ERROR("Failed to unmarshal tpm2 header: 0x%" PRIx32, rc); |
| goto out; |
| } |
| |
| LOG_DEBUG("response size: %" PRIu32, tcti_common->header.size); |
| } |
| |
| if (response_buffer == NULL) { |
| *response_size = tcti_common->header.size; |
| return TSS2_RC_SUCCESS; |
| } |
| |
| if (*response_size < tcti_common->header.size) { |
| *response_size = tcti_common->header.size; |
| return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; |
| } |
| *response_size = tcti_common->header.size; |
| |
| if (tcti_common->header.size > TPM_HEADER_SIZE) { |
| LOG_DEBUG("Reading response of size %" PRIu32, tcti_common->header.size); |
| ret = |
| fuchsia_tpm_recv(tcti_fuchsia->internal, (unsigned char *)&response_buffer[TPM_HEADER_SIZE], |
| tcti_common->header.size - TPM_HEADER_SIZE); |
| if (ret < tcti_common->header.size - TPM_HEADER_SIZE) { |
| rc = TSS2_TCTI_RC_IO_ERROR; |
| goto out; |
| } |
| } |
| |
| rc = header_marshal(&tcti_common->header, &response_buffer[0]); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG_WARNING("Failed to remarshal tpm2 header: 0x%" PRIu32, rc); |
| goto out; |
| } |
| |
| LOGBLOB_DEBUG(response_buffer, tcti_common->header.size, "Response received:"); |
| /* |
| * Executing code beyond this point transitions the state machine to |
| * TRANSMIT. Another call to this function will not be possible until |
| * another command is sent to the TPM. |
| */ |
| out: |
| tcti_common->header.size = 0; |
| tcti_common->state = TCTI_STATE_TRANSMIT; |
| return rc; |
| } |
| |
| void tcti_fuchsia_init_context_data(TSS2_TCTI_COMMON_CONTEXT *tcti_common) { |
| TSS2_TCTI_MAGIC(tcti_common) = TCTI_FUCHSIA_MAGIC; |
| TSS2_TCTI_VERSION(tcti_common) = TCTI_VERSION; |
| TSS2_TCTI_TRANSMIT(tcti_common) = tcti_fuchsia_transmit; |
| TSS2_TCTI_RECEIVE(tcti_common) = tcti_fuchsia_receive; |
| TSS2_TCTI_FINALIZE(tcti_common) = tcti_fuchsia_finalize; |
| TSS2_TCTI_CANCEL(tcti_common) = tcti_fuchsia_cancel; |
| TSS2_TCTI_GET_POLL_HANDLES(tcti_common) = tcti_fuchsia_get_poll_handles; |
| TSS2_TCTI_SET_LOCALITY(tcti_common) = tcti_fuchsia_set_locality; |
| TSS2_TCTI_MAKE_STICKY(tcti_common) = tcti_make_sticky_not_implemented; |
| tcti_common->state = TCTI_STATE_TRANSMIT; |
| memset(&tcti_common->header, 0, sizeof(tcti_common->header)); |
| } |
| |
| /* |
| * This is an implementation of the standard TCTI initialization function for |
| * this module. |
| */ |
| TSS2_RC Tss2_Tcti_Fuchsia_Init(TSS2_TCTI_CONTEXT *tctiContext, size_t *size, const char *conf) { |
| TSS2_TCTI_FUCHSIA_CONTEXT *tcti_fuchsia = (TSS2_TCTI_FUCHSIA_CONTEXT *)tctiContext; |
| TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_fuchsia_down_cast(tcti_fuchsia); |
| TSS2_RC rc; |
| |
| LOG_TRACE("tctiContext: 0x%" PRIxPTR ", size: 0x%" PRIxPTR ", conf: %s", (uintptr_t)tctiContext, |
| (uintptr_t)size, conf); |
| if (size == NULL) { |
| return TSS2_TCTI_RC_BAD_VALUE; |
| } |
| |
| if (conf != NULL) { |
| LOG_WARNING("conf is not NULL. Configurations are not supported in Fuchsia."); |
| } |
| |
| // Return the size of our opaque context, this is called first in one init call and |
| // a second call is then made with this context allocated. |
| if (tctiContext == NULL) { |
| *size = sizeof(TSS2_TCTI_FUCHSIA_CONTEXT); |
| return TSS2_RC_SUCCESS; |
| } |
| LOG_DEBUG("Initializing fuchsia TCTI"); |
| tcti_fuchsia->internal = fuchsia_tpm_init(); |
| |
| tcti_fuchsia_init_context_data(tcti_common); |
| rc = tcti_fuchsia_set_locality(tctiContext, 0); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG_WARNING("Could not set locality via control channel: 0x%" PRIx32, rc); |
| return rc; |
| } |
| return TSS2_RC_SUCCESS; |
| } |
| |
| |
| TSS2_RC Tss2_Tcti_Fuchsia_Init_Ex(TSS2_TCTI_CONTEXT **tctiContext, const char *conf) { |
| size_t context_size; |
| TSS2_RC rc = Tss2_Tcti_Fuchsia_Init(NULL, &context_size, conf); |
| if (rc != TSS2_RC_SUCCESS) { |
| return rc; |
| } |
| *tctiContext = (TSS2_TCTI_CONTEXT*)calloc(1, context_size); |
| rc = Tss2_Tcti_Fuchsia_Init(*tctiContext, &context_size, conf); |
| if (rc != TSS2_RC_SUCCESS) { |
| return rc; |
| } |
| return TSS2_RC_SUCCESS; |
| } |
| |
| |
| const TSS2_TCTI_INFO tss2_tcti_info = { |
| .version = TCTI_VERSION, |
| .name = "tcti-fuchsia", |
| .description = "TCTI module for communication with the Fuchsia.", |
| .config_help = "Configuration is not supported.", |
| .init = Tss2_Tcti_Fuchsia_Init, |
| }; |
| |
| const TSS2_TCTI_INFO *Tss2_Tcti_Info(void) { return &tss2_tcti_info; } |