The tpm plugin offers random number generation
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 18 Mar 2017 13:51:30 +0000 (14:51 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 20 Mar 2017 20:16:10 +0000 (21:16 +0100)
The tpm plugin can be used to derive true random numbers from a
TPM 2.0 device. The get_random method must be explicitly enabled
in strongswan.conf with the plugin.tpm.use_rng = yes option.

conf/Makefile.am
conf/plugins/tpm.opt [new file with mode: 0644]
src/libtpmtss/plugins/tpm/Makefile.am
src/libtpmtss/plugins/tpm/tpm_plugin.c
src/libtpmtss/plugins/tpm/tpm_rng.c [new file with mode: 0644]
src/libtpmtss/plugins/tpm/tpm_rng.h [new file with mode: 0644]
src/libtpmtss/tpm_tss.h
src/libtpmtss/tpm_tss_trousers.c
src/libtpmtss/tpm_tss_tss2.c

index 41912c4..731446a 100644 (file)
@@ -93,6 +93,7 @@ plugins = \
        plugins/tnc-pdp.opt \
        plugins/tnccs-11.opt \
        plugins/tnccs-20.opt \
+       plugins/tpm.opt \
        plugins/unbound.opt \
        plugins/updown.opt \
        plugins/vici.opt \
diff --git a/conf/plugins/tpm.opt b/conf/plugins/tpm.opt
new file mode 100644 (file)
index 0000000..cd666dd
--- /dev/null
@@ -0,0 +1,2 @@
+charon.plugins.tpm.use_rng = no
+       Whether the TPM should be used as RNG.
index c12f09b..2812810 100644 (file)
@@ -15,6 +15,7 @@ endif
 
 libstrongswan_tpm_la_SOURCES = \
        tpm_plugin.h tpm_plugin.c \
-       tpm_private_key.h tpm_private_key.c
+       tpm_private_key.h tpm_private_key.c \
+       tpm_rng.h tpm_rng.c
 
 libstrongswan_tpm_la_LDFLAGS = -module -avoid-version
index 3d6321e..b9a4c12 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "tpm_plugin.h"
 #include "tpm_private_key.h"
+#include "tpm_rng.h"
 
 #include <library.h>
 
@@ -40,13 +41,32 @@ METHOD(plugin_t, get_name, char*,
 METHOD(plugin_t, get_features, int,
        private_tpm_plugin_t *this, plugin_feature_t *features[])
 {
-       static plugin_feature_t f[] = {
+       static plugin_feature_t f_rng[] = {
+               PLUGIN_REGISTER(RNG, tpm_rng_create),
+                       PLUGIN_PROVIDE(RNG, RNG_STRONG),
+                       PLUGIN_PROVIDE(RNG, RNG_TRUE),
+       };
+       static plugin_feature_t f_privkey[] = {
                PLUGIN_REGISTER(PRIVKEY, tpm_private_key_connect, FALSE),
                        PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
        };
+       static plugin_feature_t f[countof(f_rng) + countof(f_privkey)] = {};
+
+       static int count = 0;
+
+       if (!count)
+       {
+               plugin_features_add(f, f_privkey, countof(f_privkey), &count);
+
+               if (lib->settings->get_bool(lib->settings,
+                                                               "%s.plugins.tpm.use_rng", FALSE, lib->ns))
+               {
+                       plugin_features_add(f, f_rng, countof(f_rng), &count);
+               }
+       }
        *features = f;
 
-       return countof(f);
+       return count;
 }
 
 METHOD(plugin_t, destroy, void,
diff --git a/src/libtpmtss/plugins/tpm/tpm_rng.c b/src/libtpmtss/plugins/tpm/tpm_rng.c
new file mode 100644 (file)
index 0000000..d96bc49
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "tpm_rng.h"
+
+#include <tpm_tss.h>
+#include <utils/debug.h>
+
+typedef struct private_tpm_rng_t private_tpm_rng_t;
+
+/**
+ * Private data of an tpm_rng_t object.
+ */
+struct private_tpm_rng_t {
+
+       /**
+        * Public interface.
+        */
+       tpm_rng_t public;
+
+       /**
+        * Trusted Platform Module
+        */
+       tpm_tss_t *tpm;
+
+};
+
+METHOD(rng_t, get_bytes, bool,
+       private_tpm_rng_t *this, size_t bytes, uint8_t *buffer)
+{
+       return this->tpm->get_random(this->tpm, bytes, buffer);
+}
+
+METHOD(rng_t, allocate_bytes, bool,
+       private_tpm_rng_t *this, size_t bytes, chunk_t *chunk)
+{
+       *chunk = chunk_alloc(bytes);
+       if (!get_bytes(this, chunk->len, chunk->ptr))
+       {
+               chunk_clear(chunk);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+METHOD(rng_t, destroy, void,
+       private_tpm_rng_t *this)
+{
+       this->tpm->destroy(this->tpm);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+tpm_rng_t *tpm_rng_create(rng_quality_t quality)
+{
+       private_tpm_rng_t *this;
+       tpm_tss_t *tpm;
+
+       /* try to find a TPM 2.0 */
+       tpm = tpm_tss_probe(TPM_VERSION_2_0);
+       if (!tpm)
+       {
+               DBG1(DBG_LIB, "no TPM 2.0 found");
+               return NULL;    
+       }
+
+       INIT(this,
+               .public = {
+                       .rng = {
+                               .get_bytes = _get_bytes,
+                               .allocate_bytes = _allocate_bytes,
+                               .destroy = _destroy,
+                       },
+               },
+               .tpm = tpm,
+       );
+
+       return &this->public;
+}
+
diff --git a/src/libtpmtss/plugins/tpm/tpm_rng.h b/src/libtpmtss/plugins/tpm/tpm_rng.h
new file mode 100644 (file)
index 0000000..de96816
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup tpm_rng tpm_rng
+ * @{ @ingroup tpm
+ */
+
+#ifndef TPM_RNG_H_
+#define TPM_RNG_H_
+
+typedef struct tpm_rng_t tpm_rng_t;
+
+#include <library.h>
+
+/**
+ * rng_t implementation via TSS 2.0
+ */
+struct tpm_rng_t {
+
+       /**
+        * Implements rng_t.
+        */
+       rng_t rng;
+};
+
+/**
+ * Creates a tpm_rng_t instance.
+ *
+ * @param quality      required quality of randomness
+ * @return                     created tpm_rng_t
+ */
+tpm_rng_t *tpm_rng_create(rng_quality_t quality);
+
+#endif /** TPM_RNG_H_ @} */
index 270e7df..f408d04 100644 (file)
@@ -135,6 +135,15 @@ struct tpm_tss_t {
                                 chunk_t *signature);
 
        /**
+        * Get random bytes from the TPM
+        *
+        * @param bytes                 number of random bytes requested
+        * @param buffer                buffer where the random bytes are written into
+        * @return                              TRUE if random bytes could be delivered
+        */
+       bool (*get_random)(tpm_tss_t *this, size_t bytes, uint8_t *buffer);
+
+       /**
         * Destroy a tpm_tss_t.
         */
        void (*destroy)(tpm_tss_t *this);
index 550e621..d5bc2b8 100644 (file)
@@ -589,6 +589,12 @@ METHOD(tpm_tss_t, sign, bool,
        return FALSE;
 }
 
+METHOD(tpm_tss_t, get_random, bool,
+       private_tpm_tss_trousers_t *this, size_t bytes, uint8_t *buffer)
+{
+       return FALSE;
+}
+
 METHOD(tpm_tss_t, destroy, void,
        private_tpm_tss_trousers_t *this)
 {
@@ -632,6 +638,7 @@ tpm_tss_t *tpm_tss_trousers_create()
                                .extend_pcr = _extend_pcr,
                                .quote = _quote,
                                .sign = _sign,
+                               .get_random = _get_random,
                                .destroy = _destroy,
                        },
                        .load_aik = _load_aik,
index 3589617..9a4b9a4 100644 (file)
@@ -829,6 +829,32 @@ METHOD(tpm_tss_t, sign, bool,
        return TRUE;
 }
 
+METHOD(tpm_tss_t, get_random, bool,
+       private_tpm_tss_tss2_t *this, size_t bytes, uint8_t *buffer)
+{
+       size_t len, random_len= sizeof(TPM2B_DIGEST)-2;
+       TPM2B_DIGEST random = { { random_len, } };
+       uint8_t *pos = buffer;
+       uint32_t rval;
+
+       while (bytes > 0)
+       {
+               len = min(bytes, random_len);
+
+               rval = Tss2_Sys_GetRandom(this->sys_context, NULL, len, &random, NULL);
+               if (rval != TSS2_RC_SUCCESS)
+               {
+                       DBG1(DBG_PTS,"%s Tss2_Sys_GetRandom failed: 0x%06x", LABEL, rval);
+                       return FALSE;
+           }
+               memcpy(pos, random.t.buffer, random.t.size);
+               pos   += random.t.size;
+               bytes -= random.t.size;
+       }
+
+       return TRUE;
+}
+
 METHOD(tpm_tss_t, destroy, void,
        private_tpm_tss_tss2_t *this)
 {
@@ -854,6 +880,7 @@ tpm_tss_t *tpm_tss_tss2_create()
                        .extend_pcr = _extend_pcr,
                        .quote = _quote,
                        .sign = _sign,
+                       .get_random = _get_random,
                        .destroy = _destroy,
                },
        );