1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23#include "curl_setup.h" 24 25#if defined(USE_SSLEAY) || defined(USE_AXTLS) || defined(USE_QSOSSL) || \ 26 defined(USE_GSKIT) 27/* these backends use functions from this file */ 28 29#ifdef HAVE_NETINET_IN_H 30#include <netinet/in.h> 31#endif 32 33#include "hostcheck.h" 34#include "rawstr.h" 35#include "inet_pton.h" 36 37#include "curl_memory.h" 38/* The last #include file should be: */ 39#include "memdebug.h" 40 41/* 42 * Match a hostname against a wildcard pattern. 43 * E.g. 44 * "foo.host.com" matches "*.host.com". 45 * 46 * We use the matching rule described in RFC6125, section 6.4.3. 47 * http://tools.ietf.org/html/rfc6125#section-6.4.3 48 * 49 * In addition: ignore trailing dots in the host names and wildcards, so that 50 * the names are used normalized. This is what the browsers do. 51 * 52 * Do not allow wildcard matching on IP numbers. There are apparently 53 * certificates being used with an IP address in the CN field, thus making no 54 * apparent distinction between a name and an IP. We need to detect the use of 55 * an IP address and not wildcard match on such names. 56 * 57 * NOTE: hostmatch() gets called with copied buffers so that it can modify the 58 * contents at will. 59 */ 60 61static int hostmatch(char *hostname, char *pattern) 62{ 63 const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; 64 int wildcard_enabled; 65 size_t prefixlen, suffixlen; 66 struct in_addr ignored; 67#ifdef ENABLE_IPV6 68 struct sockaddr_in6 si6; 69#endif 70 71 /* normalize pattern and hostname by stripping off trailing dots */ 72 size_t len = strlen(hostname); 73 if(hostname[len-1]=='.') 74 hostname[len-1]=0; 75 len = strlen(pattern); 76 if(pattern[len-1]=='.') 77 pattern[len-1]=0; 78 79 pattern_wildcard = strchr(pattern, '*'); 80 if(pattern_wildcard == NULL) 81 return Curl_raw_equal(pattern, hostname) ? 82 CURL_HOST_MATCH : CURL_HOST_NOMATCH; 83 84 /* detect IP address as hostname and fail the match if so */ 85 if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) 86 return CURL_HOST_NOMATCH; 87#ifdef ENABLE_IPV6 88 else if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) 89 return CURL_HOST_NOMATCH; 90#endif 91 92 /* We require at least 2 dots in pattern to avoid too wide wildcard 93 match. */ 94 wildcard_enabled = 1; 95 pattern_label_end = strchr(pattern, '.'); 96 if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || 97 pattern_wildcard > pattern_label_end || 98 Curl_raw_nequal(pattern, "xn--", 4)) { 99 wildcard_enabled = 0; 100 } 101 if(!wildcard_enabled) 102 return Curl_raw_equal(pattern, hostname) ? 103 CURL_HOST_MATCH : CURL_HOST_NOMATCH; 104 105 hostname_label_end = strchr(hostname, '.'); 106 if(hostname_label_end == NULL || 107 !Curl_raw_equal(pattern_label_end, hostname_label_end)) 108 return CURL_HOST_NOMATCH; 109 110 /* The wildcard must match at least one character, so the left-most 111 label of the hostname is at least as large as the left-most label 112 of the pattern. */ 113 if(hostname_label_end - hostname < pattern_label_end - pattern) 114 return CURL_HOST_NOMATCH; 115 116 prefixlen = pattern_wildcard - pattern; 117 suffixlen = pattern_label_end - (pattern_wildcard+1); 118 return Curl_raw_nequal(pattern, hostname, prefixlen) && 119 Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen, 120 suffixlen) ? 121 CURL_HOST_MATCH : CURL_HOST_NOMATCH; 122} 123 124int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) 125{ 126 char *matchp; 127 char *hostp; 128 int res = 0; 129 if(!match_pattern || !*match_pattern || 130 !hostname || !*hostname) /* sanity check */ 131 ; 132 else { 133 matchp = strdup(match_pattern); 134 if(matchp) { 135 hostp = strdup(hostname); 136 if(hostp) { 137 if(hostmatch(hostp, matchp) == CURL_HOST_MATCH) 138 res= 1; 139 free(hostp); 140 } 141 free(matchp); 142 } 143 } 144 145 return res; 146} 147 148#endif /* SSLEAY or AXTLS or QSOSSL or GSKIT */ 149