updated makefiles
[gnutls.git] / lib / nettle / rnd.c
blobc00726ee9c481fd39e3eac9c1be4b726a8cf15ca
1 /*
2 * Copyright (C) 2010-2012 Free Software Foundation, Inc.
3 * Copyright (C) 2000, 2001, 2008 Niels Möller
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GNUTLS.
9 * The GNUTLS library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 3 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>
24 /* Here is the random generator layer. This code was based on the LSH
25 * random generator (the trivia and device source functions for POSIX)
26 * and modified to fit gnutls' needs. Relicenced with permission.
27 * Original author Niels Möller.
30 #include <gnutls_int.h>
31 #include <gnutls_errors.h>
32 #include <locks.h>
33 #include <gnutls_num.h>
34 #include <nettle/yarrow.h>
36 #define SOURCES 2
38 #define RND_LOCK if (gnutls_mutex_lock(&rnd_mutex)!=0) abort()
39 #define RND_UNLOCK if (gnutls_mutex_unlock(&rnd_mutex)!=0) abort()
41 enum
43 RANDOM_SOURCE_TRIVIA = 0,
44 RANDOM_SOURCE_DEVICE,
47 static struct yarrow256_ctx yctx;
48 static struct yarrow_source ysources[SOURCES];
49 static time_t device_last_read = 0;
50 static time_t trivia_time_count = 0;
52 static void *rnd_mutex;
54 #define DEVICE_READ_INTERVAL 1200
56 #ifdef _WIN32
58 #include <windows.h>
59 #include <wincrypt.h>
61 #define DEVICE_READ_SIZE 16
62 #define DEVICE_READ_SIZE_MAX 32
64 static HCRYPTPROV device_fd = 0;
66 static int
67 do_trivia_source (int init)
69 struct
71 FILETIME now;
72 unsigned count;
73 } event;
75 unsigned entropy = 0;
77 GetSystemTimeAsFileTime (&event.now);
78 event.count = 0;
80 if (init)
82 trivia_time_count = 0;
84 else
86 event.count = trivia_time_count++;
87 entropy = 1;
90 return yarrow256_update (&yctx, RANDOM_SOURCE_TRIVIA, entropy,
91 sizeof (event), (const uint8_t *) &event);
94 static int
95 do_device_source (int init)
97 time_t now = gnutls_time (NULL);
98 int read_size = DEVICE_READ_SIZE;
100 if (init)
102 int old;
104 if (!CryptAcquireContext
105 (&device_fd, NULL, NULL, PROV_RSA_FULL,
106 CRYPT_SILENT | CRYPT_VERIFYCONTEXT))
108 _gnutls_debug_log ("error in CryptAcquireContext!\n");
109 return GNUTLS_E_INTERNAL_ERROR;
111 device_last_read = now;
112 read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */
115 if ((device_fd != 0)
116 && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL)))
119 /* More than 20 minutes since we last read the device */
120 uint8_t buf[DEVICE_READ_SIZE_MAX];
122 if (!CryptGenRandom (device_fd, (DWORD) read_size, buf))
124 _gnutls_debug_log ("Error in CryptGenRandom: %s\n",
125 GetLastError ());
126 return GNUTLS_E_INTERNAL_ERROR;
129 device_last_read = now;
130 return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE,
131 read_size * 8 /
132 2 /* we trust the system RNG */ ,
133 read_size, buf);
135 return 0;
138 static void
139 wrap_nettle_rnd_deinit (void *ctx)
141 RND_LOCK;
142 CryptReleaseContext (device_fd, 0);
143 RND_UNLOCK;
145 gnutls_mutex_deinit (&rnd_mutex);
146 rnd_mutex = NULL;
149 #else /* POSIX */
151 #include <time.h>
152 #include <errno.h>
153 #include <sys/types.h>
154 #include <sys/stat.h>
155 #include <sys/time.h>
156 #include <fcntl.h>
157 #include <locks.h>
158 #include <unistd.h> /* getpid */
159 #ifdef HAVE_GETRUSAGE
160 #include <sys/resource.h>
161 #endif
162 #include "egd.h"
164 #define DEVICE_READ_SIZE 16
165 #define DEVICE_READ_SIZE_MAX 32
167 static int device_fd;
168 static time_t trivia_previous_time = 0;
170 static int
171 do_trivia_source (int init)
173 struct
175 struct timeval now;
176 #ifdef HAVE_GETRUSAGE
177 struct rusage rusage;
178 #endif
179 unsigned count;
180 pid_t pid;
181 } event;
183 unsigned entropy = 0;
185 if (gettimeofday (&event.now, NULL) < 0)
187 _gnutls_debug_log ("gettimeofday failed: %s\n", strerror (errno));
188 abort ();
190 #ifdef HAVE_GETRUSAGE
191 if (getrusage (RUSAGE_SELF, &event.rusage) < 0)
193 _gnutls_debug_log ("getrusage failed: %s\n", strerror (errno));
194 abort ();
196 #endif
198 event.count = 0;
199 if (init)
201 trivia_time_count = 0;
203 else
205 event.count = trivia_time_count++;
207 if (event.now.tv_sec != trivia_previous_time)
209 /* Count one bit of entropy if we either have more than two
210 * invocations in one second, or more than two seconds
211 * between invocations. */
212 if ((trivia_time_count > 2)
213 || ((event.now.tv_sec - trivia_previous_time) > 2))
214 entropy++;
216 trivia_time_count = 0;
219 trivia_previous_time = event.now.tv_sec;
220 event.pid = getpid ();
222 return yarrow256_update (&yctx, RANDOM_SOURCE_TRIVIA, entropy,
223 sizeof (event), (const uint8_t *) &event);
226 static int
227 do_device_source_urandom (int init)
229 time_t now = gnutls_time (NULL);
230 unsigned int read_size = DEVICE_READ_SIZE;
232 if (init)
234 int old;
236 device_fd = open ("/dev/urandom", O_RDONLY);
237 if (device_fd < 0)
239 _gnutls_debug_log ("Cannot open urandom!\n");
240 return GNUTLS_E_FILE_ERROR;
243 old = fcntl (device_fd, F_GETFD);
244 fcntl (device_fd, F_SETFD, old | 1);
245 device_last_read = now;
247 read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */
250 if ((device_fd > 0)
251 && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL)))
253 /* More than 20 minutes since we last read the device */
254 uint8_t buf[DEVICE_READ_SIZE_MAX];
255 uint32_t done;
257 for (done = 0; done < read_size;)
259 int res;
261 res = read (device_fd, buf + done, sizeof (buf) - done);
262 while (res < 0 && errno == EINTR);
264 if (res <= 0)
266 if (res < 0)
268 _gnutls_debug_log ("Failed to read /dev/urandom: %s\n",
269 strerror (errno));
271 else
273 _gnutls_debug_log
274 ("Failed to read /dev/urandom: end of file\n");
277 return GNUTLS_E_INTERNAL_ERROR;
280 done += res;
283 device_last_read = now;
284 return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE,
285 read_size * 8 / 2 /* we trust the RNG */ ,
286 read_size, buf);
288 return 0;
291 static int
292 do_device_source_egd (int init)
294 time_t now = gnutls_time (NULL);
295 unsigned int read_size = DEVICE_READ_SIZE;
297 if (init)
299 device_fd = _rndegd_connect_socket ();
300 if (device_fd < 0)
302 _gnutls_debug_log ("Cannot open egd socket!\n");
303 return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
306 device_last_read = now;
308 read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */
311 if ((device_fd > 0)
312 && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL)))
315 /* More than 20 minutes since we last read the device */
316 uint8_t buf[DEVICE_READ_SIZE_MAX];
317 uint32_t done;
319 for (done = 0; done < read_size;)
321 int res;
322 res = _rndegd_read (&device_fd, buf + done, sizeof (buf) - done);
323 if (res <= 0)
325 if (res < 0)
327 _gnutls_debug_log ("Failed to read egd.\n");
329 else
331 _gnutls_debug_log ("Failed to read egd: end of file\n");
334 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
336 done += res;
339 device_last_read = now;
340 return yarrow256_update (&yctx, RANDOM_SOURCE_DEVICE, read_size * 8 / 2,
341 read_size, buf);
343 return 0;
346 static int
347 do_device_source (int init)
349 static pid_t pid; /* detect fork() */
350 int ret, reseed = 0;
351 static int (*do_source) (int init) = NULL;
352 /* using static var here is ok since we are
353 * always called with mutexes down
356 if (init == 1)
358 pid = getpid();
360 do_source = do_device_source_urandom;
361 ret = do_source (init);
362 if (ret < 0)
364 do_source = do_device_source_egd;
365 ret = do_source (init);
368 if (ret < 0)
370 gnutls_assert ();
371 return ret;
374 return ret;
376 else
378 if (getpid() != pid)
379 { /* fork() detected */
380 device_last_read = 0;
381 pid = getpid();
382 reseed = 1;
385 ret = do_source (init);
387 if (reseed)
388 yarrow256_slow_reseed (&yctx);
390 return ret;
395 static void
396 wrap_nettle_rnd_deinit (void *ctx)
398 RND_LOCK;
399 close (device_fd);
400 RND_UNLOCK;
402 gnutls_mutex_deinit (&rnd_mutex);
403 rnd_mutex = NULL;
406 #endif
409 static int
410 wrap_nettle_rnd_init (void **ctx)
412 int ret;
414 ret = gnutls_mutex_init (&rnd_mutex);
415 if (ret < 0)
417 gnutls_assert ();
418 return ret;
421 yarrow256_init (&yctx, SOURCES, ysources);
423 ret = do_device_source (1);
424 if (ret < 0)
426 gnutls_assert ();
427 return ret;
430 ret = do_trivia_source (1);
431 if (ret < 0)
433 gnutls_assert ();
434 return ret;
437 yarrow256_slow_reseed (&yctx);
439 return 0;
443 static int
444 wrap_nettle_rnd (void *_ctx, int level, void *data, size_t datasize)
446 int ret;
448 RND_LOCK;
450 ret = do_trivia_source (0);
451 if (ret < 0)
453 RND_UNLOCK;
454 gnutls_assert ();
455 return ret;
458 ret = do_device_source (0);
459 if (ret < 0)
461 RND_UNLOCK;
462 gnutls_assert ();
463 return ret;
466 yarrow256_random (&yctx, datasize, data);
467 RND_UNLOCK;
468 return 0;
471 int crypto_rnd_prio = INT_MAX;
473 gnutls_crypto_rnd_st _gnutls_rnd_ops = {
474 .init = wrap_nettle_rnd_init,
475 .deinit = wrap_nettle_rnd_deinit,
476 .rnd = wrap_nettle_rnd,