From 68d1f95d1e9e92d8d95a445b23d71a643b7363a6 Mon Sep 17 00:00:00 2001 From: Dimitar Tomov Date: Mon, 27 Apr 2020 21:54:59 +0300 Subject: [PATCH] Add interface for using TPM through the Linux device driver Signed-off-by: Dimitar Tomov --- configure.ac | 13 +++++ src/include.am | 3 +- src/tpm2_linux.c | 116 +++++++++++++++++++++++++++++++++++++++++++ wolftpm/tpm2_linux.h | 38 ++++++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/tpm2_linux.c create mode 100644 wolftpm/tpm2_linux.h diff --git a/configure.ac b/configure.ac index 13b5d04..4f86b83 100644 --- a/configure.ac +++ b/configure.ac @@ -162,6 +162,19 @@ then fi +# Linux kernel TPM device Support +AC_ARG_ENABLE([devtpm], + [AS_HELP_STRING([--enable-devtpm],[Enable use of TPM through the Linux kernel driver (default: disabled)])], + [ ENABLED_DEVTPM=$enableval ], + [ ENABLED_DEVTPM=no ] + ) + +if test "x$ENABLED_DEVTPM" = "xyes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_LINUX_DEV" +fi + + # STM ST33 Support AC_ARG_ENABLE([st33], [AS_HELP_STRING([--enable-st33],[Enable ST33 TPM Support (default: disabled)])], diff --git a/src/include.am b/src/include.am index 778083b..08e2439 100644 --- a/src/include.am +++ b/src/include.am @@ -8,7 +8,8 @@ src_libwolftpm_la_SOURCES = \ src/tpm2.c \ src/tpm2_packet.c \ src/tpm2_tis.c \ - src/tpm2_wrap.c + src/tpm2_wrap.c \ + src/tpm2_linux.c src_libwolftpm_la_CFLAGS = -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} diff --git a/src/tpm2_linux.c b/src/tpm2_linux.c new file mode 100644 index 0000000..d020424 --- /dev/null +++ b/src/tpm2_linux.c @@ -0,0 +1,116 @@ +/* tpm2_linux.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 + */ + + +#include +#include +#include /* Needed only for WOLFTPM2_MAX_BUFFER */ +#include +#include +#include +#include +#include +#include +#include + + +#define TPM2_LINUX_DEV "/dev/tpm0" +#define TPM2_LINUX_DEV_POLL_TIMEOUT -1 /* Infinite time for poll events */ +#define TPM2_LINUX_DEV_RSP_SIZE WOLFTPM2_MAX_BUFFER +/* Linux kernels older than v4.20 (before December 2018) do not support + * partial reads. The only way to receive a complete response is to read + * the maximum allowed TPM response from the kernel, which is 4K. And most + * of the ARM systems use older kernels, such as the RPI that uses v4.12 + * + * The caller knows what the expected outcome of the operation is. Therefore, + * the response size is limited only by the WOLFTPM2_MAX_BUFFER used to limit + * the WOLFTPM2_BUFFER in wolfTPM wrappers */ + + +/* Talk to a TPM device exposed by the Linux tpm_tis driver */ +int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, byte* cmd, word16 cmdSz) +{ + int rc = TPM_RC_FAILURE; + int fd, rspSz; + int rc_poll, nfds= 1; /* Polling single TPM dev file */ + struct pollfd fds; + +#ifdef DEBUG_WOLFTPM /* TODO: Change to WOLFTPM_DEBUG_VERBOSE */ + printf("Command size: %d\n", cmdSz); + TPM2_PrintBin(cmd, cmdSz); +#endif + + fd = open(TPM2_LINUX_DEV, O_RDWR | O_NONBLOCK); + if (fd > 0) { + /* Send the TPM command */ + if (write(fd, cmd, cmdSz) == cmdSz) { + fds.fd = fd; + fds.events = POLLIN; + /* Wait for response to be available */ + rc_poll = poll(&fds, nfds, TPM2_LINUX_DEV_POLL_TIMEOUT); + if (rc_poll > 0 && fds.revents == POLLIN) { + rspSz = read(fd, cmd, TPM2_LINUX_DEV_RSP_SIZE); + if (rspSz > 0) { + UINT32 tmpSz; + XMEMCPY(&tmpSz, &cmd[2], sizeof(UINT32)); + rspSz = TPM2_Packet_SwapU32(tmpSz); + /* Enough bytes for a TPM response? */ + if (rspSz >= TPM2_HEADER_SIZE) { + rc = TPM_RC_SUCCESS; + } + #ifdef DEBUG_WOLFTPM + else + { + printf("Response size is %d bytes, not enough to " + "hold TPM response.\n", rspSz); + } + } + else if (rspSz == 0) { + printf("Received EOF instead of TPM response.\n"); + } + else { + printf("Failed to read from TPM device %d, got errno %d" + " = %s\n", fd, errno, strerror(errno)); + #endif + } + } + #ifdef DEBUG_WOLFTPM /* TODO: Change to WOLFTPM_DEBUG_TIMEOUT */ + else { + printf("Failed to get a response from fd %d, got errno %d =" + "%s\n", fd, errno, strerror(errno)); + } + #endif + } + + close(fd); + } + +#ifdef DEBUG_WOLFTPM /* TODO: Change to WOLFTPM_DEBUG_VERBOSE */ + if (rspSz > 0) { + printf("Response size: %d\n", rspSz); + TPM2_PrintBin(cmd, rspSz); + } +#endif + + (void)ctx; + + return rc; +} diff --git a/wolftpm/tpm2_linux.h b/wolftpm/tpm2_linux.h new file mode 100644 index 0000000..45063c5 --- /dev/null +++ b/wolftpm/tpm2_linux.h @@ -0,0 +1,38 @@ +/* tpm2_linux.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_LINUX_H_ +#define _TPM2_LINUX_H_ + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/* TPM2 IO for using TPM through the Linux kernel driver */ +int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, byte* cmd, word16 cmdSz); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* _TPM2_LINUX_H_ */