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