Skip to content

Commit dc43fc3

Browse files
committed
New TLS implementation
Implement TLS to mqtt server thanks to WiFiClientSecure class
1 parent 423b9d7 commit dc43fc3

File tree

1 file changed

+97
-19
lines changed

1 file changed

+97
-19
lines changed

core/MyGatewayTransportMQTTClient.cpp

Lines changed: 97 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,29 @@
1717
* version 2 as published by the Free Software Foundation.
1818
*/
1919

20+
/*
21+
* Modified by Eric Grammatico <eric@grammatico.me>
22+
*
23+
* Added support to secured connexion to mqtt server thanks to WiFiClientSecure class.
24+
* Please see comments in code. You can look for WiFiClientSecure, MY_GATEWAY_ESP8266_SECURE,
25+
* MY_SSL_CERT, MY_SSL_FINGERPRINT and MY_SSL_CERT_CLIENT in the code below to see what has
26+
* changed. No new method, no new class to be used by my_sensors.
27+
*
28+
* The following constants have to be defined from the gateway code:
29+
* MY_GATEWAY_ESP8266_SECURE in place of MY_GATEWAY_ESP8266 to go to secure connexions.
30+
* MY_SSL_CERT_AUTHx Up to three root Certificates Authorities could be defined
31+
* to validate the mqtt server' certificate. The most secure.
32+
* MY_SSL_FINGERPRINT Alternatively, the mqtt server' certificate finger print
33+
* could be used. Less secure and less convenient as you'll
34+
* have to update the fingerprint each time the mqtt server'
35+
* certificate is updated
36+
* If neither MY_SSL_CERT_AUTH1 nor MY_SSL_FINGERPRINT are
37+
* defined, insecure connexion will be established. The mqtt
38+
* server' certificate will not be validated.
39+
* MY_SSL_CERT_CLIENT The mqtt server may require client certificate for
40+
* MY_SSL_KEY_CLIENT authentication.
41+
*
42+
*/
2043

2144
// Topic structure: MY_MQTT_PUBLISH_TOPIC_PREFIX/NODE-ID/SENSOR-ID/CMD-TYPE/ACK-FLAG/SUB-TYPE
2245

@@ -55,7 +78,7 @@
5578
#define MY_MQTT_PASSWORD NULL
5679
#endif
5780

58-
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
81+
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP8266_SECURE) || defined(MY_GATEWAY_ESP32)
5982
#if !defined(MY_WIFI_SSID)
6083
#error ESP8266/ESP32 MQTT gateway: MY_WIFI_SSID not defined!
6184
#endif
@@ -69,28 +92,49 @@
6992
#define _MQTT_clientIp IPAddress(MY_IP_ADDRESS)
7093
#if defined(MY_IP_GATEWAY_ADDRESS)
7194
#define _gatewayIp IPAddress(MY_IP_GATEWAY_ADDRESS)
72-
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
95+
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP8266_SECURE) || defined(MY_GATEWAY_ESP32)
7396
// Assume the gateway will be the machine on the same network as the local IP
7497
// but with last octet being '1'
7598
#define _gatewayIp IPAddress(_MQTT_clientIp[0], _MQTT_clientIp[1], _MQTT_clientIp[2], 1)
7699
#endif /* End of MY_IP_GATEWAY_ADDRESS */
77100

78101
#if defined(MY_IP_SUBNET_ADDRESS)
79102
#define _subnetIp IPAddress(MY_IP_SUBNET_ADDRESS)
80-
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
103+
#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP8266_SECURE) || defined(MY_GATEWAY_ESP32)
81104
#define _subnetIp IPAddress(255, 255, 255, 0)
82105
#endif /* End of MY_IP_SUBNET_ADDRESS */
83106
#endif /* End of MY_IP_ADDRESS */
84107

85108
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
86-
#if defined(MY_MQTT_CA_CERT) && defined(MY_MQTT_CLIENT_CERT) && defined(MY_MQTT_CLIENT_KEY)
87-
#define EthernetClient WiFiClientSecure
88-
BearSSL::X509List ca_cert(MY_MQTT_CA_CERT);
89-
BearSSL::X509List client_cert(MY_MQTT_CLIENT_CERT);
90-
BearSSL::PrivateKey client_key(MY_MQTT_CLIENT_KEY);
91-
#else
92109
#define EthernetClient WiFiClient
93-
#endif /* End of MY_MQTT_CA_CERT && MY_MQTT_CLIENT_CERT && MY_MQTT_CLIENT_KEY */
110+
#elif defined(MY_GATEWAY_ESP8266_SECURE)
111+
#define EthernetClient WiFiClientSecure
112+
#if defined(MY_SSL_CERT_AUTH1)
113+
BearSSL::X509List certAuth; //List to store Certificat Authorities
114+
#endif
115+
#if defined(MY_SSL_CERT_CLIENT) && defined(MY_SSL_KEY_CLIENT)
116+
BearSSL::X509List clientCert; //Client public key
117+
BearSSL::PrivateKey clientPrivKey; //Client private key
118+
#endif
119+
// Set time via NTP, as required for x.509 validation
120+
// BearSSL checks NotBefore and NotAfter dates in certificates
121+
// Thus an approximated date/time is needed.
122+
void setClock() {
123+
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
124+
125+
Serial.print("Waiting for NTP time sync: ");
126+
time_t now = time(nullptr);
127+
while (now < 8 * 3600 * 2) {
128+
delay(500);
129+
Serial.print(".");
130+
now = time(nullptr);
131+
}
132+
Serial.println("");
133+
struct tm timeinfo;
134+
gmtime_r(&now, &timeinfo);
135+
Serial.print("Current time: ");
136+
Serial.print(asctime(&timeinfo));
137+
}
94138
#elif defined(MY_GATEWAY_LINUX)
95139
// Nothing to do here
96140
#else
@@ -161,18 +205,57 @@ bool reconnectMQTT(void)
161205
}
162206
delay(1000);
163207
GATEWAY_DEBUG(PSTR("!GWT:RMQ:FAIL\n"));
208+
#if defined(MY_GATEWAY_ESP8266_SECURE)
209+
char sslErr[256];
210+
int errID = _MQTT_ethClient.getLastSSLError(sslErr, sizeof(sslErr));
211+
GATEWAY_DEBUG(PSTR("!GWT:RMQ:(%d) %s\n"), errID, sslErr);
212+
#endif
164213
return false;
165214
}
166215

167216
bool gatewayTransportConnect(void)
168217
{
169-
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
218+
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP8266_SECURE) || defined(MY_GATEWAY_ESP32)
170219
if (WiFi.status() != WL_CONNECTED) {
171220
GATEWAY_DEBUG(PSTR("GWT:TPC:CONNECTING...\n"));
172221
delay(1000);
173222
return false;
174223
}
175224
GATEWAY_DEBUG(PSTR("GWT:TPC:IP=%s\n"), WiFi.localIP().toString().c_str());
225+
226+
#if defined(MY_GATEWAY_ESP8266_SECURE)
227+
// Certificate Authorities are stored in the X509 list
228+
// At least one is needed, but you may need two, or three
229+
// eg to validate one certificate from LetsEncrypt two is needed
230+
#if defined(MY_SSL_CERT_AUTH1)
231+
certAuth.append(MY_SSL_CERT_AUTH1);
232+
#if defined(MY_SSL_CERT_AUTH2)
233+
certAuth.append(MY_SSL_CERT_AUTH2);
234+
#endif
235+
#if defined(MY_SSL_CERT_AUTH3)
236+
certAuth.append(MY_SSL_CERT_AUTH3);
237+
#endif
238+
_MQTT_ethClient.setTrustAnchors(&certAuth);
239+
#elif defined(MY_SSL_FINGERPRINT) //MY_SSL_CERT_AUTH1
240+
// Alternatively, the certificate could be validated with its
241+
// fingerprint, which is less secure
242+
_MQTT_ethClient.setFingerprint(MY_SSL_FINGERPRINT);
243+
#else //MY_SSL_CERT_AUTH1
244+
// At last, an insecure connexion is accepted. Meaning the
245+
// server's certificate is not validated.
246+
_MQTT_ethClient.setInsecure();
247+
GATEWAY_DEBUG(PSTR("GWT:TPC:CONNECTING WITH INSECURE SETTING...\n"));
248+
#endif //MY_SSL_CERT_AUTH1
249+
#if defined(MY_SSL_CERT_CLIENT) && defined(MY_SSL_KEY_CLIENT)
250+
// The server may required client certificate
251+
clientCert.append(MY_SSL_CERT_CLIENT);
252+
clientPrivKey.parse(MY_SSL_KEY_CLIENT);
253+
_MQTT_ethClient.setClientRSACert(&clientCert, &clientPrivKey);
254+
#endif
255+
// Once the secure connexion settings are done, date/time are retrieved
256+
// to be able to validate certificates.
257+
setClock();
258+
#endif //MY_GATEWAY_ESP8266_SECURE
176259
#elif defined(MY_GATEWAY_LINUX)
177260
#if defined(MY_IP_ADDRESS)
178261
_MQTT_ethClient.bind(_MQTT_clientIp);
@@ -250,10 +333,10 @@ bool gatewayTransportInit(void)
250333

251334
_MQTT_client.setCallback(incomingMQTT);
252335

253-
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
336+
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP8266_SECURE) || defined(MY_GATEWAY_ESP32)
254337
// Turn off access point
255338
WiFi.mode(WIFI_STA);
256-
#if defined(MY_GATEWAY_ESP8266)
339+
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP8266_SECURE)
257340
WiFi.hostname(MY_HOSTNAME);
258341
#elif defined(MY_GATEWAY_ESP32)
259342
WiFi.setHostname(MY_HOSTNAME);
@@ -264,11 +347,6 @@ bool gatewayTransportInit(void)
264347
(void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID);
265348
#endif
266349

267-
#if defined(MY_MQTT_CA_CERT) && defined(MY_MQTT_CLIENT_CERT) && defined(MY_MQTT_CLIENT_KEY)
268-
_MQTT_ethClient.setTrustAnchors(&ca_cert);
269-
_MQTT_ethClient.setClientRSACert(&client_cert, &client_key);
270-
#endif /* End of MY_MQTT_CA_CERT && MY_MQTT_CLIENT_CERT && MY_MQTT_CLIENT_KEY */
271-
272350
gatewayTransportConnect();
273351

274352
_MQTT_connecting = false;
@@ -280,7 +358,7 @@ bool gatewayTransportAvailable(void)
280358
if (_MQTT_connecting) {
281359
return false;
282360
}
283-
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)
361+
#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP8266_SECURE) || defined(MY_GATEWAY_ESP32)
284362
if (WiFi.status() != WL_CONNECTED) {
285363
#if defined(MY_GATEWAY_ESP32)
286364
(void)gatewayTransportInit();

0 commit comments

Comments
 (0)