Line data Source code
1 : /* random.c - part of the Libgcrypt test suite.
2 : Copyright (C) 2005 Free Software Foundation, Inc.
3 :
4 : This program is free software; you can redistribute it and/or
5 : modify it under the terms of the GNU General Public License as
6 : published by the Free Software Foundation; either version 2 of the
7 : License, or (at your option) any later version.
8 :
9 : This program is distributed in the hope that it will be useful, but
10 : WITHOUT ANY WARRANTY; without even the implied warranty of
11 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : General Public License for more details.
13 :
14 : You should have received a copy of the GNU General Public License
15 : along with this program; if not, write to the Free Software
16 : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 : USA. */
18 :
19 : #ifdef HAVE_CONFIG_H
20 : #include <config.h>
21 : #endif
22 : #include <assert.h>
23 : #include <stdio.h>
24 : #include <string.h>
25 : #include <stdlib.h>
26 : #include <errno.h>
27 : #ifndef HAVE_W32_SYSTEM
28 : # include <signal.h>
29 : # include <unistd.h>
30 : # include <sys/wait.h>
31 : #endif
32 :
33 : #include "../src/gcrypt-int.h"
34 :
35 : #define PGM "random"
36 :
37 :
38 : static int verbose;
39 : static int debug;
40 : static int with_progress;
41 :
42 : static void
43 0 : die (const char *format, ...)
44 : {
45 : va_list arg_ptr;
46 :
47 0 : va_start (arg_ptr, format);
48 0 : fputs ( PGM ": ", stderr);
49 0 : vfprintf (stderr, format, arg_ptr);
50 0 : va_end (arg_ptr);
51 0 : exit (1);
52 : }
53 :
54 :
55 : static void
56 0 : inf (const char *format, ...)
57 : {
58 : va_list arg_ptr;
59 :
60 0 : va_start (arg_ptr, format);
61 0 : fputs ( PGM ": ", stderr);
62 0 : vfprintf (stderr, format, arg_ptr);
63 0 : va_end (arg_ptr);
64 0 : }
65 :
66 :
67 : static void
68 0 : print_hex (const char *text, const void *buf, size_t n)
69 : {
70 0 : const unsigned char *p = buf;
71 :
72 0 : inf ("%s", text);
73 0 : for (; n; n--, p++)
74 0 : fprintf (stderr, "%02X", *p);
75 0 : putc ('\n', stderr);
76 0 : }
77 :
78 :
79 : static void
80 0 : progress_cb (void *cb_data, const char *what, int printchar,
81 : int current, int total)
82 : {
83 : (void)cb_data;
84 :
85 0 : inf ("progress (%s %c %d %d)\n", what, printchar, current, total);
86 0 : fflush (stderr);
87 0 : }
88 :
89 :
90 : #ifndef HAVE_W32_SYSTEM
91 : static int
92 0 : writen (int fd, const void *buf, size_t nbytes)
93 : {
94 0 : size_t nleft = nbytes;
95 : int nwritten;
96 :
97 0 : while (nleft > 0)
98 : {
99 0 : nwritten = write (fd, buf, nleft);
100 0 : if (nwritten < 0)
101 : {
102 0 : if (errno == EINTR)
103 0 : nwritten = 0;
104 : else
105 0 : return -1;
106 : }
107 0 : nleft -= nwritten;
108 0 : buf = (const char*)buf + nwritten;
109 : }
110 :
111 0 : return 0;
112 : }
113 : #endif /*!HAVE_W32_SYSTEM*/
114 :
115 :
116 : #ifndef HAVE_W32_SYSTEM
117 : static int
118 2 : readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
119 : {
120 2 : size_t nleft = buflen;
121 : int nread;
122 :
123 6 : while ( nleft > 0 )
124 : {
125 2 : nread = read ( fd, buf, nleft );
126 2 : if (nread < 0)
127 : {
128 0 : if (nread == EINTR)
129 0 : nread = 0;
130 : else
131 0 : return -1;
132 : }
133 2 : else if (!nread)
134 0 : break; /* EOF */
135 2 : nleft -= nread;
136 2 : buf = (char*)buf + nread;
137 : }
138 2 : if (ret_nread)
139 2 : *ret_nread = buflen - nleft;
140 2 : return 0;
141 : }
142 : #endif /*!HAVE_W32_SYSTEM*/
143 :
144 :
145 : /* Check that forking won't return the same random. */
146 : static void
147 1 : check_forking (void)
148 : {
149 : #ifdef HAVE_W32_SYSTEM
150 : if (verbose)
151 : inf ("check_forking skipped: not applicable on Windows\n");
152 : #else /*!HAVE_W32_SYSTEM*/
153 : pid_t pid;
154 : int rp[2];
155 : int i, status;
156 : size_t nread;
157 : char tmp1[16], tmp1c[16], tmp1p[16];
158 :
159 1 : if (verbose)
160 0 : inf ("checking that a fork won't cause the same random output\n");
161 :
162 : /* We better make sure that the RNG has been initialzied. */
163 1 : gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
164 1 : if (verbose)
165 0 : print_hex ("initial random: ", tmp1, sizeof tmp1);
166 :
167 1 : if (pipe (rp) == -1)
168 0 : die ("pipe failed: %s\n", strerror (errno));
169 :
170 1 : pid = fork ();
171 1 : if (pid == (pid_t)(-1))
172 0 : die ("fork failed: %s\n", strerror (errno));
173 1 : if (!pid)
174 : {
175 0 : gcry_randomize (tmp1c, sizeof tmp1c, GCRY_STRONG_RANDOM);
176 0 : if (writen (rp[1], tmp1c, sizeof tmp1c))
177 0 : die ("write failed: %s\n", strerror (errno));
178 0 : if (verbose)
179 : {
180 0 : print_hex (" child random: ", tmp1c, sizeof tmp1c);
181 0 : fflush (stdout);
182 : }
183 0 : _exit (0);
184 : }
185 1 : gcry_randomize (tmp1p, sizeof tmp1p, GCRY_STRONG_RANDOM);
186 1 : if (verbose)
187 0 : print_hex (" parent random: ", tmp1p, sizeof tmp1p);
188 :
189 1 : close (rp[1]);
190 1 : if (readn (rp[0], tmp1c, sizeof tmp1c, &nread))
191 0 : die ("read failed: %s\n", strerror (errno));
192 1 : if (nread != sizeof tmp1c)
193 0 : die ("read too short\n");
194 :
195 1 : while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
196 : ;
197 1 : if (i != (pid_t)(-1)
198 1 : && WIFEXITED (status) && !WEXITSTATUS (status))
199 : ;
200 : else
201 0 : die ("child failed\n");
202 :
203 1 : if (!memcmp (tmp1p, tmp1c, sizeof tmp1c))
204 0 : die ("parent and child got the same random number\n");
205 : #endif /*!HAVE_W32_SYSTEM*/
206 1 : }
207 :
208 :
209 :
210 : /* Check that forking won't return the same nonce. */
211 : static void
212 1 : check_nonce_forking (void)
213 : {
214 : #ifdef HAVE_W32_SYSTEM
215 : if (verbose)
216 : inf ("check_nonce_forking skipped: not applicable on Windows\n");
217 : #else /*!HAVE_W32_SYSTEM*/
218 : pid_t pid;
219 : int rp[2];
220 : int i, status;
221 : size_t nread;
222 : char nonce1[10], nonce1c[10], nonce1p[10];
223 :
224 1 : if (verbose)
225 0 : inf ("checking that a fork won't cause the same nonce output\n");
226 :
227 : /* We won't get the same nonce back if we never initialized the
228 : nonce subsystem, thus we get one nonce here and forget about
229 : it. */
230 1 : gcry_create_nonce (nonce1, sizeof nonce1);
231 1 : if (verbose)
232 0 : print_hex ("initial nonce: ", nonce1, sizeof nonce1);
233 :
234 1 : if (pipe (rp) == -1)
235 0 : die ("pipe failed: %s\n", strerror (errno));
236 :
237 1 : pid = fork ();
238 1 : if (pid == (pid_t)(-1))
239 0 : die ("fork failed: %s\n", strerror (errno));
240 1 : if (!pid)
241 : {
242 0 : gcry_create_nonce (nonce1c, sizeof nonce1c);
243 0 : if (writen (rp[1], nonce1c, sizeof nonce1c))
244 0 : die ("write failed: %s\n", strerror (errno));
245 0 : if (verbose)
246 : {
247 0 : print_hex (" child nonce: ", nonce1c, sizeof nonce1c);
248 0 : fflush (stdout);
249 : }
250 0 : _exit (0);
251 : }
252 1 : gcry_create_nonce (nonce1p, sizeof nonce1p);
253 1 : if (verbose)
254 0 : print_hex (" parent nonce: ", nonce1p, sizeof nonce1p);
255 :
256 1 : close (rp[1]);
257 1 : if (readn (rp[0], nonce1c, sizeof nonce1c, &nread))
258 0 : die ("read failed: %s\n", strerror (errno));
259 1 : if (nread != sizeof nonce1c)
260 0 : die ("read too short\n");
261 :
262 1 : while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
263 : ;
264 1 : if (i != (pid_t)(-1)
265 1 : && WIFEXITED (status) && !WEXITSTATUS (status))
266 : ;
267 : else
268 0 : die ("child failed\n");
269 :
270 1 : if (!memcmp (nonce1p, nonce1c, sizeof nonce1c))
271 0 : die ("parent and child got the same nonce\n");
272 : #endif /*!HAVE_W32_SYSTEM*/
273 1 : }
274 :
275 :
276 : /* Check that a closed random device os re-opened if needed. */
277 : static void
278 1 : check_close_random_device (void)
279 : {
280 : #ifdef HAVE_W32_SYSTEM
281 : if (verbose)
282 : inf ("check_close_random_device skipped: not applicable on Windows\n");
283 : #else /*!HAVE_W32_SYSTEM*/
284 : pid_t pid;
285 : int i, status;
286 : char buf[4];
287 :
288 1 : if (verbose)
289 0 : inf ("checking that close_random_device works\n");
290 :
291 1 : gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM);
292 1 : if (verbose)
293 0 : print_hex ("parent random: ", buf, sizeof buf);
294 :
295 1 : pid = fork ();
296 1 : if (pid == (pid_t)(-1))
297 0 : die ("fork failed: %s\n", strerror (errno));
298 1 : if (!pid)
299 : {
300 0 : gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
301 :
302 : /* The next call will re-open the device. */
303 0 : gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM);
304 0 : if (verbose)
305 : {
306 0 : print_hex ("child random : ", buf, sizeof buf);
307 0 : fflush (stdout);
308 : }
309 0 : _exit (0);
310 : }
311 :
312 1 : while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
313 : ;
314 1 : if (i != (pid_t)(-1)
315 1 : && WIFEXITED (status) && !WEXITSTATUS (status))
316 : ;
317 : else
318 0 : die ("child failed\n");
319 :
320 : #endif /*!HAVE_W32_SYSTEM*/
321 1 : }
322 :
323 :
324 : static int
325 80 : rng_type (void)
326 : {
327 : int rngtype;
328 80 : if (gcry_control (GCRYCTL_GET_CURRENT_RNG_TYPE, &rngtype))
329 0 : die ("retrieving RNG type failed\n");
330 80 : return rngtype;
331 : }
332 :
333 :
334 : static void
335 8 : check_rng_type_switching (void)
336 : {
337 : int rngtype, initial;
338 : char tmp1[4];
339 :
340 8 : if (verbose)
341 0 : inf ("checking whether RNG type switching works\n");
342 :
343 8 : rngtype = rng_type ();
344 8 : if (debug)
345 0 : inf ("rng type: %d\n", rngtype);
346 8 : initial = rngtype;
347 8 : gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
348 8 : if (debug)
349 0 : print_hex (" sample: ", tmp1, sizeof tmp1);
350 8 : if (rngtype != rng_type ())
351 0 : die ("RNG type unexpectedly changed\n");
352 :
353 8 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
354 :
355 8 : rngtype = rng_type ();
356 8 : if (debug)
357 0 : inf ("rng type: %d\n", rngtype);
358 8 : if (rngtype != initial)
359 0 : die ("switching to System RNG unexpectedly succeeded\n");
360 8 : gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
361 8 : if (debug)
362 0 : print_hex (" sample: ", tmp1, sizeof tmp1);
363 8 : if (rngtype != rng_type ())
364 0 : die ("RNG type unexpectedly changed\n");
365 :
366 8 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
367 :
368 8 : rngtype = rng_type ();
369 8 : if (debug)
370 0 : inf ("rng type: %d\n", rngtype);
371 8 : if (rngtype != initial)
372 0 : die ("switching to FIPS RNG unexpectedly succeeded\n");
373 8 : gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
374 8 : if (debug)
375 0 : print_hex (" sample: ", tmp1, sizeof tmp1);
376 8 : if (rngtype != rng_type ())
377 0 : die ("RNG type unexpectedly changed\n");
378 :
379 8 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
380 :
381 8 : rngtype = rng_type ();
382 8 : if (debug)
383 0 : inf ("rng type: %d\n", rngtype);
384 8 : if (rngtype != GCRY_RNG_TYPE_STANDARD)
385 0 : die ("switching to standard RNG failed\n");
386 8 : gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
387 8 : if (debug)
388 0 : print_hex (" sample: ", tmp1, sizeof tmp1);
389 8 : if (rngtype != rng_type ())
390 0 : die ("RNG type unexpectedly changed\n");
391 8 : }
392 :
393 :
394 : static void
395 4 : check_early_rng_type_switching (void)
396 : {
397 : int rngtype, initial;
398 :
399 4 : if (verbose)
400 0 : inf ("checking whether RNG type switching works in the early stage\n");
401 :
402 4 : rngtype = rng_type ();
403 4 : if (debug)
404 0 : inf ("rng type: %d\n", rngtype);
405 4 : initial = rngtype;
406 :
407 4 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
408 :
409 4 : rngtype = rng_type ();
410 4 : if (debug)
411 0 : inf ("rng type: %d\n", rngtype);
412 4 : if (initial >= GCRY_RNG_TYPE_SYSTEM && rngtype != GCRY_RNG_TYPE_SYSTEM)
413 0 : die ("switching to System RNG failed\n");
414 :
415 4 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
416 :
417 4 : rngtype = rng_type ();
418 4 : if (debug)
419 0 : inf ("rng type: %d\n", rngtype);
420 4 : if (initial >= GCRY_RNG_TYPE_FIPS && rngtype != GCRY_RNG_TYPE_FIPS)
421 0 : die ("switching to FIPS RNG failed\n");
422 :
423 4 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
424 :
425 4 : rngtype = rng_type ();
426 4 : if (debug)
427 0 : inf ("rng type: %d\n", rngtype);
428 4 : if (rngtype != GCRY_RNG_TYPE_STANDARD)
429 0 : die ("switching to standard RNG failed\n");
430 4 : }
431 :
432 :
433 : /* Because we want to check initialization behaviour, we need to
434 : fork/exec this program with several command line arguments. We use
435 : system, so that these tests work also on Windows. */
436 : static void
437 1 : run_all_rng_tests (const char *program)
438 : {
439 : static const char *options[] = {
440 : "--early-rng-check",
441 : "--early-rng-check --prefer-standard-rng",
442 : "--early-rng-check --prefer-fips-rng",
443 : "--early-rng-check --prefer-system-rng",
444 : "--prefer-standard-rng",
445 : "--prefer-fips-rng",
446 : "--prefer-system-rng",
447 : NULL
448 : };
449 : int idx;
450 : size_t len, maxlen;
451 : char *cmdline;
452 :
453 1 : maxlen = 0;
454 8 : for (idx=0; options[idx]; idx++)
455 : {
456 7 : len = strlen (options[idx]);
457 7 : if (len > maxlen)
458 2 : maxlen = len;
459 : }
460 1 : maxlen += strlen (program);
461 1 : maxlen += strlen (" --in-recursion --verbose --debug --progress");
462 1 : maxlen++;
463 1 : cmdline = malloc (maxlen + 1);
464 1 : if (!cmdline)
465 0 : die ("out of core\n");
466 :
467 8 : for (idx=0; options[idx]; idx++)
468 : {
469 7 : if (verbose)
470 0 : inf ("now running with options '%s'\n", options[idx]);
471 7 : strcpy (cmdline, program);
472 7 : strcat (cmdline, " --in-recursion");
473 7 : if (verbose)
474 0 : strcat (cmdline, " --verbose");
475 7 : if (debug)
476 0 : strcat (cmdline, " --debug");
477 7 : if (with_progress)
478 0 : strcat (cmdline, " --progress");
479 7 : strcat (cmdline, " ");
480 7 : strcat (cmdline, options[idx]);
481 7 : if (system (cmdline))
482 0 : die ("running '%s' failed\n", cmdline);
483 : }
484 :
485 1 : free (cmdline);
486 1 : }
487 :
488 : int
489 8 : main (int argc, char **argv)
490 : {
491 8 : int last_argc = -1;
492 8 : int early_rng = 0;
493 8 : int in_recursion = 0;
494 8 : const char *program = NULL;
495 :
496 8 : if (argc)
497 : {
498 8 : program = *argv;
499 8 : argc--; argv++;
500 : }
501 : else
502 0 : die ("argv[0] missing\n");
503 :
504 33 : while (argc && last_argc != argc )
505 : {
506 17 : last_argc = argc;
507 17 : if (!strcmp (*argv, "--"))
508 : {
509 0 : argc--; argv++;
510 0 : break;
511 : }
512 17 : else if (!strcmp (*argv, "--help"))
513 : {
514 0 : fputs ("usage: random [options]\n", stdout);
515 0 : exit (0);
516 : }
517 17 : else if (!strcmp (*argv, "--verbose"))
518 : {
519 0 : verbose = 1;
520 0 : argc--; argv++;
521 : }
522 17 : else if (!strcmp (*argv, "--debug"))
523 : {
524 0 : debug = verbose = 1;
525 0 : argc--; argv++;
526 : }
527 17 : else if (!strcmp (*argv, "--progress"))
528 : {
529 0 : argc--; argv++;
530 0 : with_progress = 1;
531 : }
532 17 : else if (!strcmp (*argv, "--in-recursion"))
533 : {
534 7 : in_recursion = 1;
535 7 : argc--; argv++;
536 : }
537 10 : else if (!strcmp (*argv, "--early-rng-check"))
538 : {
539 4 : early_rng = 1;
540 4 : argc--; argv++;
541 : }
542 6 : else if (!strcmp (*argv, "--prefer-standard-rng"))
543 : {
544 : /* This is anyway the default, but we may want to use it for
545 : debugging. */
546 2 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
547 2 : argc--; argv++;
548 : }
549 4 : else if (!strcmp (*argv, "--prefer-fips-rng"))
550 : {
551 2 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
552 2 : argc--; argv++;
553 : }
554 2 : else if (!strcmp (*argv, "--prefer-system-rng"))
555 : {
556 2 : gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
557 2 : argc--; argv++;
558 : }
559 : }
560 :
561 : #ifndef HAVE_W32_SYSTEM
562 8 : signal (SIGPIPE, SIG_IGN);
563 : #endif
564 :
565 8 : if (early_rng)
566 4 : check_early_rng_type_switching ();
567 :
568 8 : gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
569 8 : if (!gcry_check_version (GCRYPT_VERSION))
570 0 : die ("version mismatch\n");
571 :
572 8 : if (with_progress)
573 0 : gcry_set_progress_handler (progress_cb, NULL);
574 :
575 8 : gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
576 8 : if (debug)
577 0 : gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
578 :
579 8 : if (!in_recursion)
580 : {
581 1 : check_forking ();
582 1 : check_nonce_forking ();
583 1 : check_close_random_device ();
584 : }
585 8 : check_rng_type_switching ();
586 :
587 8 : if (!in_recursion)
588 1 : run_all_rng_tests (program);
589 :
590 8 : return 0;
591 : }
|