From 170637e85ab64ab72c6f82bca4aa0eee05a7fe4c Mon Sep 17 00:00:00 2001 From: mrigaya Date: Thu, 7 Jun 2018 10:57:12 +0530 Subject: [PATCH] Add changes to support hostname validation feature. --- src/Makefile.am | 10 +- src/nopoll.h | 1 + src/nopoll_conn.c | 24 ++- src/nopoll_conn_opts.c | 20 +++ src/nopoll_conn_opts.h | 2 + src/nopoll_hostcheck.c | 45 ++++++ src/nopoll_hostcheck.h | 11 ++ src/nopoll_hostname_compare.c | 254 +++++++++++++++++++++++++++++++ src/nopoll_hostname_compare.h | 9 ++ src/nopoll_hostname_validation.c | 135 ++++++++++++++++ src/nopoll_hostname_validation.h | 33 ++++ src/nopoll_private.h | 1 + test/hostname-check.pem | 81 ++++++++++ test/nopoll-regression-client.c | 201 +++++++++++++++++++++++- 14 files changed, 820 insertions(+), 7 deletions(-) create mode 100644 src/nopoll_hostcheck.c create mode 100644 src/nopoll_hostcheck.h create mode 100644 src/nopoll_hostname_compare.c create mode 100644 src/nopoll_hostname_compare.h create mode 100644 src/nopoll_hostname_validation.c create mode 100644 src/nopoll_hostname_validation.h create mode 100644 test/hostname-check.pem diff --git a/src/Makefile.am b/src/Makefile.am index abfbeab..e1f1494 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,10 @@ libnopoll_la_SOURCES = \ nopoll_io.c \ nopoll_msg.c \ nopoll_win32.c \ - nopoll_conn_opts.c + nopoll_conn_opts.c \ + nopoll_hostname_validation.c \ + nopoll_hostname_compare.c \ + nopoll_hostcheck.c libnopollinclude_HEADERS = \ nopoll.h \ @@ -39,7 +42,10 @@ libnopollinclude_HEADERS = \ nopoll_io.h \ nopoll_msg.h \ nopoll_win32.h \ - nopoll_conn_opts.h + nopoll_conn_opts.h \ + nopoll_hostname_validation.h \ + nopoll_hostname_compare.h \ + nopoll_hostcheck.h libnopoll_la_LDFLAGS = -no-undefined -export-symbols-regex '^(nopoll|__nopoll|_nopoll).*' diff --git a/src/nopoll.h b/src/nopoll.h index 8e71107..05a1560 100644 --- a/src/nopoll.h +++ b/src/nopoll.h @@ -56,6 +56,7 @@ BEGIN_C_DECLS #include #include #include +#include /** * \addtogroup nopoll_module diff --git a/src/nopoll_conn.c b/src/nopoll_conn.c index 14b6ec8..23b5b11 100644 --- a/src/nopoll_conn.c +++ b/src/nopoll_conn.c @@ -47,7 +47,7 @@ #include #include - +#include #if defined(NOPOLL_OS_UNIX) # include #endif @@ -1020,6 +1020,28 @@ noPollConn * __nopoll_conn_new_common (noPollCtx * ctx, return conn; } + + /* Check for opts to verify hostname validation during conn handshake */ + if (options == NULL || options->host_verify) + { + noPollHostValidationStatus status = ERROR; + /* hostname should be validated without http/https, so pass conn->host_name */ + status = nopoll_validate_hostname(server_cert, conn->host_name); + if( status == MATCH_FOUND ) + { + nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Hostname validation SUCCESS, done as part of client \n"); + } + else + { + nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL,"Hostname validation FAILED with errno %d \n",status); + /* release connection options */ + nopoll_free (content); + nopoll_conn_shutdown (conn); + __nopoll_conn_opts_release_if_needed (options); + X509_free (server_cert); + return NULL; + } + } X509_free (server_cert); /* call to check post ssl checks after SSL finalization */ diff --git a/src/nopoll_conn_opts.c b/src/nopoll_conn_opts.c index eded07b..621af50 100644 --- a/src/nopoll_conn_opts.c +++ b/src/nopoll_conn_opts.c @@ -77,6 +77,8 @@ noPollConnOpts * nopoll_conn_opts_new (void) /* by default, disable ssl peer verification */ result->disable_ssl_verify = nopoll_true; + /* by default, enable hostname validation */ + result->host_verify = nopoll_true; return result; } @@ -176,6 +178,24 @@ void nopoll_conn_opts_ssl_peer_verify (noPollConnOpts * opts, nopoll_bool verify return; } +/** + * @brief Allows to enable hostname validation + * + * @param opts The connection option to configure. + * + * @param hostVerify nopoll_true to enable hostname validation + * otherwise, nopoll_false should be used. By default hostname validation + * is enabled. + */ + +void nopoll_conn_opts_ssl_host_verify (noPollConnOpts * opts, nopoll_bool hostVerify) +{ + if (opts == NULL) + return; + opts->host_verify = hostVerify; + return; +} + /** * @brief Allows to set Cookie header content to be sent during the * connection handshake. If configured and the remote side server is a diff --git a/src/nopoll_conn_opts.h b/src/nopoll_conn_opts.h index f6313c5..3af3d1f 100644 --- a/src/nopoll_conn_opts.h +++ b/src/nopoll_conn_opts.h @@ -69,6 +69,8 @@ void nopoll_conn_opts_set_interface (noPollConnOpts * opts, const char * _int void nopoll_conn_opts_set_extra_headers (noPollConnOpts * opts, const char * extra_headers); void nopoll_conn_opts_free (noPollConnOpts * opts); +/* hostname validation */ +void nopoll_conn_opts_ssl_host_verify (noPollConnOpts * opts, nopoll_bool verify); /** internal API **/ void __nopoll_conn_opts_release_if_needed (noPollConnOpts * options); diff --git a/src/nopoll_hostcheck.c b/src/nopoll_hostcheck.c new file mode 100644 index 0000000..913ad30 --- /dev/null +++ b/src/nopoll_hostcheck.c @@ -0,0 +1,45 @@ +#include + +static noPollHostMatchStatus nopoll_hostcheck(char *pattern, char *hostname); + +static noPollHostMatchStatus nopoll_hostcheck(char *pattern, char *hostname){ + char *pattern_wildcard = NULL; + + size_t p_length = strlen(pattern); + size_t h_length = strlen(hostname); + /* pattern or hostname should not end with "." */ + if( pattern[p_length-1] == '.' || hostname[h_length-1] == '.') + { + return MATCH_FAIL; + } + + pattern_wildcard = strchr(pattern, '*'); + + if (pattern_wildcard == NULL) { + return nopoll_hostname_compare_without_wildcard(pattern,hostname) ? MATCH_SUCCESS : MATCH_FAIL; + } + if (nopoll_hostname_validate_inet(AF_INET, hostname) > 0) { + return MATCH_FAIL; + } + else if(nopoll_hostname_validate_inet(AF_INET6, hostname) > 0) + return MATCH_FAIL; + return nopoll_hostname_compare_with_wildcard(pattern,hostname) ? MATCH_SUCCESS : MATCH_FAIL; +} + +noPollHostMatchStatus nopoll_match_hostname(const char *pattern, const char *hostname) +{ + char *match_pattern; + char *host; + int result = MATCH_FAIL; + match_pattern = nopoll_strdup(pattern); + host = nopoll_strdup(hostname); + + if(match_pattern && host) { + result = nopoll_hostcheck(match_pattern,host); + nopoll_free(host); + nopoll_free(match_pattern); + return result; + } + return result; +} + diff --git a/src/nopoll_hostcheck.h b/src/nopoll_hostcheck.h new file mode 100644 index 0000000..6c60113 --- /dev/null +++ b/src/nopoll_hostcheck.h @@ -0,0 +1,11 @@ +#ifndef __NOPOLL_HOSTCHECK_H__ +#define __NOPOLL_HOSTCHECK_H__ + +typedef enum { + MATCH_FAIL = 0, + MATCH_SUCCESS, +} noPollHostMatchStatus; +noPollHostMatchStatus nopoll_match_hostname(const char *pattern,const char *hostname); + +#endif /* __NOPOLL_HOSTCHECK_H__ */ + diff --git a/src/nopoll_hostname_compare.c b/src/nopoll_hostname_compare.c new file mode 100644 index 0000000..3cc43a8 --- /dev/null +++ b/src/nopoll_hostname_compare.c @@ -0,0 +1,254 @@ +#include + +static int nopoll_get_delimeter_count(char * string, char *delimeter); +static int nopoll_validate_ipv4(char *hostname); +static int nopoll_validate_ipv6(char *hostname); + +char nopoll_to_lower(char ch) +{ + if(ch >= 'A' && ch <= 'Z') + return (char)('a' + ch - 'A'); + return ch; +} + +static int nopoll_get_delimeter_count(char * string, char *delimeter) { + int count = 0; + while (*string != '\0') { + if (*string == *delimeter) { + count +=1; + } + string++; + } + return count; +} + +int nopoll_hostname_compare_without_wildcard(char *pattern, char *hostname) { + while (*pattern != '\0' && *hostname != '\0') { + if( nopoll_to_lower(*pattern) != nopoll_to_lower(*hostname) ){ + return 0; + } + pattern++; + hostname++; + } + if (*pattern == '\0' && *hostname == '\0') { + return 1; + } + return 0; +} + +int nopoll_hostname_compare_with_wildcard(char *pattern, char *hostname) { + int cmp_result = 0; + int split_count = 0; + char *p_split_first, *p_split_second, *h_split_first, *h_split_second; + + /* Get the string after two dots (.) for comparison (without wildcard) + * as to long wildcard is not supported */ + p_split_first = strchr(pattern, '.'); + h_split_first = strchr(hostname,'.'); + + if (p_split_first != NULL && h_split_first != NULL) { + p_split_second = strchr(++p_split_first, '.'); + h_split_second = strchr(++h_split_first, '.'); + } + else { + return 0; + } + + if (p_split_second && h_split_second) { + cmp_result = nopoll_hostname_compare_without_wildcard(++p_split_second, ++h_split_second); + if (!cmp_result){ + return 0; + } + } + else { + return 0; + } + /* Get string till two dots (.) for wild card comparison */ + int p_index = p_split_second - pattern; + int h_index = h_split_second - hostname; + + *(pattern + (p_index)) = '\0'; + *(hostname + (h_index)) = '\0'; + + while ((*pattern!= '\0') && (*hostname != '\0')) { + /* Continue reading if both the charecters are same */ + if ( nopoll_to_lower(*pattern) == nopoll_to_lower(*hostname)) { + pattern++; + hostname++; + } + /* check if hostname contains wildcard */ + else if (*pattern == '*') { + + if(*(++pattern) == '.') { + /* If hostname contains only * in first octet then skip all charecters in pattern + * Then do comparison of next octet*/ + if (split_count == 0) { + h_index = h_split_first - hostname; + hostname += h_index; + ++pattern; + } + else { + h_index = h_split_second - hostname; + hostname += h_index; + if (*hostname == '\0') { + return 1; + } + } + } + else { + /* Will support partial wildcard comparison */ + char *p_part = strchr(pattern, '.'); + p_index = p_part - pattern; + + /* Skip all charecters in pattern and compare the charecters remained after '*' in hostname string */ + while (*(hostname + p_index) != '.'){ + hostname++; + } + + while (p_index) { + if ( nopoll_to_lower(*hostname) != nopoll_to_lower(*pattern)) { + return 0; + } + pattern++; + hostname++; + p_index -= 1; + } + } + /* After first octet comparison make this on, so that wildcard comparison for next octet will get rejected */ + split_count = 1; + } + else if ( nopoll_to_lower(*pattern) != nopoll_to_lower(*hostname)) { + return 0; + } + } + /* Outside while, check whether we have traversed both the strings completely or not */ + if ((*pattern == '\0') && (*hostname == '\0') ) { + return 1; + } + else { + return 0; + } +} + +static int nopoll_validate_ipv4(char *ip_addr){ + int octets = 0; + char delimeter[] = {"."}; + unsigned char *ip_val; + + unsigned char tmp[4]; + ip_val = tmp; + *ip_val = 0; + + char *ip_addr_tmp = ip_addr; + + octets = nopoll_get_delimeter_count(ip_addr_tmp, delimeter); + if (octets != 3){ + return 0; + } + + while (*ip_addr_tmp != '\0'){ + + if(!isdigit(*ip_addr_tmp)){ + return 0; + } + + while ( (*ip_addr_tmp != *delimeter) && (*ip_addr_tmp != '\0')) { + unsigned int val = (*ip_val) * 10 + (unsigned int)(*ip_addr_tmp - '0') ; + *ip_val = val; + ip_addr_tmp++; + + if(val >255){ + return 0; + } + } + /* IP should not end with . */ + if((*ip_addr_tmp == *delimeter) && (*(ip_addr_tmp+1) == '\0')) + return 0; + if(*ip_addr_tmp != '\0'){ + *ip_val = 0; + ip_addr_tmp++; + } + } + return 1; +} + +static int nopoll_validate_ipv6(char *ip_addr){ + int octets = 0, colon_count =0, chr_count = 0, octet_count = 0; + char *ip_addr_rem = NULL; + nopoll_bool ipv4_valid = nopoll_false; + static char ip_digits[] = "0123456789abcdef"; + + char *ip_addr_tmp = ip_addr; + /* If ip starts with ":"" then next chr should be ":"" only */ + if (*ip_addr_tmp == ':' && *(ip_addr_tmp+1) != ':'){ + return 0; + } + + octets = nopoll_get_delimeter_count(ip_addr_tmp, ":"); + if (octets > 7) + return 0; + + while (*ip_addr_tmp != '\0'){ + + while((*ip_addr_tmp != ':') && (*ip_addr_tmp != '\0')){ + if (strchr(ip_digits, nopoll_to_lower(*ip_addr_tmp))){ + ip_addr_tmp++; + chr_count +=1; + /* octet length should not be more than 4 */ + if (chr_count > 4) + return 0; + } + else if (*ip_addr_tmp == '.') + break; + else + return 0; + } + + if (*ip_addr_tmp == ':') { + if (*(ip_addr_tmp+1) == '\0' && colon_count == 0){ + return 0; + } + /* Ipv6 should not contain "::" (consecutive zero's representation) more than one */ + if (*(ip_addr_tmp+1) == ':') { + colon_count +=1; + if(colon_count >1) + return 0; + } + ip_addr_tmp++; + ip_addr_rem = ip_addr_tmp; + chr_count = 0; + octet_count +=1; + continue; + } + /* validate ipv6 dual addressing support (IPv6 + IPv4) */ + if (*ip_addr_tmp == '.'){ + if (octet_count > 6) + return 0; + if(colon_count ==0 && octet_count < 6) + return 0; + + if(nopoll_validate_ipv4(ip_addr_rem) > 0) { + ipv4_valid = nopoll_true; + break; + } + return 0; + } + } + + if(colon_count == 0 && octet_count != 7 && !ipv4_valid) + return 0; + return 1; +} + +int nopoll_hostname_validate_inet(int addr_fam, char *hostname) { + + switch(addr_fam) { + case AF_INET: + return (nopoll_validate_ipv4(hostname)); + case AF_INET6: + return (nopoll_validate_ipv6(hostname)); + default: + errno = EAFNOSUPPORT; + return (-1); + } +} diff --git a/src/nopoll_hostname_compare.h b/src/nopoll_hostname_compare.h new file mode 100644 index 0000000..ac230f5 --- /dev/null +++ b/src/nopoll_hostname_compare.h @@ -0,0 +1,9 @@ +#ifndef __NOPOLL_HOSTNAME_COMPARE_H__ +#define __NOPOLL_HOSTNAME_COMPARE_H__ + +int nopoll_hostname_compare_without_wildcard(char *pattern, char *hostname); +int nopoll_hostname_compare_with_wildcard(char *pattern, char *hostname); +int nopoll_hostname_validate_inet(int addr_fam, char *hostname); +char nopoll_to_lower(char ch); + +#endif /* __NOPOLL_HOSTNAME_COMPARE_H__*/ \ No newline at end of file diff --git a/src/nopoll_hostname_validation.c b/src/nopoll_hostname_validation.c new file mode 100644 index 0000000..d18af82 --- /dev/null +++ b/src/nopoll_hostname_validation.c @@ -0,0 +1,135 @@ +#include + +static noPollHostValidationStatus nopoll_cert_common_name_host_check(const X509 *server_cert, const char *hostname); +static noPollHostValidationStatus nopoll_cert_subject_alt_name_host_check(const X509 *server_cert, const char *hostname); + +/** +* Tries to find a match for hostname in the certificate's Common Name field. +* +* Returns MATCH_FOUND if a match was found. +* Returns MATCH_NOT_FOUND if no matches were found. +* Returns MAL_FORMED_CERTIFICATE if any of the hostnames had a NULL character embedded in it. +* Returns ERROR if there was an error. +*/ +static noPollHostValidationStatus nopoll_cert_common_name_host_check(const X509 *server_cert, const char *hostname) +{ + int cn_last_pos = -1; + const char *cn_data = NULL; + X509_NAME_ENTRY *cn_entry = NULL; + ASN1_STRING *cn_asn1_val = NULL; + + /* Find the position of the CN field in the Subject field of the certificate*/ + cn_last_pos = X509_NAME_get_index_by_NID(X509_get_subject_name((X509 *) server_cert), NID_commonName, cn_last_pos); + if (cn_last_pos < 0) { + return ERROR; + } + + /* Extract the CN field*/ + cn_entry = X509_NAME_get_entry(X509_get_subject_name((X509 *) server_cert), cn_last_pos); + if (cn_entry == NULL) { + return ERROR; + } + + cn_asn1_val = X509_NAME_ENTRY_get_data(cn_entry); + if (cn_asn1_val == NULL) { + return ERROR; + } + + /* Convert the CN field to a C string*/ +#if OPENSSL_VERSION_NUMBER >= 0x010100000L + cn_data = (char *)ASN1_STRING_get0_data(cn_asn1_val); +#else + cn_data = (char *)ASN1_STRING_data(cn_asn1_val); +#endif + + /* Make sure there isn't an embedded NULL character in the CN*/ + if (ASN1_STRING_length(cn_asn1_val) != strlen(cn_data)) { + return MAL_FORMED_CERTIFICATE; + } + + /* Compare expected hostname with the CN*/ + if (nopoll_match_hostname(cn_data, hostname)) { + return MATCH_FOUND; + } + else { + return MATCH_NOT_FOUND; + } +} + + +/** +* Will find a match for hostname in the certificate's Subject Alternative Name extension field. +* +* Returns MATCH_FOUND if a match was found. +* Returns MATCH_NOT_FOUND if no matches were found. +* Returns MAL_FORMED_CERTIFICATE if any of the hostnames had a NULL character embedded in it. +* Returns NO_SAN_PRESENT if the SAN extension was not present in the certificate. +*/ +static noPollHostValidationStatus nopoll_cert_subject_alt_name_host_check(const X509 *server_cert, const char *hostname) +{ + STACK_OF(GENERAL_NAME) *san_gen_names = NULL; + GENERAL_NAME *general_name_value; + noPollHostValidationStatus result = MATCH_NOT_FOUND; + + /* Try to extract the names within the SAN extension from the certificate*/ + san_gen_names = X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name, NULL, NULL); + if (san_gen_names == NULL) { + return NO_SAN_PRESENT; + } + + /* Check each name within the extension*/ + while (sk_GENERAL_NAME_num(san_gen_names) > 0) { + general_name_value = sk_GENERAL_NAME_pop(san_gen_names); + if (general_name_value->type == GEN_DNS) { + /* Current name is a DNS name, let's check it*/ + #if OPENSSL_VERSION_NUMBER >= 0x010100000L + char *dns_name = (char *) ASN1_STRING_get0_data(general_name_value->d.dNSName); + #else + char *dns_name = (char *) ASN1_STRING_data(general_name_value->d.dNSName); + #endif + + /* Make sure there isn't an embedded NULL character in the DNS name*/ + if ((size_t)ASN1_STRING_length(general_name_value->d.dNSName) != strlen(dns_name)) { + result = MAL_FORMED_CERTIFICATE; + break; + } + else { /* Compare expected hostname with the DNS name*/ + if (nopoll_match_hostname(dns_name, hostname)) { + result = MATCH_FOUND; + break; + } + } + } + } + sk_GENERAL_NAME_pop_free(san_gen_names, GENERAL_NAME_free); + return result; +} + + +/** +* This function Validates the server's identity by looking for the expected hostname in the +* server's certificate. As described in RFC 6125, it first tries to find a match +* in the Subject Alternative Name extension. If the extension is not present in +* the certificate, it checks the Common Name instead. +* +* Returns MATCH_FOUND if a match was found. +* Returns MATCH_NOT_FOUND if no matches were found. +* Returns MAL_FORMED_CERTIFICATE if any of the hostnames had a NUL character embedded in it. +* Returns ERROR if there was an error. +*/ + +noPollHostValidationStatus nopoll_validate_hostname(const X509 *server_cert, const char *hostname) { + noPollHostValidationStatus result; + + if((server_cert == NULL) || (hostname == NULL)) + return ERROR; + + /* First try the Subject Alternative Names extension*/ + result = nopoll_cert_subject_alt_name_host_check(server_cert, hostname); + if (result == NO_SAN_PRESENT) { + /* Extension was not found: try the Common Name*/ + result = nopoll_cert_common_name_host_check(server_cert, hostname); + } + + return result; +} diff --git a/src/nopoll_hostname_validation.h b/src/nopoll_hostname_validation.h new file mode 100644 index 0000000..b685b7b --- /dev/null +++ b/src/nopoll_hostname_validation.h @@ -0,0 +1,33 @@ +#ifndef __NOPOLL_HOSTNAME_VALIDATION_H__ +#define __NOPOLL_HOSTNAME_VALIDATION_H__ + +#include +#include + +BEGIN_C_DECLS + +#include +#include + +typedef enum { + MATCH_FOUND, + MATCH_NOT_FOUND, + NO_SAN_PRESENT, + MAL_FORMED_CERTIFICATE, + ERROR +} noPollHostValidationStatus; + +/** +* Validates the server's identity by looking for the expected hostname in the +* server's certificate. As described in RFC 6125, it first tries to find a match +* in the Subject Alternative Name extension. If the extension is not present in +* the certificate, it checks the Common Name instead. +* +* Returns MATCH_FOUND if a match was found. +* Returns MATCH_NOT_FOUND if no matches were found. +* Returns MAL_FORMED_CERTIFICATE if any of the hostnames had a NUL character embedded in it. +* Returns ERROR if there was an error. +*/ +noPollHostValidationStatus nopoll_validate_hostname(const X509 *server_cert, const char *hostname); +END_C_DECLS +#endif /* __NOPOLL_HOSTNAME_VALIDATION_H__ */ diff --git a/src/nopoll_private.h b/src/nopoll_private.h index 021870e..af67189 100644 --- a/src/nopoll_private.h +++ b/src/nopoll_private.h @@ -399,6 +399,7 @@ struct _noPollConnOpts { char * ca_certificate; nopoll_bool disable_ssl_verify; + nopoll_bool host_verify; /* cookie support */ char * cookie; diff --git a/test/hostname-check.pem b/test/hostname-check.pem new file mode 100644 index 0000000..d21938f --- /dev/null +++ b/test/hostname-check.pem @@ -0,0 +1,81 @@ +-----BEGIN CERTIFICATE----- +MIIFATCCAumgAwIBAgIJAN77SMdujDSpMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV +BAMMDCoubm9wb2xsLmNvbTAeFw0xNzAzMjQxNDQxMjZaFw0yNzAzMjIxNDQxMjZa +MBcxFTATBgNVBAMMDCoubm9wb2xsLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALWiCeEfLLyUxJkGovn7irvWz0c/HkhLwyX5mMChMNHwQg0GGBry +f/swSYv5i1KSczZwuc8X0hq48oRAd5LgeXGpnb9CDvinVJ/iUPMSaBZPXMgwagUE +1vD8MoLrjdqlpOtaI8UZs1K9POM5voJR3BDrOUcgPEwpqJBdtJ8bOMGcyzTm6G2/ +/OKsxypk1Qlbjw/ET/CDw2BoFMZl/rZmqJ8npNkA91QeYxhrccm9UKnez+isr4Xv +nCfQws1CkvFVXdTMFiSs7x9wRW6Q7sxTKsNzwuDxJuzXkYoRli98CTHmz+nJEEfa +Q5apZmoKUBx4c/bUaVXP5SSaL7TGnIXB9A61VMnThgAAnYLrgWsri2CPz3VZyFNV +FRUegTMxfzPSyMxPCd/eheyfsOlv9A7pjVtyujL981tCCUWVMarMNQCZ4AVa6qAi +5lHtDeg5dT3m4N/URJBA2lLTlmbTjciOPNnxdAAeZah/XJx++Z7QFnsRN247gZXA +L/atb7n67XlpM8b65jIiSusOEUCeAopqAnlf3yY9HYmmXQBLZZPZ8lV7Dm/CAi7f +kWNpmVkWJxlkjdV7NMWmuPwRmxQLVFz1E6NNpodsJ34WulhyokKEkDU5M+VSIC0V +76V54ROLUyxPkKcF0Fr1uMsyrIxF64ejKj7ZLn7tZh+h7KSjWYj0g5M/AgMBAAGj +UDBOMB0GA1UdDgQWBBRDwb0UAHUdZ3N43ul3ynL7ThErlTAfBgNVHSMEGDAWgBRD +wb0UAHUdZ3N43ul3ynL7ThErlTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4ICAQCbOGZfRb/DEcO15LYDViQoPB14vcpPnAilXMNERtc+VtdJf0znv7PAWEwH +ffqws8yhaWAecNfQ8y2CqVZgZTZKQwvKi6UP0cY+aXl/qyRWto/njVGdkiK21XuB +vo5xD5L023I++MeZH106V/S7b/Zm7na38yVhfObzDU0GnWm8Ozhk3CoIK7Zb0Edt +MnfIFdV1HQwb35pvyON4/1KYPACI7OUmMSPCW+icG5WUQq1vBa+lf5feg2POmN2C +m2HZJUK4JMO6FzdPNrWXO+3A8Q24xuHfDhoVCY2Uby+kVonzIt0GX3nBMCDGQxil +lefrFIG+0BGwP2+wTuiF65C1Wa1PPW79O1RI7zQaKXgoci23JRrBrVQt0zBJP6ji +KZES6IsSWtE2tMlxkVzYVBjb3Hb6Xog4rhOzYPEVBadQXhys9qCAGPIRJa7Kl9L8 +GYAUxJ+Sn8E24GoL1kYoPQY/ObJp33CJOH7Q8VwMLVxOn4ekWwGF4LmXgIonCa6L +0rHD8KqZz5UQ+EX/04pQlvn1fUs24ndKyadar4BCFFYIvFETw0gPlUCsE4bpnOBj +N/Q5HmMDdm1I25q1EtyMTHiWGDkNvWU9bRygZFck5VM1krdUMDqaRQ4P/UdysSlm +f5PJ4S+rJS4dyGgGmVmDjGxn0c8m8LbzevkmmsSrOJMp9arq1Q== +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +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 +P1TqAkHWaLYqVon5fVweJgAPVLPZnppV +-----END PRIVATE KEY----- diff --git a/test/nopoll-regression-client.c b/test/nopoll-regression-client.c index aa81997..884cc71 100644 --- a/test/nopoll-regression-client.c +++ b/test/nopoll-regression-client.c @@ -215,6 +215,127 @@ nopoll_bool test_01_masking (void) { return nopoll_true; } + +nopoll_bool test_01_hostname_check (void) { + + /*success case*/ + if(! nopoll_match_hostname("www.example.com", "www.example.com")) + { + printf ("ERROR (1): expected to match hostname validation www.example.com..\n"); + return nopoll_false; + } + if(! nopoll_match_hostname("*.example.com", "www.example.com")) + { + printf ("ERROR (1): expected to match hostname validation *.example.com..\n"); + return nopoll_false; + } + if(! nopoll_match_hostname("xxx*.example.com", "xxxwww.example.com")) + { + printf ("ERROR (1): expected to match hostname validation xxx*.example.com..\n"); + return nopoll_false; + } + if(! nopoll_match_hostname("f*.example.com", "foo.example.com")) + { + printf ("ERROR (1): expected to match hostname validation f*.example.com..\n"); + return nopoll_false; + } + if(! nopoll_match_hostname("192.168.0.0", "192.168.0.0")) + { + printf ("ERROR (1): expected to match hostname validation 192.168.0.0..\n"); + return nopoll_false; + } + if(! nopoll_match_hostname("example.com","example.com")) + { + printf ("ERROR (1): expected to match hostname validation example.com..\n"); + return nopoll_false; + } + if(! nopoll_match_hostname("*.*.com", "www.example.com")) + { + printf ("ERROR (1): expected to match hostname validation *.*.com\n"); + return nopoll_false; + } + if(! nopoll_match_hostname("fe80::3285:a9ff:fe46:b619","fe80::3285:a9ff:fe46:b619")) + { + printf ("ERROR (1): expected to match hostname validation fe80::3285:a9ff:fe46:b619..\n"); + return nopoll_false; + } + + /*Failure case*/ + + if(nopoll_match_hostname("xxx.example.com", "www.example.com")) + { + printf ("ERROR (1): expected not to match hostname validation xxx.example.com\n"); + return nopoll_false; + } + if(nopoll_match_hostname("www.example.", "www.example.")) + { + printf ("ERROR (1): expected not to match hostname validation xxx.example.com\n"); + return nopoll_false; + } + if(nopoll_match_hostname("*", "www.example.com")) + { + printf ("ERROR (1): expected not to match hostname validation for * with www.example.com\n"); + return nopoll_false; + } + if(nopoll_match_hostname("*.example.com", "baa.foo.example.com")) + { + printf ("ERROR (1): expected to not match hostname validation *.example.com with baa.foo.example.com..\n"); + return nopoll_false; + } + if(nopoll_match_hostname( "f*.example.com", "baa.example.com")) + { + printf ("ERROR (1): expected to not match hostname validation f*.example.com with baa.example.com\n"); + return nopoll_false; + } + if(nopoll_match_hostname("*.com", "example.com")) + { + printf ("ERROR (1): expected to not match hostname validation *.com with example.com.\n"); + return nopoll_false; + } + if(nopoll_match_hostname("*fail.com", "example.com")) + { + printf ("ERROR (1): expected to not match hostname validation for *fail.com with example.com\n"); + return nopoll_false; + } + if(nopoll_match_hostname("*.example.", "www.example.")) + { + printf ("ERROR (1): expected to not match hostname validation for *.example. with www.example.\n"); + return nopoll_false; + } + if(nopoll_match_hostname("*.example.", "www.example")) + { + printf ("ERROR (1): expected to not match hostname validation for *.example. with www.example\n"); + return nopoll_false; + } + if(nopoll_match_hostname("", "www")) + { + printf ("ERROR (1): expected to not match hostname validation NULL with www \n"); + return nopoll_false; + } + if(nopoll_match_hostname("*", "www")) + { + printf ("ERROR (1): expected to not match hostname validation * with www\n"); + return nopoll_false; + } + if(nopoll_match_hostname("*::3285:a9ff:fe46:b619","fe80::3285:a9ff:fe46:b619")) + { + printf ("ERROR (1): expected to not match hostname validation *::3285:a9ff:fe46:b619 with fe80::3285:a9ff:fe46:b619 \n"); + return nopoll_false; + } + if(nopoll_match_hostname("*.168.0.0" , "192.168.0.0")) + { + printf ("ERROR (1): expected to not match hostname validation *.168.0.0 with 192.168.0.0\n"); + return nopoll_false; + } + if(nopoll_match_hostname("www.example.com" , "192.168.0.0")) + { + printf ("ERROR (1): expected to not match hostname validation for www.example.com with 192.168.0.0\n"); + return nopoll_false; + } + return nopoll_true; +} + + nopoll_bool test_01 (void) { noPollCtx * ctx; noPollConn * conn; @@ -1045,6 +1166,50 @@ nopoll_bool test_05 (void) { return nopoll_true; } + +nopoll_bool test_05_hostname_validation (void) { + + char * fileName = "hostname-check.pem"; + char *hostname_valid = "test.nopoll.com"; + char *hostname_invalid = "invalid.com"; + FILE *fp = NULL; + + #if defined(NOPOLL_OS_WIN32) + fp = fopen (fileName, "rb"); + #else + fp = fopen (fileName, "r"); + #endif + + if(!fp) + { + printf("unable to open cert file for hostname validation: %s\n", fileName); + return nopoll_false; + } + + X509 *cert = PEM_read_X509(fp, NULL, NULL, NULL); + if(!cert) + { + printf("unable to parse certificate for hostname validation : %s\n", fileName); + fclose(fp); + return nopoll_false; + } + + if(nopoll_validate_hostname(cert,hostname_valid)) + { + printf("hostname %s doesn't match with dnsname \n",hostname_valid); + return nopoll_false; + } + + if(!nopoll_validate_hostname(cert, hostname_invalid)) + { + printf("hostname %s matched with dnsname \n",hostname_invalid); + return nopoll_false; + } + X509_free(cert); + fclose(fp); + return nopoll_true; +} + nopoll_bool test_06 (void) { noPollCtx * ctx; @@ -1057,6 +1222,7 @@ nopoll_bool test_06 (void) { /* disable verification */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* call to create a connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1235", NULL, NULL, NULL, NULL); @@ -1105,6 +1271,7 @@ nopoll_bool test_06a (void) { /* disable verification */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* call to create a connection */ conn = nopoll_conn_tls_new6 (ctx, opts, "::1", "2235", NULL, NULL, NULL, NULL); @@ -1153,6 +1320,7 @@ nopoll_bool test_07 (void) { /* disable verification */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* call to create a connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1235", NULL, NULL, NULL, NULL); @@ -1844,6 +2012,7 @@ nopoll_bool test_18 (void) { /* disable verification */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* call to create a connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1235", NULL, NULL, NULL, NULL); @@ -1882,6 +2051,7 @@ nopoll_bool test_19 (void) { /* create options */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_SSLV23); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1236", NULL, NULL, NULL, NULL); @@ -1905,6 +2075,7 @@ nopoll_bool test_19 (void) { /* create options */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_SSLV23); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1235", NULL, NULL, NULL, NULL); @@ -1926,6 +2097,7 @@ nopoll_bool test_19 (void) { /* create options */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_SSLV3); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ printf ("Test 19: checking SSLv3 with TLSv1..\n"); @@ -1953,6 +2125,7 @@ nopoll_bool test_19 (void) { /* create options */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_TLSV1); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1235", NULL, NULL, NULL, NULL); @@ -1976,6 +2149,7 @@ nopoll_bool test_19 (void) { /* create options */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_TLSV1_1); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1238", NULL, NULL, NULL, NULL); @@ -1997,6 +2171,7 @@ nopoll_bool test_19 (void) { /* create options */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_TLSV1_1); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_tls_new6 (ctx, opts, "::1", "2238", NULL, NULL, NULL, NULL); @@ -2021,6 +2196,7 @@ nopoll_bool test_19 (void) { /* create options */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_TLSV1_2); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1240", NULL, NULL, NULL, NULL); @@ -2129,6 +2305,7 @@ nopoll_bool test_21 (void) { NULL, /* ca certificate */ "root.pem"); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1239", NULL, NULL, NULL, NULL); if (! test_sending_and_check_echo (conn, "Test 21", "This is a test")) { printf ("ERROR: it should WORK, client certificate isn't working..\n"); @@ -2208,7 +2385,7 @@ nopoll_bool test_22 (void) { /* disable verification */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); - + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* call to create a connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1235", NULL, NULL, NULL, NULL); if (! nopoll_conn_is_ok (conn)) { @@ -2336,7 +2513,7 @@ nopoll_bool test_23 (void) { /* disable verification */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); - + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* call to create a connection */ conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1235", NULL, NULL, NULL, NULL); if (! nopoll_conn_is_ok (conn)) { @@ -2354,6 +2531,7 @@ nopoll_bool test_23 (void) { /* call to create a connection second connection */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_ssl_peer_verify (opts, nopoll_false); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); conn = nopoll_conn_tls_new (ctx, opts, "localhost", "1235", NULL, NULL, NULL, NULL); if (! nopoll_conn_is_ok (conn)) { printf ("ERROR: Expected to find proper client connection status, but found error..\n"); @@ -2390,6 +2568,7 @@ nopoll_bool test_24 (void) { /* configure cookie */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_cookie (opts, "theme=light; sessionToken=abc123"); + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_new_opts (ctx, opts, "localhost", "1234", NULL, NULL, NULL, NULL); @@ -2445,7 +2624,7 @@ nopoll_bool test_25_check_cookie (noPollCtx * ctx, const char * cookie) { /* set a cookie bigger than 1044 */ nopoll_conn_opts_set_cookie (opts, cookie); - + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_new_opts (ctx, opts, "localhost", "1234", NULL, NULL, NULL, NULL); if (! nopoll_conn_is_ok (conn)) { @@ -2649,7 +2828,7 @@ nopoll_bool test_29 (void) { /* configure extra headers */ opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_extra_headers (opts, "\r\nfoo: bar"); - + nopoll_conn_opts_ssl_host_verify (opts, nopoll_false); /* create connection */ conn = nopoll_conn_new_opts (ctx, opts, "localhost", "1234", NULL, NULL, NULL, NULL); if (! nopoll_conn_is_ok (conn)) { @@ -2927,6 +3106,13 @@ int main (int argc, char ** argv) printf ("Test 01-masking: Library websocket content masking support [ FAILED ]\n"); return -1; } + + if (test_01_hostname_check ()) { + printf ("Test 01_hostname_check: Library websocket hostname validation [ OK ]\n"); + }else { + printf ("Test 01_hostname_check: Library websocket hostname validation [ FAILED ]\n"); + return -1; + } if (test_01 ()) { printf ("Test 01: Simple connect and disconnect [ OK ]\n"); @@ -3023,6 +3209,13 @@ int main (int argc, char ** argv) return -1; } + if (test_05_hostname_validation()) { + printf ("Test 05 hostname_validation: testing basic TLS connect with hostname validation [ OK ]\n"); + } else { + printf ("Test 05 hostname_validation: testing basic TLS connect with hostname validation[ FAILED ]\n"); + return -1; + } + if (test_06 ()) { printf ("Test 06: testing basic TLS connect [ OK ]\n"); } else {