aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-01-18 22:04:33 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-01-18 22:04:33 +0000
commitd6e19bdc91b0c4c6b5a069e11898741ec082b289 (patch)
treed0cb360114e418a612eb2025d270801a1388cd7f /main
parentcc1fcc753900c912d856f3f0498a4f7bfd8344a6 (diff)
Merge changes from team/group/sip-tcptls
This set of changes introduces TCP and TLS support for chan_sip. There are various new options in configs/sip.conf.sample that are used to enable these features. Also, there is a document, doc/siptls.txt that describes some things in more detail. This code was implemented by Brett Bryant and James Golovich. It was reviewed by Joshua Colp and myself. A number of other people participated in the testing of this code, but since it was done outside of the bug tracker, I do not have their names. If you were one of them, thanks a lot for the help! (closes issue #4903, but with completely different code that what exists there.) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@99085 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r--main/Makefile2
-rw-r--r--main/http.c200
-rw-r--r--main/manager.c3
-rw-r--r--main/tcptls.c452
4 files changed, 459 insertions, 198 deletions
diff --git a/main/Makefile b/main/Makefile
index 9389ee3f6..3504b547b 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -19,7 +19,7 @@ include $(ASTTOPDIR)/Makefile.moddir_rules
RESAMPLE_OBJS:=libresample/src/resample.o libresample/src/resamplesubs.o libresample/src/filterkit.o
-OBJS= io.o sched.o logger.o frame.o loader.o config.o channel.o \
+OBJS= tcptls.o io.o sched.o logger.o frame.o loader.o config.o channel.o \
translate.o file.o pbx.o cli.o md5.o term.o \
ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
cdr.o tdd.o acl.o rtp.o udptl.o manager.o asterisk.o \
diff --git a/main/http.c b/main/http.c
index c423e56e0..6e8021fa2 100644
--- a/main/http.c
+++ b/main/http.c
@@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "minimime/mm.h"
#include "asterisk/cli.h"
+#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/utils.h"
#include "asterisk/strings.h"
@@ -59,7 +60,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define DO_SSL /* comment in/out if you want to support ssl */
#endif
-static struct tls_config http_tls_cfg;
+static struct ast_tls_config http_tls_cfg;
static void *httpd_helper_thread(void *arg);
@@ -647,7 +648,7 @@ cleanup:
* We use wrappers rather than SSL_read/SSL_write directly so
* we can put in some debugging.
*/
-static HOOK_T ssl_read(void *cookie, char *buf, LEN_T len)
+/*static HOOK_T ssl_read(void *cookie, char *buf, LEN_T len)
{
int i = SSL_read(cookie, buf, len-1);
#if 0
@@ -675,55 +676,9 @@ static int ssl_close(void *cookie)
SSL_shutdown(cookie);
SSL_free(cookie);
return 0;
-}
+}*/
#endif /* DO_SSL */
-/*!
- * creates a FILE * from the fd passed by the accept thread.
- * This operation is potentially expensive (certificate verification),
- * so we do it in the child thread context.
- */
-static void *make_file_from_fd(void *data)
-{
- struct server_instance *ser = data;
-
- /*
- * open a FILE * as appropriate.
- */
- if (!ser->parent->tls_cfg)
- ser->f = fdopen(ser->fd, "w+");
-#ifdef DO_SSL
- else if ( (ser->ssl = SSL_new(ser->parent->tls_cfg->ssl_ctx)) ) {
- SSL_set_fd(ser->ssl, ser->fd);
- if (SSL_accept(ser->ssl) == 0)
- ast_verbose(" error setting up ssl connection");
- else {
-#if defined(HAVE_FUNOPEN) /* the BSD interface */
- ser->f = funopen(ser->ssl, ssl_read, ssl_write, NULL, ssl_close);
-
-#elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
- static const cookie_io_functions_t cookie_funcs = {
- ssl_read, ssl_write, NULL, ssl_close
- };
- ser->f = fopencookie(ser->ssl, "w+", cookie_funcs);
-#else
- /* could add other methods here */
-#endif
- }
- if (!ser->f) /* no success opening descriptor stacking */
- SSL_free(ser->ssl);
- }
-#endif /* DO_SSL */
-
- if (!ser->f) {
- close(ser->fd);
- ast_log(LOG_WARNING, "FILE * open failed!\n");
- ast_free(ser);
- return NULL;
- }
- return ser->parent->worker_fn(ser);
-}
-
static void *httpd_helper_thread(void *data)
{
char buf[4096];
@@ -876,153 +831,6 @@ done:
return NULL;
}
-void *server_root(void *data)
-{
- struct server_args *desc = data;
- int fd;
- struct sockaddr_in sin;
- socklen_t sinlen;
- struct server_instance *ser;
- pthread_t launched;
-
- for (;;) {
- int i, flags;
-
- if (desc->periodic_fn)
- desc->periodic_fn(desc);
- i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
- if (i <= 0)
- continue;
- sinlen = sizeof(sin);
- fd = accept(desc->accept_fd, (struct sockaddr *)&sin, &sinlen);
- if (fd < 0) {
- if ((errno != EAGAIN) && (errno != EINTR))
- ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
- continue;
- }
- ser = ast_calloc(1, sizeof(*ser));
- if (!ser) {
- ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
- close(fd);
- continue;
- }
- flags = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
- ser->fd = fd;
- ser->parent = desc;
- memcpy(&ser->requestor, &sin, sizeof(ser->requestor));
-
- if (ast_pthread_create_detached_background(&launched, NULL, make_file_from_fd, ser)) {
- ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
- close(ser->fd);
- ast_free(ser);
- }
-
- }
- return NULL;
-}
-
-int ssl_setup(struct 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();
- cfg->ssl_ctx = SSL_CTX_new( SSLv23_server_method() );
- if (!ast_strlen_zero(cfg->certfile)) {
- 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 (!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;
- }
- }
- ast_verbose("ssl cert ok");
- return 1;
-#endif
-}
-
-/*!
- * This is a generic (re)start routine for a TCP server,
- * which does the socket/bind/listen and starts a thread for handling
- * accept().
- */
-void server_start(struct server_args *desc)
-{
- int flags;
- int x = 1;
-
- /* Do nothing if nothing has changed */
- if (!memcmp(&desc->oldsin, &desc->sin, sizeof(desc->oldsin))) {
- ast_debug(1, "Nothing changed in %s\n", desc->name);
- return;
- }
-
- desc->oldsin = desc->sin;
-
- /* 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);
-
- /* If there's no new server, stop here */
- if (desc->sin.sin_family == 0)
- return;
-
- desc->accept_fd = socket(AF_INET, SOCK_STREAM, 0);
- if (desc->accept_fd < 0) {
- ast_log(LOG_WARNING, "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->sin, sizeof(desc->sin))) {
- ast_log(LOG_NOTICE, "Unable to bind %s to %s:%d: %s\n",
- desc->name,
- ast_inet_ntoa(desc->sin.sin_addr), ntohs(desc->sin.sin_port),
- strerror(errno));
- goto error;
- }
- if (listen(desc->accept_fd, 10)) {
- ast_log(LOG_NOTICE, "Unable to listen for %s!\n", desc->name);
- goto error;
- }
- flags = fcntl(desc->accept_fd, F_GETFL);
- fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
- if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
- ast_log(LOG_NOTICE, "Unable to launch %s on %s:%d: %s\n",
- desc->name,
- ast_inet_ntoa(desc->sin.sin_addr), ntohs(desc->sin.sin_port),
- strerror(errno));
- goto error;
- }
- return;
-
-error:
- close(desc->accept_fd);
- desc->accept_fd = -1;
-}
-
/*!
* \brief Add a new URI redirect
* The entries in the redirect list are sorted by length, just like the list
diff --git a/main/manager.c b/main/manager.c
index 8e87af713..c9e69eb5b 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -65,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/md5.h"
#include "asterisk/acl.h"
#include "asterisk/utils.h"
+#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/version.h"
#include "asterisk/threadstorage.h"
@@ -3425,7 +3426,7 @@ static void purge_old_stuff(void *data)
purge_events();
}
-struct tls_config ami_tls_cfg;
+struct ast_tls_config ami_tls_cfg;
static struct server_args ami_desc = {
.accept_fd = -1,
.master = AST_PTHREADT_NULL,
diff --git a/main/tcptls.c b/main/tcptls.c
new file mode 100644
index 000000000..27faa0c18
--- /dev/null
+++ b/main/tcptls.c
@@ -0,0 +1,452 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2007 - 2008, Digium, Inc.
+ *
+ * Luigi Rizzo (TCP and TLS server code)
+ * Brett Bryant <brettbryant@gmail.com> (updated for client support)
+ *
+ * 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.
+ */
+
+/*!
+ * \file
+ * \brief Code to support TCP and TLS server/client
+ *
+ * \author Luigi Rizzo
+ * \author Brett Bryant <brettbryant@gmail.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include <sys/signal.h>
+
+#include "asterisk/compat.h"
+#include "asterisk/tcptls.h"
+#include "asterisk/http.h"
+#include "asterisk/utils.h"
+#include "asterisk/strings.h"
+#include "asterisk/options.h"
+#include "asterisk/manager.h"
+
+/*!
+ * replacement read/write functions for SSL support.
+ * We use wrappers rather than SSL_read/SSL_write directly so
+ * we can put in some debugging.
+ */
+
+#ifdef DO_SSL
+static HOOK_T ssl_read(void *cookie, char *buf, LEN_T len)
+{
+ int i = SSL_read(cookie, buf, len-1);
+#if 0
+ if (i >= 0)
+ buf[i] = '\0';
+ ast_verbose("ssl read size %d returns %d <%s>\n", (int)len, i, buf);
+#endif
+ return i;
+}
+
+static HOOK_T ssl_write(void *cookie, const char *buf, LEN_T len)
+{
+#if 0
+ char *s = alloca(len+1);
+ strncpy(s, buf, len);
+ s[len] = '\0';
+ ast_verbose("ssl write size %d <%s>\n", (int)len, s);
+#endif
+ return SSL_write(cookie, buf, len);
+}
+
+static int ssl_close(void *cookie)
+{
+ close(SSL_get_fd(cookie));
+ SSL_shutdown(cookie);
+ SSL_free(cookie);
+ return 0;
+}
+#endif /* DO_SSL */
+
+HOOK_T server_read(struct server_instance *ser, void *buf, size_t count)
+{
+ if (!ser->ssl)
+ return read(ser->fd, buf, count);
+#ifdef DO_SSL
+ else
+ return ssl_read(ser->ssl, buf, count);
+#endif
+}
+
+HOOK_T server_write(struct server_instance *ser, void *buf, size_t count)
+{
+ if (!ser->ssl)
+ return write(ser->fd, buf, count);
+#ifdef DO_SSL
+ else
+ return ssl_write(ser->ssl, buf, count);
+#endif
+}
+
+void *server_root(void *data)
+{
+ struct server_args *desc = data;
+ int fd;
+ struct sockaddr_in sin;
+ socklen_t sinlen;
+ struct server_instance *ser;
+ pthread_t launched;
+
+ for (;;) {
+ int i, flags;
+
+ if (desc->periodic_fn)
+ desc->periodic_fn(desc);
+ i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
+ if (i <= 0)
+ continue;
+ sinlen = sizeof(sin);
+ fd = accept(desc->accept_fd, (struct sockaddr *)&sin, &sinlen);
+ if (fd < 0) {
+ if ((errno != EAGAIN) && (errno != EINTR))
+ ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
+ continue;
+ }
+ ser = ast_calloc(1, sizeof(*ser));
+ if (!ser) {
+ ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
+ close(fd);
+ continue;
+ }
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+ ser->fd = fd;
+ ser->parent = desc;
+ memcpy(&ser->requestor, &sin, sizeof(ser->requestor));
+
+ ser->client = 0;
+
+ if (ast_pthread_create_detached_background(&launched, NULL, ast_make_file_from_fd, ser)) {
+ ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
+ close(ser->fd);
+ ast_free(ser);
+ }
+ }
+ return NULL;
+}
+
+static int __ssl_setup(struct ast_tls_config *cfg, int client)
+{
+#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( client ? SSLv23_client_method() : SSLv23_server_method() ))) {
+ ast_log(LOG_DEBUG, "Sorry, SSL_CTX_new call returned null...\n");
+ cfg->enabled = 0;
+ return 0;
+ }
+ if (!ast_strlen_zero(cfg->certfile)) {
+ 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 ) {
+ 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 ) {
+ 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 ssl_setup(struct ast_tls_config *cfg)
+{
+ return __ssl_setup(cfg, 0);
+}
+
+/*! A generic client routine for a TCP client
+ * and starts a thread for handling accept()
+ */
+struct server_instance *client_start(struct server_args *desc)
+{
+ int flags;
+ struct server_instance *ser = NULL;
+
+ /* Do nothing if nothing has changed */
+ if(!memcmp(&desc->oldsin, &desc->sin, sizeof(desc->oldsin))) {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Nothing changed in %s\n", desc->name);
+ return NULL;
+ }
+
+ desc->oldsin = desc->sin;
+
+ if (desc->accept_fd != -1)
+ close(desc->accept_fd);
+
+ desc->accept_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (desc->accept_fd < 0) {
+ ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n",
+ desc->name, strerror(errno));
+ return NULL;
+ }
+
+ if (connect(desc->accept_fd, (const struct sockaddr *)&desc->sin, sizeof(desc->sin))) {
+ ast_log(LOG_NOTICE, "Unable to connect %s to %s:%d: %s\n",
+ desc->name,
+ ast_inet_ntoa(desc->sin.sin_addr), ntohs(desc->sin.sin_port),
+ strerror(errno));
+ goto error;
+ }
+
+ if (!(ser = ast_calloc(1, sizeof(*ser))))
+ goto error;
+
+ flags = fcntl(desc->accept_fd, F_GETFL);
+ fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK);
+
+ ser->fd = desc->accept_fd;
+ ser->parent = desc;
+ ser->parent->worker_fn = NULL;
+ memcpy(&ser->requestor, &desc->sin, sizeof(ser->requestor));
+
+ ser->client = 1;
+
+ if (desc->tls_cfg) {
+ desc->tls_cfg->enabled = 1;
+ __ssl_setup(desc->tls_cfg, 1);
+ }
+
+ if (!ast_make_file_from_fd(ser))
+ goto error;
+
+ return ser;
+
+error:
+ close(desc->accept_fd);
+ desc->accept_fd = -1;
+ if (ser)
+ ast_free(ser);
+ return NULL;
+}
+
+/*!
+ * This is a generic (re)start routine for a TCP server,
+ * which does the socket/bind/listen and starts a thread for handling
+ * accept().
+ */
+
+void server_start(struct server_args *desc)
+{
+ int flags;
+ int x = 1;
+
+ /* Do nothing if nothing has changed */
+ if (!memcmp(&desc->oldsin, &desc->sin, sizeof(desc->oldsin))) {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Nothing changed in %s\n", desc->name);
+ return;
+ }
+
+ desc->oldsin = desc->sin;
+
+ /* 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);
+
+ /* If there's no new server, stop here */
+ if (desc->sin.sin_family == 0)
+ return;
+
+ desc->accept_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (desc->accept_fd < 0) {
+ ast_log(LOG_WARNING, "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->sin, sizeof(desc->sin))) {
+ ast_log(LOG_NOTICE, "Unable to bind %s to %s:%d: %s\n",
+ desc->name,
+ ast_inet_ntoa(desc->sin.sin_addr), ntohs(desc->sin.sin_port),
+ strerror(errno));
+ goto error;
+ }
+ if (listen(desc->accept_fd, 10)) {
+ ast_log(LOG_NOTICE, "Unable to listen for %s!\n", desc->name);
+ goto error;
+ }
+ flags = fcntl(desc->accept_fd, F_GETFL);
+ fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
+ if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
+ ast_log(LOG_NOTICE, "Unable to launch %s on %s:%d: %s\n",
+ desc->name,
+ ast_inet_ntoa(desc->sin.sin_addr), ntohs(desc->sin.sin_port),
+ strerror(errno));
+ goto error;
+ }
+ return;
+
+error:
+ close(desc->accept_fd);
+ desc->accept_fd = -1;
+}
+
+void server_stop(struct server_args *desc)
+{
+ /* 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);
+ desc->accept_fd = -1;
+}
+
+/*!
+* creates a FILE * from the fd passed by the accept thread.
+* This operation is potentially expensive (certificate verification),
+* so we do it in the child thread context.
+*/
+void *ast_make_file_from_fd(void *data)
+{
+ struct server_instance *ser = data;
+ int (*ssl_setup)(SSL *) = (ser->client) ? SSL_connect : SSL_accept;
+ int ret;
+ char err[256];
+
+ /*
+ * open a FILE * as appropriate.
+ */
+ if (!ser->parent->tls_cfg)
+ ser->f = fdopen(ser->fd, "w+");
+#ifdef DO_SSL
+ else if ( (ser->ssl = SSL_new(ser->parent->tls_cfg->ssl_ctx)) ) {
+ SSL_set_fd(ser->ssl, ser->fd);
+ if ((ret = ssl_setup(ser->ssl)) <= 0) {
+ if(option_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
+ } else {
+#if defined(HAVE_FUNOPEN) /* the BSD interface */
+ ser->f = funopen(ser->ssl, ssl_read, ssl_write, NULL, ssl_close);
+
+#elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
+ static const cookie_io_functions_t cookie_funcs = {
+ ssl_read, ssl_write, NULL, ssl_close
+ };
+ ser->f = fopencookie(ser->ssl, "w+", cookie_funcs);
+#else
+ /* 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, (char *) 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);
+ }
+#endif /* DO_SSL */
+
+ if (!ser->f) {
+ close(ser->fd);
+ ast_log(LOG_WARNING, "FILE * open failed!\n");
+ ast_free(ser);
+ return NULL;
+ }
+
+ if (ser && ser->parent->worker_fn)
+ return ser->parent->worker_fn(ser);
+ else
+ return ser;
+}