diff --git a/configure.ac b/configure.ac index 16d89b3b..8027e3cb 100644 --- a/configure.ac +++ b/configure.ac @@ -230,7 +230,7 @@ AC_ARG_ENABLE([swtpm], [ ENABLED_SWTPM=no ] ) -if test "x$ENABLED_SWTPM" = "xyes" +if test "x$ENABLED_SWTPM" != "xno" then if test "x$ENABLED_DEVTPM" = "xyes" then @@ -238,6 +238,11 @@ then fi AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_SWTPM" + + if test "x$ENABLED_SWTPM" = "xuart" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_SWTPM_UART" + fi fi # Windows TBS device Support @@ -249,7 +254,7 @@ AC_ARG_ENABLE([winapi], if test "x$ENABLED_WINAPI" = "xyes" then - if test "x$ENABLED_DEVTPM" = "xyes" -o "x$ENABLED_SWTPM" = "xyes" + if test "x$ENABLED_DEVTPM" = "xyes" -o "x$ENABLED_SWTPM" != "xno" then AC_MSG_ERROR([Cannot enable swtpm or devtpm with windows API]) fi @@ -387,7 +392,7 @@ AC_ARG_ENABLE([hal], [ ENABLED_EXAMPLE_HAL=$enableval ], [ ENABLED_EXAMPLE_HAL=yes ] ) -if test "x$ENABLED_EXAMPLE_HAL" = "xyes" +if test "x$ENABLED_EXAMPLE_HAL" = "xyes" || test "x$ENABLED_MMIO" = "xyes" then AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_EXAMPLE_HAL" fi @@ -420,12 +425,12 @@ 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" != "xno"]) AM_CONDITIONAL([BUILD_DEVTPM], [test "x$ENABLED_DEVTPM" = "xyes"]) -AM_CONDITIONAL([BUILD_SWTPM], [test "x$ENABLED_SWTPM" = "xyes"]) +AM_CONDITIONAL([BUILD_SWTPM], [test "x$ENABLED_SWTPM" != "xno"]) AM_CONDITIONAL([BUILD_WINAPI], [test "x$ENABLED_WINAPI" = "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"]) -AM_CONDITIONAL([BUILD_HAL], [test "x$ENABLED_EXAMPLE_HAL" = "xyes" || test "x$ENABLED_MMIO" = "xyes"]) +AM_CONDITIONAL([BUILD_HAL], [test "x$ENABLED_EXAMPLE_HAL" = "xyes"]) CREATE_HEX_VERSION diff --git a/docs/SWTPM.md b/docs/SWTPM.md index cc2acc0f..efa2ecf4 100644 --- a/docs/SWTPM.md +++ b/docs/SWTPM.md @@ -1,65 +1,92 @@ -# Using wolfTPM with SWTPM +# wolfTPM with Software Simulator (SWTPM) support -wolfTPM is to be able to interface with SW TPM interfaces defined by -section D.3 of -[TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code](https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code.pdf) +wolfTPM is to be able to interface with software TPM (SW TPM) interfaces defined by section D.3 of [TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code](https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code.pdf) -Using the socket connection for SWTPM is exclusive and not compatible -with TIS or devtpm. +The SWTPM interface is not compatible with TIS or devtpm (/dev/tpm0). Transport is a socket connection by default, but can also be a UART. -Only a subset of functionality is implemented to support testing of -wolfTPM. The platform requests are not used by wolfTPM. +This implementation only uses the TPM command interface typically on port 2321. It does not support the Platform interface typically on port 2322. -Two implementations were used in testing: - -* https://sourceforge.net/projects/ibmswtpm2/files/ +Software TPM implementations tested: +* https://github.com/kgoldman/ibmswtpm2 or https://sourceforge.net/projects/ibmswtpm2/files/ +* https://github.com/microsoft/ms-tpm-20-ref * https://github.com/stefanberger/swtpm -## Building with SW TPM support +## Building SW TPM support -``` +By default a socket transport will be used. + +```sh ./configure --enable-swtpm make ``` +### Build SW TPM with UART transport + +```sh +./configure --enable-swtpm=uart +make +``` + +## Build Options + +* `WOLFTPM_SWTPM`: Use socket transport (no TIS layer) +* `TPM2_SWTPM_HOST`: The host TPM address (default=localhost) +* `TPM2_SWTPM_PORT`: The socket port (default=2321) +* `WOLFTPM_SWTPM_UART`: Use UART transport (no TIS layer) + + ## SWTPM simulator setup ### ibmswtpm2 Checkout and Build -``` +```sh git clone https://github.com/kgoldman/ibmswtpm2.git cd ibmswtpm2/src/ make ``` Running: -``` +```sh ./tpm_server -rm ``` -The rm switch is optional and remove the cache file -NVChip. Alternately you can `rm NVChip` +The rm switch is optional and remove the cache file NVChip. Alternately you can `rm NVChip` + +### ms-tpm-20-ref + +```sh +git clone https://github.com/microsoft/ms-tpm-20-ref +cd ms-tpm-20-ref +./bootstrap +./configure +make +./Simulator/src/tpm2-simulator +``` ### swtpm Build libtpms -``` +```sh git clone git@github.com:stefanberger/libtpms.git -(cd libtpms && ./autogen.sh --with-tpm2 --with-openssl --prefix=/usr && make install) +cd libtpms +./autogen.sh --with-tpm2 --with-openssl --prefix=/usr +make install ``` Build swtpm -``` +```sh git clone git@github.com:stefanberger/swtpm.git -(cd swtpm && ./autogen.sh && make install) +cd swtpm +./autogen.sh +make install ``` Note: On Mac OS X had to do the following first: -``` +```sh brew install openssl socat pip3 install cryptography @@ -71,14 +98,14 @@ export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include" Running swtpm -``` +```sh mkdir -p /tmp/myvtpm swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init ``` ## Running examples -``` +```sh ./examples/pcr/extend ./examples/wrap/wrap_test ``` diff --git a/src/tpm2_swtpm.c b/src/tpm2_swtpm.c index 453c52d6..d65ae8ba 100644 --- a/src/tpm2_swtpm.c +++ b/src/tpm2_swtpm.c @@ -35,23 +35,56 @@ #include #ifdef WOLFTPM_SWTPM + #include #include #include #include #include -#include -#include +#include /* necessary for memset */ +#include /* standard in/out procedures */ +#include /* defines system calls */ + +#ifdef WOLFTPM_SWTPM_UART + #define _XOPEN_SOURCE 600 + #include + #include /* used for all socket calls */ + #include /* used for sockaddr_in6 */ + #include + #include + #include + #include + #include + #include + + #ifndef TPM2_SWTPM_HOST + #ifdef __MACH__ + #define TPM2_SWTPM_HOST "/dev/cu.usbserial-0001" + #else + #define TPM2_SWTPM_HOST "/dev/ttyUSB0" + #endif + #endif + #ifndef TPM2_SWTPM_PORT + #define TPM2_SWTPM_PORT 115200 + #endif + #ifndef TPM2_TIMEOUT_SECONDS + #define TPM2_TIMEOUT_SECONDS 60 + #endif +#else + #include -#include + #ifndef TPM2_SWTPM_HOST + #define TPM2_SWTPM_HOST "localhost" + #endif + #ifndef TPM2_SWTPM_PORT + #define TPM2_SWTPM_PORT "2321" + #endif + #ifndef TPM2_TIMEOUT_SECONDS + #define TPM2_TIMEOUT_SECONDS 10 + #endif +#endif /* WOLFTPM_SWTPM_UART */ -#ifndef TPM2_SWTPM_HOST -#define TPM2_SWTPM_HOST "localhost" -#endif -#ifndef TPM2_SWTPM_PORT -#define TPM2_SWTPM_PORT "2321" -#endif static TPM_RC SwTpmTransmit(TPM2_CTX* ctx, const void* buffer, ssize_t bufSz) { @@ -62,6 +95,11 @@ static TPM_RC SwTpmTransmit(TPM2_CTX* ctx, const void* buffer, ssize_t bufSz) return BAD_FUNC_ARG; } +#ifdef DEBUG_SWTPM_IO + printf("Write %zd\n", bufSz); + TPM2_PrintBin(buffer, (word32)bufSz); +#endif + wrc = write(ctx->tcpCtx.fd, buffer, bufSz); if (bufSz != wrc) { rc = SOCKET_ERROR_E; @@ -77,48 +115,114 @@ static TPM_RC SwTpmTransmit(TPM2_CTX* ctx, const void* buffer, ssize_t bufSz) return rc; } -static TPM_RC SwTpmReceive(TPM2_CTX* ctx, void* buffer, size_t rxSz) +static int SwTpmReceive(TPM2_CTX* ctx, void* buffer, size_t rxSz) { - TPM_RC rc = TPM_RC_SUCCESS; - ssize_t wrc = 0; - size_t bytes_remaining = rxSz; + int rc; + size_t remain; char* ptr = (char*)buffer; + fd_set rfds; + struct timeval tv = { TPM2_TIMEOUT_SECONDS, 0}; 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) { + FD_ZERO(&rfds); + FD_SET(ctx->tcpCtx.fd, &rfds); + + remain = rxSz; + while (remain > 0) { + /* use select to wait for data */ + rc = select(ctx->tcpCtx.fd + 1, &rfds, NULL, NULL, &tv); + if (rc == 0) { + rc = SOCKET_ERROR_E; /* timeout */ + break; + } + rc = (int)read(ctx->tcpCtx.fd, ptr, remain); +#ifdef DEBUG_SWTPM_IO + printf("Read asked %zd, got %d\n", remain, rc); +#endif + if (rc <= 0) { + #ifdef DEBUG_WOLFTPM + if (rc == 0) { + #ifdef WOLFTPM_SWTPM_UART + continue; /* keep trying */ + #else printf("Failed to read from TPM socket: EOF\n"); + #endif } else { printf("Failed to read from TPM socket %d, got errno %d" " = %s\n", ctx->tcpCtx.fd, errno, strerror(errno)); } - #endif + #endif rc = SOCKET_ERROR_E; break; } - bytes_remaining -= wrc; - ptr += wrc; +#ifdef DEBUG_SWTPM_IO + TPM2_PrintBin((const byte*)ptr, rc); +#endif + remain -= rc; + ptr += rc; - #ifdef WOLFTPM_DEBUG_VERBOSE - printf("TPM socket received %zd waiting for %zu more\n", - wrc, bytes_remaining); - #endif + #ifdef WOLFTPM_DEBUG_VERBOSE + printf("TPM socket received %d waiting for %zu more\n", + rc, remain); + #endif + } + if (remain == 0) { + rc = TPM_RC_SUCCESS; } return rc; } -static TPM_RC SwTpmConnect(TPM2_CTX* ctx, const char* host, const char* port) +#ifdef WOLFTPM_SWTPM_UART +static int SwTpmConnect(TPM2_CTX* ctx, const char* uartDev, uint32_t baud) { - TPM_RC rc = SOCKET_ERROR_E; + struct termios tty; + int fd; + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + /* Open UART file descriptor */ + fd = open(uartDev, O_RDWR | O_NOCTTY); + if (fd < 0) { +#ifdef DEBUG_WOLFTPM + printf("Error opening %s: Error %i (%s)\n", + uartDev, errno, strerror(errno)); +#endif + return SOCKET_ERROR_E; + } + tcgetattr(fd, &tty); + cfsetospeed(&tty, baud); + cfsetispeed(&tty, baud); + tty.c_cflag = (tty.c_cflag & ~CSIZE) | (CS8); + tty.c_iflag &= ~(IGNBRK | IXON | IXOFF | IXANY| INLCR | ICRNL); + tty.c_oflag &= ~OPOST; + tty.c_oflag &= ~(ONLCR|OCRNL); + tty.c_cflag &= ~(PARENB | PARODD | CSTOPB); + tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + tty.c_iflag &= ~ISTRIP; + tty.c_cc[VMIN] = 0; + tty.c_cc[VTIME] = 5; + tcsetattr(fd, TCSANOW, &tty); + + /* Flush any data in the RX buffer */ + tcflush(fd, TCIOFLUSH); + + /* save file descriptor to context */ + ctx->tcpCtx.fd = fd; + + return TPM_RC_SUCCESS; +} +#else +static int SwTpmConnect(TPM2_CTX* ctx, const char* host, const char* port) +{ + int rc = SOCKET_ERROR_E; struct addrinfo hints; struct addrinfo *result, *rp; int s; @@ -163,6 +267,7 @@ static TPM_RC SwTpmConnect(TPM2_CTX* ctx, const char* host, const char* port) return rc; } +#endif /* WOLFTPM_SWTPM_UART */ static TPM_RC SwTpmDisconnect(TPM2_CTX* ctx) { @@ -173,22 +278,22 @@ static TPM_RC SwTpmDisconnect(TPM2_CTX* ctx) return BAD_FUNC_ARG; } - /* end swtpm session */ + /* end software TPM session */ tss_cmd = TPM2_Packet_SwapU32(TPM_SESSION_END); rc = SwTpmTransmit(ctx, &tss_cmd, sizeof(uint32_t)); - #ifdef WOLFTPM_DEBUG_VERBOSE +#ifdef WOLFTPM_DEBUG_VERBOSE if (rc != TPM_RC_SUCCESS) { printf("Failed to transmit SESSION_END\n"); } - #endif +#endif - if (0 != close(ctx->tcpCtx.fd)) { + if (close(ctx->tcpCtx.fd) != 0) { rc = SOCKET_ERROR_E; - #ifdef WOLFTPM_DEBUG_VERBOSE + #ifdef WOLFTPM_DEBUG_VERBOSE printf("Failed to close fd %d, got errno %d =" "%s\n", ctx->tcpCtx.fd, errno, strerror(errno)); - #endif + #endif } ctx->tcpCtx.fd = -1; @@ -247,10 +352,10 @@ int TPM2_SWTPM_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet) rc = SwTpmReceive(ctx, &tss_word, sizeof(uint32_t)); rspSz = TPM2_Packet_SwapU32(tss_word); if (rspSz > packet->size) { - #ifdef WOLFTPM_DEBUG_VERBOSE + #ifdef WOLFTPM_DEBUG_VERBOSE printf("Response size(%d) larger than command buffer(%d)\n", rspSz, packet->pos); - #endif + #endif rc = SOCKET_ERROR_E; } } @@ -266,14 +371,13 @@ int TPM2_SWTPM_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet) if (rc == TPM_RC_SUCCESS) { rc = SwTpmReceive(ctx, &tss_word, sizeof(uint32_t)); tss_word = TPM2_Packet_SwapU32(tss_word); - #ifdef WOLFTPM_DEBUG + #ifdef WOLFTPM_DEBUG if (tss_word != 0) { printf("SWTPM ack %d\n", tss_word); } - #endif + #endif } - #ifdef WOLFTPM_DEBUG_VERBOSE if (rspSz > 0) { printf("Response size: %d\n", rspSz);