123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227 |
- /*
- Copyright (c) 2009-2020 Roger Light <roger@atchoo.org>
- All rights reserved. This program and the accompanying materials
- are made available under the terms of the Eclipse Public License 2.0
- and Eclipse Distribution License v1.0 which accompany this distribution.
- The Eclipse Public License is available at
- https://www.eclipse.org/legal/epl-2.0/
- and the Eclipse Distribution License is available at
- http://www.eclipse.org/org/documents/edl-v10.php.
- SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
- Contributors:
- Roger Light - initial implementation and documentation.
- */
- #define _GNU_SOURCE
- #include "config.h"
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <string.h>
- #ifndef WIN32
- #define _GNU_SOURCE
- #include <netdb.h>
- #include <netinet/tcp.h>
- #include <sys/socket.h>
- #include <unistd.h>
- #else
- #include <winsock2.h>
- #include <ws2tcpip.h>
- #endif
- #ifdef __ANDROID__
- #include <linux/in.h>
- #include <linux/in6.h>
- #include <sys/endian.h>
- #endif
- #ifdef HAVE_NETINET_IN_H
- # include <netinet/in.h>
- #endif
- #ifdef WITH_UNIX_SOCKETS
- # include <sys/un.h>
- #endif
- #ifdef __QNX__
- #include <net/netbyte.h>
- #endif
- #ifdef WITH_TLS
- #include <openssl/conf.h>
- #include <openssl/engine.h>
- #include <openssl/err.h>
- #include <openssl/ui.h>
- #include <tls_mosq.h>
- #endif
- #ifdef WITH_BROKER
- # include "mosquitto_broker_internal.h"
- # ifdef WITH_WEBSOCKETS
- # include <libwebsockets.h>
- # endif
- #else
- # include "read_handle.h"
- #endif
- #include "logging_mosq.h"
- #include "memory_mosq.h"
- #include "mqtt_protocol.h"
- #include "net_mosq.h"
- #include "time_mosq.h"
- #include "util_mosq.h"
- #ifdef WITH_TLS
- int tls_ex_index_mosq = -1;
- UI_METHOD *_ui_method = NULL;
- static bool is_tls_initialized = false;
- /* Functions taken from OpenSSL s_server/s_client */
- static int ui_open(UI *ui)
- {
- return UI_method_get_opener(UI_OpenSSL())(ui);
- }
- static int ui_read(UI *ui, UI_STRING *uis)
- {
- return UI_method_get_reader(UI_OpenSSL())(ui, uis);
- }
- static int ui_write(UI *ui, UI_STRING *uis)
- {
- return UI_method_get_writer(UI_OpenSSL())(ui, uis);
- }
- static int ui_close(UI *ui)
- {
- return UI_method_get_closer(UI_OpenSSL())(ui);
- }
- static void setup_ui_method(void)
- {
- _ui_method = UI_create_method("OpenSSL application user interface");
- UI_method_set_opener(_ui_method, ui_open);
- UI_method_set_reader(_ui_method, ui_read);
- UI_method_set_writer(_ui_method, ui_write);
- UI_method_set_closer(_ui_method, ui_close);
- }
- static void cleanup_ui_method(void)
- {
- if(_ui_method){
- UI_destroy_method(_ui_method);
- _ui_method = NULL;
- }
- }
- UI_METHOD *net__get_ui_method(void)
- {
- return _ui_method;
- }
- #endif
- int net__init(void)
- {
- #ifdef WIN32
- WSADATA wsaData;
- if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
- return MOSQ_ERR_UNKNOWN;
- }
- #endif
- #ifdef WITH_SRV
- ares_library_init(ARES_LIB_INIT_ALL);
- #endif
- return MOSQ_ERR_SUCCESS;
- }
- void net__cleanup(void)
- {
- #ifdef WITH_TLS
- # if OPENSSL_VERSION_NUMBER < 0x10100000L
- CRYPTO_cleanup_all_ex_data();
- ERR_free_strings();
- ERR_remove_thread_state(NULL);
- EVP_cleanup();
- # if !defined(OPENSSL_NO_ENGINE)
- ENGINE_cleanup();
- # endif
- is_tls_initialized = false;
- # endif
- CONF_modules_unload(1);
- cleanup_ui_method();
- #endif
- #ifdef WITH_SRV
- ares_library_cleanup();
- #endif
- #ifdef WIN32
- WSACleanup();
- #endif
- }
- #ifdef WITH_TLS
- void net__init_tls(void)
- {
- if(is_tls_initialized) return;
- # if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL_load_error_strings();
- SSL_library_init();
- OpenSSL_add_all_algorithms();
- # else
- OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
- | OPENSSL_INIT_ADD_ALL_DIGESTS \
- | OPENSSL_INIT_LOAD_CONFIG, NULL);
- # endif
- #if !defined(OPENSSL_NO_ENGINE)
- ENGINE_load_builtin_engines();
- #endif
- setup_ui_method();
- if(tls_ex_index_mosq == -1){
- tls_ex_index_mosq = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL);
- }
- is_tls_initialized = true;
- }
- #endif
- /* Close a socket associated with a context and set it to -1.
- * Returns 1 on failure (context is NULL)
- * Returns 0 on success.
- */
- int net__socket_close(struct mosquitto *mosq)
- {
- int rc = 0;
- #ifdef WITH_BROKER
- struct mosquitto *mosq_found;
- #endif
- assert(mosq);
- #ifdef WITH_TLS
- #ifdef WITH_WEBSOCKETS
- if(!mosq->wsi)
- #endif
- {
- if(mosq->ssl){
- if(!SSL_in_init(mosq->ssl)){
- SSL_shutdown(mosq->ssl);
- }
- SSL_free(mosq->ssl);
- mosq->ssl = NULL;
- }
- }
- #endif
- #ifdef WITH_WEBSOCKETS
- if(mosq->wsi)
- {
- if(mosq->state != mosq_cs_disconnecting){
- mosquitto__set_state(mosq, mosq_cs_disconnect_ws);
- }
- lws_callback_on_writable(mosq->wsi);
- }else
- #endif
- {
- if(mosq->sock != INVALID_SOCKET){
- #ifdef WITH_BROKER
- HASH_FIND(hh_sock, db.contexts_by_sock, &mosq->sock, sizeof(mosq->sock), mosq_found);
- if(mosq_found){
- HASH_DELETE(hh_sock, db.contexts_by_sock, mosq_found);
- }
- #endif
- rc = COMPAT_CLOSE(mosq->sock);
- mosq->sock = INVALID_SOCKET;
- }
- }
- #ifdef WITH_BROKER
- if(mosq->listener){
- mosq->listener->client_count--;
- mosq->listener = NULL;
- }
- #endif
- return rc;
- }
- #ifdef FINAL_WITH_TLS_PSK
- static unsigned int psk_client_callback(SSL *ssl, const char *hint,
- char *identity, unsigned int max_identity_len,
- unsigned char *psk, unsigned int max_psk_len)
- {
- struct mosquitto *mosq;
- int len;
- UNUSED(hint);
- mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq);
- if(!mosq) return 0;
- snprintf(identity, max_identity_len, "%s", mosq->tls_psk_identity);
- len = mosquitto__hex2bin(mosq->tls_psk, psk, (int)max_psk_len);
- if (len < 0) return 0;
- return (unsigned int)len;
- }
- #endif
- #if defined(WITH_BROKER) && defined(__GLIBC__) && defined(WITH_ADNS)
- /* Async connect, part 1 (dns lookup) */
- int net__try_connect_step1(struct mosquitto *mosq, const char *host)
- {
- int s;
- void *sevp = NULL;
- struct addrinfo *hints;
- if(mosq->adns){
- gai_cancel(mosq->adns);
- mosquitto__free((struct addrinfo *)mosq->adns->ar_request);
- mosquitto__free(mosq->adns);
- }
- mosq->adns = mosquitto__calloc(1, sizeof(struct gaicb));
- if(!mosq->adns){
- return MOSQ_ERR_NOMEM;
- }
- hints = mosquitto__calloc(1, sizeof(struct addrinfo));
- if(!hints){
- mosquitto__free(mosq->adns);
- mosq->adns = NULL;
- return MOSQ_ERR_NOMEM;
- }
- hints->ai_family = AF_UNSPEC;
- hints->ai_socktype = SOCK_STREAM;
- mosq->adns->ar_name = host;
- mosq->adns->ar_request = hints;
- s = getaddrinfo_a(GAI_NOWAIT, &mosq->adns, 1, sevp);
- if(s){
- errno = s;
- if(mosq->adns){
- mosquitto__free((struct addrinfo *)mosq->adns->ar_request);
- mosquitto__free(mosq->adns);
- mosq->adns = NULL;
- }
- return MOSQ_ERR_EAI;
- }
- return MOSQ_ERR_SUCCESS;
- }
- /* Async connect part 2, the connection. */
- int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *sock)
- {
- struct addrinfo *ainfo, *rp;
- int rc;
- ainfo = mosq->adns->ar_result;
- for(rp = ainfo; rp != NULL; rp = rp->ai_next){
- *sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
- if(*sock == INVALID_SOCKET) continue;
- if(rp->ai_family == AF_INET){
- ((struct sockaddr_in *)rp->ai_addr)->sin_port = htons(port);
- }else if(rp->ai_family == AF_INET6){
- ((struct sockaddr_in6 *)rp->ai_addr)->sin6_port = htons(port);
- }else{
- COMPAT_CLOSE(*sock);
- *sock = INVALID_SOCKET;
- continue;
- }
- /* Set non-blocking */
- if(net__socket_nonblock(sock)){
- continue;
- }
- rc = connect(*sock, rp->ai_addr, rp->ai_addrlen);
- #ifdef WIN32
- errno = WSAGetLastError();
- #endif
- if(rc == 0 || errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK){
- if(rc < 0 && (errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK)){
- rc = MOSQ_ERR_CONN_PENDING;
- }
- /* Set non-blocking */
- if(net__socket_nonblock(sock)){
- continue;
- }
- break;
- }
- COMPAT_CLOSE(*sock);
- *sock = INVALID_SOCKET;
- }
- freeaddrinfo(mosq->adns->ar_result);
- mosq->adns->ar_result = NULL;
- mosquitto__free((struct addrinfo *)mosq->adns->ar_request);
- mosquitto__free(mosq->adns);
- mosq->adns = NULL;
- if(!rp){
- return MOSQ_ERR_ERRNO;
- }
- return rc;
- }
- #endif
- static int net__try_connect_tcp(const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking)
- {
- struct addrinfo hints;
- struct addrinfo *ainfo, *rp;
- struct addrinfo *ainfo_bind, *rp_bind;
- int s;
- int rc = MOSQ_ERR_SUCCESS;
- ainfo_bind = NULL;
- *sock = INVALID_SOCKET;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- s = getaddrinfo(host, NULL, &hints, &ainfo);
- if(s){
- errno = s;
- return MOSQ_ERR_EAI;
- }
- if(bind_address){
- s = getaddrinfo(bind_address, NULL, &hints, &ainfo_bind);
- if(s){
- freeaddrinfo(ainfo);
- errno = s;
- return MOSQ_ERR_EAI;
- }
- }
- for(rp = ainfo; rp != NULL; rp = rp->ai_next){
- *sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
- if(*sock == INVALID_SOCKET) continue;
- if(rp->ai_family == AF_INET){
- ((struct sockaddr_in *)rp->ai_addr)->sin_port = htons(port);
- }else if(rp->ai_family == AF_INET6){
- ((struct sockaddr_in6 *)rp->ai_addr)->sin6_port = htons(port);
- }else{
- COMPAT_CLOSE(*sock);
- *sock = INVALID_SOCKET;
- continue;
- }
- if(bind_address){
- for(rp_bind = ainfo_bind; rp_bind != NULL; rp_bind = rp_bind->ai_next){
- if(bind(*sock, rp_bind->ai_addr, rp_bind->ai_addrlen) == 0){
- break;
- }
- }
- if(!rp_bind){
- COMPAT_CLOSE(*sock);
- *sock = INVALID_SOCKET;
- continue;
- }
- }
- if(!blocking){
- /* Set non-blocking */
- if(net__socket_nonblock(sock)){
- continue;
- }
- }
- rc = connect(*sock, rp->ai_addr, rp->ai_addrlen);
- #ifdef WIN32
- errno = WSAGetLastError();
- #endif
- if(rc == 0 || errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK){
- if(rc < 0 && (errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK)){
- rc = MOSQ_ERR_CONN_PENDING;
- }
- if(blocking){
- /* Set non-blocking */
- if(net__socket_nonblock(sock)){
- continue;
- }
- }
- break;
- }
- COMPAT_CLOSE(*sock);
- *sock = INVALID_SOCKET;
- }
- freeaddrinfo(ainfo);
- if(bind_address){
- freeaddrinfo(ainfo_bind);
- }
- if(!rp){
- return MOSQ_ERR_ERRNO;
- }
- return rc;
- }
- #ifdef WITH_UNIX_SOCKETS
- static int net__try_connect_unix(const char *host, mosq_sock_t *sock)
- {
- struct sockaddr_un addr;
- int s;
- int rc;
- if(host == NULL || strlen(host) == 0 || strlen(host) > sizeof(addr.sun_path)-1){
- return MOSQ_ERR_INVAL;
- }
- memset(&addr, 0, sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, host, sizeof(addr.sun_path)-1);
- s = socket(AF_UNIX, SOCK_STREAM, 0);
- if(s < 0){
- return MOSQ_ERR_ERRNO;
- }
- rc = net__socket_nonblock(&s);
- if(rc) return rc;
- rc = connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));
- if(rc < 0){
- close(s);
- return MOSQ_ERR_ERRNO;
- }
- *sock = s;
- return 0;
- }
- #endif
- int net__try_connect(const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking)
- {
- if(port == 0){
- #ifdef WITH_UNIX_SOCKETS
- return net__try_connect_unix(host, sock);
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- }else{
- return net__try_connect_tcp(host, port, sock, bind_address, blocking);
- }
- }
- #ifdef WITH_TLS
- void net__print_ssl_error(struct mosquitto *mosq)
- {
- char ebuf[256];
- unsigned long e;
- int num = 0;
- e = ERR_get_error();
- while(e){
- log__printf(mosq, MOSQ_LOG_ERR, "OpenSSL Error[%d]: %s", num, ERR_error_string(e, ebuf));
- e = ERR_get_error();
- num++;
- }
- }
- int net__socket_connect_tls(struct mosquitto *mosq)
- {
- int ret, err;
- long res;
- ERR_clear_error();
- if (mosq->tls_ocsp_required) {
- /* Note: OCSP is available in all currently supported OpenSSL versions. */
- if ((res=SSL_set_tlsext_status_type(mosq->ssl, TLSEXT_STATUSTYPE_ocsp)) != 1) {
- log__printf(mosq, MOSQ_LOG_ERR, "Could not activate OCSP (error: %ld)", res);
- return MOSQ_ERR_OCSP;
- }
- if ((res=SSL_CTX_set_tlsext_status_cb(mosq->ssl_ctx, mosquitto__verify_ocsp_status_cb)) != 1) {
- log__printf(mosq, MOSQ_LOG_ERR, "Could not activate OCSP (error: %ld)", res);
- return MOSQ_ERR_OCSP;
- }
- if ((res=SSL_CTX_set_tlsext_status_arg(mosq->ssl_ctx, mosq)) != 1) {
- log__printf(mosq, MOSQ_LOG_ERR, "Could not activate OCSP (error: %ld)", res);
- return MOSQ_ERR_OCSP;
- }
- }
- ret = SSL_connect(mosq->ssl);
- if(ret != 1) {
- err = SSL_get_error(mosq->ssl, ret);
- if (err == SSL_ERROR_SYSCALL) {
- mosq->want_connect = true;
- return MOSQ_ERR_SUCCESS;
- }
- if(err == SSL_ERROR_WANT_READ){
- mosq->want_connect = true;
- /* We always try to read anyway */
- }else if(err == SSL_ERROR_WANT_WRITE){
- mosq->want_write = true;
- mosq->want_connect = true;
- }else{
- net__print_ssl_error(mosq);
- COMPAT_CLOSE(mosq->sock);
- mosq->sock = INVALID_SOCKET;
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- }else{
- mosq->want_connect = false;
- }
- return MOSQ_ERR_SUCCESS;
- }
- #endif
- #ifdef WITH_TLS
- static int net__tls_load_ca(struct mosquitto *mosq)
- {
- int ret;
- if(mosq->tls_use_os_certs){
- SSL_CTX_set_default_verify_paths(mosq->ssl_ctx);
- }
- #if OPENSSL_VERSION_NUMBER < 0x30000000L
- if(mosq->tls_cafile || mosq->tls_capath){
- ret = SSL_CTX_load_verify_locations(mosq->ssl_ctx, mosq->tls_cafile, mosq->tls_capath);
- if(ret == 0){
- # ifdef WITH_BROKER
- if(mosq->tls_cafile && mosq->tls_capath){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\" and bridge_capath \"%s\".", mosq->tls_cafile, mosq->tls_capath);
- }else if(mosq->tls_cafile){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\".", mosq->tls_cafile);
- }else{
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_capath \"%s\".", mosq->tls_capath);
- }
- # else
- if(mosq->tls_cafile && mosq->tls_capath){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\" and capath \"%s\".", mosq->tls_cafile, mosq->tls_capath);
- }else if(mosq->tls_cafile){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\".", mosq->tls_cafile);
- }else{
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check capath \"%s\".", mosq->tls_capath);
- }
- # endif
- return MOSQ_ERR_TLS;
- }
- }
- #else
- if(mosq->tls_cafile){
- ret = SSL_CTX_load_verify_file(mosq->ssl_ctx, mosq->tls_cafile);
- if(ret == 0){
- # ifdef WITH_BROKER
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_cafile \"%s\".", mosq->tls_cafile);
- # else
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check cafile \"%s\".", mosq->tls_cafile);
- # endif
- return MOSQ_ERR_TLS;
- }
- }
- if(mosq->tls_capath){
- ret = SSL_CTX_load_verify_dir(mosq->ssl_ctx, mosq->tls_capath);
- if(ret == 0){
- # ifdef WITH_BROKER
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check bridge_capath \"%s\".", mosq->tls_capath);
- # else
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load CA certificates, check capath \"%s\".", mosq->tls_capath);
- # endif
- return MOSQ_ERR_TLS;
- }
- }
- #endif
- return MOSQ_ERR_SUCCESS;
- }
- static int net__init_ssl_ctx(struct mosquitto *mosq)
- {
- int ret;
- ENGINE *engine = NULL;
- uint8_t tls_alpn_wire[256];
- uint8_t tls_alpn_len;
- #if !defined(OPENSSL_NO_ENGINE)
- EVP_PKEY *pkey;
- #endif
- #ifndef WITH_BROKER
- if(mosq->user_ssl_ctx){
- mosq->ssl_ctx = mosq->user_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: If you use MOSQ_OPT_SSL_CTX then MOSQ_OPT_SSL_CTX_WITH_DEFAULTS must be true, or at least one of cafile, capath or psk must be specified.");
- return MOSQ_ERR_INVAL;
- }
- }
- #endif
- /* Apply default SSL_CTX settings. This is only used if MOSQ_OPT_SSL_CTX
- * has not been set, or if both of MOSQ_OPT_SSL_CTX and
- * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS are set. */
- if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk || mosq->tls_use_os_certs){
- if(!mosq->ssl_ctx){
- net__init_tls();
- #if OPENSSL_VERSION_NUMBER < 0x10100000L
- mosq->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
- #else
- mosq->ssl_ctx = SSL_CTX_new(TLS_client_method());
- #endif
- if(!mosq->ssl_ctx){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- }
- #ifdef SSL_OP_NO_TLSv1_3
- if(mosq->tls_psk){
- SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_TLSv1_3);
- }
- #endif
- if(!mosq->tls_version){
- SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
- #ifdef SSL_OP_NO_TLSv1_3
- }else if(!strcmp(mosq->tls_version, "tlsv1.3")){
- SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
- #endif
- }else if(!strcmp(mosq->tls_version, "tlsv1.2")){
- SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
- }else if(!strcmp(mosq->tls_version, "tlsv1.1")){
- SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
- }else{
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Protocol %s not supported.", mosq->tls_version);
- return MOSQ_ERR_INVAL;
- }
- #if OPENSSL_VERSION_NUMBER >= 0x10100000L
- /* Allow use of DHE ciphers */
- SSL_CTX_set_dh_auto(mosq->ssl_ctx, 1);
- #endif
- /* Disable compression */
- SSL_CTX_set_options(mosq->ssl_ctx, SSL_OP_NO_COMPRESSION);
- /* Set ALPN */
- if(mosq->tls_alpn) {
- 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 + 1U);
- }
- #ifdef SSL_MODE_RELEASE_BUFFERS
- /* Use even less memory per SSL connection. */
- SSL_CTX_set_mode(mosq->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
- #endif
- #if !defined(OPENSSL_NO_ENGINE)
- if(mosq->tls_engine){
- engine = ENGINE_by_id(mosq->tls_engine);
- if(!engine){
- log__printf(mosq, MOSQ_LOG_ERR, "Error loading %s engine\n", mosq->tls_engine);
- return MOSQ_ERR_TLS;
- }
- if(!ENGINE_init(engine)){
- log__printf(mosq, MOSQ_LOG_ERR, "Failed engine initialisation\n");
- ENGINE_free(engine);
- return MOSQ_ERR_TLS;
- }
- ENGINE_set_default(engine, ENGINE_METHOD_ALL);
- ENGINE_free(engine); /* release the structural reference from ENGINE_by_id() */
- }
- #endif
- if(mosq->tls_ciphers){
- ret = SSL_CTX_set_cipher_list(mosq->ssl_ctx, mosq->tls_ciphers);
- if(ret == 0){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", mosq->tls_ciphers);
- #if !defined(OPENSSL_NO_ENGINE)
- ENGINE_FINISH(engine);
- #endif
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- }
- if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_use_os_certs){
- ret = net__tls_load_ca(mosq);
- if(ret != MOSQ_ERR_SUCCESS){
- # if !defined(OPENSSL_NO_ENGINE)
- ENGINE_FINISH(engine);
- # endif
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- if(mosq->tls_cert_reqs == 0){
- SSL_CTX_set_verify(mosq->ssl_ctx, SSL_VERIFY_NONE, NULL);
- }else{
- SSL_CTX_set_verify(mosq->ssl_ctx, SSL_VERIFY_PEER, mosquitto__server_certificate_verify);
- }
- if(mosq->tls_pw_callback){
- SSL_CTX_set_default_passwd_cb(mosq->ssl_ctx, mosq->tls_pw_callback);
- SSL_CTX_set_default_passwd_cb_userdata(mosq->ssl_ctx, mosq);
- }
- if(mosq->tls_certfile){
- ret = SSL_CTX_use_certificate_chain_file(mosq->ssl_ctx, mosq->tls_certfile);
- if(ret != 1){
- #ifdef WITH_BROKER
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate, check bridge_certfile \"%s\".", mosq->tls_certfile);
- #else
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client certificate \"%s\".", mosq->tls_certfile);
- #endif
- #if !defined(OPENSSL_NO_ENGINE)
- ENGINE_FINISH(engine);
- #endif
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- }
- if(mosq->tls_keyfile){
- if(mosq->tls_keyform == mosq_k_engine){
- #if !defined(OPENSSL_NO_ENGINE)
- UI_METHOD *ui_method = net__get_ui_method();
- if(mosq->tls_engine_kpass_sha1){
- if(!ENGINE_ctrl_cmd(engine, ENGINE_SECRET_MODE, ENGINE_SECRET_MODE_SHA, NULL, NULL, 0)){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set engine secret mode sha1");
- ENGINE_FINISH(engine);
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- if(!ENGINE_ctrl_cmd(engine, ENGINE_PIN, 0, mosq->tls_engine_kpass_sha1, NULL, 0)){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to set engine pin");
- ENGINE_FINISH(engine);
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- ui_method = NULL;
- }
- pkey = ENGINE_load_private_key(engine, mosq->tls_keyfile, ui_method, NULL);
- if(!pkey){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load engine private key file \"%s\".", mosq->tls_keyfile);
- ENGINE_FINISH(engine);
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- if(SSL_CTX_use_PrivateKey(mosq->ssl_ctx, pkey) <= 0){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to use engine private key file \"%s\".", mosq->tls_keyfile);
- ENGINE_FINISH(engine);
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- #endif
- }else{
- ret = SSL_CTX_use_PrivateKey_file(mosq->ssl_ctx, mosq->tls_keyfile, SSL_FILETYPE_PEM);
- if(ret != 1){
- #ifdef WITH_BROKER
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file, check bridge_keyfile \"%s\".", mosq->tls_keyfile);
- #else
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Unable to load client key file \"%s\".", mosq->tls_keyfile);
- #endif
- #if !defined(OPENSSL_NO_ENGINE)
- ENGINE_FINISH(engine);
- #endif
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- }
- ret = SSL_CTX_check_private_key(mosq->ssl_ctx);
- if(ret != 1){
- log__printf(mosq, MOSQ_LOG_ERR, "Error: Client certificate/key are inconsistent.");
- #if !defined(OPENSSL_NO_ENGINE)
- ENGINE_FINISH(engine);
- #endif
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- }
- #ifdef FINAL_WITH_TLS_PSK
- }else if(mosq->tls_psk){
- SSL_CTX_set_psk_client_callback(mosq->ssl_ctx, psk_client_callback);
- if(mosq->tls_ciphers == NULL){
- SSL_CTX_set_cipher_list(mosq->ssl_ctx, "PSK");
- }
- #endif
- }
- }
- return MOSQ_ERR_SUCCESS;
- }
- #endif
- int net__socket_connect_step3(struct mosquitto *mosq, const char *host)
- {
- #ifdef WITH_TLS
- BIO *bio;
- int rc = net__init_ssl_ctx(mosq);
- if(rc){
- net__socket_close(mosq);
- return rc;
- }
- if(mosq->ssl_ctx){
- if(mosq->ssl){
- SSL_free(mosq->ssl);
- }
- mosq->ssl = SSL_new(mosq->ssl_ctx);
- if(!mosq->ssl){
- net__socket_close(mosq);
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- SSL_set_ex_data(mosq->ssl, tls_ex_index_mosq, mosq);
- bio = BIO_new_socket(mosq->sock, BIO_NOCLOSE);
- if(!bio){
- net__socket_close(mosq);
- net__print_ssl_error(mosq);
- return MOSQ_ERR_TLS;
- }
- SSL_set_bio(mosq->ssl, bio, bio);
- /*
- * required for the SNI resolving
- */
- if(SSL_set_tlsext_host_name(mosq->ssl, host) != 1) {
- net__socket_close(mosq);
- return MOSQ_ERR_TLS;
- }
- if(net__socket_connect_tls(mosq)){
- net__socket_close(mosq);
- return MOSQ_ERR_TLS;
- }
- }
- #else
- UNUSED(mosq);
- UNUSED(host);
- #endif
- return MOSQ_ERR_SUCCESS;
- }
- /* Create a socket and connect it to 'ip' on port 'port'. */
- int net__socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking)
- {
- int rc, rc2;
- if(!mosq || !host) return MOSQ_ERR_INVAL;
- rc = net__try_connect(host, port, &mosq->sock, bind_address, blocking);
- if(rc > 0) return rc;
- if(mosq->tcp_nodelay){
- int flag = 1;
- if(setsockopt(mosq->sock, IPPROTO_TCP, TCP_NODELAY, (const void*)&flag, sizeof(int)) != 0){
- log__printf(mosq, MOSQ_LOG_WARNING, "Warning: Unable to set TCP_NODELAY.");
- }
- }
- #if defined(WITH_SOCKS) && !defined(WITH_BROKER)
- if(!mosq->socks5_host)
- #endif
- {
- rc2 = net__socket_connect_step3(mosq, host);
- if(rc2) return rc2;
- }
- return rc;
- }
- #ifdef WITH_TLS
- static int net__handle_ssl(struct mosquitto* mosq, int ret)
- {
- int err;
- err = SSL_get_error(mosq->ssl, ret);
- if (err == SSL_ERROR_WANT_READ) {
- ret = -1;
- errno = EAGAIN;
- }
- else if (err == SSL_ERROR_WANT_WRITE) {
- ret = -1;
- #ifdef WITH_BROKER
- mux__add_out(mosq);
- #else
- mosq->want_write = true;
- #endif
- errno = EAGAIN;
- }
- else {
- net__print_ssl_error(mosq);
- errno = EPROTO;
- }
- ERR_clear_error();
- #ifdef WIN32
- WSASetLastError(errno);
- #endif
- return ret;
- }
- #endif
- ssize_t net__read(struct mosquitto *mosq, void *buf, size_t count)
- {
- #ifdef WITH_TLS
- int ret;
- #endif
- assert(mosq);
- errno = 0;
- #ifdef WITH_TLS
- if(mosq->ssl){
- ret = SSL_read(mosq->ssl, buf, (int)count);
- if(ret <= 0){
- ret = net__handle_ssl(mosq, ret);
- }
- return (ssize_t )ret;
- }else{
- /* Call normal read/recv */
- #endif
- #ifndef WIN32
- return read(mosq->sock, buf, count);
- #else
- return recv(mosq->sock, buf, count, 0);
- #endif
- #ifdef WITH_TLS
- }
- #endif
- }
- ssize_t net__write(struct mosquitto *mosq, const void *buf, size_t count)
- {
- #ifdef WITH_TLS
- int ret;
- #endif
- assert(mosq);
- errno = 0;
- #ifdef WITH_TLS
- if(mosq->ssl){
- mosq->want_write = false;
- ret = SSL_write(mosq->ssl, buf, (int)count);
- if(ret < 0){
- ret = net__handle_ssl(mosq, ret);
- }
- return (ssize_t )ret;
- }else{
- /* Call normal write/send */
- #endif
- #ifndef WIN32
- return write(mosq->sock, buf, count);
- #else
- return send(mosq->sock, buf, count, 0);
- #endif
- #ifdef WITH_TLS
- }
- #endif
- }
- int net__socket_nonblock(mosq_sock_t *sock)
- {
- #ifndef WIN32
- int opt;
- /* Set non-blocking */
- opt = fcntl(*sock, F_GETFL, 0);
- if(opt == -1){
- COMPAT_CLOSE(*sock);
- *sock = INVALID_SOCKET;
- return MOSQ_ERR_ERRNO;
- }
- if(fcntl(*sock, F_SETFL, opt | O_NONBLOCK) == -1){
- /* If either fcntl fails, don't want to allow this client to connect. */
- COMPAT_CLOSE(*sock);
- *sock = INVALID_SOCKET;
- return MOSQ_ERR_ERRNO;
- }
- #else
- unsigned long opt = 1;
- if(ioctlsocket(*sock, FIONBIO, &opt)){
- COMPAT_CLOSE(*sock);
- *sock = INVALID_SOCKET;
- return MOSQ_ERR_ERRNO;
- }
- #endif
- return MOSQ_ERR_SUCCESS;
- }
- #ifndef WITH_BROKER
- int net__socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
- {
- #ifdef WIN32
- int family[2] = {AF_INET, AF_INET6};
- int i;
- struct sockaddr_storage ss;
- struct sockaddr_in *sa = (struct sockaddr_in *)&ss;
- struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&ss;
- socklen_t ss_len;
- mosq_sock_t spR, spW;
- mosq_sock_t listensock;
- *pairR = INVALID_SOCKET;
- *pairW = INVALID_SOCKET;
- for(i=0; i<2; i++){
- memset(&ss, 0, sizeof(ss));
- if(family[i] == AF_INET){
- sa->sin_family = family[i];
- sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- sa->sin_port = 0;
- ss_len = sizeof(struct sockaddr_in);
- }else if(family[i] == AF_INET6){
- sa6->sin6_family = family[i];
- sa6->sin6_addr = in6addr_loopback;
- sa6->sin6_port = 0;
- ss_len = sizeof(struct sockaddr_in6);
- }else{
- return MOSQ_ERR_INVAL;
- }
- listensock = socket(family[i], SOCK_STREAM, IPPROTO_TCP);
- if(listensock == -1){
- continue;
- }
- if(bind(listensock, (struct sockaddr *)&ss, ss_len) == -1){
- COMPAT_CLOSE(listensock);
- continue;
- }
- if(listen(listensock, 1) == -1){
- COMPAT_CLOSE(listensock);
- continue;
- }
- memset(&ss, 0, sizeof(ss));
- ss_len = sizeof(ss);
- if(getsockname(listensock, (struct sockaddr *)&ss, &ss_len) < 0){
- COMPAT_CLOSE(listensock);
- continue;
- }
- if(family[i] == AF_INET){
- sa->sin_family = family[i];
- sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- ss_len = sizeof(struct sockaddr_in);
- }else if(family[i] == AF_INET6){
- sa6->sin6_family = family[i];
- sa6->sin6_addr = in6addr_loopback;
- ss_len = sizeof(struct sockaddr_in6);
- }
- spR = socket(family[i], SOCK_STREAM, IPPROTO_TCP);
- if(spR == -1){
- COMPAT_CLOSE(listensock);
- continue;
- }
- if(net__socket_nonblock(&spR)){
- COMPAT_CLOSE(listensock);
- continue;
- }
- if(connect(spR, (struct sockaddr *)&ss, ss_len) < 0){
- #ifdef WIN32
- errno = WSAGetLastError();
- #endif
- if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK){
- COMPAT_CLOSE(spR);
- COMPAT_CLOSE(listensock);
- continue;
- }
- }
- spW = accept(listensock, NULL, 0);
- if(spW == -1){
- #ifdef WIN32
- errno = WSAGetLastError();
- #endif
- if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK){
- COMPAT_CLOSE(spR);
- COMPAT_CLOSE(listensock);
- continue;
- }
- }
- if(net__socket_nonblock(&spW)){
- COMPAT_CLOSE(spR);
- COMPAT_CLOSE(listensock);
- continue;
- }
- COMPAT_CLOSE(listensock);
- *pairR = spR;
- *pairW = spW;
- return MOSQ_ERR_SUCCESS;
- }
- return MOSQ_ERR_UNKNOWN;
- #else
- int sv[2];
- *pairR = INVALID_SOCKET;
- *pairW = INVALID_SOCKET;
- if(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1){
- return MOSQ_ERR_ERRNO;
- }
- if(net__socket_nonblock(&sv[0])){
- COMPAT_CLOSE(sv[1]);
- return MOSQ_ERR_ERRNO;
- }
- if(net__socket_nonblock(&sv[1])){
- COMPAT_CLOSE(sv[0]);
- return MOSQ_ERR_ERRNO;
- }
- *pairR = sv[0];
- *pairW = sv[1];
- return MOSQ_ERR_SUCCESS;
- #endif
- }
- #endif
- #ifndef WITH_BROKER
- void *mosquitto_ssl_get(struct mosquitto *mosq)
- {
- #ifdef WITH_TLS
- return mosq->ssl;
- #else
- UNUSED(mosq);
- return NULL;
- #endif
- }
- #endif
|