summaryrefslogtreecommitdiff
path: root/qrngd/qrngd.c
diff options
context:
space:
mode:
Diffstat (limited to 'qrngd/qrngd.c')
-rw-r--r--qrngd/qrngd.c462
1 files changed, 0 insertions, 462 deletions
diff --git a/qrngd/qrngd.c b/qrngd/qrngd.c
deleted file mode 100644
index 0be5bd3e..00000000
--- a/qrngd/qrngd.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <linux/random.h>
-#include <linux/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/poll.h>
-#include <linux/capability.h>
-#include <sys/prctl.h>
-#include <private/android_filesystem_config.h>
-
-#ifdef ANDROID_CHANGES
-#include <android/log.h>
-#endif
-
-#ifndef min
- #define min(a,b) (((a)>(b))?(b):(a))
-#endif
-
-typedef unsigned char bool;
-
-#define TRUE 1
-#define FALSE 0
-
-#define RANDOM_DEVICE "/dev/random"
-#define RANDOM_DEVICE_HW "/dev/hw_random"
-
-/* The device (/dev/random) internal limits 4096 bits of entropy, 512 bytes */
-#define MAX_ENT_POOL_BITS 4096
-#define MAX_ENT_POOL_BYTES (MAX_ENT_POOL_BITS / 8)
-
-#define MAX_ENT_POOL_WRITES 128 /* write pool with smaller chunks */
-
-///* Burst-mode timeout in us (micro-seconds) */
-//#define BURST_MODE_TIMEOUT 100000 /* 100ms */
-///* Idle-mode wait in us (micro-seconds) */
-//#define IDLE_MODE_WAIT 10000 /* 10ms */
-
-/* Buffer to hold hardware entropy bytes (this must be 2KB for FIPS testing */
-#define MAX_BUFFER 2048 /* do not change this value */
-static unsigned char databuf[MAX_BUFFER]; /* create buffer for FIPS testing */
-static unsigned long buffsize; /* size of data in buffer */
-static unsigned long curridx; /* position of current index */
-
-/* Globals */
-//static bool read_blocked = FALSE;
-//static pid_t qrngd_pid;
-
-/* User parameters */
-struct user_options {
- char input_device_name[128];
- char output_device_name[128];
- bool run_as_daemon;
-};
-
-/* Version number of this source */
-#define APP_VERSION "1.01"
-#define APP_NAME "qrngd"
-
-const char *program_version =
-APP_NAME " " APP_VERSION "\n"
-"Copyright (c) 2011, The Linux Foundation. All rights reserved.\n"
-"This is free software; see the source for copying conditions. There is NO\n"
-"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n";
-
-const char *program_usage =
-"Usage: " APP_NAME " [OPTION...]\n"
-" -b background - become a daemon (default)\n"
-" -f foreground - do not fork and become a daemon\n"
-" -r <device name> hardware random input device (default: /dev/hw_random)\n"
-" -o <device name> system random output device (default: /dev/random)\n"
-" -h help (this page)\n";
-
-/* Logging information */
-enum log_level {
- DEBUG = 0,
- INFO = 1,
- WARNING = 2,
- ERROR = 3,
- FATAL = 4,
- LOG_MAX = 4,
-};
-
-/* Logging function for outputing to stderr or log */
-void log_print(int level, char *format, ...)
-{
- if (level >= 0 && level <= LOG_MAX) {
-#ifdef ANDROID_CHANGES
- static int levels[5] = {
- ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
- ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
- };
- va_list ap;
- va_start(ap, format);
- __android_log_vprint(levels[level], APP_NAME, format, ap);
- va_end(ap);
-#else
- static char *levels = "DIWEF";
- va_list ap;
- fprintf(stderr, "%c: ", levels[level]);
- va_start(ap, format);
- vfprintf(stderr, format, ap);
- va_end(ap);
- fputc('\n', stderr);
-#endif
- }
-}
-
-static void title(void)
-{
- printf("%s", program_version);
-}
-
-static void usage(void)
-{
- printf("%s", program_usage);
-}
-
-/* Parse command line parameters */
-static int get_user_options(struct user_options *user_ops, int argc, char **argv)
-{
- int max_params = argc;
- int itr = 1; /* skip program name */
- while (itr < max_params) {
- if (argv[itr][0] != '-')
- return -1;
-
- switch (argv[itr++][1]) {
- case 'b':
- user_ops->run_as_daemon = TRUE;
- break;
-
- case 'f':
- user_ops->run_as_daemon = FALSE;
- break;
-
- case 'r':
- if (itr < max_params) {
- if (strlen(argv[itr]) < sizeof(user_ops->input_device_name))
- strcpy(user_ops->input_device_name, argv[itr++]);
- else
- return -1;
- break;
- }
- else
- return -1;
-
- case 'o':
- if (itr < max_params) {
- if (strlen(argv[itr]) < sizeof(user_ops->output_device_name))
- strcpy(user_ops->output_device_name, argv[itr++]);
- else
- return -1;
- break;
- }
- else
- return -1;
-
- case 'h':
- return -1;
-
-
- default:
- fprintf(stderr, "ERROR: Bad option: '%s'\n", argv[itr-1]);
- return -1;
- }
- }
- return 0;
-}
-
-/* Only check FIPS 140-2 (Continuous Random Number Generator Test) */
-static int fips_test(const unsigned char *buf, size_t size)
-{
- unsigned long *buff_ul = (unsigned long *) buf;
- size_t size_ul = size >> 2; /* convert byte to word size */
- unsigned long last_value;
- unsigned int rnd_ctr[256];
- int i;
-
-
- /* Continuous Random Number Generator Test */
- last_value = *(buff_ul++);
- size_ul--;
-
- while (size_ul > 0) {
- if (*buff_ul == last_value) {
- log_print(ERROR, "ERROR: Bad word value from hardware.");
- return -1;
- } else
- last_value = *buff_ul;
- buff_ul++;
- size_ul--;
- }
-
- /* count each random number */
- for (i = 0; i < size; ++i) {
- rnd_ctr[buf[i]]++;
- }
-
- /* check random numbers to make sure they are not bogus */
- for (i = 0; i < 256; ++i) {
- if (rnd_ctr[i] == 0) {
- log_print(ERROR, "ERROR: Bad spectral random number sample.");
- return -1;
- }
- }
-
- return 0;
-}
-
-/* Read data from the hardware RNG source */
-static int read_src(int fd, void *buf, size_t size)
-{
- size_t offset = 0;
- char *chr = (char *) buf;
- ssize_t ret;
-
- if (!size)
- return -1;
- do {
- ret = read(fd, chr + offset, size);
- /* any read failure is bad */
- if (ret == -1)
- return -1;
- size -= ret;
- offset += ret;
- } while (size > 0);
-
- /* should have read in all of requested data */
- if (size > 0)
- return -1;
- return 0;
-}
-
-/*Hold minimal permissions, so as to get IOCTL working*/
-static int qrng_update_cap()
-{
- int retvalue = 0;
- struct __user_cap_header_struct header;
- struct __user_cap_data_struct cap;
-
- memset(&header, 0, sizeof(header));
- memset(&cap, 0, sizeof(cap));
- prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
- if( 0 != setgid(AID_SYSTEM)){
- fprintf(stderr, "setgid error\n");
- return -1;
- }
- if( 0 != setuid(AID_SYSTEM)){
- fprintf(stderr, "setuid error\n");
- return -1;
- }
- header.version = _LINUX_CAPABILITY_VERSION;
- header.pid = 0;
- cap.effective = (1 << CAP_SYS_ADMIN) | (1 << CAP_NET_RAW);
- cap.permitted = cap.effective;
- cap.inheritable = 0;
- retvalue = capset(&header, &cap);
- if(retvalue != 0){
- fprintf(stderr, "capset error\n");
- return -1;
- }
- return 0;
-}
-
-/* The beginning of everything */
-int main(int argc, char **argv)
-{
- struct user_options user_ops; /* holds user configuration data */
- struct rand_pool_info *rand = NULL; /* structure to pass entropy (IOCTL) */
- int random_fd = 0; /* output file descriptor */
- int random_hw_fd = 0; /* input file descriptor */
- int ent_count; /* current system entropy */
- int write_size; /* max entropy data to pass */
- struct pollfd fds[1]; /* used for polling file descriptor */
- int ret;
- int exitval = 0;
-
- /* set default parameters */
- user_ops.run_as_daemon = TRUE;
- strcpy(user_ops.input_device_name, RANDOM_DEVICE_HW);
- strcpy(user_ops.output_device_name, RANDOM_DEVICE);
-
- /* display application header */
- title();
-
- /* get user preferences */
- ret = get_user_options(&user_ops, argc, argv);
- if (ret < 0) {
- usage();
- exitval = 1;
- goto exit;
- }
-
- /* open hardware random device */
- random_hw_fd = open(user_ops.input_device_name, O_RDONLY);
- if (random_hw_fd < 0) {
- fprintf(stderr, "Can't open hardware random device file %s\n", user_ops.input_device_name);
- exitval = 1;
- goto exit;
- }
-
- /*Hold minimal permissions, just enough to get IOCTL working*/
- if(0 != qrng_update_cap()){
- log_print(ERROR, "qrngd permission reset failed, exiting\n");
- exitval = 1;
- goto exit;
- }
-
- /* open random device */
- random_fd = open(user_ops.output_device_name, O_RDWR);
- if (random_fd < 0) {
- fprintf(stderr, "Can't open random device file %s\n", user_ops.output_device_name);
- exitval = 1;
- goto exit;
- }
-
- /* allocate memory for ioctl data struct and buffer */
- rand = malloc(sizeof(struct rand_pool_info) + MAX_ENT_POOL_WRITES);
- if (!rand) {
- fprintf(stderr, "Can't allocate memory\n");
- exitval = 1;
- goto exit;
- }
-
- /* setup poll() data */
- memset(fds, 0 , sizeof(fds));
- fds[0].fd = random_fd;
- fds[0].events = POLLOUT;
-
- /* run as daemon if requested to do so */
- if (user_ops.run_as_daemon) {
- fprintf(stderr, "Starting daemon.\n");
- if (daemon(0, 0) < 0) {
- fprintf(stderr, "can't daemonize: %s\n", strerror(errno));
- exitval = 1;
- goto exit;
- }
-#ifndef ANDROID_CHANGES
- openlog(APP_NAME, 0, LOG_DAEMON);
-#endif
- }
-
- /* log message */
- log_print(INFO, APP_NAME " has started:\n" "Reading device:'%s' updating entropy for device:'%s'",
- user_ops.input_device_name,
- user_ops.output_device_name);
-
- /* main loop to get data from hardware and feed RNG entropy pool */
- while (1) {
-
- /* Check for empty buffer and fill with hardware random generated numbers */
- if (buffsize == 0) {
- /* fill buffer with random data from hardware */
- ret = read_src(random_hw_fd, databuf, MAX_BUFFER);
- if (ret < 0) {
- log_print(ERROR, "ERROR: Can't read from hardware source.");
- exitval = 1;
- goto exit;
- }
- /* run FIPS test on buffer, if buffer fails then ditch it and get new data */
- ret = fips_test(databuf, MAX_BUFFER);
- if (ret < 0) {
- buffsize = 0;
- log_print(INFO, "ERROR: Failed FIPS test.");
- }
- /* everything good, reset buffer variables to indicate full buffer */
- else {
- buffsize = MAX_BUFFER;
- curridx = 0;
- }
- }
- /* We should have data here, if not then something bad happened above and we should wait and try again */
- if (buffsize == 0) {
- log_print(ERROR, "ERROR: Timeout getting valid random data from hardware.");
- usleep(100000); /* 100ms */
- continue;
- }
-
- /* Get current entropy pool size in bits and convert to bytes */
- if (ioctl(random_fd, RNDGETENTCNT, &ent_count) != 0) {
- log_print(ERROR, "ERROR: Can't read entropy count.");
- exitval = 1;
- goto exit;
- }
- /* convert entropy bits to bytes */
- ent_count >>= 3;
-
- /* fill entropy pool */
- write_size = min(buffsize, MAX_ENT_POOL_WRITES);
-
- /* Write some data to the device */
- rand->entropy_count = write_size * 8;
- rand->buf_size = write_size;
- memcpy(rand->buf, &databuf[curridx], write_size);
- curridx += write_size;
- buffsize -= write_size;
-
- /* Issue the ioctl to increase the entropy count */
- if (ioctl(random_fd, RNDADDENTROPY, rand) < 0) {
- log_print(ERROR,"ERROR: RNDADDENTROPY ioctl() failed.");
- exitval = 1;
- goto exit;
- }
-
- /* Wait if entropy pool is full */
- ret = poll(fds, 1, -1);
- if (ret < 0) {
- log_print(ERROR,"ERROR: poll call failed.");
- /* wait if error */
- usleep(100000);
- }
- }
-
-exit:
- /* free other resources */
- if (rand)
- free(rand);
- if (random_fd)
- close(random_fd);
- if (random_hw_fd)
- close(random_hw_fd);
- return exitval;
-}
-