]> sjero.net Git - wget/blobdiff - src/openssl.c
Detect NULs in common name.
[wget] / src / openssl.c
index 03fb1810172b61b1ad4572cb0c05a65e6f7a7952..dd3a62a4ee0cf594f97cc35655be548e259dd3c4 100644 (file)
@@ -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);
     }
@@ -516,7 +524,8 @@ ssl_check_certificate (int fd, const char *host)
       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"),
       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), quote (escnonprint (issuer)));
+                 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,53 @@ 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),
+  X509_NAME_get_text_by_NID (xname,
                              NID_commonName, common_name, sizeof (common_name));
                              NID_commonName, common_name, sizeof (common_name));
+
+  /* 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 [0].
+   *
+   * [0] https://www.blackhat.com/html/bh-usa-09/bh-usa-09-archives.html#Marlinspike
+   * */
+
+  int i=-1,j;
+  if(xname) {
+         for(;(j=X509_NAME_get_index_by_NID (xname, NID_commonName, i))!=-1;i=j);
+  }
+
+  X509_NAME_ENTRY *xentry = X509_NAME_get_entry(xname,i);
+  ASN1_STRING *sdata = X509_NAME_ENTRY_get_data(xentry);
+
+  if (strlen(common_name) != ASN1_STRING_length(sdata)) 
+    {
+      logprintf (LOG_NOTQUIET, _("\
+%s: certificate common name is invalid. It is possible that someone is \
+eavesdropping on you (man-in-the-middle attack)!\n"),
+                 severity);
+      success = false;
+    }
+
   if (!pattern_match (common_name, host))
     {
       logprintf (LOG_NOTQUIET, _("\
 %s: certificate common name %s doesn't match requested host name %s.\n"),
   if (!pattern_match (common_name, host))
     {
       logprintf (LOG_NOTQUIET, _("\
 %s: certificate common name %s doesn't match requested host name %s.\n"),
-                 severity, quote (escnonprint (common_name)), quote (escnonprint (host)));
+                 severity, quote (common_name), quote (host));
       success = false;
     }
 
   if (success)
     DEBUGP (("X509 certificate successfully verified and matches host %s\n",
       success = false;
     }
 
   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;