bagder: curl-www/CVE-2009-2417 curl-7.10.6-CVE-2009-2417.patch, NONE, 1.1 curl-7.11.0-CVE-2009-2417.patch, NONE, 1.1 curl-7.12.1-CVE-2009-2417.patch, NONE, 1.1 curl-7.15.1-CVE-2009-2417.patch, NONE, 1.1 curl-7.15.5-CVE-2009-2417.patch, NONE, 1.1 curl-7.16.4-CVE-2009-2417.patch, NONE, 1.1 curl-7.18.1-CVE-2009-2417.patch, NONE, 1.1 curl-7.19.0-CVE-2009-2417.patch, NONE, 1.1 curl-7.19.5-CVE-2009-2417.patch, NONE, 1.1

[email protected] Mon, 17 Aug 2009 12:54:29 +0000
Newsgroups gmane.comp.web.curl.www.cvs
Message-ID <[email protected]>
Update of /cvsroot/curl/curl-www/CVE-2009-2417
In directory labb:/tmp/cvs-serv29490/CVE-2009-2417

Added Files:
	curl-7.10.6-CVE-2009-2417.patch 
	curl-7.11.0-CVE-2009-2417.patch 
	curl-7.12.1-CVE-2009-2417.patch 
	curl-7.15.1-CVE-2009-2417.patch 
	curl-7.15.5-CVE-2009-2417.patch 
	curl-7.16.4-CVE-2009-2417.patch 
	curl-7.18.1-CVE-2009-2417.patch 
	curl-7.19.0-CVE-2009-2417.patch 
	curl-7.19.5-CVE-2009-2417.patch 
Log Message:
the patches for CVE-2009-2417


--- NEW FILE: curl-7.11.0-CVE-2009-2417.patch ---
---
 lib/ssluse.c |   98 +++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 75 insertions(+), 23 deletions(-)

--- lib/ssluse.c.orig
+++ lib/ssluse.c
@@ -780,7 +780,6 @@ cert_hostcheck(const char *certname, con
 static CURLcode verifyhost(struct connectdata *conn,
                            X509 *server_cert)
 {
-  char peer_CN[257];
   bool matched = FALSE; /* no alternative match yet */
   int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
   int addrlen = 0;
@@ -791,6 +790,7 @@ static CURLcode verifyhost(struct connec
 #else
   struct in_addr addr;
 #endif
+  CURLcode res = CURLE_OK;
  
 #ifdef ENABLE_IPV6
   if(conn->bits.ipv6_ip && 
@@ -839,8 +839,12 @@ static CURLcode verifyhost(struct connec
 
         switch(target) {
         case GEN_DNS: /* name comparison */
+          if(altlen == strlen(altptr))
+          /* if this isn't true, there was an embedded zero in the name
+             string and we cannot match it. */
+            ;
           /* Is this an exact match? */
-          if((hostlen == altlen) &&
+          else if((hostlen == altlen) &&
              curl_strnequal(conn->hostname, altptr, hostlen))
             matched = TRUE;
         
@@ -867,11 +871,62 @@ static CURLcode verifyhost(struct connec
     /* an alternative name matched the server hostname */
     infof(data, "\t subjectAltName: %s matched\n", conn->hostname);
   else {
-    bool obtain=FALSE;
-    if(X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
-                                 NID_commonName,
-                                 peer_CN,
-                                 sizeof(peer_CN)) < 0) {
+    /* we have to look to the last occurence of a commonName in the
+       distinguished one to get the most significant one. */
+    int j,i=-1 ;
+
+/* The following is done because of a bug in 0.9.6b */
+
+    unsigned char *nulstr = (unsigned char *)"";
+    unsigned char *peer_CN = nulstr;
+
+    X509_NAME *name = X509_get_subject_name(server_cert) ;
+    if (name)
+      while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0)
+        i=j;
+
+    /* we have the name entry and we will now convert this to a string
+       that we can use for comparison. Doing this we support BMPstring,
+       UTF8 etc. */
+
+    if (i>=0) {
+      ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));
+
+      /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
+         is already UTF-8 encoded. We check for this case and copy the raw
+         string manually to avoid the problem. This code can be made
+         conditional in the future when OpenSSL has been fixed. Work-around
+         brought by Alexis S. L. Carvalho. */
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          j = ASN1_STRING_length(tmp);
+          if(j >= 0) {
+            peer_CN = OPENSSL_malloc(j+1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+              peer_CN[j] = '\0';
+            }
+          }
+        }
+        else /* not a UTF8 name */
+          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          res = CURLE_SSL_PEER_CERTIFICATE;
+        }
+      }
+    }
+
+    if (peer_CN == nulstr)
+       peer_CN = NULL;
+
+    if(res)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
       if(data->set.ssl.verifyhost > 1) {
         failf(data,
               "SSL: unable to obtain common name from peer certificate");
@@ -883,26 +938,23 @@ static CURLcode verifyhost(struct connec
         infof(data, "\t common name: WARNING couldn't obtain\n");
       }
     }
-    else
-      obtain = TRUE;
-         
-    if(obtain) {
-      if(!cert_hostcheck(peer_CN, conn->hostname)) {
-        if(data->set.ssl.verifyhost > 1) {
-          failf(data, "SSL: certificate subject name '%s' does not match "
-                "target host name '%s'", peer_CN, conn->hostname);
-          return CURLE_SSL_PEER_CERTIFICATE;
-        }
-        else
-          infof(data, "\t common name: %s (does not match '%s')\n",
-                peer_CN, conn->hostname);
+    else if(!cert_hostcheck((const char *)peer_CN, conn->hostname)) {
+      if(data->set.ssl.verifyhost > 1) {
+        failf(data, "SSL: certificate subject name '%s' does not match "
+              "target host name '%s'", peer_CN, conn->hostname);
+        res = CURLE_SSL_PEER_CERTIFICATE;
       }
       else
-        infof(data, "\t common name: %s (matched)\n", peer_CN);
+        infof(data, "\t common name: %s (does not match '%s')\n",
+              peer_CN, conn->hostname);
     }
+    else {
+      infof(data, "\t common name: %s (matched)\n", peer_CN);
+    }
+    if(peer_CN)
+      OPENSSL_free(peer_CN);
   }
-
-  return CURLE_OK;
+  return res;
 }
 #endif
 

--- NEW FILE: curl-7.15.5-CVE-2009-2417.patch ---
---
 lib/ssluse.c |   40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

--- lib/ssluse.c.orig
+++ lib/ssluse.c
@@ -929,7 +929,7 @@ static CURLcode verifyhost(struct connec
       if(check->type == target) {
         /* get data and length */
         const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
-        int altlen;
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
 
         switch(target) {
         case GEN_DNS: /* name/pattern comparison */
@@ -943,14 +943,16 @@ static CURLcode verifyhost(struct connec
              "I checked the 0.9.6 and 0.9.8 sources before my patch and
              it always 0-terminates an IA5String."
           */
-          if (cert_hostcheck(altptr, conn->host.name))
+          if((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             cert_hostcheck(altptr, conn->host.name))
             matched = TRUE;
           break;
 
         case GEN_IPADD: /* IP address comparison */
           /* compare alternative IP address if the data chunk is the same size
              our server IP address is */
-          altlen = ASN1_STRING_length(check->d.ia5);
           if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
             matched = TRUE;
           break;
@@ -990,18 +992,27 @@ static CURLcode verifyhost(struct connec
          string manually to avoid the problem. This code can be made
          conditional in the future when OpenSSL has been fixed. Work-around
          brought by Alexis S. L. Carvalho. */
-      if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
-        j = ASN1_STRING_length(tmp);
-        if (j >= 0) {
-          peer_CN = OPENSSL_malloc(j+1);
-          if (peer_CN) {
-            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
-            peer_CN[j] = '\0';
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          j = ASN1_STRING_length(tmp);
+          if(j >= 0) {
+            peer_CN = OPENSSL_malloc(j+1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+              peer_CN[j] = '\0';
+            }
           }
         }
+        else /* not a UTF8 name */
+          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          res = CURLE_SSL_PEER_CERTIFICATE;
+        }
       }
-      else /* not a UTF8 name */
-        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
     }
 
     if (peer_CN == nulstr)
@@ -1018,7 +1029,10 @@ static CURLcode verifyhost(struct connec
     }
 #endif /* CURL_DOES_CONVERSIONS */
 
-    if (!peer_CN) {
+    if(res)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
       if(data->set.ssl.verifyhost > 1) {
         failf(data,
               "SSL: unable to obtain common name from peer certificate");

--- NEW FILE: curl-7.19.5-CVE-2009-2417.patch ---
--- lib/ssluse.c-7.19.5	2009-08-03 16:01:58.000000000 +0200
+++ lib/ssluse.c	2009-08-03 16:07:17.000000000 +0200
@@ -1092,7 +1092,8 @@
       if(check->type == target) {
         /* get data and length */
         const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
-        size_t altlen;
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
+
 
         switch(target) {
         case GEN_DNS: /* name/pattern comparison */
@@ -1106,14 +1107,16 @@
              "I checked the 0.9.6 and 0.9.8 sources before my patch and
              it always 0-terminates an IA5String."
           */
-          if(cert_hostcheck(altptr, conn->host.name))
+          if((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             cert_hostcheck(altptr, conn->host.name))
             matched = TRUE;
           break;
 
         case GEN_IPADD: /* IP address comparison */
           /* compare alternative IP address if the data chunk is the same size
              our server IP address is */
-          altlen = (size_t) ASN1_STRING_length(check->d.ia5);
           if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
             matched = TRUE;
           break;
@@ -1153,18 +1156,27 @@
          string manually to avoid the problem. This code can be made
          conditional in the future when OpenSSL has been fixed. Work-around
          brought by Alexis S. L. Carvalho. */
-      if(tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
-        j = ASN1_STRING_length(tmp);
-        if(j >= 0) {
-          peer_CN = OPENSSL_malloc(j+1);
-          if(peer_CN) {
-            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
-            peer_CN[j] = '\0';
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          j = ASN1_STRING_length(tmp);
+          if(j >= 0) {
+            peer_CN = OPENSSL_malloc(j+1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+              peer_CN[j] = '\0';
+            }
           }
         }
+        else /* not a UTF8 name */
+          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          res = CURLE_PEER_FAILED_VERIFICATION;
+        }
       }
-      else /* not a UTF8 name */
-        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
     }
 
     if(peer_CN == nulstr)
@@ -1182,7 +1194,10 @@
     }
 #endif /* CURL_DOES_CONVERSIONS */
 
-    if(!peer_CN) {
+    if(res)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
       failf(data,
             "SSL: unable to obtain common name from peer certificate");
       return CURLE_PEER_FAILED_VERIFICATION;

--- NEW FILE: curl-7.12.1-CVE-2009-2417.patch ---
diff -rup curl-7.12.1.orig/lib/ssluse.c curl-7.12.1/lib/ssluse.c
--- curl-7.12.1.orig/lib/ssluse.c	2009-08-08 10:59:35.082595273 +0200
+++ curl-7.12.1/lib/ssluse.c	2009-08-08 10:59:56.406590013 +0200
@@ -868,7 +868,7 @@ static CURLcode verifyhost(struct connec
       if(check->type == target) {
         /* get data and length */
         const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
-        int altlen;
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
 
         switch(target) {
         case GEN_DNS: /* name/pattern comparison */
@@ -882,14 +882,16 @@ static CURLcode verifyhost(struct connec
              "I checked the 0.9.6 and 0.9.8 sources before my patch and
              it always 0-terminates an IA5String."
           */
-          if (cert_hostcheck(altptr, conn->host.name))
+          if((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             cert_hostcheck(altptr, conn->host.name))
             matched = TRUE;
           break;
 
         case GEN_IPADD: /* IP address comparison */
           /* compare alternative IP address if the data chunk is the same size
              our server IP address is */
-          altlen = ASN1_STRING_length(check->d.ia5);
           if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
             matched = TRUE;
           break;
@@ -929,18 +931,29 @@ static CURLcode verifyhost(struct connec
          string manually to avoid the problem. This code can be made
          conditional in the future when OpenSSL has been fixed. Work-around
          brought by Alexis S. L. Carvalho. */
-      if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
-        j = ASN1_STRING_length(tmp);
-        if (j >= 0) {
-          peer_CN = OPENSSL_malloc(j+1);
-          if (peer_CN) {
-            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
-            peer_CN[j] = '\0';
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          j = ASN1_STRING_length(tmp);
+          if(j >= 0) {
+            peer_CN = OPENSSL_malloc(j+1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+              peer_CN[j] = '\0';
+            }
           }
         }
+        else /* not a UTF8 name */
+          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          if (peer_CN != nulstr)
+              OPENSSL_free(peer_CN);
+          return CURLE_SSL_PEER_CERTIFICATE;
+        }
       }
-      else /* not a UTF8 name */
-        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
     }
 
     if (peer_CN == nulstr)

--- NEW FILE: curl-7.18.1-CVE-2009-2417.patch ---
---
 lib/ssluse.c |   40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

--- lib/ssluse.c.orig
+++ lib/ssluse.c
@@ -1061,7 +1061,7 @@ static CURLcode verifyhost(struct connec
       if(check->type == target) {
         /* get data and length */
         const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
-        int altlen;
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
 
         switch(target) {
         case GEN_DNS: /* name/pattern comparison */
@@ -1075,14 +1075,16 @@ static CURLcode verifyhost(struct connec
              "I checked the 0.9.6 and 0.9.8 sources before my patch and
              it always 0-terminates an IA5String."
           */
-          if(cert_hostcheck(altptr, conn->host.name))
+          if((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             cert_hostcheck(altptr, conn->host.name))
             matched = TRUE;
           break;
 
         case GEN_IPADD: /* IP address comparison */
           /* compare alternative IP address if the data chunk is the same size
              our server IP address is */
-          altlen = ASN1_STRING_length(check->d.ia5);
           if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
             matched = TRUE;
           break;
@@ -1122,18 +1124,27 @@ static CURLcode verifyhost(struct connec
          string manually to avoid the problem. This code can be made
          conditional in the future when OpenSSL has been fixed. Work-around
          brought by Alexis S. L. Carvalho. */
-      if(tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
-        j = ASN1_STRING_length(tmp);
-        if(j >= 0) {
-          peer_CN = OPENSSL_malloc(j+1);
-          if(peer_CN) {
-            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
-            peer_CN[j] = '\0';
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          j = ASN1_STRING_length(tmp);
+          if(j >= 0) {
+            peer_CN = OPENSSL_malloc(j+1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+              peer_CN[j] = '\0';
+            }
           }
         }
+        else /* not a UTF8 name */
+          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          res = CURLE_PEER_FAILED_VERIFICATION;
+        }
       }
-      else /* not a UTF8 name */
-        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
     }
 
     if(peer_CN == nulstr)
@@ -1151,7 +1162,10 @@ static CURLcode verifyhost(struct connec
     }
 #endif /* CURL_DOES_CONVERSIONS */
 
-    if(!peer_CN) {
+    if(res)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
       failf(data,
             "SSL: unable to obtain common name from peer certificate");
       return CURLE_PEER_FAILED_VERIFICATION;

--- NEW FILE: curl-7.19.0-CVE-2009-2417.patch ---
---
 lib/ssluse.c |   40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

--- lib/ssluse.c.orig
+++ lib/ssluse.c
@@ -1064,7 +1064,7 @@ static CURLcode verifyhost(struct connec
       if(check->type == target) {
         /* get data and length */
         const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
-        int altlen;
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
 
         switch(target) {
         case GEN_DNS: /* name/pattern comparison */
@@ -1078,14 +1078,16 @@ static CURLcode verifyhost(struct connec
              "I checked the 0.9.6 and 0.9.8 sources before my patch and
              it always 0-terminates an IA5String."
           */
-          if(cert_hostcheck(altptr, conn->host.name))
+          if((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             cert_hostcheck(altptr, conn->host.name))
             matched = TRUE;
           break;
 
         case GEN_IPADD: /* IP address comparison */
           /* compare alternative IP address if the data chunk is the same size
              our server IP address is */
-          altlen = ASN1_STRING_length(check->d.ia5);
           if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
             matched = TRUE;
           break;
@@ -1125,18 +1127,27 @@ static CURLcode verifyhost(struct connec
          string manually to avoid the problem. This code can be made
          conditional in the future when OpenSSL has been fixed. Work-around
          brought by Alexis S. L. Carvalho. */
-      if(tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
-        j = ASN1_STRING_length(tmp);
-        if(j >= 0) {
-          peer_CN = OPENSSL_malloc(j+1);
-          if(peer_CN) {
-            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
-            peer_CN[j] = '\0';
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          j = ASN1_STRING_length(tmp);
+          if(j >= 0) {
+            peer_CN = OPENSSL_malloc(j+1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+              peer_CN[j] = '\0';
+            }
           }
         }
+        else /* not a UTF8 name */
+          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          res = CURLE_PEER_FAILED_VERIFICATION;
+        }
       }
-      else /* not a UTF8 name */
-        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
     }
 
     if(peer_CN == nulstr)
@@ -1154,7 +1165,10 @@ static CURLcode verifyhost(struct connec
     }
 #endif /* CURL_DOES_CONVERSIONS */
 
-    if(!peer_CN) {
+    if(res)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
       failf(data,
             "SSL: unable to obtain common name from peer certificate");
       return CURLE_PEER_FAILED_VERIFICATION;

--- NEW FILE: curl-7.10.6-CVE-2009-2417.patch ---
diff -rup curl-7.10.6.orig/lib/ssluse.c curl-7.10.6/lib/ssluse.c
--- curl-7.10.6.orig/lib/ssluse.c	2009-08-08 10:41:32.442607231 +0200
+++ curl-7.10.6/lib/ssluse.c	2009-08-08 10:53:52.459515245 +0200
@@ -736,6 +736,95 @@ cert_hostcheck(const char *certname, con
 }
 #endif
 
+static CURLcode verifyhost(struct connectdata *conn,
+                           X509 *server_cert)
+{
+  struct SessionHandle *data = conn->data;
+
+  /* we have to look to the last occurence of a commonName in the
+     distinguished one to get the most significant one. */
+  int j,i=-1 ;
+
+/* The following is done because of a bug in 0.9.6b */
+
+  unsigned char *nulstr = (unsigned char *)"";
+  unsigned char *peer_CN = nulstr;
+
+  X509_NAME *name = X509_get_subject_name(server_cert) ;
+  if (name)
+    while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0)
+      i=j;
+
+  /* we have the name entry and we will now convert this to a string
+     that we can use for comparison. Doing this we support BMPstring,
+     UTF8 etc. */
+
+  if (i>=0) {
+    ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));
+
+    /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
+       is already UTF-8 encoded. We check for this case and copy the raw
+       string manually to avoid the problem. This code can be made
+       conditional in the future when OpenSSL has been fixed. Work-around
+       brought by Alexis S. L. Carvalho. */
+    if(tmp) {
+      if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+        j = ASN1_STRING_length(tmp);
+        if(j >= 0) {
+          peer_CN = OPENSSL_malloc(j+1);
+          if(peer_CN) {
+            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+            peer_CN[j] = '\0';
+          }
+        }
+      }
+      else /* not a UTF8 name */
+        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+      if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+        /* there was a terminating zero before the end of string, this
+           cannot match and we return failure! */
+        failf(data, "SSL: illegal cert name field");
+        if (peer_CN != nulstr)
+            OPENSSL_free(peer_CN);
+        return CURLE_SSL_PEER_CERTIFICATE;
+      }
+    }
+  }
+
+  if (peer_CN == nulstr)
+     peer_CN = NULL;
+
+  if (!peer_CN) {
+    if(data->set.ssl.verifyhost > 1) {
+      failf(data,
+            "SSL: unable to obtain common name from peer certificate");
+      return CURLE_SSL_PEER_CERTIFICATE;
+    }
+    else {
+      /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we
+         output a note about the situation */
+      infof(data, "\t common name: WARNING couldn't obtain\n");
+    }
+  }
+  else if(!cert_hostcheck((const char *)peer_CN, conn->hostname)) {
+    if(data->set.ssl.verifyhost > 1) {
+      failf(data, "SSL: certificate subject name '%s' does not match "
+            "target host name '%s'", peer_CN, conn->hostname);
+      OPENSSL_free(peer_CN);
+      return CURLE_SSL_PEER_CERTIFICATE ;
+    }
+    else
+      infof(data, "\t common name: %s (does not match '%s')\n",
+            peer_CN, conn->hostname);
+  }
+  else {
+    infof(data, "\t common name: %s (matched)\n", peer_CN);
+    OPENSSL_free(peer_CN);
+  }
+  return CURLE_OK;
+}
+
 /* ====================================================== */
 CURLcode
 Curl_SSLConnect(struct connectdata *conn)
@@ -1013,32 +1102,12 @@ Curl_SSLConnect(struct connectdata *conn
   certdate = X509_get_notAfter(conn->ssl.server_cert);
   Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate);
 
-  if (data->set.ssl.verifyhost) {
-    char peer_CN[257];
-    if (X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert),
-                                  NID_commonName,
-                                  peer_CN,
-                                  sizeof(peer_CN)) < 0) {
-      failf(data, "SSL: unable to obtain common name from peer certificate");
-      X509_free(conn->ssl.server_cert);
-      return CURLE_SSL_PEER_CERTIFICATE;
-    }
-
-    if (!cert_hostcheck(peer_CN, conn->hostname)) {
-      if (data->set.ssl.verifyhost > 1) {
-        failf(data, "SSL: certificate subject name '%s' does not match "
-              "target host name '%s'",
-              peer_CN, conn->hostname);
-        X509_free(conn->ssl.server_cert);
-        return CURLE_SSL_PEER_CERTIFICATE;
-      }
-      else
-        infof(data,
-              "\t common name: %s (does not match '%s')\n",
-              peer_CN, conn->hostname);
+  if(data->set.ssl.verifyhost) {
+    retcode = verifyhost(conn, conn->ssl.server_cert);
+    if(retcode) {
+      X509_free(conn->ssl.server_cert);
+      return retcode;
     }
-    else
-      infof(data, "\t common name: %s (matched)\n", peer_CN);
   }
 
   str = X509_NAME_oneline (X509_get_issuer_name  (conn->ssl.server_cert),

--- NEW FILE: curl-7.15.1-CVE-2009-2417.patch ---
---
 lib/ssluse.c |   40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

--- lib/ssluse.c.orig
+++ lib/ssluse.c
@@ -894,7 +894,7 @@ static CURLcode verifyhost(struct connec
       if(check->type == target) {
         /* get data and length */
         const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
-        int altlen;
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
 
         switch(target) {
         case GEN_DNS: /* name/pattern comparison */
@@ -908,14 +908,16 @@ static CURLcode verifyhost(struct connec
              "I checked the 0.9.6 and 0.9.8 sources before my patch and
              it always 0-terminates an IA5String."
           */
-          if (cert_hostcheck(altptr, conn->host.name))
+          if((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             cert_hostcheck(altptr, conn->host.name))
             matched = TRUE;
           break;
 
         case GEN_IPADD: /* IP address comparison */
           /* compare alternative IP address if the data chunk is the same size
              our server IP address is */
-          altlen = ASN1_STRING_length(check->d.ia5);
           if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
             matched = TRUE;
           break;
@@ -955,24 +957,36 @@ static CURLcode verifyhost(struct connec
          string manually to avoid the problem. This code can be made
          conditional in the future when OpenSSL has been fixed. Work-around
          brought by Alexis S. L. Carvalho. */
-      if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
-        j = ASN1_STRING_length(tmp);
-        if (j >= 0) {
-          peer_CN = OPENSSL_malloc(j+1);
-          if (peer_CN) {
-            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
-            peer_CN[j] = '\0';
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          j = ASN1_STRING_length(tmp);
+          if(j >= 0) {
+            peer_CN = OPENSSL_malloc(j+1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+              peer_CN[j] = '\0';
+            }
           }
         }
+        else /* not a UTF8 name */
+          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          res = CURLE_SSL_PEER_CERTIFICATE;
+        }
       }
-      else /* not a UTF8 name */
-        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
     }
 
     if (peer_CN == nulstr)
        peer_CN = NULL;
 
-    if (!peer_CN) {
+    if(res)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
       if(data->set.ssl.verifyhost > 1) {
         failf(data,
               "SSL: unable to obtain common name from peer certificate");

--- NEW FILE: curl-7.16.4-CVE-2009-2417.patch ---
---
 lib/ssluse.c |   40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

--- lib/ssluse.c.orig
+++ lib/ssluse.c
@@ -1040,7 +1040,7 @@ static CURLcode verifyhost(struct connec
       if(check->type == target) {
         /* get data and length */
         const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
-        int altlen;
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
 
         switch(target) {
         case GEN_DNS: /* name/pattern comparison */
@@ -1054,14 +1054,16 @@ static CURLcode verifyhost(struct connec
              "I checked the 0.9.6 and 0.9.8 sources before my patch and
              it always 0-terminates an IA5String."
           */
-          if (cert_hostcheck(altptr, conn->host.name))
+          if((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             cert_hostcheck(altptr, conn->host.name))
             matched = TRUE;
           break;
 
         case GEN_IPADD: /* IP address comparison */
           /* compare alternative IP address if the data chunk is the same size
              our server IP address is */
-          altlen = ASN1_STRING_length(check->d.ia5);
           if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
             matched = TRUE;
           break;
@@ -1101,18 +1103,27 @@ static CURLcode verifyhost(struct connec
          string manually to avoid the problem. This code can be made
          conditional in the future when OpenSSL has been fixed. Work-around
          brought by Alexis S. L. Carvalho. */
-      if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
-        j = ASN1_STRING_length(tmp);
-        if (j >= 0) {
-          peer_CN = OPENSSL_malloc(j+1);
-          if (peer_CN) {
-            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
-            peer_CN[j] = '\0';
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          j = ASN1_STRING_length(tmp);
+          if(j >= 0) {
+            peer_CN = OPENSSL_malloc(j+1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+              peer_CN[j] = '\0';
+            }
           }
         }
+        else /* not a UTF8 name */
+          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          res = CURLE_SSL_PEER_CERTIFICATE;
+        }
       }
-      else /* not a UTF8 name */
-        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
     }
 
     if (peer_CN == nulstr)
@@ -1130,7 +1141,10 @@ static CURLcode verifyhost(struct connec
     }
 #endif /* CURL_DOES_CONVERSIONS */
 
-    if (!peer_CN) {
+    if(res)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
       if(data->set.ssl.verifyhost > 1) {
         failf(data,
               "SSL: unable to obtain common name from peer certificate");