From 07e0de32295ae20076bda153ee11915bfbc51243 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Mon, 15 Jul 2013 18:52:09 -0400 Subject: [PATCH] mod_rayo: support secure client-to-server connections --- conf/rayo/autoload_configs/rayo.conf.xml | 4 +- .../conf/autoload_configs/rayo.conf.xml | 4 +- src/mod/event_handlers/mod_rayo/iks_helpers.h | 3 +- src/mod/event_handlers/mod_rayo/mod_rayo.c | 26 ++-- .../event_handlers/mod_rayo/xmpp_streams.c | 129 +++++++++++------- .../event_handlers/mod_rayo/xmpp_streams.h | 2 + 6 files changed, 103 insertions(+), 65 deletions(-) diff --git a/conf/rayo/autoload_configs/rayo.conf.xml b/conf/rayo/autoload_configs/rayo.conf.xml index f9ac49b99d..0cb46d7992 100644 --- a/conf/rayo/autoload_configs/rayo.conf.xml +++ b/conf/rayo/autoload_configs/rayo.conf.xml @@ -11,8 +11,10 @@ - + + + diff --git a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml index f9ac49b99d..0cb46d7992 100644 --- a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml +++ b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml @@ -11,8 +11,10 @@ - + + + diff --git a/src/mod/event_handlers/mod_rayo/iks_helpers.h b/src/mod/event_handlers/mod_rayo/iks_helpers.h index 4e21113452..442722a267 100644 --- a/src/mod/event_handlers/mod_rayo/iks_helpers.h +++ b/src/mod/event_handlers/mod_rayo/iks_helpers.h @@ -39,8 +39,7 @@ #define IKS_NS_XMPP_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas" #define IKS_NS_XMPP_STREAMS "http://etherx.jabber.org/streams" #define IKS_NS_XMPP_DIALBACK "jabber:server:dialback" -#define IKS_NS_BIDI_FEATURE "urn:xmpp:features:bidi" -#define IKS_NS_BIDI "urn:xmpp:bidi" +#define IKS_NS_XMPP_TLS "urn:ietf:params:xml:ns:xmpp-tls" struct xmpp_error { const char *name; diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index 24b187d739..a110cdb703 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -3079,6 +3079,8 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_ switch_xml_t l; const char *shared_secret = switch_xml_attr_soft(domain, "shared-secret"); const char *name = switch_xml_attr_soft(domain, "name"); + const char *cert = switch_xml_attr_soft(domain, "cert"); + const char *key = switch_xml_attr_soft(domain, "key"); if (zstr(name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing #include +#include + #include "xmpp_streams.h" #include "iks_helpers.h" #include "sasl.h" @@ -63,6 +65,10 @@ struct xmpp_stream_context { int shutdown; /** prevents context shutdown until all threads are finished */ switch_thread_rwlock_t *shutdown_rwlock; + /** path to cert PEM file */ + const char *cert_pem_file; + /** path to key PEM file */ + const char *key_pem_file; }; /** @@ -71,8 +77,8 @@ struct xmpp_stream_context { enum xmpp_stream_state { /** new connection */ XSS_CONNECT, - /** bidirectional comms established */ - XSS_BIDI, + /** encrypted comms established */ + XSS_SECURE, /** remote party authenticated */ XSS_AUTHENTICATED, /** client resource bound */ @@ -159,7 +165,7 @@ static const char *xmpp_stream_state_to_string(enum xmpp_stream_state state) { switch(state) { case XSS_CONNECT: return "CONNECT"; - case XSS_BIDI: return "BIDI"; + case XSS_SECURE: return "SECURE"; case XSS_AUTHENTICATED: return "AUTHENTICATED"; case XSS_RESOURCE_BOUND: return "RESOURCE_BOUND"; case XSS_READY: return "READY"; @@ -358,6 +364,31 @@ static void xmpp_send_client_header_auth(struct xmpp_stream *stream) free(header); } +/** + * Send sasl + starttls reply to xmpp + * @param stream the xmpp stream + */ +static void xmpp_send_client_header_tls(struct xmpp_stream *stream) +{ + if (stream->context->key_pem_file && stream->context->cert_pem_file) { + struct xmpp_stream_context *context = stream->context; + char *header = switch_mprintf( + "" + "" + "" + "PLAIN" + "", context->domain, stream->id); + iks_send_raw(stream->parser, header); + free(header); + } else { + /* not set up for TLS, skip it */ + stream->state = XSS_SECURE; + xmpp_send_client_header_auth(stream); + } +} + /** * Send sasl reply to xmpp * @param stream the xmpp stream @@ -370,12 +401,6 @@ static void xmpp_send_server_header_auth(struct xmpp_stream *stream) " from='%s' id='%s' xml:lang='en' version='1.0'" " xmlns:stream='"IKS_NS_XMPP_STREAMS"'>" "" -#if 0 - "" - "" - "PLAIN" - "" -#endif "", context->domain, stream->id); iks_send_raw(stream->parser, header); @@ -417,6 +442,21 @@ static void xmpp_send_outbound_server_header(struct xmpp_stream *stream) free(header); } +/** + * Handle message. + * @param the xmpp stream + * @param node the packet + */ +static void on_stream_starttls(struct xmpp_stream *stream, iks *node) +{ + /* wait for handshake to start */ + if (iks_proceed_tls(stream->parser, stream->context->cert_pem_file, stream->context->key_pem_file, 1) == IKS_OK) { + stream->state = XSS_SECURE; + } else { + stream->state = XSS_ERROR; + } +} + /** * Handle message. Only PLAIN supported. * @param stream the xmpp stream @@ -431,7 +471,7 @@ static void on_stream_auth(struct xmpp_stream *stream, iks *node) switch_log_printf(SWITCH_CHANNEL_UUID_LOG(stream->id), SWITCH_LOG_DEBUG, "%s, auth, state = %s\n", stream->jid, xmpp_stream_state_to_string(stream->state)); /* wrong state for authentication */ - if (stream->state != XSS_BIDI) { + if (stream->state != XSS_SECURE) { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(stream->id), SWITCH_LOG_WARNING, "%s, auth UNEXPECTED, state = %s\n", stream->jid, xmpp_stream_state_to_string(stream->state)); /* on_auth unexpected error */ stream->state = XSS_ERROR; @@ -486,38 +526,6 @@ static void on_stream_auth(struct xmpp_stream *stream, iks *node) } } -/** - * Handle message. - * @param stream the xmpp stream - * @param node the packet - */ -static void on_stream_bidi(struct xmpp_stream *stream, iks *node) -{ - /* only allow bidi on s2s connections before auth */ - if (stream->s2s) { - switch(stream->state) { - case XSS_CONNECT: - stream->state = XSS_BIDI; - break; - case XSS_BIDI: - case XSS_AUTHENTICATED: - case XSS_RESOURCE_BOUND: - case XSS_READY: - case XSS_SHUTDOWN: - case XSS_ERROR: - case XSS_DESTROY: - /* error */ - stream->state = XSS_ERROR; - switch_log_printf(SWITCH_CHANNEL_UUID_LOG(stream->id), SWITCH_LOG_INFO, "%s, bad state: %s\n", stream->jid, xmpp_stream_state_to_string(stream->state)); - break; - } - } else { - /* error */ - stream->state = XSS_ERROR; - switch_log_printf(SWITCH_CHANNEL_UUID_LOG(stream->id), SWITCH_LOG_INFO, "%s, bidi not allowed from client\n", stream->jid); - } -} - /** * Handle request * @param stream the xmpp stream @@ -606,7 +614,7 @@ static void on_stream_iq(struct xmpp_stream *stream, iks *iq) struct xmpp_stream_context *context = stream->context; switch(stream->state) { case XSS_CONNECT: - case XSS_BIDI: { + case XSS_SECURE: { iks *error = iks_new_error(iq, STANZA_ERROR_NOT_AUTHORIZED); xmpp_stream_stanza_send(stream, error); break; @@ -689,7 +697,9 @@ static void on_client_stream_start(struct xmpp_stream *stream, iks *node) switch (stream->state) { case XSS_CONNECT: - case XSS_BIDI: + xmpp_send_client_header_tls(stream); + break; + case XSS_SECURE: xmpp_send_client_header_auth(stream); break; case XSS_AUTHENTICATED: @@ -960,7 +970,7 @@ static void on_outbound_server_stream_start(struct xmpp_stream *stream, iks *nod /* strange... I expect IKS_NODE_STOP, this is a workaround. */ stream->state = XSS_DESTROY; break; - case XSS_BIDI: + case XSS_SECURE: case XSS_AUTHENTICATED: case XSS_RESOURCE_BOUND: case XSS_READY: @@ -1001,7 +1011,7 @@ static void on_inbound_server_stream_start(struct xmpp_stream *stream, iks *node case XSS_CONNECT: xmpp_send_server_header_auth(stream); break; - case XSS_BIDI: + case XSS_SECURE: break; case XSS_AUTHENTICATED: { /* all set */ @@ -1075,8 +1085,8 @@ static int on_stream(void *user_data, int type, iks *node) on_stream_presence(stream, node); } else if (!strcmp("auth", name)) { on_stream_auth(stream, node); - } else if (!strcmp("bidi", name)) { - on_stream_bidi(stream, node); + } else if (!strcmp("starttls", name)) { + on_stream_starttls(stream, node); } else if (!strcmp("db:result", name)) { on_stream_dialback_result(stream, node); } else if (!strcmp("db:verify", name)) { @@ -1194,6 +1204,7 @@ static void *SWITCH_THREAD_FUNC xmpp_stream_thread(switch_thread_t *thread, void case IKS_OK: err_count = 0; break; + case IKS_NET_TLSFAIL: case IKS_NET_RWERR: case IKS_NET_NOCONN: case IKS_NET_NOSOCK: @@ -1291,11 +1302,6 @@ static struct xmpp_stream *xmpp_stream_init(struct xmpp_stream_context *context, stream->incoming = incoming; switch_queue_create(&stream->msg_queue, MAX_QUEUE_LEN, pool); - if (!stream->s2s) { - /* client is already bi-directional */ - stream->state = XSS_BIDI; - } - /* set up XMPP stream parser */ stream->parser = iks_stream_new(stream->s2s ? IKS_NS_SERVER : IKS_NS_CLIENT, stream, on_stream); @@ -1829,6 +1835,23 @@ void *xmpp_stream_get_private(struct xmpp_stream *stream) return stream->user_private; } +/** + * Add PEM cert file to stream for new SSL connections + */ +void xmpp_stream_context_add_cert(struct xmpp_stream_context *context, const char *cert_pem_file) +{ + context->cert_pem_file = switch_core_strdup(context->pool, cert_pem_file); +} + +/** + * Add PEM key file to stream for new SSL connections + */ +void xmpp_stream_context_add_key(struct xmpp_stream_context *context, const char *key_pem_file) +{ + context->key_pem_file = switch_core_strdup(context->pool, key_pem_file); +} + + /* For Emacs: * Local Variables: * mode:c diff --git a/src/mod/event_handlers/mod_rayo/xmpp_streams.h b/src/mod/event_handlers/mod_rayo/xmpp_streams.h index d4ba663246..a07c75d025 100644 --- a/src/mod/event_handlers/mod_rayo/xmpp_streams.h +++ b/src/mod/event_handlers/mod_rayo/xmpp_streams.h @@ -37,6 +37,8 @@ typedef void (* xmpp_stream_recv_callback)(struct xmpp_stream *stream, iks *stan typedef void (* xmpp_stream_destroy_callback)(struct xmpp_stream *stream); extern struct xmpp_stream_context *xmpp_stream_context_create(const char *domain, const char *domain_secret, xmpp_stream_ready_callback ready, xmpp_stream_recv_callback recv, xmpp_stream_destroy_callback destroy); +extern void xmpp_stream_context_add_cert(struct xmpp_stream_context *context, const char *cert_pem_file); +extern void xmpp_stream_context_add_key(struct xmpp_stream_context *context, const char *key_pem_file); extern void xmpp_stream_context_add_user(struct xmpp_stream_context *context, const char *user, const char *password); extern void xmpp_stream_context_dump(struct xmpp_stream_context *context, switch_stream_handle_t *stream); extern void xmpp_stream_context_destroy(struct xmpp_stream_context *context);