[svn] Fix OpenSSL PRNG seeding.

Published in <sxs7ks1noc4.fsf@florida.arsdigita.de>.
This commit is contained in:
hniksic 2001-12-05 17:13:31 -08:00
parent b248bfe395
commit 0620ada923
6 changed files with 101 additions and 54 deletions

View File

@ -1,3 +1,16 @@
2001-12-06 Hrvoje Niksic <hniksic@arsdigita.com>
* 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 <hniksic@arsdigita.com>
* utils.c (read_whole_line): Handle lines beginning with \0.

View File

@ -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 */
}

View File

@ -25,7 +25,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
# include <openssl/ssl.h>
#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 *));

View File

@ -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++)
{

View File

@ -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;
}

View File

@ -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 *));