Created
December 10, 2017 13:12
-
-
Save eLement87/133cddc5bd0472daf5cb35a20bfd811e to your computer and use it in GitHub Desktop.
ESP8266 Secure MQTT Connection with Client Certificate Authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <FS.h> | |
#include <ESP8266WiFi.h> | |
#include <WiFiClientSecure.h> | |
#include <PubSubClient.h> | |
#include <time.h> | |
// Insert your FQDN of your MQTT Broker | |
#define MQTT_SERVER "mqtt.srvx1.local" | |
const char* mqtt_server = MQTT_SERVER; | |
// WiFi Credentials | |
const char* ssid = "insert_coin"; | |
const char* password = "supersecretwifipassword"; | |
// Static IP configuration | |
#define IPSET_STATIC { 10, 10, 10, 13 } | |
#define IPSET_GATEWAY { 10, 10, 10, 254 } | |
#define IPSET_SUBNET { 255, 255, 255, 0 } | |
#define IPSET_DNS { 10, 10, 10, 254 } | |
byte ip_static[] = IPSET_STATIC; | |
byte ip_gateway[] = IPSET_GATEWAY; | |
byte ip_subnet[] = IPSET_SUBNET; | |
byte ip_dns[] = IPSET_DNS; | |
// Fingerprint of the broker CA | |
// openssl x509 -in mqttserver.crt -sha1 -noout -fingerprint | |
const char* fingerprint = "28:7C:0E:AC:E1:B9:00:9B:DB:4B:BA:19:0A:3D:4A:B5:F6:AA:4D:A6"; | |
// Topic | |
char* topic = "test"; | |
String clientName; | |
long lastReconnectAttempt = 0; | |
long lastMsg = 0; | |
int test_para = 2000; | |
unsigned long startMills; | |
WiFiClientSecure wifiClient; | |
PubSubClient client(mqtt_server, 8883, wifiClient); | |
void verifytls() { | |
// Use WiFiClientSecure class to create TLS connection | |
Serial.print("connecting to "); | |
Serial.println(mqtt_server); | |
if (!wifiClient.connect(mqtt_server, 8883)) { | |
Serial.println("connection failed"); | |
return; | |
} | |
if (wifiClient.verify(fingerprint, mqtt_server)) { | |
Serial.println("certificate matches"); | |
} else { | |
Serial.println("certificate doesn't match"); | |
} | |
} | |
// Load Certificates | |
void loadcerts() { | |
if (!SPIFFS.begin()) { | |
Serial.println("Failed to mount file system"); | |
return; | |
} | |
// Load client certificate file from SPIFFS | |
File cert = SPIFFS.open("/esp.der", "r"); //replace esp.der with your uploaded file name | |
if (!cert) { | |
Serial.println("Failed to open cert file"); | |
} | |
else | |
Serial.println("Success to open cert file"); | |
delay(1000); | |
// Set client certificate | |
if (wifiClient.loadCertificate(cert)) | |
Serial.println("cert loaded"); | |
else | |
Serial.println("cert not loaded"); | |
// Load client private key file from SPIFFS | |
File private_key = SPIFFS.open("/espkey.der", "r"); //replace espkey.der with your uploaded file name | |
if (!private_key) { | |
Serial.println("Failed to open private cert file"); | |
} | |
else | |
Serial.println("Success to open private cert file"); | |
delay(1000); | |
// Set client private key | |
if (wifiClient.loadPrivateKey(private_key)) | |
Serial.println("private key loaded"); | |
else | |
Serial.println("private key not loaded"); | |
// Load CA file from SPIFFS | |
File ca = SPIFFS.open("/ca.der", "r"); //replace ca.der with your uploaded file name | |
if (!ca) { | |
Serial.println("Failed to open ca "); | |
} | |
else | |
Serial.println("Success to open ca"); | |
delay(1000); | |
// Set server CA file | |
if(wifiClient.loadCACert(ca)) | |
Serial.println("ca loaded"); | |
else | |
Serial.println("ca failed"); | |
} | |
void getTime(){ | |
// Synchronize time useing SNTP. This is necessary to verify that | |
// the TLS certificates offered by the server are currently valid. | |
Serial.print("Setting time using SNTP"); | |
configTime(8 * 3600, 0, "de.pool.ntp.org"); | |
time_t now = time(nullptr); | |
while (now < 1000) { | |
delay(500); | |
Serial.print("."); | |
now = time(nullptr); | |
} | |
Serial.println(""); | |
struct tm timeinfo; | |
gmtime_r(&now, &timeinfo); | |
Serial.print("Current time: "); | |
Serial.print(asctime(&timeinfo)); | |
} | |
boolean reconnect() | |
{ | |
if (!client.connected()) { | |
if (client.connect((char*) clientName.c_str())) { | |
Serial.println("===> mqtt connected"); | |
} else { | |
Serial.print("---> mqtt failed, rc="); | |
Serial.println(client.state()); | |
} | |
} | |
return client.connected(); | |
} | |
void wifi_connect() | |
{ | |
if (WiFi.status() != WL_CONNECTED) { | |
// WIFI | |
Serial.println(); | |
Serial.print("===> WIFI ---> Connecting to "); | |
Serial.println(ssid); | |
delay(10); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
WiFi.config(IPAddress(ip_static), IPAddress(ip_gateway), IPAddress(ip_subnet), IPAddress(ip_dns)); | |
int Attempt = 0; | |
while (WiFi.status() != WL_CONNECTED) { | |
Serial.print(". "); | |
Serial.print(Attempt); | |
delay(100); | |
Attempt++; | |
if (Attempt == 150) | |
{ | |
Serial.println(); | |
Serial.println("-----> Could not connect to WIFI"); | |
ESP.restart(); | |
delay(200); | |
} | |
} | |
Serial.println(); | |
Serial.print("===> WiFi connected"); | |
Serial.print(" ------> IP address: "); | |
Serial.println(WiFi.localIP()); | |
} | |
} | |
void setup() | |
{ | |
Serial.begin(115200); | |
startMills = millis(); | |
wifi_connect(); | |
delay(500); | |
getTime(); | |
delay(500); | |
loadcerts(); | |
delay(200); | |
clientName += "esp8266-"; | |
uint8_t mac[6]; | |
WiFi.macAddress(mac); | |
clientName += macToStr(mac); | |
clientName += "-"; | |
clientName += String(micros() & 0xff, 16); | |
} | |
void loop() | |
{ | |
if (WiFi.status() == WL_CONNECTED) { | |
if (!client.connected()) { | |
long now = millis(); | |
if (now - lastReconnectAttempt > 2000) { | |
lastReconnectAttempt = now; | |
if (reconnect()) { | |
lastReconnectAttempt = 0; | |
} | |
} | |
} else { | |
long now = millis(); | |
if (now - lastMsg > test_para) { | |
lastMsg = now; | |
String payload = "{\"startMills\":"; | |
payload += (millis() - startMills); | |
payload += "}"; | |
sendmqttMsg(topic, payload); | |
} | |
client.loop(); | |
} | |
} else { | |
wifi_connect(); | |
} | |
} | |
void sendmqttMsg(char* topictosend, String payload) | |
{ | |
if (client.connected()) { | |
Serial.print("Sending payload: "); | |
Serial.print(payload); | |
unsigned int msg_length = payload.length(); | |
Serial.print(" length: "); | |
Serial.println(msg_length); | |
byte* p = (byte*)malloc(msg_length); | |
memcpy(p, (char*) payload.c_str(), msg_length); | |
if ( client.publish(topictosend, p, msg_length)) { | |
Serial.println("Publish ok"); | |
free(p); | |
//return 1; | |
} else { | |
Serial.println("Publish failed"); | |
free(p); | |
//return 0; | |
} | |
} | |
} | |
String macToStr(const uint8_t* mac) | |
{ | |
String result; | |
for (int i = 0; i < 6; ++i) { | |
result += String(mac[i], 16); | |
if (i < 5) | |
result += ':'; | |
} | |
return result; | |
} |
Do we need to use
.setCertificate(client_key);
.setPrivateKey(client_cert);
additionally to
.loadCACert()
.loadPrivateKey()
?
Hi,
i have loaded all the cert file ( client.crt client.key ca.crt ), but i don't know where i can set username and password.
So my broker respond "mqtt failed, rc=5" for a lot of seconds, and after esp8266 restart...
thank you...
@atsspp, the certificates replace the username and password. This is the whole idea of Client Certificate Authentication. The code is not only about setting up an encrypted connection.
Hi, i have the -2 rc too... i don't understand what's wrong. I've laoded client, cient ket and ca certificate (I used the same certificates to connect from node-red and it works) but this is the result:
20:34:19.288 -> Connecting to GhostNet
20:34:19.888 -> .......
20:34:23.727 -> WiFi connected
20:34:23.727 -> IP address:
20:34:23.727 -> xxx.xxx.xxx.xxx
20:34:23.727 -> Success to open cert file
20:34:24.793 -> cert loaded
20:34:24.793 -> Success to open private cert file
20:34:25.856 -> private key loaded
20:34:25.856 -> Success to open ca
20:34:26.922 -> ca loaded
20:34:27.803 -> Attempting MQTT connection...failed, rc=-2 try again in 5 seconds
20:34:32.847 -> Attempting MQTT connection...failed, rc=-2 try again in 5 seconds
20:34:37.933 -> Attempting MQTT connection...failed, rc=-2 try again in 5 seconds
and this is my code:
#include <FS.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <DHT_U.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
//dht settings
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
StaticJsonDocument<256> temphum;
float Humidity = 0.0;
float Temperature = 0.0;
bool isValid = true;
// wifi and mqtt settings
const char* ssid = "MySSID";
const char* password = "thebestpasswordintheworld";
const char* mqtt_server = "mqqtserver";
const char* mqtt_user = "mqqtuser";
const char* mqtt_pass = "awonderpass";
// Fingerprint of the broker CA
// openssl x509 -in mqttserver.crt -sha1 -noout -fingerprint
const char* fingerprint = "FA:KE:FI:NG:ER:PR:IN:T0:12:34:56:78:90:A0:B1:C2:D3:E4:F5:AA";
WiFiClientSecure espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (256)
char msg[MSG_BUFFER_SIZE];
int value = 0;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void verifytls() {
// Use WiFiClientSecure class to create TLS connection
Serial.print("connecting to ");
Serial.println(mqtt_server);
if (!espClient.connect(mqtt_server, 8883)) {
Serial.println("connection failed");
return;
}
if (espClient.verify(fingerprint, mqtt_server)) {
Serial.println("certificate matches");
} else {
Serial.println("certificate doesn't match");
}
}
// Load Certificates
void loadcerts() {
if (!SPIFFS.begin()) {
Serial.println("Failed to mount file system");
return;
}
// Load client certificate file from SPIFFS
File cert = SPIFFS.open("/client.crt", "r"); //replace esp.der with your uploaded file name
if (!cert) {
Serial.println("Failed to open cert file");
}
else
Serial.println("Success to open cert file");
delay(1000);
// Set client certificate
if (espClient.loadCertificate(cert))
Serial.println("cert loaded");
else
Serial.println("cert not loaded");
// Load client private key file from SPIFFS
File private_key = SPIFFS.open("/client.key", "r"); //replace espkey.der with your uploaded file name
if (!private_key) {
Serial.println("Failed to open private cert file");
}
else
Serial.println("Success to open private cert file");
delay(1000);
// Set client private key
if (espClient.loadPrivateKey(private_key))
Serial.println("private key loaded");
else
Serial.println("private key not loaded");
// Load CA file from SPIFFS
File ca = SPIFFS.open("/ca.crt", "r"); //replace ca.der with your uploaded file name
if (!ca) {
Serial.println("Failed to open ca ");
}
else
Serial.println("Success to open ca");
delay(1000);
// Set server CA file
if (espClient.loadCACert(ca))
Serial.println("ca loaded");
else
Serial.println("ca failed");
}
int digitalReadOutputPin(uint8_t pin)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
if (port == NOT_A_PIN)
return LOW;
return (*portOutputRegister(port) & bit) ? HIGH : LOW;
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
int b = 0;
char out[256];
switch ((char)payload[0]) {
case '1':
digitalWrite(BUILTIN_LED, LOW);
b =serializeJson(temphum, out);
snprintf (msg, MSG_BUFFER_SIZE, out);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("my/mqqt/temperature", msg);
break;
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str(), mqtt_user, mqtt_pass)) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("my/mqqt/temperature", "29");
// ... and resubscribe
client.subscribe("my/sensors/commands");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
delay(500);
setup_wifi();
loadcerts();
delay(500);
client.setServer(mqtt_server, 8883);
client.setCallback(callback);
dht.begin();
}
void loop() {
digitalWrite(BUILTIN_LED, HIGH);
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if (now - lastMsg > 5000) {
// Read humidity
Humidity = (float(int(dht.readHumidity() * 10))/10);
//Read temperature in degree Celsius
Temperature = (float(int(dht.readTemperature() * 10))/10);
isValid = true;
if (isnan(Humidity) || isnan(Temperature)) {
isValid = false;
}
temphum["temperature"] = Temperature;
temphum["humidity"] = Humidity;
temphum["isValid"] = isValid;
lastMsg = now;
char out[256];
int b =serializeJson(temphum, out);
snprintf (msg, MSG_BUFFER_SIZE, out);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("my/mqqt/temperature", msg);
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Please send aid by uploading your entire directory, I am having problems pulling the files. My job and therefore my life depends on it!