2
* viapadlock-rng.c -- VIA PadLock TRNG access/setup utility
4
* Accesses the VIA PadLock True RNG for setup and reading of
5
* random bytes (does not peform any FIPS testing).
7
* Copyright (C) 2005 Henrique de Moraes Holschuh <hmh@debian.org>
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
#error Invalid or missing autoconf build environment
30
#include "rng-tools-config.h"
32
/* For printf types macros (PRIu64) */
33
#define __STDC_FORMAT_MACROS
46
#include "viapadlock_engine.h"
51
#define PROGNAME "viapadlock-rng"
52
const char* logprefix = PROGNAME ": ";
58
const char *argp_program_version =
59
PROGNAME " " VERSION "\n"
60
"Copyright (c) 2005 by Henrique de Moraes Holschuh\n"
61
"VIA PadLock RNG routines based on work by Martin Peck\n"
62
"This is free software; see the source for copying conditions. There is NO "
63
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.";
65
const char *argp_program_bug_address = PACKAGE_BUGREPORT;
66
error_t argp_err_exit_status = EXIT_USAGE;
69
"Setup and read the VIA PadLock True Random Number Generator.\n"
71
"Random data is not post-processed, and it is sent to stdout as received from "
72
"the VIA PadLock TRNG. You probably want to pipe the output of this utility to "
73
"rngtest --pipe for FIPS testing to discard problematic data.\n\n"
74
"Error messages are sent to stderr.\n";
76
static struct argp_option options[] = {
77
{ "bytecount", 'b', "n", 0,
78
"Number of bytes of random data to output. Set to zero for no limit "
80
{ "config-only", 'c', 0, 0,
81
"Just configure and reset the TRNG" },
82
/* FIXME: options to setup the TRNG */
87
unsigned long int blockstats;
88
uint64_t timedstats; /* microseconds */
90
unsigned long int blockcount;
93
static struct arguments default_arguments = {
100
static error_t parse_opt (int key, char *arg, struct argp_state *state)
102
struct arguments *arguments = state->input;
108
n = strtol(arg, &p, 10);
109
if ((p == arg) || (*p != 0) || (n < 0))
112
arguments->blockcount = n;
118
n = strtol(arg, &p, 10);
119
if ((p == arg) || (*p != 0) || (n < 0))
122
arguments->blockstats = n;
128
n = strtol(arg, &p, 10);
129
if ((p == arg) || (*p != 0) || (n < 0))
132
arguments->timedstats = 1000000ULL * n;
137
arguments->pipemode = 1;
141
return ARGP_ERR_UNKNOWN;
153
/* simple counters */
154
uint64_t bytes_received; /* Bytes read from input */
156
/* performance timers */
157
struct rng_stat source_blockfill; /* Block-receive time */
159
struct timeval progstart; /* Program start time */
162
/* Logic and contexts */
163
static int exitstatus = EXIT_SUCCESS; /* Exit status */
165
/* Command line arguments and processing */
166
struct arguments *arguments = &default_arguments;
167
static struct argp argp = { options, parse_opt, NULL, doc };
170
static volatile int gotsigterm = 0; /* Received SIGTERM/SIGINT */
176
static void sigterm_handler(int sig)
181
static void init_sighandlers(void)
183
struct sigaction action;
185
sigemptyset(&action.sa_mask);
187
action.sa_handler = sigterm_handler;
189
/* Handle SIGTERM and SIGINT the same way */
190
if (sigaction(SIGTERM, &action, NULL) < 0) {
192
"unable to install signal handler for SIGTERM: %s",
196
if (sigaction(SIGINT, &action, NULL) < 0) {
198
"unable to install signal handler for SIGINT: %s",
205
static int xread(void *buf, size_t size)
211
r = read(0, (unsigned char *)buf + off, size);
213
if (gotsigterm) return -1;
214
if ((errno == EAGAIN) || (errno == EINTR)) continue;
217
if (!arguments->pipemode)
219
"%sentropy source exhausted!\n",
225
rng_stats.bytes_received += r;
230
"%serror reading input: %s\n", logprefix,
232
exitstatus = EXIT_IOERR;
238
static int xwrite(void *buf, size_t size)
244
r = write(1, (unsigned char *)buf + off, size);
246
if (gotsigterm) return -1;
247
if ((errno == EAGAIN) || (errno == EINTR)) continue;
251
"%swrite channel stuck\n", logprefix);
252
exitstatus = EXIT_IOERR;
257
rng_stats.bytes_sent += r;
262
"%serror writing to output: %s\n", logprefix,
264
exitstatus = EXIT_IOERR;
271
static void init_rng_stats(void)
273
memset(&rng_stats, 0, sizeof(rng_stats));
274
gettimeofday(&rng_stats.progstart, 0);
275
set_stat_prefix(logprefix);
278
static void dump_rng_stats(void)
284
fprintf(stderr, "%s\n", dump_stat_counter(buf, sizeof(buf),
285
"bits received from input",
286
rng_stats.bytes_received * 8));
287
if (arguments->pipemode)
288
fprintf(stderr, "%s\n", dump_stat_counter(buf, sizeof(buf),
289
"bits sent to output",
290
rng_stats.bytes_sent * 8));
291
fprintf(stderr, "%s\n", dump_stat_counter(buf, sizeof(buf),
292
"FIPS 140-2 successes",
293
rng_stats.good_fips_blocks));
294
fprintf(stderr, "%s\n", dump_stat_counter(buf, sizeof(buf),
295
"FIPS 140-2 failures",
296
rng_stats.bad_fips_blocks));
297
for (j = 0; j < N_FIPS_TESTS; j++)
298
fprintf(stderr, "%s\n", dump_stat_counter(buf, sizeof(buf),
300
rng_stats.fips_failures[j]));
301
fprintf(stderr, "%s\n", dump_stat_bw(buf, sizeof(buf),
302
"input channel speed", "bits",
303
&rng_stats.source_blockfill, FIPS_RNG_BUFFER_SIZE*8));
304
fprintf(stderr, "%s\n", dump_stat_bw(buf, sizeof(buf),
305
"FIPS tests speed", "bits",
306
&rng_stats.fips_blockfill, FIPS_RNG_BUFFER_SIZE*8));
307
if (arguments->pipemode)
308
fprintf(stderr, "%s\n", dump_stat_bw(buf, sizeof(buf),
309
"output channel speed", "bits",
310
&rng_stats.sink_blockfill, FIPS_RNG_BUFFER_SIZE*8));
312
gettimeofday(&now, 0);
313
fprintf(stderr, "%sProgram run time: %" PRIu64 " microseconds\n",
314
logprefix, elapsed_time(&rng_stats.progstart, &now));
317
/* Return 32 bits of bootstrap data */
318
static unsigned int discard_initial_data(void)
320
unsigned char tempbuf[4];
322
/* Do full startup discards when in pipe mode */
323
if (arguments->pipemode)
324
if (xread(tempbuf, sizeof tempbuf)) exit(EXIT_FAIL);
326
/* Bootstrap data for FIPS tests */
327
if (xread(tempbuf, sizeof tempbuf)) exit(EXIT_FAIL);
329
return tempbuf[0] | (tempbuf[1] << 8) |
330
(tempbuf[2] << 16) | (tempbuf[3] << 24);
333
static void do_rng_fips_test_loop( void )
337
struct timeval start, stop, statdump, now;
338
unsigned long int statruns, runs;
341
gettimeofday(&statdump, 0);
342
while (!gotsigterm) {
343
gettimeofday(&start, 0);
344
if (xread(rng_buffer, sizeof(rng_buffer))) return;
345
gettimeofday(&stop, 0);
346
update_usectimer_stat(&rng_stats.source_blockfill,
349
gettimeofday(&start, 0);
350
fips_result = fips_run_rng_test(&fipsctx, &rng_buffer);
351
gettimeofday (&stop, 0);
352
update_usectimer_stat(&rng_stats.fips_blockfill,
356
rng_stats.bad_fips_blocks++;
357
for (j = 0; j < N_FIPS_TESTS; j++)
358
if (fips_result & fips_test_mask[j])
359
rng_stats.fips_failures[j]++;
361
rng_stats.good_fips_blocks++;
362
if (arguments->pipemode) {
363
gettimeofday(&start, 0);
364
if (xwrite(rng_buffer, sizeof(rng_buffer)))
366
gettimeofday (&stop, 0);
367
update_usectimer_stat(
368
&rng_stats.sink_blockfill,
373
if (arguments->blockcount &&
374
(++runs >= arguments->blockcount)) break;
376
gettimeofday(&now, 0);
377
if ((arguments->blockstats &&
378
(++statruns >= arguments->blockstats)) ||
379
(arguments->timedstats &&
380
(elapsed_time(&statdump, &now) > arguments->timedstats))) {
382
gettimeofday(&statdump, 0);
388
int main(int argc, char **argv)
390
argp_parse(&argp, argc, argv, 0, 0, arguments);
392
if (!arguments->pipemode)
393
fprintf(stderr, "%s\n\n",
394
argp_program_version);
398
/* Init data structures */
401
if (!arguments->pipemode)
402
fprintf(stderr, "%sstarting FIPS tests...\n",
405
/* Bootstrap FIPS tests */
406
fips_init(&fipsctx, discard_initial_data());
408
do_rng_fips_test_loop();
412
if ((exitstatus == EXIT_SUCCESS) &&
413
(rng_stats.bad_fips_blocks || !rng_stats.good_fips_blocks)) {
414
exitstatus = EXIT_FAIL;