]> sjero.net Git - wget/blobdiff - src/openssl.c
Only warn of attack if the hostname would have matched.
[wget] / src / openssl.c
index 143271e0c2b74060b7be68ccb263cd39c28ce329..de335c086a021aec355014f7a7aa25b1bbaece93 100644 (file)
@@ -1,6 +1,6 @@
 /* SSL support via OpenSSL library.
 /* SSL support via OpenSSL library.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free
-   Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+   2008 Free Software Foundation, Inc.
    Originally contributed by Christian Fraenkel.
 
 This file is part of GNU Wget.
    Originally contributed by Christian Fraenkel.
 
 This file is part of GNU Wget.
@@ -210,6 +210,13 @@ ssl_init ()
      than examining the error stack after a failed SSL_connect.  */
   SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_NONE, NULL);
 
      than examining the error stack after a failed SSL_connect.  */
   SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_NONE, NULL);
 
+  /* Use the private key from the cert file unless otherwise specified. */
+  if (opt.cert_file && !opt.private_key)
+    {
+      opt.private_key = opt.cert_file;
+      opt.private_key_type = opt.cert_type;
+    }
+
   if (opt.cert_file)
     if (SSL_CTX_use_certificate_file (ssl_ctx, opt.cert_file,
                                       key_type_to_ssl_type (opt.cert_type))
   if (opt.cert_file)
     if (SSL_CTX_use_certificate_file (ssl_ctx, opt.cert_file,
                                       key_type_to_ssl_type (opt.cert_type))
@@ -383,7 +390,7 @@ static struct transport_implementation openssl_transport = {
    Returns true on success, false on failure.  */
 
 bool
    Returns true on success, false on failure.  */
 
 bool
-ssl_connect (int fd) 
+ssl_connect_wget (int fd) 
 {
   SSL *conn;
   struct openssl_transport_context *ctx;
 {
   SSL *conn;
   struct openssl_transport_context *ctx;
@@ -466,7 +473,7 @@ pattern_match (const char *pattern, const char *string)
    its certificate, corresponds to HOST.  (HOST typically comes from
    the URL and is what the user thinks he's connecting to.)
 
    its certificate, corresponds to HOST.  (HOST typically comes from
    the URL and is what the user thinks he's connecting to.)
 
-   This assumes that ssl_connect has successfully finished, i.e. that
+   This assumes that ssl_connect_wget has successfully finished, i.e. that
    the SSL handshake has been performed and that FD is connected to an
    SSL handle.
 
    the SSL handshake has been performed and that FD is connected to an
    SSL handle.
 
@@ -495,7 +502,7 @@ ssl_check_certificate (int fd, const char *host)
   if (!cert)
     {
       logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
   if (!cert)
     {
       logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
-                 severity, escnonprint (host));
+                 severity, quotearg_style (escape_quoting_style, host));
       success = false;
       goto no_cert;             /* must bail out since CERT is NULL */
     }
       success = false;
       goto no_cert;             /* must bail out since CERT is NULL */
     }
@@ -505,7 +512,8 @@ ssl_check_certificate (int fd, const char *host)
       char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0);
       char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
       DEBUGP (("certificate:\n  subject: %s\n  issuer:  %s\n",
       char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0);
       char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
       DEBUGP (("certificate:\n  subject: %s\n  issuer:  %s\n",
-               escnonprint (subject), escnonprint (issuer)));
+               quotearg_style (escape_quoting_style, subject), 
+               quotearg_style (escape_quoting_style, issuer)));
       OPENSSL_free (subject);
       OPENSSL_free (issuer);
     }
       OPENSSL_free (subject);
       OPENSSL_free (issuer);
     }
@@ -515,8 +523,9 @@ ssl_check_certificate (int fd, const char *host)
     {
       char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
       logprintf (LOG_NOTQUIET,
     {
       char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
       logprintf (LOG_NOTQUIET,
-                 _("%s: cannot verify %s's certificate, issued by `%s':\n"),
-                 severity, escnonprint (host), escnonprint (issuer));
+                 _("%s: cannot verify %s's certificate, issued by %s:\n"),
+                 severity, quotearg_style (escape_quoting_style, host), 
+                 quote (issuer));
       /* Try to print more user-friendly (and translated) messages for
          the frequent verification errors.  */
       switch (vresult)
       /* Try to print more user-friendly (and translated) messages for
          the frequent verification errors.  */
       switch (vresult)
@@ -560,27 +569,64 @@ ssl_check_certificate (int fd, const char *host)
      - Ensure that ASN1 strings from the certificate are encoded as
        UTF-8 which can be meaningfully compared to HOST.  */
 
      - Ensure that ASN1 strings from the certificate are encoded as
        UTF-8 which can be meaningfully compared to HOST.  */
 
+  X509_NAME *xname = X509_get_subject_name(cert);
   common_name[0] = '\0';
   common_name[0] = '\0';
-  X509_NAME_get_text_by_NID (X509_get_subject_name (cert),
-                             NID_commonName, common_name, sizeof (common_name));
+  X509_NAME_get_text_by_NID (xname, NID_commonName, common_name,
+                             sizeof (common_name));
+
   if (!pattern_match (common_name, host))
     {
       logprintf (LOG_NOTQUIET, _("\
   if (!pattern_match (common_name, host))
     {
       logprintf (LOG_NOTQUIET, _("\
-%s: certificate common name `%s' doesn't match requested host name `%s'.\n"),
-                 severity, escnonprint (common_name), escnonprint (host));
+%s: certificate common name %s doesn't match requested host name %s.\n"),
+                 severity, quote (common_name), quote (host));
       success = false;
     }
       success = false;
     }
+  else
+    {
+      /* We now determine the length of the ASN1 string. If it differs from
+       * common_name's length, then there is a \0 before the string terminates.
+       * This can be an instance of a null-prefix attack.
+       *
+       * https://www.blackhat.com/html/bh-usa-09/bh-usa-09-archives.html#Marlinspike
+       * */
+
+      int i = -1, j;
+      X509_NAME_ENTRY *xentry;
+      ASN1_STRING *sdata;
+
+      if (xname) {
+        for (;;)
+          {
+            j = X509_NAME_get_index_by_NID (xname, NID_commonName, i);
+            if (j == -1) break;
+            i = j;
+          }
+      }
+
+      xentry = X509_NAME_get_entry(xname,i);
+      sdata = X509_NAME_ENTRY_get_data(xentry);
+      if (strlen (common_name) != ASN1_STRING_length (sdata)) 
+        {
+          logprintf (LOG_NOTQUIET, _("\
+%s: certificate common name is invalid (contains a NUL character).\n\
+This may be an indication that the host is not who it claims to be\n\
+(that is, it is not the real %s).\n"),
+                     severity, quote (host));
+          success = false;
+        }
+    }
+  
 
   if (success)
     DEBUGP (("X509 certificate successfully verified and matches host %s\n",
 
   if (success)
     DEBUGP (("X509 certificate successfully verified and matches host %s\n",
-             escnonprint (host)));
+             quotearg_style (escape_quoting_style, host)));
   X509_free (cert);
 
  no_cert:
   if (opt.check_cert && !success)
     logprintf (LOG_NOTQUIET, _("\
 To connect to %s insecurely, use `--no-check-certificate'.\n"),
   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));
+               quotearg_style (escape_quoting_style, host));
 
   /* Allow --no-check-cert to disable certificate checking. */
   return opt.check_cert ? success : true;
 
   /* Allow --no-check-cert to disable certificate checking. */
   return opt.check_cert ? success : true;