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#include <signal.h>
28#include <unistd.h>
29#include <sys/wait.h>
30
31#include "../src/gcrypt.h"
32
33static int verbose;
34
35static void
36die (const char *format, ...)
37{
38  va_list arg_ptr;
39
40  va_start (arg_ptr, format);
41  vfprintf (stderr, format, arg_ptr);
42  va_end (arg_ptr);
43  exit (1);
44}
45
46
47static void
48print_hex (const char *text, const void *buf, size_t n)
49{
50  const unsigned char *p = buf;
51
52  fputs (text, stdout);
53  for (; n; n--, p++)
54    printf ("%02X", *p);
55  putchar ('\n');
56}
57
58
59static int
60writen (int fd, const void *buf, size_t nbytes)
61{
62  size_t nleft = nbytes;
63  int nwritten;
64
65  while (nleft > 0)
66    {
67      nwritten = write (fd, buf, nleft);
68      if (nwritten < 0)
69        {
70          if (errno == EINTR)
71            nwritten = 0;
72          else
73            return -1;
74        }
75      nleft -= nwritten;
76      buf = (const char*)buf + nwritten;
77    }
78
79  return 0;
80}
81
82static int
83readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
84{
85  size_t nleft = buflen;
86  int nread;
87
88  while ( nleft > 0 )
89    {
90      nread = read ( fd, buf, nleft );
91      if (nread < 0)
92        {
93          if (nread == EINTR)
94            nread = 0;
95          else
96            return -1;
97        }
98      else if (!nread)
99        break; /* EOF */
100      nleft -= nread;
101      buf = (char*)buf + nread;
102    }
103  if (ret_nread)
104    *ret_nread = buflen - nleft;
105  return 0;
106}
107
108
109
110/* Check that forking won't return the same random. */
111static void
112check_forking (void)
113{
114  pid_t pid;
115  int rp[2];
116  int i, status;
117  size_t nread;
118  char tmp1[16], tmp1c[16], tmp1p[16];
119
120  /* We better make sure that the RNG has been initialzied. */
121  gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
122  if (verbose)
123    print_hex ("initial random: ", tmp1, sizeof tmp1);
124
125  if (pipe (rp) == -1)
126    die ("pipe failed: %s\n", strerror (errno));
127
128  pid = fork ();
129  if (pid == (pid_t)(-1))
130    die ("fork failed: %s\n", strerror (errno));
131  if (!pid)
132    {
133      gcry_randomize (tmp1c, sizeof tmp1c, GCRY_STRONG_RANDOM);
134      if (writen (rp[1], tmp1c, sizeof tmp1c))
135        die ("write failed: %s\n", strerror (errno));
136      if (verbose)
137        {
138          print_hex ("  child random: ", tmp1c, sizeof tmp1c);
139          fflush (stdout);
140        }
141      _exit (0);
142    }
143  gcry_randomize (tmp1p, sizeof tmp1p, GCRY_STRONG_RANDOM);
144  if (verbose)
145    print_hex (" parent random: ", tmp1p, sizeof tmp1p);
146
147  close (rp[1]);
148  if (readn (rp[0], tmp1c, sizeof tmp1c, &nread))
149    die ("read failed: %s\n", strerror (errno));
150  if (nread != sizeof tmp1c)
151    die ("read too short\n");
152
153  while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
154    ;
155  if (i != (pid_t)(-1)
156      && WIFEXITED (status) && !WEXITSTATUS (status))
157    ;
158  else
159    die ("child failed\n");
160
161  if (!memcmp (tmp1p, tmp1c, sizeof tmp1c))
162    die ("parent and child got the same random number\n");
163}
164
165
166
167/* Check that forking won't return the same nonce. */
168static void
169check_nonce_forking (void)
170{
171  pid_t pid;
172  int rp[2];
173  int i, status;
174  size_t nread;
175  char nonce1[10], nonce1c[10], nonce1p[10];
176
177  /* We won't get the same nonce back if we never initialized the
178     nonce subsystem, thus we get one nonce here and forget about
179     it. */
180  gcry_create_nonce (nonce1, sizeof nonce1);
181  if (verbose)
182    print_hex ("initial nonce: ", nonce1, sizeof nonce1);
183
184  if (pipe (rp) == -1)
185    die ("pipe failed: %s\n", strerror (errno));
186
187  pid = fork ();
188  if (pid == (pid_t)(-1))
189    die ("fork failed: %s\n", strerror (errno));
190  if (!pid)
191    {
192      gcry_create_nonce (nonce1c, sizeof nonce1c);
193      if (writen (rp[1], nonce1c, sizeof nonce1c))
194        die ("write failed: %s\n", strerror (errno));
195      if (verbose)
196        {
197          print_hex ("  child nonce: ", nonce1c, sizeof nonce1c);
198          fflush (stdout);
199        }
200      _exit (0);
201    }
202  gcry_create_nonce (nonce1p, sizeof nonce1p);
203  if (verbose)
204    print_hex (" parent nonce: ", nonce1p, sizeof nonce1p);
205
206  close (rp[1]);
207  if (readn (rp[0], nonce1c, sizeof nonce1c, &nread))
208    die ("read failed: %s\n", strerror (errno));
209  if (nread != sizeof nonce1c)
210    die ("read too short\n");
211
212  while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
213    ;
214  if (i != (pid_t)(-1)
215      && WIFEXITED (status) && !WEXITSTATUS (status))
216    ;
217  else
218    die ("child failed\n");
219
220  if (!memcmp (nonce1p, nonce1c, sizeof nonce1c))
221    die ("parent and child got the same nonce\n");
222}
223
224
225
226
227
228
229int
230main (int argc, char **argv)
231{
232  int debug = 0;
233
234  if ((argc > 1) && (! strcmp (argv[1], "--verbose")))
235    verbose = 1;
236  else if ((argc > 1) && (! strcmp (argv[1], "--debug")))
237    verbose = debug = 1;
238
239  signal (SIGPIPE, SIG_IGN);
240
241  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
242  if (!gcry_check_version (GCRYPT_VERSION))
243    die ("version mismatch\n");
244
245  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
246  if (debug)
247    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
248
249  check_forking ();
250  check_nonce_forking ();
251
252  return 0;
253}
254