diff --git a/ChangeLog.txt b/ChangeLog.txt index 30260f4a..db6f9db8 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -97,6 +97,12 @@ Client library features: - Add mosquitto_connect_with_flags_callback_set(), which allows a second connect callback to be used which also exposes the connect flags parameter. Closes #738 and #128. +- Add MOSQ_OPT_SSL_CTX option to allow a user specified SSL_CTX to be used + instead of the one generated by libmosquitto. This allows greater control + over what options can be set. Closes #715. +- Add MOSQ_OPT_SSL_CTX_WITH_DEFAULTS to work with MOSQ_OPT_SSL_CTX and have + the default libmosquitto SSL_CTX configuration applied to the user provided + SSL_CTX. Closes #567. Client library fixes: - Fix incorrect PSK key being used if it had leading zeroes. diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 2644725b..65b2278e 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -172,6 +172,7 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_se mosq->threaded = mosq_ts_none; #ifdef WITH_TLS mosq->ssl = NULL; + mosq->ssl_ctx = NULL; mosq->tls_cert_reqs = SSL_VERIFY_PEER; mosq->tls_insecure = false; mosq->want_write = false; diff --git a/lib/mosquitto.h b/lib/mosquitto.h index a1f369c4..48f2f418 100644 --- a/lib/mosquitto.h +++ b/lib/mosquitto.h @@ -90,6 +90,8 @@ enum mosq_err_t { /* Error values */ enum mosq_opt_t { MOSQ_OPT_PROTOCOL_VERSION = 1, + MOSQ_OPT_SSL_CTX = 2, + MOSQ_OPT_SSL_CTX_WITH_DEFAULTS = 3, }; /* MQTT specification restricts client ids to a maximum of 23 characters */ @@ -960,10 +962,27 @@ libmosq_EXPORT int mosquitto_threaded_set(struct mosquitto *mosq, bool threaded) * value - the option specific value. * * Options: - * MOSQ_OPT_PROTOCOL_VERSION - value must be an int, set to either - * MQTT_PROTOCOL_V31 or MQTT_PROTOCOL_V311. Must - * be set before the client connects. Defaults to - * MQTT_PROTOCOL_V31. + * MOSQ_OPT_PROTOCOL_VERSION + * Value must be an int, set to either MQTT_PROTOCOL_V31 or + * MQTT_PROTOCOL_V311. Must be set before the client connects. + * Defaults to MQTT_PROTOCOL_V31. + * + * MOSQ_OPT_SSL_CTX + * Pass an openssl SSL_CTX to be used when creating TLS connections + * rather than libmosquitto creating its own. This must be called + * before connecting to have any effect. If you use this option, the + * onus is on you to ensure that you are using secure settings. + * Setting to NULL means that libmosquitto will use its own SSL_CTX + * if TLS is to be used. + * + * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS + * Value must be an int set to 1 or 0. If set to 1, then the user + * specified SSL_CTX passed in using MOSQ_OPT_SSL_CTX will have the + * default options applied to it. This means that you only need to + * change the values that are relevant to you. If you use this + * option then you must configure the TLS options as normal, i.e. + * you should use to configure the cafile/capath + * as a minimum. */ libmosq_EXPORT int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value); diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 3a704c12..05667a78 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -188,6 +188,7 @@ struct mosquitto { char *tls_psk_identity; int tls_cert_reqs; bool tls_insecure; + bool ssl_ctx_defaults; #endif bool want_write; bool want_connect; diff --git a/lib/net_mosq.c b/lib/net_mosq.c index 1f442791..0be1cedb 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -442,14 +442,21 @@ int net__socket_connect_tls(struct mosquitto *mosq) } #endif -int net__socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking) + +static int net__init_ssl_ctx(struct mosquitto *mosq) { #ifdef WITH_TLS int ret; - BIO *bio; -#endif -#ifdef WITH_TLS + if(mosq->ssl_ctx){ + if(!mosq->ssl_ctx_defaults){ + return MOSQ_ERR_SUCCESS; + }else if(!mosq->tls_cafile && !mosq->tls_capath && !mosq->tls_psk){ + log__printf(mosq, MOSQ_LOG_ERR, "Error: MOSQ_OPT_SSL_CTX_WITH_DEFAULTS used without specifying cafile, capath or psk."); + return MOSQ_ERR_INVAL; + } + } + if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){ #if OPENSSL_VERSION_NUMBER >= 0x10001000L if(!mosq->tls_version){ @@ -572,7 +579,22 @@ int net__socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t SSL_CTX_set_psk_client_callback(mosq->ssl_ctx, psk_client_callback); #endif } + } + +#endif + return MOSQ_ERR_SUCCESS; +} + + +int net__socket_connect_step3(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking) +{ +#ifdef WITH_TLS + BIO *bio; + + int rc = net__init_ssl_ctx(mosq); + if(rc) return rc; + if(mosq->ssl_ctx){ mosq->ssl = SSL_new(mosq->ssl_ctx); if(!mosq->ssl){ COMPAT_CLOSE(mosq->sock); diff --git a/lib/options.c b/lib/options.c index f6dc3165..670ab57a 100644 --- a/lib/options.c +++ b/lib/options.c @@ -277,6 +277,20 @@ int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *val return MOSQ_ERR_INVAL; } break; + case MOSQ_OPT_SSL_CTX: +#ifdef WITH_TLS + mosq->ssl_ctx = (SSL_CTX *)value; + break; +#else + return MOSQ_ERR_UNSUPPORTED; +#endif + case MOSQ_OPT_SSL_CTX_WITH_DEFAULTS: +#ifdef WITH_TLS + mosq->ssl_ctx_defaults = true; + break; +#else + return MOSQ_ERR_UNSUPPORTED; +#endif default: return MOSQ_ERR_INVAL; }