From 63c445fd81f8f228271b6c6860e628e896b68482 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 27 Mar 2023 16:21:15 -0700 Subject: [PATCH] Experimental USB TPM support using libusb and the LetsTrust TPM2Go USB-Stick. --- configure.ac | 23 ++++++ src/include.am | 5 +- src/tpm2.c | 20 ++--- src/tpm2_usb.c | 174 ++++++++++++++++++++++++++++++++++++++++++ src/tpm2_wrap.c | 2 +- wolftpm/include.am | 1 + wolftpm/tpm2.h | 24 ++---- wolftpm/tpm2_linux.h | 7 +- wolftpm/tpm2_packet.h | 4 +- wolftpm/tpm2_swtpm.h | 10 ++- wolftpm/tpm2_usb.h | 54 +++++++++++++ wolftpm/tpm2_winapi.h | 22 +++++- 12 files changed, 312 insertions(+), 34 deletions(-) create mode 100644 src/tpm2_usb.c create mode 100644 wolftpm/tpm2_usb.h diff --git a/configure.ac b/configure.ac index 16d89b3b..714bcf0d 100644 --- a/configure.ac +++ b/configure.ac @@ -257,6 +257,27 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_WINAPI" fi +# libusb support for USB 2 SPI bridge such as found in LetsTrust TPM2Go USB-Stick +AC_ARG_ENABLE([usb], + [AS_HELP_STRING([--enable-usb],[Enable use of TPM through a USB2SPI bridge (default: disabled)])], + [ ENABLED_USB=$enableval ], + [ ENABLED_USB=no ] + ) + +if test "x$ENABLED_USB" = "xyes" +then + if test "x$ENABLED_DEVTPM" = "xyes" + then + AC_MSG_ERROR([Cannot enable both usb and devtpm]) + fi + + PKG_CHECK_MODULES([LIBUSB_1_0], libusb-1.0 >= 0.9.1) + AC_SUBST(LIBUSB_1_0_CFLAGS) + AC_SUBST(LIBUSB_1_0_LIBS) + + AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_USB $LIBUSB_1_0_CFLAGS" + AM_LDFLAGS="$AM_LDFLAGS $LIBUSB_1_0_LIBS" +fi # STM ST33 Support AC_ARG_ENABLE([st33],, @@ -422,6 +443,7 @@ AM_CONDITIONAL([BUILD_INFINEON], [test "x$ENABLED_INFINEON" != "xno"]) AM_CONDITIONAL([BUILD_DEVTPM], [test "x$ENABLED_DEVTPM" = "xyes"]) AM_CONDITIONAL([BUILD_SWTPM], [test "x$ENABLED_SWTPM" = "xyes"]) AM_CONDITIONAL([BUILD_WINAPI], [test "x$ENABLED_WINAPI" = "xyes"]) +AM_CONDITIONAL([BUILD_USB], [test "x$ENABLED_USB" = "xyes"]) AM_CONDITIONAL([BUILD_NUVOTON], [test "x$ENABLED_NUVOTON" = "xyes"]) AM_CONDITIONAL([BUILD_CHECKWAITSTATE], [test "x$ENABLED_CHECKWAITSTATE" = "xyes"]) AM_CONDITIONAL([BUILD_AUTODETECT], [test "x$ENABLED_AUTODETECT" = "xyes"]) @@ -542,6 +564,7 @@ echo " * I2C: $ENABLED_I2C" echo " * Linux kernel TPM device: $ENABLED_DEVTPM" echo " * SWTPM: $ENABLED_SWTPM" echo " * WINAPI: $ENABLED_WINAPI" +echo " * LetsTrust TPM2Go USB: $ENABLED_USB" echo " * TIS/SPI Check Wait State: $ENABLED_CHECKWAITSTATE" echo " * Infineon SLB967X $ENABLED_INFINEON" diff --git a/src/include.am b/src/include.am index e6ab5741..e4a9fc35 100644 --- a/src/include.am +++ b/src/include.am @@ -21,10 +21,13 @@ if BUILD_WINAPI src_libwolftpm_la_SOURCES += src/tpm2_winapi.c src_libwolftpm_la_LIBADD = -ltbs endif +if BUILD_USB +src_libwolftpm_la_SOURCES += src/tpm2_usb.c +endif src_libwolftpm_la_CFLAGS = $(src_libwolftpm_la_EXTRAS) -DBUILDING_WOLFTPM $(AM_CFLAGS) src_libwolftpm_la_CPPFLAGS = -DBUILDING_WOLFTPM $(AM_CPPFLAGS) -src_libwolftpm_la_LDFLAGS = ${AM_LDFLAGS} -no-undefined -version-info ${WOLFTPM_LIBRARY_VERSION} +src_libwolftpm_la_LDFLAGS = ${AM_LDFLAGS} -no-undefined -version-info ${WOLFTPM_LIBRARY_VERSION} #src_libwolftpm_la_DEPENDENCIES = #EXTRA_DIST += diff --git a/src/tpm2.c b/src/tpm2.c index 8784fd41..02dadc30 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -23,9 +23,6 @@ #include #include #include -#include -#include -#include #include #include @@ -40,16 +37,19 @@ static volatile int gWolfCryptRefCount = 0; #endif #ifdef WOLFTPM_LINUX_DEV -#define INTERNAL_SEND_COMMAND TPM2_LINUX_SendCommand +#define TPM2_INTERNAL_SENDCMD TPM2_LINUX_SendCommand #define TPM2_INTERNAL_CLEANUP(ctx) #elif defined(WOLFTPM_SWTPM) -#define INTERNAL_SEND_COMMAND TPM2_SWTPM_SendCommand +#define TPM2_INTERNAL_SENDCMD TPM2_SWTPM_SendCommand #define TPM2_INTERNAL_CLEANUP(ctx) #elif defined(WOLFTPM_WINAPI) -#define INTERNAL_SEND_COMMAND TPM2_WinApi_SendCommand +#define TPM2_INTERNAL_SENDCMD TPM2_WinApi_SendCommand #define TPM2_INTERNAL_CLEANUP(ctx) TPM2_WinApi_Cleanup(ctx) +#elif defined(WOLFTPM_USB) +#define TPM2_INTERNAL_SENDCMD TPM2_USB_SendCommand +#define TPM2_INTERNAL_CLEANUP(ctx) TPM2_USB_Cleanup #else -#define INTERNAL_SEND_COMMAND TPM2_TIS_SendCommand +#define TPM2_INTERNAL_SENDCMD TPM2_TIS_SendCommand #define TPM2_INTERNAL_CLEANUP(ctx) #endif @@ -420,7 +420,7 @@ static TPM_RC TPM2_SendCommandAuth(TPM2_CTX* ctx, TPM2_Packet* packet, packet->pos = cmdSz; /* submit command and wait for response */ - rc = (TPM_RC)INTERNAL_SEND_COMMAND(ctx, packet); + rc = (TPM_RC)TPM2_INTERNAL_SENDCMD(ctx, packet); if (rc != 0) return rc; @@ -451,7 +451,7 @@ static TPM_RC TPM2_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet) return BAD_FUNC_ARG; /* submit command and wait for response */ - rc = (TPM_RC)INTERNAL_SEND_COMMAND(ctx, packet); + rc = (TPM_RC)TPM2_INTERNAL_SENDCMD(ctx, packet); if (rc != 0) return rc; @@ -625,7 +625,7 @@ TPM_RC TPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx, #endif #if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SWTPM) || \ - defined(WOLFTPM_WINAPI) + defined(WOLFTPM_WINAPI) || defined(WOLFTPM_USB) if (ioCb != NULL || userCtx != NULL) { return BAD_FUNC_ARG; } diff --git a/src/tpm2_usb.c b/src/tpm2_usb.c new file mode 100644 index 00000000..e8e5456f --- /dev/null +++ b/src/tpm2_usb.c @@ -0,0 +1,174 @@ +/* tpm2_usb.c + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfTPM. + * + * wolfTPM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfTPM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#ifdef WOLFTPM_USB + +#include +#include + + + +#define VID_CYPRESS 0x04B4u +#define PID_CYUSBSPI 0x0004u + +#define CTRL_SET 0xC0u +#define CTRL_GET 0x40u + +#define CY_CMD_SPI 0xCAu +#define CY_CMD_GPIO_SET 0xDBu +#define CY_SPI_WRITEREAD 0x03u + +#define EP_OUT 0x01u +#define EP_IN 0x82u + +#define SPI_TIMEOUT 1000 +#define SPI_MAX_TRANSFER (4 + 64) + +static int TPM2_USB_Init(TPM2_CTX* ctx) +{ + int ret; + int nb_ifaces = 0; + libusb_device *dev = NULL; + struct libusb_config_descriptor *conf_desc = NULL; + + if (ctx->usbCtx.dev_ctx != NULL) { + return 0; /* already initialized */ + } + + ret = libusb_init(&ctx->usbCtx.dev_ctx); + if (ret == 0) { + ctx->usbCtx.dev_handle = libusb_open_device_with_vid_pid(ctx->usbCtx.dev_ctx, + VID_CYPRESS, PID_CYUSBSPI); + if (ctx->usbCtx.dev_handle == NULL) { + ret = -1; + } + } + if (ret == 0) { + dev = libusb_get_device(ctx->usbCtx.dev_handle); + if (dev == NULL) { + ret = -1; + } + } + if (ret == 0) { + ret = libusb_get_config_descriptor(dev, 0, &conf_desc); + if (ret == 0) { + nb_ifaces = conf_desc->bNumInterfaces; + if (nb_ifaces <= 0) { + ret = -1; + } + libusb_free_config_descriptor(conf_desc); + } + } + if (ret == 0) { + ret = libusb_set_auto_detach_kernel_driver(ctx->usbCtx.dev_handle, 1); + } + if (ret == 0) { + ret = libusb_claim_interface(ctx->usbCtx.dev_handle, 0); + } + + ctx->usbCtx.spi_dma_buffer = libusb_dev_mem_alloc(ctx->usbCtx.dev_handle, SPI_MAX_TRANSFER); + /* failure to allocate DMA, means we will use the buffer directly */ + + if (ret != 0) { + TPM2_USB_Cleanup(ctx); + } + return ret; +} + + +int TPM2_USB_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet) +{ + int ret; + int act_len = 0; + int retry = 0; + int transferred = 0; + int length; + uint8_t* buffer; + + ret = TPM2_USB_Init(ctx); + + /* start transfer */ + if (ret == 0) { + length = packet->pos; + if (ctx->usbCtx.spi_dma_buffer != NULL && length < SPI_MAX_TRANSFER) { + buffer = ctx->usbCtx.spi_dma_buffer; + XMEMCPY(buffer, packet->buf, length); + } + else { + buffer = packet->buf; + } + + ret = libusb_control_transfer(ctx->usbCtx.dev_handle, CTRL_SET, CY_CMD_SPI, + CY_SPI_WRITEREAD, length, NULL, 0, SPI_TIMEOUT); + + /* do send */ + while (ret == 0 && transferred < length) { + ret = libusb_bulk_transfer(ctx->usbCtx.dev_handle, EP_OUT, + ctx->usbCtx.spi_dma_buffer + transferred, length, &act_len, SPI_TIMEOUT); + if (ret == 0) { + transferred += act_len; + length -= act_len; + } + } + + /* do receive */ + transferred = 0; + length = packet->pos; + while (ret == 0 && transferred < length) { + ret = libusb_bulk_transfer(ctx->usbCtx.dev_handle, EP_IN, + ctx->usbCtx.spi_dma_buffer + transferred, length, &act_len, SPI_TIMEOUT); + if (ret != 0) { + /* allow retry up to 5 times */ + if (retry++ > 5) { + ret = -1; + break; + } + continue; + } + transferred += act_len; + length -= act_len; + } + } + + return ret; +} + +int TPM2_USB_Cleanup(TPM2_CTX* ctx) +{ + if (ctx->usbCtx.dev_handle != NULL) { + if (ctx->usbCtx.spi_dma_buffer != NULL) { + libusb_dev_mem_free(ctx->usbCtx.dev_handle, + ctx->usbCtx.spi_dma_buffer, SPI_MAX_TRANSFER); + } + + libusb_release_interface(ctx->usbCtx.dev_handle, 0); + libusb_close(ctx->usbCtx.dev_handle); + ctx->usbCtx.dev_handle = NULL; + } + if (ctx->usbCtx.dev_ctx != NULL) { + libusb_exit(ctx->usbCtx.dev_ctx); + ctx->usbCtx.dev_ctx = NULL; + } + return 0; +} + +#endif /* WOLFTPM_USB */ diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index ee49d505..112751db 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -60,7 +60,7 @@ static int wolfTPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx, return BAD_FUNC_ARG; #if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SWTPM) || \ - defined(WOLFTPM_WINAPI) + defined(WOLFTPM_WINAPI) || defined(WOLFTPM_USB) rc = TPM2_Init_minimal(ctx); /* Using standard file I/O for the Linux TPM device */ (void)ioCb; diff --git a/wolftpm/include.am b/wolftpm/include.am index 75baa15b..4ab00eb5 100644 --- a/wolftpm/include.am +++ b/wolftpm/include.am @@ -11,6 +11,7 @@ nobase_include_HEADERS+= \ wolftpm/tpm2_linux.h \ wolftpm/tpm2_swtpm.h \ wolftpm/tpm2_winapi.h \ + wolftpm/tpm2_usb.h \ wolftpm/tpm2_param_enc.h \ wolftpm/tpm2_socket.h \ wolftpm/version.h \ diff --git a/wolftpm/tpm2.h b/wolftpm/tpm2.h index fdad8f3c..51486961 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -1651,25 +1651,14 @@ static const BYTE TPM_20_EK_AUTH_POLICY[] = { /* HAL IO Callbacks */ struct TPM2_CTX; +struct TPM2_Packet; -#ifdef WOLFTPM_SWTPM -struct wolfTPM_tcpContext { - int fd; -}; -#endif /* WOLFTPM_SWTPM */ +#include +#include +#include +#include #ifdef WOLFTPM_WINAPI -#include -#include - -struct wolfTPM_winContext { - TBS_HCONTEXT tbs_context; -}; -/* may be needed with msys */ -#ifndef TPM_E_COMMAND_BLOCKED -#define TPM_E_COMMAND_BLOCKED (0x80280400) -#endif - #define WOLFTPM_IS_COMMAND_UNAVAILABLE(code) ((code) == (int)TPM_RC_COMMAND_CODE || (code) == (int)TPM_E_COMMAND_BLOCKED) #else #define WOLFTPM_IS_COMMAND_UNAVAILABLE(code) (code == (int)TPM_RC_COMMAND_CODE) @@ -1703,6 +1692,9 @@ typedef struct TPM2_CTX { #ifdef WOLFTPM_WINAPI struct wolfTPM_winContext winCtx; #endif +#ifdef WOLFTPM_USB + struct tpmUsbCtx usbCtx; +#endif #ifndef WOLFTPM2_NO_WOLFCRYPT #ifndef SINGLE_THREADED wolfSSL_Mutex hwLock; diff --git a/wolftpm/tpm2_linux.h b/wolftpm/tpm2_linux.h index 11a85680..5b55c252 100644 --- a/wolftpm/tpm2_linux.h +++ b/wolftpm/tpm2_linux.h @@ -29,8 +29,13 @@ extern "C" { #endif +#ifdef WOLFTPM_LINUX_DEV + /* TPM2 IO for using TPM through the Linux kernel driver */ -WOLFTPM_LOCAL int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet); +WOLFTPM_LOCAL int TPM2_LINUX_SendCommand(struct TPM2_CTX* ctx, + struct TPM2_Packet* packet); + +#endif /* WOLFTPM_LINUX_DEV */ #ifdef __cplusplus } /* extern "C" */ diff --git a/wolftpm/tpm2_packet.h b/wolftpm/tpm2_packet.h index eacde1a6..38596479 100644 --- a/wolftpm/tpm2_packet.h +++ b/wolftpm/tpm2_packet.h @@ -55,7 +55,7 @@ WOLFTPM_LOCAL UINT32 TPM2_Packet_SwapU32(UINT32 data); WOLFTPM_LOCAL UINT64 TPM2_Packet_SwapU64(UINT64 data); WOLFTPM_LOCAL void TPM2_Packet_InitBuf(TPM2_Packet* packet, byte* buf, int size); -WOLFTPM_LOCAL void TPM2_Packet_Init(TPM2_CTX* ctx, TPM2_Packet* packet); +WOLFTPM_LOCAL void TPM2_Packet_Init(struct TPM2_CTX* ctx, TPM2_Packet* packet); WOLFTPM_LOCAL void TPM2_Packet_AppendU8(TPM2_Packet* packet, UINT8 data); WOLFTPM_LOCAL void TPM2_Packet_ParseU8(TPM2_Packet* packet, UINT8* data); WOLFTPM_LOCAL void TPM2_Packet_AppendU16(TPM2_Packet* packet, UINT16 data); @@ -71,7 +71,7 @@ WOLFTPM_LOCAL void TPM2_Packet_MarkU16(TPM2_Packet* packet, int* markSz); WOLFTPM_LOCAL int TPM2_Packet_PlaceU16(TPM2_Packet* packet, int markSz); WOLFTPM_LOCAL void TPM2_Packet_MarkU32(TPM2_Packet* packet, int* markSz); WOLFTPM_LOCAL void TPM2_Packet_PlaceU32(TPM2_Packet* packet, int markSz); -WOLFTPM_LOCAL int TPM2_Packet_AppendAuth(TPM2_Packet* packet, TPM2_CTX* ctx); +WOLFTPM_LOCAL int TPM2_Packet_AppendAuth(TPM2_Packet* packet, struct TPM2_CTX* ctx); WOLFTPM_LOCAL void TPM2_Packet_AppendAuthCmd(TPM2_Packet* packet, TPMS_AUTH_COMMAND* authCmd); WOLFTPM_LOCAL void TPM2_Packet_ParseAuth(TPM2_Packet* packet, TPMS_AUTH_RESPONSE* auth); WOLFTPM_LOCAL void TPM2_Packet_AppendPCR(TPM2_Packet* packet, TPML_PCR_SELECTION* pcr); diff --git a/wolftpm/tpm2_swtpm.h b/wolftpm/tpm2_swtpm.h index 52a9294c..54b8c408 100644 --- a/wolftpm/tpm2_swtpm.h +++ b/wolftpm/tpm2_swtpm.h @@ -29,6 +29,11 @@ extern "C" { #endif +#ifdef WOLFTPM_SWTPM +struct wolfTPM_tcpContext { + int fd; +}; + /* copy from TpmTcpProtocol.h */ #if 0 #define TPM_SIGNAL_POWER_ON 1 @@ -43,7 +48,10 @@ #endif /* TPM2 IO for using TPM through a Socket connection */ -WOLFTPM_LOCAL int TPM2_SWTPM_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet); +WOLFTPM_LOCAL int TPM2_SWTPM_SendCommand(struct TPM2_CTX* ctx, + struct TPM2_Packet* packet); + +#endif /* WOLFTPM_SWTPM */ #ifdef __cplusplus } /* extern "C" */ diff --git a/wolftpm/tpm2_usb.h b/wolftpm/tpm2_usb.h new file mode 100644 index 00000000..174613e8 --- /dev/null +++ b/wolftpm/tpm2_usb.h @@ -0,0 +1,54 @@ +/* tpm2_usb.h + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfTPM. + * + * wolfTPM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfTPM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _TPM2_USB_H_ +#define _TPM2_USB_H_ + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef WOLFTPM_USB + +#include + +typedef struct tpmUsbCtx { + libusb_device_handle *dev_handle; + libusb_context *dev_ctx; + uint8_t *spi_dma_buffer; +} tpmUsbCtx_t; + +/* TPM2 IO for using TPM through a libusb USB2SPI converter */ +WOLFTPM_LOCAL int TPM2_USB_SendCommand(struct TPM2_CTX* ctx, + struct TPM2_Packet* packet); + +WOLFTPM_LOCAL int TPM2_USB_Cleanup(struct TPM2_CTX* ctx); + +#endif /* WOLFTPM_USB */ + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* _TPM2_USB_H_ */ diff --git a/wolftpm/tpm2_winapi.h b/wolftpm/tpm2_winapi.h index dc1bb825..2273263f 100644 --- a/wolftpm/tpm2_winapi.h +++ b/wolftpm/tpm2_winapi.h @@ -29,11 +29,29 @@ extern "C" { #endif +#ifdef WOLFTPM_WINAPI + +#include +#include + +struct wolfTPM_winContext { + TBS_HCONTEXT tbs_context; +}; + +/* may be needed with msys */ +#ifndef TPM_E_COMMAND_BLOCKED +#define TPM_E_COMMAND_BLOCKED (0x80280400) +#endif + + /* TPM2 IO for using TPM through the Winapi kernel driver */ -WOLFTPM_LOCAL int TPM2_WinApi_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet); +WOLFTPM_LOCAL int TPM2_WinApi_SendCommand(struct TPM2_CTX* ctx, + struct TPM2_Packet* packet); /* Cleanup winpi context */ -WOLFTPM_LOCAL int TPM2_WinApi_Cleanup(TPM2_CTX* ctx); +WOLFTPM_LOCAL int TPM2_WinApi_Cleanup(struct TPM2_CTX* ctx); + +#endif /* WOLFTPM_WINAPI */ #ifdef __cplusplus } /* extern "C" */