From 20bc69340cc5cf880f31794bc5d7a81de8087d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Sun, 27 Aug 2017 18:14:39 +0200 Subject: [PATCH] Testing SSL with PubSubClient --- code/espurna/mqtt.ino | 123 +++++++++++++++++++++++++++++++++--------- code/platformio.ini | 3 +- 2 files changed, 101 insertions(+), 25 deletions(-) diff --git a/code/espurna/mqtt.ino b/code/espurna/mqtt.ino index 26cde2b8..f8184b2f 100644 --- a/code/espurna/mqtt.ino +++ b/code/espurna/mqtt.ino @@ -14,14 +14,22 @@ Copyright (C) 2016-2017 by Xose PĂ©rez const char *mqtt_user = 0; const char *mqtt_pass = 0; -#if MQTT_USE_ASYNC +#if MQTT_USE_ASYNC // Using AsyncMqttClient + #include AsyncMqttClient mqtt; -#else + +#else // Using PubSubClient + #include -WiFiClient mqttWiFiClient; -PubSubClient mqtt(mqttWiFiClient); +PubSubClient mqtt; bool _mqttConnected = false; + +WiFiClient _mqttClient; +#if ASYNC_TCP_SSL_ENABLED +WiFiClientSecure _mqttClientSecure; +#endif + #endif String _mqttTopic; @@ -244,9 +252,11 @@ void _mqttOnMessage(char* topic, char* payload, unsigned int len) { } -bool fp2array(const char * fingerprint, unsigned char * bytearray) { +#if MQTT_USE_ASYNC + +bool mqttFormatFP(const char * fingerprint, unsigned char * bytearray) { - // check length (20 2-character digits ':'-separated => 20*2+19 = 59) + // check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59) if (strlen(fingerprint) != 59) return false; DEBUG_MSG_P(PSTR("[MQTT] Fingerprint %s\n"), fingerprint); @@ -260,6 +270,30 @@ bool fp2array(const char * fingerprint, unsigned char * bytearray) { } +#else + +bool mqttFormatFP(const char * fingerprint, char * destination) { + + // check length (20 2-character digits ':' or ' ' separated => 20*2+19 = 59) + if (strlen(fingerprint) != 59) return false; + + DEBUG_MSG_P(PSTR("[MQTT] Fingerprint %s\n"), fingerprint); + + // copy it + strncpy(destination, fingerprint, 59); + + // walk the fingerprint replacing ':' for ' ' + for (unsigned char i = 0; i<59; i++) { + if (destination[i] == ':') destination[i] = ' '; + } + + return true; + +} + +#endif + + void mqttConnect() { if (!mqtt.connected()) { @@ -283,8 +317,6 @@ void mqttConnect() { last_try = millis(); #endif - mqtt.disconnect(); - if (_mqttUser) free(_mqttUser); if (_mqttPass) free(_mqttPass); @@ -295,43 +327,86 @@ void mqttConnect() { if (_mqttWill) free(_mqttWill); _mqttWill = strdup((_mqttTopic + MQTT_TOPIC_STATUS).c_str()); - DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%d"), host, port); - mqtt.setServer(host, port); + DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%d\n"), host, port); #if MQTT_USE_ASYNC + mqtt.setServer(host, port); mqtt.setKeepAlive(MQTT_KEEPALIVE).setCleanSession(false); mqtt.setWill(_mqttWill, MQTT_QOS, MQTT_RETAIN, "0"); if ((strlen(_mqttUser) > 0) && (strlen(_mqttPass) > 0)) { - DEBUG_MSG_P(PSTR(" as user '%s'."), _mqttUser); + DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqttUser); mqtt.setCredentials(_mqttUser, _mqttPass); } - DEBUG_MSG_P(PSTR("\n")); #if ASYNC_TCP_SSL_ENABLED + bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1; mqtt.setSecure(secure); if (secure) { DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n")); - unsigned char fp[20]; - if (fp2array(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) { + unsigned char fp[20] = {0}; + if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) { mqtt.addServerFingerprint(fp); + } else { + DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n")); } } - #endif + + #endif // ASYNC_TCP_SSL_ENABLED mqtt.connect(); - #else + #else // not MQTT_USE_ASYNC - bool response; + bool response = true; + + #if ASYNC_TCP_SSL_ENABLED + + bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1; + if (secure) { + DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n")); + if (_mqttClientSecure.connect(host, port)) { + char fp[60] = {0}; + if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) { + Serial.println(fp); + Serial.println(strlen(fp)); + if (_mqttClientSecure.verify(fp, host)) { + mqtt.setClient(_mqttClientSecure); + } else { + DEBUG_MSG_P(PSTR("[MQTT] Invalid fingerprint\n")); + response = false; + } + } else { + DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n")); + response = false; + } + } else { + DEBUG_MSG_P(PSTR("[MQTT] Client connection failed\n")); + response = false; + } + + } else { + mqtt.setClient(_mqttClient); + } + + #else // not ASYNC_TCP_SSL_ENABLED + + mqtt.setClient(_mqttClient); + + #endif // ASYNC_TCP_SSL_ENABLED + + if (response) { + + mqtt.setServer(host, port); + + if ((strlen(_mqttUser) > 0) && (strlen(_mqttPass) > 0)) { + DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqttUser); + response = mqtt.connect(getIdentifier().c_str(), _mqttUser, _mqttPass, _mqttWill, MQTT_QOS, MQTT_RETAIN, "0"); + } else { + response = mqtt.connect(getIdentifier().c_str(), _mqttWill, MQTT_QOS, MQTT_RETAIN, "0"); + } - if ((strlen(_mqttUser) > 0) && (strlen(_mqttPass) > 0)) { - DEBUG_MSG_P(PSTR(" as user '%s'\n"), _mqttUser); - response = mqtt.connect(getIdentifier().c_str(), _mqttUser, _mqttPass, _mqttWill, MQTT_QOS, MQTT_RETAIN, "0"); - } else { - DEBUG_MSG_P(PSTR("\n")); - response = mqtt.connect(getIdentifier().c_str(), _mqttWill, MQTT_QOS, MQTT_RETAIN, "0"); } if (response) { @@ -341,7 +416,7 @@ void mqttConnect() { DEBUG_MSG_P(PSTR("[MQTT] Connection failed\n")); } - #endif + #endif // MQTT_USE_ASYNC free(host); diff --git a/code/platformio.ini b/code/platformio.ini index 7e6cb19c..9d2a8fa8 100644 --- a/code/platformio.ini +++ b/code/platformio.ini @@ -5,6 +5,7 @@ data_dir = espurna/data [common] build_flags = -g -DMQTT_MAX_PACKET_SIZE=400 ${env.FLAGS} +debug_flags = -DDEBUG_ESP_CORE -DDEBUG_ESP_SSL -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM build_flags_512k = ${common.build_flags} -Wl,-Tesp8266.flash.512k0.ld build_flags_1m = ${common.build_flags} -Wl,-Tesp8266.flash.1m0.ld lib_deps = @@ -80,7 +81,7 @@ framework = arduino board = nodemcuv2 lib_deps = ${common.lib_deps} lib_ignore = ${common.lib_ignore} -build_flags = ${common.build_flags} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1 +build_flags = ${common.build_flags} -DNODEMCU_LOLIN -DDEBUG_FAUXMO=Serial -DNOWSAUTH -DASYNC_TCP_SSL_ENABLED=1 ${common.debug_flags} upload_speed = 460800 monitor_baud = 115200