]> sjero.net Git - wget/blobdiff - src/openssl.c
[svn] Move extern declarations to .h files.
[wget] / src / openssl.c
index d459dd653a7ff15683111b395fddc9665d0e28a8..75011af7ccc988888c37849664c095453426a977 100644 (file)
@@ -35,11 +35,7 @@ so, delete this exception statement from your version.  */
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif
+#include <string.h>
 
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
@@ -52,13 +48,9 @@ so, delete this exception statement from your version.  */
 #include "url.h"
 #include "ssl.h"
 
-#ifndef errno
-extern int errno;
-#endif
-
 /* Application-wide SSL context.  This is common to all SSL
    connections.  */
-SSL_CTX *ssl_ctx;
+static SSL_CTX *ssl_ctx;
 
 /* Initialize the SSL's PRNG using various methods. */
 
@@ -162,16 +154,16 @@ key_type_to_ssl_type (enum keyfile_type type)
 /* Create an SSL Context and set default paths etc.  Called the first
    time an HTTP download is attempted.
 
-   Returns 1 on success, 0 otherwise.  */
+   Returns true on success, false otherwise.  */
 
-int
+bool
 ssl_init ()
 {
   SSL_METHOD *meth;
 
   if (ssl_ctx)
     /* The SSL has already been initialized. */
-    return 1;
+    return true;
 
   /* Init the PRNG.  If that fails, bail out.  */
   init_prng ();
@@ -233,13 +225,13 @@ ssl_init ()
      handles them correctly), allow them in OpenSSL.  */
   SSL_CTX_set_mode (ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
 
-  return 1;
+  return true;
 
  error:
   if (ssl_ctx)
     SSL_CTX_free (ssl_ctx);
   print_errors ();
-  return 0;
+  return false;
 }
 
 static int
@@ -314,13 +306,15 @@ openssl_close (int fd, void *ctx)
    fd_register_transport, so that subsequent calls to fd_read,
    fd_write, etc., will use the corresponding SSL functions.
 
-   Returns 1 on success, 0 on failure.  */
+   Returns true on success, false on failure.  */
 
-int
+bool
 ssl_connect (int fd) 
 {
   SSL *ssl;
 
+  DEBUGP (("Initiating SSL handshake.\n"));
+
   assert (ssl_ctx != NULL);
   ssl = SSL_new (ssl_ctx);
   if (!ssl)
@@ -335,20 +329,21 @@ ssl_connect (int fd)
      functions are used for reading, writing, and polling.  */
   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;
+  DEBUGP (("Handshake successful; connected socket %d to SSL handle 0x%0*lx\n",
+          fd, PTR_FORMAT (ssl)));
+  return true;
 
  error:
+  DEBUGP (("SSL handshake failed.\n"));
   print_errors ();
   if (ssl)
     SSL_free (ssl);
-  return 0;
+  return false;
 }
 
 #define ASTERISK_EXCLUDES_DOT  /* mandated by rfc2818 */
 
-/* Return 1 is STRING (case-insensitively) matches PATTERN, 0
+/* Return true is STRING (case-insensitively) matches PATTERN, false
    otherwise.  The recognized wildcard character is "*", which matches
    any character in STRING except ".".  Any number of the "*" wildcard
    may be present in the pattern.
@@ -362,7 +357,7 @@ ssl_connect (int fd)
    If the pattern contain no wildcards, pattern_match(a, b) is
    equivalent to !strcasecmp(a, b).  */
 
-static int
+static bool
 pattern_match (const char *pattern, const char *string)
 {
   const char *p = pattern, *n = string;
@@ -374,17 +369,17 @@ pattern_match (const char *pattern, const char *string)
          ;
        for (; *n != '\0'; n++)
          if (TOLOWER (*n) == c && pattern_match (p, n))
-           return 1;
+           return true;
 #ifdef ASTERISK_EXCLUDES_DOT
          else if (*n == '.')
-           return 0;
+           return false;
 #endif
        return c == '\0';
       }
     else
       {
        if (c != TOLOWER (*n))
-         return 0;
+         return false;
       }
   return *n == '\0';
 }
@@ -398,18 +393,18 @@ pattern_match (const char *pattern, const char *string)
    the SSL handshake has been performed and that FD is connected to an
    SSL handle.
 
-   If opt.check_cert is non-zero (the default), this returns 1 if the
+   If opt.check_cert is true (the default), this returns 1 if the
    certificate is valid, 0 otherwise.  If opt.check_cert is 0, the
    function always returns 1, but should still be called because it
    warns the user about any problems with the certificate.  */
 
-int
+bool
 ssl_check_certificate (int fd, const char *host)
 {
   X509 *cert;
   char common_name[256];
   long vresult;
-  int success;
+  bool success = true;
 
   /* If the user has specified --no-check-cert, we still want to warn
      him about problems with the server's certificate.  */
@@ -423,12 +418,11 @@ ssl_check_certificate (int fd, const char *host)
     {
       logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
                 severity, escnonprint (host));
-      success = 0;
-      goto out;
+      success = false;
+      goto no_cert;            /* must bail out since CERT is NULL */
     }
 
-#ifdef ENABLE_DEBUG
-  if (opt.debug)
+  IF_DEBUG
     {
       char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0);
       char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
@@ -437,17 +431,26 @@ ssl_check_certificate (int fd, const char *host)
       OPENSSL_free (subject);
       OPENSSL_free (issuer);
     }
-#endif
 
   vresult = SSL_get_verify_result (ssl);
   if (vresult != X509_V_OK)
     {
+      /* #### We might want to print saner (and translatable) error
+        messages for several frequently encountered errors.  The
+        candidates would include
+        X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
+        X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
+        X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
+        X509_V_ERR_CERT_NOT_YET_VALID, X509_V_ERR_CERT_HAS_EXPIRED,
+        and possibly others.  The current approach would still be
+        used for the less frequent failure cases.  */
       logprintf (LOG_NOTQUIET,
                 _("%s: Certificate verification error for %s: %s\n"),
                 severity, escnonprint (host),
                 X509_verify_cert_error_string (vresult));
-      success = 0;
-      goto out;
+      success = false;
+      /* Fall through, so that the user is warned about *all* issues
+        with the cert (important with --no-check-certificate.)  */
     }
 
   /* Check that HOST matches the common name in the certificate.
@@ -461,8 +464,8 @@ ssl_check_certificate (int fd, const char *host)
        common names and choose the most specific one, i.e. the last
        one, not the first one, which the current code picks.
 
-     - Make sure that the names are encoded as UTF-8 which, being
-       ASCII-compatible, can be easily compared against HOST.  */
+     - Ensure that ASN1 strings from the certificate are encoded as
+       UTF-8 which can be meaningfully compared to HOST.  */
 
   common_name[0] = '\0';
   X509_NAME_get_text_by_NID (X509_get_subject_name (cert),
@@ -472,22 +475,20 @@ ssl_check_certificate (int fd, const char *host)
       logprintf (LOG_NOTQUIET, _("\
 %s: certificate common name `%s' doesn't match requested host name `%s'.\n"),
                 severity, escnonprint (common_name), escnonprint (host));
-      success = 0;
-      goto out;
+      success = false;
     }
 
-  /* The certificate was found, verified, and matched HOST. */
-  success = 1;
-
- out:
-  if (cert)
-    X509_free (cert);
+  if (success)
+    DEBUGP (("X509 certificate successfully verified and matches host %s\n",
+            escnonprint (host)));
+  X509_free (cert);
 
+ no_cert:
   if (opt.check_cert && !success)
     logprintf (LOG_NOTQUIET, _("\
 To connect to %s insecurely, use `--no-check-certificate'.\n"),
               escnonprint (host));
 
   /* Allow --no-check-cert to disable certificate checking. */
-  return opt.check_cert ? success : 1;
+  return opt.check_cert ? success : true;
 }