From d82a10217ad5ac09500e272b74cdacb4bf04414b Mon Sep 17 00:00:00 2001
From: Roxie Linden <roxie@lindenlab.com>
Date: Mon, 26 Apr 2010 17:41:21 -0700
Subject: [PATCH] Fix issue parsing wildcard cns in certificates CR: Karina

---
 indra/newview/llsechandler_basic.cpp          | 46 +++++++++++++++----
 .../newview/tests/llsechandler_basic_test.cpp | 31 +++++++++++--
 2 files changed, 62 insertions(+), 15 deletions(-)

diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index 51e250ffc6..df55ccf142 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -782,23 +782,49 @@ bool _cert_hostname_wildcard_match(const std::string& hostname, const std::strin
 {
 	std::string new_hostname = hostname;
 	std::string new_cn = common_name;
-	int subdomain_pos = new_hostname.find_first_of('.');
-	int subcn_pos = new_cn.find_first_of('.');
 	
-	while((subcn_pos != std::string::npos) && (subdomain_pos != std::string::npos))
+	// find the last '.' in the hostname and the match name.
+	int subdomain_pos = new_hostname.find_last_of('.');
+	int subcn_pos = new_cn.find_last_of('.');
+	
+	// if the last char is a '.', strip it
+	if(subdomain_pos == (new_hostname.length()-1))
+	{
+		new_hostname = new_hostname.substr(0, subdomain_pos);
+		subdomain_pos = new_hostname.find_last_of('.');
+	}
+	if(subcn_pos == (new_cn.length()-1))
 	{
-		// snip out the first subdomain and cn element
+		new_cn = new_cn.substr(0, subcn_pos);
+		subcn_pos = new_cn.find_last_of('.');
+	}	
 
-		if(!_cert_subdomain_wildcard_match(new_hostname.substr(0, subdomain_pos),
-										   new_cn.substr(0, subcn_pos)))
+	// Check to see if there are any further '.' in the string.  
+	while((subcn_pos != std::string::npos) && (subdomain_pos != std::string::npos))
+	{
+		// snip out last subdomain in both the match string and the hostname
+		// The last bit for 'my.current.host.com' would be 'com'  
+		std::string cn_part = new_cn.substr(subcn_pos+1, std::string::npos);
+		std::string hostname_part = new_hostname.substr(subdomain_pos+1, std::string::npos);
+		
+		if(!_cert_subdomain_wildcard_match(new_hostname.substr(subdomain_pos+1, std::string::npos),
+										   cn_part))
 		{
 			return FALSE;
 		}
-		new_hostname = new_hostname.substr(subdomain_pos+1, std::string::npos);
-		new_cn = new_cn.substr(subcn_pos+1, std::string::npos);
-		subdomain_pos = new_hostname.find_first_of('.');
-		subcn_pos = new_cn.find_first_of('.');
+		new_hostname = new_hostname.substr(0, subdomain_pos);
+		new_cn = new_cn.substr(0, subcn_pos);
+		subdomain_pos = new_hostname.find_last_of('.');
+		subcn_pos = new_cn.find_last_of('.');
+	}	
+	// check to see if the most significant portion of the common name is '*'.  If so, we can
+	// simply return success as child domains are also matched.
+	if(new_cn == "*")
+	{
+		// if it's just a '*' we support all child domains as well, so '*.
+		return TRUE;
 	}
+	
 	return _cert_subdomain_wildcard_match(new_hostname, new_cn);
 
 }
diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp
index 3f4474e23a..ba448d4b5b 100644
--- a/indra/newview/tests/llsechandler_basic_test.cpp
+++ b/indra/newview/tests/llsechandler_basic_test.cpp
@@ -702,12 +702,18 @@ namespace tut
 	{
 		ensure("simple name match", 
 			   _cert_hostname_wildcard_match("foo", "foo"));
-		
+
 		ensure("simple name match, with end period", 
 			   _cert_hostname_wildcard_match("foo.", "foo."));
 		
 		ensure("simple name match, with begin period", 
 			   _cert_hostname_wildcard_match(".foo", ".foo"));		
+
+		ensure("simple name match, with mismatched period cn", 
+			   _cert_hostname_wildcard_match("foo.", "foo"));	
+		
+		ensure("simple name match, with mismatched period hostname", 
+			   _cert_hostname_wildcard_match("foo", "foo."));	
 		
 		ensure("simple name match, with subdomain", 
 			   _cert_hostname_wildcard_match("foo.bar", "foo.bar"));	
@@ -772,11 +778,26 @@ namespace tut
 		ensure("end periods", 
 			   _cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com."));	
 		
-		ensure("mismatch end period", 
-			   !_cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com"));
+		ensure("match end period", 
+			   _cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com"));
+		
+		ensure("match end period2", 
+			   _cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com."));
+		
+		ensure("wildcard mismatch", 
+			   !_cert_hostname_wildcard_match("bar.com", "*.bar.com"));	
+		
+		ensure("wildcard match", 
+			   _cert_hostname_wildcard_match("foo.bar.com", "*.bar.com"));	
+
+		ensure("wildcard match", 
+			   _cert_hostname_wildcard_match("foo.foo.bar.com", "*.bar.com"));	
+		
+		ensure("wildcard match", 
+			   _cert_hostname_wildcard_match("foo.foo.bar.com", "*.*.com"));
 		
-		ensure("mismatch end period2", 
-			   !_cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com."));				
+		ensure("wildcard mismatch", 
+			   !_cert_hostname_wildcard_match("foo.foo.bar.com", "*.foo.com"));			
 	}
 	
 	// test cert chain
-- 
GitLab