~ubuntu-branches/ubuntu/vivid/rng-tools/vivid

« back to all changes in this revision

Viewing changes to viapadlock-rng.c

  • Committer: Package Import Robot
  • Author(s): Tim Gardner
  • Date: 2013-08-13 13:12:05 UTC
  • mfrom: (1.2.5)
  • Revision ID: package-import@ubuntu.com-20130813131205-rxv50a9sgze6ya6o
Tags: 4-0ubuntu1
Merge from upstream git://git.kernel.org/pub/scm/utils/kernel/rng-tools/rng-tools.git
908d733527a361621da88cdf931a71aa83cba430
-LP: #1084378

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * viapadlock-rng.c -- VIA PadLock TRNG access/setup utility
3
 
 *
4
 
 * Accesses the VIA PadLock True RNG for setup and reading of
5
 
 * random bytes (does not peform any FIPS testing).
6
 
 * 
7
 
 * Copyright (C) 2005 Henrique de Moraes Holschuh <hmh@debian.org>
8
 
 *
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.
13
 
 * 
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.
18
 
 *
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
22
 
 */
23
 
 
24
 
#define _GNU_SOURCE
25
 
 
26
 
#ifndef HAVE_CONFIG_H
27
 
#error Invalid or missing autoconf build environment
28
 
#endif
29
 
 
30
 
#include "rng-tools-config.h"
31
 
 
32
 
/* For printf types macros (PRIu64) */
33
 
#define __STDC_FORMAT_MACROS
34
 
 
35
 
#include <unistd.h>
36
 
#include <stdint.h>
37
 
#include <inttypes.h>
38
 
#include <stdio.h>
39
 
#include <stdlib.h>
40
 
#include <sys/time.h>
41
 
#include <time.h>
42
 
#include <string.h>
43
 
#include <argp.h>
44
 
#include <signal.h>
45
 
 
46
 
#include "viapadlock_engine.h"
47
 
#include "stats.h"
48
 
#include "exits.h"
49
 
#include "util.h"
50
 
 
51
 
#define PROGNAME "viapadlock-rng"
52
 
const char* logprefix = PROGNAME ": ";
53
 
 
54
 
/*
55
 
 * argp stuff
56
 
 */
57
 
 
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.";
64
 
 
65
 
const char *argp_program_bug_address = PACKAGE_BUGREPORT;
66
 
error_t argp_err_exit_status = EXIT_USAGE;
67
 
 
68
 
static char doc[] =
69
 
        "Setup and read the VIA PadLock True Random Number Generator.\n"
70
 
        "\v"
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";
75
 
 
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 "
79
 
          "(default: 0)" },
80
 
        { "config-only", 'c', 0, 0,
81
 
          "Just configure and reset the TRNG" },
82
 
        /* FIXME: options to setup the TRNG */
83
 
        { 0 },
84
 
};
85
 
 
86
 
struct arguments {
87
 
        unsigned long int blockstats;
88
 
        uint64_t timedstats;            /* microseconds */
89
 
        int pipemode;
90
 
        unsigned long int blockcount;
91
 
};
92
 
 
93
 
static struct arguments default_arguments = {
94
 
        .blockstats     = 0,
95
 
        .timedstats     = 0,
96
 
        .pipemode       = 0,
97
 
        .blockcount     = 0,
98
 
};
99
 
 
100
 
static error_t parse_opt (int key, char *arg, struct argp_state *state)
101
 
{
102
 
        struct arguments *arguments = state->input;
103
 
        
104
 
        switch(key) {
105
 
        case 'c': {
106
 
                long int n;
107
 
                char *p;
108
 
                n = strtol(arg, &p, 10);
109
 
                if ((p == arg) || (*p != 0) || (n < 0))
110
 
                        argp_usage(state);
111
 
                else
112
 
                        arguments->blockcount = n;
113
 
                break;
114
 
        }
115
 
        case 'b': {
116
 
                long int n;
117
 
                char *p;
118
 
                n = strtol(arg, &p, 10);
119
 
                if ((p == arg) || (*p != 0) || (n < 0))
120
 
                        argp_usage(state);
121
 
                else
122
 
                        arguments->blockstats = n;
123
 
                break;
124
 
        }
125
 
        case 't': {
126
 
                long int n;
127
 
                char *p;
128
 
                n = strtol(arg, &p, 10);
129
 
                if ((p == arg) || (*p != 0) || (n < 0))
130
 
                        argp_usage(state);
131
 
                else
132
 
                        arguments->timedstats = 1000000ULL * n;
133
 
                break;
134
 
        }
135
 
 
136
 
        case 'p':
137
 
                arguments->pipemode = 1;
138
 
                break;
139
 
 
140
 
        default:
141
 
                return ARGP_ERR_UNKNOWN;
142
 
        }
143
 
 
144
 
        return 0;
145
 
}
146
 
 
147
 
/*
148
 
 * Globals
149
 
 */
150
 
 
151
 
/* Statistics */
152
 
struct {
153
 
        /* simple counters */
154
 
        uint64_t bytes_received;        /* Bytes read from input */
155
 
 
156
 
        /* performance timers */
157
 
        struct rng_stat source_blockfill;       /* Block-receive time */
158
 
 
159
 
        struct timeval progstart;       /* Program start time */
160
 
} rng_stats;
161
 
 
162
 
/* Logic and contexts */
163
 
static int exitstatus = EXIT_SUCCESS;   /* Exit status */
164
 
 
165
 
/* Command line arguments and processing */
166
 
struct arguments *arguments = &default_arguments;
167
 
static struct argp argp = { options, parse_opt, NULL, doc };
168
 
 
169
 
/* signals */
170
 
static volatile int gotsigterm = 0;     /* Received SIGTERM/SIGINT */
171
 
 
172
 
 
173
 
/*
174
 
 * Signal handling
175
 
 */
176
 
static void sigterm_handler(int sig)
177
 
{
178
 
        gotsigterm = sig;
179
 
}
180
 
 
181
 
static void init_sighandlers(void)
182
 
{
183
 
        struct sigaction action;
184
 
 
185
 
        sigemptyset(&action.sa_mask);
186
 
        action.sa_flags = 0;
187
 
        action.sa_handler = sigterm_handler;
188
 
 
189
 
        /* Handle SIGTERM and SIGINT the same way */
190
 
        if (sigaction(SIGTERM, &action, NULL) < 0) {
191
 
                fprintf(stderr, 
192
 
                        "unable to install signal handler for SIGTERM: %s",
193
 
                        strerror(errno));
194
 
                exit(EXIT_OSERR);
195
 
        }
196
 
        if (sigaction(SIGINT, &action, NULL) < 0) {
197
 
                fprintf(stderr,
198
 
                        "unable to install signal handler for SIGINT: %s",
199
 
                        strerror(errno));
200
 
                exit(EXIT_OSERR);
201
 
        }
202
 
}
203
 
 
204
 
 
205
 
static int xread(void *buf, size_t size)
206
 
{
207
 
        size_t off = 0;
208
 
        ssize_t r;
209
 
 
210
 
        while (size) {
211
 
                r = read(0, (unsigned char *)buf + off, size);
212
 
                if (r < 0) {
213
 
                        if (gotsigterm) return -1;
214
 
                        if ((errno == EAGAIN) || (errno == EINTR)) continue;
215
 
                        break;
216
 
                } else if (!r) {
217
 
                        if (!arguments->pipemode)
218
 
                                fprintf(stderr, 
219
 
                                        "%sentropy source exhausted!\n", 
220
 
                                        logprefix);
221
 
                        return -1;
222
 
                }
223
 
                off += r;
224
 
                size -= r;
225
 
                rng_stats.bytes_received += r;
226
 
        }
227
 
 
228
 
        if (size) {
229
 
                fprintf(stderr,
230
 
                        "%serror reading input: %s\n", logprefix,
231
 
                        strerror(errno));
232
 
                exitstatus = EXIT_IOERR;
233
 
                return -1;
234
 
        }
235
 
        return 0;
236
 
}
237
 
 
238
 
static int xwrite(void *buf, size_t size)
239
 
{
240
 
        size_t off = 0;
241
 
        ssize_t r;
242
 
 
243
 
        while (size) {
244
 
                r = write(1, (unsigned char *)buf + off, size);
245
 
                if (r < 0) {
246
 
                        if (gotsigterm) return -1;
247
 
                        if ((errno == EAGAIN) || (errno == EINTR)) continue;
248
 
                        break;
249
 
                } else if (!r) {
250
 
                        fprintf(stderr, 
251
 
                                "%swrite channel stuck\n", logprefix);
252
 
                        exitstatus = EXIT_IOERR;
253
 
                        return -1;
254
 
                }
255
 
                off += r;
256
 
                size -= r;
257
 
                rng_stats.bytes_sent += r;
258
 
        }
259
 
 
260
 
        if (size) {
261
 
                fprintf(stderr,
262
 
                        "%serror writing to output: %s\n", logprefix,
263
 
                        strerror(errno));
264
 
                exitstatus = EXIT_IOERR;
265
 
                return -1;
266
 
        }
267
 
        return 0;
268
 
}
269
 
 
270
 
 
271
 
static void init_rng_stats(void)
272
 
{
273
 
        memset(&rng_stats, 0, sizeof(rng_stats));
274
 
        gettimeofday(&rng_stats.progstart, 0);
275
 
        set_stat_prefix(logprefix);
276
 
}
277
 
 
278
 
static void dump_rng_stats(void)
279
 
{
280
 
        int j;
281
 
        char buf[256];
282
 
        struct timeval now;
283
 
 
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),
299
 
                                        fips_test_names[j],
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));
311
 
 
312
 
        gettimeofday(&now, 0);
313
 
        fprintf(stderr, "%sProgram run time: %" PRIu64 " microseconds\n",
314
 
                logprefix, elapsed_time(&rng_stats.progstart, &now));
315
 
}
316
 
 
317
 
/* Return 32 bits of bootstrap data */
318
 
static unsigned int discard_initial_data(void)
319
 
{
320
 
        unsigned char tempbuf[4];
321
 
 
322
 
        /* Do full startup discards when in pipe mode */
323
 
        if (arguments->pipemode)
324
 
                if (xread(tempbuf, sizeof tempbuf)) exit(EXIT_FAIL);
325
 
 
326
 
        /* Bootstrap data for FIPS tests */
327
 
        if (xread(tempbuf, sizeof tempbuf)) exit(EXIT_FAIL);
328
 
 
329
 
        return tempbuf[0] | (tempbuf[1] << 8) | 
330
 
                (tempbuf[2] << 16) | (tempbuf[3] << 24);
331
 
}
332
 
 
333
 
static void do_rng_fips_test_loop( void )
334
 
{
335
 
        int j;
336
 
        int fips_result;
337
 
        struct timeval start, stop, statdump, now;
338
 
        unsigned long int statruns, runs;
339
 
 
340
 
        runs = statruns = 0;
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, 
347
 
                                &start, &stop);
348
 
 
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,
353
 
                                &start, &stop);
354
 
 
355
 
                if (fips_result) {
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]++;
360
 
                } else {
361
 
                        rng_stats.good_fips_blocks++;
362
 
                        if (arguments->pipemode) {
363
 
                                gettimeofday(&start, 0);
364
 
                                if (xwrite(rng_buffer, sizeof(rng_buffer)))
365
 
                                        return;
366
 
                                gettimeofday (&stop, 0);
367
 
                                update_usectimer_stat(
368
 
                                        &rng_stats.sink_blockfill,
369
 
                                        &start, &stop);
370
 
                        }
371
 
                }
372
 
 
373
 
                if (arguments->blockcount &&
374
 
                    (++runs >= arguments->blockcount)) break;
375
 
 
376
 
                gettimeofday(&now, 0);
377
 
                if ((arguments->blockstats && 
378
 
                     (++statruns >= arguments->blockstats)) ||
379
 
                    (arguments->timedstats &&
380
 
                     (elapsed_time(&statdump, &now) > arguments->timedstats))) {
381
 
                        dump_rng_stats();
382
 
                        gettimeofday(&statdump, 0);
383
 
                        statruns = 0;
384
 
                }
385
 
        }
386
 
}
387
 
 
388
 
int main(int argc, char **argv)
389
 
{
390
 
        argp_parse(&argp, argc, argv, 0, 0, arguments);
391
 
 
392
 
        if (!arguments->pipemode)
393
 
                fprintf(stderr, "%s\n\n",
394
 
                        argp_program_version);
395
 
 
396
 
        init_sighandlers();
397
 
 
398
 
        /* Init data structures */
399
 
        init_rng_stats();
400
 
 
401
 
        if (!arguments->pipemode)
402
 
                fprintf(stderr, "%sstarting FIPS tests...\n",
403
 
                        logprefix);
404
 
 
405
 
        /* Bootstrap FIPS tests */
406
 
        fips_init(&fipsctx, discard_initial_data());
407
 
 
408
 
        do_rng_fips_test_loop();
409
 
        
410
 
        dump_rng_stats();
411
 
 
412
 
        if ((exitstatus == EXIT_SUCCESS) && 
413
 
            (rng_stats.bad_fips_blocks || !rng_stats.good_fips_blocks)) {
414
 
                exitstatus = EXIT_FAIL;
415
 
        }
416
 
 
417
 
        exit(exitstatus);
418
 
}