---
 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
 

