summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}