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>
33 #include <gnutls_num.h>
34 #include <nettle/yarrow.h>
38 #define RND_LOCK if (gnutls_mutex_lock(&rnd_mutex)!=0) abort()
39 #define RND_UNLOCK if (gnutls_mutex_unlock(&rnd_mutex)!=0) abort()
43 RANDOM_SOURCE_TRIVIA
= 0,
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
61 #define DEVICE_READ_SIZE 16
62 #define DEVICE_READ_SIZE_MAX 32
64 static HCRYPTPROV device_fd
= 0;
67 do_trivia_source (int init
)
77 GetSystemTimeAsFileTime (&event
.now
);
82 trivia_time_count
= 0;
86 event
.count
= trivia_time_count
++;
90 return yarrow256_update (&yctx
, RANDOM_SOURCE_TRIVIA
, entropy
,
91 sizeof (event
), (const uint8_t *) &event
);
95 do_device_source (int init
)
97 time_t now
= gnutls_time (NULL
);
98 int read_size
= DEVICE_READ_SIZE
;
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 */
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",
126 return GNUTLS_E_INTERNAL_ERROR
;
129 device_last_read
= now
;
130 return yarrow256_update (&yctx
, RANDOM_SOURCE_DEVICE
,
132 2 /* we trust the system RNG */ ,
139 wrap_nettle_rnd_deinit (void *ctx
)
142 CryptReleaseContext (device_fd
, 0);
145 gnutls_mutex_deinit (&rnd_mutex
);
153 #include <sys/types.h>
154 #include <sys/stat.h>
155 #include <sys/time.h>
158 #include <unistd.h> /* getpid */
159 #ifdef HAVE_GETRUSAGE
160 #include <sys/resource.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;
171 do_trivia_source (int init
)
176 #ifdef HAVE_GETRUSAGE
177 struct rusage rusage
;
183 unsigned entropy
= 0;
185 if (gettimeofday (&event
.now
, NULL
) < 0)
187 _gnutls_debug_log ("gettimeofday failed: %s\n", strerror (errno
));
190 #ifdef HAVE_GETRUSAGE
191 if (getrusage (RUSAGE_SELF
, &event
.rusage
) < 0)
193 _gnutls_debug_log ("getrusage failed: %s\n", strerror (errno
));
201 trivia_time_count
= 0;
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))
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
);
227 do_device_source_urandom (int init
)
229 time_t now
= gnutls_time (NULL
);
230 unsigned int read_size
= DEVICE_READ_SIZE
;
236 device_fd
= open ("/dev/urandom", O_RDONLY
);
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 */
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
];
257 for (done
= 0; done
< read_size
;)
261 res
= read (device_fd
, buf
+ done
, sizeof (buf
) - done
);
262 while (res
< 0 && errno
== EINTR
);
268 _gnutls_debug_log ("Failed to read /dev/urandom: %s\n",
274 ("Failed to read /dev/urandom: end of file\n");
277 return GNUTLS_E_INTERNAL_ERROR
;
283 device_last_read
= now
;
284 return yarrow256_update (&yctx
, RANDOM_SOURCE_DEVICE
,
285 read_size
* 8 / 2 /* we trust the RNG */ ,
292 do_device_source_egd (int init
)
294 time_t now
= gnutls_time (NULL
);
295 unsigned int read_size
= DEVICE_READ_SIZE
;
299 device_fd
= _rndegd_connect_socket ();
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 */
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
];
319 for (done
= 0; done
< read_size
;)
322 res
= _rndegd_read (&device_fd
, buf
+ done
, sizeof (buf
) - done
);
327 _gnutls_debug_log ("Failed to read egd.\n");
331 _gnutls_debug_log ("Failed to read egd: end of file\n");
334 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR
);
339 device_last_read
= now
;
340 return yarrow256_update (&yctx
, RANDOM_SOURCE_DEVICE
, read_size
* 8 / 2,
347 do_device_source (int init
)
349 static pid_t pid
; /* detect fork() */
351 static int (*do_source
) (int init
) = NULL
;
352 /* using static var here is ok since we are
353 * always called with mutexes down
360 do_source
= do_device_source_urandom
;
361 ret
= do_source (init
);
364 do_source
= do_device_source_egd
;
365 ret
= do_source (init
);
379 { /* fork() detected */
380 device_last_read
= 0;
385 ret
= do_source (init
);
388 yarrow256_slow_reseed (&yctx
);
396 wrap_nettle_rnd_deinit (void *ctx
)
402 gnutls_mutex_deinit (&rnd_mutex
);
410 wrap_nettle_rnd_init (void **ctx
)
414 ret
= gnutls_mutex_init (&rnd_mutex
);
421 yarrow256_init (&yctx
, SOURCES
, ysources
);
423 ret
= do_device_source (1);
430 ret
= do_trivia_source (1);
437 yarrow256_slow_reseed (&yctx
);
444 wrap_nettle_rnd (void *_ctx
, int level
, void *data
, size_t datasize
)
450 ret
= do_trivia_source (0);
458 ret
= do_device_source (0);
466 yarrow256_random (&yctx
, datasize
, data
);
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
,