blob: 201c083115ceb2340da80f006c0b4a0acdec67e4 [file] [log] [blame]
#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; }