Merge pull request #5 from rodriguezst/mqtt-tls-rebased

Enable MQTT encryption on Wifi
This commit is contained in:
Jan-Ole Schümann
2022-06-15 20:26:01 +02:00
committed by GitHub
10 changed files with 121 additions and 11 deletions

View File

@@ -9,6 +9,11 @@ project(nuki_hub CXX)
set(LOG_LEVEL ARDUHAL_LOG_LEVEL_NONE)
# Length of char arrays to store certificates for MQTTS
add_compile_definitions(TLS_CA_MAX_SIZE=1500)
add_compile_definitions(TLS_CERT_MAX_SIZE=1500)
add_compile_definitions(TLS_KEY_MAX_SIZE=1800)
include_directories(${PROJECT_NAME}
PRIVATE
lib/Crc16
@@ -83,6 +88,7 @@ target_link_arduino_libraries(${PROJECT_NAME}
PRIVATE
core
WiFi
WiFiClientSecure
Update
# WebServer
DNSServer

View File

@@ -42,11 +42,11 @@ void Network::setupDevice(const NetworkDeviceType hardware)
break;
case NetworkDeviceType::WiFi:
Serial.println(F("Network device: Builtin WiFi"));
_device = new WifiDevice(_hostname);
_device = new WifiDevice(_hostname, _preferences);
break;
default:
Serial.println(F("Unknown network device type, defaulting to WiFi"));
_device = new WifiDevice(_hostname);
_device = new WifiDevice(_hostname, _preferences);
break;
}
}
@@ -161,6 +161,8 @@ bool Network::reconnect()
{
Serial.print(F("MQTT connect failed, rc="));
Serial.println(_device->mqttClient()->state());
_device->printError();
_device->mqttClient()->disconnect();
_mqttConnected = false;
_nextReconnect = millis() + 5000;
}

View File

@@ -10,6 +10,9 @@
#define preference_mqtt_lock_path "mqttpath"
#define preference_opener_enabled "openerena"
#define preference_mqtt_opener_path "mqttoppath"
#define preference_mqtt_ca "mqttca"
#define preference_mqtt_crt "mqttcrt"
#define preference_mqtt_key "mqttkey"
#define preference_hostname "hostname"
#define preference_network_timeout "nettmout"
#define preference_query_interval_lockstate "lockStInterval"

View File

@@ -168,6 +168,21 @@ bool WebCfgServer::processArgs(String& message)
_preferences->putString(preference_mqtt_opener_path, value);
configChanged = true;
}
else if(key == "MQTTCA")
{
_preferences->putString(preference_mqtt_ca, value);
configChanged = true;
}
else if(key == "MQTTCRT")
{
_preferences->putString(preference_mqtt_crt, value);
configChanged = true;
}
else if(key == "MQTTKEY")
{
_preferences->putString(preference_mqtt_key, value);
configChanged = true;
}
else if(key == "HOSTNAME")
{
_preferences->putString(preference_hostname, value);
@@ -437,6 +452,9 @@ void WebCfgServer::buildMqttConfigHtml(String &response)
printInputField(response, "MQTTPORT", "MQTT Broker port", _preferences->getInt(preference_mqtt_broker_port), 5);
printInputField(response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30);
printInputField(response, "MQTTPASS", "MQTT Password", "*", 30, true);
printTextarea(response, "MQTTCA", "MQTT SSL CA Certificate", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE);
printTextarea(response, "MQTTCRT", "MQTT SSL Client Certificate", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE);
printTextarea(response, "MQTTKEY", "MQTT SSL Client Key", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE);
printInputField(response, "NETTIMEOUT", "Network Timeout until restart (seconds; -1 to disable)", _preferences->getInt(preference_network_timeout), 5);
response.concat("</table>");
response.concat("<br><INPUT TYPE=SUBMIT NAME=\"submit\" VALUE=\"Save\">");
@@ -580,6 +598,32 @@ void WebCfgServer::printCheckBox(String &response, const char *token, const char
response.concat("/></td></tr>");
}
void WebCfgServer::printTextarea(String& response,
const char *token,
const char *description,
const char *value,
const size_t maxLength)
{
char maxLengthStr[20];
itoa(maxLength, maxLengthStr, 10);
response.concat("<tr>");
response.concat("<td>");
response.concat(description);
response.concat("</td>");
response.concat("<td>");
response.concat(" <TEXTAREA NAME=\"");
response.concat(token);
response.concat("\" MAXLENGTH=\"");
response.concat(maxLengthStr);
response.concat("\\\">");
response.concat(value);
response.concat("</TEXTAREA>");
response.concat("</td>");
response.concat("</tr>");
}
void WebCfgServer::printParameter(String& response, const char *description, const char *value)
{
response.concat("<tr>");

View File

@@ -41,6 +41,7 @@ private:
void printInputField(String& response, const char* token, const char* description, const char* value, const size_t maxLength, const bool isPassword = false);
void printInputField(String& response, const char* token, const char* description, const int value, size_t maxLength);
void printCheckBox(String& response, const char* token, const char* description, const bool value);
void printTextarea(String& response, const char *token, const char *description, const char *value, const size_t maxLength);
void printParameter(String& response, const char* description, const char* value);

View File

@@ -14,6 +14,7 @@ public:
virtual void initialize() = 0;
virtual bool reconnect() = 0;
virtual void reconfigure() = 0;
virtual void printError() = 0;
virtual void update() = 0;

View File

@@ -117,6 +117,13 @@ void W5500Device::resetDevice()
nwDelay(1500);
}
void W5500Device::printError()
{
Serial.print(F("Free Heap: "));
Serial.println(ESP.getFreeHeap());
}
PubSubClient *W5500Device::mqttClient()
{
return _mqttClient;

View File

@@ -13,6 +13,7 @@ public:
virtual void initialize();
virtual bool reconnect();
virtual void reconfigure();
virtual void printError();
virtual void update();

View File

@@ -1,15 +1,41 @@
#include <WiFi.h>
#include "WifiDevice.h"
#include "WiFiManager.h"
#include "../PreferencesKeys.h"
WifiDevice::WifiDevice(const String& hostname)
: NetworkDevice(hostname),
_mqttClient(_wifiClient)
{}
WifiDevice::WifiDevice(const String& hostname, Preferences* _preferences)
: NetworkDevice(hostname)
{
size_t caLength = _preferences->getString(preference_mqtt_ca,_ca,TLS_CA_MAX_SIZE);
size_t crtLength = _preferences->getString(preference_mqtt_crt,_cert,TLS_CERT_MAX_SIZE);
size_t keyLength = _preferences->getString(preference_mqtt_key,_key,TLS_KEY_MAX_SIZE);
if(caLength > 1) // length is 1 when empty
{
Serial.println(F("MQTT over TLS."));
Serial.println(_ca);
_wifiClientSecure = new WiFiClientSecure();
_wifiClientSecure->setCACert(_ca);
if(crtLength > 1 && keyLength > 1) // length is 1 when empty
{
Serial.println(F("MQTT with client certificate."));
Serial.println(_cert);
Serial.println(_key);
_wifiClientSecure->setCertificate(_cert);
_wifiClientSecure->setPrivateKey(_key);
}
_mqttClient = new PubSubClient(*_wifiClientSecure);
} else
{
Serial.println(F("MQTT without TLS."));
_wifiClient = new WiFiClient();
_mqttClient = new PubSubClient(*_wifiClient);
}
}
PubSubClient *WifiDevice::mqttClient()
{
return &_mqttClient;
return _mqttClient;
}
void WifiDevice::initialize()
@@ -48,7 +74,7 @@ void WifiDevice::initialize()
Serial.println(WiFi.localIP().toString());
}
_mqttClient.setBufferSize(_mqttMaxBufferSize);
_mqttClient->setBufferSize(_mqttMaxBufferSize);
}
void WifiDevice::reconfigure()
@@ -58,6 +84,18 @@ void WifiDevice::reconfigure()
ESP.restart();
}
void WifiDevice::printError()
{
if(_wifiClientSecure != nullptr)
{
char lastError[100];
_wifiClientSecure->lastError(lastError,100);
Serial.println(lastError);
}
Serial.print(F("Free Heap: "));
Serial.println(ESP.getFreeHeap());
}
bool WifiDevice::isConnected()
{
return WiFi.isConnected();

View File

@@ -1,17 +1,20 @@
#pragma once
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <Preferences.h>
#include "NetworkDevice.h"
#include "../SpiffsCookie.h"
class WifiDevice : public NetworkDevice
{
public:
WifiDevice(const String& hostname);
WifiDevice(const String& hostname, Preferences* _preferences);
virtual void initialize();
virtual void reconfigure();
virtual bool reconnect();
virtual void printError();
virtual void update();
@@ -20,7 +23,11 @@ public:
virtual PubSubClient *mqttClient();
private:
WiFiClient _wifiClient;
PubSubClient _mqttClient;
WiFiClient* _wifiClient = nullptr;
WiFiClientSecure* _wifiClientSecure = nullptr;
PubSubClient* _mqttClient = nullptr;
SpiffsCookie _cookie;
char _ca[TLS_CA_MAX_SIZE];
char _cert[TLS_CERT_MAX_SIZE];
char _key[TLS_KEY_MAX_SIZE];
};