[asterisk-commits] jamesgolovich: branch group/sip-tcptls r91346 - in /team/group/sip-tcptls: ch...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Dec 6 02:00:40 CST 2007


Author: jamesgolovich
Date: Thu Dec  6 02:00:39 2007
New Revision: 91346

URL: http://svn.digium.com/view/asterisk?view=rev&rev=91346
Log:
Allow CA to be configured by file or path
Reuse code in server.c for client and server connections
Verify certificates and compare 'common name' against the hostname
Change chan_sip so we configure a default_tls_cfg and copy that to the server and every client


Modified:
    team/group/sip-tcptls/channels/chan_sip.c
    team/group/sip-tcptls/include/asterisk/server.h
    team/group/sip-tcptls/main/server.c

Modified: team/group/sip-tcptls/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/group/sip-tcptls/channels/chan_sip.c?view=diff&rev=91346&r1=91345&r2=91346
==============================================================================
--- team/group/sip-tcptls/channels/chan_sip.c (original)
+++ team/group/sip-tcptls/channels/chan_sip.c Thu Dec  6 02:00:39 2007
@@ -1913,6 +1913,7 @@
 static void *sip_tcp_worker_fn(void *);
 
 static struct ast_tls_config sip_tls_cfg;
+static struct ast_tls_config default_tls_cfg;
 
 static struct server_args sip_tcp_desc = {
 	.accept_fd = -1,
@@ -17162,10 +17163,18 @@
 		return s->fd;
 	}
 
-	ca.tls_cfg = (s->ser) ? s->ser->parent->tls_cfg : NULL;
-	if (!ca.tls_cfg && s->type & SIP_TRANSPORT_TLS && 
-		!(ca.tls_cfg = ast_calloc(1, sizeof(*ca.tls_cfg))))
-		return -1;
+	if (s->ser && s->ser->parent->tls_cfg) 
+		ca.tls_cfg = s->ser->parent->tls_cfg;
+	else {
+		if (s->type & SIP_TRANSPORT_TLS) {
+			ca.tls_cfg = ast_calloc(1, sizeof(*ca.tls_cfg));
+			if (!ca.tls_cfg)
+				return -1;
+			memcpy(ca.tls_cfg, &default_tls_cfg, sizeof(*ca.tls_cfg));
+			if (!ast_strlen_zero(p->tohost))
+				ast_copy_string(ca.hostname, p->tohost, sizeof(ca.hostname));
+		}
+	}
 	s->ser = (!s->ser) ? client_start(&ca) : s->ser;
 
 	if (!s->ser) {
@@ -18624,8 +18633,10 @@
 		ASTOBJ_CONTAINER_MARKALL(&peerl);
 	}
 
-	sip_tls_desc.tls_cfg->certfile 	= ast_strdup(AST_CERTFILE); /*XXX Not sure if this is useful */
-	sip_tls_desc.tls_cfg->cipher 	= ast_strdup("");
+	default_tls_cfg.certfile = ast_strdup(AST_CERTFILE); /*XXX Not sure if this is useful */
+	default_tls_cfg.cipher = ast_strdup("");
+	default_tls_cfg.cafile = ast_strdup("");
+	default_tls_cfg.capath = ast_strdup("");
 	
 	/* Initialize copy of current global_regcontext for later use in removing stale contexts */
 	ast_copy_string(oldcontexts, global_regcontext, sizeof(oldcontexts));
@@ -18782,14 +18793,24 @@
 			if (ast_parse_arg(v->value, PARSE_INADDR, &sip_tcp_desc.sin))
 				ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n", v->name, v->value, v->lineno, config);
 		} else if (!strcasecmp(v->name, "tlsenable")) {
-			sip_tls_desc.tls_cfg->enabled = ast_true(v->value) ? TRUE : FALSE;
+			default_tls_cfg.enabled = ast_true(v->value) ? TRUE : FALSE;
 			sip_tls_desc.sin.sin_family = AF_INET;
 		} else if (!strcasecmp(v->name, "tlscertfile")) {
-			ast_free(sip_tls_desc.tls_cfg->certfile);
-			sip_tls_desc.tls_cfg->certfile = ast_strdup(v->value);
+			ast_free(default_tls_cfg.certfile);
+			default_tls_cfg.certfile = ast_strdup(v->value);
 		} else if (!strcasecmp(v->name, "tlscipher")) {
-			ast_free(sip_tls_desc.tls_cfg->cipher);
-			sip_tls_desc.tls_cfg->cipher = ast_strdup(v->value);
+			ast_free(default_tls_cfg.cipher);
+			default_tls_cfg.cipher = ast_strdup(v->value);
+		} else if (!strcasecmp(v->name, "tlscafile")) {
+			ast_free(default_tls_cfg.cafile);
+			default_tls_cfg.cafile = ast_strdup(v->value);
+		} else if (!strcasecmp(v->name, "tlscapath")) {
+			ast_free(default_tls_cfg.capath);
+			default_tls_cfg.capath = ast_strdup(v->value);
+		} else if (!strcasecmp(v->name, "tlsverifyclient")) {
+			ast_set2_flag(&default_tls_cfg.flags, ast_true(v->value), AST_SSL_VERIFY_CLIENT);	
+		} else if (!strcasecmp(v->name, "tlsdontverifyserver")) {
+			ast_set2_flag(&default_tls_cfg.flags, ast_true(v->value), AST_SSL_DONT_VERIFY_SERVER);	
 		} else if (!strcasecmp(v->name, "tlsbindaddr")) {
 			if (ast_parse_arg(v->value, PARSE_INADDR, &sip_tls_desc.sin))
 				ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n", v->name, v->value, v->lineno, config);
@@ -19206,6 +19227,7 @@
 		ast_config_destroy(notify_types);
 	notify_types = ast_config_load(notify_config, config_flags);
 
+	memcpy(sip_tls_desc.tls_cfg, &default_tls_cfg, sizeof(default_tls_cfg));
 	server_start(&sip_tcp_desc);
 
 	if (ssl_setup(sip_tls_desc.tls_cfg))

Modified: team/group/sip-tcptls/include/asterisk/server.h
URL: http://svn.digium.com/view/asterisk/team/group/sip-tcptls/include/asterisk/server.h?view=diff&rev=91346&r1=91345&r2=91346
==============================================================================
--- team/group/sip-tcptls/include/asterisk/server.h (original)
+++ team/group/sip-tcptls/include/asterisk/server.h Thu Dec  6 02:00:39 2007
@@ -46,6 +46,8 @@
 #ifndef _ASTERISK_SERVER_H
 #define _ASTERISK_SERVER_H
 
+#include "asterisk/utils.h"
+
 #if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
 #define DO_SSL  /* comment in/out if you want to support ssl */
 #endif
@@ -57,15 +59,27 @@
 /* declare dummy types so we can define a pointer to them */
 typedef struct {} SSL;
 typedef struct {} SSL_CTX;
-#endif /*DO_SSL */
+#endif /* DO_SSL */
 
 /*! SSL support */
 #define AST_CERTFILE "asterisk.pem"
+
+enum ast_ssl_flags {
+	/*! Verify certificate when acting as server */
+	AST_SSL_VERIFY_CLIENT = (1 << 0),
+	/*! Don't verify certificate when connecting to a server */
+	AST_SSL_DONT_VERIFY_SERVER = (1 << 1),
+	/*! Don't compare "Common Name" against IP or hostname */
+	AST_SSL_IGNORE_COMMON_NAME = (1 << 2)
+};
 
 struct ast_tls_config {
 	int enabled;
 	char *certfile;
 	char *cipher;
+	char *cafile;
+	char *capath;
+	struct ast_flags flags;
 	SSL_CTX *ssl_ctx;
 };
 
@@ -118,6 +132,7 @@
 struct server_args {
 	struct sockaddr_in sin;
 	struct sockaddr_in oldsin;
+	char hostname[MAXHOSTNAMELEN]; /* only necessary for SSL clients so we can compare to common name */
 	struct ast_tls_config *tls_cfg; /* points to the SSL configuration if any */
 	int accept_fd;
 	int poll_timeout;

Modified: team/group/sip-tcptls/main/server.c
URL: http://svn.digium.com/view/asterisk/team/group/sip-tcptls/main/server.c?view=diff&rev=91346&r1=91345&r2=91346
==============================================================================
--- team/group/sip-tcptls/main/server.c (original)
+++ team/group/sip-tcptls/main/server.c Thu Dec  6 02:00:39 2007
@@ -1,3 +1,21 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2007, Digium, Inc.
+ *
+ * Not sure who wrote this code originally, will update when I find out
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -141,9 +159,7 @@
 	return NULL;
 }
 
-int client_setup(struct ast_tls_config *);
-
-int ssl_setup(struct ast_tls_config *cfg)
+static int __ssl_setup(struct ast_tls_config *cfg, int client)
 {
 #ifndef DO_SSL
 	cfg->enabled = 0;
@@ -155,7 +171,7 @@
 	SSL_load_error_strings();
 	SSLeay_add_ssl_algorithms();
 
-	if (!(cfg->ssl_ctx = SSL_CTX_new( SSLv23_server_method() ))) {
+	if (!(cfg->ssl_ctx = SSL_CTX_new( client ? SSLv23_client_method() : SSLv23_server_method() ))) {
 		ast_log(LOG_DEBUG, "Sorry, SSL_CTX_new call returned null...\n");
 		cfg->enabled = 0;
 		return 0;
@@ -164,45 +180,38 @@
 		if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0 ||
 		    SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0 ||
 		    SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 ) {
-			ast_verbose("ssl cert error <%s>", cfg->certfile);
-			sleep(2);
-			cfg->enabled = 0;
-			return 0;
+			if (!client) {
+				/* Clients don't need a certificate, but if its setup we can use it */
+				ast_verbose("ssl cert error <%s>", cfg->certfile);
+				sleep(2);
+				cfg->enabled = 0;
+				return 0;
+			}
 		}
 	}
 	if (!ast_strlen_zero(cfg->cipher)) {
 		if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
-			ast_verbose("ssl cipher error <%s>", cfg->cipher);
-			sleep(2);
-			cfg->enabled = 0;
-			return 0;
-		}
-	}
+			if (!client) {
+				ast_verbose("ssl cipher error <%s>", cfg->cipher);
+				sleep(2);
+				cfg->enabled = 0;
+				return 0;
+			}
+		}
+	}
+	if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
+		if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0)
+			ast_verbose("ssl CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
+	}
+
 	ast_verbose("ssl cert ok\n");
 	return 1;
 #endif
 }
 
-int client_setup(struct ast_tls_config *cfg)
-{
-#ifndef DO_SSL
-	cfg->enabled = 0;
-	return 0;
-#else
-	if (!cfg->enabled)
-		return 0;
-
-	SSL_load_error_strings();
-	SSLeay_add_ssl_algorithms();
-
-	if (!(cfg->ssl_ctx = SSL_CTX_new( SSLv23_client_method() ))) {
-		ast_log(LOG_DEBUG, "SSL_CTX_new returned null\n");
-		cfg->enabled = 0;
-		return 0;
-	}
-
-	return 1;
-#endif
+int ssl_setup(struct ast_tls_config *cfg)
+{
+	return __ssl_setup(cfg, 0);
 }
 
 /*! A generic client routine for a TCP client
@@ -255,7 +264,7 @@
 
 	if (desc->tls_cfg) {
 		desc->tls_cfg->enabled = 1;
-		client_setup(desc->tls_cfg);
+		__ssl_setup(desc->tls_cfg, 1);
 	}
 
 	if (!ast_make_file_from_fd(ser))
@@ -266,6 +275,8 @@
 error:
 	close(desc->accept_fd);
 	desc->accept_fd = -1;
+	if (ser)
+		ast_free(ser);
 	return NULL;
 }
 
@@ -374,6 +385,51 @@
 			/* could add other methods here */
 			ast_log(LOG_WARNING, "no ser->f methods attempted!");
 #endif
+			if ((ser->client && !ast_test_flag(&ser->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
+				|| (!ser->client && ast_test_flag(&ser->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) {
+				X509 *peer;
+				long res;
+				peer = SSL_get_peer_certificate(ser->ssl);
+				if (!peer)
+					ast_log(LOG_WARNING, "No peer certificate\n");
+				res = SSL_get_verify_result(ser->ssl);
+				if (res != X509_V_OK)
+					ast_log(LOG_WARNING, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res));
+				if (!ast_test_flag(&ser->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) {
+					ASN1_STRING *str;
+					unsigned char *str2;
+					X509_NAME *name = X509_get_subject_name(peer);
+					int pos = -1;
+					int found = 0;
+				
+					for (;;) {
+						/* Walk the certificate to check all available "Common Name" */
+						/* XXX Probably should do a gethostbyname on the hostname and compare that as well */
+						pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos);
+						if (pos < 0)
+							break;
+						str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
+						ASN1_STRING_to_UTF8(&str2, str);
+						if (str2) {
+							if (!strcasecmp(ser->parent->hostname, str2))
+								found = 1;
+							ast_log(LOG_DEBUG, "SSL Common Name compare s1='%s' s2='%s'\n", ser->parent->hostname, str2);
+							OPENSSL_free(str2);
+						}
+						if (found)
+							break;
+					}
+					if (!found) {
+						ast_log(LOG_WARNING, "Certificate common name did not match (%s)\n", ser->parent->hostname);
+						if (peer)
+							X509_free(peer);
+						fclose(ser->f);
+						return NULL;
+					}
+				}
+				if (peer)
+					X509_free(peer);
+			}
 		}
 		if (!ser->f)	/* no success opening descriptor stacking */
 			SSL_free(ser->ssl);




More information about the asterisk-commits mailing list