I am making web application, where ESP32 is sending and also reading some datas from website.
ESP32 is client. I am using WifiClientSecure.h library for HTTPS connection.
I have tried to put Let's Encrypt certificate to my website, Global Root CA was DST ROOT CA x3.
I have downloaded its .pem certificate and put it to code.
It is working without any problem.
Nowadays I have tried to generate own certificates for server, CA, client. I have installed that generated CA certificate to Windows laptop and connection is working. I also added that CA .pem to code for ESP32 but connection is unsucessful. Certificate is valid isn't revoked or something like that. On Windows, Android working everything great.
Errors are:
Code: Select all
[E][ssl_client.cpp:32] handle_error(): X509 - Certificate verification failed, e.g. CRL, CA or signature check failed
[E][ssl_client.cpp:34] handle_error(): MbedTLS message code: -9984
[E][WiFiClientSecure.cpp:108] connect(): lwip_connect_r: 11
Code: Select all
#include <WiFi.h> //Wifi kniznica - pripojenie na wifi, HTTP konektivita - Webclient
#include <SPI.h>
#include <WiFiClientSecure.h>
#include "esp_wpa2.h" //doplnkova kniznica pre WPA/WPA2 Enterprise siete pod protokolom 802.1x
#include <Wire.h>
#include "SparkFun_Si7021_Breakout_Library.h" //Kniznica pre SHT21 senzor
//Identita a meno su totozne
//Metoda overenia Eduroamu: 1. krok PEAP + 2. krok MsCHAPv2
#define EAP_IDENTITY "identity" //identita - bez @tuke.sk pri pripojeni z inej organizacie, pouzit login@tuke.sk
#define EAP_PASSWORD "password" //heslo pouzivatela
const char* ssid = "INTRAK"; // Eduroam SSID
const char* host = "www.esp32.sk"; //adresa externeho webservera
const int rele = 23; //nastavenie premennej na GPIO pin 23
int pocitadlo = 0; //pocitadlo pre timeout
int rssi;
Weather sensor; //instancia pre senzor
#ifdef __cplusplus
extern "C" { //externa cast jazyka C
#endif
uint8_t temprature_sens_read(); //systemove volanie funkcie teplomera
#ifdef __cplusplus
}
#endif
const char* test_root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIICSjCCAbMCFHGiBSCT7reuv03fRC18PtDIqmdXMA0GCSqGSIb3DQEBCwUAMGQx\n" \
"CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApGYWtlIFN0YXRlMRYwFAYDVQQHDA1GYWtl\n" \
"IExvY2FsaXR5MRUwEwYDVQQKDAxGYWtlIENvbXBhbnkxETAPBgNVBAMMCGVzcDMy\n" \
"LnNrMB4XDTE4MTIxMzAwMTgxMFoXDTIzMTIxMjAwMTgxMFowZDELMAkGA1UEBhMC\n" \
"VVMxEzARBgNVBAgMCkZha2UgU3RhdGUxFjAUBgNVBAcMDUZha2UgTG9jYWxpdHkx\n" \
"FTATBgNVBAoMDEZha2UgQ29tcGFueTERMA8GA1UEAwwIZXNwMzIuc2swgZ8wDQYJ\n" \
"KoZIhvcNAQEBBQADgY0AMIGJAoGBAJYEKHi3PD8EDgj39wO02LDpSaim41BOu1GR\n" \
"ZoCScLPq8++l9DdTD31sVm37XCxQul8XUUpHpfKr2Ibspwv+AMj/fy12Rf49hZBg\n" \
"ey0qQrCbKJPC74nEIQHd7Y3/P++j8XRFUC0P3Pla+pSo6u2sEQrBtE23rJjXn3JQ\n" \
"Gcu7MSRtAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAI9CjtIxFQcaU9D8N2qBGvhP8\n" \
"PR4fC2dLPTRpyhpvbh5ABXwiOIVfN5zZFfCXPCHgXbcoYiSe9clutXFl9CZVFO1b\n" \
"cqXm2M29OwlZ38FL1n1GXvsbtPZCNjvjIoh8GJQtrbrB2TGCib55aKgDInLHJGPl\n" \
"RpwC0wffnU3m28c1clI=\n" \
"-----END CERTIFICATE-----\n";
// You can use x.509 client certificates if you want
//const char* test_client_key = ""; //to verify the client
//const char* test_client_cert = ""; //to verify the client
WiFiClientSecure client;
void setup() { //cast setupu prebieha iba raz
Serial.begin(115200); //pocet znakov/s v serial monitore - UART
delay(10); //vyckaj na inicializaciu
sensor.begin();
Serial.println();
Serial.print("Pripajam sa na wifi siet: ");
Serial.println(ssid); //informativne vypisy o nazve wifi siete
WiFi.disconnect(true); //odpoj sa od wifi pred nastavenim noveho pripojenia
WiFi.mode(WIFI_STA); //nastavenie modu wifi modulu - vyzadovane v ESP32 Arduino Core v poslednych 2 verziach
//pinMode(LED_BUILTIN, OUTPUT); nastavenie vystupu - zabudovana led
pinMode(rele, OUTPUT);
esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //nastavenie identity
esp_wifi_sta_wpa2_ent_set_username((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //nastavenie mena - identita a meno a zhoduju
esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EAP_PASSWORD, strlen(EAP_PASSWORD)); //nastavenie hesla
esp_wpa2_config_t config = WPA2_CONFIG_INIT_DEFAULT(); //crypto funkcie (sha1, sha256.....) - z kniznice esp esp_wpa2.h
esp_wifi_sta_wpa2_ent_enable(&config); //nakonfiguruj sietove pripojenie
WiFi.begin(ssid);
while (WiFi.status() != WL_CONNECTED) { //pokym nie je zariadenie autentizovane a autorizovane, pozdrz program a posielaj . do vypisu
delay(500); // pauza 500ms
Serial.print("."); // vypis znaku
pocitadlo++; //inkrementuj pocitadlo
if(pocitadlo>=60){ //po 30 sekundach restartuj dosku softverovym resetom, ak nedojde k pripojeniu
ESP.restart();
}
}
client.setCACert(test_root_ca);
//client.setCertificate(test_client_key); // for client verification
//client.setPrivateKey(test_client_cert); // for client verification
Serial.println("");
Serial.println("WiFi pripojene");
Serial.println("IP addresa nastavena: ");
Serial.println(WiFi.localIP()); //vypis pridelenu IP od DHCP sluzby
}
void restart(){
Serial.print("Pripajam sa na: ");
Serial.println(host);
if (client.connect(host, 443)) { //ak je spojenie uspesne na server na porte 80 vykonaj blok prikazov
Serial.println("Pripojenie pre kontrolu resetu uspesne");
String url = "/values/reset.txt"; //citanie z URL adresy na serveri
client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: NodeMCU\r\n" + "Connection: close\r\n\r\n");
//vykonanie GET HTTP requestu s verziou HTTP hlavicky, adresa hosta, user-agent zariadenia, ukoncenie HTTP hlavicky
while (client.connected()) {
String hlavicka = client.readStringUntil('\n'); //vypis hlavicky po riadkoch, verzia, engine, info o serveri, dlzka response atd...
Serial.println(hlavicka);
if (hlavicka == "\r") {
break; //prazdny riadok za hlavickou, ukonc cyklus
}
}
String premenna = client.readStringUntil('\n'); //riadok za HTTP hlavickou - nasa premenna, s ktorou pracujeme
Serial.println(premenna);
if(premenna=="RST"){ //za normalnych okolnosti je v premennej OK, ignoruje sa, pokym z webu nie je vyziadany reset, ktory zmeni obsah na RST.
Serial.println("Restart vyziadany");
client.stop(); //ukonc vsetky HTTP spojenia
if (client.connect(host, 443)) {
Serial.println("Potvrdzujem reset");
String url = "/esp32/potvrdreset.php"; //potvrd reset tymto HTTP requestom, ktory opat nastavi do textoveho suboru text OK
client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: NodeMCU\r\n" + "Connection: close\r\n\r\n");
delay(1000);
Serial.println("Restartujem...");
ESP.restart(); //softverovy restart zariadenia
}else{
Serial.println("Nepodarilo sa potvrdit reset - pripojenie zlyhalo");
}
}
}else{
Serial.println("Nepodarilo sa nacitat stav resetu");
}
client.stop();
}
void stav_rele(){
Serial.print("Pripajam sa na: ");
Serial.println(host);
if (client.connect(host, 443)) {
Serial.println("Pripojenie pre stav rele uspesne");
String url = "/values/stav.txt";
client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: NodeMCU\r\n" + "Connection: close\r\n\r\n");
while (client.connected()) {
String hlavicka = client.readStringUntil('\n');
Serial.println(hlavicka);
if (hlavicka == "\r") {
break;
}
}
String premenna = client.readStringUntil('\n');
Serial.println(premenna);
if(premenna=="ZAP"){ //rozhodovanie medzi ZAP a VYP stavom citaneho z .txt suboru
Serial.println("ZAPINAM RELE");
digitalWrite(rele, HIGH);
// digitalWrite(LED_BUILTIN, HIGH);
}else if(premenna=="VYP"){
Serial.println("VYPINAM RELE");
digitalWrite(rele, LOW);
// digitalWrite(LED_BUILTIN, LOW);
}
}else{
Serial.println("Nepodarilo sa nacitat stav rele");
}
client.stop(); //ukonc spojenia
}
void odoslanie(){
float vlhkost = sensor.getRH();
float teplotadnu = sensor.getTemp();
String hum = String(vlhkost);
String temp2 = String(teplotadnu);
float teplota = (temprature_sens_read() - 32) / 1.8; //teplota cpu, povodna extern C funkcia - konstanta / konstanta
String temp = String(teplota); //Pomocna premenna typu String, kolizia pri vyskladani GET requestmi s roznymi datovymi typmi String - float, int ....
int sonda = hallRead(); //nacitanie udajov z hallovej sondy, systemova funkcia
String hall = String(sonda); //prevedenie na String do pomocnej funkcie
unsigned long beh = millis();
String uptime = String(beh);
if (client.connect(host, 443)) { //ak je pripojenie uspesne
Serial.println("Pripojenie pre odoslanie dat uspesne");
String url = "/esp32/zapisdata.php?teplota="+temp+"&hall="+hall+"&temp2="+temp2+"&hum="+hum+"&uptime="+uptime+"&signal="+rssi+"&ssid="+ssid; //vyskladany HTTP request s dvomi hodnotami, oddelene ampersandom & - pre rozlisenie na strane webu
client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: NodeMCU\r\n" + "Connection: close\r\n\r\n");
}else{ //ak je pripojenie neuspesne, informuj do UART monitoru
Serial.println("Nepodarilo sa odoslat data"); //informativny vypis
}
client.stop();
}
void loop() {
if (WiFi.status() == WL_CONNECTED) { //ak je pripojenie uspesne
pocitadlo = 0; //vynuluj pocitadlo
Serial.println("Wifi je stale pripojene s IP: ");
Serial.println(WiFi.localIP()); //informuj pouzivatela o jeho IP v kazdej slucke
rssi = WiFi.RSSI();
Serial.print("Sila signalu (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}else if (WiFi.status() != WL_CONNECTED) { //ak nie je uspesne, opakuj spojenie
Serial.println("Spojenie stratene - Pripajanie k wifi...");
WiFi.begin(ssid);
}
while (WiFi.status() != WL_CONNECTED) { //pozdrz program, pokym sa doska pripoji
delay(500);
Serial.print(".");
pocitadlo++;
if(pocitadlo>=60){ //po 30 sekundach restartuj dosku softverovym resetom, ak nedojde k pripojeniu
ESP.restart();
}
}
odoslanie(); //volanie funkcie pre odosielanie
stav_rele(); //volanie funkcie pre citanie stavu rele
restart(); //volanie funkcie pre citanie vyziadania resetu
delay(2000); //pockaj 2 sekundy pred novou sluckou
}
I have generated certificates with OpenSSL with following commands:
Code: Select all
openssl genrsa -out myCA.key 1024
openssl req -x509 -config certificate-authority-options.conf -new -nodes -key myCA.key -sha256 -days 1825 -out myCA.pem
openssl x509 -outform pem -in myCA.pem -out myCA.crt
openssl genrsa -out server.key 1024
openssl req -config options.conf -new -key server.key -out server.csr
openssl x509 -req -in server.csr -CA myCA.pem -CAkey myCA.key -CAcreateserial -out server.pem -days 1825 -sha256 -extfile server.ext
openssl x509 -outform pem -in server.pem -out server.crt
openssl genrsa -out client.key 1024
openssl req -config options.conf -new -key client.key -out client.csr
openssl x509 -req -in client.csr -CA myCA.pem -CAkey myCA.key -CAcreateserial -out client.pem -days 1825 -sha256 -extfile client.ext
Code: Select all
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = esp32.sk
DNS.2 = www.esp32.sk
Code: Select all
[req]
prompt = no
distinguished_name = req_distinguished_name
[req_distinguished_name]
C = US
ST = Fake State
L = Fake Locality
O = Fake Company
# OU = Org Unit Name
# emailAddress = info@example.com
CN = esp32.sk