blob: f0e219d7af674204e5bdcf96e9045c40717872c3 [file] [log] [blame]
/*
* 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 <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <stddef.h>
#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;
}