Hallo zusammen,
ich versuche, mit meinem ESP32 einen HTTP GET request auf einen
WebServer, der auf einer speziellen Maschine läuft, auszuführen,
allerdings mittels einer sicheren Verbindung (HTTPS).
Wenn ich in dem Code zum BasicHTTPSClient.ino-Beispiel aus der Arduino
IDE nur den WLAN-Namen und das WLAN-Passwort in WiFi.begin() ändere und
anschließend hochlade (ich hänge den Code nachher noch an, also siehe
unten), sieht mein Output auf dem Serial Monitor ungefähr so aus:
1
Waiting for WiFi to connect................ connected
Also habe ich mal mit WireShark auf die Leitung gehört, um
herauszufinden, warum der Server die Verbindung verweigert. Dabei ist
mir folgende Zeile aufgefallen:
Es scheint, als erwarte der Server also AES256 bzw. SHA384 Chiffren,
aber der ESP diese nicht standardmäßig unterstützt/beherrscht.
Kann mir jemand vielleicht sagen, wie ich meinem ESP32 beibringe,
AES256/SHA384 zu unterstützen?
Freue mich über jede Antwort, vielen Dank im voraus, und sorry falls ich
an irgend einer Stelle Probleme hatte, mich auszudrücken bzw. mein
Problem zu beschreiben, ich hoffe es war dennoch irgendwie verständlich.
Liebe Grüße
PS: Der Vollständigkeit halber hier noch der Code, den ich versucht
habe, auszuführen:
1
/**
2
BasicHTTPSClient.ino
3
Created on: 14.10.2018
4
*/
5
6
#include<Arduino.h>
7
#include<WiFi.h>
8
#include<HTTPClient.h>
9
#include<WiFiClientSecure.h>
10
11
// This is GandiStandardSSLCA2.pem, the root Certificate Authority that signed
12
// the server certifcate for the demo server https://jigsaw.w3.org in this
13
// example. This certificate is valid until Sep 11 23:59:59 2024 GMT
Bevor du irgendwelche speziellen Cipher/Digest-Algorithmen auspackst:
Hat der Server https://192.168.200.146/ ein gültiges Zertfikat, *was
auch 192.168.200.146* beinhaltet?
Bei Let's-Encrypt gibt es sowas nicht.
=> Hostnamen statt IP verwenden, ggfs. im DNS tricksen.
Kannst du die URL z.B. mit "curl" ohne Fehlermeldung aufrufen?
Und:
Hast du den richtigen, zugehörigen CA-Root-Key extrahiert und in dein
Programm einkompiliert?
Da muss der Public-Key rein, mit dem dein Server-Zertifikat signiert
ist, nicht das Server-Zertifikat selber.
Hallo @ernst und vielen herzlichen Dank für deine Antwort!
Um ehrlich zu sein, bin ich leider nur ein kleiner Student, der gerade
in dieser ganzen Mikrocontroller/Arduino/ESP/IOT-Welt anfängt, sorry^^
Trotzdem möchte ich versuchen, deine Fragen so adäquat wie möglich zu
beantworten:
1.) Du frägst, ob das Server-Zertifikat die Host-IP beinhaltet. Das wage
ich zu bezweifeln, da der Server seine IP über DHCP erhält (sprich die
könnte sich nach Netzneustart theoretisch ändern). Was meinst du mit
"Bei Let's-Encrypt gibt es sowas nicht"?^^ Der Server befindet sich auch
lediglich in meinem lokalen Netz und ist nicht ans Internet angebunden.
Daher kann ich leider mit deinem Tipp "Hostnamen statt IP verwenden,
ggfs. im DNS tricksen." grad noch wenig anfangen sorry :-/
2.) Du hast weiterhin gefragt, ob ich die URL z.B. mit "curl" ohne
Fehlermeldung aufrufen kann. Wenn ich in meiner CMD-Konsole
curl: (77) schannel: next InitializeSecurityContext failed: SEC_E_UNTRUSTED_ROOT (0x80090325) - Die Zertifikatkette wurde von einer nicht vertrauenswürdigen Zertifizierungsstelle ausgestellt.
Wenn ich die URL im Browser aufrufe, so wird mir angezeigt, dass die
Website nicht sicher sei (Fehlercode: DLG_FLAGS_INVALID_CA
DLG_FLAGS_SEC_CERT_CN_INVALID). Allerdings kann ich unten auf "Details"
und dann auf "Webseite trotzdem laden" klicken. Gebe ich im nun
folgenden PopUp den richtigen Benutzernamen sowie das korrekte Passwort
ein, so erhalte ich den gewünschten JSON-String angezeigt.
Auch in C# kann ich die Zertifikatsvalidierung ganz einfach
manipulieren:
Bei ESP scheint das leider nicht so einfach zu sein :(
3.) Um des CA-Root-Keys meines Servers habhaft zu werden, bin ich exakt
nach diesem Tutorial vorgegangen:
https://techtutorialsx.com/2017/11/18/esp32-arduino-https-get-request/
Ich hoffe natürlich, die Anleitung hier war korrekt und ich habe den
Public-Key und nicht das Server-Zertifikat dadurch bekommen.
Vielen Dank nochmals für deine Hilfsanstrengungen. Liebe Grüße :)
der ESP32 (-Arduino-core) verwendet die "MbedTLS"-Bibliothek für TLS,
diese unterstützt u.A.
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" und
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
d.H. dein Problem ist vermutlich wirklich das ungültige / self-signed
Zertifikat.
Wenn dir nicht wichtig ist, dass das geprüft wird, lass den Check
einfach weg.
d.H.:
1
client->setCACert(rootCACertificate);
und das "rootCACertificate" auskommentieren, testen.
Evtl. gibt es eine Warn-Meldung beim connect,
1
log_i("WARNING: Use certificates for a more secure communication!");
Ich würde an deiner Stelle jetzt anfangen, das Schrittweise zu debuggen.
z.B. erstmal versuchen, ob der WiFiClientSecure eine Verbindung aufbauen
kann, unabhängig von HTTP, "GET" usw.
Dazu alles rausnehmen, was den http-client benutzt, und übriglassen:
1
WiFiClientSecure*client=newWiFiClientSecure;
2
if(!client->connect("192.168.200.146",443)){
3
Serial.println("Fehler");
4
}else{
5
Serial.println("Verbunden");
6
}
7
client->stop();
8
deleteclient;
9
Serial.println("Waiting 10s before the next round...");
10
delay(10000);
Evtl. im Fehlerfall client->lastError(char *buf, const size_t size);
aufrufen, ausgeben.
Sam M. schrieb:> Oder hab ich es an der falschen Position eingefügt?
Nö, das ist bei "Verbunden" schon richtig aufgehoben.
Änder den Fehler-Pfad mal ab:
Ups. mein Fehler.
Die "client->available()"-Schleife wird nicht richtig betreten, weil
nicht sofort Daten vorhanden sind.
mach mal noch eine "while connected" Schleife drum.
also
1
while(client->connected()){
2
while(client->available()){
3
Serial.write(client->read());
4
}
5
yield();
6
}
Unabhängig davon: Der Request müsste schon am Server angekommen sein,
kannst du da ins Logfile schauen?
<html><head><title>Nicht autorisiert</title></head><body><h2>Zugang verweigert. Bitte überprüfen Sie ihre Eingaben.</h2></body></html>
Allerdings bricht er danach ab und loopt nicht weiter gell. Also das ist
der komplette Output,
1
Waiting 10s before the next round...
kommt nicht mehr, egal wie lang ich warte...
Wir müssen uns jetzt glaube ich noch irgendwie mit Benutzername/Passwort
authentifizieren oder? :X
Zu deiner Frage noch kurz ob ich irgendwie ins Logfile des Servers
schauen kann: das wird wahrscheinlich schwer, da das Gerät, auf das ich
mich zu verbinden versuche, kein "Computer" ist, also kein "normales"
Windows/Linux hat, sondern ein Spielautomat xD Daher weiß ich leider
nicht, ob dieser überhaupt Logfiles für Requests führt, und falls doch,
wo die sein sollen/wie ich an die rankomme :P Ich kann aber morgen mal
meine Kollegen fragen, vielleicht wissen die das^^
Sam M. schrieb:> Allerdings bricht er danach ab und loopt nicht weiter gell. Also das ist> der komplette Output,> Waiting 10s before the next round...kommt nicht mehr, egal wie lang ich> warte...
Liegt daran, dass diese Schleife keine vollwertige HTTP-Implementation
ist.
Ein "Connection: close" - Header mitzusenden könnte das verbessern.
Aber Egal, Test-Resultat: Am TLS, den Verschlüsselungsalgorithmen, den
Zertifikaten o.Ä. liegt es nicht.
Insofern wäre der nächste Schritt im soweit funktionierenden
Testprogramm das "HTTP-von-Hand"-Senden wieder rauszunehmen und durch
den HTTPClient zu ersetzen.
Damit fällt dann auch das Basic-Auth leichter.
Εrnst B. schrieb:> Aber Egal, Test-Resultat: Am TLS, den Verschlüsselungsalgorithmen, den> Zertifikaten o.Ä. liegt es nicht.>> Insofern wäre der nächste Schritt im soweit funktionierenden> Testprogramm das "HTTP-von-Hand"-Senden wieder rauszunehmen und durch> den HTTPClient zu ersetzen.> Damit fällt dann auch das Basic-Auth leichter.
Hallo Ernst und vielen vielen herzlichen Dank für deine Hilfe, du hast
mir echt meinen A*sch gerettet!^^
Komischerweise hat das jetzt funktioniert - ich habe den Code des
HTTPClients wieder reingenommen/-kopiert und volià auf einmal erhalte
ich das gewünschte JSON. Keine Ahnung was das Problem war, ich hab mir
echt nen Wolf gesucht xD