diff options
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | configs/sip.conf.sample | 6 | ||||
-rw-r--r-- | include/asterisk/tcptls.h | 8 | ||||
-rw-r--r-- | main/tcptls.c | 53 |
4 files changed, 57 insertions, 12 deletions
@@ -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; } |