]> granicus.if.org Git - curl/commitdiff
SSL: Several SSL-backend related fixes
authorOscar Koeroo <okoeroo@gmail.com>
Sat, 3 Nov 2012 01:06:51 +0000 (02:06 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 8 Nov 2012 21:23:12 +0000 (22:23 +0100)
axTLS:

This will make the axTLS backend perform the RFC2818 checks, honoring
the VERIFYHOST setting similar to the OpenSSL backend.

Generic for OpenSSL and axTLS:

Move the hostcheck and cert_hostcheck functions from the lib/ssluse.c
files to make them genericly available for both the OpenSSL, axTLS and
other SSL backends. They are now in the new lib/hostcheck.c file.

CyaSSL:

CyaSSL now also has the RFC2818 checks enabled by default. There is a
limitation that the verifyhost can not be enabled exclusively on the
Subject CN field comparison. This SSL backend will thus behave like the
NSS and the GnuTLS (meaning: RFC2818 ok, or bust). In other words:
setting verifyhost to 0 or 1 will disable the Subject Alt Names checks
too.

Schannel:

Updated the schannel information messages: Split the IP address usage
message from the verifyhost setting and changed the message about
disabling SNI (Server Name Indication, used in HTTP virtual hosting)
into a message stating that the Subject Alternative Names checks are
being disabled when verifyhost is set to 0 or 1. As a side effect of
switching off the RFC2818 related servername checks with
SCH_CRED_NO_SERVERNAME_CHECK
(http://msdn.microsoft.com/en-us/library/aa923430.aspx) the SNI feature
is being disabled. This effect is not documented in MSDN, but Wireshark
output clearly shows the effect (details on the libcurl maillist).

PolarSSL:

Fix the prototype change in PolarSSL of ssl_set_session() and the move
of the peer_cert from the ssl_context to the ssl_session. Found this
change in the PolarSSL SVN between r1316 and r1317 where the
POLARSSL_VERSION_NUMBER was at 0x01010100. But to accommodate the Ubuntu
PolarSSL version 1.1.4 the check is to discriminate between lower then
PolarSSL version 1.2.0 and 1.2.0 and higher. Note: The PolarSSL SVN
trunk jumped from version 1.1.1 to 1.2.0.

Generic:

All the SSL backends are fixed and checked to work with the
ssl.verifyhost as a boolean, which is an internal API change.

lib/Makefile.inc
lib/axtls.c
lib/curl_darwinssl.c
lib/curl_schannel.c
lib/cyassl.c
lib/hostcheck.c [new file with mode: 0644]
lib/hostcheck.h [new file with mode: 0644]
lib/polarssl.c
lib/ssluse.c

index e0044ec659b54c13f62cded343caf68bdc47be95..fcb8c28ec43410e39062cc32f8e872cb635bf9f6 100644 (file)
@@ -24,7 +24,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c   \
   idn_win32.c http_negotiate_sspi.c cyassl.c http_proxy.c non-ascii.c  \
   asyn-ares.c asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c   \
   curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_schannel.c        \
-  curl_multibyte.c curl_darwinssl.c
+  curl_multibyte.c curl_darwinssl.c hostcheck.c
 
 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h      \
   progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h     \
@@ -41,4 +41,5 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h     \
   warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h     \
   gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h curl_ntlm.h        \
   curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h       \
-  curl_sasl.h curl_schannel.h curl_multibyte.h curl_darwinssl.h
+  curl_sasl.h curl_schannel.h curl_multibyte.h curl_darwinssl.h        \
+  hostcheck.h
index e37aed50ae00316fa91bc7e0f469628f5f8bb430..ea94c6cf9d453e52c235a41b7a20d777491214fb 100644 (file)
@@ -47,6 +47,8 @@
 #include "curl_memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
+#include "hostcheck.h"
+
 
 /* SSL_read is opied from axTLS compat layer */
 static int SSL_read(SSL *ssl, void *buf, int num)
@@ -150,7 +152,11 @@ Curl_axtls_connect(struct connectdata *conn,
   int i, ssl_fcn_return;
   const uint8_t *ssl_sessionid;
   size_t ssl_idsize;
-  const char *x509;
+  const char *peer_CN;
+  uint32_t dns_altname_index;
+  const char *dns_altname;
+  int8_t found_subject_alt_names = 0;
+  int8_t found_subject_alt_name_matching_conn = 0;
 
   /* Assuming users will not compile in custom key/cert to axTLS */
   uint32_t client_option = SSL_NO_DEFAULT_KEY|SSL_SERVER_VERIFY_LATER;
@@ -296,19 +302,65 @@ Curl_axtls_connect(struct connectdata *conn,
   /* Here, gtls.c does issuer verification. axTLS has no straightforward
    * equivalent, so omitting for now.*/
 
-  /* See if common name was set in server certificate */
-  x509 = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
-  if(x509 == NULL)
-    infof(data, "error fetching CN from cert\n");
-
   /* Here, gtls.c does the following
    * 1) x509 hostname checking per RFC2818.  axTLS doesn't support this, but
-   *    it seems useful.  Omitting for now.
+   *    it seems useful. This is now implemented, by Oscar Koeroo
    * 2) checks cert validity based on time.  axTLS does this in ssl_verify_cert
    * 3) displays a bunch of cert information.  axTLS doesn't support most of
    *    this, but a couple fields are available.
    */
 
+
+  /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a
+     risk of an inifite loop */
+  for(dns_altname_index = 0; ; dns_altname_index++) {
+    dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index);
+    if(dns_altname == NULL) {
+      break;
+    }
+    found_subject_alt_names = 1;
+
+    infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n",
+          dns_altname, conn->host.name);
+    if(Curl_cert_hostcheck(dns_altname, conn->host.name)) {
+      found_subject_alt_name_matching_conn = 1;
+      break;
+    }
+  }
+
+  /* RFC2818 checks */
+  if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
+    /* Break connection ! */
+    Curl_axtls_close(conn, sockindex);
+    failf(data, "\tsubjectAltName(s) do not match %s\n", conn->host.dispname);
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+  else if(found_subject_alt_names == 0) {
+    /* Per RFC2818, when no Subject Alt Names were available, examine the peer
+       CN as a legacy fallback */
+    peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
+    if(peer_CN == NULL) {
+      /* Similar behaviour to the OpenSSL interface */
+      Curl_axtls_close(conn, sockindex);
+      failf(data, "unable to obtain common name from peer certificate");
+      return CURLE_PEER_FAILED_VERIFICATION;
+    }
+    else {
+      if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
+        if(data->set.ssl.verifyhost) {
+          /* Break connection ! */
+          Curl_axtls_close(conn, sockindex);
+          failf(data, "\tcommon name \"%s\" does not match \"%s\"\n",
+                peer_CN, conn->host.dispname);
+          return CURLE_PEER_FAILED_VERIFICATION;
+        }
+        else
+          infof(data, "\tcommon name \"%s\" does not match \"%s\"\n",
+                peer_CN, conn->host.dispname);
+      }
+    }
+  }
+
   /* General housekeeping */
   conn->ssl[sockindex].state = ssl_connection_complete;
   conn->ssl[sockindex].ssl = ssl;
index 334944f0985ceaab2ad265c91abb1d113733d718..3cc278a1f6cb5a6102f85f39b53be0f3870d32b8 100644 (file)
@@ -803,6 +803,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
   }
 #endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */
 
+  /* If this is a domain name and not an IP address, then configure SNI.
+   * Also: the verifyhost setting influences SNI usage */
   /* If this is a domain name and not an IP address, then configure SNI: */
   if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
 #ifdef ENABLE_IPV6
@@ -862,7 +864,6 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
         connssl->connecting_state = connssl->ssl_direction ?
             ssl_connect_2_writing : ssl_connect_2_reading;
         return CURLE_OK;
-        break;
 
       case errSSLServerAuthCompleted:
         /* the documentation says we need to call SSLHandshake() again */
@@ -874,13 +875,16 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
       case errSSLCertExpired:
         failf(data, "SSL certificate problem: OSStatus %d", err);
         return CURLE_SSL_CACERT;
-        break;
+
+      case errSSLHostNameMismatch:
+        failf(data, "SSL certificate peer verification failed, the "
+              "certificate did not match \"%s\"\n", conn->host.dispname);
+        return CURLE_PEER_FAILED_VERIFICATION;
 
       default:
         failf(data, "Unknown SSL protocol error in connection to %s:%d",
               conn->host.name, err);
         return CURLE_SSL_CONNECT_ERROR;
-        break;
     }
   }
   else {
index ef6b1adb0c0d79d955c2127178fdcd9e4f909b90..8cb3af80fa2964eda20c81c2c9f00aa976ffae65 100644 (file)
@@ -156,14 +156,22 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
       infof(data, "schannel: disable server certificate revocation checks\n");
     }
 
-    if(Curl_inet_pton(AF_INET, conn->host.name, &addr) ||
+    if(Curl_inet_pton(AF_INET, conn->host.name, &addr)
 #ifdef ENABLE_IPV6
-       Curl_inet_pton(AF_INET6, conn->host.name, &addr6) ||
+       || Curl_inet_pton(AF_INET6, conn->host.name, &addr6)
 #endif
-       !data->set.ssl.verifyhost) {
+      ) {
       schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
-      infof(data, "schannel: using IP address, disable SNI servername "
-            "check\n");
+      infof(data, "schannel: using IP address, SNI is being disabled by "
+                  "disabling the servername check against the "
+                  "subject names in server certificates.\n");
+    }
+
+    if(!data->set.ssl.verifyhost) {
+      schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+      infof(data, "schannel: verifyhost setting prevents Schannel from "
+                  "comparing the supplied target name with the subject "
+                  "names in server certificates. Also disables SNI.\n");
     }
 
     switch(data->set.ssl.version) {
index 4c517802fdb7b13dcee19a0d06d7975b825a065c..3639532b2c444c972a0b25a73fdc0b3f9cda1f88 100644 (file)
@@ -53,6 +53,8 @@
 #include "curl_memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
+#include <cyassl/ssl.h>
+#include <cyassl/error.h>
 
 
 static Curl_recv cyassl_recv;
@@ -237,6 +239,13 @@ cyassl_connect_step2(struct connectdata *conn,
   conn->recv[sockindex] = cyassl_recv;
   conn->send[sockindex] = cyassl_send;
 
+  /* Enable RFC2818 checks */
+  if(data->set.ssl.verifyhost) {
+    ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name);
+    if(ret == SSL_FAILURE)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
   ret = SSL_connect(conssl->handle);
   if(ret != 1) {
     char error_buffer[80];
@@ -246,15 +255,43 @@ cyassl_connect_step2(struct connectdata *conn,
       conssl->connecting_state = ssl_connect_2_reading;
       return CURLE_OK;
     }
-
-    if(SSL_ERROR_WANT_WRITE == detail) {
+    else if(SSL_ERROR_WANT_WRITE == detail) {
       conssl->connecting_state = ssl_connect_2_writing;
       return CURLE_OK;
     }
-
-    failf(data, "SSL_connect failed with error %d: %s", detail,
+    /* There is no easy way to override only the CN matching.
+     * This will enable the override of both mismatching SubjectAltNames
+     * as also mismatching CN fields */
+    else if(DOMAIN_NAME_MISMATCH == detail) {
+#if 1
+      failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
+            conn->host.dispname);
+      return CURLE_PEER_FAILED_VERIFICATION;
+#else
+      /* When the CyaSSL_check_domain_name() is used and you desire to continue
+       * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0',
+       * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
+       * way to do this is currently to switch the CyaSSL_check_domain_name()
+       * in and out based on the 'data->set.ssl.verifyhost' value. */
+      if(data->set.ssl.verifyhost) {
+        failf(data,
+              "\tsubject alt name(s) or common name do not match \"%s\"\n",
+              conn->host.dispname);
+        return CURLE_PEER_FAILED_VERIFICATION;
+      }
+      else {
+        infof(data,
+              "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
+              conn->host.dispname);
+        return CURLE_OK;
+      }
+#endif
+    }
+    else {
+      failf(data, "SSL_connect failed with error %d: %s", detail,
           ERR_error_string(detail, error_buffer));
-    return CURLE_SSL_CONNECT_ERROR;
+      return CURLE_SSL_CONNECT_ERROR;
+    }
   }
 
   conssl->connecting_state = ssl_connect_3;
diff --git a/lib/hostcheck.c b/lib/hostcheck.c
new file mode 100644 (file)
index 0000000..c8c4ac3
--- /dev/null
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include "hostcheck.h"
+#include "rawstr.h"
+
+/*
+ * Match a hostname against a wildcard pattern.
+ * E.g.
+ *  "foo.host.com" matches "*.host.com".
+ *
+ * We use the matching rule described in RFC6125, section 6.4.3.
+ * http://tools.ietf.org/html/rfc6125#section-6.4.3
+ */
+
+int Curl_hostmatch(const char *hostname, const char *pattern)
+{
+  const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
+  int wildcard_enabled;
+  size_t prefixlen, suffixlen;
+  pattern_wildcard = strchr(pattern, '*');
+  if(pattern_wildcard == NULL)
+    return Curl_raw_equal(pattern, hostname) ?
+      CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+
+  /* We require at least 2 dots in pattern to avoid too wide wildcard
+     match. */
+  wildcard_enabled = 1;
+  pattern_label_end = strchr(pattern, '.');
+  if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL ||
+     pattern_wildcard > pattern_label_end ||
+     Curl_raw_nequal(pattern, "xn--", 4)) {
+    wildcard_enabled = 0;
+  }
+  if(!wildcard_enabled)
+    return Curl_raw_equal(pattern, hostname) ?
+      CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+
+  hostname_label_end = strchr(hostname, '.');
+  if(hostname_label_end == NULL ||
+     !Curl_raw_equal(pattern_label_end, hostname_label_end))
+    return CURL_HOST_NOMATCH;
+
+  /* The wildcard must match at least one character, so the left-most
+     label of the hostname is at least as large as the left-most label
+     of the pattern. */
+  if(hostname_label_end - hostname < pattern_label_end - pattern)
+    return CURL_HOST_NOMATCH;
+
+  prefixlen = pattern_wildcard - pattern;
+  suffixlen = pattern_label_end - (pattern_wildcard+1);
+  return Curl_raw_nequal(pattern, hostname, prefixlen) &&
+    Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen,
+                    suffixlen) ?
+    CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+}
+
+int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
+{
+  if(!match_pattern || !*match_pattern ||
+      !hostname || !*hostname) /* sanity check */
+    return 0;
+
+  if(Curl_raw_equal(hostname, match_pattern)) /* trivial case */
+    return 1;
+
+  if(Curl_hostmatch(hostname,match_pattern) == CURL_HOST_MATCH)
+    return 1;
+  return 0;
+}
diff --git a/lib/hostcheck.h b/lib/hostcheck.h
new file mode 100644 (file)
index 0000000..9019ccb
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __HOSTCHECK_H
+#define __HOSTCHECK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+#define CURL_HOST_NOMATCH 0
+#define CURL_HOST_MATCH   1
+int Curl_hostmatch(const char *hostname, const char *pattern);
+int Curl_cert_hostcheck(const char *match_pattern, const char *hostname);
+
+#endif
index a2f61d23d1d5c1a4ccda4be71db1ff01735af854..b20b4a3979cbf33ccc81cabf1e6392cae3c7011c 100644 (file)
@@ -212,8 +212,15 @@ polarssl_connect_step1(struct connectdata *conn,
     infof(data, "PolarSSL re-using session\n");
   }
 
+/* PolarSSL SVN revision r1316 to r1317, matching <1.2.0 is to cover Ubuntu's
+   1.1.4 version and the like */
+#if POLARSSL_VERSION_NUMBER<0x01020000
   ssl_set_session(&connssl->ssl, 1, 600,
                   &connssl->ssn);
+#else
+  ssl_set_session(&connssl->ssl,
+                  &connssl->ssn);
+#endif
 
   ssl_set_ca_chain(&connssl->ssl,
                    &connssl->cacert,
@@ -306,12 +313,25 @@ polarssl_connect_step2(struct connectdata *conn,
     return CURLE_PEER_FAILED_VERIFICATION;
   }
 
+/* PolarSSL SVN revision r1316 to r1317, matching <1.2.0 is to cover Ubuntu's
+   1.1.4 version and the like */
+#if POLARSSL_VERSION_NUMBER<0x01020000
   if(conn->ssl[sockindex].ssl.peer_cert) {
+#else
+  if(ssl_get_peer_cert(&(connssl->ssl))) {
+#endif
     /* If the session was resumed, there will be no peer certs */
     memset(buffer, 0, sizeof(buffer));
 
+/* PolarSSL SVN revision r1316 to r1317, matching <1.2.0 is to cover Ubuntu's
+   1.1.4 version and the like */
+#if POLARSSL_VERSION_NUMBER<0x01020000
     if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ",
                            conn->ssl[sockindex].ssl.peer_cert) != -1)
+#else
+    if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ",
+                           ssl_get_peer_cert(&(connssl->ssl))) != -1)
+#endif
       infof(data, "Dumping cert info:\n%s\n", buffer);
   }
 
index 6f0e6bf6b490a192fcdd64a78886c41fc60c73dc..7c4c9269aeeffd7891fe371ebc32a20769b8a521 100644 (file)
@@ -50,6 +50,7 @@
 #include "select.h"
 #include "sslgen.h"
 #include "rawstr.h"
+#include "hostcheck.h"
 
 #define _MPRINTF_REPLACE /* use the internal *printf() functions */
 #include <curl/mprintf.h>
@@ -1039,71 +1040,6 @@ static int asn1_output(const ASN1_UTCTIME *tm,
 
 /* ====================================================== */
 
-/*
- * Match a hostname against a wildcard pattern.
- * E.g.
- *  "foo.host.com" matches "*.host.com".
- *
- * We use the matching rule described in RFC6125, section 6.4.3.
- * http://tools.ietf.org/html/rfc6125#section-6.4.3
- */
-#define HOST_NOMATCH 0
-#define HOST_MATCH   1
-
-static int hostmatch(const char *hostname, const char *pattern)
-{
-  const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
-  int wildcard_enabled;
-  size_t prefixlen, suffixlen;
-  pattern_wildcard = strchr(pattern, '*');
-  if(pattern_wildcard == NULL) {
-    return Curl_raw_equal(pattern, hostname) ? HOST_MATCH : HOST_NOMATCH;
-  }
-  /* We require at least 2 dots in pattern to avoid too wide wildcard
-     match. */
-  wildcard_enabled = 1;
-  pattern_label_end = strchr(pattern, '.');
-  if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL ||
-     pattern_wildcard > pattern_label_end ||
-     Curl_raw_nequal(pattern, "xn--", 4)) {
-    wildcard_enabled = 0;
-  }
-  if(!wildcard_enabled) {
-    return Curl_raw_equal(pattern, hostname) ? HOST_MATCH : HOST_NOMATCH;
-  }
-  hostname_label_end = strchr(hostname, '.');
-  if(hostname_label_end == NULL ||
-     !Curl_raw_equal(pattern_label_end, hostname_label_end)) {
-    return HOST_NOMATCH;
-  }
-  /* The wildcard must match at least one character, so the left-most
-     label of the hostname is at least as large as the left-most label
-     of the pattern. */
-  if(hostname_label_end - hostname < pattern_label_end - pattern) {
-    return HOST_NOMATCH;
-  }
-  prefixlen = pattern_wildcard - pattern;
-  suffixlen = pattern_label_end - (pattern_wildcard+1);
-  return Curl_raw_nequal(pattern, hostname, prefixlen) &&
-    Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen,
-                    suffixlen) ?
-    HOST_MATCH : HOST_NOMATCH;
-}
-
-static int
-cert_hostcheck(const char *match_pattern, const char *hostname)
-{
-  if(!match_pattern || !*match_pattern ||
-      !hostname || !*hostname) /* sanity check */
-    return 0;
-
-  if(Curl_raw_equal(hostname, match_pattern)) /* trivial case */
-    return 1;
-
-  if(hostmatch(hostname,match_pattern) == HOST_MATCH)
-    return 1;
-  return 0;
-}
 
 /* Quote from RFC2818 section 3.1 "Server Identity"
 
@@ -1192,7 +1128,7 @@ static CURLcode verifyhost(struct connectdata *conn,
           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))
+             Curl_cert_hostcheck(altptr, conn->host.name))
             matched = 1;
           else
             matched = 0;
@@ -1291,7 +1227,7 @@ static CURLcode verifyhost(struct connectdata *conn,
             "SSL: unable to obtain common name from peer certificate");
       res = CURLE_PEER_FAILED_VERIFICATION;
     }
-    else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) {
+    else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
       failf(data, "SSL: certificate subject name '%s' does not match "
             "target host name '%s'", peer_CN, conn->host.dispname);
       res = CURLE_PEER_FAILED_VERIFICATION;