Line data Source code
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 18 : set_cloexec_flag (int fd)
44 : {
45 : int oldflags;
46 :
47 18 : oldflags= fcntl (fd, F_GETFD, 0);
48 18 : if (oldflags < 0)
49 0 : return oldflags;
50 18 : oldflags |= FD_CLOEXEC;
51 18 : 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 18 : open_device (const char *name, int retry)
63 : {
64 : int fd;
65 :
66 18 : if (retry)
67 0 : _gcry_random_progress ("open_dev_random", 'X', 1, 0);
68 : again:
69 18 : fd = open (name, O_RDONLY);
70 18 : if (fd == -1 && retry)
71 : {
72 : struct timeval tv;
73 :
74 0 : tv.tv_sec = 5;
75 0 : tv.tv_usec = 0;
76 0 : _gcry_random_progress ("wait_dev_random", 'X', 0, (int)tv.tv_sec);
77 0 : select (0, NULL, NULL, NULL, &tv);
78 0 : goto again;
79 : }
80 18 : if (fd == -1)
81 0 : log_fatal ("can't open %s: %s\n", name, strerror(errno) );
82 :
83 18 : if (set_cloexec_flag (fd))
84 0 : log_error ("error setting FD_CLOEXEC on fd %d: %s\n",
85 0 : 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 18 : 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 430 : _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 430 : size_t want = length;
120 430 : size_t last_so_far = 0;
121 430 : int any_need_entropy = 0;
122 : int delay;
123 :
124 430 : if (!add)
125 : {
126 : /* Special mode to close the descriptors. */
127 0 : if (fd_random != -1)
128 : {
129 0 : close (fd_random);
130 0 : fd_random = -1;
131 : }
132 0 : if (fd_urandom != -1)
133 : {
134 0 : close (fd_urandom);
135 0 : fd_urandom = -1;
136 : }
137 0 : return 0;
138 : }
139 :
140 :
141 : /* First read from a hardware source. However let it account only
142 : for up to 50% of the requested bytes. */
143 430 : n_hw = _gcry_rndhw_poll_slow (add, origin);
144 430 : if (n_hw > length/2)
145 0 : n_hw = length/2;
146 430 : if (length > 1)
147 430 : length -= n_hw;
148 :
149 : /* Open the requested device. The first time a device is to be
150 : opened we fail with a fatal error if the device does not exists.
151 : In case the device has ever been closed, further open requests
152 : will however retry indefinitely. The rationale for this behaviour is
153 : that we always require the device to be existent but want a more
154 : graceful behaviour if the rarely needed close operation has been
155 : used and the device needs to be re-opened later. */
156 430 : if (level >= 2)
157 : {
158 2 : if (fd_random == -1)
159 : {
160 1 : fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1));
161 1 : ever_opened |= 1;
162 : }
163 2 : fd = fd_random;
164 : }
165 : else
166 : {
167 428 : if (fd_urandom == -1)
168 : {
169 17 : fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2));
170 17 : ever_opened |= 2;
171 : }
172 428 : fd = fd_urandom;
173 : }
174 :
175 : /* Enter the read loop. */
176 430 : delay = 0; /* Start with 0 seconds so that we do no block on the
177 : first iteration and in turn call the progress function
178 : before blocking. To give the OS a better chance to
179 : return with something we will actually use 100ms. */
180 1290 : while (length)
181 : {
182 : fd_set rfds;
183 : struct timeval tv;
184 : int rc;
185 :
186 : /* If we collected some bytes update the progress indicator. We
187 : do this always and not just if the select timed out because
188 : often just a few bytes are gathered within the timeout
189 : period. */
190 430 : if (any_need_entropy || last_so_far != (want - length) )
191 : {
192 0 : last_so_far = want - length;
193 0 : _gcry_random_progress ("need_entropy", 'X',
194 : (int)last_so_far, (int)want);
195 0 : any_need_entropy = 1;
196 : }
197 :
198 : /* If the system has no limit on the number of file descriptors
199 : and we encounter an fd which is larger than the fd_set size,
200 : we don't use the select at all. The select code is only used
201 : to emit progress messages. A better solution would be to
202 : fall back to poll() if available. */
203 : #ifdef FD_SETSIZE
204 430 : if (fd < FD_SETSIZE)
205 : #endif
206 : {
207 430 : FD_ZERO(&rfds);
208 430 : FD_SET(fd, &rfds);
209 430 : tv.tv_sec = delay;
210 430 : tv.tv_usec = delay? 0 : 100000;
211 430 : if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) )
212 : {
213 0 : any_need_entropy = 1;
214 0 : delay = 3; /* Use 3 seconds henceforth. */
215 0 : continue;
216 : }
217 430 : else if( rc == -1 )
218 : {
219 0 : log_error ("select() error: %s\n", strerror(errno));
220 0 : if (!delay)
221 0 : delay = 1; /* Use 1 second if we encounter an error before
222 : we have ever blocked. */
223 0 : continue;
224 : }
225 : }
226 :
227 : do
228 : {
229 : size_t nbytes;
230 :
231 430 : nbytes = length < sizeof(buffer)? length : sizeof(buffer);
232 430 : n = read (fd, buffer, nbytes);
233 430 : if (n >= 0 && n > nbytes)
234 : {
235 0 : log_error("bogus read from random device (n=%d)\n", n );
236 0 : n = nbytes;
237 : }
238 : }
239 430 : while (n == -1 && errno == EINTR);
240 430 : if (n == -1)
241 0 : log_fatal("read error on random device: %s\n", strerror(errno));
242 430 : (*add)(buffer, n, origin);
243 430 : length -= n;
244 : }
245 430 : wipememory (buffer, sizeof buffer);
246 :
247 430 : if (any_need_entropy)
248 0 : _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want);
249 :
250 430 : return 0; /* success */
251 : }
|