From: hniksic Date: Thu, 6 Dec 2001 01:13:31 +0000 (-0800) Subject: [svn] Fix OpenSSL PRNG seeding. X-Git-Tag: v1.13~1944 X-Git-Url: http://sjero.net/git/?p=wget;a=commitdiff_plain;h=0620ada92340c150b64129dbdbe646bbec27ea4b [svn] Fix OpenSSL PRNG seeding. Published in . --- diff --git a/src/ChangeLog b/src/ChangeLog index 9620ba74..0fa409a5 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,16 @@ +2001-12-06 Hrvoje Niksic + + * url.c (scheme_disable): New function. + + * main.c (main): Call ssl_init_prng from here rather than from + init_ssl, so that it has a chance to disable support for https + before a URL has been resolved. + + * gen_sslfunc.c (ssl_init_prng): Seed with rand() if all else + failed. + (ssl_init_prng): Disable support for https if seeding the PRNG + fails. + 2001-12-06 Hrvoje Niksic * utils.c (read_whole_line): Handle lines beginning with \0. diff --git a/src/gen_sslfunc.c b/src/gen_sslfunc.c index 4a9ebd17..a782727f 100644 --- a/src/gen_sslfunc.c +++ b/src/gen_sslfunc.c @@ -43,6 +43,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "wget.h" #include "connect.h" +#include "url.h" #ifndef errno extern int errno; @@ -50,57 +51,66 @@ extern int errno; static int verify_callback PARAMS ((int, X509_STORE_CTX *)); -static void +void ssl_init_prng (void) { + /* It is likely that older versions of OpenSSL will fail on + non-Linux machines because this code is unable to seed the PRNG + on older versions of the library. */ + #if SSLEAY_VERSION_NUMBER >= 0x00905100 + char rand_file[256]; + int maxrand = 500; + + /* First, seed from a file specified by the user. This will be + $RANDFILE, if set, or ~/.rnd. */ + RAND_file_name (rand_file, sizeof (rand_file)); + if (rand_file) + /* Seed at most 16k (value borrowed from curl) from random file. */ + RAND_load_file (rand_file, 16384); + + if (RAND_status ()) + return; + + /* Get random data from EGD if opt.sslegdsock was set. */ + if (opt.sslegdsock) + RAND_egd (opt.sslegdsock); + + if (RAND_status ()) + return; + +#ifdef WINDOWS + /* Under Windows, we can try to seed the PRNG using screen content. + This may or may not work, depending on whether we'll calling Wget + interactively. */ + + RAND_screen (); + if (RAND_status ()) + return; +#endif + + /* Still not enough randomness, presumably because neither random + file nor EGD have been available. Use the stupidest possible + method -- seed OpenSSL's PRNG with the system's PRNG. This is + insecure in the cryptographic sense, but people who care about + security will use /dev/random or their own source of randomness + anyway. */ + + srand (time (NULL)); + while (RAND_status () == 0 && maxrand-- > 0) + { + int rnd = rand (); + RAND_seed ((unsigned char *)&rnd, sizeof (rnd)); + } + if (RAND_status () == 0) { - char rand_file[256]; - time_t t; - long l,seed; - - t = time(NULL); - /* gets random data from egd if opt.sslegdsock was set */ - if (opt.sslegdsock != NULL) - RAND_egd(opt.sslegdsock); - /* gets the file ~/.rnd or $RANDFILE if set */ - RAND_file_name(rand_file, 256); - if (rand_file != NULL) - { - /* Seed as much as 1024 bytes from RAND_file_name */ - RAND_load_file(rand_file, 1024); - } - /* Seed in time (mod_ssl does this) */ - RAND_seed((unsigned char *)&t, sizeof(time_t)); - /* Initialize system's random number generator */ - RAND_bytes((unsigned char *)&seed, sizeof(long)); -#ifndef WINDOWS - srand48(seed); - while (RAND_status () == 0) - { - /* Repeatedly seed the PRNG using the system's random number - generator until it has been seeded with enough data. */ - l = lrand48(); - RAND_seed((unsigned char *)&l, sizeof(long)); - } -#else /* WINDOWS */ - RAND_screen(); - if (RAND_status() == 0) - /* Here we should probably disable the whole ssl protocol ? HEH */ - DEBUGP (("SSL random data generator not seeded correctly, %i",RAND_status())); -#endif /* WINDOWS */ - if (rand_file != NULL) - { - /* Write a rand_file */ - RAND_write_file(rand_file); - } + logprintf (LOG_NOTQUIET, "Could not seed OpenSSL PRNG; disabling SSL.\n"); + scheme_disable (SCHEME_HTTPS); } #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */ - return; } - /* Creates a SSL Context and sets some defaults for it */ uerr_t init_ssl (SSL_CTX **ctx) @@ -126,7 +136,6 @@ init_ssl (SSL_CTX **ctx) SSL_FILETYPE_PEM) <= 0) return SSLERRCERTKEY; } - ssl_init_prng(); return 0; /* Succeded */ } diff --git a/src/gen_sslfunc.h b/src/gen_sslfunc.h index 6a12e032..90295fad 100644 --- a/src/gen_sslfunc.h +++ b/src/gen_sslfunc.h @@ -25,7 +25,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ # include #endif +void ssl_init_prng PARAMS ((void)); int init_ssl PARAMS ((SSL_CTX **)); + int connect_ssl PARAMS ((SSL **, SSL_CTX *, int)); void shutdown_ssl PARAMS ((SSL*)); void free_ssl_ctx PARAMS ((SSL_CTX *)); diff --git a/src/main.c b/src/main.c index 0aa46492..cf97cd48 100644 --- a/src/main.c +++ b/src/main.c @@ -53,6 +53,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "url.h" #include "progress.h" /* for progress_handle_sigwinch */ +#ifdef HAVE_SSL +# include "gen_sslfunc.h" +#endif + /* On GNU system this will include system-wide getopt.h. */ #include "getopt.h" @@ -794,8 +798,13 @@ Can't timestamp and not clobber old files at the same time.\n")); #endif #endif /* HAVE_SIGNAL */ +#ifdef HAVE_SSL + /* Must call this before resolving any URLs because it has the power + to disable `https'. */ + ssl_init_prng (); +#endif + status = RETROK; /* initialize it, just-in-case */ - /*recursive_reset ();*/ /* Retrieve the URLs from argument list. */ for (t = url; *t; t++) { diff --git a/src/url.c b/src/url.c index efb65927..5be58fcb 100644 --- a/src/url.c +++ b/src/url.c @@ -54,19 +54,20 @@ struct scheme_data { char *leading_string; int default_port; + int enabled; }; /* Supported schemes: */ static struct scheme_data supported_schemes[] = { - { "http://", DEFAULT_HTTP_PORT }, + { "http://", DEFAULT_HTTP_PORT, 1 }, #ifdef HAVE_SSL - { "https://", DEFAULT_HTTPS_PORT }, + { "https://", DEFAULT_HTTPS_PORT, 1 }, #endif - { "ftp://", DEFAULT_FTP_PORT }, + { "ftp://", DEFAULT_FTP_PORT, 1 }, /* SCHEME_INVALID */ - { NULL, -1 } + { NULL, -1, 0 } }; static char *construct_relative PARAMS ((const char *, const char *)); @@ -420,9 +421,15 @@ url_scheme (const char *url) int i; for (i = 0; supported_schemes[i].leading_string; i++) - if (!strncasecmp (url, supported_schemes[i].leading_string, - strlen (supported_schemes[i].leading_string))) - return (enum url_scheme)i; + if (0 == strncasecmp (url, supported_schemes[i].leading_string, + strlen (supported_schemes[i].leading_string))) + { + if (supported_schemes[i].enabled) + return (enum url_scheme) i; + else + return SCHEME_INVALID; + } + return SCHEME_INVALID; } @@ -466,6 +473,12 @@ scheme_default_port (enum url_scheme scheme) return supported_schemes[scheme].default_port; } +void +scheme_disable (enum url_scheme scheme) +{ + supported_schemes[scheme].enabled = 0; +} + /* Skip the username and password, if present here. The function should be called *not* with the complete URL, but with the part right after the scheme. @@ -606,8 +619,8 @@ lowercase_str (char *str) static char *parse_errors[] = { #define PE_NO_ERROR 0 "No error", -#define PE_UNRECOGNIZED_SCHEME 1 - "Unrecognized scheme", +#define PE_UNSUPPORTED_SCHEME 1 + "Unsupported scheme", #define PE_EMPTY_HOST 2 "Empty host", #define PE_BAD_PORT_NUMBER 3 @@ -650,7 +663,7 @@ url_parse (const char *url, int *error) scheme = url_scheme (url); if (scheme == SCHEME_INVALID) { - SETERR (error, PE_UNRECOGNIZED_SCHEME); + SETERR (error, PE_UNSUPPORTED_SCHEME); return NULL; } diff --git a/src/url.h b/src/url.h index b99c64ce..6d4fdeab 100644 --- a/src/url.h +++ b/src/url.h @@ -133,6 +133,7 @@ enum url_scheme url_scheme PARAMS ((const char *)); int url_skip_scheme PARAMS ((const char *)); int url_has_scheme PARAMS ((const char *)); int scheme_default_port PARAMS ((enum url_scheme)); +void scheme_disable PARAMS ((enum url_scheme)); int url_skip_uname PARAMS ((const char *));