]> sjero.net Git - wget/blobdiff - src/openssl.c
Only warn of attack if the hostname would have matched.
[wget] / src / openssl.c
index f5239ede6e8f0b478a81625261a805165e13403c..de335c086a021aec355014f7a7aa25b1bbaece93 100644 (file)
@@ -390,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;
@@ -473,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.
 
@@ -569,9 +569,11 @@ 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, _("\
@@ -579,6 +581,41 @@ ssl_check_certificate (int fd, const char *host)
                  severity, quote (common_name), quote (host));
       success = false;
     }
                  severity, quote (common_name), quote (host));
       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",