Merge pull request #15 from tuxad-loudmouth/master
authorMikael <mikael@lilotux.net>
Sat, 14 Feb 2015 19:34:43 +0100
changeset 662 9600dc32c15c
parent 659 761839714ea3 (current diff)
parent 661 22492003e3f7 (diff)
child 663 3697251ef911
Merge pull request #15 from tuxad-loudmouth/master SSL/TLS protocol usage; use SANs of CERTs
--- a/loudmouth/lm-ssl-openssl.c	Sat Feb 14 19:34:24 2015 +0100
+++ b/loudmouth/lm-ssl-openssl.c	Sat Feb 14 19:34:43 2015 +0100
@@ -37,6 +37,9 @@
 
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+#include <openssl/x509v3.h>
+#include <openssl/asn1.h>
+#include <openssl/safestack.h>
 
 #define LM_SSL_CN_MAX       63
 
@@ -207,6 +210,7 @@
     crt_subj = X509_get_subject_name(srv_crt);
     cn = (gchar *) g_malloc0(LM_SSL_CN_MAX + 1);
 
+    /* FWB: deprecated call, can only get first entry */
     if (X509_NAME_get_text_by_NID(crt_subj, NID_commonName, cn, LM_SSL_CN_MAX) > 0) {
         gchar *domain = cn;
 
@@ -214,11 +218,53 @@
                "%s: server = '%s', cn = '%s'\n",
                __FILE__, server, cn);
 
-        if ((cn[0] == '*') && (cn[1] == '.')) {
-            domain = strstr (cn, server);
-        }
+        if (domain != NULL) {
 
-        if ((domain == NULL) || (strncasecmp (server, domain, LM_SSL_CN_MAX) != 0)) {
+            if ((cn[0] == '*') && (cn[1] == '.')) {
+                /* 
+                 * FWB: huh? ever tested?
+                 * server="sub.domain.tld";
+                 * cn="*.domain.tld";
+                 * domain=strstr(cn, server); ???
+                 */
+                /* domain = strstr (cn, server); */
+                server = strchr(server, '.') + 1;
+                domain = cn + 2;
+            }
+    
+            if (strncasecmp (server, domain, LM_SSL_CN_MAX) != 0) {
+                /* FWB: CN doesn't match, try SANs */
+                int subject_alt_names_nb = -1;
+                int san_result = 0;
+                int san_counter;
+                STACK_OF(GENERAL_NAME) *subject_alt_names = NULL;
+    
+                /* g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: CN does not match server name\n", __FILE__); */
+                // Try to extract the names within the SAN extension from the certificate
+                subject_alt_names = X509_get_ext_d2i((X509 *) srv_crt, NID_subject_alt_name, NULL, NULL);
+                if (subject_alt_names != NULL) {
+    
+                    // Check each name within the extension
+                    subject_alt_names_nb = sk_GENERAL_NAME_num(subject_alt_names);
+                    for (san_counter=0; san_counter<subject_alt_names_nb; san_counter++) {
+                        const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(subject_alt_names, san_counter);
+                        if (current_name->type == GEN_DNS) {
+                            // Current name is a DNS name, let's check it, it's ASCII
+                            if (strcasecmp(server, (char *)current_name->d.dNSName->data) == 0) {
+                                g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: found SAN '%s' - MATCH\n", __FILE__, current_name->d.dNSName->data);
+                                san_result = 1; /* break; */
+                            } else {
+                                g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL, "%s: found SAN '%s'\n", __FILE__, current_name->d.dNSName->data);
+                            }
+                        }
+                    }
+    
+                }
+                sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
+                if (!san_result) goto cn_and_san_mismatch;
+            } /* SAN */
+        } else {
+            cn_and_san_mismatch:
             if (base->func (ssl,
                             LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH,
                             base->func_data) != LM_SSL_RESPONSE_CONTINUE) {
@@ -298,10 +344,13 @@
         initialized = TRUE;
     }
 
-    ssl->ssl_method = TLSv1_client_method();
+    /* don't use TLSv1_client_method() because otherwise we don't get
+     * connections to TLS1_1 and TLS1_2 only servers
+     */
+    ssl->ssl_method = SSLv23_client_method();
     if (ssl->ssl_method == NULL) {
         g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SSL,
-               "TLSv1_client_method() == NULL");
+               "SSLv23_client_method() == NULL");
         abort();
     }
     ssl->ssl_ctx = SSL_CTX_new(ssl->ssl_method);
@@ -317,7 +366,7 @@
      * See http://twistedmatrix.com/trac/ticket/3463 and
      * Loudmouth [#28].
      */
-    SSL_CTX_set_options (ssl->ssl_ctx, SSL_OP_NO_TICKET);
+    SSL_CTX_set_options (ssl->ssl_ctx, (SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3));
 
     /*if (access("/etc/ssl/cert.pem", R_OK) == 0)
       cert_file = "/etc/ssl/cert.pem";