diff --git a/src/MQTTAsync.c b/src/MQTTAsync.c index c548ae31c..2f2927d02 100644 --- a/src/MQTTAsync.c +++ b/src/MQTTAsync.c @@ -816,6 +816,12 @@ int MQTTAsync_connect(MQTTAsync handle, const MQTTAsync_connectOptions* options) m->c->sslopts->protos = (const unsigned char*)MQTTStrdup((const char*)options->ssl->protos); m->c->sslopts->protos_len = options->ssl->protos_len; } + + if (options->ssl->ssl_keylog_cb) + { + m->c->sslopts->ssl_keylog_cb = options->ssl->ssl_keylog_cb; + m->c->sslopts->ssl_keylog_context = options->ssl->ssl_keylog_context; + } } #else if (options->struct_version != 0 && options->ssl) diff --git a/src/MQTTAsync.h b/src/MQTTAsync.h index 3c7f0995f..8c712e3ca 100644 --- a/src/MQTTAsync.h +++ b/src/MQTTAsync.h @@ -1072,12 +1072,13 @@ typedef struct /** The eyecatcher for this structure. Must be MQTS */ char struct_id[4]; - /** The version number of this structure. Must be 0, 1, 2, 3, 4 or 5. + /** The version number of this structure. Must be 0, 1, 2, 3, 4, 5 or 6. * 0 means no sslVersion * 1 means no verify, CApath * 2 means no ssl_error_context, ssl_error_cb * 3 means no ssl_psk_cb, ssl_psk_context, disableDefaultTrustStore * 4 means no protos, protos_len + * 5 means no ssl_keylog_context or ssl_keylog_cb */ int struct_version; @@ -1176,9 +1177,23 @@ typedef struct * Exists only if struct_version >= 5 */ unsigned int protos_len; + + /** + * Callback function for handling the SSL keylogs. + * line: the SSL keylog line. + * ctx: pointer to context data set to ssl_keylog_context by the application. + * Exists only if struct_version >= 6 + */ + void (*ssl_keylog_cb) (const char *line, void *ctx); + + /** + * Application-specific contex for ssl_keylog_cb + * Exists only if struct_version >= 6 + */ + void* ssl_keylog_context; } MQTTAsync_SSLOptions; -#define MQTTAsync_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 5, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0 } +#define MQTTAsync_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 5, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL } /** Utility structure where name/value pairs are needed */ typedef struct diff --git a/src/MQTTClient.c b/src/MQTTClient.c index 32d59c3b8..f43fef622 100644 --- a/src/MQTTClient.c +++ b/src/MQTTClient.c @@ -1678,6 +1678,12 @@ static MQTTResponse MQTTClient_connectURI(MQTTClient handle, MQTTClient_connectO m->c->sslopts->protos = options->ssl->protos; m->c->sslopts->protos_len = options->ssl->protos_len; } + + if (options->ssl->ssl_keylog_cb) + { + m->c->sslopts->ssl_keylog_cb = options->ssl->ssl_keylog_cb; + m->c->sslopts->ssl_keylog_context = options->ssl->ssl_keylog_context; + } } #endif diff --git a/src/MQTTClient.h b/src/MQTTClient.h index 5c03d1179..4bdc25309 100644 --- a/src/MQTTClient.h +++ b/src/MQTTClient.h @@ -677,12 +677,13 @@ typedef struct /** The eyecatcher for this structure. Must be MQTS */ char struct_id[4]; - /** The version number of this structure. Must be 0, 1, 2, 3, 4 or 5. + /** The version number of this structure. Must be 0, 1, 2, 3, 4, 5 or 6. * 0 means no sslVersion * 1 means no verify, CApath * 2 means no ssl_error_context, ssl_error_cb * 3 means no ssl_psk_cb, ssl_psk_context, disableDefaultTrustStore * 4 means no protos, protos_len + * 5 means no ssl_keylog_context or ssl_keylog_cb */ int struct_version; @@ -781,9 +782,23 @@ typedef struct * Exists only if struct_version >= 5 */ unsigned int protos_len; + + /** + * Callback function for handling the SSL keylogs. + * line: the SSL keylog line. + * ctx: pointer to context data set to ssl_keylog_context by the application. + * Exists only if struct_version >= 6 + */ + void (*ssl_keylog_cb) (const char *line, void *ctx); + + /** + * Application-specific contex for ssl_keylog_cb + * Exists only if struct_version >= 6 + */ + void* ssl_keylog_context; } MQTTClient_SSLOptions; -#define MQTTClient_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 5, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0 } +#define MQTTClient_SSLOptions_initializer { {'M', 'Q', 'T', 'S'}, 5, NULL, NULL, NULL, NULL, NULL, 1, MQTT_SSL_VERSION_DEFAULT, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL } /** * MQTTClient_libraryInfo is used to store details relating to the currently used diff --git a/src/SSLSocket.c b/src/SSLSocket.c index 8cb090c47..7a0b5348d 100644 --- a/src/SSLSocket.c +++ b/src/SSLSocket.c @@ -39,6 +39,7 @@ #include "Heap.h" #include +#include #include #include #include @@ -79,6 +80,10 @@ static ssl_mutex_type sslCoreMutex; /* Used to store MQTTClient_SSLOptions for TLS-PSK callback */ static int tls_ex_index_ssl_opts; +/* Used to store the callback function and context for SSL key logging*/ +static void (*SSL_CTX_keylog_callback) (const char *line, void *ctx) = NULL; +static void * SSL_CTX_keylog_context = NULL; + #if defined(_WIN32) || defined(_WIN64) #define iov_len len #define iov_base buf @@ -543,6 +548,38 @@ static unsigned int call_ssl_psk_cb(SSL *ssl, const char *hint, char *identity, return rc; } +static void call_ssl_keylog_cb(const SSL *ssl, const char *line) +{ + FUNC_ENTRY; + + { + char* envval = NULL; + static int log_printed = 0; + if (SSL_CTX_keylog_callback) + { + SSL_CTX_keylog_callback(line, SSL_CTX_keylog_context); + } + else if ((envval = getenv("SSLKEYLOGFILE")) != NULL && strlen(envval) > 0) + { + FILE* fout = fopen(envval, "a"); + if (fout != NULL) + { + fprintf(fout, "%s\n", line); + fclose(fout); + } + else + { + if(log_printed == 0) + Log(LOG_ERROR, 1, "SSL failed to open SSLKEYLOGFILE \"%s\" with error: %s\n", envval, strerror(errno)); + + log_printed = 1; + } + } + } +exit: + FUNC_EXIT; +} + int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) { int rc = 1; @@ -721,6 +758,11 @@ int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, SSL_CTX_set_info_callback(net->ctx, SSL_CTX_info_callback); SSL_CTX_set_msg_callback(net->ctx, SSL_CTX_msg_callback); + + SSL_CTX_keylog_callback = opts->ssl_keylog_cb; + SSL_CTX_keylog_context = opts->ssl_keylog_context; + SSL_CTX_set_keylog_callback(net->ctx, call_ssl_keylog_cb); + if (opts->enableServerCertAuth) SSL_CTX_set_verify(net->ctx, SSL_VERIFY_PEER, NULL);