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
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
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
167216bool 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