]> andersk Git - openssh.git/blame - entropy.c
- Fix from Andre Lucas <andre.lucas@dial.pipex.com>
[openssh.git] / entropy.c
CommitLineData
bfc9a610 1/*
2 * Copyright (c) 2000 Damien Miller. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "includes.h"
31
32#include "ssh.h"
33#include "xmalloc.h"
34
35484284 35#include <openssl/rand.h>
36#include <openssl/sha.h>
bfc9a610 37
38RCSID("$Id$");
39
40#ifdef EGD_SOCKET
41#ifndef offsetof
42# define offsetof(type, member) ((size_t) &((type *)0)->member)
43#endif
44/* Collect entropy from EGD */
45void get_random_bytes(unsigned char *buf, int len)
46{
47 static int egd_socket = -1;
48 int c;
49 char egd_message[2] = { 0x02, 0x00 };
50 struct sockaddr_un addr;
51 int addr_len;
52
53 memset(&addr, '\0', sizeof(addr));
54 addr.sun_family = AF_UNIX;
55
56 /* FIXME: compile time check? */
57 if (sizeof(EGD_SOCKET) > sizeof(addr.sun_path))
58 fatal("Random pool path is too long");
59
60 strcpy(addr.sun_path, EGD_SOCKET);
61
62 addr_len = offsetof(struct sockaddr_un, sun_path) + sizeof(EGD_SOCKET);
63
64 if (egd_socket == -1) {
65 egd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
66 if (egd_socket == -1)
67 fatal("Couldn't create AF_UNIX socket: %s", strerror(errno));
68 if (connect(egd_socket, (struct sockaddr*)&addr, addr_len) == -1)
69 fatal("Couldn't connect to EGD socket \"%s\": %s", addr.sun_path, strerror(errno));
70 }
71
72 if (len > 255)
73 fatal("Too many bytes to read from EGD");
74
75 /* Send blocking read request to EGD */
76 egd_message[1] = len;
77
78 c = atomicio(write, egd_socket, egd_message, sizeof(egd_message));
79 if (c == -1)
80 fatal("Couldn't write to EGD socket \"%s\": %s", EGD_SOCKET, strerror(errno));
81
82 c = atomicio(read, egd_socket, buf, len);
83 if (c <= 0)
84 fatal("Couldn't read from EGD socket \"%s\": %s", EGD_SOCKET, strerror(errno));
85
86 close(EGD_SOCKET);
87}
88#else /* !EGD_SOCKET */
89#ifdef RANDOM_POOL
90/* Collect entropy from /dev/urandom or pipe */
91void get_random_bytes(unsigned char *buf, int len)
92{
93 static int random_pool = -1;
94 int c;
95
96 if (random_pool == -1) {
97 random_pool = open(RANDOM_POOL, O_RDONLY);
98 if (random_pool == -1)
99 fatal("Couldn't open random pool \"%s\": %s", RANDOM_POOL, strerror(errno));
100 }
101
bfc9a610 102 c = atomicio(read, random_pool, buf, len);
103 if (c <= 0)
104 fatal("Couldn't read from random pool \"%s\": %s", RANDOM_POOL, strerror(errno));
105}
106#endif /* RANDOM_POOL */
107#endif /* EGD_SOCKET */
108
109#if !defined(EGD_SOCKET) && !defined(RANDOM_POOL)
110/*
111 * FIXME: proper entropy estimations. All current values are guesses
b7a87eea 112 * FIXME: (ATL) do estimates at compile time?
bfc9a610 113 * FIXME: More entropy sources
114 */
115
b7a87eea 116/* slow command timeouts (all in milliseconds) */
117/* static int entropy_timeout_default = ENTROPY_TIMEOUT_MSEC; */
118static int entropy_timeout_current = ENTROPY_TIMEOUT_MSEC;
119
120static int prng_seed_loaded = 0;
d3083fbd 121static int prng_seed_saved = 0;
122static int prng_commands_loaded = 0;
bfc9a610 123
124typedef struct
125{
126 /* Proportion of data that is entropy */
127 double rate;
b7a87eea 128 /* Counter goes positive if this command times out */
129 unsigned int badness;
130 /* Increases by factor of two each timeout */
131 unsigned int sticky_badness;
bfc9a610 132 /* Path to executable */
d3083fbd 133 char *path;
bfc9a610 134 /* argv to pass to executable */
d3083fbd 135 char *args[5];
ad85db64 136 /* full command string (debug) */
137 char *cmdstring;
bfc9a610 138} entropy_source_t;
139
b7a87eea 140double stir_from_system(void);
141double stir_from_programs(void);
142double stir_gettimeofday(double entropy_estimate);
143double stir_clock(double entropy_estimate);
144double stir_rusage(int who, double entropy_estimate);
145double hash_output_from_command(entropy_source_t *src, char *hash);
146
d3083fbd 147/* this is initialised from a file, by prng_read_commands() */
148entropy_source_t *entropy_sources = NULL;
149#define MIN_ENTROPY_SOURCES 16
150
bfc9a610 151
bfc9a610 152double
153stir_from_system(void)
154{
155 double total_entropy_estimate;
156 long int i;
157
158 total_entropy_estimate = 0;
159
160 i = getpid();
161 RAND_add(&i, sizeof(i), 0.1);
162 total_entropy_estimate += 0.1;
163
164 i = getppid();
165 RAND_add(&i, sizeof(i), 0.1);
166 total_entropy_estimate += 0.1;
167
168 i = getuid();
169 RAND_add(&i, sizeof(i), 0.0);
170 i = getgid();
171 RAND_add(&i, sizeof(i), 0.0);
172
173 total_entropy_estimate += stir_gettimeofday(1.0);
174 total_entropy_estimate += stir_clock(0.2);
175 total_entropy_estimate += stir_rusage(RUSAGE_SELF, 2.0);
176
177 return(total_entropy_estimate);
178}
179
180double
181stir_from_programs(void)
182{
183 int i;
184 int c;
185 double entropy_estimate;
186 double total_entropy_estimate;
187 char hash[SHA_DIGEST_LENGTH];
188
189 /*
190 * Run through list of programs twice to catch differences
191 */
192 total_entropy_estimate = 0;
193 for(i = 0; i < 2; i++) {
194 c = 0;
195 while (entropy_sources[c].path != NULL) {
bfc9a610 196
b7a87eea 197 if (!entropy_sources[c].badness) {
198 /* Hash output from command */
199 entropy_estimate = hash_output_from_command(&entropy_sources[c], hash);
200
201 /* Scale back entropy estimate according to command's rate */
202 entropy_estimate *= entropy_sources[c].rate;
bfc9a610 203
b7a87eea 204 /* Upper bound of entropy estimate is SHA_DIGEST_LENGTH */
205 if (entropy_estimate > SHA_DIGEST_LENGTH)
206 entropy_estimate = SHA_DIGEST_LENGTH;
bfc9a610 207
208 /* * Scale back estimates for subsequent passes through list */
b7a87eea 209 entropy_estimate /= 10.0 * (i + 1.0);
bfc9a610 210
b7a87eea 211 /* Stir it in */
212 RAND_add(hash, sizeof(hash), entropy_estimate);
bfc9a610 213
214/* FIXME: turn this off later */
215#if 1
ad85db64 216 debug("Got %0.2f bytes of entropy from '%s'", entropy_estimate,
217 entropy_sources[c].cmdstring);
bfc9a610 218#endif
219
b7a87eea 220 total_entropy_estimate += entropy_estimate;
bfc9a610 221
222 /* Execution times should be a little unpredictable */
b7a87eea 223 total_entropy_estimate += stir_gettimeofday(0.05);
224 total_entropy_estimate += stir_clock(0.05);
225 total_entropy_estimate += stir_rusage(RUSAGE_SELF, 0.1);
226 total_entropy_estimate += stir_rusage(RUSAGE_CHILDREN, 0.1);
227 } else {
228/* FIXME: turn this off later */
229#if 1
ad85db64 230 debug("Command '%s' disabled (badness %d)",
231 entropy_sources[c].cmdstring, entropy_sources[c].badness);
b7a87eea 232#endif
233
234 if (entropy_sources[c].badness > 0)
235 entropy_sources[c].badness--;
236 }
237
bfc9a610 238 c++;
239 }
240 }
241
242 return(total_entropy_estimate);
243}
244
245double
246stir_gettimeofday(double entropy_estimate)
247{
248 struct timeval tv;
249
250 if (gettimeofday(&tv, NULL) == -1)
251 fatal("Couldn't gettimeofday: %s", strerror(errno));
252
253 RAND_add(&tv, sizeof(tv), entropy_estimate);
254
255 return(entropy_estimate);
256}
257
258double
259stir_clock(double entropy_estimate)
260{
261#ifdef HAVE_CLOCK
262 clock_t c;
263
264 c = clock();
265 RAND_add(&c, sizeof(c), entropy_estimate);
266
267 return(entropy_estimate);
268#else /* _HAVE_CLOCK */
269 return(0);
270#endif /* _HAVE_CLOCK */
271}
272
273double
274stir_rusage(int who, double entropy_estimate)
275{
276#ifdef HAVE_GETRUSAGE
277 struct rusage ru;
278
b7a87eea 279 if (getrusage(who, &ru) == -1)
bfc9a610 280 fatal("Couldn't getrusage: %s", strerror(errno));
281
282 RAND_add(&ru, sizeof(ru), 0.1);
283
284 return(entropy_estimate);
285#else /* _HAVE_GETRUSAGE */
286 return(0);
287#endif /* _HAVE_GETRUSAGE */
288}
289
ad85db64 290
291static
292int
293_get_timeval_msec_difference(struct timeval *t1, struct timeval *t2) {
294 int secdiff, usecdiff;
295
296 secdiff = t2->tv_sec - t1->tv_sec;
297 usecdiff = (secdiff*1000000) + (t2->tv_usec - t1->tv_usec);
298 return (int)(usecdiff / 1000);
299}
300
bfc9a610 301double
b7a87eea 302hash_output_from_command(entropy_source_t *src, char *hash)
bfc9a610 303{
304 static int devnull = -1;
305 int p[2];
b7a87eea 306 fd_set rdset;
307 int cmd_eof = 0, error_abort = 0;
ad85db64 308 struct timeval tv_start, tv_current;
309 int msec_elapsed = 0;
bfc9a610 310 pid_t pid;
311 int status;
ad85db64 312 char buf[16384];
bfc9a610 313 int bytes_read;
314 int total_bytes_read;
315 SHA_CTX sha;
316
317 if (devnull == -1) {
318 devnull = open("/dev/null", O_RDWR);
319 if (devnull == -1)
320 fatal("Couldn't open /dev/null: %s", strerror(errno));
321 }
322
323 if (pipe(p) == -1)
324 fatal("Couldn't open pipe: %s", strerror(errno));
325
ad85db64 326 (void)gettimeofday(&tv_start, NULL); /* record start time */
327
bfc9a610 328 switch (pid = fork()) {
329 case -1: /* Error */
330 close(p[0]);
331 close(p[1]);
332 fatal("Couldn't fork: %s", strerror(errno));
333 /* NOTREACHED */
334 case 0: /* Child */
b7a87eea 335 dup2(devnull, STDIN_FILENO);
336 dup2(p[1], STDOUT_FILENO);
337 dup2(p[1], STDERR_FILENO);
bfc9a610 338 close(p[0]);
339 close(p[1]);
340 close(devnull);
341
b7a87eea 342 execv(src->path, (char**)(src->args));
ad85db64 343 debug("(child) Couldn't exec '%s': %s", src->cmdstring,
344 strerror(errno));
b7a87eea 345 src->badness = src->sticky_badness = 128;
bfc9a610 346 _exit(-1);
347 default: /* Parent */
348 break;
349 }
350
351 RAND_add(&pid, sizeof(&pid), 0.0);
352
353 close(p[1]);
354
355 /* Hash output from child */
356 SHA1_Init(&sha);
357 total_bytes_read = 0;
b7a87eea 358
359 while (!error_abort && !cmd_eof) {
360 int ret;
361 struct timeval tv;
ad85db64 362 int msec_remaining;
363
364 (void) gettimeofday(&tv_current, 0);
365 msec_elapsed = _get_timeval_msec_difference(
366 &tv_start, &tv_current);
367 if (msec_elapsed >= entropy_timeout_current) {
368 error_abort=1;
369 continue;
370 }
371 msec_remaining = entropy_timeout_current - msec_elapsed;
b7a87eea 372
373 FD_ZERO(&rdset);
374 FD_SET(p[0], &rdset);
ad85db64 375 tv.tv_sec = msec_remaining / 1000;
376 tv.tv_usec = (msec_remaining % 1000) * 1000;
b7a87eea 377
378 ret = select(p[0]+1, &rdset, NULL, NULL, &tv);
ad85db64 379
b7a87eea 380 switch (ret) {
381 case 0:
382 /* timer expired */
383 error_abort = 1;
384 break;
385
386 case 1:
387 /* command input */
388 bytes_read = read(p[0], buf, sizeof(buf));
389 if (bytes_read == -1) {
390 error_abort = 1;
391 break;
392 }
ad85db64 393 if (bytes_read) {
394 SHA1_Update(&sha, buf, bytes_read);
395 total_bytes_read += bytes_read;
396 RAND_add(&bytes_read, sizeof(&bytes_read), 0.0);
397 } else
398 cmd_eof = 1;
b7a87eea 399
400 break;
401
402 case -1:
403 default:
ad85db64 404 debug("Command '%s': select() failed: %s", src->cmdstring,
405 strerror(errno));
b7a87eea 406 error_abort = 1;
407 break;
408 } /* switch ret */
409
410 RAND_add(&tv, sizeof(&tv), 0.0);
411 } /* while !error_abort && !cmd_eof */
412
bfc9a610 413 SHA1_Final(hash, &sha);
414
415 close(p[0]);
ad85db64 416
417 debug("Time elapsed: %d msec", msec_elapsed);
bfc9a610 418
419 if (waitpid(pid, &status, 0) == -1) {
ad85db64 420 debug("Couldn't wait for child '%s' completion: %s", src->cmdstring,
421 strerror(errno));
b7a87eea 422 return(0.0);
bfc9a610 423 }
424
425 RAND_add(&status, sizeof(&status), 0.0);
426
b7a87eea 427 if (error_abort) {
428 /* closing p[0] on timeout causes the entropy command to
429 * SIGPIPE. Take whatever output we got, and mark this command
430 * as slow */
ad85db64 431 debug("Command '%s' timed out", src->cmdstring);
b7a87eea 432 src->sticky_badness *= 2;
433 src->badness = src->sticky_badness;
bfc9a610 434 return(total_bytes_read);
b7a87eea 435 }
436
437 if (WIFEXITED(status)) {
438 if (WEXITSTATUS(status)==0) {
439 return(total_bytes_read);
440 } else {
441 debug("Exit status was %d", WEXITSTATUS(status));
442 src->badness = src->sticky_badness = 128;
443 return (0.0);
444 }
445 } else if (WIFSIGNALED(status)) {
446 debug("Returned on uncaught signal %d !", status);
447 src->badness = src->sticky_badness = 128;
448 return(0.0);
449 } else
450 return(0.0);
451}
452
453/*
454 * prng seedfile functions
455 */
456int
457prng_check_seedfile(char *filename) {
458
459 struct stat st;
460
461 /* FIXME raceable: eg replace seed between this stat and subsequent open */
462 /* Not such a problem because we don't trust the seed file anyway */
463 if (lstat(filename, &st) == -1) {
464 /* Fail on hard errors */
465 if (errno != ENOENT)
466 fatal("Couldn't stat random seed file \"%s\": %s", filename,
467 strerror(errno));
468
469 return(0);
470 }
471
472 /* regular file? */
473 if (!S_ISREG(st.st_mode))
474 fatal("PRNG seedfile %.100s is not a regular file", filename);
475
476 /* mode 0600, owned by root or the current user? */
d02a3a00 477 if (((st.st_mode & 0177) != 0) || !(st.st_uid == getuid()))
b7a87eea 478 fatal("PRNG seedfile %.100s must be mode 0600, owned by uid %d",
479 filename, getuid());
480
481 return(1);
482}
483
484void
485prng_write_seedfile(void) {
486 int fd;
487 char seed[1024];
488 char filename[1024];
489 struct passwd *pw;
490
491 /* Don't bother if we have already saved a seed */
492 if (prng_seed_saved)
493 return;
494
52bcc044 495 prng_seed_saved = 1;
496
b7a87eea 497 pw = getpwuid(getuid());
498 if (pw == NULL)
499 fatal("Couldn't get password entry for current user (%i): %s",
500 getuid(), strerror(errno));
501
502 /* Try to ensure that the parent directory is there */
503 snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
504 SSH_USER_DIR);
505 mkdir(filename, 0700);
506
507 snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
508 SSH_PRNG_SEED_FILE);
509
510 debug("writing PRNG seed to file %.100s", filename);
511
512 RAND_bytes(seed, sizeof(seed));
513
514 /* Don't care if the seed doesn't exist */
515 prng_check_seedfile(filename);
516
517 if ((fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0600)) == -1)
518 fatal("couldn't access PRNG seedfile %.100s (%.100s)", filename,
519 strerror(errno));
520
521 if (atomicio(write, fd, &seed, sizeof(seed)) != sizeof(seed))
522 fatal("problem writing PRNG seedfile %.100s (%.100s)", filename,
523 strerror(errno));
524
525 close(fd);
526}
527
528void
529prng_read_seedfile(void) {
530 int fd;
531 char seed[1024];
532 char filename[1024];
533 struct passwd *pw;
534
535 pw = getpwuid(getuid());
536 if (pw == NULL)
537 fatal("Couldn't get password entry for current user (%i): %s",
538 getuid(), strerror(errno));
539
540 snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
541 SSH_PRNG_SEED_FILE);
542
543 debug("loading PRNG seed from file %.100s", filename);
544
545 if (!prng_check_seedfile(filename)) {
546 verbose("Random seed file not found, creating new");
547 prng_write_seedfile();
548
549 /* Reseed immediatly */
550 (void)stir_from_system();
551 (void)stir_from_programs();
552 return;
553 }
554
555 /* open the file and read in the seed */
556 fd = open(filename, O_RDONLY);
557 if (fd == -1)
558 fatal("could not open PRNG seedfile %.100s (%.100s)", filename,
559 strerror(errno));
560
561 if (atomicio(read, fd, &seed, sizeof(seed)) != sizeof(seed)) {
562 verbose("invalid or short read from PRNG seedfile %.100s - ignoring",
563 filename);
564 memset(seed, '\0', sizeof(seed));
565 }
566 close(fd);
567
568 /* stir in the seed, with estimated entropy zero */
569 RAND_add(&seed, sizeof(seed), 0.0);
bfc9a610 570}
b7a87eea 571
d3083fbd 572
573/*
574 * entropy command initialisation functions
575 */
576#define WHITESPACE " \t\n"
577
578int
579prng_read_commands(char *cmdfilename)
580{
581 FILE *f;
582 char line[1024];
583 char cmd[1024], path[256];
584 double est;
585 char *cp;
586 int linenum;
587 entropy_source_t *entcmd;
588 int num_cmds = 64;
589 int cur_cmd = 0;
590
591 f = fopen(cmdfilename, "r");
592 if (!f) {
593 fatal("couldn't read entropy commands file %.100s: %.100s",
594 cmdfilename, strerror(errno));
595 }
596
597 linenum = 0;
598
599 entcmd = (entropy_source_t *)xmalloc(num_cmds * sizeof(entropy_source_t));
600 memset(entcmd, '\0', num_cmds * sizeof(entropy_source_t));
601
602 while (fgets(line, sizeof(line), f)) {
603 linenum++;
604
605 /* skip leading whitespace, test for blank line or comment */
606 cp = line + strspn(line, WHITESPACE);
607 if ((*cp == 0) || (*cp == '#'))
608 continue; /* done with this line */
609
610 switch (*cp) {
611 int arg;
612 char *argv;
613
614 case '"':
615 /* first token, command args (incl. argv[0]) in double quotes */
616 cp = strtok(cp, "\"");
617 if (cp==NULL) {
618 error("missing or bad command string, %.100s line %d -- ignored",
619 cmdfilename, linenum);
620 continue;
621 }
622 strncpy(cmd, cp, sizeof(cmd));
623 /* second token, full command path */
624 if ((cp = strtok(NULL, WHITESPACE)) == NULL) {
625 error("missing command path, %.100s line %d -- ignored",
626 cmdfilename, linenum);
627 continue;
628 }
629 if (strncmp("undef", cp, 5)==0) /* did configure mark this as dead? */
630 continue;
631
632 strncpy(path, cp, sizeof(path));
633 /* third token, entropy rate estimate for this command */
634 if ( (cp = strtok(NULL, WHITESPACE)) == NULL) {
635 error("missing entropy estimate, %.100s line %d -- ignored",
636 cmdfilename, linenum);
637 continue;
638 }
639 est = strtod(cp, &argv);/* FIXME: (ATL) no error checking here */
640
641 /* end of line */
642 if ((cp = strtok(NULL, WHITESPACE)) != NULL) {
643 error("garbage at end of line %d in %.100s -- ignored",
644 linenum, cmdfilename);
645 continue;
646 }
647
ad85db64 648 /* save the command for debug messages */
649 entcmd[cur_cmd].cmdstring = (char*) xmalloc(strlen(cmd)+1);
650 strncpy(entcmd[cur_cmd].cmdstring, cmd, strlen(cmd)+1);
651
d3083fbd 652 /* split the command args */
653 cp = strtok(cmd, WHITESPACE);
654 arg = 0; argv = NULL;
655 do {
656 char *s = (char*)xmalloc(strlen(cp)+1);
657 strncpy(s, cp, strlen(cp)+1);
658 entcmd[cur_cmd].args[arg] = s;
659 arg++;
660 } while ((arg < 5) && (cp = strtok(NULL, WHITESPACE)));
661 if (strtok(NULL, WHITESPACE))
662 error("ignored extra command elements (max 5), %.100s line %d",
663 cmdfilename, linenum);
664
665 /* copy the command path and rate estimate */
666 entcmd[cur_cmd].path = (char *)xmalloc(strlen(path)+1);
667 strncpy(entcmd[cur_cmd].path, path, strlen(path)+1);
668 entcmd[cur_cmd].rate = est;
669 /* initialise other values */
670 entcmd[cur_cmd].sticky_badness = 1;
671
672 cur_cmd++;
673
674 /* If we've filled the array, reallocate it twice the size */
675 /* Do this now because even if this we're on the last command,
676 we need another slot to mark the last entry */
677 if (cur_cmd == num_cmds) {
678 num_cmds *= 2;
679 entcmd = xrealloc(entcmd, num_cmds * sizeof(entropy_source_t));
680 }
681 break;
682
683 default:
684 error("bad entropy command, %.100s line %d", cmdfilename,
685 linenum);
686 continue;
687 }
688 }
689
690 /* zero the last entry */
691 memset(&entcmd[cur_cmd], '\0', sizeof(entropy_source_t));
692 /* trim to size */
693 entropy_sources = xrealloc(entcmd, (cur_cmd+1) * sizeof(entropy_source_t));
694
695 debug("loaded %d entropy commands from %.100s", cur_cmd, cmdfilename);
696
697 return (cur_cmd >= MIN_ENTROPY_SOURCES);
698}
699
700
bfc9a610 701#endif /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */
702
703#if defined(EGD_SOCKET) || defined(RANDOM_POOL)
b7a87eea 704
bfc9a610 705/*
706 * Seed OpenSSL's random number pool from Kernel random number generator
707 * or EGD
708 */
709void
710seed_rng(void)
711{
712 char buf[32];
713
714 debug("Seeding random number generator");
715 get_random_bytes(buf, sizeof(buf));
716 RAND_add(buf, sizeof(buf), sizeof(buf));
717 memset(buf, '\0', sizeof(buf));
718}
b7a87eea 719
bfc9a610 720#else /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */
b7a87eea 721
722/*
723 * Write a keyfile at exit
724 */
725void
726prng_seed_cleanup(void *junk)
727{
728 prng_write_seedfile();
729}
730
bfc9a610 731/*
b7a87eea 732 * Conditionally Seed OpenSSL's random number pool from
733 * syscalls and program output
bfc9a610 734 */
735void
736seed_rng(void)
737{
d3083fbd 738 if (!prng_commands_loaded) {
739 if (!prng_read_commands(SSH_PRNG_COMMAND_FILE))
740 fatal("PRNG initialisation failed -- exiting.");
741 prng_commands_loaded = 1;
742 }
743
6c081128 744 debug("Seeding random number generator.");
745 debug("OpenSSL random status is now %i\n", RAND_status());
746 debug("%i bytes from system calls", (int)stir_from_system());
747 debug("%i bytes from programs", (int)stir_from_programs());
748 debug("OpenSSL random status is now %i\n", RAND_status());
b7a87eea 749
ad85db64 750 if (!RAND_status())
751 fatal("Couldn't initialise builtin random number generator -- exiting.");
752
b7a87eea 753 if (!prng_seed_loaded)
754 {
755 prng_seed_loaded = 1;
756 prng_seed_saved = 0;
757 prng_read_seedfile();
758 fatal_add_cleanup(prng_seed_cleanup, NULL);
759 atexit(prng_write_seedfile);
760 }
bfc9a610 761}
762#endif /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */
This page took 0.3276 seconds and 5 git commands to generate.