--random-file

Hrvoje Niksic <[email protected]>
Newsgroups gmane.comp.web.wget.patches
Message-ID <[email protected]>
While working on SSL options, I noticed that we were using insecure
random seeding by default.  This patch introduces a --random-file
option, a la curl, which may be used to select an explicit file with
external randomness.  This patch disables insecure seeds (leaving them
ifdeffed out in the code), but hints the user to use --random-file
when seeding is a problem.

The patch also makes Wget exit upon encountering serious problems with
certificates and such.  It makes little sense to keep going in that
case, even when a warning is printed.  Think Jan Minar.  :-)

The certificate validation code is still badly in need of auditing.
Anyone?

The patch should not affect non-SSL usage.  Update to the manual
follows RSN.


2005-04-27  Hrvoje Niksic  <[email protected]>

	* openssl.c (init_prng): Disable the weak random seed by default.

	* http.c (gethttp): Simplify SSL initialization; disable SSL when
	anything goes wrong with the initialization.

	* options.h (struct options): New option opt.random_file.

Index: src/http.c
===================================================================
RCS file: /pack/anoncvs/wget/src/http.c,v
retrieving revision 1.168
diff -u -r1.168 http.c
--- src/http.c	2005/04/27 17:15:09	1.168
+++ src/http.c	2005/04/27 21:02:31
@@ -1187,29 +1187,12 @@
     {
       /* Initialize the SSL context.  After this has once been done,
 	 it becomes a no-op.  */
-      switch (ssl_init ())
+      if (!ssl_init ())
 	{
-	case SSLERRCTXCREATE:
-	  /* this is fatal */
-	  logprintf (LOG_NOTQUIET, _("Failed to set up an SSL context\n"));
-	  return SSLERRCTXCREATE;
-	case SSLERRCERTFILE:
-	  /* try without certfile */
+	  scheme_disable (SCHEME_HTTPS);
 	  logprintf (LOG_NOTQUIET,
-		     _("Failed to load certificates from %s\n"),
-		     opt.cert_file);
-	  logprintf (LOG_NOTQUIET,
-		     _("Trying without the specified certificate\n"));
-	  break;
-	case SSLERRCERTKEY:
-	  logprintf (LOG_NOTQUIET,
-		     _("Failed to get private key from %s\n"),
-		     opt.private_key);
-	  logprintf (LOG_NOTQUIET,
-		     _("Trying without the specified certificate\n"));
-	  break;
-	default:
-	  break;
+		     _("Disabling SSL due to encountered errors.\n"));
+	  return SSLINITFAILED;
 	}
     }
 #endif /* HAVE_SSL */
@@ -2232,7 +2215,7 @@
 	  continue;
 	  break;
 	case HOSTERR: case CONIMPOSSIBLE: case PROXERR: case AUTHFAILED: 
-	case SSLERRCTXCREATE: case CONTNOTSUPPORTED:
+	case SSLINITFAILED: case CONTNOTSUPPORTED:
 	  /* Fatal errors just return from the function.  */
 	  free_hstat (&hstat);
 	  xfree_null (dummy);
Index: src/init.c
===================================================================
RCS file: /pack/anoncvs/wget/src/init.c,v
retrieving revision 1.106
diff -u -r1.106 init.c
--- src/init.c	2005/04/27 18:27:57	1.106
+++ src/init.c	2005/04/27 21:02:33
@@ -205,6 +205,7 @@
   { "proxyuser",	&opt.proxy_user,	cmd_string },
   { "quiet",		&opt.quiet,		cmd_boolean },
   { "quota",		&opt.quota,		cmd_bytes_large },
+  { "randomfile",	&opt.random_file,	cmd_file },
   { "randomwait",	&opt.random_wait,	cmd_boolean },
   { "readtimeout",	&opt.read_timeout,	cmd_time },
   { "reclevel",		&opt.reclevel,		cmd_number_inf },
Index: src/main.c
===================================================================
RCS file: /pack/anoncvs/wget/src/main.c,v
retrieving revision 1.130
diff -u -r1.130 main.c
--- src/main.c	2005/04/27 17:15:10	1.130
+++ src/main.c	2005/04/27 21:02:35
@@ -231,6 +231,7 @@
     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
     { "quota", 'Q', OPT_VALUE, "quota", -1 },
+    { "random-file", 0, OPT_VALUE, "randomfile", -1 },
     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
@@ -552,7 +553,9 @@
     N_("\
        --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
     N_("\
-       --egd-file=FILE          file name of the EGD socket.\n"),
+       --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
+    N_("\
+       --egd-file=FILE          file naming the EGD socket with random data.\n"),
     "\n",
 #endif /* HAVE_SSL */
 
Index: src/openssl.c
===================================================================
RCS file: /pack/anoncvs/wget/src/openssl.c,v
retrieving revision 1.2
diff -u -r1.2 openssl.c
--- src/openssl.c	2005/04/27 17:15:10	1.2
+++ src/openssl.c	2005/04/27 21:02:35
@@ -59,29 +59,43 @@
 extern int errno;
 #endif
 
+/* Application-wide SSL context.  This is common to all SSL
+   connections.  */
 SSL_CTX *ssl_ctx;
 
+/* Initialize the SSL's PRNG using various methods. */
+
 static void
-ssl_init_prng (void)
+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];
-
-  /* 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);
+  char namebuf[256];
+  const char *random_file;
+
+  if (RAND_status ())
+    /* The PRNG has been seeded; no further action is necessary. */
+    return;
+
+  /* Seed from a file specified by the user.  This will be the file
+     specified with --random-file, $RANDFILE, if set, or ~/.rnd, if it
+     exists.  */
+  if (opt.random_file)
+    random_file = opt.random_file;
+  else
+    {
+      /* Get the random file name using RAND_file_name. */
+      namebuf[0] = '\0';
+      random_file = RAND_file_name (namebuf, sizeof (namebuf));
+    }
+
+  if (random_file && *random_file)
+    /* Seed at most 16k (apparently arbitrary value borrowed from
+       curl) from random file. */
+    RAND_load_file (random_file, 16384);
 
   if (RAND_status ())
     return;
 
-  /* Get random data from EGD if opt.egd_file was set.  */
+  /* Get random data from EGD if opt.egd_file was used.  */
   if (opt.egd_file && *opt.egd_file)
     RAND_egd (opt.egd_file);
 
@@ -107,7 +121,7 @@
        PRNG.  This is cryptographically weak and defeats the purpose
        of using OpenSSL, which is why it is highly discouraged.  */
 
-    logprintf (LOG_VERBOSE, _("WARNING: using a weak random seed.\n"));
+    logprintf (LOG_NOTQUIET, _("WARNING: using a weak random seed.\n"));
 
     while (RAND_status () == 0 && maxrand-- > 0)
       {
@@ -116,16 +130,17 @@
       }
   }
 #endif
-
-#endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
 }
 
+/* #### Someone should audit and document this. */
+
 static int
 verify_callback (int ok, X509_STORE_CTX *ctx)
 {
-  char *s, buf[256];
-  s = X509_NAME_oneline (X509_get_subject_name (ctx->current_cert),
-			 buf, sizeof (buf));
+  char buf[256];
+  /* #### Why are we not using the result of this call? */
+  X509_NAME_oneline (X509_get_subject_name (ctx->current_cert),
+		     buf, sizeof (buf));
   if (ok == 0)
     {
       switch (ctx->error)
@@ -144,10 +159,10 @@
   return ok;
 }
 
-/* Print SSL errors. */
+/* Print errors in the OpenSSL error stack. */
 
 static void
-ssl_print_errors (void) 
+print_errors (void) 
 {
   unsigned long curerr = 0;
   while ((curerr = ERR_get_error ()) != 0)
@@ -173,30 +188,35 @@
       abort ();
     }
 }
+
+/* Create an SSL Context and set default paths etc.  Called the first
+   time an HTTP download is attempted.
+
+   Returns 0 on success, non-zero otherwise.  */
 
-/* Creates a SSL Context and sets some defaults for it */
-uerr_t
+int
 ssl_init ()
 {
-  SSL_METHOD *meth = NULL;
+  SSL_METHOD *meth;
 
   if (ssl_ctx)
-    return 0;
+    /* The SSL has already been initialized. */
+    return 1;
 
   /* Init the PRNG.  If that fails, bail out.  */
-  ssl_init_prng ();
-  if (RAND_status () == 0)
+  init_prng ();
+  if (RAND_status () != 1)
     {
       logprintf (LOG_NOTQUIET,
-		 _("Could not seed OpenSSL PRNG; disabling SSL.\n"));
-      scheme_disable (SCHEME_HTTPS);
-      return SSLERRCTXCREATE;
+		 _("Could not seed PRNG; consider using --random-file.\n"));
+      goto error;
     }
 
   SSL_library_init ();
   SSL_load_error_strings ();
   SSLeay_add_all_algorithms ();
   SSLeay_add_ssl_algorithms ();
+
   switch (opt.secure_protocol)
     {
     case secure_protocol_auto:
@@ -216,6 +236,9 @@
     }
 
   ssl_ctx = SSL_CTX_new (meth);
+  if (!ssl_ctx)
+    goto error;
+
   SSL_CTX_set_default_verify_paths (ssl_ctx);
   SSL_CTX_load_verify_locations (ssl_ctx, opt.ca_cert, opt.ca_directory);
   SSL_CTX_set_verify (ssl_ctx,
@@ -226,24 +249,24 @@
     if (SSL_CTX_use_certificate_file (ssl_ctx, opt.cert_file,
 				      key_type_to_ssl_type (opt.cert_type))
 	!= 1)
-      {
-	ssl_print_errors ();
-	return SSLERRCERTFILE;
-      }
+      goto error;
   if (opt.private_key)
     if (SSL_CTX_use_PrivateKey_file (ssl_ctx, opt.private_key,
 				     key_type_to_ssl_type (opt.private_key_type))
 	!= 1)
-      {
-	ssl_print_errors ();
-	return SSLERRCERTKEY;
-      }
+      goto error;
 
-  return 0; /* Succeded */
+  return 1;
+
+ error:
+  if (ssl_ctx)
+    SSL_CTX_free (ssl_ctx);
+  print_errors ();
+  return 0;
 }
 
 static int
-ssl_read (int fd, char *buf, int bufsize, void *ctx)
+openssl_read (int fd, char *buf, int bufsize, void *ctx)
 {
   int ret;
   SSL *ssl = (SSL *) ctx;
@@ -256,7 +279,7 @@
 }
 
 static int
-ssl_write (int fd, char *buf, int bufsize, void *ctx)
+openssl_write (int fd, char *buf, int bufsize, void *ctx)
 {
   int ret = 0;
   SSL *ssl = (SSL *) ctx;
@@ -269,7 +292,7 @@
 }
 
 static int
-ssl_poll (int fd, double timeout, int wait_for, void *ctx)
+openssl_poll (int fd, double timeout, int wait_for, void *ctx)
 {
   SSL *ssl = (SSL *) ctx;
   if (timeout == 0)
@@ -280,7 +303,7 @@
 }
 
 static int
-ssl_peek (int fd, char *buf, int bufsize, void *ctx)
+openssl_peek (int fd, char *buf, int bufsize, void *ctx)
 {
   int ret;
   SSL *ssl = (SSL *) ctx;
@@ -293,7 +316,7 @@
 }
 
 static void
-ssl_close (int fd, void *ctx)
+openssl_close (int fd, void *ctx)
 {
   SSL *ssl = (SSL *) ctx;
   SSL_shutdown (ssl);
@@ -332,16 +355,16 @@
 
   /* Register FD with Wget's transport layer, i.e. arrange that
      SSL-enabled functions are used for reading, writing, and polling.
-     That way the rest of Wget can keep using xread, xwrite, and
+     That way the rest of Wget can keep using fd_read, fd_write, and
      friends and not care what happens underneath.  */
-  fd_register_transport (fd, ssl_read, ssl_write, ssl_poll, ssl_peek,
-			 ssl_close, ssl);
+  fd_register_transport (fd, openssl_read, openssl_write, openssl_poll,
+			 openssl_peek, openssl_close, ssl);
   DEBUGP (("Connected %d to SSL 0x%0*lx\n", fd, 2 * sizeof (void *),
 	   (unsigned long) ssl));
   return 1;
 
  err:
-  ssl_print_errors ();
+  print_errors ();
   if (ssl)
     SSL_free (ssl);
   return 0;
Index: src/options.h
===================================================================
RCS file: /pack/anoncvs/wget/src/options.h,v
retrieving revision 1.50
diff -u -r1.50 options.h
--- src/options.h	2005/04/27 17:15:10	1.50
+++ src/options.h	2005/04/27 21:02:36
@@ -179,6 +179,7 @@
   char *ca_cert;		/* CA certificate file to use */
 
 
+  char *random_file;		/* file with random data to seed the PRNG */
   char *egd_file;		/* file name of the egd daemon socket */
 #endif /* HAVE_SSL */
 
Index: src/ssl.h
===================================================================
RCS file: /pack/anoncvs/wget/src/ssl.h,v
retrieving revision 1.1
diff -u -r1.1 ssl.h
--- src/ssl.h	2005/04/26 21:41:38	1.1
+++ src/ssl.h	2005/04/27 21:02:36
@@ -31,7 +31,7 @@
 #ifndef GEN_SSLFUNC_H
 #define GEN_SSLFUNC_H
 
-uerr_t ssl_init PARAMS ((void));
+int ssl_init PARAMS ((void));
 int ssl_connect PARAMS ((int));
 
 #endif /* GEN_SSLFUNC_H */
Index: src/wget.h
===================================================================
RCS file: /pack/anoncvs/wget/src/wget.h,v
retrieving revision 1.56
diff -u -r1.56 wget.h
--- src/wget.h	2005/04/10 19:54:02	1.56
+++ src/wget.h	2005/04/27 21:02:36
@@ -252,8 +252,7 @@
   CONTNOTSUPPORTED, RETRUNNEEDED, RETRFINISHED, READERR, TRYLIMEXC,
   URLBADPATTERN, FILEBADFILE, RANGEERR, RETRBADPATTERN,
   RETNOTSUP, ROBOTSOK, NOROBOTS, PROXERR, AUTHFAILED,
-  QUOTEXC, WRITEFAILED,
-  SSLERRCERTFILE,SSLERRCERTKEY,SSLERRCTXCREATE
+  QUOTEXC, WRITEFAILED, SSLINITFAILED
 } uerr_t;
 
 #endif /* WGET_H */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.