diff --git a/cipher/ChangeLog b/cipher/ChangeLog index c150c4c99..87caa98a9 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,12 @@ +2002-08-30 Werner Koch + + * random.c: Automagically detect the entrop gatherer when + configure so. + * rndegd.c (rndegd_connect_socket): New. Factored out from .. + (rndegd_gather_random): here and call it. + (do_read): Update the counter variables correctly. This was not a + problem due to the way EGD works. Bug found by Christian Biere. + 2002-08-20 Werner Koch * primegen.c (generate_elg_prime): Return all factors for mode 1. diff --git a/cipher/cipher.c b/cipher/cipher.c index 6a545db78..ecab7a520 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -32,7 +32,7 @@ /* We have support for a DUMMY encryption cipher which comes handy to debug MDCs and similar things. Because this is a bit dangerous it is not enabled. */ -/*#define ALLOW_DUMMY 1 */ +#define ALLOW_DUMMY 1 #define MAX_BLOCKSIZE 16 #define TABLE_SIZE 14 diff --git a/cipher/rand-internal.h b/cipher/rand-internal.h index eb81174f8..581902b2a 100644 --- a/cipher/rand-internal.h +++ b/cipher/rand-internal.h @@ -24,6 +24,7 @@ int rndunix_gather_random (void (*add)(const void*, size_t, int), int requester, size_t length, int level); int rndlinux_gather_random (void (*add)(const void*, size_t, int), int requester, size_t length, int level); +int rndegd_connect_socket (int nofail); int rndegd_gather_random (void (*add)(const void*, size_t, int), int requester, size_t length, int level ); int rndw32_gather_random (void (*add)(const void*, size_t, int), diff --git a/cipher/random.c b/cipher/random.c index d7ebf5787..c2dea9c28 100644 --- a/cipher/random.c +++ b/cipher/random.c @@ -129,20 +129,49 @@ static int (* getfnc_gather_random (void))(void (*)(const void*, size_t, int), int, size_t, int) { -#ifdef USE_RNDLINUX +#ifdef USE_ALL_RANDOM_MODULES + static int (*fnc)(void (*)(const void*, size_t, int), int, size_t, int); + + if (fnc) + return fnc; +# ifdef USE_RNDLINUX + if ( !access (NAME_OF_DEV_RANDOM, R_OK) + && !access (NAME_OF_DEV_RANDOM, R_OK)) + { + fnc = rndlinux_gather_random; + return fnc; + } +# endif +# ifdef USE_RNDEGD + if ( rndegd_connect_socket (1) != -1 ) + { + fnc = rndegd_gather_random; + return fnc; + } +# endif +# ifdef USE_RNDUNIX + fnc = rndunix_gather_random; + return fnc; +# endif + + log_fatal (_("no entropy gathering module detected\n")); + +#else +# ifdef USE_RNDLINUX return rndlinux_gather_random; -#endif -#ifdef USE_RNDUNIX +# endif +# ifdef USE_RNDUNIX return rndunix_gather_random; -#endif -#ifdef USE_RNDEGD +# endif +# ifdef USE_RNDEGD return rndegd_gather_random; -#endif -#ifdef USE_RNDW32 +# endif +# ifdef USE_RNDW32 return rndw32_gather_random; -#endif -#ifdef USE_RNDRISCOS +# endif +# ifdef USE_RNDRISCOS return rndriscos_gather_random; +# endif #endif return NULL; } diff --git a/cipher/rndegd.c b/cipher/rndegd.c index 7503ab464..5f71ab858 100644 --- a/cipher/rndegd.c +++ b/cipher/rndegd.c @@ -20,7 +20,7 @@ #include -#ifdef USE_RNDEG +#ifdef USE_RNDEGD #include #include @@ -45,6 +45,8 @@ #define offsetof(type, member) ((size_t) &((type *)0)->member) #endif +static int egd_socket = -1; + static int do_write( int fd, void *buf, size_t nbytes ) { @@ -67,24 +69,81 @@ do_write( int fd, void *buf, size_t nbytes ) static int do_read( int fd, void *buf, size_t nbytes ) { - int n, nread = 0; - - do { - do { - n = read(fd, (char*)buf + nread, nbytes ); - } while( n == -1 && errno == EINTR ); - if( n == -1 ) - return -1; - else if( n == 0 ) { - /* EGD probably died. */ - errno = ECONNRESET; - return -1; - } - nread += n; - } while( nread < nbytes ); - return nbytes; + int n, nread = 0; + + while (nbytes) + { + do { + n = read(fd, (char*)buf + nread, nbytes ); + } while( n == -1 && errno == EINTR ); + if( n == -1 ) + return nread? nread:-1; + else if( n == 0 ) { + /* EGD probably died. */ + errno = ECONNRESET; + return -1; + } + nread += n; + nbytes -= n; + } + return nread; } +/* Connect to the EGD and return the file descriptor. Return -1 on + error. With NOFAIL set to true, silently fail and return the + error, otherwise print an error message and die. */ +int +rndegd_connect_socket (int nofail) +{ + int fd; + const char *bname = NULL; + char *name; + struct sockaddr_un addr; + int addr_len; + + if (egd_socket != -1) + { + close (egd_socket); + egd_socket = -1; + } + +#ifdef EGD_SOCKET_NAME + bname = EGD_SOCKET_NAME; +#endif + if ( !bname || !*bname ) + bname = "=entropy"; + + if ( *bname == '=' && bname[1] ) + name = make_filename( g10_opt_homedir, bname+1 , NULL ); + else + name = make_filename( bname , NULL ); + + if ( strlen(name)+1 >= sizeof addr.sun_path ) + g10_log_fatal ("EGD socketname is too long\n"); + + memset( &addr, 0, sizeof addr ); + addr.sun_family = AF_UNIX; + strcpy( addr.sun_path, name ); + addr_len = (offsetof( struct sockaddr_un, sun_path ) + + strlen( addr.sun_path )); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1 && !nofail) + g10_log_fatal("can't create unix domain socket: %s\n", + strerror(errno) ); + else if (connect (fd, (struct sockaddr*)&addr, addr_len) == -1) + { + if (!nofail) + g10_log_fatal("can't connect to `%s': %s\n", + name, strerror(errno) ); + close (fd); + fd = -1; + } + m_free(name); + if (fd != -1) + egd_socket = fd; + return fd; +} /**************** @@ -99,7 +158,7 @@ int rndegd_gather_random( void (*add)(const void*, size_t, int), int requester, size_t length, int level ) { - static int fd = -1; + int fd = egd_socket; int n; byte buffer[256+2]; int nbytes; @@ -111,47 +170,9 @@ rndegd_gather_random( void (*add)(const void*, size_t, int), int requester, return 0; restart: - if( do_restart ) { - if( fd != -1 ) { - close( fd ); - fd = -1; - } - } - if( fd == -1 ) { - const char *bname = NULL; - char *name; - struct sockaddr_un addr; - int addr_len; - - #ifdef EGD_SOCKET_NAME - bname = EGD_SOCKET_NAME; - #endif - if ( !bname || !*bname ) - bname = "=entropy"; + if (fd == -1 || do_restart) + fd = rndegd_connect_socket (0); - if ( *bname == '=' && bname[1] ) - name = make_filename( g10_opt_homedir, bname+1 , NULL ); - else - name = make_filename( bname , NULL ); - - if ( strlen(name)+1 >= sizeof addr.sun_path ) - g10_log_fatal ("EGD socketname is too long\n"); - - memset( &addr, 0, sizeof addr ); - addr.sun_family = AF_UNIX; - strcpy( addr.sun_path, name ); - addr_len = offsetof( struct sockaddr_un, sun_path ) - + strlen( addr.sun_path ); - - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if( fd == -1 ) - g10_log_fatal("can't create unix domain socket: %s\n", - strerror(errno) ); - if( connect( fd, (struct sockaddr*)&addr, addr_len) == -1 ) - g10_log_fatal("can't connect to `%s': %s\n", - name, strerror(errno) ); - m_free(name); - } do_restart = 0; nbytes = length < 255? length : 255;