Skip to content

Commit 91a2f1f

Browse files
authored
New SSL implementation
Added support to secured connexion to mqtt server thanks to WiFiClientSecure class. Please see comments in code. You can look for WiFiClientSecure, MY_GATEWAY_ESP8266_SECURE, MY_SSL_CERT, MY_SSL_FINGERPRINT and MY_SSL_CERT_CLIENT in the code below to see what has changed. No new method, no new class to be used by my_sensors. The following constants have to be defined from the gateway code: MY_GATEWAY_ESP8266_SECURE in place of MY_GATEWAY_ESP8266 to go to secure connections. MY_SSL_CERT_AUTHx Up to three root Certificates Authorities could be defined to validate the mqtt server' certificate. The most secure. Let's Encrypt requires at least two to validate all the certificates signed by them. MY_SSL_FINGERPRINT Alternatively, the mqtt server' certificate finger print could be used. Less secure and less convenient as you'll have to update the fingerprint each time the mqtt server' certificate is updated If neither MY_SSL_CERT_AUTH1 nor MY_SSL_FINGERPRINT are defined, insecure connexion will be established. The mqtt server' certificate will not be validated. MY_SSL_CERT_CLIENT The mqtt server may require client certificate for MY_SSL_KEY_CLIENT authentication.
1 parent 423b9d7 commit 91a2f1f

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 <[email protected]>
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)