From c011be62a41aea8b1e08cb323eb2a59dd36b7add Mon Sep 17 00:00:00 2001 From: John Hickey Date: Thu, 4 Apr 2019 16:38:08 -0700 Subject: [PATCH] Bridge TLS Application-Layer Protocol Negotiation In order to connect to brokers that support both websockets and mqtt on the same port (such as Amazon IoT), we need to set an application for the SSL context. This change allows the specification of an application by using the `bridge_alpn` configuration token. Signed-off-by: John Hickey --- lib/mosquitto.c | 1 + lib/mosquitto.h | 1 + lib/mosquitto_internal.h | 1 + lib/net_mosq.c | 16 ++++++++++++++++ lib/options.c | 12 ++++++++++++ man/mosquitto.conf.5.xml | 8 ++++++++ src/bridge.c | 1 + src/conf.c | 12 ++++++++++++ src/mosquitto_broker_internal.h | 1 + 9 files changed, 53 insertions(+) diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 28b3fe3d55..2efbe8292e 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -247,6 +247,7 @@ void mosquitto__destroy(struct mosquitto *mosq) mosquitto__free(mosq->tls_ciphers); mosquitto__free(mosq->tls_psk); mosquitto__free(mosq->tls_psk_identity); + mosquitto__free(mosq->tls_alpn); #endif mosquitto__free(mosq->address); diff --git a/lib/mosquitto.h b/lib/mosquitto.h index b18af4d246..707bca9938 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -110,6 +110,7 @@ enum mosq_opt_t { MOSQ_OPT_TLS_ENGINE = 7, MOSQ_OPT_TLS_ENGINE_KPASS_SHA1 = 8, MOSQ_OPT_TLS_OCSP_REQUIRED = 9, + MOSQ_OPT_TLS_ALPN = 10, }; diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 93222b8e74..cf33c9ad29 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -224,6 +224,7 @@ struct mosquitto { char *tls_engine; char *tls_engine_kpass_sha1; enum mosquitto__keyform tls_keyform; + char *tls_alpn; #endif bool want_write; bool want_connect; diff --git a/lib/net_mosq.c b/lib/net_mosq.c index be37223dc9..0376cebb77 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -527,6 +527,10 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) { int ret; ENGINE *engine = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x10002000L /* ALPN was added into OpenSSL 1.0.2 */ + uint8_t tls_alpn_wire[256]; + uint8_t tls_alpn_len; +#endif if(mosq->ssl_ctx){ if(!mosq->ssl_ctx_defaults){ @@ -582,6 +586,18 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) /* Disable compression */ SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_COMPRESSION); + /* Set ALPN */ + if(mosq->tls_alpn) { +#if OPENSSL_VERSION_NUMBER >= 0x10002000L /* ALPN was added into OpenSSL 1.0.2 */ + tls_alpn_len = (uint8_t) strnlen(mosq->tls_alpn, 254); + tls_alpn_wire[0] = tls_alpn_len; // first byte is length of string + memcpy(tls_alpn_wire + 1, mosq->tls_alpn, tls_alpn_len); + SSL_CTX_set_alpn_protos(mosq->ssl_ctx, tls_alpn_wire, tls_alpn_len + 1); +#else + log__printf(mosq, MOSQ_LOG_ERR, "Error: TLS ALPN not supported by version of OpenSSL."); +#endif + } + #ifdef SSL_MODE_RELEASE_BUFFERS /* Use even less memory per SSL connection. */ SSL_CTX_set_mode(mosq->ssl_ctx, SSL_MODE_RELEASE_BUFFERS); diff --git a/lib/options.c b/lib/options.c index dfd1df3974..72fb8aaea8 100644 --- a/lib/options.c +++ b/lib/options.c @@ -298,6 +298,18 @@ int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, cons #endif break; + case MOSQ_OPT_TLS_ALPN: +#ifdef WITH_TLS + mosq->tls_alpn = mosquitto__strdup(value); + if(!mosq->tls_alpn){ + return MOSQ_ERR_NOMEM; + } + return MOSQ_ERR_SUCCESS; +#else + return MOSQ_ERR_NOT_SUPPORTED; +#endif + break; + default: return MOSQ_ERR_INVAL; } diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index ea32659c49..47a557f158 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -1809,6 +1809,14 @@ topic clients/total in 0 test/mosquitto/org $SYS/broker/ connection to succeed. + + alpn + + Configure the application layer protocol negotiation + option for the TLS session. Useful for brokers that support + both websockets and MQTT on the same port. + + diff --git a/src/bridge.c b/src/bridge.c index f55f12f2ae..7b46daf693 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -87,6 +87,7 @@ int bridge__new(struct mosquitto_db *db, struct mosquitto__bridge *bridge) new_context->tls_ocsp_required = new_context->bridge->tls_ocsp_required; new_context->tls_version = new_context->bridge->tls_version; new_context->tls_insecure = new_context->bridge->tls_insecure; + new_context->tls_alpn = new_context->bridge->tls_alpn; #ifdef FINAL_WITH_TLS_PSK new_context->tls_psk_identity = new_context->bridge->tls_psk_identity; new_context->tls_psk = new_context->bridge->tls_psk; diff --git a/src/conf.c b/src/conf.c index e9e0a410ab..100e521c88 100644 --- a/src/conf.c +++ b/src/conf.c @@ -356,6 +356,7 @@ void config__cleanup(struct mosquitto__config *config) #ifdef WITH_TLS mosquitto__free(config->bridges[i].tls_version); mosquitto__free(config->bridges[i].tls_cafile); + mosquitto__free(config->bridges[i].tls_alpn); #ifdef FINAL_WITH_TLS_PSK mosquitto__free(config->bridges[i].tls_psk_identity); mosquitto__free(config->bridges[i].tls_psk); @@ -962,6 +963,17 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct if(conf__parse_string(&token, "bridge_cafile", &cur_bridge->tls_cafile, saveptr)) return MOSQ_ERR_INVAL; #else log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available."); +#endif + }else if(!strcmp(token, "bridge_alpn")){ +#if defined(WITH_BRIDGE) && defined(WITH_TLS) + if(reload) continue; // FIXME + if(!cur_bridge){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); + return MOSQ_ERR_INVAL; + } + if(conf__parse_string(&token, "bridge_alpn", &cur_bridge->tls_alpn, saveptr)) return MOSQ_ERR_INVAL; +#else + log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TLS support not available."); #endif }else if(!strcmp(token, "bridge_capath")){ #if defined(WITH_BRIDGE) && defined(WITH_TLS) diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 5574463baf..e5b99a5c2d 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -493,6 +493,7 @@ struct mosquitto__bridge{ char *tls_certfile; char *tls_keyfile; char *tls_version; + char *tls_alpn; # ifdef FINAL_WITH_TLS_PSK char *tls_psk_identity; char *tls_psk;