[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