diff options
Diffstat (limited to 'entropy.c')
-rw-r--r-- | entropy.c | 257 |
1 files changed, 134 insertions, 123 deletions
@@ -35,12 +35,29 @@ | |||
35 | #include <openssl/rand.h> | 35 | #include <openssl/rand.h> |
36 | #include <openssl/sha.h> | 36 | #include <openssl/sha.h> |
37 | 37 | ||
38 | RCSID("$Id: entropy.c,v 1.12 2000/05/31 01:24:34 damien Exp $"); | 38 | RCSID("$Id: entropy.c,v 1.13 2000/06/07 12:20:23 djm Exp $"); |
39 | 39 | ||
40 | #ifdef EGD_SOCKET | ||
41 | #ifndef offsetof | 40 | #ifndef offsetof |
42 | # define offsetof(type, member) ((size_t) &((type *)0)->member) | 41 | # define offsetof(type, member) ((size_t) &((type *)0)->member) |
43 | #endif | 42 | #endif |
43 | |||
44 | /* Print lots of detail */ | ||
45 | /* #define DEBUG_ENTROPY */ | ||
46 | |||
47 | /* Number of times to pass through command list gathering entropy */ | ||
48 | #define NUM_ENTROPY_RUNS 1 | ||
49 | |||
50 | /* Scale entropy estimates back by this amount on subsequent runs */ | ||
51 | #define SCALE_PER_RUN 10.0 | ||
52 | |||
53 | /* Minimum number of commands to be considered valid */ | ||
54 | #define MIN_ENTROPY_SOURCES 16 | ||
55 | |||
56 | #define WHITESPACE " \t\n" | ||
57 | |||
58 | #if defined(EGD_SOCKET) || defined(RANDOM_POOL) | ||
59 | |||
60 | #ifdef EGD_SOCKET | ||
44 | /* Collect entropy from EGD */ | 61 | /* Collect entropy from EGD */ |
45 | void get_random_bytes(unsigned char *buf, int len) | 62 | void get_random_bytes(unsigned char *buf, int len) |
46 | { | 63 | { |
@@ -57,7 +74,7 @@ void get_random_bytes(unsigned char *buf, int len) | |||
57 | if (sizeof(EGD_SOCKET) > sizeof(addr.sun_path)) | 74 | if (sizeof(EGD_SOCKET) > sizeof(addr.sun_path)) |
58 | fatal("Random pool path is too long"); | 75 | fatal("Random pool path is too long"); |
59 | 76 | ||
60 | strcpy(addr.sun_path, EGD_SOCKET); | 77 | strlcpy(addr.sun_path, EGD_SOCKET, sizeof(addr.sun_path)); |
61 | 78 | ||
62 | addr_len = offsetof(struct sockaddr_un, sun_path) + sizeof(EGD_SOCKET); | 79 | addr_len = offsetof(struct sockaddr_un, sun_path) + sizeof(EGD_SOCKET); |
63 | 80 | ||
@@ -104,7 +121,23 @@ void get_random_bytes(unsigned char *buf, int len) | |||
104 | #endif /* RANDOM_POOL */ | 121 | #endif /* RANDOM_POOL */ |
105 | #endif /* EGD_SOCKET */ | 122 | #endif /* EGD_SOCKET */ |
106 | 123 | ||
107 | #if !defined(EGD_SOCKET) && !defined(RANDOM_POOL) | 124 | /* |
125 | * Seed OpenSSL's random number pool from Kernel random number generator | ||
126 | * or EGD | ||
127 | */ | ||
128 | void | ||
129 | seed_rng(void) | ||
130 | { | ||
131 | char buf[32]; | ||
132 | |||
133 | debug("Seeding random number generator"); | ||
134 | get_random_bytes(buf, sizeof(buf)); | ||
135 | RAND_add(buf, sizeof(buf), sizeof(buf)); | ||
136 | memset(buf, '\0', sizeof(buf)); | ||
137 | } | ||
138 | |||
139 | #else /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */ | ||
140 | |||
108 | /* | 141 | /* |
109 | * FIXME: proper entropy estimations. All current values are guesses | 142 | * FIXME: proper entropy estimations. All current values are guesses |
110 | * FIXME: (ATL) do estimates at compile time? | 143 | * FIXME: (ATL) do estimates at compile time? |
@@ -144,8 +177,6 @@ double hash_output_from_command(entropy_source_t *src, char *hash); | |||
144 | 177 | ||
145 | /* this is initialised from a file, by prng_read_commands() */ | 178 | /* this is initialised from a file, by prng_read_commands() */ |
146 | entropy_source_t *entropy_sources = NULL; | 179 | entropy_source_t *entropy_sources = NULL; |
147 | #define MIN_ENTROPY_SOURCES 16 | ||
148 | |||
149 | 180 | ||
150 | double | 181 | double |
151 | stir_from_system(void) | 182 | stir_from_system(void) |
@@ -184,11 +215,8 @@ stir_from_programs(void) | |||
184 | double total_entropy_estimate; | 215 | double total_entropy_estimate; |
185 | char hash[SHA_DIGEST_LENGTH]; | 216 | char hash[SHA_DIGEST_LENGTH]; |
186 | 217 | ||
187 | /* | ||
188 | * Run through list of programs twice to catch differences | ||
189 | */ | ||
190 | total_entropy_estimate = 0; | 218 | total_entropy_estimate = 0; |
191 | for(i = 0; i < 2; i++) { | 219 | for(i = 0; i < NUM_ENTROPY_RUNS; i++) { |
192 | c = 0; | 220 | c = 0; |
193 | while (entropy_sources[c].path != NULL) { | 221 | while (entropy_sources[c].path != NULL) { |
194 | 222 | ||
@@ -203,14 +231,13 @@ stir_from_programs(void) | |||
203 | if (entropy_estimate > SHA_DIGEST_LENGTH) | 231 | if (entropy_estimate > SHA_DIGEST_LENGTH) |
204 | entropy_estimate = SHA_DIGEST_LENGTH; | 232 | entropy_estimate = SHA_DIGEST_LENGTH; |
205 | 233 | ||
206 | /* * Scale back estimates for subsequent passes through list */ | 234 | /* Scale back estimates for subsequent passes through list */ |
207 | entropy_estimate /= 10.0 * (i + 1.0); | 235 | entropy_estimate /= SCALE_PER_RUN * (i + 1.0); |
208 | 236 | ||
209 | /* Stir it in */ | 237 | /* Stir it in */ |
210 | RAND_add(hash, sizeof(hash), entropy_estimate); | 238 | RAND_add(hash, sizeof(hash), entropy_estimate); |
211 | 239 | ||
212 | /* FIXME: turn this off later */ | 240 | #ifdef DEBUG_ENTROPY |
213 | #if 1 | ||
214 | debug("Got %0.2f bytes of entropy from '%s'", entropy_estimate, | 241 | debug("Got %0.2f bytes of entropy from '%s'", entropy_estimate, |
215 | entropy_sources[c].cmdstring); | 242 | entropy_sources[c].cmdstring); |
216 | #endif | 243 | #endif |
@@ -223,8 +250,7 @@ stir_from_programs(void) | |||
223 | total_entropy_estimate += stir_rusage(RUSAGE_SELF, 0.1); | 250 | total_entropy_estimate += stir_rusage(RUSAGE_SELF, 0.1); |
224 | total_entropy_estimate += stir_rusage(RUSAGE_CHILDREN, 0.1); | 251 | total_entropy_estimate += stir_rusage(RUSAGE_CHILDREN, 0.1); |
225 | } else { | 252 | } else { |
226 | /* FIXME: turn this off later */ | 253 | #ifdef DEBUG_ENTROPY |
227 | #if 1 | ||
228 | debug("Command '%s' disabled (badness %d)", | 254 | debug("Command '%s' disabled (badness %d)", |
229 | entropy_sources[c].cmdstring, entropy_sources[c].badness); | 255 | entropy_sources[c].cmdstring, entropy_sources[c].badness); |
230 | #endif | 256 | #endif |
@@ -360,8 +386,7 @@ hash_output_from_command(entropy_source_t *src, char *hash) | |||
360 | int msec_remaining; | 386 | int msec_remaining; |
361 | 387 | ||
362 | (void) gettimeofday(&tv_current, 0); | 388 | (void) gettimeofday(&tv_current, 0); |
363 | msec_elapsed = _get_timeval_msec_difference( | 389 | msec_elapsed = _get_timeval_msec_difference(&tv_start, &tv_current); |
364 | &tv_start, &tv_current); | ||
365 | if (msec_elapsed >= entropy_timeout_current) { | 390 | if (msec_elapsed >= entropy_timeout_current) { |
366 | error_abort=1; | 391 | error_abort=1; |
367 | continue; | 392 | continue; |
@@ -412,7 +437,9 @@ hash_output_from_command(entropy_source_t *src, char *hash) | |||
412 | 437 | ||
413 | close(p[0]); | 438 | close(p[0]); |
414 | 439 | ||
440 | #ifdef DEBUG_ENTROPY | ||
415 | debug("Time elapsed: %d msec", msec_elapsed); | 441 | debug("Time elapsed: %d msec", msec_elapsed); |
442 | #endif | ||
416 | 443 | ||
417 | if (waitpid(pid, &status, 0) == -1) { | 444 | if (waitpid(pid, &status, 0) == -1) { |
418 | debug("Couldn't wait for child '%s' completion: %s", src->cmdstring, | 445 | debug("Couldn't wait for child '%s' completion: %s", src->cmdstring, |
@@ -436,12 +463,14 @@ hash_output_from_command(entropy_source_t *src, char *hash) | |||
436 | if (WEXITSTATUS(status)==0) { | 463 | if (WEXITSTATUS(status)==0) { |
437 | return(total_bytes_read); | 464 | return(total_bytes_read); |
438 | } else { | 465 | } else { |
439 | debug("Exit status was %d", WEXITSTATUS(status)); | 466 | debug("Command '%s' exit status was %d", src->cmdstring, |
467 | WEXITSTATUS(status)); | ||
440 | src->badness = src->sticky_badness = 128; | 468 | src->badness = src->sticky_badness = 128; |
441 | return (0.0); | 469 | return (0.0); |
442 | } | 470 | } |
443 | } else if (WIFSIGNALED(status)) { | 471 | } else if (WIFSIGNALED(status)) { |
444 | debug("Returned on uncaught signal %d !", status); | 472 | debug("Command '%s' returned on uncaught signal %d !", src->cmdstring, |
473 | status); | ||
445 | src->badness = src->sticky_badness = 128; | 474 | src->badness = src->sticky_badness = 128; |
446 | return(0.0); | 475 | return(0.0); |
447 | } else | 476 | } else |
@@ -571,20 +600,19 @@ prng_read_seedfile(void) { | |||
571 | /* | 600 | /* |
572 | * entropy command initialisation functions | 601 | * entropy command initialisation functions |
573 | */ | 602 | */ |
574 | #define WHITESPACE " \t\n" | ||
575 | |||
576 | int | 603 | int |
577 | prng_read_commands(char *cmdfilename) | 604 | prng_read_commands(char *cmdfilename) |
578 | { | 605 | { |
579 | FILE *f; | 606 | FILE *f; |
580 | char line[1024]; | ||
581 | char cmd[1024], path[256]; | ||
582 | double est; | ||
583 | char *cp; | 607 | char *cp; |
608 | char line[1024]; | ||
609 | char cmd[1024]; | ||
610 | char path[256]; | ||
584 | int linenum; | 611 | int linenum; |
585 | entropy_source_t *entcmd; | ||
586 | int num_cmds = 64; | 612 | int num_cmds = 64; |
587 | int cur_cmd = 0; | 613 | int cur_cmd = 0; |
614 | double est; | ||
615 | entropy_source_t *entcmd; | ||
588 | 616 | ||
589 | f = fopen(cmdfilename, "r"); | 617 | f = fopen(cmdfilename, "r"); |
590 | if (!f) { | 618 | if (!f) { |
@@ -592,12 +620,15 @@ prng_read_commands(char *cmdfilename) | |||
592 | cmdfilename, strerror(errno)); | 620 | cmdfilename, strerror(errno)); |
593 | } | 621 | } |
594 | 622 | ||
595 | linenum = 0; | ||
596 | |||
597 | entcmd = (entropy_source_t *)xmalloc(num_cmds * sizeof(entropy_source_t)); | 623 | entcmd = (entropy_source_t *)xmalloc(num_cmds * sizeof(entropy_source_t)); |
598 | memset(entcmd, '\0', num_cmds * sizeof(entropy_source_t)); | 624 | memset(entcmd, '\0', num_cmds * sizeof(entropy_source_t)); |
599 | 625 | ||
626 | /* Read in file */ | ||
627 | linenum = 0; | ||
600 | while (fgets(line, sizeof(line), f)) { | 628 | while (fgets(line, sizeof(line), f)) { |
629 | int arg; | ||
630 | char *argv; | ||
631 | |||
601 | linenum++; | 632 | linenum++; |
602 | 633 | ||
603 | /* skip leading whitespace, test for blank line or comment */ | 634 | /* skip leading whitespace, test for blank line or comment */ |
@@ -605,88 +636,90 @@ prng_read_commands(char *cmdfilename) | |||
605 | if ((*cp == 0) || (*cp == '#')) | 636 | if ((*cp == 0) || (*cp == '#')) |
606 | continue; /* done with this line */ | 637 | continue; /* done with this line */ |
607 | 638 | ||
608 | switch (*cp) { | 639 | /* First non-whitespace char should be double quote delimiting */ |
609 | int arg; | 640 | /* commandline */ |
610 | char *argv; | 641 | if (*cp != '"') { |
611 | 642 | error("bad entropy command, %.100s line %d", cmdfilename, | |
612 | case '"': | 643 | linenum); |
613 | /* first token, command args (incl. argv[0]) in double quotes */ | 644 | continue; |
614 | cp = strtok(cp, "\""); | 645 | } |
615 | if (cp==NULL) { | ||
616 | error("missing or bad command string, %.100s line %d -- ignored", | ||
617 | cmdfilename, linenum); | ||
618 | continue; | ||
619 | } | ||
620 | strncpy(cmd, cp, sizeof(cmd)); | ||
621 | /* second token, full command path */ | ||
622 | if ((cp = strtok(NULL, WHITESPACE)) == NULL) { | ||
623 | error("missing command path, %.100s line %d -- ignored", | ||
624 | cmdfilename, linenum); | ||
625 | continue; | ||
626 | } | ||
627 | if (strncmp("undef", cp, 5)==0) /* did configure mark this as dead? */ | ||
628 | continue; | ||
629 | |||
630 | strncpy(path, cp, sizeof(path)); | ||
631 | /* third token, entropy rate estimate for this command */ | ||
632 | if ( (cp = strtok(NULL, WHITESPACE)) == NULL) { | ||
633 | error("missing entropy estimate, %.100s line %d -- ignored", | ||
634 | cmdfilename, linenum); | ||
635 | continue; | ||
636 | } | ||
637 | est = strtod(cp, &argv);/* FIXME: (ATL) no error checking here */ | ||
638 | 646 | ||
639 | /* end of line */ | 647 | /* first token, command args (incl. argv[0]) in double quotes */ |
640 | if ((cp = strtok(NULL, WHITESPACE)) != NULL) { | 648 | cp = strtok(cp, "\""); |
641 | error("garbage at end of line %d in %.100s -- ignored", | 649 | if (cp == NULL) { |
642 | linenum, cmdfilename); | 650 | error("missing or bad command string, %.100s line %d -- ignored", |
643 | continue; | 651 | cmdfilename, linenum); |
644 | } | 652 | continue; |
653 | } | ||
654 | strlcpy(cmd, cp, sizeof(cmd)); | ||
655 | |||
656 | /* second token, full command path */ | ||
657 | if ((cp = strtok(NULL, WHITESPACE)) == NULL) { | ||
658 | error("missing command path, %.100s line %d -- ignored", | ||
659 | cmdfilename, linenum); | ||
660 | continue; | ||
661 | } | ||
645 | 662 | ||
646 | /* save the command for debug messages */ | 663 | /* did configure mark this as dead? */ |
647 | entcmd[cur_cmd].cmdstring = (char*) xmalloc(strlen(cmd)+1); | 664 | if (strncmp("undef", cp, 5) == 0) |
648 | strncpy(entcmd[cur_cmd].cmdstring, cmd, strlen(cmd)+1); | 665 | continue; |
649 | |||
650 | /* split the command args */ | ||
651 | cp = strtok(cmd, WHITESPACE); | ||
652 | arg = 0; argv = NULL; | ||
653 | do { | ||
654 | char *s = (char*)xmalloc(strlen(cp)+1); | ||
655 | strncpy(s, cp, strlen(cp)+1); | ||
656 | entcmd[cur_cmd].args[arg] = s; | ||
657 | arg++; | ||
658 | } while ((arg < 5) && (cp = strtok(NULL, WHITESPACE))); | ||
659 | if (strtok(NULL, WHITESPACE)) | ||
660 | error("ignored extra command elements (max 5), %.100s line %d", | ||
661 | cmdfilename, linenum); | ||
662 | |||
663 | /* copy the command path and rate estimate */ | ||
664 | entcmd[cur_cmd].path = (char *)xmalloc(strlen(path)+1); | ||
665 | strncpy(entcmd[cur_cmd].path, path, strlen(path)+1); | ||
666 | entcmd[cur_cmd].rate = est; | ||
667 | /* initialise other values */ | ||
668 | entcmd[cur_cmd].sticky_badness = 1; | ||
669 | |||
670 | cur_cmd++; | ||
671 | |||
672 | /* If we've filled the array, reallocate it twice the size */ | ||
673 | /* Do this now because even if this we're on the last command, | ||
674 | we need another slot to mark the last entry */ | ||
675 | if (cur_cmd == num_cmds) { | ||
676 | num_cmds *= 2; | ||
677 | entcmd = xrealloc(entcmd, num_cmds * sizeof(entropy_source_t)); | ||
678 | } | ||
679 | break; | ||
680 | 666 | ||
681 | default: | 667 | strlcpy(path, cp, sizeof(path)); |
682 | error("bad entropy command, %.100s line %d", cmdfilename, | 668 | |
683 | linenum); | 669 | /* third token, entropy rate estimate for this command */ |
670 | if ((cp = strtok(NULL, WHITESPACE)) == NULL) { | ||
671 | error("missing entropy estimate, %.100s line %d -- ignored", | ||
672 | cmdfilename, linenum); | ||
673 | continue; | ||
674 | } | ||
675 | est = strtod(cp, &argv); | ||
676 | |||
677 | /* end of line */ | ||
678 | if ((cp = strtok(NULL, WHITESPACE)) != NULL) { | ||
679 | error("garbage at end of line %d in %.100s -- ignored", linenum, | ||
680 | cmdfilename); | ||
684 | continue; | 681 | continue; |
685 | } | 682 | } |
683 | |||
684 | /* save the command for debug messages */ | ||
685 | entcmd[cur_cmd].cmdstring = xstrdup(cmd); | ||
686 | |||
687 | /* split the command args */ | ||
688 | cp = strtok(cmd, WHITESPACE); | ||
689 | arg = 0; | ||
690 | argv = NULL; | ||
691 | do { | ||
692 | char *s = (char*)xmalloc(strlen(cp) + 1); | ||
693 | strncpy(s, cp, strlen(cp) + 1); | ||
694 | entcmd[cur_cmd].args[arg] = s; | ||
695 | arg++; | ||
696 | } while ((arg < 5) && (cp = strtok(NULL, WHITESPACE))); | ||
697 | |||
698 | if (strtok(NULL, WHITESPACE)) | ||
699 | error("ignored extra command elements (max 5), %.100s line %d", | ||
700 | cmdfilename, linenum); | ||
701 | |||
702 | /* Copy the command path and rate estimate */ | ||
703 | entcmd[cur_cmd].path = xstrdup(path); | ||
704 | entcmd[cur_cmd].rate = est; | ||
705 | |||
706 | /* Initialise other values */ | ||
707 | entcmd[cur_cmd].sticky_badness = 1; | ||
708 | |||
709 | cur_cmd++; | ||
710 | |||
711 | /* If we've filled the array, reallocate it twice the size */ | ||
712 | /* Do this now because even if this we're on the last command, | ||
713 | we need another slot to mark the last entry */ | ||
714 | if (cur_cmd == num_cmds) { | ||
715 | num_cmds *= 2; | ||
716 | entcmd = xrealloc(entcmd, num_cmds * sizeof(entropy_source_t)); | ||
717 | } | ||
686 | } | 718 | } |
687 | 719 | ||
688 | /* zero the last entry */ | 720 | /* zero the last entry */ |
689 | memset(&entcmd[cur_cmd], '\0', sizeof(entropy_source_t)); | 721 | memset(&entcmd[cur_cmd], '\0', sizeof(entropy_source_t)); |
722 | |||
690 | /* trim to size */ | 723 | /* trim to size */ |
691 | entropy_sources = xrealloc(entcmd, (cur_cmd+1) * sizeof(entropy_source_t)); | 724 | entropy_sources = xrealloc(entcmd, (cur_cmd+1) * sizeof(entropy_source_t)); |
692 | 725 | ||
@@ -695,28 +728,6 @@ prng_read_commands(char *cmdfilename) | |||
695 | return (cur_cmd >= MIN_ENTROPY_SOURCES); | 728 | return (cur_cmd >= MIN_ENTROPY_SOURCES); |
696 | } | 729 | } |
697 | 730 | ||
698 | |||
699 | #endif /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */ | ||
700 | |||
701 | #if defined(EGD_SOCKET) || defined(RANDOM_POOL) | ||
702 | |||
703 | /* | ||
704 | * Seed OpenSSL's random number pool from Kernel random number generator | ||
705 | * or EGD | ||
706 | */ | ||
707 | void | ||
708 | seed_rng(void) | ||
709 | { | ||
710 | char buf[32]; | ||
711 | |||
712 | debug("Seeding random number generator"); | ||
713 | get_random_bytes(buf, sizeof(buf)); | ||
714 | RAND_add(buf, sizeof(buf), sizeof(buf)); | ||
715 | memset(buf, '\0', sizeof(buf)); | ||
716 | } | ||
717 | |||
718 | #else /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */ | ||
719 | |||
720 | /* | 731 | /* |
721 | * Write a keyfile at exit | 732 | * Write a keyfile at exit |
722 | */ | 733 | */ |