#105 [Patch] for review, Add tpm rng support to rngtools

closed-accepted
Jeff Garzik
None
5
2015-02-15
2008-11-11
No

diff -uNr rng-tools-2-orig/rngd.c rng-tools-2/rngd.c
--- rng-tools-2-orig/rngd.c 2004-08-24 23:30:00.000000000 +0530
+++ rng-tools-2/rngd.c 2008-11-11 15:39:31.000000000 +0530
@@ -91,6 +91,8 @@

{ "timeout", 't', "nnn", 0,
"Interval written to random-device when the entropy pool is full, in seconds (default: 60)" },
+ { "no-tpm", 'n', "1|0", 0,
+ "do not use tpm as a source of random number input (default: 0)" },

{ 0 },
};
@@ -102,6 +104,7 @@
.random_step = 64,
.fill_watermark = 2048,
.daemon = 1,
+ .no_tpm =0,
};
struct arguments *arguments = &default_arguments;

@@ -147,6 +150,15 @@
arguments->fill_watermark = n;
break;
}
+ case 'n': {
+ int n;
+ if ((sscanf(arg,"%i", &n) == 0) || ((n | 1)!=1))
+ argp_usage(state);
+ else
+ arguments->no_tpm=0;
+ break;
+
+ }

default:
return ARGP_ERR_UNKNOWN;
@@ -162,26 +174,41 @@
double poll_timeout)
{
unsigned char buf[FIPS_RNG_BUFFER_SIZE];
- unsigned char *p;
- int fips;
+ int fips,retval;

for (;;) {
- xread(buf, sizeof buf);
+ if (arguments->no_tpm == 0) {
+ retval=xread_tpm(buf, sizeof buf);
+ if (retval < 0)
+ sleep(1);
+ else
+ update_kernel_random(random_step,
+ poll_timeout, buf, &tpm_fipsctx);
+ }
+ retval=xread(buf, sizeof buf);
+ if (retval > 0)
+ update_kernel_random(random_step,
+ poll_timeout, buf, &fipsctx);
+ }
+}

- fips = fips_run_rng_test(&fipsctx, buf);
+int update_kernel_random(int random_step, double poll_timeout,
+ unsigned char *buf, fips_ctx_t *fipsctx) {

- if (fips) {
- message(LOG_DAEMON|LOG_ERR, "failed fips test\n");
- sleep(1);
- continue;
- }
+ int fips;
+ unsigned char *p;
+ fips = fips_run_rng_test(fipsctx, buf);
+ if (fips) {
+ message(LOG_DAEMON|LOG_ERR, "failed fips test\n");
+ return 1;
+ }

- for (p = buf; p + random_step <= &buf[sizeof buf];
- p += random_step) {
- random_add_entropy(p, random_step);
- random_sleep(poll_timeout);
- }
+ for (p = buf; p + random_step <= &buf[FIPS_RNG_BUFFER_SIZE];
+ p += random_step) {
+ random_add_entropy(p, random_step);
+ random_sleep(poll_timeout);
}
+ return 0;
}

diff -uNr rng-tools-2-orig/rngd_entsource.c rng-tools-2/rngd_entsource.c
--- rng-tools-2-orig/rngd_entsource.c 2004-04-15 10:36:17.000000000 +0530
+++ rng-tools-2/rngd_entsource.c 2008-11-11 15:39:31.000000000 +0530
@@ -35,6 +35,7 @@
#include <errno.h>
#include <syslog.h>
#include <string.h>
+#include <signal.h>

#include "rngd.h"
#include "fips.h"
@@ -42,17 +43,27 @@
#include "rngd_entsource.h"

-/* Logic and contexts */
-static int rng_fd; /* rng data source */
-fips_ctx_t fipsctx; /* Context for the FIPS tests */
+/* The overhead incured when tpm returns the random nos as per TCG spec
+ * it is 14 bytes.*/
+#define TPM_GET_RNG_OVERHEAD 14

+static const char *rng_device="/dev/tpm0";
+/* Logic and contexts */
+static int rng_fd; /* rng data source */
+fips_ctx_t fipsctx; /* Context for the FIPS tests */
+fips_ctx_t tpm_fipsctx; /* Context for the tpm FIPS tests */

/* Read data from the entropy source */
-void xread(void *buf, size_t size)
+int xread(void *buf, size_t size)
{
size_t off = 0;
ssize_t r;

+ /* Do nothing if we have no hw rng, maybe we have tpm */
+ if (rng_fd < 0) {
+ message(LOG_DAEMON|LOG_ERR, "Invalid file handle\n");
+ return -1;
+ }
while (size > 0) {
do {
r = read(rng_fd, buf + off, size);
@@ -65,8 +76,85 @@

if (size) {
message(LOG_DAEMON|LOG_ERR, "read error\n");
- exit(1);
+ return -1;
+ }
+ return 0;
+}
+
+alarm_handler(int i) {
+ ;
+}
+/* tpm rng read call to kernel has 13 bytes of overhead
+ * the logic to process this involves reading to a temporary_buf
+ * and copying the no generated to buf*/
+int xread_tpm(void *buf, size_t size)
+{
+ size_t bytes_read = 0;
+ ssize_t r;
+ int retval,rngtpm_fd;
+ unsigned char *temp_buf=NULL;
+ unsigned char rng_cmd[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 14, /* length */
+ 0, 0, 0, 70, /* TPM_ORD_GetRandom */
+ 0, 0, 0, 0, /* number of bytes to return */
+ };
+ char *offset;
+
+ rngtpm_fd=open(rng_device, O_RDWR);
+ if (rngtpm_fd < 0) {
+ message(LOG_ERR|LOG_INFO,
+ "Unable to open %s: %s\n",rng_device,strerror(errno));
+ return -1;
+ }
+
+ temp_buf= (unsigned char *) malloc(size + TPM_GET_RNG_OVERHEAD);
+ memset(temp_buf,0,(size+TPM_GET_RNG_OVERHEAD));
+ if (temp_buf == NULL) {
+ message(LOG_ERR|LOG_INFO,"No memory");
+ return -1;
+ }
+ /* 32 bits has been reserved for random byte size */
+ rng_cmd[13]=(unsigned char)(size & 0xFF);
+ rng_cmd[12]=(unsigned char)((size >> 8) & 0xFF);
+ rng_cmd[11]=(unsigned char)((size >> 16) & 0xFF);
+ rng_cmd[10]=(unsigned char)((size >> 24) & 0xFF);
+ offset=buf;
+ while (bytes_read < size) {
+ r=0;
+ while (r < sizeof(rng_cmd)) {
+ retval=write(rngtpm_fd,rng_cmd + r,sizeof(rng_cmd)-r);
+ if (retval < 0) {
+ message(LOG_ERR|LOG_INFO,
+ "Error writing %s\n",rng_device);
+ retval=-1;
+ goto error_out;
+ }
+ r+=retval;
+ }
+ if (r < sizeof(rng_cmd)) {
+ message(LOG_ERR|LOG_INFO,
+ "Error writing %s\n",rng_device);
+ retval=-1;
+ goto error_out;
+ }
+ r=read(rngtpm_fd,temp_buf,size);
+ r=(r - TPM_GET_RNG_OVERHEAD);
+ bytes_read=bytes_read + r;
+ if (bytes_read > size) {
+ memcpy(offset,temp_buf + TPM_GET_RNG_OVERHEAD,
+ r - (bytes_read - size));
+ break;
+ }
+ memcpy(offset, temp_buf + TPM_GET_RNG_OVERHEAD,
+ r);
+ offset=offset+r;
}
+ retval=0;
+error_out:
+ free(temp_buf);
+ close(rngtpm_fd);
+ return retval;
}

/* Initialize entropy source */
@@ -93,14 +181,31 @@
*/
void init_entropy_source(const char* sourcedev)
{
+ /* We cannot keep the tpm device open always.
+ * We need to open get random data and close
+ * to allow tpm-tools and other utilities
+ * access to /dev/tpm */
+ int tpm_fd;
rng_fd = open(sourcedev, O_RDONLY);
if (rng_fd == -1) {
message(LOG_DAEMON|LOG_ERR, "can't open %s: %s",
sourcedev, strerror(errno));
- exit(EXIT_FAIL);
+ /* Try to open tpm this is just a test, no point in proceeding further
+ * if no source of entropy is present
+ */
+ tpm_fd = open(rng_device, O_RDONLY);
+ if (tpm_fd < 0 ) {
+ message(LOG_DAEMON|LOG_ERR,
+ "can't open entropy source(tpm or intel/amd rng) %s",
+ strerror(errno));
+ message(LOG_DAEMON|LOG_ERR,"Maybe RNG device modules are not loaded\n");
+ exit(1);
+ }
+ close(tpm_fd);
}

/* Bootstrap FIPS tests */
fips_init(&fipsctx, discard_initial_data());
+ fips_init(&tpm_fipsctx, 0);
}

diff -uNr rng-tools-2-orig/rngd_entsource.h rng-tools-2/rngd_entsource.h
--- rng-tools-2-orig/rngd_entsource.h 2004-04-15 10:34:45.000000000 +0530
+++ rng-tools-2/rngd_entsource.h 2008-11-11 15:39:31.000000000 +0530
@@ -28,7 +28,7 @@

/* Logic and contexts */
extern fips_ctx_t fipsctx; /* Context for the FIPS tests */
-
+extern fips_ctx_t tpm_fipsctx; /* Context for the tpm FIPS tests */
/*
* Initialize entropy source and entropy conditioning
*
@@ -37,6 +37,6 @@
extern void init_entropy_source(const char* sourcedev);

/* Read data from the entropy source */
-void xread(void *buf, size_t size);
+int xread(void *buf, size_t size);

#endif /* RNGD_ENTSOURCE__H */
diff -uNr rng-tools-2-orig/rngd.h rng-tools-2/rngd.h
--- rng-tools-2-orig/rngd.h 2004-08-24 23:23:04.000000000 +0530
+++ rng-tools-2/rngd.h 2008-11-11 15:39:31.000000000 +0530
@@ -42,6 +42,7 @@
double poll_timeout;

int daemon;
+ int no_tpm;
};
extern struct arguments *arguments;

Discussion

  • Attaching the patch as the inline patch is mangled.
    File Added: rngd_tpm_support.patch

     
  • Patch to add tpm rng support.

     
  • Jeff Garzik
    Jeff Garzik
    2009-03-06

    • assigned_to: nobody --> jgarzik
     
  • Matt Domsch
    Matt Domsch
    2009-10-20

    This patch fails for me on a PowerEdge R610 with the TPM enabled. The logic for deciding if either or both of /dev/hw_random and /dev/tpm0 are available was buggy. I cleaned up the patch and submitted it separately.

    Please don't use this version of the patch.

     
  • Jeff Garzik
    Jeff Garzik
    2010-07-04

    • status: open --> closed-accepted