From 3da7c6207ebc4002bc1b0260d7d7c581c2fd635e Mon Sep 17 00:00:00 2001
From: Chris <ccpp@gmx.at>
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