From 410c70135a648c963f2c2fb83a9c5348faaacf06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Ondr=C3=A1=C4=8Dek?= Date: Thu, 27 Sep 2018 21:32:55 +0200 Subject: [PATCH 01/58] Replace deprecated functions for establishment TLS/SSL connections with function TLS_client_method in OpenSSL 1.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roman Ondráček --- src/SSLSocket.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/SSLSocket.c b/src/SSLSocket.c index 5b5c20edf..c1829b290 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -521,6 +521,9 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) FUNC_ENTRY; if (net->ctx == NULL) { +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + net->ctx = SSL_CTX_new(TLS_client_method()); +#else int sslVersion = MQTT_SSL_VERSION_DEFAULT; if (opts->struct_version >= 1) sslVersion = opts->sslVersion; /* SSL_OP_NO_TLSv1_1 is defined in ssl.h if the library version supports TLSv1.1. @@ -550,6 +553,7 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) default: break; } +#endif if (net->ctx == NULL) { if (opts->struct_version >= 3) From 919aeb7cc7058c36efa587f52ff8dd758da5283a Mon Sep 17 00:00:00 2001 From: Keith Holman Date: Thu, 4 Oct 2018 15:53:34 -0400 Subject: [PATCH 02/58] websocket: fix loop to handle pings A small fix to allow the websocket interface respond to websocket pings. Signed-off-by: Keith Holman --- src/WebSocket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WebSocket.c b/src/WebSocket.c index 47b1dad26..ce3d016f7 100644 --- a/src/WebSocket.c +++ b/src/WebSocket.c @@ -853,7 +853,7 @@ int WebSocket_receiveFrame(networkHandles *net, WebSocket_getRawSocketData(net, 0u, &len); } - if ( opcode == WebSocket_OP_PONG || opcode == WebSocket_OP_PONG ) + if ( opcode == WebSocket_OP_PING || opcode == WebSocket_OP_PONG ) { /* respond to a "ping" with a "pong" */ if ( opcode == WebSocket_OP_PING ) From 27b66d1b2fc3e9b449185d21252207e0c3051507 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 15 Oct 2018 14:14:20 +0100 Subject: [PATCH 03/58] Add un/suback packet consistency checks #563 --- src/MQTTPacketOut.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/MQTTPacketOut.c b/src/MQTTPacketOut.c index b17c0be56..ef9e275a2 100644 --- a/src/MQTTPacketOut.c +++ b/src/MQTTPacketOut.c @@ -277,11 +277,13 @@ int MQTTPacket_send_subscribe(List* topics, List* qoss, MQTTSubscribe_options* o */ void* MQTTPacket_suback(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen) { - Suback* pack = malloc(sizeof(Suback)); + Suback* pack = NULL; char* curdata = data; char* enddata = &data[datalen]; FUNC_ENTRY; + if ((pack = malloc(sizeof(Suback))) == NULL) + goto exit; pack->MQTTVersion = MQTTVersion; pack->header.byte = aHeader; pack->msgId = readInt(&curdata); @@ -291,9 +293,12 @@ void* MQTTPacket_suback(int MQTTVersion, unsigned char aHeader, char* data, size pack->properties = props; if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1) { - free(pack->properties.array); - free(pack); + if (pack->properties.array) + free(pack->properties.array); + if (pack) + free(pack); pack = NULL; /* signal protocol error */ + goto exit; } } pack->qoss = ListInitialize(); @@ -304,6 +309,16 @@ void* MQTTPacket_suback(int MQTTVersion, unsigned char aHeader, char* data, size *newint = (unsigned int)readChar(&curdata); ListAppend(pack->qoss, newint, sizeof(unsigned int)); } + if (pack->qoss->count == 0) + { + if (pack->properties.array) + free(pack->properties.array); + if (pack) + free(pack); + ListFree(pack->qoss); + pack = NULL; + } +exit: FUNC_EXIT; return pack; } @@ -366,11 +381,13 @@ int MQTTPacket_send_unsubscribe(List* topics, MQTTProperties* props, int msgid, */ void* MQTTPacket_unsuback(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen) { - Unsuback* pack = malloc(sizeof(Unsuback)); + Unsuback* pack = NULL; char* curdata = data; char* enddata = &data[datalen]; FUNC_ENTRY; + if ((pack = malloc(sizeof(Unsuback))) == NULL) + goto exit; pack->MQTTVersion = MQTTVersion; pack->header.byte = aHeader; pack->msgId = readInt(&curdata); @@ -381,9 +398,12 @@ void* MQTTPacket_unsuback(int MQTTVersion, unsigned char aHeader, char* data, si pack->properties = props; if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1) { - free(pack->properties.array); - free(pack); + if (pack->properties.array) + free(pack->properties.array); + if (pack) + free(pack); pack = NULL; /* signal protocol error */ + goto exit; } pack->reasonCodes = ListInitialize(); while ((size_t)(curdata - data) < datalen) @@ -393,7 +413,17 @@ void* MQTTPacket_unsuback(int MQTTVersion, unsigned char aHeader, char* data, si *newrc = (enum MQTTReasonCodes)readChar(&curdata); ListAppend(pack->reasonCodes, newrc, sizeof(enum MQTTReasonCodes)); } + if (pack->reasonCodes->count == 0) + { + ListFree(pack->reasonCodes); + if (pack->properties.array) + free(pack->properties.array); + if (pack) + free(pack); + pack = NULL; + } } +exit: FUNC_EXIT; return pack; } From ac9c99a981a27c91eeb105d5aec2b7e8ee86a531 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 24 Oct 2018 18:12:44 +0200 Subject: [PATCH 04/58] Fix for issue #570 --- src/Clients.h | 1 + src/MQTTProtocolClient.c | 43 +++++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Clients.h b/src/Clients.h index fd32e3b97..d5b2a4b9c 100644 --- a/src/Clients.h +++ b/src/Clients.h @@ -79,6 +79,7 @@ typedef struct int socket; time_t lastSent; time_t lastReceived; + time_t lastPing; #if defined(OPENSSL) SSL* ssl; SSL_CTX* ctx; diff --git a/src/MQTTProtocolClient.c b/src/MQTTProtocolClient.c index 4217af0f0..1dc04f137 100644 --- a/src/MQTTProtocolClient.c +++ b/src/MQTTProtocolClient.c @@ -611,32 +611,35 @@ void MQTTProtocol_keepalive(time_t now) { Clients* client = (Clients*)(current->content); ListNextElement(bstate->clients, ¤t); - if (client->connected && client->keepAliveInterval > 0 && - (difftime(now, client->net.lastSent) >= client->keepAliveInterval || - difftime(now, client->net.lastReceived) >= client->keepAliveInterval)) + + if (client->connected == 0 || client->keepAliveInterval == 0) + continue; + + if (client->ping_outstanding == 1) { - if (client->ping_outstanding == 0) - { - if (Socket_noPendingWrites(client->net.socket)) - { - if (MQTTPacket_send_pingreq(&client->net, client->clientID) != TCPSOCKET_COMPLETE) - { - Log(TRACE_PROTOCOL, -1, "Error sending PINGREQ for client %s on socket %d, disconnecting", client->clientID, client->net.socket); - MQTTProtocol_closeSession(client, 1); - } - else - { - client->net.lastSent = now; - client->ping_outstanding = 1; - } - } - } - else + if (difftime(now, client->net.lastPing) >= client->keepAliveInterval) { Log(TRACE_PROTOCOL, -1, "PINGRESP not received in keepalive interval for client %s on socket %d, disconnecting", client->clientID, client->net.socket); MQTTProtocol_closeSession(client, 1); } } + else if (difftime(now, client->net.lastSent) >= client->keepAliveInterval || + difftime(now, client->net.lastReceived) >= client->keepAliveInterval) + { + if (Socket_noPendingWrites(client->net.socket)) + { + if (MQTTPacket_send_pingreq(&client->net, client->clientID) != TCPSOCKET_COMPLETE) + { + Log(TRACE_PROTOCOL, -1, "Error sending PINGREQ for client %s on socket %d, disconnecting", client->clientID, client->net.socket); + MQTTProtocol_closeSession(client, 1); + } + else + { + client->net.lastPing = now; + client->ping_outstanding = 1; + } + } + } } FUNC_EXIT; } From 0f06c3f9b163a8873f79713274d8b6770810dfef Mon Sep 17 00:00:00 2001 From: Johan Anderholm Date: Wed, 24 Oct 2018 11:13:35 +0200 Subject: [PATCH 05/58] Add OpenSSL psk handler callback function and context * Add new members to SSL option structs MQTTClient_SSLOptions / MQTTAsync_SSLOptions to set an application-specific TLS-PSK handler callback function and context * Add support for disabling loading of default trust store * Increment the struct version Close #146 Signed-off-by: Johan Anderholm --- src/MQTTAsync.c | 8 +++++++- src/MQTTAsync.h | 23 ++++++++++++++++++++++- src/MQTTClient.c | 8 +++++++- src/MQTTClient.h | 22 +++++++++++++++++++++- src/SSLSocket.c | 47 +++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 98 insertions(+), 10 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index a5813b45c..40ac31b5e 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -2771,7 +2771,7 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) } if (options->struct_version != 0 && options->ssl) /* check validity of SSL options structure */ { - if (strncmp(options->ssl->struct_id, "MQTS", 4) != 0 || options->ssl->struct_version < 0 || options->ssl->struct_version > 3) + if (strncmp(options->ssl->struct_id, "MQTS", 4) != 0 || options->ssl->struct_version < 0 || options->ssl->struct_version > 4) { rc = MQTTASYNC_BAD_STRUCTURE; goto exit; @@ -2938,6 +2938,12 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) m->c->sslopts->ssl_error_cb = options->ssl->ssl_error_cb; m->c->sslopts->ssl_error_context = options->ssl->ssl_error_context; } + if (m->c->sslopts->struct_version >= 4) + { + m->c->sslopts->ssl_psk_cb = options->ssl->ssl_psk_cb; + m->c->sslopts->ssl_psk_context = options->ssl->ssl_psk_context; + m->c->sslopts->disableDefaultTrustStore = options->ssl->disableDefaultTrustStore; + } } #else if (options->struct_version != 0 && options->ssl) diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 1b3593d25..85eeb32fd 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -968,9 +968,30 @@ typedef struct * Exists only if struct_version >= 3 */ void* ssl_error_context; + + /** + * Callback function for setting TLS-PSK options. Parameters correspond to that of + * SSL_CTX_set_psk_client_callback, except for u which is the pointer ssl_psk_context. + * Exists only if struct_version >= 4 + */ + unsigned int (*ssl_psk_cb) (const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len, void *u); + + /** + * Application-specific contex for ssl_psk_cb + * Exists only if struct_version >= 4 + */ + void* ssl_psk_context; + + /** + * Don't load default SSL CA. Should be used together with PSK to make sure + * regular servers with certificate in place is not accepted. + * Exists only if struct_version >= 4 + */ + int disableDefaultTrustStore; + } MQTTAsync_SSLOptions; -#define MQTTAsync_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 3, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL } +#define MQTTAsync_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 4, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL, NULL, NULL, 0} /** * MQTTAsync_connectOptions defines several settings that control the way the diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 2069ff96d..33012c547 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -1449,6 +1449,12 @@ static MQTTResponse MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectO m->c->sslopts->ssl_error_cb = options->ssl->ssl_error_cb; m->c->sslopts->ssl_error_context = options->ssl->ssl_error_context; } + if (m->c->sslopts->struct_version >= 4) + { + m->c->sslopts->ssl_psk_cb = options->ssl->ssl_psk_cb; + m->c->sslopts->ssl_psk_context = options->ssl->ssl_psk_context; + m->c->sslopts->disableDefaultTrustStore = options->ssl->disableDefaultTrustStore; + } } #endif @@ -1569,7 +1575,7 @@ MQTTResponse MQTTClient_connectAll(MQTTClient handle, MQTTClient_connectOptions* #if defined(OPENSSL) if (options->struct_version != 0 && options->ssl) /* check validity of SSL options structure */ { - if (strncmp(options->ssl->struct_id, "MQTS", 4) != 0 || options->ssl->struct_version < 0 || options->ssl->struct_version > 3) + if (strncmp(options->ssl->struct_id, "MQTS", 4) != 0 || options->ssl->struct_version < 0 || options->ssl->struct_version > 4) { rc.reasonCode = MQTTCLIENT_BAD_STRUCTURE; goto exit; diff --git a/src/MQTTClient.h b/src/MQTTClient.h index b3fadbe7f..0bbc93ae7 100644 --- a/src/MQTTClient.h +++ b/src/MQTTClient.h @@ -714,9 +714,29 @@ typedef struct */ void* ssl_error_context; + /** + * Callback function for setting TLS-PSK options. Parameters correspond to that of + * SSL_CTX_set_psk_client_callback, except for u which is the pointer ssl_psk_context. + * Exists only if struct_version >= 4 + */ + unsigned int (*ssl_psk_cb) (const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len, void *u); + + /** + * Application-specific contex for ssl_psk_cb + * Exists only if struct_version >= 4 + */ + void* ssl_psk_context; + + /** + * Don't load default SSL CA. Should be used together with PSK to make sure + * regular servers with certificate in place is not accepted. + * Exists only if struct_version >= 4 + */ + int disableDefaultTrustStore; + } MQTTClient_SSLOptions; -#define MQTTClient_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 3, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL } +#define MQTTClient_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 4, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL, NULL, NULL, 0 } /** * MQTTClient_connectOptions defines several settings that control the way the diff --git a/src/SSLSocket.c b/src/SSLSocket.c index 5b5c20edf..be002bef0 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -76,6 +76,9 @@ static int handle_openssl_init = 1; static ssl_mutex_type* sslLocks = NULL; static ssl_mutex_type sslCoreMutex; +/* Used to store MQTTClient_SSLOptions for TLS-PSK callback */ +static int tls_ex_index_ssl_opts; + #if defined(WIN32) || defined(WIN64) #define iov_len len #define iov_base buf @@ -483,6 +486,8 @@ int SSLSocket_initialize(void) SSL_create_mutex(&sslCoreMutex); + tls_ex_index_ssl_opts = SSL_get_ex_new_index(0, "paho ssl options", NULL, NULL, NULL); + exit: FUNC_EXIT_RC(rc); return rc; @@ -514,6 +519,25 @@ void SSLSocket_terminate(void) FUNC_EXIT; } +static unsigned int call_ssl_psk_cb(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) +{ + int rc = 0; + + FUNC_ENTRY; + + SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); + MQTTClient_SSLOptions* opts = SSL_CTX_get_ex_data(ctx, tls_ex_index_ssl_opts); + + if (opts == NULL) + goto exit; + + if (opts->ssl_psk_cb != NULL) + rc = opts->ssl_psk_cb(hint, identity, max_identity_len, psk, max_psk_len, opts->ssl_psk_context); +exit: + FUNC_EXIT_RC(rc); + return rc; +} + int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) { int rc = 1; @@ -605,13 +629,16 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) goto free_ctx; } } - else if ((rc = SSL_CTX_set_default_verify_paths(net->ctx)) != 1) + else if (!opts->disableDefaultTrustStore) { - if (opts->struct_version >= 3) - SSLSocket_error("SSL_CTX_set_default_verify_paths", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); - else - SSLSocket_error("SSL_CTX_set_default_verify_paths", NULL, net->socket, rc, NULL, NULL); - goto free_ctx; + if ((rc = SSL_CTX_set_default_verify_paths(net->ctx)) != 1) + { + if (opts->struct_version >= 3) + SSLSocket_error("SSL_CTX_set_default_verify_paths", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); + else + SSLSocket_error("SSL_CTX_set_default_verify_paths", NULL, net->socket, rc, NULL, NULL); + goto free_ctx; + } } if (opts->enabledCipherSuites) @@ -626,6 +653,14 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) } } +#ifndef OPENSSL_NO_PSK + if (opts->ssl_psk_cb != NULL) + { + SSL_CTX_set_ex_data(net->ctx, tls_ex_index_ssl_opts, opts); + SSL_CTX_set_psk_client_callback(net->ctx, call_ssl_psk_cb); + } +#endif + SSL_CTX_set_mode(net->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); goto exit; From 76f6efddf37e9c74a58d1d04facf2943dcd68bfa Mon Sep 17 00:00:00 2001 From: Johan Anderholm Date: Tue, 30 Oct 2018 09:05:17 +0100 Subject: [PATCH 06/58] Update sample to utilize psk callback function Signed-off-by: Johan Anderholm --- src/samples/paho_c_pub.c | 52 ++++++++++++++++++++++++++++++++++++++- src/samples/paho_c_sub.c | 2 +- src/samples/paho_cs_pub.c | 2 +- src/samples/paho_cs_sub.c | 2 +- src/samples/pubsub_opts.c | 16 ++++++++++++ src/samples/pubsub_opts.h | 2 ++ 6 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/samples/paho_c_pub.c b/src/samples/paho_c_pub.c index 5d92b1735..8fd034229 100644 --- a/src/samples/paho_c_pub.c +++ b/src/samples/paho_c_pub.c @@ -45,7 +45,7 @@ struct pubsub_opts opts = NULL, NULL, 1, 0, 0, /* message options */ MQTTVERSION_DEFAULT, NULL, "paho-c-pub", 0, 0, NULL, NULL, "localhost", "1883", NULL, 10, /* MQTT options */ NULL, NULL, 0, 0, /* will options */ - 0, NULL, NULL, NULL, NULL, NULL, NULL, /* TLS options */ + 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* TLS options */ 0, {NULL, NULL}, /* MQTT V5 options */ }; @@ -222,6 +222,54 @@ static int onSSLError(const char *str, size_t len, void *context) return fprintf(stderr, "SSL error: %s\n", str); } +static unsigned int onPSKAuth(const char* hint, + char* identity, + unsigned int max_identity_len, + unsigned char* psk, + unsigned int max_psk_len, + void* context) +{ + int psk_len; + int k, n; + + int rc = 0; + struct pubsub_opts* opts = context; + + printf("Trying TLS-PSK auth with hint: %s\n", hint); + + if (opts->psk == NULL || opts->psk_identity == NULL) + { + printf("No PSK entered\n"); + goto exit; + } + + /* psk should be array of bytes. This is a quick and dirty way to + * convert hex to bytes without input validation */ + psk_len = strlen(opts->psk) / 2; + if (psk_len > max_psk_len) + { + printf("PSK too long\n"); + goto exit; + } + for (k=0, n=0; k < psk_len; k++, n += 2) + { + sscanf(&opts->psk[n], "%2hhx", &psk[k]); + } + + /* identity should be NULL terminated string */ + strncpy(identity, opts->psk_identity, max_identity_len); + if (identity[max_identity_len - 1] != '\0') + { + printf("Identity too long\n"); + goto exit; + } + + /* Function should return length of psk on success. */ + rc = psk_len; + +exit: + return rc; +} void myconnect(MQTTAsync client) { @@ -275,6 +323,8 @@ void myconnect(MQTTAsync client) ssl_opts.enabledCipherSuites = opts.ciphers; ssl_opts.ssl_error_cb = onSSLError; ssl_opts.ssl_error_context = client; + ssl_opts.ssl_psk_cb = onPSKAuth; + ssl_opts.ssl_psk_context = &opts; conn_opts.ssl = &ssl_opts; } diff --git a/src/samples/paho_c_sub.c b/src/samples/paho_c_sub.c index 7fa82dc72..62281600c 100644 --- a/src/samples/paho_c_sub.c +++ b/src/samples/paho_c_sub.c @@ -66,7 +66,7 @@ struct pubsub_opts opts = NULL, NULL, 1, 0, 0, /* message options */ MQTTVERSION_DEFAULT, NULL, "paho-c-sub", 0, 0, NULL, NULL, "localhost", "1883", NULL, 10, /* MQTT options */ NULL, NULL, 0, 0, /* will options */ - 0, NULL, NULL, NULL, NULL, NULL, NULL, /* TLS options */ + 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* TLS options */ 0, {NULL, NULL}, /* MQTT V5 options */ }; diff --git a/src/samples/paho_cs_pub.c b/src/samples/paho_cs_pub.c index e5d627a03..a89dc372c 100644 --- a/src/samples/paho_cs_pub.c +++ b/src/samples/paho_cs_pub.c @@ -46,7 +46,7 @@ struct pubsub_opts opts = NULL, NULL, 1, 0, 0, /* message options */ MQTTVERSION_DEFAULT, NULL, "paho-cs-pub", 0, 0, NULL, NULL, "localhost", "1883", NULL, 10, /* MQTT options */ NULL, NULL, 0, 0, /* will options */ - 0, NULL, NULL, NULL, NULL, NULL, NULL, /* TLS options */ + 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* TLS options */ 0, {NULL, NULL}, /* MQTT V5 options */ }; diff --git a/src/samples/paho_cs_sub.c b/src/samples/paho_cs_sub.c index dbe1bf00c..b5eaf6242 100644 --- a/src/samples/paho_cs_sub.c +++ b/src/samples/paho_cs_sub.c @@ -43,7 +43,7 @@ struct pubsub_opts opts = NULL, NULL, 1, 0, 0, /* message options */ MQTTVERSION_DEFAULT, NULL, "paho-cs-sub", 0, 0, NULL, NULL, "localhost", "1883", NULL, 10, /* MQTT options */ NULL, NULL, 0, 0, /* will options */ - 0, NULL, NULL, NULL, NULL, NULL, NULL, /* TLS options */ + 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* TLS options */ 0, {NULL, NULL}, /* MQTT V5 options */ }; diff --git a/src/samples/pubsub_opts.c b/src/samples/pubsub_opts.c index c94cc1674..b6ef7ad3b 100644 --- a/src/samples/pubsub_opts.c +++ b/src/samples/pubsub_opts.c @@ -115,6 +115,8 @@ void usage(struct pubsub_opts* opts, pubsub_opts_nameValue* name_values, const c " --ciphers : the list of cipher suites that the client will present to the server during\n" " the TLS handshake.\n" " --insecure : don't check that the server certificate common name matches the hostname.\n" + " --psk : pre-shared-key in hexadecimal (no leading 0x) \n" + " --psk-identity : client identity string for TLS-PSK mode.\n" ); printf("\nSee http://eclipse.org/paho for more information about the Eclipse Paho project.\n"); @@ -299,6 +301,20 @@ int getopts(int argc, char** argv, struct pubsub_opts* opts) else return 1; } + else if (strcmp(argv[count], "--psk") == 0) + { + if (++count < argc) + opts->psk = argv[count]; + else + return 1; + } + else if (strcmp(argv[count], "--psk-identity") == 0) + { + if (++count < argc) + opts->psk_identity = argv[count]; + else + return 1; + } else if (strcmp(argv[count], "-V") == 0) { if (++count < argc) diff --git a/src/samples/pubsub_opts.h b/src/samples/pubsub_opts.h index a506a68ae..462bf040c 100644 --- a/src/samples/pubsub_opts.h +++ b/src/samples/pubsub_opts.h @@ -61,6 +61,8 @@ struct pubsub_opts char* key; char* keypass; char* ciphers; + char* psk_identity; + char* psk; /* MQTT V5 options */ int message_expiry; struct { From 19aa5bbbe6cba7c3fa6d89afa0e6b3ab162e6729 Mon Sep 17 00:00:00 2001 From: Johan Anderholm Date: Wed, 31 Oct 2018 08:13:44 +0100 Subject: [PATCH 07/58] Added tests for TLS-PSK Signed-off-by: Johan Anderholm --- test/CMakeLists.txt | 12 ++++ test/test3.c | 84 +++++++++++++++++++++++- test/test5.c | 111 +++++++++++++++++++++++++++++++- test/tls-testing/mosquitto.conf | 5 ++ test/tls-testing/mosquitto.psk | 1 + 5 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 test/tls-testing/mosquitto.psk diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 06bf46ffc..1ac0a5711 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -265,6 +265,11 @@ ADD_TEST( COMMAND test3 "--test_no" "10" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" ) +ADD_TEST( + NAME test3-6-psk-ssl-auth + COMMAND test3 "--test_no" "11" "--hostname" ${MQTT_SSL_HOSTNAME} +) + SET_TESTS_PROPERTIES( test3-1-ssl-conn-to-non-SSL-broker test3-2as-mutual-ssl-auth-single-thread @@ -276,6 +281,7 @@ SET_TESTS_PROPERTIES( test3-3b-broker-auth-client-missing-broker-cert test3-4s-broker-auth-accept-invalid-certificate-single-thread test3-4m-broker-auth-accept-invalid-certificate-multi-thread + test3-6-psk-ssl-auth PROPERTIES TIMEOUT 540 ) @@ -456,6 +462,11 @@ ADD_TEST( COMMAND test5 "--test_no" "8" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" ) +ADD_TEST( + NAME test5-8-psk-ssl-auth + COMMAND test5 "--test_no" "11" "--hostname" ${MQTT_SSL_HOSTNAME} +) + SET_TESTS_PROPERTIES( test5-1-ssl-connection-to-no-SSL-server test5-2a-multual-ssl-auth-certificates-in-place @@ -465,6 +476,7 @@ SET_TESTS_PROPERTIES( test5-3a-server-auth-server-cert-in-client-store test5-3b-server-auth-client-missing-broker-cert test5-4-accept-invalid-certificates + test5-8-psk-ssl-auth PROPERTIES TIMEOUT 540 ) diff --git a/test/test3.c b/test/test3.c index 9194094f0..1429aa360 100644 --- a/test/test3.c +++ b/test/test3.c @@ -76,6 +76,7 @@ struct Options char nocert_mutual_auth_connection[100]; char server_auth_connection[100]; char anon_connection[100]; + char psk_connection[100]; char** haconnections; /**< connection to system under test. */ int hacount; char* client_key_file; @@ -92,6 +93,7 @@ struct Options "ssl://m2m.eclipse.org:18887", "ssl://m2m.eclipse.org:18885", "ssl://m2m.eclipse.org:18886", + "ssl://m2m.eclipse.org:18888", NULL, 0, "../../../test/ssl/client.pem", @@ -169,6 +171,8 @@ void getopts(int argc, char** argv) printf("Setting server_auth_connection to %s\n", options.server_auth_connection); sprintf(options.anon_connection, "%s://%s:18886", prefix, argv[count]); printf("Setting anon_connection to %s\n", options.anon_connection); + sprintf(options.psk_connection, "%s://%s:18888", prefix, argv[count]); + printf("Setting psk_connection to %s\n", options.psk_connection); } else usage(); @@ -1480,6 +1484,84 @@ int test5c(struct Options options) return failures; } + +/********************************************************************* + +Test6: TLS-PSK - client and server has a common pre-shared key + +*********************************************************************/ +static unsigned int onPSKAuth(const char* hint, + char* identity, + unsigned int max_identity_len, + unsigned char* psk, + unsigned int max_psk_len, + void* context) +{ + unsigned char test_psk[] = {0x50, 0x53, 0x4B, 0x00}; /* {'P', 'S', 'K', '\0' } */ + MyLog(LOGA_DEBUG, "PSK auth callback"); + + if (!(assert("Good application context in onPSKAuth", context == (void *) 42, "context was %d\n", context))) + return 0; + + strncpy(identity, "id", max_identity_len); + memcpy(psk, test_psk, sizeof(test_psk)); + return sizeof(test_psk); +} + + +int test6(struct Options options) +{ + char* testname = "test6"; + MQTTClient c; + MQTTClient_connectOptions opts = MQTTClient_connectOptions_initializer; + MQTTClient_willOptions wopts = MQTTClient_willOptions_initializer; + MQTTClient_SSLOptions sslopts = MQTTClient_SSLOptions_initializer; + int rc = 0; + + failures = 0; + MyLog(LOGA_INFO, "Starting test 6 - TLS-PSK - client and server has a common pre-shared key"); + fprintf(xml, "ssl_psk_cb = onPSKAuth; + opts.ssl->ssl_psk_context = (void *) 42; + opts.ssl->enabledCipherSuites = "PSK-AES128-CBC-SHA"; + + MyLog(LOGA_DEBUG, "Connecting"); + + rc = MQTTClient_connect(c, &opts); + if (!(assert("Good rc from connect", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc))) + goto exit; + + MyLog(LOGA_DEBUG, "Stopping\n"); + + rc = MQTTClient_disconnect(c, 0); + if (!(assert("Disconnect successful", rc == MQTTCLIENT_SUCCESS, "rc was %d\n", rc))) + goto exit; +exit: + MQTTClient_destroy(&c); + MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", testname, tests, failures); + write_test_result(); + return failures; +} + + typedef struct { char* clientID; /**< the string id of the client */ @@ -1527,7 +1609,7 @@ int main(int argc, char** argv) { int* numtests = &tests; int rc = 0; - int (*tests[])() = {NULL, test1, test2a_s, test2a_m, test2b, test2c, test3a_s, test3a_m, test3b, test4_s, test4_m, /*test5a, test5b,test5c */}; + int (*tests[])() = {NULL, test1, test2a_s, test2a_m, test2b, test2c, test3a_s, test3a_m, test3b, test4_s, test4_m, test6, /*test5a, test5b,test5c */}; //MQTTClient_nameValue* info; xml = fopen("TEST-test3.xml", "w"); diff --git a/test/test5.c b/test/test5.c index 8868a6105..ebc9dc785 100644 --- a/test/test5.c +++ b/test/test5.c @@ -59,6 +59,7 @@ struct Options char nocert_mutual_auth_connection[100]; char server_auth_connection[100]; char anon_connection[100]; + char psk_connection[100]; char* client_key_file; char* client_key_pass; char* server_key_file; @@ -74,6 +75,7 @@ struct Options "ssl://m2m.eclipse.org:18887", "ssl://m2m.eclipse.org:18885", "ssl://m2m.eclipse.org:18886", + "ssl://m2m.eclipse.org:18888", "../../../test/ssl/client.pem", NULL, "../../../test/ssl/test-root-ca.crt", @@ -158,6 +160,8 @@ void getopts(int argc, char** argv) printf("Setting server_auth_connection to %s\n", options.server_auth_connection); sprintf(options.anon_connection, "%s://%s:18886", prefix, argv[count]); printf("Setting anon_connection to %s\n", options.anon_connection); + sprintf(options.psk_connection, "%s://%s:18888", prefix, argv[count]); + printf("Setting psk_connection to %s\n", options.psk_connection); } else usage(); @@ -2146,6 +2150,111 @@ int test7(struct Options options) return failures; } +/********************************************************************* + +Test8: TLS-PSK - client and server has a common pre-shared key + +*********************************************************************/ + +static unsigned int onPSKAuth(const char* hint, + char* identity, + unsigned int max_identity_len, + unsigned char* psk, + unsigned int max_psk_len, + void* context) +{ + unsigned char test_psk[] = {0x50, 0x53, 0x4B, 0x00}; /* {'P', 'S', 'K', '\0' } */ + MyLog(LOGA_DEBUG, "PSK auth callback"); + + assert("Good application context in onPSKAuth", context == (void *) 42, "context was %d\n", context); + + strncpy(identity, "id", max_identity_len); + memcpy(psk, test_psk, sizeof(test_psk)); + return sizeof(test_psk); +} + + +int test8(struct Options options) +{ + char* testname = "test8"; + + AsyncTestClient tc = + AsyncTestClient_initializer; + MQTTAsync c; + MQTTAsync_connectOptions opts = MQTTAsync_connectOptions_initializer; + MQTTAsync_willOptions wopts = MQTTAsync_willOptions_initializer; + MQTTAsync_SSLOptions sslopts = MQTTAsync_SSLOptions_initializer; + int rc = 0; + + failures = 0; + MyLog(LOGA_INFO, "Starting test 8 - TLS-PSK - client and server has a common pre-shared key"); + fprintf(xml, "ssl_psk_cb = onPSKAuth; + opts.ssl->ssl_psk_context = (void *) 42; + opts.ssl->enabledCipherSuites = "PSK-AES128-CBC-SHA"; + + rc = MQTTAsync_setCallbacks(c, &tc, NULL, asyncTestMessageArrived, + asyncTestOnDeliveryComplete); + assert("Good rc from setCallbacks", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + + MyLog(LOGA_DEBUG, "Connecting"); + rc = MQTTAsync_connect(c, &opts); + assert("Good rc from connect", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + if (rc != MQTTASYNC_SUCCESS) + goto exit; + + while (!tc.subscribed && !tc.testFinished) +#if defined(WIN32) + Sleep(100); +#else + usleep(10000L); +#endif + + if (tc.testFinished) + goto exit; + + while (!tc.testFinished) +#if defined(WIN32) + Sleep(100); +#else + usleep(10000L); +#endif + + MyLog(LOGA_DEBUG, "Stopping"); + +exit: + MQTTAsync_destroy(&c); + MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", testname, tests, failures); + write_test_result(); + return failures; +} + + void handleTrace(enum MQTTASYNC_TRACE_LEVELS level, char* message) { printf("%s\n", message); @@ -2157,7 +2266,7 @@ int main(int argc, char** argv) int rc = 0; int (*tests[])() = { NULL, test1, test2a, test2b, test2c, test2d, test3a, test3b, test4, /* test5a, - test5b, test5c, */ test6, test7 }; + test5b, test5c, */ test6, test7, test8 }; xml = fopen("TEST-test5.xml", "w"); fprintf(xml, "\n", (int)ARRAY_SIZE(tests) - 1); diff --git a/test/tls-testing/mosquitto.conf b/test/tls-testing/mosquitto.conf index 32744b118..9f9bdbd1b 100644 --- a/test/tls-testing/mosquitto.conf +++ b/test/tls-testing/mosquitto.conf @@ -50,3 +50,8 @@ keyfile test/tls-testing/keys/server/server-mitm.key require_certificate true #tls_version tlsv1 +# TLS-PSK authentication +listener 18888 +ciphers PSK-AES128-CBC-SHA +psk_hint Test +psk_file test/tls-testing/mosquitto.psk diff --git a/test/tls-testing/mosquitto.psk b/test/tls-testing/mosquitto.psk new file mode 100644 index 000000000..5767d17cf --- /dev/null +++ b/test/tls-testing/mosquitto.psk @@ -0,0 +1 @@ +id:50534B00 From bd69d9a909912228ee14326771086c6093a46d3c Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 28 Nov 2018 18:11:38 +0000 Subject: [PATCH 08/58] Delete some files --- cmake/modules/CMakeDebHelper.cmake | 3 --- cmake/modules/CMakeDebHelperInstall.cmake | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 cmake/modules/CMakeDebHelper.cmake delete mode 100644 cmake/modules/CMakeDebHelperInstall.cmake diff --git a/cmake/modules/CMakeDebHelper.cmake b/cmake/modules/CMakeDebHelper.cmake deleted file mode 100644 index f01072e51..000000000 --- a/cmake/modules/CMakeDebHelper.cmake +++ /dev/null @@ -1,3 +0,0 @@ -#============================================================================= -# Removed content due to licensing/copyright issues -#============================================================================= diff --git a/cmake/modules/CMakeDebHelperInstall.cmake b/cmake/modules/CMakeDebHelperInstall.cmake deleted file mode 100644 index f01072e51..000000000 --- a/cmake/modules/CMakeDebHelperInstall.cmake +++ /dev/null @@ -1,3 +0,0 @@ -#============================================================================= -# Removed content due to licensing/copyright issues -#============================================================================= From 9393170f1c9fef8bb9533674a6e0ea5be2494846 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 4 Dec 2018 09:53:43 +0000 Subject: [PATCH 09/58] Update doc for BAD_PROTOCOL return code #587 --- src/MQTTAsync.h | 8 +++++--- src/MQTTClient.h | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 1b3593d25..cb32344e8 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -175,9 +175,11 @@ * Return code: Attempting SSL connection using non-SSL version of library */ #define MQTTASYNC_SSL_NOT_SUPPORTED -13 -/** - * Return code: protocol prefix in serverURI should be tcp:// or ssl:// - */ + /** + * Return code: protocol prefix in serverURI should be tcp://, ssl://, ws:// or wss:// + * The TLS enabled prefixes (ssl, wss) are only valid if the TLS version of the library + * is linked with. + */ #define MQTTASYNC_BAD_PROTOCOL -14 /** * Return code: don't use options for another version of MQTT diff --git a/src/MQTTClient.h b/src/MQTTClient.h index b3fadbe7f..9a8affe1f 100644 --- a/src/MQTTClient.h +++ b/src/MQTTClient.h @@ -184,7 +184,9 @@ */ #define MQTTCLIENT_BAD_MQTT_VERSION -11 /** - * Return code: protocol prefix in serverURI should be tcp:// or ssl:// + * Return code: protocol prefix in serverURI should be tcp://, ssl://, ws:// or wss:// + * The TLS enabled prefixes (ssl, wss) are only valid if the TLS version of the library + * is linked with. */ #define MQTTCLIENT_BAD_PROTOCOL -14 /** From 73746c0d717753c158eac79b59d367c6d72ae0e0 Mon Sep 17 00:00:00 2001 From: Samuel COLLON Date: Tue, 4 Dec 2018 15:33:35 -0500 Subject: [PATCH 10/58] Update PERSISTENCE_V5_COMMAND_KEY value update value from c- to c5- to differentiate it from PERSISTENCE_COMMAND_KEY Signed-off-by: Samuel COLLON --- src/MQTTPersistence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MQTTPersistence.h b/src/MQTTPersistence.h index 93edb2b9a..67d1e6640 100644 --- a/src/MQTTPersistence.h +++ b/src/MQTTPersistence.h @@ -44,7 +44,7 @@ /** Stem of the key for an async client command */ #define PERSISTENCE_COMMAND_KEY "c-" /** Stem of the key for an MQTT V5 async client command */ -#define PERSISTENCE_V5_COMMAND_KEY "c-" +#define PERSISTENCE_V5_COMMAND_KEY "c5-" /** Stem of the key for an async client message queue */ #define PERSISTENCE_QUEUE_KEY "q-" /** Stem of the key for an MQTT V5 message queue */ From 0a2e5964d4e959feed129a1fc662101bb26ca4e6 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 24 Dec 2018 12:04:45 +0000 Subject: [PATCH 11/58] Fix for issue #596 --- src/MQTTAsync.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index a5813b45c..2584df462 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -3657,7 +3657,6 @@ static int MQTTAsync_connecting(MQTTAsyncs* m) static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) { struct timeval tp = {0L, 0L}; - static Ack ack; MQTTPacket* pack = NULL; FUNC_ENTRY; @@ -3712,29 +3711,36 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) else if (pack->header.bits.type == PUBACK || pack->header.bits.type == PUBCOMP || pack->header.bits.type == PUBREC) { - int msgid; + int msgid = 0, + msgtype = 0, + ackrc = 0, + mqttversion = 0; + MQTTProperties msgprops = MQTTProperties_initializer; - ack = *(Ack*)pack; - msgid = ack.msgId; + /* This block is so that the ack variable is local and isn't accidentally reused */ + { + static Ack ack; + ack = *(Ack*)pack; + /* these values are stored because the packet structure is freed in the handle functions */ + msgid = ack.msgId; + msgtype = pack->header.bits.type; + if (ack.MQTTVersion >= MQTTVERSION_5) + { + ackrc = ack.rc; + msgprops = MQTTProperties_copy(&ack.properties); + mqttversion = ack.MQTTVersion; + } + } if (pack->header.bits.type == PUBCOMP) - { - //ack = *(Pubcomp*)pack; *rc = MQTTProtocol_handlePubcomps(pack, *sock); - } else if (pack->header.bits.type == PUBREC) - { - //ack = *(Pubrec*)pack; *rc = MQTTProtocol_handlePubrecs(pack, *sock); - } else if (pack->header.bits.type == PUBACK) - { - //ack = *(Puback*)pack; *rc = MQTTProtocol_handlePubacks(pack, *sock); - } if (!m) Log(LOG_ERROR, -1, "PUBCOMP, PUBACK or PUBREC received for no client, msgid %d", msgid); - if (m && (pack->header.bits.type != PUBREC || ack.rc >= MQTTREASONCODE_UNSPECIFIED_ERROR)) + if (m && (msgtype != PUBREC || ackrc >= MQTTREASONCODE_UNSPECIFIED_ERROR)) { ListElement* current = NULL; @@ -3764,7 +3770,7 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) Log(TRACE_MIN, -1, "Calling publish success for client %s", m->c->clientID); (*(command->command.onSuccess))(command->command.context, &data); } - else if (command->command.onSuccess5 && ack.rc < MQTTREASONCODE_UNSPECIFIED_ERROR) + else if (command->command.onSuccess5 && ackrc < MQTTREASONCODE_UNSPECIFIED_ERROR) { MQTTAsync_successData5 data = MQTTAsync_successData5_initializer; @@ -3778,18 +3784,20 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) Log(TRACE_MIN, -1, "Calling publish success for client %s", m->c->clientID); (*(command->command.onSuccess5))(command->command.context, &data); } - else if (command->command.onFailure5 && ack.rc >= MQTTREASONCODE_UNSPECIFIED_ERROR) + else if (command->command.onFailure5 && ackrc >= MQTTREASONCODE_UNSPECIFIED_ERROR) { MQTTAsync_failureData5 data = MQTTAsync_failureData5_initializer; data.token = command->command.token; - data.reasonCode = ack.rc; - data.properties = ack.properties; + data.reasonCode = ackrc; + data.properties = msgprops; data.packet_type = pack->header.bits.type; Log(TRACE_MIN, -1, "Calling publish failure for client %s", m->c->clientID); (*(command->command.onFailure5))(command->command.context, &data); } MQTTAsync_freeCommand(command); + if (mqttversion >= MQTTVERSION_5) + MQTTProperties_free(&msgprops); break; } } From 4405ad81ea5cb9f0d4250918f226fb2eb11b52b2 Mon Sep 17 00:00:00 2001 From: Maksym Ruchko Date: Mon, 7 Jan 2019 17:14:50 +0000 Subject: [PATCH 12/58] Fix MQTTClient_createOptions_initializer - add missing field The commit 7cc0e3fa385910a5e1f0bb176f128de51a05a5b9 introduced - MQTTClient_createWithOptions function - MQTTClient_createOptions structure - MQTTClient_createOptions_initializer The MQTTClient_createOptions struct has 3 fields, but only two were initialized in the MQTTClient_createOptions_initializer. It was just fortunate that MQTTVERSION_DEFAULT is defined as 0 and implicitly initialized MQTTVersion field has value of 0 too. Signed-off-by: Maksym Ruchko --- src/MQTTClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MQTTClient.h b/src/MQTTClient.h index 9a8affe1f..33f5ca94b 100644 --- a/src/MQTTClient.h +++ b/src/MQTTClient.h @@ -540,7 +540,7 @@ typedef struct int MQTTVersion; } MQTTClient_createOptions; -#define MQTTClient_createOptions_initializer { {'M', 'Q', 'C', 'O'}, MQTTVERSION_DEFAULT } +#define MQTTClient_createOptions_initializer { {'M', 'Q', 'C', 'O'}, 0, MQTTVERSION_DEFAULT } /** * A version of :MQTTClient_create() with additional options. From f5a62906250fc03c08a4b6d6fb0b5be4856c69c8 Mon Sep 17 00:00:00 2001 From: Kilian von Pflugk Date: Tue, 30 Oct 2018 23:00:55 +0100 Subject: [PATCH 13/58] if CApath is set load the PEM files in 695563fccb5d3add93c46a9562dbdc9f6afa5a57 the loading option is missing Signed-off-by: Kilian von Pflugk --- src/SSLSocket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SSLSocket.c b/src/SSLSocket.c index 5b5c20edf..06320acad 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -594,9 +594,9 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) } } - if (opts->trustStore) + if (opts->trustStore || opts->CApath) { - if ((rc = SSL_CTX_load_verify_locations(net->ctx, opts->trustStore, NULL)) != 1) + if ((rc = SSL_CTX_load_verify_locations(net->ctx, opts->trustStore, opts->CApath)) != 1) { if (opts->struct_version >= 3) SSLSocket_error("SSL_CTX_load_verify_locations", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); From 0a5e23c15397edc5411e6ee8f70648f3e5fa84e5 Mon Sep 17 00:00:00 2001 From: Maksym Ruchko Date: Thu, 14 Feb 2019 13:45:51 +0000 Subject: [PATCH 14/58] Added missing verification for SSL server's IP address The PAHO SSL code was checking only DNS names from certificate's Subject Alternative Name. Thus if the "verify" was properly set to 1 in the MQTTClient_SSLOptions and connection was made to the IP address (not the DNS name), the SSL verification was failing regardless the server had valid cert. Samples incorrectly assumed default value for verify as 1, so never set it to 1, only reset to 0. Thus samples were always operating as if --insecure flag was specified. This is fixed in this commit as well. Signed-off-by: Maksym Ruchko --- src/SSLSocket.c | 24 ++++++++++++++++++++---- src/samples/paho_c_pub.c | 2 ++ src/samples/paho_c_sub.c | 2 ++ src/samples/paho_cs_pub.c | 2 ++ src/samples/paho_cs_sub.c | 2 ++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/SSLSocket.c b/src/SSLSocket.c index 5b5c20edf..7c652ce93 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -719,13 +719,29 @@ int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify, int rc = X509_check_host(cert, hostname, hostname_len, 0, &peername); Log(TRACE_MIN, -1, "rc from X509_check_host is %d", rc); Log(TRACE_MIN, -1, "peername from X509_check_host is %s", peername); - + if (peername != NULL) OPENSSL_free(peername); - // 0 == fail, -1 == SSL internal error - if (rc == 0 || rc == -1) - rc = SSL_FATAL; + // 0 == fail, -1 == SSL internal error, -2 == mailformed input + if (rc == 0 || rc == -1 || rc == -2) + { + char* ip_addr = malloc(hostname_len + 1); + // cannot use = strndup(hostname, hostname_len); here because of custom Heap + if (ip_addr) + { + strncpy(ip_addr, hostname, hostname_len); + ip_addr[hostname_len] = '\0'; + + rc = X509_check_ip_asc(cert, ip_addr, 0); + Log(TRACE_MIN, -1, "rc from X509_check_ip_asc is %d", rc); + + free(ip_addr); + } + + if (rc == 0 || rc == -1 || rc == -2) + rc = SSL_FATAL; + } if (cert) X509_free(cert); diff --git a/src/samples/paho_c_pub.c b/src/samples/paho_c_pub.c index 5d92b1735..f69052aa5 100644 --- a/src/samples/paho_c_pub.c +++ b/src/samples/paho_c_pub.c @@ -267,6 +267,8 @@ void myconnect(MQTTAsync client) { if (opts.insecure) ssl_opts.verify = 0; + else + ssl_opts.verify = 1; ssl_opts.CApath = opts.capath; ssl_opts.keyStore = opts.cert; ssl_opts.trustStore = opts.cafile; diff --git a/src/samples/paho_c_sub.c b/src/samples/paho_c_sub.c index 7fa82dc72..6fb63d121 100644 --- a/src/samples/paho_c_sub.c +++ b/src/samples/paho_c_sub.c @@ -304,6 +304,8 @@ int main(int argc, char** argv) { if (opts.insecure) ssl_opts.verify = 0; + else + ssl_opts.verify = 1; ssl_opts.CApath = opts.capath; ssl_opts.keyStore = opts.cert; ssl_opts.trustStore = opts.cafile; diff --git a/src/samples/paho_cs_pub.c b/src/samples/paho_cs_pub.c index e5d627a03..8dcf8133b 100644 --- a/src/samples/paho_cs_pub.c +++ b/src/samples/paho_cs_pub.c @@ -86,6 +86,8 @@ int myconnect(MQTTClient* client) { if (opts.insecure) ssl_opts.verify = 0; + else + ssl_opts.verify = 1; ssl_opts.CApath = opts.capath; ssl_opts.keyStore = opts.cert; ssl_opts.trustStore = opts.cafile; diff --git a/src/samples/paho_cs_sub.c b/src/samples/paho_cs_sub.c index dbe1bf00c..1042fd82b 100644 --- a/src/samples/paho_cs_sub.c +++ b/src/samples/paho_cs_sub.c @@ -83,6 +83,8 @@ int myconnect(MQTTClient* client) { if (opts.insecure) ssl_opts.verify = 0; + else + ssl_opts.verify = 1; ssl_opts.CApath = opts.capath; ssl_opts.keyStore = opts.cert; ssl_opts.trustStore = opts.cafile; From 290ef4b59b85ab2efb71144b35e2f5d5886942b0 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 6 Mar 2019 11:04:25 +0000 Subject: [PATCH 15/58] Some TLS verify changes --- src/SSLSocket.c | 9 ++++++--- src/samples/paho_c_sub.c | 5 ++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/SSLSocket.c b/src/SSLSocket.c index 5b5c20edf..98eb82c4c 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -717,8 +717,11 @@ int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify, int hostname_len = MQTTProtocol_addressPort(hostname, &port, NULL); rc = X509_check_host(cert, hostname, hostname_len, 0, &peername); - Log(TRACE_MIN, -1, "rc from X509_check_host is %d", rc); - Log(TRACE_MIN, -1, "peername from X509_check_host is %s", peername); + if (rc == 1) + Log(TRACE_PROTOCOL, -1, "peername from X509_check_host is %s", peername); + else + Log(TRACE_PROTOCOL, -1, "X509_check_host for hostname %.*s failed, rc %d", + hostname_len, hostname, rc); if (peername != NULL) OPENSSL_free(peername); diff --git a/src/samples/paho_c_sub.c b/src/samples/paho_c_sub.c index 7fa82dc72..2b1df674f 100644 --- a/src/samples/paho_c_sub.c +++ b/src/samples/paho_c_sub.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2018 IBM Corp., and others + * Copyright (c) 2012, 2019 IBM Corp., and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -302,8 +302,7 @@ int main(int argc, char** argv) if (opts.connection && (strncmp(opts.connection, "ssl://", 6) == 0 || strncmp(opts.connection, "wss://", 6) == 0)) { - if (opts.insecure) - ssl_opts.verify = 0; + ssl_opts.verify = (opts.insecure) ? 0 : 1; ssl_opts.CApath = opts.capath; ssl_opts.keyStore = opts.cert; ssl_opts.trustStore = opts.cafile; From 0a399ebac913290dc8e09d2ec0770a75f49d1d85 Mon Sep 17 00:00:00 2001 From: Piotr Wach Date: Fri, 11 Jan 2019 13:00:24 +0000 Subject: [PATCH 16/58] Fix websocket frame parsing Signed-off-by: Piotr Wach --- src/WebSocket.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 5 deletions(-) diff --git a/src/WebSocket.c b/src/WebSocket.c index 47b1dad26..736d1e612 100644 --- a/src/WebSocket.c +++ b/src/WebSocket.c @@ -141,6 +141,10 @@ struct ws_frame *last_frame = NULL; /** Holds any received websocket frames, to be process */ static List* in_frames = NULL; +static char * frame_buffer = NULL; +static size_t frame_buffer_len = 0; +static size_t frame_buffer_index = 0; +static size_t frame_buffer_data_len = 0; /* static function declarations */ static const char *WebSocket_strcasefind( @@ -149,6 +153,8 @@ static const char *WebSocket_strcasefind( static char *WebSocket_getRawSocketData( networkHandles *net, size_t bytes, size_t* actual_len); +static void WebSocket_rewindData( void ); + static void WebSocket_pong( networkHandles *net, char *app_data, size_t app_data_len); @@ -585,6 +591,11 @@ char *WebSocket_getdata(networkHandles *net, size_t bytes, size_t* actual_len) return rv; } +void WebSocket_rewindData( void ) +{ + frame_buffer_index = 0; +} + /** * reads raw socket data for underlying layers * @@ -598,12 +609,97 @@ char *WebSocket_getRawSocketData( networkHandles *net, size_t bytes, size_t* actual_len) { char *rv; + + if (bytes > 0) + { + if (frame_buffer_data_len - frame_buffer_index >= bytes) + { + *actual_len = bytes; + rv = frame_buffer + frame_buffer_index; + frame_buffer_index += bytes; + + goto exit; + } + else + { + bytes = bytes - (frame_buffer_data_len - frame_buffer_index); + } + } + + *actual_len = 0; + + // not enough data in the buffer, get data from socket #if defined(OPENSSL) if ( net->ssl ) rv = SSLSocket_getdata(net->ssl, net->socket, bytes, actual_len); else #endif rv = Socket_getdata(net->socket, bytes, actual_len); + + // clear buffer + if (bytes == 0) + { + frame_buffer_index = 0; + frame_buffer_data_len = 0; + frame_buffer_len = 0; + + free (frame_buffer); + frame_buffer = NULL; + } + // append data to the buffer + else if (rv != NULL) + { + // no buffer allocated + if (!frame_buffer) + { + frame_buffer = (char *)malloc(*actual_len); + memcpy(frame_buffer, rv, *actual_len); + + frame_buffer_index = 0; + frame_buffer_data_len = *actual_len; + frame_buffer_len = *actual_len; + } + // buffer size is big enough + else if (frame_buffer_data_len + *actual_len < frame_buffer_len) + { + memcpy(frame_buffer + frame_buffer_data_len, rv, *actual_len); + frame_buffer_data_len += *actual_len; + } + // resize buffer + else + { + frame_buffer = realloc(frame_buffer, frame_buffer_data_len + *actual_len); + frame_buffer_len = frame_buffer_data_len + *actual_len; + + memcpy(frame_buffer + frame_buffer_data_len, rv, *actual_len); + frame_buffer_data_len += *actual_len; + } + + SocketBuffer_complete(net->socket); + } + else + { + return rv; + } + + // if possible, return data from the buffer + if (bytes > 0) + { + if (frame_buffer_data_len - frame_buffer_index >= bytes) + { + *actual_len = bytes; + rv = frame_buffer + frame_buffer_index; + frame_buffer_index += bytes; + } + else + { + *actual_len = frame_buffer_data_len - frame_buffer_index; + rv = frame_buffer + frame_buffer_index; + frame_buffer_index += *actual_len; + } + } + +exit: return rv; } @@ -757,7 +853,12 @@ int WebSocket_receiveFrame(networkHandles *net, size_t payload_len; b = WebSocket_getRawSocketData(net, 2u, &len); - if ( !b || len == 0u ) + if ( !b ) + { + rc = SOCKET_ERROR; + goto exit; + } + else if (len < 2u ) { rc = TCPSOCKET_INTERRUPTED; goto exit; @@ -789,7 +890,12 @@ int WebSocket_receiveFrame(networkHandles *net, { b = WebSocket_getRawSocketData( net, 2u, &len); - if ( !b || len == 0u ) + if ( !b ) + { + rc = SOCKET_ERROR; + goto exit; + } + else if (len < 2u ) { rc = TCPSOCKET_INTERRUPTED; goto exit; @@ -801,7 +907,12 @@ int WebSocket_receiveFrame(networkHandles *net, { b = WebSocket_getRawSocketData( net, 8u, &len); - if ( !b || len == 0u ) + if ( !b ) + { + rc = SOCKET_ERROR; + goto exit; + } + else if (len < 8u ) { rc = TCPSOCKET_INTERRUPTED; goto exit; @@ -814,7 +925,12 @@ int WebSocket_receiveFrame(networkHandles *net, { uint8_t mask[4]; b = WebSocket_getRawSocketData(net, 4u, &len); - if ( !b || len == 0u ) + if ( !b ) + { + rc = SOCKET_ERROR; + goto exit; + } + else if (len < 4u ) { rc = TCPSOCKET_INTERRUPTED; goto exit; @@ -825,7 +941,12 @@ int WebSocket_receiveFrame(networkHandles *net, b = WebSocket_getRawSocketData(net, payload_len, &len); - if ( !b || len == 0u ) + if ( !b ) + { + rc = SOCKET_ERROR; + goto exit; + } + else if (len < payload_len ) { rc = TCPSOCKET_INTERRUPTED; goto exit; @@ -881,6 +1002,11 @@ int WebSocket_receiveFrame(networkHandles *net, *actual_len = res->len - res->pos; exit: + if (rc == TCPSOCKET_INTERRUPTED) + { + WebSocket_rewindData(); + } + FUNC_EXIT_RC(rc); return rc; } @@ -937,6 +1063,17 @@ void WebSocket_terminate( void ) free( last_frame ); last_frame = NULL; } + + if ( frame_buffer ) + { + free( frame_buffer ); + frame_buffer = NULL; + } + + frame_buffer_len = 0; + frame_buffer_index = 0; + frame_buffer_data_len = 0; + Socket_outTerminate(); #if defined(OPENSSL) SSLSocket_terminate(); From cd38a958d03597249aa73f271650604c4e574255 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 13 Mar 2019 10:16:05 +0000 Subject: [PATCH 17/58] Fix for #604 --- src/Thread.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Thread.c b/src/Thread.c index 4cb2f16e7..4536c0ae0 100644 --- a/src/Thread.c +++ b/src/Thread.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -234,7 +234,7 @@ int Thread_wait_sem(sem_type sem, int timeout) #define USE_TRYWAIT #if defined(USE_TRYWAIT) int i = 0; - int interval = 10000; /* 10000 microseconds: 10 milliseconds */ + useconds_t interval = 10000; /* 10000 microseconds: 10 milliseconds */ int count = (1000 * timeout) / interval; /* how many intervals in timeout period */ #else struct timespec ts; @@ -318,7 +318,9 @@ int Thread_post_sem(sem_type sem) #elif defined(OSX) rc = (int)dispatch_semaphore_signal(sem); #else - if (sem_post(sem) == -1) + int val; + int rc1 = sem_getvalue(sem, &val); + if (val == 0 && sem_post(sem) == -1) rc = errno; #endif From 5ae406e79e054809718fd38c1f6e60dd334e3a11 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 13 Mar 2019 11:59:03 +0000 Subject: [PATCH 18/58] Correct state changes in MQTTClient.c --- src/MQTTClient.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 2069ff96d..77a52f3cd 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -776,11 +776,13 @@ static thread_return_type WINAPI MQTTClient_run(void* n) if (m->c->connect_state == SSL_IN_PROGRESS) { Log(TRACE_MIN, -1, "Posting connect semaphore for client %s", m->c->clientID); + m->c->connect_state = NOT_IN_PROGRESS; Thread_post_sem(m->connect_sem); } if (m->c->connect_state == WAIT_FOR_CONNACK) { Log(TRACE_MIN, -1, "Posting connack semaphore for client %s", m->c->clientID); + m->c->connect_state = NOT_IN_PROGRESS; Thread_post_sem(m->connack_sem); } } @@ -877,6 +879,8 @@ static thread_return_type WINAPI MQTTClient_run(void* n) if ((m->rc = getsockopt(m->c->net.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len)) == 0) m->rc = error; Log(TRACE_MIN, -1, "Posting connect semaphore for client %s rc %d", m->c->clientID, m->rc); + printf("Posting connect semaphore for client %s rc %d", m->c->clientID, m->rc); + m->c->connect_state = NOT_IN_PROGRESS; Thread_post_sem(m->connect_sem); } #if defined(OPENSSL) @@ -893,6 +897,7 @@ static thread_return_type WINAPI MQTTClient_run(void* n) m->c->session = SSL_get1_session(m->c->net.ssl); m->rc = rc; Log(TRACE_MIN, -1, "Posting connect semaphore for SSL client %s rc %d", m->c->clientID, m->rc); + m->c->connect_state = NOT_IN_PROGRESS; Thread_post_sem(m->connect_sem); } } From d01fa1cce9188604b216b85912f016b05bf86649 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 13 Mar 2019 11:59:03 +0000 Subject: [PATCH 19/58] Correct state changes in MQTTClient.c #604 --- src/MQTTClient.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 2069ff96d..77a52f3cd 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -776,11 +776,13 @@ static thread_return_type WINAPI MQTTClient_run(void* n) if (m->c->connect_state == SSL_IN_PROGRESS) { Log(TRACE_MIN, -1, "Posting connect semaphore for client %s", m->c->clientID); + m->c->connect_state = NOT_IN_PROGRESS; Thread_post_sem(m->connect_sem); } if (m->c->connect_state == WAIT_FOR_CONNACK) { Log(TRACE_MIN, -1, "Posting connack semaphore for client %s", m->c->clientID); + m->c->connect_state = NOT_IN_PROGRESS; Thread_post_sem(m->connack_sem); } } @@ -877,6 +879,8 @@ static thread_return_type WINAPI MQTTClient_run(void* n) if ((m->rc = getsockopt(m->c->net.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len)) == 0) m->rc = error; Log(TRACE_MIN, -1, "Posting connect semaphore for client %s rc %d", m->c->clientID, m->rc); + printf("Posting connect semaphore for client %s rc %d", m->c->clientID, m->rc); + m->c->connect_state = NOT_IN_PROGRESS; Thread_post_sem(m->connect_sem); } #if defined(OPENSSL) @@ -893,6 +897,7 @@ static thread_return_type WINAPI MQTTClient_run(void* n) m->c->session = SSL_get1_session(m->c->net.ssl); m->rc = rc; Log(TRACE_MIN, -1, "Posting connect semaphore for SSL client %s rc %d", m->c->clientID, m->rc); + m->c->connect_state = NOT_IN_PROGRESS; Thread_post_sem(m->connect_sem); } } From a232829f660c0b0dfc32f57674aeca8b339f939e Mon Sep 17 00:00:00 2001 From: Stanislaw Findeisen Date: Wed, 13 Mar 2019 21:54:20 +0100 Subject: [PATCH 20/58] [623] Fix include paths in samples Bug: https://github.com/eclipse/paho.mqtt.c/issues/623 Signed-off-by: Stanislaw Findeisen --- src/samples/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/samples/CMakeLists.txt b/src/samples/CMakeLists.txt index f55b1993d..5dddd7ba6 100644 --- a/src/samples/CMakeLists.txt +++ b/src/samples/CMakeLists.txt @@ -20,8 +20,8 @@ ## compilation/linkage settings INCLUDE_DIRECTORIES( . - ${CMAKE_SOURCE_DIR}/src - ${CMAKE_BINARY_DIR} + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_BINARY_DIR} ) IF (WIN32) From 68f2bd21be7b8b76eee7adbc1a74205fc89ca690 Mon Sep 17 00:00:00 2001 From: Milan Tucic Date: Thu, 14 Mar 2019 11:14:19 +0100 Subject: [PATCH 21/58] Test session present flag on MQTTClient_connect (issue #627) Signed-off-by: Milan Tucic --- test/CMakeLists.txt | 20 ++ test/test_sync_session_present.c | 491 +++++++++++++++++++++++++++++++ 2 files changed, 511 insertions(+) create mode 100644 test/test_sync_session_present.c diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 06bf46ffc..9593dce4c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -792,3 +792,23 @@ TARGET_LINK_LIBRARIES( test_issue373 paho-mqtt3a ) + +ADD_EXECUTABLE( + test_sync_session_present + test_sync_session_present.c +) + +TARGET_LINK_LIBRARIES( + test_sync_session_present + paho-mqtt3c +) + +ADD_TEST( + NAME test_sync_session_present-1-client_session_present_after_reconnect + COMMAND "test_sync_session_present" "--test_no" "1" "--connection" ${MQTT_TEST_BROKER} "--proxy_connection" ${MQTT_TEST_PROXY} +) + +SET_TESTS_PROPERTIES( + test_sync_session_present-1-client_session_present_after_reconnect + PROPERTIES TIMEOUT 540 +) diff --git a/test/test_sync_session_present.c b/test/test_sync_session_present.c new file mode 100644 index 000000000..544169b61 --- /dev/null +++ b/test/test_sync_session_present.c @@ -0,0 +1,491 @@ +/******************************************************************************* + * Copyright (c) 2009, 2019 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - Test program utilities + * Milan Tucic - Session present test1 + *******************************************************************************/ + + +/** + * @file + * Tests for the MQ Telemetry MQTT C client + */ + +#include "MQTTClient.h" +#include +#include + +#if !defined(_WINDOWS) + #include + #include + #include + #include +#else + #include + #define setenv(a, b, c) _putenv_s(a, b) +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +void usage(void) +{ + printf("help!!\n"); + exit(EXIT_FAILURE); +} + +struct Options +{ + char* connection; /**< connection to system under test. */ + char** haconnections; + char* proxy_connection; + char* client_id; + char* username; + char* password; + char* log; + int hacount; + int verbose; + int test_no; + int MQTTVersion; + int iterations; + int reconnect_period; +} options = +{ + "tcp://iot.eclipse.org:1883", + NULL, + "tcp://localhost:1883", + "cli/test", + NULL, + NULL, + NULL, + 0, + 0, + 0, + MQTTVERSION_DEFAULT, + 1, + 3 +}; + +void getopts(int argc, char** argv) +{ + int count = 1; + + while (count < argc) + { + if (strcmp(argv[count], "--test_no") == 0) + { + if (++count < argc) + options.test_no = atoi(argv[count]); + else + usage(); + } + else if (strcmp(argv[count], "--connection") == 0) + { + if (++count < argc) + { + options.connection = argv[count]; + printf("\nSetting connection to %s\n", options.connection); + } + else + usage(); + } + else if (strcmp(argv[count], "--haconnections") == 0) + { + if (++count < argc) + { + char* tok = strtok(argv[count], " "); + options.hacount = 0; + options.haconnections = malloc(sizeof(char*) * 5); + while (tok) + { + options.haconnections[options.hacount] = malloc(strlen(tok) + 1); + strcpy(options.haconnections[options.hacount], tok); + options.hacount++; + tok = strtok(NULL, " "); + } + } + else + usage(); + } + else if (strcmp(argv[count], "--proxy_connection") == 0) + { + if (++count < argc) + options.proxy_connection = argv[count]; + else + usage(); + } + else if (strcmp(argv[count], "--client_id") == 0) + { + if (++count < argc) + options.client_id = argv[count]; + else + usage(); + } + else if (strcmp(argv[count], "--username") == 0) + { + if (++count < argc) + options.username = argv[count]; + else + usage(); + } + else if (strcmp(argv[count], "--password") == 0) + { + if (++count < argc) + options.password = argv[count]; + else + usage(); + } + else if (strcmp(argv[count], "--log") == 0) + { + if (++count < argc) + options.log = argv[count]; + else + usage(); + } + else if (strcmp(argv[count], "--MQTTversion") == 0) + { + if (++count < argc) + { + options.MQTTVersion = atoi(argv[count]); + printf("setting MQTT version to %d\n", options.MQTTVersion); + } + else + usage(); + } + else if (strcmp(argv[count], "--iterations") == 0) + { + if (++count < argc) + options.iterations = atoi(argv[count]); + else + usage(); + } + else if (strcmp(argv[count], "--reconnection_period") == 0) + { + if (++count < argc) + options.reconnect_period = atoi(argv[count]); + else + usage(); + } + else if (strcmp(argv[count], "--verbose") == 0) + { + options.verbose = 1; + printf("\nSetting verbose on\n"); + } + count++; + } +} + + +#define LOGA_DEBUG 0 +#define LOGA_INFO 1 +#include +#include +#include +void MyLog(int LOGA_level, char* format, ...) +{ + static char msg_buf[256]; + va_list args; + struct timeb ts; + + struct tm *timeinfo; + + if (LOGA_level == LOGA_DEBUG && options.verbose == 0) + return; + + ftime(&ts); + timeinfo = localtime(&ts.time); + strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo); + + sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm); + + va_start(args, format); + vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args); + va_end(args); + + printf("%s\n", msg_buf); + fflush(stdout); +} + + +#if defined(WIN32) || defined(_WINDOWS) +#define mqsleep(A) Sleep(1000*A) +#define START_TIME_TYPE DWORD +static DWORD start_time = 0; +START_TIME_TYPE start_clock(void) +{ + return GetTickCount(); +} +#elif defined(AIX) +#define mqsleep sleep +#define START_TIME_TYPE struct timespec +START_TIME_TYPE start_clock(void) +{ + static struct timespec start; + clock_gettime(CLOCK_REALTIME, &start); + return start; +} +#else +#define mqsleep sleep +#define START_TIME_TYPE struct timeval +/* TODO - unused - remove? static struct timeval start_time; */ +START_TIME_TYPE start_clock(void) +{ + struct timeval start_time; + gettimeofday(&start_time, NULL); + return start_time; +} +#endif + + +#if defined(WIN32) +long elapsed(START_TIME_TYPE start_time) +{ + return GetTickCount() - start_time; +} +#elif defined(AIX) +#define assert(a) +long elapsed(struct timespec start) +{ + struct timespec now, res; + + clock_gettime(CLOCK_REALTIME, &now); + ntimersub(now, start, res); + return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L; +} +#else +long elapsed(START_TIME_TYPE start_time) +{ + struct timeval now, res; + + gettimeofday(&now, NULL); + timersub(&now, &start_time, &res); + return (res.tv_sec)*1000 + (res.tv_usec)/1000; +} +#endif + + +#define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d) +#define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e) + +int tests = 0; +int failures = 0; +FILE* xml; +START_TIME_TYPE global_start_time; +char output[3000]; +char* cur_output = output; + + +void write_test_result(void) +{ + long duration = elapsed(global_start_time); + + fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000); + if (cur_output != output) + { + fprintf(xml, "%s", output); + cur_output = output; + } + fprintf(xml, "\n"); +} + + +void myassert(char* filename, int lineno, char* description, int value, char* format, ...) +{ + ++tests; + if (!value) + { + va_list args; + + ++failures; + MyLog(LOGA_INFO, "Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description); + + va_start(args, format); + vprintf(format, args); + va_end(args); + + cur_output += sprintf(cur_output, "file %s, line %d \n", + description, filename, lineno); + } + else + MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description); +} + +void mysleep(int seconds) +{ +#if defined(WIN32) + Sleep(1000L*seconds); +#else + sleep(seconds); +#endif +} + +/********************************************************************* + +Test 1: clean session and reconnect with session present + +*********************************************************************/ +MQTTClient test1_c1; + +void test1_connectionLost(void* context, char* cause) +{ + printf("Callback: connection lost\n"); +} + +void test1_deliveryComplete(void* context, MQTTClient_deliveryToken token) +{ + printf("Callback: publish complete for token %d\n", token); +} + +int test1_messageArrived(void* context, char* topicName, int topicLen, MQTTClient_message* m) +{ + MQTTClient c = (MQTTClient)context; + printf("Callback: message received on topic '%s' is '%.*s'.\n", topicName, m->payloadlen, (char*)(m->payload)); + MQTTClient_free(topicName); + MQTTClient_freeMessage(&m); + return 1; +} + +int test1(struct Options options) +{ + char* testname = "test1"; + MQTTClient_connectOptions opts = MQTTClient_connectOptions_initializer; + int rc; + + failures = 0; + MyLog(LOGA_INFO, "Starting test 1 - clean session and reconnect with session present"); + fprintf(xml, "\n", (int)(ARRAY_SIZE(tests) - 1)); + + getopts(argc, argv); + + if (options.log) + { + setenv("MQTT_C_CLIENT_TRACE", "ON", 1); + setenv("MQTT_C_CLIENT_TRACE_LEVEL", options.log, 1); + } + + + MyLog(LOGA_INFO, "Running %d iteration(s)", options.iterations); + + for (i = 0; i < options.iterations; ++i) + { + if (options.test_no == 0) + { /* run all the tests */ + for (test_i = 1; test_i < ARRAY_SIZE(tests); ++test_i) + rc += tests[test_i](options); /* return number of failures. 0 = test succeeded */ + } + else + rc = tests[options.test_no](options); /* run just the selected test */ + } + + if (rc == 0) + MyLog(LOGA_INFO, "verdict pass"); + else + MyLog(LOGA_INFO, "verdict fail"); + + fprintf(xml, "\n"); + fclose(xml); + return rc; +} From dbe9dc6c96b67b48dc6ba0509ffd6c12d0b4fc26 Mon Sep 17 00:00:00 2001 From: Milan Tucic Date: Thu, 14 Mar 2019 11:20:42 +0100 Subject: [PATCH 22/58] Fix for invalid session present on MQTTClient_connect (issue #627) Signed-off-by: Milan Tucic --- src/MQTTClient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 2069ff96d..33ea00902 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -1300,7 +1300,7 @@ static MQTTResponse MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_c exit: if (rc == MQTTCLIENT_SUCCESS) { - if (options->struct_version == 4) /* means we have to fill out return values */ + if (options->struct_version >= 4) /* means we have to fill out return values */ { options->returned.serverURI = serverURI; options->returned.MQTTVersion = MQTTVersion; From 7ffa64386aa18a1cdd6d2a082087a07e8a4e5478 Mon Sep 17 00:00:00 2001 From: Milan Tucic Date: Thu, 14 Mar 2019 11:27:40 +0100 Subject: [PATCH 23/58] Fix for TRACE_MINIMUM log level env val not handled (issue #628) Signed-off-by: Milan Tucic --- src/Log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Log.c b/src/Log.c index 8988dc1dd..405870fb0 100644 --- a/src/Log.c +++ b/src/Log.c @@ -162,7 +162,7 @@ int Log_initialize(Log_nameValue* info) trace_settings.trace_level = TRACE_MAXIMUM; else if (strcmp(envval, "MEDIUM") == 0 || strcmp(envval, "TRACE_MEDIUM") == 0) trace_settings.trace_level = TRACE_MEDIUM; - else if (strcmp(envval, "MINIMUM") == 0 || strcmp(envval, "TRACE_MEDIUM") == 0) + else if (strcmp(envval, "MINIMUM") == 0 || strcmp(envval, "TRACE_MINIMUM") == 0) trace_settings.trace_level = TRACE_MINIMUM; else if (strcmp(envval, "PROTOCOL") == 0 || strcmp(envval, "TRACE_PROTOCOL") == 0) trace_output_level = TRACE_PROTOCOL; From de778c934c968e371962b24b44a3ee975a3fc7e7 Mon Sep 17 00:00:00 2001 From: Piotr Wach Date: Fri, 22 Mar 2019 14:05:33 +0000 Subject: [PATCH 24/58] Fix failing tests Signed-off-by: Piotr Wach --- src/WebSocket.c | 6 +++++- test/test8.c | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/WebSocket.c b/src/WebSocket.c index 736d1e612..4003670e5 100644 --- a/src/WebSocket.c +++ b/src/WebSocket.c @@ -582,8 +582,12 @@ char *WebSocket_getdata(networkHandles *net, size_t bytes, size_t* actual_len) } } } +#if defined(OPENSSL) + else if ( net->ssl ) + rv = SSLSocket_getdata(net->ssl, net->socket, bytes, actual_len); +#endif else - rv = WebSocket_getRawSocketData(net, bytes, actual_len); + rv = Socket_getdata(net->socket, bytes, actual_len); exit: rc = rv != NULL; diff --git a/test/test8.c b/test/test8.c index 809d799ae..f5f8bdbbf 100644 --- a/test/test8.c +++ b/test/test8.c @@ -785,6 +785,7 @@ void test4_onSubscribe(void* context, MQTTAsync_successData* response) pubmsg.retained = 0; rc = MQTTAsync_send(c, test_topic, pubmsg.payloadlen, pubmsg.payload, pubmsg.qos, pubmsg.retained, NULL); + assert("Send successful", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); } From 88039703945d2c2f88c7d03769047fffaf986bb9 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 15 Apr 2019 11:06:40 +0100 Subject: [PATCH 25/58] Update connect message to add MQTT version --- src/MQTTPacketOut.c | 3 ++- src/Messages.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/MQTTPacketOut.c b/src/MQTTPacketOut.c index ef9e275a2..723707798 100644 --- a/src/MQTTPacketOut.c +++ b/src/MQTTPacketOut.c @@ -118,7 +118,8 @@ int MQTTPacket_send_connect(Clients* client, int MQTTVersion, writeData(&ptr, client->password, client->passwordlen); rc = MQTTPacket_send(&client->net, packet.header, buf, len, 1, MQTTVersion); - Log(LOG_PROTOCOL, 0, NULL, client->net.socket, client->clientID, client->cleansession, rc); + Log(LOG_PROTOCOL, 0, NULL, client->net.socket, client->clientID, + MQTTVersion, client->cleansession, rc); exit: if (rc != TCPSOCKET_INTERRUPTED) free(buf); diff --git a/src/Messages.c b/src/Messages.c index 63bd193e9..c54ade577 100644 --- a/src/Messages.c +++ b/src/Messages.c @@ -36,7 +36,7 @@ static const char *protocol_message_list[] = { - "%d %s -> CONNECT cleansession: %d (%d)", /* 0, was 131, 68 and 69 */ + "%d %s -> CONNECT version %d clean: %d (%d)", /* 0, was 131, 68 and 69 */ "%d %s <- CONNACK rc: %d", /* 1, was 132 */ "%d %s -> CONNACK rc: %d (%d)", /* 2, was 138 */ "%d %s <- PINGREQ", /* 3, was 35 */ From 9705ef26067d428a7084cb89412c2211b4cc610f Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 15 Apr 2019 17:12:07 +0100 Subject: [PATCH 26/58] Fix for issue #588, persistence key for MQTT V5 --- src/MQTTAsync.c | 7 +++++-- src/MQTTClient.c | 1 + src/MQTTPersistence.c | 13 +++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index 2584df462..6d95a292a 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -634,7 +634,10 @@ static int MQTTAsync_unpersistCommand(MQTTAsync_queuedCommand* qcmd) char key[PERSISTENCE_MAX_KEY_LENGTH + 1]; FUNC_ENTRY; - sprintf(key, "%s%u", PERSISTENCE_COMMAND_KEY, qcmd->seqno); + if (qcmd->client->c->MQTTVersion >= MQTTVERSION_5) + sprintf(key, "%s%u", PERSISTENCE_V5_COMMAND_KEY, qcmd->seqno); + else + sprintf(key, "%s%u", PERSISTENCE_COMMAND_KEY, qcmd->seqno); if ((rc = qcmd->client->c->persistence->premove(qcmd->client->c->phandle, key)) != 0) Log(LOG_ERROR, 0, "Error %d removing command from persistence", rc); FUNC_EXIT_RC(rc); diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 06c7a7a5c..d07c80ea1 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -493,6 +493,7 @@ static void MQTTClient_emptyMessageQueue(Clients* client) { qEntry* qe = (qEntry*)(current->content); free(qe->topicName); + MQTTProperties_free(&qe->msg->properties); free(qe->msg->payload); free(qe->msg); } diff --git a/src/MQTTPersistence.c b/src/MQTTPersistence.c index d7db8bf59..efcdd772a 100644 --- a/src/MQTTPersistence.c +++ b/src/MQTTPersistence.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -187,11 +187,13 @@ int MQTTPersistence_restore(Clients *c) { while (rc == 0 && i < nkeys) { - if (strncmp(msgkeys[i], PERSISTENCE_COMMAND_KEY, strlen(PERSISTENCE_COMMAND_KEY)) == 0) + if (strncmp(msgkeys[i], PERSISTENCE_COMMAND_KEY, strlen(PERSISTENCE_COMMAND_KEY)) == 0 || + strncmp(msgkeys[i], PERSISTENCE_V5_COMMAND_KEY, strlen(PERSISTENCE_V5_COMMAND_KEY)) == 0) { ; } - else if (strncmp(msgkeys[i], PERSISTENCE_QUEUE_KEY, strlen(PERSISTENCE_QUEUE_KEY)) == 0) + else if (strncmp(msgkeys[i], PERSISTENCE_QUEUE_KEY, strlen(PERSISTENCE_QUEUE_KEY)) == 0 || + strncmp(msgkeys[i], PERSISTENCE_V5_QUEUE_KEY, strlen(PERSISTENCE_V5_QUEUE_KEY)) == 0) { ; } @@ -553,7 +555,10 @@ int MQTTPersistence_unpersistQueueEntry(Clients* client, MQTTPersistence_qEntry* char key[PERSISTENCE_MAX_KEY_LENGTH + 1]; FUNC_ENTRY; - sprintf(key, "%s%u", PERSISTENCE_QUEUE_KEY, qe->seqno); + if (client->MQTTVersion >= MQTTVERSION_5) + sprintf(key, "%s%u", PERSISTENCE_V5_QUEUE_KEY, qe->seqno); + else + sprintf(key, "%s%u", PERSISTENCE_QUEUE_KEY, qe->seqno); if ((rc = client->persistence->premove(client->phandle, key)) != 0) Log(LOG_ERROR, 0, "Error %d removing qEntry from persistence", rc); FUNC_EXIT_RC(rc); From 87450e252ca50168c6f6f55d2fe79a5be0afca02 Mon Sep 17 00:00:00 2001 From: Kilian von Pflugk Date: Thu, 15 Nov 2018 20:50:16 +0100 Subject: [PATCH 27/58] add capath test Signed-off-by: Kilian von Pflugk --- test/CMakeLists.txt | 12 +++ test/test5.c | 223 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 233 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 06bf46ffc..118572858 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -456,6 +456,16 @@ ADD_TEST( COMMAND test5 "--test_no" "8" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" ) +ADD_TEST( + NAME test5-5-server-verify-with-capath + COMMAND test5 "--test_no" "9" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" +) + +ADD_TEST( + NAME test5-6-server-verify-with-capath + COMMAND test5 "--test_no" "10" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" +) + SET_TESTS_PROPERTIES( test5-1-ssl-connection-to-no-SSL-server test5-2a-multual-ssl-auth-certificates-in-place @@ -465,6 +475,8 @@ SET_TESTS_PROPERTIES( test5-3a-server-auth-server-cert-in-client-store test5-3b-server-auth-client-missing-broker-cert test5-4-accept-invalid-certificates + test5-5-server-verify-with-capath + test5-6-server-verify-with-capath PROPERTIES TIMEOUT 540 ) diff --git a/test/test5.c b/test/test5.c index 8868a6105..68558dedd 100644 --- a/test/test5.c +++ b/test/test5.c @@ -63,6 +63,7 @@ struct Options char* client_key_pass; char* server_key_file; char* client_private_key_file; + char* capath; int verbose; int test_no; int size; @@ -77,6 +78,7 @@ struct Options "../../../test/ssl/client.pem", NULL, "../../../test/ssl/test-root-ca.crt", + "../../../test/ssl/", NULL, 0, 0, @@ -1106,8 +1108,6 @@ int test2d(struct Options options) return failures; } - - /********************************************************************* Test3a: Server Authentication - server certificate in client trust store @@ -2192,6 +2192,225 @@ int main(int argc, char** argv) return rc; } +/********************************************************************* + + Test9: Mutual SSL Authentication - Testing CApath + + *********************************************************************/ + +void test9OnConnectFailure(void* context, MQTTAsync_failureData* response) +{ + AsyncTestClient* client = (AsyncTestClient*) context; + MyLog(LOGA_DEBUG, "In test9OnConnectFailure callback, %s", + client->clientid); + + assert("There should be no failures in this test. ", 0, "test9OnConnectFailure callback was called\n", 0); + client->testFinished = 1; +} + +int test9(struct Options options) +{ + char* testname = "test9"; + + AsyncTestClient tc = + AsyncTestClient_initializer; + MQTTAsync c; + MQTTAsync_connectOptions opts = MQTTAsync_connectOptions_initializer; + MQTTAsync_willOptions wopts = MQTTAsync_willOptions_initializer; + MQTTAsync_SSLOptions sslopts = MQTTAsync_SSLOptions_initializer; + int rc = 0; + + failures = 0; + MyLog(LOGA_INFO, "Starting test 9 - Mutual SSL authentication"); + fprintf(xml, "message = "will message"; + opts.will->qos = 1; + opts.will->retained = 0; + opts.will->topicName = "will topic"; + opts.will = NULL; + opts.onSuccess = asyncTestOnConnect; + opts.onFailure = test9OnConnectFailure; + opts.context = &tc; + + opts.ssl = &sslopts; + if (options.server_key_file != NULL) + opts.ssl->trustStore = options.server_key_file; /*file of certificates trusted by client*/ + opts.ssl->keyStore = options.client_key_file; /*file of certificate for client to present to server*/ + if (options.client_key_pass != NULL) + opts.ssl->privateKeyPassword = options.client_key_pass; + opts.ssl->CApath = options.capath; + opts.ssl->enableServerCertAuth = 1; + opts.ssl->verify = 1; + MyLog(LOGA_DEBUG, "enableServerCertAuth %d\n", opts.ssl->enableServerCertAuth); + MyLog(LOGA_DEBUG, "verify %d\n", opts.ssl->verify); + + rc = MQTTAsync_setCallbacks(c, &tc, NULL, asyncTestMessageArrived, + asyncTestOnDeliveryComplete); + assert("Good rc from setCallbacks", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + + MyLog(LOGA_DEBUG, "Connecting"); + rc = MQTTAsync_connect(c, &opts); + assert("Good rc from connect", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + if (rc != MQTTASYNC_SUCCESS) + goto exit; + + while (!tc.subscribed && !tc.testFinished) +#if defined(WIN32) + Sleep(100); +#else + usleep(10000L); +#endif + + if (tc.testFinished) + goto exit; + + while (!tc.testFinished) +#if defined(WIN32) + Sleep(100); +#else + usleep(10000L); +#endif + + MyLog(LOGA_DEBUG, "Stopping"); + + exit: MQTTAsync_destroy(&c); + MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", testname, tests, failures); + write_test_result(); + return failures; +} + +/********************************************************************* + + Test10: Mutual SSL Authentication - Testing CApath + + *********************************************************************/ + +int test10Finished; + +void test10OnConnectFailure(void* context, MQTTAsync_failureData* response) +{ + AsyncTestClient* client = (AsyncTestClient*) context; + MyLog(LOGA_DEBUG, "In test10OnConnectFailure callback, %s", + client->clientid); + + assert("This test should call test10OnConnectFailure. ", 1, "test10OnConnectFailure callback was called\n", 1); + test10Finished = 1; +} + +void test10OnConnect(void* context, MQTTAsync_successData* response) +{ + MyLog(LOGA_DEBUG, "In test10OnConnect callback, context %p", context); + + assert("This connect should not succeed. ", 0, "test10OnConnect callback was called\n", 0); + test10Finished = 1; +} + +int test10(struct Options options) +{ + char* testname = "test10"; + + AsyncTestClient tc = + AsyncTestClient_initializer; + MQTTAsync c; + MQTTAsync_connectOptions opts = MQTTAsync_connectOptions_initializer; + MQTTAsync_willOptions wopts = MQTTAsync_willOptions_initializer; + MQTTAsync_SSLOptions sslopts = MQTTAsync_SSLOptions_initializer; + int rc = 0; + + failures = 0; + test10Finished = 0; + MyLog(LOGA_INFO, "Starting test 10 - Mutual SSL authentication"); + fprintf(xml, "message = "will message"; + opts.will->qos = 1; + opts.will->retained = 0; + opts.will->topicName = "will topic"; + opts.will = NULL; + opts.onSuccess = test10OnConnect; + opts.onFailure = test10OnConnectFailure; + opts.context = &tc; + + opts.ssl = &sslopts; + if (options.server_key_file != NULL) + opts.ssl->trustStore = options.server_key_file; /*file of certificates trusted by client*/ + opts.ssl->keyStore = options.client_key_file; /*file of certificate for client to present to server*/ + if (options.client_key_pass != NULL) + opts.ssl->privateKeyPassword = options.client_key_pass; + opts.ssl->CApath = "DUMMY"; + opts.ssl->enableServerCertAuth = 1; + opts.ssl->verify = 1; + MyLog(LOGA_DEBUG, "enableServerCertAuth %d\n", opts.ssl->enableServerCertAuth); + MyLog(LOGA_DEBUG, "verify %d\n", opts.ssl->verify); + + rc = MQTTAsync_setCallbacks(c, &tc, NULL, asyncTestMessageArrived, + asyncTestOnDeliveryComplete); + assert("Good rc from setCallbacks", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + + MyLog(LOGA_DEBUG, "Connecting"); + rc = MQTTAsync_connect(c, &opts); + assert("Good rc from connect", rc == MQTTASYNC_SUCCESS, "rc was %d", rc); + if (rc != MQTTASYNC_SUCCESS) + goto exit; + + while (!test10Finished) +#if defined(WIN32) + Sleep(100); +#else + usleep(10000L); +#endif + MyLog(LOGA_DEBUG, "Stopping"); + + exit: MQTTAsync_destroy(&c); + MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.", + (failures == 0) ? "passed" : "failed", testname, tests, failures); + write_test_result(); + return failures; +} + /* Local Variables: */ /* indent-tabs-mode: t */ /* c-basic-offset: 8 */ From 2bff0f10ace91ac2b7bb1efc1472d794dcb15b2e Mon Sep 17 00:00:00 2001 From: Julien Grossholtz Date: Tue, 16 Apr 2019 15:38:11 +0200 Subject: [PATCH 28/58] Add disconnect option initializer for mqttv5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New fields where added to the MQTTAsync_disconnectOptions structure for MQTTv5 support. The macro provided to initialize this macro, does not included the new fields. Depending on compilation options it may cause a warning similar to: 'warning: missing initializer for field ‘onSuccess5’". Add a MQTTAsync_disconnectOptions_initializer5 with the two missing fields (onSuccelss5 and onFailure5) set to NULL. Update the previous initializer and set the struct_version to 0 as it should not be used for MQTTv5 anyway. Signed-off-by: Julien Grossholtz --- src/MQTTAsync.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 1b3593d25..c6e456984 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -1227,8 +1227,11 @@ typedef struct MQTTAsync_onFailure5* onFailure5; } MQTTAsync_disconnectOptions; -#define MQTTAsync_disconnectOptions_initializer { {'M', 'Q', 'T', 'D'}, 1, 0, NULL, NULL, NULL, MQTTProperties_initializer, MQTTREASONCODE_SUCCESS } +#define MQTTAsync_disconnectOptions_initializer { {'M', 'Q', 'T', 'D'}, 0, 0, NULL, NULL, NULL,\ + MQTTProperties_initializer, MQTTREASONCODE_SUCCESS } +#define MQTTAsync_disconnectOptions_initializer5 { {'M', 'Q', 'T', 'D'}, 1, 0, NULL, NULL, NULL,\ + MQTTProperties_initializer, MQTTREASONCODE_SUCCESS, NULL, NULL } /** * This function attempts to disconnect the client from the MQTT From c2052af5f990b87762c8d5ee9d1b033d2959c920 Mon Sep 17 00:00:00 2001 From: Andrew Fischer Date: Mon, 6 May 2019 20:43:07 -0700 Subject: [PATCH 29/58] Fix symlink location for synchronous shared library Signed-off-by: Andrew Fischer --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 639bf4048..35fb8d2fa 100755 --- a/Makefile +++ b/Makefile @@ -285,7 +285,7 @@ install: build ln -s lib$(MQTTLIB_CS).so.${MAJOR_VERSION} $(DESTDIR)${libdir}/lib$(MQTTLIB_CS).so ln -s lib$(MQTTLIB_A).so.${MAJOR_VERSION} $(DESTDIR)${libdir}/lib$(MQTTLIB_A).so ln -s lib$(MQTTLIB_AS).so.${MAJOR_VERSION} $(DESTDIR)${libdir}/lib$(MQTTLIB_AS).so - @if test ! -f $(DESTDIR)${blddir}/lib$(MQTTLIB_C).so.${MAJOR_VERSION}; then ln -s lib$(MQTTLIB_C).so.${VERSION} $(DESTDIR)${blddir}/lib$(MQTTLIB_C).so.${MAJOR_VERSION}; fi + @if test ! -f $(DESTDIR)${libdir}/lib$(MQTTLIB_C).so.${MAJOR_VERSION}; then ln -s lib$(MQTTLIB_C).so.${VERSION} $(DESTDIR)${libdir}/lib$(MQTTLIB_C).so.${MAJOR_VERSION}; fi @if test ! -f $(DESTDIR)${libdir}/lib$(MQTTLIB_CS).so.${MAJOR_VERSION}; then ln -s lib$(MQTTLIB_CS).so.${VERSION} $(DESTDIR)${libdir}/lib$(MQTTLIB_CS).so.${MAJOR_VERSION}; fi @if test ! -f $(DESTDIR)${libdir}/lib$(MQTTLIB_A).so.${MAJOR_VERSION}; then ln -s lib$(MQTTLIB_A).so.${VERSION} $(DESTDIR)${libdir}/lib$(MQTTLIB_A).so.${MAJOR_VERSION}; fi @if test ! -f $(DESTDIR)${libdir}/lib$(MQTTLIB_AS).so.${MAJOR_VERSION}; then ln -s lib$(MQTTLIB_AS).so.${VERSION} $(DESTDIR)${libdir}/lib$(MQTTLIB_AS).so.${MAJOR_VERSION}; fi @@ -318,7 +318,7 @@ uninstall: - rm $(DESTDIR)${libdir}/lib$(MQTTLIB_CS).so - rm $(DESTDIR)${libdir}/lib$(MQTTLIB_A).so - rm $(DESTDIR)${libdir}/lib$(MQTTLIB_AS).so - - rm $(DESTDIR)${blddir}/lib$(MQTTLIB_C).so.${MAJOR_VERSION} + - rm $(DESTDIR)${libdir}/lib$(MQTTLIB_C).so.${MAJOR_VERSION} - rm $(DESTDIR)${libdir}/lib$(MQTTLIB_CS).so.${MAJOR_VERSION} - rm $(DESTDIR)${libdir}/lib$(MQTTLIB_A).so.${MAJOR_VERSION} - rm $(DESTDIR)${libdir}/lib$(MQTTLIB_AS).so.${MAJOR_VERSION} From 08a153e0e8281159d146a9bc65b73e1e4cab9255 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 29 May 2019 16:31:27 +0100 Subject: [PATCH 30/58] Fix for issue #661 not sending MQTT V5 disconnect packet if no properties and reasoncode=0 --- src/MQTTPacket.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/MQTTPacket.c b/src/MQTTPacket.c index c6115d197..4c309a231 100644 --- a/src/MQTTPacket.c +++ b/src/MQTTPacket.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -489,21 +489,18 @@ int MQTTPacket_send_disconnect(Clients* client, enum MQTTReasonCodes reason, MQT header.byte = 0; header.bits.type = DISCONNECT; - if (client->MQTTVersion >= 5) + if (client->MQTTVersion >= 5 && (props || reason != MQTTREASONCODE_SUCCESS)) { - if (props || reason != MQTTREASONCODE_SUCCESS) - { - size_t buflen = 1 + ((props == NULL) ? 0 : MQTTProperties_len(props)); - char *buf = malloc(buflen), *ptr = NULL; - - ptr = buf; - writeChar(&ptr, reason); - if (props) - MQTTProperties_write(&ptr, props); - if ((rc = MQTTPacket_send(&client->net, header, buf, buflen, 1, - client->MQTTVersion)) != TCPSOCKET_INTERRUPTED) - free(buf); - } + size_t buflen = 1 + ((props == NULL) ? 0 : MQTTProperties_len(props)); + char *buf = malloc(buflen), *ptr = NULL; + + ptr = buf; + writeChar(&ptr, reason); + if (props) + MQTTProperties_write(&ptr, props); + if ((rc = MQTTPacket_send(&client->net, header, buf, buflen, 1, + client->MQTTVersion)) != TCPSOCKET_INTERRUPTED) + free(buf); } else rc = MQTTPacket_send(&client->net, header, NULL, 0, 0, client->MQTTVersion); From bcf472886b955ed80ac766dc140cac5c4c512f29 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 30 May 2019 16:30:08 +0100 Subject: [PATCH 31/58] Small trace and compile warning cleanup --- src/MQTTAsync.c | 7 +------ src/WebSocket.c | 3 ++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index 6d95a292a..ee6b188c6 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -3688,7 +3688,7 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) m = (MQTTAsync)(handles->current->content); if (m != NULL) { - Log(TRACE_MINIMUM, -1, "m->c->connect_state = %d",m->c->connect_state); + Log(TRACE_MINIMUM, -1, "m->c->connect_state = %d", m->c->connect_state); if (m->c->connect_state == TCP_IN_PROGRESS || m->c->connect_state == SSL_IN_PROGRESS || m->c->connect_state == WEBSOCKET_IN_PROGRESS) *rc = MQTTAsync_connecting(m); else @@ -3698,11 +3698,6 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc) Log(TRACE_MINIMUM, -1, "CONNECT sent but MQTTPacket_Factory has returned SOCKET_ERROR"); nextOrClose(m, MQTTASYNC_FAILURE, "TCP connect completion failure"); } - else - { - Log(TRACE_MINIMUM, -1, "m->c->connect_state = %d",m->c->connect_state); - Log(TRACE_MINIMUM, -1, "CONNECT sent, *rc is %d",*rc); - } } if (pack) { diff --git a/src/WebSocket.c b/src/WebSocket.c index b732689b4..e3e15b36a 100644 --- a/src/WebSocket.c +++ b/src/WebSocket.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Wind River Systems, Inc. and others. All Rights Reserved. + * Copyright (c) 2018, 2019 Wind River Systems, Inc. and others. All Rights Reserved. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -26,6 +26,7 @@ #include "SHA1.h" #include "LinkedList.h" #include "MQTTProtocolOut.h" +#include "SocketBuffer.h" #include "StackTrace.h" #if defined(__linux__) From 6c3530f6816287458cdf22eab137c1face30c9e0 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Thu, 20 Jun 2019 11:27:47 +0100 Subject: [PATCH 32/58] Remove unused sample --- test/MQTTTest_v2.c | 416 --------------------------------------------- 1 file changed, 416 deletions(-) delete mode 100644 test/MQTTTest_v2.c diff --git a/test/MQTTTest_v2.c b/test/MQTTTest_v2.c deleted file mode 100644 index b005baf22..000000000 --- a/test/MQTTTest_v2.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * ----------------------------------------------------------------- - * IBM Websphere MQ Telemetry - * MQTTV3ASample MQTT v3 Asynchronous Client application - * - * Version: @(#) MQMBID sn=p000-L130522.1 su=_M3QBMsMbEeK31Ln-reX3cg pn=com.ibm.mq.mqxr.listener/SDK/clients/c/samples/MQTTV3ASample.c - * - * - * Licensed Materials - Property of IBM - * - * 5724-H72, - * - * (C) Copyright IBM Corp. 2010, 2012 All Rights Reserved. - * - * US Government Users Restricted Rights - Use, duplication or - * disclosure restricted by GSA ADP Schedule Contract with - * IBM Corp. - * - * ----------------------------------------------------------------- - */ - -/** - * This sample application demonstrates basic usage - * of the MQTT v3 Asynchronous Client api. - * - * It can be run in one of two modes: - * - as a publisher, sending a single message to a topic on the server - * - as a subscriber, listening for messages from the server - * - */ - - -#include -#include -#include -#include -#include -#include - -#if defined(WIN32) -#include -#define sleep Sleep -#else -#include -#include -#endif - - volatile int toStop = 0; - volatile int finished = 0; - volatile int connected = 0; - volatile int quietMode = 0; - volatile int sent = 0; - volatile int delivery = 0; - volatile MQTTAsync_token deliveredtoken; - static char clientId[24]; - struct Options - { - char* action; - char* topic; - char* message; - int qos; - char* broker; - char* port; - int message_count; - } options = - { - "publish", - NULL, - "2", - 2, - "localhost", - "1883", - 100 - }; - - void printHelp() - { - printf("Syntax:\n\n"); - printf(" MQTTV3ASample [-h] [-a publish|subscribe] [-t ] [-m ]\n"); - printf(" [-s 0|1|2] [-b ] [-p ] \n\n"); - printf(" -h Print this help text and quit\n"); - printf(" -q Quiet mode (default is false)\n"); - printf(" -a Perform the relevant action (default is publish)\n"); - printf(" -t Publish/subscribe to instead of the default\n"); - printf(" (publish: \"MQTTV3ASample/C/v3\", subscribe: \"MQTTV3ASample/#\")\n"); - printf(" -m Use this message instead of the default (\"Message from MQTTv3 C asynchronous client\")\n"); - printf(" -s Use this QoS instead of the default (2)\n"); - printf(" -b Use this name/IP address instead of the default (localhost)\n"); - printf(" -p Use this port instead of the default (1883)\n"); - printf("\nDelimit strings containing spaces with \"\"\n"); - printf("\nPublishers transmit a single message then disconnect from the broker.\n"); - printf("Subscribers remain connected to the broker and receive appropriate messages\n"); - printf("until Control-C (^C) is received from the keyboard.\n\n"); - } - - - void handleSignal(int sig) - { - toStop = 1; - } - - int messageArrived(void *context, char *topicName, int topicLen, MQTTAsync_message *message) - { - int i; - char* payloadptr; - if((sent++ % 1000) == 0) - printf("%d messages received\n", sent++); - //printf("Message arrived\n"); - //printf(" topic: %s\n", topicName); - //printf(" message: "); - - //payloadptr = message->payload; - //for(i=0; ipayloadlen; i++) - //{ - // putchar(*payloadptr++); - //} - //putchar('\n'); - MQTTAsync_freeMessage(&message); - MQTTAsync_free(topicName); - return 1; - } - - void onSubscribe(void* context, MQTTAsync_successData* response) - { - printf("Subscribe succeeded\n"); - } - - void onSubscribeFailure(void* context, MQTTAsync_failureData* response) - { - printf("Subscribe failed\n"); - finished = 1; - } - - void onDisconnect(void* context, MQTTAsync_successData* response) - { - printf("Successful disconnection\n"); - finished = 1; - } - - - void onSendFailure(void* context, MQTTAsync_failureData* response) - { - printf("onSendFailure: message with token value %d delivery failed\n", response->token); - } - - - - void onSend(void* context, MQTTAsync_successData* response) - { - static last_send = 0; - - if (response->token - last_send != 1) - printf("Error in onSend, token value %d, last_send %d\n", response->token, last_send); - - last_send++; - - if ((response->token % 1000) == 0) - printf("onSend: message with token value %d delivery confirmed\n", response->token); - } - - void deliveryComplete(void* context, MQTTAsync_token token) - { - sent++; - if ((sent % 1000) == 0) - printf("deliveryComplete: message with token value %d delivery confirmed\n", token); - if (sent != token) - printf("Error, sent %d != token %d\n", sent, token); - if (sent == options.message_count) - toStop = 1; - } - - void onConnectFailure(void* context, MQTTAsync_failureData* response) - { - printf("Connect failed\n"); - finished = 1; - } - - - void onConnect(void* context, MQTTAsync_successData* response) - { - printf("Connected\n"); - connected=1; - } - - void connectionLost(void *context, char *cause) - { - MQTTAsync client = (MQTTAsync)context; - MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; - int rc; - - printf("\nConnection lost\n"); - printf(" cause: %s\n", cause); - - printf("Reconnecting\n"); - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - conn_opts.onSuccess = onConnect; - conn_opts.onFailure = onConnectFailure; - conn_opts.context = client; - conn_opts.retryInterval = 1000; - if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start connect, return code %d\n", rc); - finished = 1; - } - } - - -void handleTrace(enum MQTTASYNC_TRACE_LEVELS level, char* message) -{ - printf("%s\n", message); -} - - -/** - * The main entry point of the sample. - * - * This method handles parsing the arguments specified on the - * command-line before performing the specified action. - */ - int main(int argc, char** argv) - { - int rc = 0; - int ch; - char url[256]; - - // Default settings: - int i=0; - - MQTTAsync client; - MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; - MQTTAsync_message pubmsg = MQTTAsync_message_initializer; - MQTTAsync_token token; - - signal(SIGINT, handleSignal); - signal(SIGTERM, handleSignal); - - quietMode = 0; - // Parse the arguments - - for (i=1; i 2) - { - printf("Invalid QoS: %d\n", options.qos); - printHelp(); - return 255; - } - if (options.topic == NULL || ( options.topic != NULL && strlen(options.topic) == 0) ) - { - // Set the default topic according to the specified action - if (strcmp(options.action, "publish") == 0) - options.topic = "MQTTV3ASample/C/v3"; - else - options.topic = "MQTTV3ASample/#"; - } - - // Construct the full broker URL and clientId - sprintf(url, "tcp://%s:%s", options.broker, options.port); - sprintf(clientId, "SampleCV3A_%s", options.action); - - - MQTTAsync_create(&client, url, clientId, MQTTCLIENT_PERSISTENCE_NONE, NULL); - - MQTTAsync_setTraceCallback(handleTrace); - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); - - MQTTAsync_setCallbacks(client, client, connectionLost, messageArrived, deliveryComplete); - - conn_opts.cleansession = 0; - conn_opts.onSuccess = onConnect; - conn_opts.onFailure = onConnectFailure; - conn_opts.context = client; - conn_opts.keepAliveInterval = 0; - conn_opts.retryInterval = 0; - //conn_opts.maxInflight= 30; - - if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start connect, return code %d\n", rc); - goto exit; - } - printf("Waiting for connect\n"); - while (connected == 0 && finished == 0 && toStop == 0) { - printf("Waiting for connect: %d %d %d\n", connected, finished, toStop); - usleep(10000L); - } - - MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; - printf("Waiting for connect: %d %d %d\n", connected, finished, toStop); - - printf("Successful connection\n"); - - if (connected == 1 && strcmp(options.action, "publish") == 0) - { - unsigned long i; - struct timeval tv; - gettimeofday(&tv,NULL); - printf("start seconds : %ld\n",tv.tv_sec); - for (i = 0; i < options.message_count; i++) - { - opts.onSuccess = onSend; - opts.onFailure = onSendFailure; - opts.context = client; - pubmsg.payload = options.message; - pubmsg.payloadlen = strlen(options.message); - pubmsg.qos = options.qos; - pubmsg.retained = 0; - deliveredtoken = 0; - usleep(100); - - if ((rc = MQTTAsync_sendMessage(client, options.topic, &pubmsg, &opts)) - != MQTTASYNC_SUCCESS) - { - printf("Failed to start sendMessage, return code %d\n", rc); - exit(EXIT_FAILURE); - } - } - - gettimeofday(&tv,NULL); - - printf("end seconds : %ld\n",tv.tv_sec); - } else if (strcmp(options.action, "subscribe") == 0) { - opts.onSuccess = onSubscribe; - opts.onFailure = onSubscribeFailure; - opts.context = client; - if ((rc = MQTTAsync_subscribe(client, options.topic, options.qos, &opts)) != MQTTASYNC_SUCCESS) { - printf("Failed to subscribe, return code %d\n", rc); - exit(EXIT_FAILURE); - } - } - - while (!finished) - { -#if defined(WIN32) - Sleep(100); -#else - usleep(1000L); -#endif - if (toStop == 1) - { - MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer; - - opts.onSuccess = onDisconnect; - opts.context = client; - printf("Entering disconnection phase\n"); - if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS) - { - printf("Failed to start disconnect, return code %d\n", rc); - exit(EXIT_FAILURE); - } - toStop = 0; - } - } - - exit: - printf("calling destroy\n"); - MQTTAsync_destroy(&client); - return rc; - } From 9dc33e62842b4386529349c34d9349aeaf9a31fc Mon Sep 17 00:00:00 2001 From: fpagliughi Date: Sat, 20 Jul 2019 12:43:44 -0400 Subject: [PATCH 33/58] #680 Async creation accepts struct_version 1 and handles versions properly --- src/MQTTAsync.c | 6 ++++-- src/MQTTAsync.h | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index ee6b188c6..6b305b50c 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -508,7 +508,8 @@ int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const } } - if (options && (strncmp(options->struct_id, "MQCO", 4) != 0 || options->struct_version != 0)) + if (options && (strncmp(options->struct_id, "MQCO", 4) != 0 || + options->struct_version < 0 || options->struct_version > 1)) { rc = MQTTASYNC_BAD_STRUCTURE; goto exit; @@ -571,7 +572,8 @@ int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const { m->createOptions = malloc(sizeof(MQTTAsync_createOptions)); memcpy(m->createOptions, options, sizeof(MQTTAsync_createOptions)); - m->c->MQTTVersion = options->MQTTVersion; + if (options->struct_version > 0) + m->c->MQTTVersion = options->MQTTVersion; } #if !defined(NO_PERSISTENCE) diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 8964aefd3..9f33a7d8e 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -838,7 +838,9 @@ typedef struct int MQTTVersion; } MQTTAsync_createOptions; -#define MQTTAsync_createOptions_initializer { {'M', 'Q', 'C', 'O'}, 0, 0, 100, MQTTVERSION_DEFAULT } +#define MQTTAsync_createOptions_initializer { {'M', 'Q', 'C', 'O'}, 1, 0, 100, MQTTVERSION_DEFAULT } + +#define MQTTAsync_createOptions_initializer5 { {'M', 'Q', 'C', 'O'}, 1, 0, 100, MQTTVERSION_5 } DLLExport int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const char* clientId, From 62e7f5c0353619965511e9b3551480df8b2fbad2 Mon Sep 17 00:00:00 2001 From: fpagliughi Date: Sat, 20 Jul 2019 12:51:38 -0400 Subject: [PATCH 34/58] #681 The Eclipse MQTT sandbox server moved to new address, 'mqtt.eclipse.org' --- src/samples/MQTTAsync_publish.c | 2 +- test/test1.c | 2 +- test/test4.c | 2 +- test/test9.c | 2 +- test/test95.c | 2 +- test/test_sync_session_present.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/samples/MQTTAsync_publish.c b/src/samples/MQTTAsync_publish.c index 4d2bb44e7..4c4792695 100644 --- a/src/samples/MQTTAsync_publish.c +++ b/src/samples/MQTTAsync_publish.c @@ -29,7 +29,7 @@ #include #endif -#define ADDRESS "tcp://iot.eclipse.org:1883" +#define ADDRESS "tcp://mqtt.eclipse.org:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" diff --git a/test/test1.c b/test/test1.c index 87704622c..0e4e2e9e5 100644 --- a/test/test1.c +++ b/test/test1.c @@ -56,7 +56,7 @@ struct Options int iterations; } options = { - "tcp://iot.eclipse.org:1883", + "tcp://mqtt.eclipse.org:1883", NULL, "tcp://localhost:1883", 0, diff --git a/test/test4.c b/test/test4.c index 0948461c1..953ec209a 100644 --- a/test/test4.c +++ b/test/test4.c @@ -54,7 +54,7 @@ struct Options int iterations; } options = { - "iot.eclipse.org:1883", + "mqtt.eclipse.org:1883", 0, -1, 10000, diff --git a/test/test9.c b/test/test9.c index b5118ab62..9bf640111 100644 --- a/test/test9.c +++ b/test/test9.c @@ -56,7 +56,7 @@ struct Options int test_no; } options = { - "iot.eclipse.org:1883", + "mqtt.eclipse.org:1883", "localhost:1883", 0, 0, diff --git a/test/test95.c b/test/test95.c index a8e6523e4..472c2aa61 100644 --- a/test/test95.c +++ b/test/test95.c @@ -57,7 +57,7 @@ struct Options int test_no; } options = { - "iot.eclipse.org:1883", + "mqtt.eclipse.org:1883", "localhost:1883", 0, 0, diff --git a/test/test_sync_session_present.c b/test/test_sync_session_present.c index 544169b61..90d9185cb 100644 --- a/test/test_sync_session_present.c +++ b/test/test_sync_session_present.c @@ -60,7 +60,7 @@ struct Options int reconnect_period; } options = { - "tcp://iot.eclipse.org:1883", + "tcp://mqtt.eclipse.org:1883", NULL, "tcp://localhost:1883", "cli/test", From b5f1f7dff3ce253307bedc48dce3c6e3c3dd47cc Mon Sep 17 00:00:00 2001 From: Dom Postorivo Date: Fri, 19 Jul 2019 20:59:27 -0400 Subject: [PATCH 35/58] Add random jitter to exponential backoff time Signed-off-by: Dom Postorivo --- src/MQTTAsync.c | 87 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 11 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index ee6b188c6..dcbdf4cf8 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -219,6 +219,26 @@ START_TIME_TYPE MQTTAsync_start_clock(void) } #endif +#if defined(WIN32) || defined(WIN64) +void MQTTAsync_init_rand(void) +{ + START_TIME_TYPE now = MQTTAsync_start_clock(); + srand(now); +} +#elif defined(AIX) +void MQTTAsync_init_rand(void) +{ + START_TIME_TYPE now = MQTTAsync_start_clock(); + srand(now.tv_nsec); +} +#else +void MQTTAsync_init_rand(void) +{ + START_TIME_TYPE now = MQTTAsync_start_clock(); + srand(now.tv_usec); +} +#endif + #if defined(WIN32) || defined(WIN64) long MQTTAsync_elapsed(DWORD milliseconds) @@ -249,7 +269,6 @@ long MQTTAsync_elapsed(struct timeval start) } #endif - typedef struct { MQTTAsync_message* msg; @@ -352,6 +371,7 @@ typedef struct MQTTAsync_struct int connectTimeout; int currentInterval; + int currentIntervalBase; START_TIME_TYPE lastConnectionFailedTime; int retrying; int reconnectNow; @@ -427,6 +447,45 @@ void MQTTAsync_sleep(long milliseconds) } +// Add random amount of jitter for exponential backoff on retry +// Jitter value will be +/- 20% of "base" interval, including max interval +// https://www.awsarchitectureblog.com/2015/03/backoff.html +// http://ee.lbl.gov/papers/sync_94.pdf +int MQTTAsync_randomJitter(int currentIntervalBase, int minInterval, int maxInterval) +{ + int max_sleep = min(maxInterval, currentIntervalBase) * 1.2; // (e.g. 72 if base > 60) + int min_sleep = max(minInterval, currentIntervalBase) / 1.2; // (e.g. 48 if base > 60) + + if (min_sleep >= max_sleep) // shouldn't happen, but just incase + { + return min_sleep; + } + + // random_between(min_sleep, max_sleep) + // http://stackoverflow.com/questions/2509679/how-to-generate-a-random-number-from-within-a-range + int r; + int range = max_sleep - min_sleep + 1; + if (range > RAND_MAX) + { + range = RAND_MAX; + } + + int buckets = RAND_MAX / range; + int limit = buckets * range; + + /* Create equal size buckets all in a row, then fire randomly towards + * the buckets until you land in one of them. All buckets are equally + * likely. If you land off the end of the line of buckets, try again. */ + do + { + r = rand(); + } while (r >= limit); + + int randResult = r / buckets; + return min_sleep + randResult; +} + + /** * List callback function for comparing clients by socket * @param a first integer value @@ -598,6 +657,8 @@ int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const int MQTTAsync_create(MQTTAsync* handle, const char* serverURI, const char* clientId, int persistence_type, void* persistence_context) { + MQTTAsync_init_rand(); + return MQTTAsync_createWithOptions(handle, serverURI, clientId, persistence_type, persistence_context, NULL); } @@ -1029,12 +1090,15 @@ static void MQTTAsync_startConnectRetry(MQTTAsyncs* m) { m->lastConnectionFailedTime = MQTTAsync_start_clock(); if (m->retrying) - m->currentInterval = min(m->currentInterval * 2, m->maxRetryInterval); + { + m->currentIntervalBase = min(m->currentIntervalBase * 2, m->maxRetryInterval); + } else { - m->currentInterval = m->minRetryInterval; + m->currentIntervalBase = m->minRetryInterval; m->retrying = 1; } + m->currentInterval = MQTTAsync_randomJitter(m->currentIntervalBase, m->minRetryInterval, m->maxRetryInterval); } } @@ -1052,12 +1116,13 @@ int MQTTAsync_reconnect(MQTTAsync handle) if (m->shouldBeConnected) { m->reconnectNow = 1; - if (m->retrying == 0) - { - m->currentInterval = m->minRetryInterval; - m->retrying = 1; - } - rc = MQTTASYNC_SUCCESS; + if (m->retrying == 0) + { + m->currentIntervalBase = m->minRetryInterval; + m->currentInterval = m->minRetryInterval; + m->retrying = 1; + } + rc = MQTTASYNC_SUCCESS; } } else @@ -1069,9 +1134,9 @@ int MQTTAsync_reconnect(MQTTAsync handle) conn->command = m->connect; /* make sure that the version attempts are restarted */ if (m->c->MQTTVersion == MQTTVERSION_DEFAULT) - conn->command.details.conn.MQTTVersion = 0; + conn->command.details.conn.MQTTVersion = 0; MQTTAsync_addCommand(conn, sizeof(m->connect)); - rc = MQTTASYNC_SUCCESS; + rc = MQTTASYNC_SUCCESS; } MQTTAsync_unlock_mutex(mqttasync_mutex); From c223d91a049589cd65c2bfefd275e32ae754fec7 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 22 Jul 2019 22:13:25 +0100 Subject: [PATCH 36/58] Error handling when properties not read properly #563 --- src/MQTTPacket.c | 22 +++++++++++++++++----- src/MQTTPacketOut.c | 13 ++++++++++--- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/MQTTPacket.c b/src/MQTTPacket.c index 4c309a231..9a1837e34 100644 --- a/src/MQTTPacket.c +++ b/src/MQTTPacket.c @@ -520,11 +520,13 @@ int MQTTPacket_send_disconnect(Clients* client, enum MQTTReasonCodes reason, MQT */ void* MQTTPacket_publish(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen) { - Publish* pack = malloc(sizeof(Publish)); + Publish* pack = NULL; char* curdata = data; char* enddata = &data[datalen]; FUNC_ENTRY; + if ((pack = malloc(sizeof(Publish))) == NULL) + goto exit; memset(pack, '\0', sizeof(Publish)); pack->MQTTVersion = MQTTVersion; pack->header.byte = aHeader; @@ -544,8 +546,11 @@ void* MQTTPacket_publish(int MQTTVersion, unsigned char aHeader, char* data, siz pack->properties = props; if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1) { - free(pack); - pack = NULL; + if (pack->properties.array) + free(pack->properties.array); + if (pack) + free(pack); + pack = NULL; /* signal protocol error */ goto exit; } } @@ -736,11 +741,13 @@ int MQTTPacket_send_pubcomp(int msgid, networkHandles* net, const char* clientID */ void* MQTTPacket_ack(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen) { - Ack* pack = malloc(sizeof(Ack)); + Ack* pack = NULL; char* curdata = data; char* enddata = &data[datalen]; FUNC_ENTRY; + if ((pack = malloc(sizeof(Ack))) == NULL) + goto exit; pack->MQTTVersion = MQTTVersion; pack->header.byte = aHeader; if (pack->header.bits.type != DISCONNECT) @@ -759,11 +766,16 @@ void* MQTTPacket_ack(int MQTTVersion, unsigned char aHeader, char* data, size_t { if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1) { - free(pack); + if (pack->properties.array) + free(pack->properties.array); + if (pack) + free(pack); pack = NULL; /* signal protocol error */ + goto exit; } } } +exit: FUNC_EXIT; return pack; } diff --git a/src/MQTTPacketOut.c b/src/MQTTPacketOut.c index 723707798..335aecc47 100644 --- a/src/MQTTPacketOut.c +++ b/src/MQTTPacketOut.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -138,11 +138,13 @@ int MQTTPacket_send_connect(Clients* client, int MQTTVersion, */ void* MQTTPacket_connack(int MQTTVersion, unsigned char aHeader, char* data, size_t datalen) { - Connack* pack = malloc(sizeof(Connack)); + Connack* pack = NULL; char* curdata = data; char* enddata = &data[datalen]; FUNC_ENTRY; + if ((pack = malloc(sizeof(Connack))) == NULL) + goto exit; pack->MQTTVersion = MQTTVersion; pack->header.byte = aHeader; pack->flags.all = readChar(&curdata); /* connect flags */ @@ -161,10 +163,15 @@ void* MQTTPacket_connack(int MQTTVersion, unsigned char aHeader, char* data, siz pack->properties = props; if (MQTTProperties_read(&pack->properties, &curdata, enddata) != 1) { - free(pack); + if (pack->properties.array) + free(pack->properties.array); + if (pack) + free(pack); pack = NULL; /* signal protocol error */ + goto exit; } } +exit: FUNC_EXIT; return pack; } From e748cd886b5f32a6f2dface4569fb18b9506bab6 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Mon, 22 Jul 2019 22:14:52 +0100 Subject: [PATCH 37/58] Properties free error #637 --- src/MQTTAsync.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index ea8425417..5a133cf79 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -841,12 +841,12 @@ static int MQTTAsync_persistCommand(MQTTAsync_queuedCommand* qcmd) Log(LOG_ERROR, 0, "Error persisting command, rc %d", rc); qcmd->seqno = aclient->command_seqno; } + if (props_allocated > 0) + free(bufs[props_allocated]); if (lens) free(lens); if (bufs) free(bufs); - if (props_allocated > 0) - free(bufs[props_allocated]); FUNC_EXIT_RC(rc); return rc; } From 282b54c3a9bf06eda74d53ce96440fda7857d933 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 23 Jul 2019 12:22:06 +0100 Subject: [PATCH 38/58] Correct property integer types to unsigned #559 --- src/MQTTPacket.c | 4 ++-- src/MQTTPacket.h | 4 ++-- src/MQTTProperties.c | 4 ++-- src/MQTTProperties.h | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/MQTTPacket.c b/src/MQTTPacket.c index 9a1837e34..57b174935 100644 --- a/src/MQTTPacket.c +++ b/src/MQTTPacket.c @@ -957,7 +957,7 @@ int MQTTPacket_VBIlen(int rem_len) * @param value the decoded length returned * @return the number of bytes read from the socket */ -int MQTTPacket_VBIdecode(int (*getcharfn)(char*, int), int* value) +int MQTTPacket_VBIdecode(int (*getcharfn)(char*, int), unsigned int* value) { char c; int multiplier = 1; @@ -997,7 +997,7 @@ int bufchar(char* c, int count) } -int MQTTPacket_decodeBuf(char* buf, int* value) +int MQTTPacket_decodeBuf(char* buf, unsigned int* value) { bufptr = buf; return MQTTPacket_VBIdecode(bufchar, value); diff --git a/src/MQTTPacket.h b/src/MQTTPacket.h index 350886e39..eb070a212 100644 --- a/src/MQTTPacket.h +++ b/src/MQTTPacket.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. + * Copyright (c) 2009, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -263,7 +263,7 @@ int readInt4(char** pptr); void writeMQTTLenString(char** pptr, MQTTLenString lenstring); int MQTTLenStringRead(MQTTLenString* lenstring, char** pptr, char* enddata); int MQTTPacket_VBIlen(int rem_len); -int MQTTPacket_decodeBuf(char* buf, int* value); +int MQTTPacket_decodeBuf(char* buf, unsigned int* value); #include "MQTTPacketOut.h" diff --git a/src/MQTTProperties.c b/src/MQTTProperties.c index 797e360ea..876128be1 100644 --- a/src/MQTTProperties.c +++ b/src/MQTTProperties.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 IBM Corp. + * Copyright (c) 2017, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -273,7 +273,7 @@ int MQTTProperty_read(MQTTProperty* prop, char** pptr, char* enddata) int MQTTProperties_read(MQTTProperties* properties, char** pptr, char* enddata) { int rc = 0; - int remlength = 0; + unsigned int remlength = 0; FUNC_ENTRY; /* we assume an initialized properties structure */ diff --git a/src/MQTTProperties.h b/src/MQTTProperties.h index deec12451..7e83638b8 100644 --- a/src/MQTTProperties.h +++ b/src/MQTTProperties.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 IBM Corp. + * Copyright (c) 2017, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -102,9 +102,9 @@ typedef struct enum MQTTPropertyCodes identifier; /**< The MQTT V5 property id. A multi-byte integer. */ /** The value of the property, as a union of the different possible types. */ union { - char byte; /**< holds the value of a byte property type */ - short integer2; /**< holds the value of a 2 byte integer property type */ - int integer4; /**< holds the value of a 4 byte integer property type */ + unsigned char byte; /**< holds the value of a byte property type */ + unsigned short integer2; /**< holds the value of a 2 byte integer property type */ + unsigned int integer4; /**< holds the value of a 4 byte integer property type */ struct { MQTTLenString data; /**< The value of a string property, or the name of a user property. */ MQTTLenString value; /**< The value of a user property. */ From 0168090fc0ac0d3b01929b7409011dc6d8199f00 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 30 Jul 2019 16:49:28 +0100 Subject: [PATCH 39/58] Correct tests running in test5.c, including capath tests --- test/CMakeLists.txt | 17 ++++- test/ssl/capath/374b031c.0 | 1 + test/ssl/capath/ab88c291.0 | 1 + test/ssl/capath/server.pem | 60 +++++++++++++++++ test/ssl/capath/test-root-ca.pem | 17 +++++ test/test5.c | 109 +++++++++++++++++-------------- 6 files changed, 153 insertions(+), 52 deletions(-) create mode 120000 test/ssl/capath/374b031c.0 create mode 120000 test/ssl/capath/ab88c291.0 create mode 100644 test/ssl/capath/server.pem create mode 100644 test/ssl/capath/test-root-ca.pem diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 556a69444..9f9073b8f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -463,12 +463,12 @@ ADD_TEST( ) ADD_TEST( - NAME test5-5-server-verify-with-capath + NAME test5-6-multiple-connections COMMAND test5 "--test_no" "9" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" ) ADD_TEST( - NAME test5-6-server-verify-with-capath + NAME test5-7-big-messages COMMAND test5 "--test_no" "10" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--server_key" "${CERTDIR}/test-root-ca.crt" ) @@ -477,6 +477,17 @@ ADD_TEST( # COMMAND test5 "--test_no" "11" "--hostname" ${MQTT_SSL_HOSTNAME} #) +ADD_TEST( + NAME test5-5-server-verify-with-capath + COMMAND test5 "--test_no" "12" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--capath" "${CERTDIR}/capath" +) + +ADD_TEST( + NAME test5-6-server-verify-with-capath + COMMAND test5 "--test_no" "13" "--hostname" ${MQTT_SSL_HOSTNAME} "--client_key" "${CERTDIR}/client.pem" "--capath" "${CERTDIR}/notexist" +) + + SET_TESTS_PROPERTIES( test5-1-ssl-connection-to-no-SSL-server test5-2a-multual-ssl-auth-certificates-in-place @@ -486,6 +497,8 @@ SET_TESTS_PROPERTIES( test5-3a-server-auth-server-cert-in-client-store test5-3b-server-auth-client-missing-broker-cert test5-4-accept-invalid-certificates + test5-6-multiple-connections + test5-7-big-messages test5-5-server-verify-with-capath test5-6-server-verify-with-capath # test5-8-psk-ssl-auth diff --git a/test/ssl/capath/374b031c.0 b/test/ssl/capath/374b031c.0 new file mode 120000 index 000000000..8f18c71de --- /dev/null +++ b/test/ssl/capath/374b031c.0 @@ -0,0 +1 @@ +server.pem \ No newline at end of file diff --git a/test/ssl/capath/ab88c291.0 b/test/ssl/capath/ab88c291.0 new file mode 120000 index 000000000..708ac696b --- /dev/null +++ b/test/ssl/capath/ab88c291.0 @@ -0,0 +1 @@ +test-root-ca.pem \ No newline at end of file diff --git a/test/ssl/capath/server.pem b/test/ssl/capath/server.pem new file mode 100644 index 000000000..b6009a774 --- /dev/null +++ b/test/ssl/capath/server.pem @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=GB, ST=Derbyshire, O=Mosquitto Project, OU=Testing, CN=Signing CA + Validity + Not Before: Mar 1 18:53:44 2018 GMT + Not After : Feb 28 18:53:44 2023 GMT + Subject: C=GB, ST=Nottinghamshire, L=Nottingham, O=Server, OU=Production, CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:c9:18:e1:6a:c4:45:58:0e:b7:65:3a:b8:6f:df: + 0a:d8:5d:18:aa:40:08:d6:d5:79:fa:ca:79:6b:9e: + ce:55:85:c9:d5:4f:bb:7f:5a:81:c8:3c:5d:aa:ed: + 7f:48:87:c2:f1:4c:62:00:c3:8d:9a:a3:c2:77:25: + c6:70:cc:ef:d1:8f:17:7d:1b:c3:ab:66:3e:90:f0: + 44:e3:85:8b:77:86:21:b2:dd:0b:2c:ed:a0:16:a0: + 16:63:49:b9:bb:90:45:44:f1:f7:1e:ad:57:1c:45: + a2:08:99:13:05:e3:13:76:ef:f3:cd:f3:3a:21:73: + 21:75:0a:2d:58:e2:0a:3a:3d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 7E:42:6C:12:CB:42:12:36:54:03:29:B6:D8:21:CA:E1:65:48:C5:67 + X509v3 Authority Key Identifier: + keyid:9E:54:3E:E5:2F:E5:EA:40:4A:FC:37:96:6C:45:BB:1A:79:0E:CA:AB + + Signature Algorithm: sha256WithRSAEncryption + 08:e1:a9:a0:e9:c4:1b:65:8d:b0:71:60:68:18:d8:af:49:8f: + 0b:41:62:bb:f8:23:71:65:f2:c7:cf:59:23:63:48:fa:ba:26: + 5f:2d:2e:4c:18:e4:f0:6e:cb:38:be:51:d0:e2:cc:76:ab:f6: + 13:c2:49:68:e2:ef:da:86:a9:3d:80:29:9f:ee:33:be:cd:4c: + b2:4c:14:04:e3:46:46:46:ec:c1:4a:63:de:f3:5a:7b:0f:28: + a1:92:c8:96:07:b3:73:96:f4:9e:a0:bf:36:ea:f1:1a:8b:f7: + d5:ed:6c:e2:bf:cd:61:bc:a4:ca:ee:fa:75:af:ad:4c:54:4b: + af:18 +-----BEGIN CERTIFICATE----- +MIICzDCCAjWgAwIBAgIBATANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJHQjET +MBEGA1UECAwKRGVyYnlzaGlyZTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3Qx +EDAOBgNVBAsMB1Rlc3RpbmcxEzARBgNVBAMMClNpZ25pbmcgQ0EwHhcNMTgwMzAx +MTg1MzQ0WhcNMjMwMjI4MTg1MzQ0WjB2MQswCQYDVQQGEwJHQjEYMBYGA1UECAwP +Tm90dGluZ2hhbXNoaXJlMRMwEQYDVQQHDApOb3R0aW5naGFtMQ8wDQYDVQQKDAZT +ZXJ2ZXIxEzARBgNVBAsMClByb2R1Y3Rpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyRjhasRFWA63ZTq4b98K2F0YqkAI +1tV5+sp5a57OVYXJ1U+7f1qByDxdqu1/SIfC8UxiAMONmqPCdyXGcMzv0Y8XfRvD +q2Y+kPBE44WLd4Yhst0LLO2gFqAWY0m5u5BFRPH3Hq1XHEWiCJkTBeMTdu/zzfM6 +IXMhdQotWOIKOj0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYd +T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFH5CbBLLQhI2 +VAMpttghyuFlSMVnMB8GA1UdIwQYMBaAFJ5UPuUv5epASvw3lmxFuxp5DsqrMA0G +CSqGSIb3DQEBCwUAA4GBAAjhqaDpxBtljbBxYGgY2K9JjwtBYrv4I3Fl8sfPWSNj +SPq6Jl8tLkwY5PBuyzi+UdDizHar9hPCSWji79qGqT2AKZ/uM77NTLJMFATjRkZG +7MFKY97zWnsPKKGSyJYHs3OW9J6gvzbq8RqL99XtbOK/zWG8pMru+nWvrUxUS68Y +-----END CERTIFICATE----- diff --git a/test/ssl/capath/test-root-ca.pem b/test/ssl/capath/test-root-ca.pem new file mode 100644 index 000000000..02ec098ac --- /dev/null +++ b/test/ssl/capath/test-root-ca.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICtDCCAh2gAwIBAgIJAObVjC0tPL4iMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNV +BAYTAkdCMRMwEQYDVQQIDApEZXJieXNoaXJlMQ4wDAYDVQQHDAVEZXJieTEaMBgG +A1UECgwRTW9zcXVpdHRvIFByb2plY3QxEDAOBgNVBAsMB1Rlc3RpbmcxEDAOBgNV +BAMMB1Jvb3QgQ0EwIBcNMTgwMzAxMTg1MzM2WhgPMjEwMDA0MjAxODUzMzZaMHIx +CzAJBgNVBAYTAkdCMRMwEQYDVQQIDApEZXJieXNoaXJlMQ4wDAYDVQQHDAVEZXJi +eTEaMBgGA1UECgwRTW9zcXVpdHRvIFByb2plY3QxEDAOBgNVBAsMB1Rlc3Rpbmcx +EDAOBgNVBAMMB1Jvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANSZ +3aRYdHcnta24XXJGfomsg2OpYys3KkqK76aWEwhqRvdH2m54yBvHTZ2LsMLQro0q +r4oGLyvlupC9fxwQF4ZDFHrn7VbxU947V+cipGkRaECXiGVO1ngUSpKti8nrIUkn +FXkLmVaGuVv1jVOGBi6/6f3ct6LsNyFqXzaSw9DtAgMBAAGjUDBOMB0GA1UdDgQW +BBQctE6LhA0eD8TM9BeH28ryVfE0OTAfBgNVHSMEGDAWgBQctE6LhA0eD8TM9BeH +28ryVfE0OTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAHVShEeqQRjP +IoMU8MFnnC1ZadADvSn1E6gRR7eoNU0MeMpTYmTA+TIklEzhaRHSkQqyPHAe/YMl +WLmq1NqyxPv9uKekVlatJxYbm1ME4e+wGs3U9OGsIKX0nFcBO8iqpj5s7GZmSYyY +u1YJnq1oe0C5IblVB9amcoB743/YyMme +-----END CERTIFICATE----- diff --git a/test/test5.c b/test/test5.c index 9a48ce0fb..6e9440ba8 100644 --- a/test/test5.c +++ b/test/test5.c @@ -79,8 +79,8 @@ struct Options "ssl://m2m.eclipse.org:18888", "../../../test/ssl/client.pem", NULL, - "../../../test/ssl/test-root-ca.crt", - "../../../test/ssl/", + NULL, // "../../../test/ssl/test-root-ca.crt", + NULL, // "../../../test/ssl/capath", NULL, 0, 0, @@ -140,6 +140,13 @@ void getopts(int argc, char** argv) else usage(); } + else if (strcmp(argv[count], "--capath") == 0) + { + if (++count < argc) + options.capath = argv[count]; + else + usage(); + } else if (strcmp(argv[count], "--verbose") == 0) { options.verbose = 1; @@ -2255,52 +2262,6 @@ int test8(struct Options options) } -void handleTrace(enum MQTTASYNC_TRACE_LEVELS level, char* message) -{ - printf("%s\n", message); -} - -int main(int argc, char** argv) -{ - int* numtests = &tests; - int rc = 0; - int (*tests[])() = - { NULL, test1, test2a, test2b, test2c, test2d, test3a, test3b, test4, /* test5a, - test5b, test5c, */ test6, test7, test8 }; - - xml = fopen("TEST-test5.xml", "w"); - fprintf(xml, "\n", (int)ARRAY_SIZE(tests) - 1); - - MQTTAsync_setTraceCallback(handleTrace); - getopts(argc, argv); - - if (options.test_no == 0) - { /* run all the tests */ - for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no) - { - failures = 0; - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); - rc += tests[options.test_no](options); /* return number of failures. 0 = test succeeded */ - } - } - else - { - MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); - rc = tests[options.test_no](options); /* run just the selected test */ - } - - MyLog(LOGA_INFO, "Total tests run: %d", *numtests); - if (rc == 0) - MyLog(LOGA_INFO, "verdict pass"); - else - MyLog(LOGA_INFO, "verdict fail"); - - fprintf(xml, "\n"); - fclose(xml); - - return rc; -} - /********************************************************************* Test9: Mutual SSL Authentication - Testing CApath @@ -2330,7 +2291,7 @@ int test9(struct Options options) int rc = 0; failures = 0; - MyLog(LOGA_INFO, "Starting test 9 - Mutual SSL authentication"); + MyLog(LOGA_INFO, "Starting test 9 - Mutual SSL authentication with CApath"); fprintf(xml, "\n", (int)ARRAY_SIZE(tests) - 1); + + MQTTAsync_setTraceCallback(handleTrace); + getopts(argc, argv); + + if (options.test_no == 0) + { /* run all the tests */ + for (options.test_no = 1; options.test_no < ARRAY_SIZE(tests); ++options.test_no) + { + failures = 0; + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + rc += tests[options.test_no](options); /* return number of failures. 0 = test succeeded */ + } + } + else + { + MQTTAsync_setTraceLevel(MQTTASYNC_TRACE_ERROR); + rc = tests[options.test_no](options); /* run just the selected test */ + } + + MyLog(LOGA_INFO, "Total tests run: %d", *numtests); + if (rc == 0) + MyLog(LOGA_INFO, "verdict pass"); + else + MyLog(LOGA_INFO, "verdict fail"); + + fprintf(xml, "\n"); + fclose(xml); + + return rc; +} + /* Local Variables: */ /* indent-tabs-mode: t */ /* c-basic-offset: 8 */ From 99d896fc5659412ffa870d2aeb27223d9d08e276 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Tue, 30 Jul 2019 20:40:41 +0100 Subject: [PATCH 40/58] Reduce size of message in big message test for Travis MacOS test --- test/test5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test5.c b/test/test5.c index 6e9440ba8..9630f065e 100644 --- a/test/test5.c +++ b/test/test5.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2018 IBM Corp. + * Copyright (c) 2012, 2019 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -84,7 +84,7 @@ struct Options NULL, 0, 0, - 5000000, + 1000000, 0, }; From 7044c2f905ca5f80160bc0b9db87564920517076 Mon Sep 17 00:00:00 2001 From: Ian Craggs Date: Wed, 31 Jul 2019 12:07:24 +0100 Subject: [PATCH 41/58] Change version numbers to 1.3.1 in prep for release --- CMakeLists.txt | 4 ++-- Makefile | 4 ++-- build.xml | 4 ++-- conanfile.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b53745b94..9817ff1f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ #******************************************************************************* -# Copyright (c) 2015, 2018 logi.cals GmbH and others +# Copyright (c) 2015, 2019 logi.cals GmbH and others # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 @@ -28,7 +28,7 @@ SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") ## build settings SET(PAHO_VERSION_MAJOR 1) SET(PAHO_VERSION_MINOR 3) -SET(PAHO_VERSION_PATCH 0) +SET(PAHO_VERSION_PATCH 1) SET(CLIENT_VERSION ${PAHO_VERSION_MAJOR}.${PAHO_VERSION_MINOR}.${PAHO_VERSION_PATCH}) INCLUDE(GNUInstallDirs) diff --git a/Makefile b/Makefile index 35fb8d2fa..0679006e4 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ #******************************************************************************* -# Copyright (c) 2009, 2018 IBM Corp. +# Copyright (c) 2009, 2019 IBM Corp. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,7 @@ SHELL = /bin/sh .PHONY: clean, mkdir, install, uninstall, html ifndef release.version - release.version = 1.3.0 + release.version = 1.3.1 endif # determine current platform diff --git a/build.xml b/build.xml index 0df93c9cd..71631e995 100644 --- a/build.xml +++ b/build.xml @@ -1,5 +1,5 @@