summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Vossel <dvossel@digium.com>2009-04-29 21:13:43 +0000
committerDavid Vossel <dvossel@digium.com>2009-04-29 21:13:43 +0000
commita6adc84e6952883381805a75d1ebcae3c192dfd6 (patch)
treed6c952359c1ff180fb4c871647ce784eaf1684e4
parentd35fd35ae3dfa0e6c5567711a30ec617dbc012fc (diff)
SIP option to specify outbound TLS/SSL client protocol.
chan_sip allows for outbound TLS connections, but does not allow the user to specify what protocol to use (default was SSLv2, and still is if this new option is not specified). This patch lets the user pick the SSL/TLS client method for outbound connections in sip. (closes issue #14770) Reported by: TheOldSaint (closes issue #14768) Reported by: TheOldSaint Review: http://reviewboard.digium.com/r/240/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@191177 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--CHANGES2
-rw-r--r--configs/sip.conf.sample6
-rw-r--r--include/asterisk/tcptls.h8
-rw-r--r--main/tcptls.c53
4 files changed, 57 insertions, 12 deletions
diff --git a/CHANGES b/CHANGES
index 8bfdb3cc9..3c33582df 100644
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,8 @@ SIP Changes
* Added tlsprivatekey option to sip.conf. This allows a separate .pem file
to be used for holding a private key. If tlsprivatekey is not specified,
tlscertfile is searched for both public and private key.
+ * Added tlsclientmethod option to sip.conf. This allows the protocol for
+ outbound client connections to be specified.
Applications
------------
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index b5e984f6a..37e3c47d4 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -142,8 +142,12 @@ tcpbindaddr=0.0.0.0 ; IP address for TCP server to bind to (0.0.0.0
;tlscipher=<SSL cipher string>
; A string specifying which SSL ciphers to use or not use
-; A list of valid SSL cipher strings can be found at:
+; A list of valid SSL cipher strings can be found at:
; http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
+;
+;tlsclientmethod=tlsv1 ; values include tlsv1, sslv3, sslv2.
+ ; Specify protocol for outbound client connections.
+ ; If left unspecified, the default is sslv2.
srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; Note: Asterisk only uses the first host
diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h
index 9496d9772..b6cc9a31b 100644
--- a/include/asterisk/tcptls.h
+++ b/include/asterisk/tcptls.h
@@ -72,7 +72,13 @@ enum ast_ssl_flags {
/*! 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)
+ AST_SSL_IGNORE_COMMON_NAME = (1 << 2),
+ /*! Use SSLv2 for outgoing client connections */
+ AST_SSL_SSLV2_CLIENT = (1 << 3),
+ /*! Use SSLv3 for outgoing client connections */
+ AST_SSL_SSLV3_CLIENT = (1 << 4),
+ /*! Use TLSv1 for outgoing client connections */
+ AST_SSL_TLSV1_CLIENT = (1 << 5)
};
struct ast_tls_config {
diff --git a/main/tcptls.c b/main/tcptls.c
index 4609438f5..e51d7a208 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -173,7 +173,7 @@ static void *handle_tls_connection(void *data)
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 */
@@ -229,7 +229,7 @@ void *ast_tcptls_server_root(void *data)
socklen_t sinlen;
struct ast_tcptls_session_instance *tcptls_session;
pthread_t launched;
-
+
for (;;) {
int i, flags;
@@ -261,7 +261,7 @@ void *ast_tcptls_server_root(void *data)
memcpy(&tcptls_session->remote_address, &sin, sizeof(tcptls_session->remote_address));
tcptls_session->client = 0;
-
+
if (ast_pthread_create_detached_background(&launched, NULL, handle_tls_connection, tcptls_session)) {
ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
close(tcptls_session->fd);
@@ -283,7 +283,26 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
- if (!(cfg->ssl_ctx = SSL_CTX_new( client ? SSLv23_client_method() : SSLv23_server_method() ))) {
+ if (client) {
+ if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) {
+ cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
+ } else if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) {
+ cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
+ } else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
+ cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
+ } else {
+ /* SSLv23_client_method() sends SSLv2, this was the original
+ * default for ssl clients before the option was given to
+ * pick what protocol a client should use. In order not
+ * to break expected behavior it remains the default. */
+ cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+ }
+ } else {
+ /* SSLv23_server_method() supports TLSv1, SSLv2, and SSLv3 inbound connections. */
+ cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+ }
+
+ if (!cfg->ssl_ctx) {
ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
cfg->enabled = 0;
return 0;
@@ -417,22 +436,22 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
{
int flags;
int x = 1;
-
+
/* Do nothing if nothing has changed */
if (!memcmp(&desc->old_address, &desc->local_address, sizeof(desc->old_address))) {
ast_debug(1, "Nothing changed in %s\n", desc->name);
return;
}
-
+
desc->old_address = desc->local_address;
-
+
/* Shutdown a running server if there is one */
if (desc->master != AST_PTHREADT_NULL) {
pthread_cancel(desc->master);
pthread_kill(desc->master, SIGURG);
pthread_join(desc->master, NULL);
}
-
+
if (desc->accept_fd != -1)
close(desc->accept_fd);
@@ -447,7 +466,7 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
return;
}
-
+
setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) {
ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n",
@@ -494,7 +513,7 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_
if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
tls_cfg->enabled = ast_true(value) ? 1 : 0;
tls_desc->local_address.sin_family = AF_INET;
- } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert")) {
+ } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
ast_free(tls_cfg->certfile);
tls_cfg->certfile = ast_strdup(value);
} else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
@@ -518,6 +537,20 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_
ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value);
} else if (!strcasecmp(varname, "tlsbindport") || !strcasecmp(varname, "sslbindport")) {
tls_desc->local_address.sin_port = htons(atoi(value));
+ } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
+ if (!strcasecmp(value, "tlsv1")) {
+ ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
+ ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
+ ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
+ } else if (!strcasecmp(value, "sslv3")) {
+ ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
+ ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
+ ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
+ } else if (!strcasecmp(value, "sslv2")) {
+ ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
+ ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
+ ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
+ }
} else {
return -1;
}