diff --git a/configure.ac b/configure.ac index f83b0ab..986dcf8 100644 --- a/configure.ac +++ b/configure.ac @@ -179,6 +179,23 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_LINUX_DEV" fi +# Socket TPM device Support +AC_ARG_ENABLE([socket], + [AS_HELP_STRING([--enable-socket],[Enable use of TPM through the socket driver (default: disabled)])], + [ ENABLED_SOCKET=$enableval ], + [ ENABLED_SOCKET=no ] + ) + +if test "x$ENABLED_SOCKET" = "xyes" +then + if test "x$ENABLED_DEVTPM" = "xyes" + then + AC_MSG_ERROR([Cannot enable both socket and devtpm]) + fi + + AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_SOCKET" +fi + # STM ST33 Support AC_ARG_ENABLE([st33],, @@ -318,6 +335,7 @@ AM_CONDITIONAL([BUILD_ST], [test "x$ENABLED_ST" = "xyes"]) AM_CONDITIONAL([BUILD_MICROCHIP], [test "x$ENABLED_MICROCHIP" = "xyes"]) AM_CONDITIONAL([BUILD_INFINEON], [test "x$ENABLED_INFINEON" = "xyes"]) AM_CONDITIONAL([BUILD_DEVTPM], [test "x$ENABLED_DEVTPM" = "xyes"]) +AM_CONDITIONAL([BUILD_SOCKET], [test "x$ENABLED_SOCKET" = "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"]) diff --git a/src/include.am b/src/include.am index aae1365..e809cb9 100644 --- a/src/include.am +++ b/src/include.am @@ -13,6 +13,9 @@ src_libwolftpm_la_SOURCES = \ if BUILD_DEVTPM src_libwolftpm_la_SOURCES += src/tpm2_linux.c endif +if BUILD_SOCKET +src_libwolftpm_la_SOURCES += src/tpm2_socket.c +endif src_libwolftpm_la_CFLAGS = -DBUILDING_WOLFTPM $(AM_CFLAGS) src_libwolftpm_la_CPPFLAGS = -DBUILDING_WOLFTPM $(AM_CPPFLAGS) diff --git a/src/tpm2.c b/src/tpm2.c index 7c70ae6..e1e5ade 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -24,6 +24,7 @@ #include #include #include +#include /******************************************************************************/ /* --- Local Variables -- */ @@ -169,6 +170,8 @@ static TPM_RC TPM2_SendCommandAuth(TPM2_CTX* ctx, TPM2_Packet* packet, /* submit command and wait for response */ #ifdef WOLFTPM_LINUX_DEV rc = (TPM_RC)TPM2_LINUX_SendCommand(ctx, cmd, cmdSz); +#elif defined(WOLFTPM_SOCKET) + rc = (TPM_RC)TPM2_SOCKET_SendCommand(ctx, cmd, cmdSz); #else rc = (TPM_RC)TPM2_TIS_SendCommand(ctx, cmd, cmdSz); #endif @@ -237,10 +240,12 @@ static TPM_RC TPM2_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet) return BAD_FUNC_ARG; /* submit command and wait for response */ -#ifndef WOLFTPM_LINUX_DEV - rc = (TPM_RC)TPM2_TIS_SendCommand(ctx, packet->buf, packet->pos); -#else +#ifdef WOLFTPM_LINUX_DEV rc = (TPM_RC)TPM2_LINUX_SendCommand(ctx, packet->buf, packet->pos); +#elif defined(WOLFTPM_SOCKET) + rc = (TPM_RC)TPM2_SOCKET_SendCommand(ctx, packet->buf, packet->pos); +#else + rc = (TPM_RC)TPM2_TIS_SendCommand(ctx, packet->buf, packet->pos); #endif return TPM2_Packet_Parse(rc, packet); diff --git a/src/tpm2_linux.c b/src/tpm2_linux.c index 362267c..794a902 100644 --- a/src/tpm2_linux.c +++ b/src/tpm2_linux.c @@ -72,6 +72,7 @@ int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, byte* cmd, word16 cmdSz) /* Wait for response to be available */ rc_poll = poll(&fds, nfds, TPM2_LINUX_DEV_POLL_TIMEOUT); if (rc_poll > 0 && fds.revents == POLLIN) { + // TODO: could cmdSz be smaller than the response? rspSz = read(fd, cmd, TPM2_LINUX_DEV_RSP_SIZE); /* The caller parses the TPM_Packet for correctness */ if (rspSz >= TPM2_HEADER_SIZE) { diff --git a/src/tpm2_socket.c b/src/tpm2_socket.c new file mode 100644 index 0000000..857dcc7 --- /dev/null +++ b/src/tpm2_socket.c @@ -0,0 +1,284 @@ +/* tpm2_socket.c + * + * Copyright (C) 2006-2020 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 + */ + + + +/** + * This implements a subset of TPM TCP protocol as described in + * "TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code" + * + * This is intended for testing with a simulator such as + * http://ibmswtpm.sourceforge.net/ or + * https://github.com/stefanberger/swtpm + */ + +#ifdef WOLFTPM_SOCKET +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +#ifndef TPM2_SOCKET_HOST +#define TPM2_SOCKET_HOST "localhost" +#endif +#ifndef TPM2_SOCKET_PORT +#define TPM2_SOCKET_PORT "2321" +#endif + +static TPM_RC tpm_tcp_transmit(TPM2_CTX* ctx, const void* buffer, ssize_t bufSz) +{ + TPM_RC rc = TPM_RC_SUCCESS; + ssize_t wrc = 0; + + if (ctx == NULL || ctx->tcpCtx.fd <= 0 || buffer == NULL) { + return BAD_FUNC_ARG; + } + + /* send start */ + wrc = write(ctx->tcpCtx.fd, buffer, bufSz); + if (bufSz != wrc) { + rc = SOCKET_ERROR_E; + } + +#ifdef WOLFTPM_DEBUG_VERBOSE + if (wrc < 0) { + printf("Failed to send the TPM command to fd %d, got errno %d =" + "%s\n", ctx->tcpCtx.fd, errno, strerror(errno)); + } +#endif + + return rc; +} + +static TPM_RC tpm_tcp_receive(TPM2_CTX* ctx, void* buffer, size_t rxSz) { + TPM_RC rc = TPM_RC_SUCCESS; + ssize_t wrc = 0; + size_t bytes_remaining = rxSz; + char* ptr = buffer; + + if (ctx == NULL || ctx->tcpCtx.fd <= 0 || buffer == NULL) { + return BAD_FUNC_ARG; + } + + while (bytes_remaining > 0) { + wrc = read(ctx->tcpCtx.fd, ptr, bytes_remaining); + if (wrc <= 0) { + #ifdef DEBUG_WOLFTPM + if (wrc == 0) { + printf("Failed to read from TPM socket: EOF\n"); + } else { + printf("Failed to read from TPM socket %d, got errno %d" + " = %s\n", ctx->tcpCtx.fd, errno, strerror(errno)); + } + #endif + rc = SOCKET_ERROR_E; + break; + } + + bytes_remaining -= wrc; + ptr += wrc; + + #ifdef WOLFTPM_DEBUG_VERBOSE + printf("TPM socket received %zd waiting for %zu more\n", + wrc, bytes_remaining); + #endif + } + + return rc; +} + +static TPM_RC tpm_tcp_connect(TPM2_CTX* ctx, const char* host, const char* port) +{ + TPM_RC rc = SOCKET_ERROR_E; + struct addrinfo hints; + struct addrinfo *result, *rp; + int s; + int fd; + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + s = getaddrinfo(host, port, &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + } + + for (rp = result; rp != NULL; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) + continue; + + if (connect(fd, rp->ai_addr, rp->ai_addrlen) == -1) { + close(fd); + } else { + break; + } + } + freeaddrinfo(result); + + if (rp != NULL) { + ctx->tcpCtx.fd = fd; + rc = TPM_RC_SUCCESS; + } else { + #ifdef DEBUG_WOLFTPM + printf("Failed to connect to %s %s\n", host, port); + #endif + } + + return rc; +} + +static TPM_RC tpm_tcp_disconnect(TPM2_CTX* ctx) +{ + TPM_RC rc = TPM_RC_SUCCESS; + uint32_t tss_cmd; + + if (ctx == NULL || ctx->tcpCtx.fd <= 0) { + return BAD_FUNC_ARG; + } + + /* end swtpm session */ + tss_cmd = htonl(TPM_SESSION_END); + rc = tpm_tcp_transmit(ctx, &tss_cmd, sizeof(uint32_t)); + #ifdef WOLFTPM_DEBUG_VERBOSE + if (rc != TPM_RC_SUCCESS) { + printf("Failed to transmit SESSION_END\n"); + } + #endif + + if (0 != close(ctx->tcpCtx.fd)) { + rc = SOCKET_ERROR_E; + + #ifdef WOLFTPM_DEBUG_VERBOSE + printf("Failed to close fd %d, got errno %d =" + "%s\n", ctx->tcpCtx.fd, errno, strerror(errno)); + #endif + } + + ctx->tcpCtx.fd = -1; + + return rc; +} + +/* Talk to a TPM through socket */ +int TPM2_SOCKET_SendCommand(TPM2_CTX* ctx, byte* cmd, word16 cmdSz) +{ + int rc = TPM_RC_FAILURE; + word32 rspSz = 0; + uint32_t tss_word; + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + if (ctx->tcpCtx.fd <= 0) { + rc = tpm_tcp_connect(ctx, TPM2_SOCKET_HOST, TPM2_SOCKET_PORT); + } + +#ifdef WOLFTPM_DEBUG_VERBOSE + printf("Command size: %d\n", cmdSz); + TPM2_PrintBin(cmd, cmdSz); +#endif + + /* send start */ + tss_word = htonl(TPM_SEND_COMMAND); + if (rc == TPM_RC_SUCCESS) { + rc = tpm_tcp_transmit(ctx, &tss_word, sizeof(uint32_t)); + } + + /* locality */ + if (rc == TPM_RC_SUCCESS) { + rc = tpm_tcp_transmit(ctx, &ctx->locality, sizeof(uint8_t)); + } + + /* buffer size */ + tss_word = htonl(cmdSz); + if (rc == TPM_RC_SUCCESS) { + rc = tpm_tcp_transmit(ctx, &tss_word, sizeof(uint32_t)); + } + + /* Send the TPM command buffer */ + if (rc == TPM_RC_SUCCESS) { + rc = tpm_tcp_transmit(ctx, cmd, cmdSz); + } + + /* receive response */ + if (rc == TPM_RC_SUCCESS) { + rc = tpm_tcp_receive(ctx, &tss_word, sizeof(uint32_t)); + rspSz = ntohl(tss_word); + if (rspSz > cmdSz) { + #ifdef WOLFTPM_DEBUG_VERBOSE + printf("Response size(%d) larger than command buffer(%d)\n", + rspSz, cmdSz); + #endif + /* TODO: return error, for figure out way to avoid buffer overflow */ + //rc = SOCKET_ERROR_E; + } + } + + /* TODO: could hang as currently implemented, but is not TSS complient */ + if (rc == TPM_RC_SUCCESS) { + rc = tpm_tcp_receive(ctx, cmd, rspSz); + } + + /* receive ack */ + if (rc == TPM_RC_SUCCESS) { + rc = tpm_tcp_receive(ctx, &tss_word, sizeof(uint32_t)); + tss_word = ntohl(tss_word); + #ifdef WOLFTPM_DEBUG + if (tss_word != 0) { + printf("SWTPM ack %d\n", tss_word); + } + #endif + } + + +#ifdef WOLFTPM_DEBUG_VERBOSE + if (rspSz > 0) { + printf("Response size: %d\n", rspSz); + TPM2_PrintBin(cmd, rspSz); + } +#endif + + if (ctx->tcpCtx.fd > 0) { + TPM_RC rc_disconnect = tpm_tcp_disconnect(ctx); + if (rc == TPM_RC_SUCCESS) { + rc = rc_disconnect; + } + } + + return rc; +} +#endif /* WOLFTPM_SOCKET */ diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 9006546..b959e0b 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -97,8 +97,8 @@ static int wolfTPM2_Init_NoDev(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx, return rc; } -#ifdef WOLFTPM_LINUX_DEV -static int wolfTPM2_Init_LinuxDev(TPM2_CTX* ctx, void* userCtx) +#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SOCKET) +static int wolfTPM2_Init_NonTIS(TPM2_CTX* ctx, void* userCtx) { int rc; @@ -162,8 +162,8 @@ int wolfTPM2_Init(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb, void* userCtx) XMEMSET(dev, 0, sizeof(WOLFTPM2_DEV)); -#ifdef WOLFTPM_LINUX_DEV - rc = wolfTPM2_Init_LinuxDev(&dev->ctx, userCtx); +#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SOCKET) + rc = wolfTPM2_Init_NonTIS(&dev->ctx, userCtx); (void)ioCb; /* Using standard file I/O for the Linux TPM device */ #else diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 83ddf81..c984f69 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -93,7 +93,7 @@ static void test_wolfTPM2_Init(void) AssertIntNE(rc, 0); /* Test second argument, TPM2 IO Callbacks */ rc = wolfTPM2_Init(&dev, NULL, NULL); -#ifdef WOLFTPM_LINUX_DEV +#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SOCKET) /* Custom IO Callbacks are not needed for Linux TIS driver */ AssertIntEQ(rc, 0); #else diff --git a/wolftpm/include.am b/wolftpm/include.am index 7f268d1..c10adfb 100644 --- a/wolftpm/include.am +++ b/wolftpm/include.am @@ -9,6 +9,7 @@ nobase_include_HEADERS+= \ wolftpm/tpm2_types.h \ wolftpm/tpm2_wrap.h \ wolftpm/tpm2_linux.h \ + wolftpm/tpm2_socket.h \ wolftpm/version.h \ wolftpm/visibility.h \ wolftpm/options.h diff --git a/wolftpm/tpm2.h b/wolftpm/tpm2.h index b28c370..5457de3 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -1612,6 +1612,11 @@ static const BYTE TPM_20_EK_AUTH_POLICY[] = { /* HAL IO Callbacks */ struct TPM2_CTX; +#ifdef WOLFTPM_SOCKET +struct wolfTPM_tcpContext { + int fd; +}; +#endif /* WOLFTPM_SOCKET */ /* make sure advanced IO is enabled for I2C */ #ifdef WOLFTPM_I2C @@ -1635,6 +1640,9 @@ typedef int (*TPM2HalIoCb)(struct TPM2_CTX*, const BYTE* txBuf, BYTE* rxBuf, typedef struct TPM2_CTX { TPM2HalIoCb ioCb; void* userCtx; +#ifdef WOLFTPM_SOCKET + struct wolfTPM_tcpContext tcpCtx; +#endif #ifndef WOLFTPM2_NO_WOLFCRYPT #ifndef SINGLE_THREADED wolfSSL_Mutex hwLock; diff --git a/wolftpm/tpm2_socket.h b/wolftpm/tpm2_socket.h new file mode 100644 index 0000000..fa4f947 --- /dev/null +++ b/wolftpm/tpm2_socket.h @@ -0,0 +1,48 @@ +/* tpm2_socket.h + * + * Copyright (C) 2006-2020 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_SOCKET_H_ +#define _TPM2_SOCKET_H_ + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/* copy from TpmTcpProtocol.h */ +#define TPM_SIGNAL_POWER_ON 1 +#define TPM_SIGNAL_POWER_OFF 2 +#define TPM_SIGNAL_NV_ON 11 + +#define TPM_SEND_COMMAND 8 +#define TPM_SESSION_END 20 +#define TPM_STOP 21 + +/* TPM2 IO for using TPM through a Socket connection */ +int TPM2_SOCKET_SendCommand(TPM2_CTX* ctx, byte* cmd, word16 cmdSz); +/* int TPM2_SOCKET_PowerOn(TPM2_CTX* ctx); */ + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* _TPM2_SOCKET_H_ */ diff --git a/wolftpm/tpm2_types.h b/wolftpm/tpm2_types.h index e329fd7..3d6c2cc 100644 --- a/wolftpm/tpm2_types.h +++ b/wolftpm/tpm2_types.h @@ -75,6 +75,7 @@ typedef int64_t INT64; #include #include #include + #include #include #include #include @@ -110,12 +111,16 @@ typedef int64_t INT64; typedef uint32_t word32; typedef uint64_t word64; + /* Errors from wolfssl/wolfcrypt/error-crypt.h */ #define BAD_FUNC_ARG -173 /* Bad function argument provided */ #define BUFFER_E -132 /* output buffer too small or input too large */ #define NOT_COMPILED_IN -174 /* Feature not compiled in */ #define BAD_MUTEX_E -106 /* Bad mutex operation */ #define WC_TIMEOUT_E -107 /* timeout error */ + /* Errors from wolfssl/error-ssl.h */ + #define SOCKET_ERROR_E -308 /* error state on socket */ + #ifndef WOLFTPM_CUSTOM_TYPES #define XMEMCPY(d,s,l) memcpy((d),(s),(l)) #define XMEMSET(b,c,l) memset((b),(c),(l)) @@ -265,7 +270,7 @@ typedef int64_t INT64; #endif #ifndef TPM_TIMEOUT_TRIES - #ifdef WOLFTPM_LINUX_DEV + #if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SOCKET) #define TPM_TIMEOUT_TRIES 0 #else #define TPM_TIMEOUT_TRIES 1000000