From 3da7c6207ebc4002bc1b0260d7d7c581c2fd635e Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 17 Jun 2013 21:19:01 +0200 Subject: [PATCH 3/5] 1) Add support for Wildcard Certificates 2) For Gateway connections compare against gateway host name instead of target host --- libfreerdp-core/tls.c | 66 ++++++++++++++++++++++++++++++++++++++++++++------- libfreerdp-core/tls.h | 1 + 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/libfreerdp-core/tls.c b/libfreerdp-core/tls.c index b05100e..db09960 100644 --- a/libfreerdp-core/tls.c +++ b/libfreerdp-core/tls.c @@ -25,6 +25,7 @@ boolean tls_connect(rdpTls* tls) { int connection_status; + char *hostname; tls->ctx = SSL_CTX_new(TLSv1_client_method()); @@ -80,7 +81,13 @@ boolean tls_connect(rdpTls* tls) return false; } - if (!tls_verify_certificate(tls, tls->cert, tls->settings->hostname)) { + if (tls->settings->ts_gateway) + hostname = tls->settings->tsg_hostname; + else + hostname = tls->settings->hostname; + + if (!tls_verify_certificate(tls, tls->cert, hostname)) + { printf("tls_connect: certificate not trusted, aborting.\n"); tls_disconnect(tls); return false; @@ -253,6 +260,50 @@ CryptoCert tls_get_certificate(rdpTls* tls) return cert; } +boolean tls_match_hostname(char *pattern, int pattern_length, char *hostname) +{ + if (strlen(hostname) == pattern_length) + { + if (memcmp((void*) hostname, (void*) pattern, pattern_length) == 0) + return true; + } + + /* ccpp: Check for wildcard certificates */ + if (memchr(pattern, '*', pattern_length) != NULL) + { + /* The wildcard matches one subdomain level (all except a dot) */ + + int pattern_position = 0; + int hostname_position = 0; + + for(; hostname[hostname_position] && pattern_position < pattern_length; pattern_position++, hostname_position++) + { + if( pattern[pattern_position] == '*' ) { + while( hostname[hostname_position] != '.' && hostname[hostname_position] != '\0' ) + hostname_position++; + + pattern_position++; + } + + if (hostname[hostname_position] != pattern[pattern_position] ) + { + return false; + } + } + } + + if (pattern_length > 2 && pattern[0] == '*' && pattern[1] == '.') + { + char *check_hostname = &hostname[ strlen(hostname) - pattern_length+1 ]; + if (memcmp((void*) check_hostname, (void*) &pattern[1], pattern_length - 1) == 0 ) + { + return true; + } + } + + return false; +} + boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) { int match; @@ -288,11 +339,8 @@ boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) if (common_name != NULL) { - if (strlen(hostname) == common_name_length) - { - if (memcmp((void*) hostname, (void*) common_name, common_name_length) == 0) - hostname_match = true; - } + if (tls_match_hostname(common_name, common_name_length, hostname)) + hostname_match = true; } /* compare against alternative names */ @@ -301,10 +349,10 @@ boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) { for (index = 0; index < alt_names_count; index++) { - if (strlen(hostname) == alt_names_lengths[index]) + if (tls_match_hostname(alt_names[index], alt_names_lengths[index], hostname)) { - if (memcmp((void*) hostname, (void*) alt_names[index], alt_names_lengths[index]) == 0) - hostname_match = true; + hostname_match = true; + break; } } } diff --git a/libfreerdp-core/tls.h b/libfreerdp-core/tls.h index e941dd0..b2218f9 100644 --- a/libfreerdp-core/tls.h +++ b/libfreerdp-core/tls.h @@ -50,6 +50,7 @@ int tls_read(rdpTls* tls, uint8* data, int length); int tls_write(rdpTls* tls, uint8* data, int length); CryptoCert tls_get_certificate(rdpTls* tls); +boolean tls_match_hostname(char *pattern, int pattern_length, char *hostname); boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname); void tls_print_certificate_error(char* hostname, char* fingerprint); void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count); -- 2.5.5