0cb65dfd879b9e8d9d6c7b14c69088e06caa752b
[libgcrypt.git] / random / rndlinux.c
1 /* rndlinux.c  -  raw random number for OSes with /dev/random
2  * Copyright (C) 1998, 2001, 2002, 2003, 2007,
3  *               2009  Free Software Foundation, Inc.
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #ifdef HAVE_GETTIMEOFDAY
30 # include <sys/times.h>
31 #endif
32 #include <string.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include "types.h"
36 #include "g10lib.h"
37 #include "rand-internal.h"
38
39 static int open_device (const char *name, int retry);
40
41
42 static int
43 set_cloexec_flag (int fd)
44 {
45   int oldflags;
46
47   oldflags= fcntl (fd, F_GETFD, 0);
48   if (oldflags < 0)
49     return oldflags;
50   oldflags |= FD_CLOEXEC;
51   return fcntl (fd, F_SETFD, oldflags);
52 }
53
54
55
56 /*
57  * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it
58  * exists)).  If RETRY is true, the function does not terminate with
59  * a fatal error but retries until it is able to reopen the device.
60  */
61 static int
62 open_device (const char *name, int retry)
63 {
64   int fd;
65
66   if (retry)
67     _gcry_random_progress ("open_dev_random", 'X', 1, 0);
68  again:
69   fd = open (name, O_RDONLY);
70   if (fd == -1 && retry)
71     {
72       struct timeval tv;
73
74       tv.tv_sec = 5;
75       tv.tv_usec = 0;
76       _gcry_random_progress ("wait_dev_random", 'X', 0, (int)tv.tv_sec);
77       select (0, NULL, NULL, NULL, &tv);
78       goto again;
79     }
80   if (fd == -1)
81     log_fatal ("can't open %s: %s\n", name, strerror(errno) );
82
83   if (set_cloexec_flag (fd))
84     log_error ("error setting FD_CLOEXEC on fd %d: %s\n",
85                fd, strerror (errno));
86
87   /* We used to do the following check, however it turned out that this
88      is not portable since more OSes provide a random device which is
89      sometimes implemented as another device type.
90
91      struct stat sb;
92
93      if( fstat( fd, &sb ) )
94         log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
95      if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
96         log_fatal("invalid random device!\n" );
97   */
98   return fd;
99 }
100
101
102 /* Note that the caller needs to make sure that this function is only
103    called by one thread at a time.  The function returns 0 on success
104    or true on failure (in which case the caller will signal a fatal
105    error).  */
106 int
107 _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
108                                           enum random_origins),
109                               enum random_origins origin,
110                               size_t length, int level )
111 {
112   static int fd_urandom = -1;
113   static int fd_random = -1;
114   static unsigned char ever_opened;
115   int fd;
116   int n;
117   byte buffer[768];
118   size_t n_hw;
119   size_t want = length;
120   size_t last_so_far = 0;
121   int any_need_entropy = 0;
122   int delay;
123
124   if (!add)
125     {
126       /* Special mode to close the descriptors.  */
127       if (fd_random != -1)
128         {
129           close (fd_random);
130           fd_random = -1;
131         }
132       if (fd_urandom != -1)
133         {
134           close (fd_urandom);
135           fd_urandom = -1;
136         }
137       return 0;
138     }
139
140
141   /* First read from a hardware source.  However let it account only
142      for up to 50% (or 25% for RDRAND) of the requested bytes.  */
143   n_hw = _gcry_rndhw_poll_slow (add, origin);
144   if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND))
145     {
146       if (n_hw > length/4)
147         n_hw = length/4;
148     }
149   else
150     {
151       if (n_hw > length/2)
152         n_hw = length/2;
153     }
154   if (length > 1)
155     length -= n_hw;
156
157   /* Open the requested device.  The first time a device is to be
158      opened we fail with a fatal error if the device does not exists.
159      In case the device has ever been closed, further open requests
160      will however retry indefinitely.  The rationale for this behaviour is
161      that we always require the device to be existent but want a more
162      graceful behaviour if the rarely needed close operation has been
163      used and the device needs to be re-opened later. */
164   if (level >= 2)
165     {
166       if (fd_random == -1)
167         {
168           fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1));
169           ever_opened |= 1;
170         }
171       fd = fd_random;
172     }
173   else
174     {
175       if (fd_urandom == -1)
176         {
177           fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2));
178           ever_opened |= 2;
179         }
180       fd = fd_urandom;
181     }
182
183   /* Enter the read loop.  */
184   delay = 0;  /* Start with 0 seconds so that we do no block on the
185                  first iteration and in turn call the progress function
186                  before blocking.  To give the OS a better chance to
187                  return with something we will actually use 100ms. */
188   while (length)
189     {
190       fd_set rfds;
191       struct timeval tv;
192       int rc;
193
194       /* If we collected some bytes update the progress indicator.  We
195          do this always and not just if the select timed out because
196          often just a few bytes are gathered within the timeout
197          period.  */
198       if (any_need_entropy || last_so_far != (want - length) )
199         {
200           last_so_far = want - length;
201           _gcry_random_progress ("need_entropy", 'X',
202                                  (int)last_so_far, (int)want);
203           any_need_entropy = 1;
204         }
205
206       /* If the system has no limit on the number of file descriptors
207          and we encounter an fd which is larger than the fd_set size,
208          we don't use the select at all.  The select code is only used
209          to emit progress messages.  A better solution would be to
210          fall back to poll() if available.  */
211 #ifdef FD_SETSIZE
212       if (fd < FD_SETSIZE)
213 #endif
214         {
215           FD_ZERO(&rfds);
216           FD_SET(fd, &rfds);
217           tv.tv_sec = delay;
218           tv.tv_usec = delay? 0 : 100000;
219           if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) )
220             {
221               any_need_entropy = 1;
222               delay = 3; /* Use 3 seconds henceforth.  */
223               continue;
224             }
225           else if( rc == -1 )
226             {
227               log_error ("select() error: %s\n", strerror(errno));
228               if (!delay)
229                 delay = 1; /* Use 1 second if we encounter an error before
230                               we have ever blocked.  */
231               continue;
232             }
233         }
234
235       do
236         {
237           size_t nbytes;
238
239           nbytes = length < sizeof(buffer)? length : sizeof(buffer);
240           n = read (fd, buffer, nbytes);
241           if (n >= 0 && n > nbytes)
242             {
243               log_error("bogus read from random device (n=%d)\n", n );
244               n = nbytes;
245             }
246         }
247       while (n == -1 && errno == EINTR);
248       if  (n == -1)
249         log_fatal("read error on random device: %s\n", strerror(errno));
250       (*add)(buffer, n, origin);
251       length -= n;
252     }
253   wipememory (buffer, sizeof buffer);
254
255   if (any_need_entropy)
256     _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want);
257
258   return 0; /* success */
259 }