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;