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