/* * rngd_entsource.c -- Entropy source and conditioning * * Copyright (C) 2001 Philipp Rumpf * * 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. * * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #define _GNU_SOURCE #ifndef HAVE_CONFIG_H #error Invalid or missing autoconf build environment #endif #include "rng-tools-config.h" #include #include #include #include #include #include #include #include #include #include #include "rngd.h" #include "fips.h" #include "exits.h" #include "rngd_entsource.h" /* The overhead incured when tpm returns the random nos as per TCG spec * it is 14 bytes.*/ #define TPM_GET_RNG_OVERHEAD 14 /* Read data from the entropy source */ int xread(void *buf, size_t size, struct rng *ent_src) { size_t off = 0; ssize_t r; while (size > 0) { do { r = read(ent_src->rng_fd, buf + off, size); } while ((r == -1) && (errno == EINTR)); if (r <= 0) break; off += r; size -= r; } if (size) { message(LOG_DAEMON|LOG_ERR, "read error\n"); return -1; } return 0; } /* 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, struct rng *ent_src) { size_t bytes_read = 0; ssize_t r; int retval; 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; ent_src->rng_fd = open(ent_src->rng_name, O_RDWR); if (ent_src->rng_fd == -1) { message(LOG_ERR|LOG_INFO,"Unable to open file: %s",ent_src->rng_name); 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"); close(ent_src->rng_fd); 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(ent_src->rng_fd, rng_cmd + r, sizeof(rng_cmd) - r); if (retval < 0) { message(LOG_ERR|LOG_INFO, "Error writing %s\n", ent_src->rng_name); retval = -1; goto error_out; } r += retval; } if (r < sizeof(rng_cmd)) { message(LOG_ERR|LOG_INFO, "Error writing %s\n", ent_src->rng_name); retval = -1; goto error_out; } r = read(ent_src->rng_fd, temp_buf,size); r = (r - TPM_GET_RNG_OVERHEAD); if(r <= 0) { message(LOG_ERR|LOG_INFO, "Error reading from TPM, no entropy gathered"); retval = -1; goto error_out; } 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: close(ent_src->rng_fd); free(temp_buf); return retval; } /* Initialize entropy source */ static int discard_initial_data(struct rng *ent_src) { /* Trash 32 bits of what is probably stale (non-random) * initial state from the RNG. For Intel's, 8 bits would * be enough, but since AMD's generates 32 bits at a time... * * The kernel drivers should be doing this at device powerup, * but at least up to 2.4.24, it doesn't. */ unsigned char tempbuf[4]; xread(tempbuf, sizeof(tempbuf), ent_src); /* Return 32 bits of bootstrap data */ xread(tempbuf, sizeof(tempbuf), ent_src); return tempbuf[0] | (tempbuf[1] << 8) | (tempbuf[2] << 16) | (tempbuf[3] << 24); } /* * Open entropy source, and initialize it */ int init_entropy_source(struct rng *ent_src) { ent_src->rng_fd = open(ent_src->rng_name, O_RDONLY); if (ent_src->rng_fd == -1) { return 1; } src_list_add(ent_src); /* Bootstrap FIPS tests */ ent_src->fipsctx = malloc(sizeof(fips_ctx_t)); fips_init(ent_src->fipsctx, discard_initial_data(ent_src)); return 0; } /* * Open tpm entropy source, and initialize it */ int init_tpm_entropy_source(struct rng *ent_src) { ent_src->rng_fd = open(ent_src->rng_name, O_RDWR); if (ent_src->rng_fd == -1) { message(LOG_ERR|LOG_INFO,"Unable to open file: %s",ent_src->rng_name); return 1; } src_list_add(ent_src); /* Bootstrap FIPS tests */ ent_src->fipsctx = malloc(sizeof(fips_ctx_t)); fips_init(ent_src->fipsctx, 0); close(ent_src->rng_fd); return 0; }