This uses the trousers daemon to gather entropy from a local TPM RNG. Signed-off-by: Kees Cook <k...@debian.org> --- Makefile.am | 6 ++- configure.ac | 7 +++- rngd.c | 10 ++++ rngd_entsource.c | 34 ++++++++++++++ rngd_entsource.h | 3 +- tpm_engine.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tpm_engine.h | 53 ++++++++++++++++++++++ 7 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 tpm_engine.c create mode 100644 tpm_engine.h
diff --git a/Makefile.am b/Makefile.am index 921f2a2..af6648a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,13 +9,14 @@ bin_PROGRAMS = rngtest man_MANS = rngd.8 rngtest.1 noinst_LIBRARIES = librngd.a -common_sources = exits.h fips.h stats.h util.h viapadlock_engine.h +common_sources = exits.h fips.h stats.h util.h viapadlock_engine.h \ + tpm_engine.h rngd_SOURCES = $(common_sources) rngd.h rngd.c \ rngd_threads.h rngd_threads.c \ rngd_signals.h rngd_signals.c \ rngd_entsource.h rngd_entsource.c \ rngd_linux.h rngd_linux.c -rngd_LDADD = librngd.a @LIB_PTHREAD@ +rngd_LDADD = librngd.a @LIB_PTHREAD@ @LIB_TSPI@ rngtest_SOURCES = $(common_sources) rngtest.c rngtest_LDADD = librngd.a @@ -23,6 +24,7 @@ rngtest_LDADD = librngd.a librngd_a_SOURCES = fips.h fips.c \ stats.h stats.c \ util.h util.c \ + tpm_engine.h tpm_engine.c \ viapadlock_engine.h viapadlock_engine.c diff --git a/configure.ac b/configure.ac index 89af262..644d3d0 100644 --- a/configure.ac +++ b/configure.ac @@ -49,12 +49,17 @@ dnl Checks for required libraries dnl ----------------------------- AC_CHECK_LIB([pthread], [pthread_create], [LIB_PTHREAD="-lpthread"], - [AC_MSG_ERROR([Can't compile without pthreads])]) + [AC_MSG_ERROR([Can not compile without pthreads])]) AC_SUBST(LIB_PTHREAD) dnl ------------------------------------- dnl Checks for optional library functions dnl ------------------------------------- +AC_CHECK_LIB([tspi], [Tspi_Context_Create], + [LIB_TSPI="-ltspi" + AC_DEFINE(TPM_ENTSOURCE_DRIVER, 1, + [Include code for TPM RNG driver]) ], ) +AC_SUBST(LIB_TSPI) dnl ----------------- dnl Configure options diff --git a/rngd.c b/rngd.c index 27781aa..96fe013 100644 --- a/rngd.c +++ b/rngd.c @@ -265,6 +265,13 @@ static struct trng_params trng_parameters[] = { .entropy = 0.0, .driver = RNGD_ENTSOURCE_VIAPADLOCK, }, + { .name = "TPM RNG", + .tag = "tpm", + .width = 256, + .buffers = 1, + .entropy = 0.75, + .driver = RNGD_ENTSOURCE_TPM, + }, { NULL }, }; @@ -391,6 +398,9 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) if (! (seen_opt & SEEN_OPT_RNGENTROPY)) arguments->rng_entropy = 0.0; seen_opt |= SEEN_OPT_RNGDRIVER; + } else if (strcasecmp(arg, "tpm") == 0) { + arguments->rng_driver = RNGD_ENTSOURCE_TPM; + seen_opt |= SEEN_OPT_RNGDRIVER; } else { argp_usage(state); } diff --git a/rngd_entsource.c b/rngd_entsource.c index ebe2a44..90a62fc 100644 --- a/rngd_entsource.c +++ b/rngd_entsource.c @@ -49,6 +49,7 @@ #include "stats.h" #include "exits.h" #include "viapadlock_engine.h" +#include "tpm_engine.h" #include "rngd_threads.h" #include "rngd_signals.h" #include "rngd_entsource.h" @@ -87,6 +88,8 @@ const char *entropy_source_driver_name(entropy_source_driver_t driver) return "UNIX stream"; case RNGD_ENTSOURCE_VIAPADLOCK: return "VIA PadLock TRNG"; + case RNGD_ENTSOURCE_TPM: + return "TPM RNG"; default: return "(unknown)"; }; @@ -130,6 +133,12 @@ static int xread(void *buf, size_t size, unsigned int abortonsigalrm) break; } #endif +#ifdef TPM_ENTSOURCE_DRIVER + case RNGD_ENTSOURCE_TPM: { + r = tpm_rng_read((unsigned char *)buf + off, size); + break; + } +#endif default: errno = ENXIO; return -1; @@ -231,6 +240,31 @@ void init_entropy_source( void ) die(EXIT_USAGE); #endif /* VIA_ENTSOURCE_DRIVER */ } + case RNGD_ENTSOURCE_TPM: { +#ifdef TPM_ENTSOURCE_DRIVER + switch (tpm_rng_init()) { + case 0: + message(LOG_ERR, + "Could not detect a TPM " + "RNG, check that TPM is " + "available and enabled."); + die(EXIT_OSERR); + case 1: + break; + default: + message_strerr(LOG_ERR, errno, + "Error initializing TPM " + "RNG"); + die(EXIT_OSERR); + } + break; +#else + message(LOG_ERR, + "Support for the TPM RNG entropy source " + "driver has not been compiled in."); + die(EXIT_USAGE); +#endif /* TPM_ENTSOURCE_DRIVER */ + } default: message(LOG_ERR, "Unknown entropy source driver, internal program error!"); diff --git a/rngd_entsource.h b/rngd_entsource.h index c51874d..ada4a58 100644 --- a/rngd_entsource.h +++ b/rngd_entsource.h @@ -31,7 +31,8 @@ typedef enum { RNGD_ENTSOURCE_NONE, RNGD_ENTSOURCE_UNIXSTREAM, - RNGD_ENTSOURCE_VIAPADLOCK + RNGD_ENTSOURCE_VIAPADLOCK, + RNGD_ENTSOURCE_TPM, } entropy_source_driver_t; extern const char *entropy_source_driver_name(entropy_source_driver_t driver); diff --git a/tpm_engine.c b/tpm_engine.c new file mode 100644 index 0000000..c118838 --- /dev/null +++ b/tpm_engine.c @@ -0,0 +1,132 @@ +/* + * tpm_engine.c -- TPM RNG interface + * + * Copyright (C) 2009 Kees Cook <k...@outflux.net> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _GNU_SOURCE + +#include "rng-tools-config.h" +#ifdef TPM_ENTSOURCE_DRIVER + +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <trousers/tss.h> +#include <trousers/trousers.h> + +#include "tpm_engine.h" + +static TSS_HCONTEXT hContext; +static TSS_HTPM hTPM; +static int tpm_rng_ready; + +int tpm_rng_init_attempt(void) +{ + TSS_RESULT rc; + + if (tpm_rng_ready) return 1; + + if ((rc=Tspi_Context_Create(&hContext)) != TSS_SUCCESS) { + //fprintf(stderr,"Tspi_Context_Create: %s\n", Trspi_Error_String(rc)); + return 0; + } + + if ((rc=Tspi_Context_Connect(hContext, NULL)) != TSS_SUCCESS) { + //fprintf(stderr,"Tspi_Context_Connect: %s\n", Trspi_Error_String(rc)); + Tspi_Context_Close(hContext); + return 0; + } + + if ((rc=Tspi_Context_GetTpmObject(hContext, &hTPM)) != TSS_SUCCESS) { + //fprintf(stderr,"Tspi_Context_GetTpmObject: %s\n", Trspi_Error_String(rc)); + Tspi_Context_Close(hContext); + return 0; + } + + tpm_rng_ready = 1; + + return tpm_rng_ready; +} + +/* + * Initialize TPM RNG + * + * Returns: + * 0 if no working TPM RNG was detected + * 1 if a TPM RNG has been detected + * -1 if an error happened (errno will be set) + */ +int tpm_rng_init(void) +{ + int count, rc = 0; + + /* wait 5 seconds for TPM to become available */ + for (count = 0; count < 5; count++) { + if ( (rc = tpm_rng_init_attempt()) ) break; + sleep(1); + } + + return rc; +} + +/* + * Free up any resources used by the TPM RNG. + * It is legal to call tpm_rng_init() after this. + */ +void tpm_rng_free(void) +{ + if (tpm_rng_ready) { + Tspi_Context_Close(hContext); + tpm_rng_ready = 0; + } +} + +/* + * Read data from a TPM RNG + * + * Returns the number of bytes read if no errors happen + * -1 if an error happened, with errno set. + */ +ssize_t tpm_rng_read(void* buf, size_t size) +{ + TSS_RESULT rc; + BYTE *bytes; + + if (!tpm_rng_ready) { + errno = ENXIO; + return -1; + } + + if (!buf) { + errno = EOVERFLOW; + return -1; + } + + if (size > 32) size = 32; + if ((rc=Tspi_TPM_GetRandom(hTPM, size, &bytes)) != TSS_SUCCESS) { + //fprintf(stderr,"Tspi_TPM_GetRandom: %s\n", Trspi_Error_String(rc)); + errno = EIO; + return -1; + } + memcpy(buf, bytes, size); + Tspi_Context_FreeMemory(hContext, bytes); + + return size; +} + +#endif /* TPM_ENTSOURCE_DRIVER */ diff --git a/tpm_engine.h b/tpm_engine.h new file mode 100644 index 0000000..f5148e8 --- /dev/null +++ b/tpm_engine.h @@ -0,0 +1,53 @@ +/* + * tpm_engine.h -- TPM RNG interface + * + * Copyright (C) 2009 Kees Cook <k...@outflux.net> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TPM_RNG__H +#define TPM_RNG__H + +#define _GNU_SOURCE +#include "rng-tools-config.h" + +#ifdef TPM_ENTSOURCE_DRIVER + +/* + * Initialize TPM RNG + * + * Returns: + * 0 if no functional TPM RNG was detected + * 1 if a functional TPM RNG set was detected + * -1 if an error happened (errno will be set) + */ +extern int tpm_rng_init(void); + +/* + * Free up resources used by the TPM RNG + */ +extern void tpm_rng_free(void); + +/* + * Read data from TPM RNG + * + * Returns the number of bytes read if no errors happen + * -1 if an error happened, with errno set. + */ +extern ssize_t tpm_rng_read(void* buf, size_t size); + +#endif /* TPM_ENTSOURCE_DRIVER */ +#endif /* TPM_RNG__H */ -- 1.7.2.3 -- Kees Cook @debian.org -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org