hwfeatures: add 'all' for disabling all hardware features
[libgcrypt.git] / tests / random.c
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 #ifndef DIM
38 # define DIM(v)              (sizeof(v)/sizeof((v)[0]))
39 #endif
40
41
42 static int verbose;
43 static int debug;
44 static int with_progress;
45
46 /* If we have a decent libgpg-error we can use some gcc attributes.  */
47 #ifdef GPGRT_ATTR_NORETURN
48 static void die (const char *format, ...) GPGRT_ATTR_NR_PRINTF(1,2);
49 static void inf (const char *format, ...) GPGRT_ATTR_PRINTF(1,2);
50 #endif /*GPGRT_ATTR_NORETURN*/
51
52
53 static void
54 die (const char *format, ...)
55 {
56   va_list arg_ptr;
57
58   va_start (arg_ptr, format);
59   fputs ( PGM ": ", stderr);
60   vfprintf (stderr, format, arg_ptr);
61   va_end (arg_ptr);
62   exit (1);
63 }
64
65
66 static void
67 inf (const char *format, ...)
68 {
69   va_list arg_ptr;
70
71   va_start (arg_ptr, format);
72   fputs ( PGM ": ", stderr);
73   vfprintf (stderr, format, arg_ptr);
74   va_end (arg_ptr);
75 }
76
77
78 static void
79 print_hex (const char *text, const void *buf, size_t n)
80 {
81   const unsigned char *p = buf;
82
83   inf ("%s", text);
84   for (; n; n--, p++)
85     fprintf (stderr, "%02X", *p);
86   putc ('\n', stderr);
87 }
88
89
90 static void
91 progress_cb (void *cb_data, const char *what, int printchar,
92              int current, int total)
93 {
94   (void)cb_data;
95
96   inf ("progress (%s %c %d %d)\n", what, printchar, current, total);
97   fflush (stderr);
98 }
99
100
101 #ifndef HAVE_W32_SYSTEM
102 static int
103 writen (int fd, const void *buf, size_t nbytes)
104 {
105   size_t nleft = nbytes;
106   int nwritten;
107
108   while (nleft > 0)
109     {
110       nwritten = write (fd, buf, nleft);
111       if (nwritten < 0)
112         {
113           if (errno == EINTR)
114             nwritten = 0;
115           else
116             return -1;
117         }
118       nleft -= nwritten;
119       buf = (const char*)buf + nwritten;
120     }
121
122   return 0;
123 }
124 #endif /*!HAVE_W32_SYSTEM*/
125
126
127 #ifndef HAVE_W32_SYSTEM
128 static int
129 readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
130 {
131   size_t nleft = buflen;
132   int nread;
133
134   while ( nleft > 0 )
135     {
136       nread = read ( fd, buf, nleft );
137       if (nread < 0)
138         {
139           if (nread == EINTR)
140             nread = 0;
141           else
142             return -1;
143         }
144       else if (!nread)
145         break; /* EOF */
146       nleft -= nread;
147       buf = (char*)buf + nread;
148     }
149   if (ret_nread)
150     *ret_nread = buflen - nleft;
151   return 0;
152 }
153 #endif /*!HAVE_W32_SYSTEM*/
154
155
156 /* Check that forking won't return the same random. */
157 static void
158 check_forking (void)
159 {
160 #ifdef HAVE_W32_SYSTEM
161   if (verbose)
162     inf ("check_forking skipped: not applicable on Windows\n");
163 #else /*!HAVE_W32_SYSTEM*/
164   pid_t pid;
165   int rp[2];
166   int i, status;
167   size_t nread;
168   char tmp1[16], tmp1c[16], tmp1p[16];
169
170   if (verbose)
171     inf ("checking that a fork won't cause the same random output\n");
172
173   /* We better make sure that the RNG has been initialzied. */
174   gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
175   if (verbose)
176     print_hex ("initial random: ", tmp1, sizeof tmp1);
177
178   if (pipe (rp) == -1)
179     die ("pipe failed: %s\n", strerror (errno));
180
181   pid = fork ();
182   if (pid == (pid_t)(-1))
183     die ("fork failed: %s\n", strerror (errno));
184   if (!pid)
185     {
186       gcry_randomize (tmp1c, sizeof tmp1c, GCRY_STRONG_RANDOM);
187       if (writen (rp[1], tmp1c, sizeof tmp1c))
188         die ("write failed: %s\n", strerror (errno));
189       if (verbose)
190         {
191           print_hex ("  child random: ", tmp1c, sizeof tmp1c);
192           fflush (stdout);
193         }
194       _exit (0);
195     }
196   gcry_randomize (tmp1p, sizeof tmp1p, GCRY_STRONG_RANDOM);
197   if (verbose)
198     print_hex (" parent random: ", tmp1p, sizeof tmp1p);
199
200   close (rp[1]);
201   if (readn (rp[0], tmp1c, sizeof tmp1c, &nread))
202     die ("read failed: %s\n", strerror (errno));
203   if (nread != sizeof tmp1c)
204     die ("read too short\n");
205
206   while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
207     ;
208   if (i != (pid_t)(-1)
209       && WIFEXITED (status) && !WEXITSTATUS (status))
210     ;
211   else
212     die ("child failed\n");
213
214   if (!memcmp (tmp1p, tmp1c, sizeof tmp1c))
215     die ("parent and child got the same random number\n");
216 #endif  /*!HAVE_W32_SYSTEM*/
217 }
218
219
220
221 /* Check that forking won't return the same nonce. */
222 static void
223 check_nonce_forking (void)
224 {
225 #ifdef HAVE_W32_SYSTEM
226   if (verbose)
227     inf ("check_nonce_forking skipped: not applicable on Windows\n");
228 #else /*!HAVE_W32_SYSTEM*/
229   pid_t pid;
230   int rp[2];
231   int i, status;
232   size_t nread;
233   char nonce1[10], nonce1c[10], nonce1p[10];
234
235   if (verbose)
236     inf ("checking that a fork won't cause the same nonce output\n");
237
238   /* We won't get the same nonce back if we never initialized the
239      nonce subsystem, thus we get one nonce here and forget about
240      it. */
241   gcry_create_nonce (nonce1, sizeof nonce1);
242   if (verbose)
243     print_hex ("initial nonce: ", nonce1, sizeof nonce1);
244
245   if (pipe (rp) == -1)
246     die ("pipe failed: %s\n", strerror (errno));
247
248   pid = fork ();
249   if (pid == (pid_t)(-1))
250     die ("fork failed: %s\n", strerror (errno));
251   if (!pid)
252     {
253       gcry_create_nonce (nonce1c, sizeof nonce1c);
254       if (writen (rp[1], nonce1c, sizeof nonce1c))
255         die ("write failed: %s\n", strerror (errno));
256       if (verbose)
257         {
258           print_hex ("  child nonce: ", nonce1c, sizeof nonce1c);
259           fflush (stdout);
260         }
261       _exit (0);
262     }
263   gcry_create_nonce (nonce1p, sizeof nonce1p);
264   if (verbose)
265     print_hex (" parent nonce: ", nonce1p, sizeof nonce1p);
266
267   close (rp[1]);
268   if (readn (rp[0], nonce1c, sizeof nonce1c, &nread))
269     die ("read failed: %s\n", strerror (errno));
270   if (nread != sizeof nonce1c)
271     die ("read too short\n");
272
273   while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
274     ;
275   if (i != (pid_t)(-1)
276       && WIFEXITED (status) && !WEXITSTATUS (status))
277     ;
278   else
279     die ("child failed\n");
280
281   if (!memcmp (nonce1p, nonce1c, sizeof nonce1c))
282     die ("parent and child got the same nonce\n");
283 #endif  /*!HAVE_W32_SYSTEM*/
284 }
285
286
287 /* Check that a closed random device os re-opened if needed. */
288 static void
289 check_close_random_device (void)
290 {
291 #ifdef HAVE_W32_SYSTEM
292   if (verbose)
293     inf ("check_close_random_device skipped: not applicable on Windows\n");
294 #else /*!HAVE_W32_SYSTEM*/
295   pid_t pid;
296   int i, status;
297   char buf[4];
298
299   if (verbose)
300     inf ("checking that close_random_device works\n");
301
302   gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM);
303   if (verbose)
304     print_hex ("parent random: ", buf, sizeof buf);
305
306   pid = fork ();
307   if (pid == (pid_t)(-1))
308     die ("fork failed: %s\n", strerror (errno));
309   if (!pid)
310     {
311       gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0);
312
313       /* The next call will re-open the device.  */
314       gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM);
315       if (verbose)
316         {
317           print_hex ("child random : ", buf, sizeof buf);
318           fflush (stdout);
319         }
320       _exit (0);
321     }
322
323   while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
324     ;
325   if (i != (pid_t)(-1)
326       && WIFEXITED (status) && !WEXITSTATUS (status))
327     ;
328   else
329     die ("child failed\n");
330
331 #endif  /*!HAVE_W32_SYSTEM*/
332 }
333
334
335 static int
336 rng_type (void)
337 {
338   int rngtype;
339   if (gcry_control (GCRYCTL_GET_CURRENT_RNG_TYPE, &rngtype))
340     die ("retrieving RNG type failed\n");
341   return rngtype;
342 }
343
344
345 static void
346 check_rng_type_switching (void)
347 {
348   int rngtype, initial;
349   char tmp1[4];
350
351   if (verbose)
352     inf ("checking whether RNG type switching works\n");
353
354   rngtype = rng_type ();
355   if (debug)
356     inf ("rng type: %d\n", rngtype);
357   initial = rngtype;
358   gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
359   if (debug)
360     print_hex ("  sample: ", tmp1, sizeof tmp1);
361   if (rngtype != rng_type ())
362     die ("RNG type unexpectedly changed\n");
363
364   gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
365
366   rngtype = rng_type ();
367   if (debug)
368     inf ("rng type: %d\n", rngtype);
369   if (rngtype != initial)
370     die ("switching to System RNG unexpectedly succeeded\n");
371   gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
372   if (debug)
373     print_hex ("  sample: ", tmp1, sizeof tmp1);
374   if (rngtype != rng_type ())
375     die ("RNG type unexpectedly changed\n");
376
377   gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
378
379   rngtype = rng_type ();
380   if (debug)
381     inf ("rng type: %d\n", rngtype);
382   if (rngtype != initial)
383     die ("switching to FIPS RNG unexpectedly succeeded\n");
384   gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
385   if (debug)
386     print_hex ("  sample: ", tmp1, sizeof tmp1);
387   if (rngtype != rng_type ())
388     die ("RNG type unexpectedly changed\n");
389
390   gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
391
392   rngtype = rng_type ();
393   if (debug)
394     inf ("rng type: %d\n", rngtype);
395   if (rngtype != GCRY_RNG_TYPE_STANDARD)
396     die ("switching to standard RNG failed\n");
397   gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
398   if (debug)
399     print_hex ("  sample: ", tmp1, sizeof tmp1);
400   if (rngtype != rng_type ())
401     die ("RNG type unexpectedly changed\n");
402 }
403
404
405 static void
406 check_early_rng_type_switching (void)
407 {
408   int rngtype, initial;
409
410   if (verbose)
411     inf ("checking whether RNG type switching works in the early stage\n");
412
413   rngtype = rng_type ();
414   if (debug)
415     inf ("rng type: %d\n", rngtype);
416   initial = rngtype;
417
418   gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
419
420   rngtype = rng_type ();
421   if (debug)
422     inf ("rng type: %d\n", rngtype);
423   if (initial >= GCRY_RNG_TYPE_SYSTEM && rngtype != GCRY_RNG_TYPE_SYSTEM)
424     die ("switching to System RNG failed\n");
425
426   gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
427
428   rngtype = rng_type ();
429   if (debug)
430     inf ("rng type: %d\n", rngtype);
431   if (initial >= GCRY_RNG_TYPE_FIPS && rngtype != GCRY_RNG_TYPE_FIPS)
432     die ("switching to FIPS RNG failed\n");
433
434   gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
435
436   rngtype = rng_type ();
437   if (debug)
438     inf ("rng type: %d\n", rngtype);
439   if (rngtype != GCRY_RNG_TYPE_STANDARD)
440     die ("switching to standard RNG failed\n");
441 }
442
443
444 static void
445 check_drbg_reinit (void)
446 {
447   static struct { const char *flags; } tv[] = {
448     { NULL },
449     { "" },
450     { "sha1" },
451     { "sha1 pr" },
452     { "sha256" },
453     { "sha256 pr" },
454     { "sha512" },
455     { "sha512 pr" },
456     { "hmac sha1" },
457     { "hmac sha1 pr" },
458     { "hmac sha256" },
459     { "hmac sha256 pr" },
460     { "hmac sha512" },
461     { "hmac sha512 pr" },
462     { "aes sym128" },
463     { "aes sym128 pr" },
464     { "aes sym192" },
465     { "aes sym192 pr" },
466     { "aes sym256" },
467     { "aes sym256 pr" }
468   };
469   int tidx;
470   gpg_error_t err;
471   char pers_string[] = "I'm a doctor, not an engineer.";
472   gcry_buffer_t pers[1];
473
474   if (verbose)
475     inf ("checking DRBG_REINIT\n");
476
477   memset (pers, 0, sizeof pers);
478   pers[0].data = pers_string;
479   pers[0].len = strlen (pers_string);
480
481   err = gcry_control (GCRYCTL_DRBG_REINIT, "", NULL, 0, &err);
482   if (gpg_err_code (err) != GPG_ERR_INV_ARG)
483     die ("gcry_control(DRBG_REINIT) guard value did not work\n");
484
485   err = gcry_control (GCRYCTL_DRBG_REINIT, "", NULL, -1, NULL);
486   if (gpg_err_code (err) != GPG_ERR_INV_ARG)
487     die ("gcry_control(DRBG_REINIT) npers negative detection failed\n");
488
489   if (rng_type () != GCRY_RNG_TYPE_FIPS)
490     {
491       err = gcry_control (GCRYCTL_DRBG_REINIT, "", NULL, 0, NULL);
492       if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
493         die ("DRBG_REINIT worked despite that DRBG is not active\n");
494       return;
495     }
496
497   err = gcry_control (GCRYCTL_DRBG_REINIT, "", NULL, 1, NULL);
498   if (gpg_err_code (err) != GPG_ERR_INV_ARG)
499     die ("_gcry_rngdrbg_reinit failed to detact: (!pers && npers)\n");
500   err = gcry_control (GCRYCTL_DRBG_REINIT, "", pers, 2, NULL);
501   if (gpg_err_code (err) != GPG_ERR_INV_ARG)
502     die ("_gcry_rngdrbg_reinit failed to detect: (pers && npers != 1)\n");
503
504   err = gcry_control (GCRYCTL_DRBG_REINIT, "aes sym128 bad pr ", pers, 1, NULL);
505   if (gpg_err_code (err) != GPG_ERR_INV_FLAG)
506     die ("_gcry_rngdrbg_reinit failed to detect a bad flag\n");
507
508   for (tidx=0; tidx < DIM(tv); tidx++)
509     {
510       err = gcry_control (GCRYCTL_DRBG_REINIT, tv[tidx].flags, NULL, 0, NULL);
511       if (err)
512         die ("_gcry_rngdrbg_reinit failed for \"%s\" w/o pers: %s\n",
513
514              tv[tidx].flags, gpg_strerror (err));
515       err = gcry_control (GCRYCTL_DRBG_REINIT, tv[tidx].flags, pers, 1, NULL);
516       if (err)
517         die ("_gcry_rngdrbg_reinit failed for \"%s\" with pers: %s\n",
518              tv[tidx].flags, gpg_strerror (err));
519       /* fixme: We should extract some random after each test.  */
520     }
521 }
522
523
524 /* Because we want to check initialization behaviour, we need to
525    fork/exec this program with several command line arguments.  We use
526    system, so that these tests work also on Windows.  */
527 static void
528 run_all_rng_tests (const char *program)
529 {
530   static const char *options[] = {
531     "--early-rng-check",
532     "--early-rng-check --prefer-standard-rng",
533     "--early-rng-check --prefer-fips-rng",
534     "--early-rng-check --prefer-system-rng",
535     "--prefer-standard-rng",
536     "--prefer-fips-rng",
537     "--prefer-system-rng",
538     NULL
539   };
540   int idx;
541   size_t len, maxlen;
542   char *cmdline;
543
544   maxlen = 0;
545   for (idx=0; options[idx]; idx++)
546     {
547       len = strlen (options[idx]);
548       if (len > maxlen)
549         maxlen = len;
550     }
551   maxlen += strlen (program);
552   maxlen += strlen (" --in-recursion --verbose --debug --progress");
553   maxlen++;
554   cmdline = malloc (maxlen + 1);
555   if (!cmdline)
556     die ("out of core\n");
557
558   for (idx=0; options[idx]; idx++)
559     {
560       if (verbose)
561         inf ("now running with options '%s'\n", options[idx]);
562       strcpy (cmdline, program);
563       strcat (cmdline, " --in-recursion");
564       if (verbose)
565         strcat (cmdline, " --verbose");
566       if (debug)
567         strcat (cmdline, " --debug");
568       if (with_progress)
569         strcat (cmdline, " --progress");
570       strcat (cmdline, " ");
571       strcat (cmdline, options[idx]);
572       if (system (cmdline))
573         die ("running '%s' failed\n", cmdline);
574     }
575
576   free (cmdline);
577 }
578
579 int
580 main (int argc, char **argv)
581 {
582   int last_argc = -1;
583   int early_rng = 0;
584   int in_recursion = 0;
585   const char *program = NULL;
586
587   if (argc)
588     {
589       program = *argv;
590       argc--; argv++;
591     }
592   else
593     die ("argv[0] missing\n");
594
595   while (argc && last_argc != argc )
596     {
597       last_argc = argc;
598       if (!strcmp (*argv, "--"))
599         {
600           argc--; argv++;
601           break;
602         }
603       else if (!strcmp (*argv, "--help"))
604         {
605           fputs ("usage: random [options]\n", stdout);
606           exit (0);
607         }
608       else if (!strcmp (*argv, "--verbose"))
609         {
610           verbose = 1;
611           argc--; argv++;
612         }
613       else if (!strcmp (*argv, "--debug"))
614         {
615           debug = verbose = 1;
616           argc--; argv++;
617         }
618       else if (!strcmp (*argv, "--progress"))
619         {
620           argc--; argv++;
621           with_progress = 1;
622         }
623       else if (!strcmp (*argv, "--in-recursion"))
624         {
625           in_recursion = 1;
626           argc--; argv++;
627         }
628       else if (!strcmp (*argv, "--early-rng-check"))
629         {
630           early_rng = 1;
631           argc--; argv++;
632         }
633       else if (!strcmp (*argv, "--prefer-standard-rng"))
634         {
635           /* This is anyway the default, but we may want to use it for
636              debugging. */
637           gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
638           argc--; argv++;
639         }
640       else if (!strcmp (*argv, "--prefer-fips-rng"))
641         {
642           gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
643           argc--; argv++;
644         }
645       else if (!strcmp (*argv, "--prefer-system-rng"))
646         {
647           gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
648           argc--; argv++;
649         }
650     }
651
652 #ifndef HAVE_W32_SYSTEM
653   signal (SIGPIPE, SIG_IGN);
654 #endif
655
656   if (early_rng)
657     {
658       /* Don't switch RNG in fips mode. */
659       if (!gcry_fips_mode_active())
660         check_early_rng_type_switching ();
661     }
662
663   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
664   if (!gcry_check_version (GCRYPT_VERSION))
665     die ("version mismatch\n");
666
667   if (with_progress)
668     gcry_set_progress_handler (progress_cb, NULL);
669
670   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
671   if (debug)
672     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
673
674   if (!in_recursion)
675     {
676       check_forking ();
677       check_nonce_forking ();
678       check_close_random_device ();
679     }
680   /* For now we do not run the drgb_reinit check from "make check" due
681      to its high requirement for entropy.  */
682   if (!getenv ("GCRYPT_IN_REGRESSION_TEST"))
683     check_drbg_reinit ();
684
685   /* Don't switch RNG in fips mode.  */
686   if (!gcry_fips_mode_active())
687     check_rng_type_switching ();
688
689   if (!in_recursion)
690     run_all_rng_tests (program);
691
692   return 0;
693 }