]> sjero.net Git - wget/blobdiff - src/openssl.c
Follow RFC 2616 and httpbis specifications when handling redirects
[wget] / src / openssl.c
index 4eef5c6c49c82efa3510da3ce6c005cd50068d0c..3924e41ea19e9cf7af2c7b0e6296206753d1e789 100644 (file)
@@ -1,6 +1,6 @@
 /* SSL support via OpenSSL library.
    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009 Free Software Foundation, Inc.
+   2009, 2010, 2011, 2012 Free Software Foundation, Inc.
    Originally contributed by Christian Fraenkel.
 
 This file is part of GNU Wget.
@@ -33,9 +33,7 @@ as that of the covered work.  */
 
 #include <assert.h>
 #include <errno.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
+#include <unistd.h>
 #include <string.h>
 
 #include <openssl/ssl.h>
@@ -48,6 +46,10 @@ as that of the covered work.  */
 #include "url.h"
 #include "ssl.h"
 
+#ifdef WINDOWS
+# include <w32sock.h>
+#endif
+
 /* Application-wide SSL context.  This is common to all SSL
    connections.  */
 static SSL_CTX *ssl_ctx;
@@ -157,9 +159,9 @@ key_type_to_ssl_type (enum keyfile_type type)
    Returns true on success, false otherwise.  */
 
 bool
-ssl_init ()
+ssl_init (void)
 {
-  SSL_METHOD *meth;
+  SSL_METHOD const *meth;
 
   if (ssl_ctx)
     /* The SSL has already been initialized. */
@@ -184,9 +186,11 @@ ssl_init ()
     case secure_protocol_auto:
       meth = SSLv23_client_method ();
       break;
+#ifndef OPENSSL_NO_SSL2
     case secure_protocol_sslv2:
       meth = SSLv2_client_method ();
       break;
+#endif
     case secure_protocol_sslv3:
       meth = SSLv3_client_method ();
       break;
@@ -197,7 +201,9 @@ ssl_init ()
       abort ();
     }
 
-  ssl_ctx = SSL_CTX_new (meth);
+  /* The type cast below accommodates older OpenSSL versions (0.9.8)
+     where SSL_CTX_new() is declared without a "const" argument. */
+  ssl_ctx = SSL_CTX_new ((SSL_METHOD *)meth);
   if (!ssl_ctx)
     goto error;
 
@@ -261,6 +267,7 @@ openssl_read (int fd, char *buf, int bufsize, void *arg)
   while (ret == -1
          && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
          && errno == EINTR);
+
   return ret;
 }
 
@@ -283,10 +290,10 @@ openssl_poll (int fd, double timeout, int wait_for, void *arg)
 {
   struct openssl_transport_context *ctx = arg;
   SSL *conn = ctx->conn;
-  if (timeout == 0)
-    return 1;
   if (SSL_pending (conn))
     return 1;
+  if (timeout == 0)
+    return 1;
   return select_fd (fd, timeout, wait_for);
 }
 
@@ -296,6 +303,8 @@ openssl_peek (int fd, char *buf, int bufsize, void *arg)
   int ret;
   struct openssl_transport_context *ctx = arg;
   SSL *conn = ctx->conn;
+  if (! openssl_poll (fd, 0.0, WAIT_FOR_READ, arg))
+    return 0;
   do
     ret = SSL_peek (conn, buf, bufsize);
   while (ret == -1
@@ -364,11 +373,7 @@ openssl_close (int fd, void *arg)
   xfree_null (ctx->last_error);
   xfree (ctx);
 
-#if defined(WINDOWS) || defined(USE_WATT32)
-  closesocket (fd);
-#else
   close (fd);
-#endif
 
   DEBUGP (("Closed %d/SSL 0x%0*lx\n", fd, PTR_FORMAT (conn)));
 }
@@ -390,7 +395,7 @@ static struct transport_implementation openssl_transport = {
    Returns true on success, false on failure.  */
 
 bool
-ssl_connect_wget (int fd)
+ssl_connect_wget (int fd, const char *hostname)
 {
   SSL *conn;
   struct openssl_transport_context *ctx;
@@ -401,7 +406,23 @@ ssl_connect_wget (int fd)
   conn = SSL_new (ssl_ctx);
   if (!conn)
     goto error;
-  if (!SSL_set_fd (conn, fd))
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+  /* If the SSL library was build with support for ServerNameIndication
+     then use it whenever we have a hostname.  If not, don't, ever. */
+  if (! is_valid_ip_address (hostname))
+    {
+      if (! SSL_set_tlsext_host_name (conn, hostname))
+       {
+       DEBUGP (("Failed to set TLS server-name indication."));
+       goto error;
+       }
+    }
+#endif
+
+#ifndef FD_TO_SOCKET
+# define FD_TO_SOCKET(X) (X)
+#endif
+  if (!SSL_set_fd (conn, FD_TO_SOCKET (fd)))
     goto error;
   SSL_set_connect_state (conn);
   if (SSL_connect (conn) <= 0 || conn->state != SSL_ST_OK)
@@ -576,8 +597,7 @@ ssl_check_certificate (int fd, const char *host)
 
       /* Do we want to check for dNSNAmes or ipAddresses (see RFC 2818)?
        * Signal it by host_in_octet_string. */
-      ASN1_OCTET_STRING *host_in_octet_string = NULL;
-      host_in_octet_string = a2i_IPADDRESS (host);
+      ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (host);
 
       int numaltnames = sk_GENERAL_NAME_num (subjectAltNames);
       int i;
@@ -602,11 +622,13 @@ ssl_check_certificate (int fd, const char *host)
                 }
               else if (name->type == GEN_DNS)
                 {
-                  /* Check for dNSName */
-                  alt_name_checked = true;
                   /* dNSName should be IA5String (i.e. ASCII), however who
                    * does trust CA? Convert it into UTF-8 for sure. */
                   unsigned char *name_in_utf8 = NULL;
+
+                  /* Check for dNSName */
+                  alt_name_checked = true;
+
                   if (0 <= ASN1_STRING_to_UTF8 (&name_in_utf8, name->d.dNSName))
                     {
                       /* Compare and check for NULL attack in ASN1_STRING */