From 4ee7d3b0118c82e651712bb65da53d08e78cd7b1 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Sat, 23 Mar 2019 05:13:51 +0000 Subject: [PATCH] Allow using TPM as entropy source. TPM has a built-in RNG, with its own entropy source. The driver was extended to harvest 16 random bytes from TPM every 10 seconds. A new build option "TPM_HARVEST" was introduced - for now, however, it is not enabled by default in the GENERIC config. Submitted by: Kornel Duleba Reviewed by: markm, delphij Approved by: secteam Obtained from: Semihalf Sponsored by: Stormshield Differential Revision: https://reviews.freebsd.org/D19620 --- sys/conf/options | 3 ++ sys/dev/random/random_harvestq.c | 1 + sys/dev/tpm/tpm20.c | 76 +++++++++++++++++++++++++++++++- sys/dev/tpm/tpm20.h | 6 +++ sys/dev/tpm/tpm_crb.c | 5 ++- sys/dev/tpm/tpm_tis.c | 2 +- sys/sys/random.h | 1 + 7 files changed, 90 insertions(+), 4 deletions(-) diff --git a/sys/conf/options b/sys/conf/options index 3e533542d519..4dffa9cf0c8b 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -983,6 +983,9 @@ RANDOM_LOADABLE opt_global.h RANDOM_ENABLE_UMA opt_global.h RANDOM_ENABLE_ETHER opt_global.h +# This options turns TPM into entropy source. +TPM_HARVEST opt_tpm.h + # BHND(4) driver BHND_LOGLEVEL opt_global.h diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c index 6c6adb0120e8..3f5ecc7ddea3 100644 --- a/sys/dev/random/random_harvestq.c +++ b/sys/dev/random/random_harvestq.c @@ -330,6 +330,7 @@ static const char *random_source_descr[ENTROPYSOURCE] = { [RANDOM_PURE_BROADCOM] = "PURE_BROADCOM", [RANDOM_PURE_CCP] = "PURE_CCP", [RANDOM_PURE_DARN] = "PURE_DARN", + [RANDOM_PURE_TPM] = "PURE_TPM", /* "ENTROPYSOURCE" */ }; diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c index 7aebaad78440..4e07b6eebbbf 100644 --- a/sys/dev/tpm/tpm20.c +++ b/sys/dev/tpm/tpm20.c @@ -28,13 +28,27 @@ #include __FBSDID("$FreeBSD$"); +#include + #include "tpm20.h" +#define TPM_HARVEST_SIZE 16 +/* + * Perform a harvest every 10 seconds. + * Since discrete TPMs are painfully slow + * we don't want to execute this too often + * as the chip is likely to be used by others too. + */ +#define TPM_HARVEST_INTERVAL 10000000 + MALLOC_DECLARE(M_TPM20); MALLOC_DEFINE(M_TPM20, "tpm_buffer", "buffer for tpm 2.0 driver"); static void tpm20_discard_buffer(void *arg); -static int tpm20_save_state(device_t dev, bool suspend); +#ifdef TPM_HARVEST +static void tpm20_harvest(void *arg); +#endif +static int tpm20_save_state(device_t dev, bool suspend); static d_open_t tpm20_open; static d_close_t tpm20_close; @@ -175,6 +189,11 @@ tpm20_init(struct tpm_sc *sc) sx_init(&sc->dev_lock, "TPM driver lock"); cv_init(&sc->buf_cv, "TPM buffer cv"); callout_init(&sc->discard_buffer_callout, 1); +#ifdef TPM_HARVEST + sc->harvest_ticks = TPM_HARVEST_INTERVAL / tick; + callout_init(&sc->harvest_callout, 1); + callout_reset(&sc->harvest_callout, 0, tpm20_harvest, sc); +#endif sc->pending_data_length = 0; make_dev_args_init(&args); @@ -195,6 +214,10 @@ void tpm20_release(struct tpm_sc *sc) { +#ifdef TPM_HARVEST + callout_drain(&sc->harvest_callout); +#endif + if (sc->buf != NULL) free(sc->buf, M_TPM20); @@ -217,6 +240,57 @@ tpm20_shutdown(device_t dev) return (tpm20_save_state(dev, false)); } +#ifdef TPM_HARVEST + +/* + * Get TPM_HARVEST_SIZE random bytes and add them + * into system entropy pool. + */ +static void +tpm20_harvest(void *arg) +{ + struct tpm_sc *sc; + unsigned char entropy[TPM_HARVEST_SIZE]; + uint16_t entropy_size; + int result; + uint8_t cmd[] = { + 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ + 0x00, 0x00, 0x00, 0x0c, /* cmd length */ + 0x00, 0x00, 0x01, 0x7b, /* cmd TPM_CC_GetRandom */ + 0x00, TPM_HARVEST_SIZE /* number of bytes requested */ + }; + + + sc = arg; + sx_xlock(&sc->dev_lock); + + memcpy(sc->buf, cmd, sizeof(cmd)); + result = sc->transmit(sc, sizeof(cmd)); + if (result != 0) { + sx_xunlock(&sc->dev_lock); + return; + } + + /* Ignore response size */ + sc->pending_data_length = 0; + + /* The number of random bytes we got is placed right after the header */ + entropy_size = (uint16_t) sc->buf[TPM_HEADER_SIZE + 1]; + if (entropy_size > 0) { + entropy_size = MIN(entropy_size, TPM_HARVEST_SIZE); + memcpy(entropy, + sc->buf + TPM_HEADER_SIZE + sizeof(uint16_t), + entropy_size); + } + + sx_xunlock(&sc->dev_lock); + if (entropy_size > 0) + random_harvest_queue(entropy, entropy_size, RANDOM_PURE_TPM); + + callout_reset(&sc->harvest_callout, sc->harvest_ticks, tpm20_harvest, sc); +} +#endif /* TPM_HARVEST */ + static int tpm20_save_state(device_t dev, bool suspend) { diff --git a/sys/dev/tpm/tpm20.h b/sys/dev/tpm/tpm20.h index 619b101d2fee..71128b58e577 100644 --- a/sys/dev/tpm/tpm20.h +++ b/sys/dev/tpm/tpm20.h @@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$"); #include #include "opt_acpi.h" +#include "opt_tpm.h" + #define BIT(x) (1 << (x)) /* Timeouts in us */ @@ -120,6 +122,10 @@ struct tpm_sc { size_t pending_data_length; struct callout discard_buffer_callout; +#ifdef TPM_HARVEST + struct callout harvest_callout; + int harvest_ticks; +#endif int (*transmit)(struct tpm_sc *, size_t); }; diff --git a/sys/dev/tpm/tpm_crb.c b/sys/dev/tpm/tpm_crb.c index abe4c4d13c25..f5c8047b1496 100644 --- a/sys/dev/tpm/tpm_crb.c +++ b/sys/dev/tpm/tpm_crb.c @@ -165,7 +165,8 @@ tpmcrb_attach(device_t dev) return (ENXIO); if(!tpmcrb_request_locality(sc, 0)) { - tpmcrb_detach(dev); + bus_release_resource(dev, SYS_RES_MEMORY, + sc->mem_rid, sc->mem_res); return (ENXIO); } @@ -231,12 +232,12 @@ tpmcrb_detach(device_t dev) struct tpm_sc *sc; sc = device_get_softc(dev); + tpm20_release(sc); if (sc->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); - tpm20_release(sc); return (0); } diff --git a/sys/dev/tpm/tpm_tis.c b/sys/dev/tpm/tpm_tis.c index 170fdd3967ff..25924a359325 100644 --- a/sys/dev/tpm/tpm_tis.c +++ b/sys/dev/tpm/tpm_tis.c @@ -162,6 +162,7 @@ tpmtis_detach(device_t dev) struct tpm_sc *sc; sc = device_get_softc(dev); + tpm20_release(sc); if (sc->intr_cookie != NULL) bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie); @@ -174,7 +175,6 @@ tpmtis_detach(device_t dev) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); - tpm20_release(sc); return (0); } diff --git a/sys/sys/random.h b/sys/sys/random.h index d65089baf7b9..b13ae6d69143 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -87,6 +87,7 @@ enum random_entropy_source { RANDOM_PURE_BROADCOM, RANDOM_PURE_CCP, RANDOM_PURE_DARN, + RANDOM_PURE_TPM, ENTROPYSOURCE }; _Static_assert(ENTROPYSOURCE <= 32,