-
Notifications
You must be signed in to change notification settings - Fork 13.3k
BearSSL::WiFiClientSecure not working the same way axTLS did #4738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Please check the examples. You have not set any CAs, nor have you asked it to be insecure (i.e. SSL connect but w/o checking certificates). Added #4739 to track adding some debug output beyond the GetLastError API. |
Thanks, I already found client.setInsecure(). Debug Messages
MCVE Sketch (logger lines removed)BearSSL::WiFiClientSecure client;
client.setInsecure();
client.setTimeout(API_TIMEOUT);
client.connect(host, httpsPort);
client.print(String("POST ") + url + " HTTP/1.0\r\n" +
"Host: " + host + "\r\n"
+ "Content-Type: application/json\r\n"
+ "Content-Length: " + data.length() + "\r\n\r\n"
+ data);
client.setTimeout(API_TIMEOUT);
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line.startsWith("HTTP/1.")) {
res.code = line.substring(9, 12).toInt();
}
if (line.startsWith("Content-Length: ")) {
c_len = line.substring(15).toInt();
}
if (line == "\r") {
break;
}
}
if (client.available()) {
bytes = client.readBytes(c_buf, c_len);
c_buf[c_len] = '\0';
}
res.content = String(c_buf);
client.stop();
return (res);
} |
@artua, can you please give a full sketch example that doesn't work and can be publicly accessible? I'm not able to reproduce it with my own testing... |
Hello @earlephilhower Here is quick sketch for you to quickly compare two clients and debug output for both. Maybe timeout is hardcoded or setTimeout() not working? Also please note it takes almost 500ms more for BearSSL to connect. It's huge for tiny battery-powered devices. Sketch#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
const int API_TIMEOUT = 8000;
struct Result {
int code;
String content;
};
Result res;
String line;
int myWdt;
const char* host = "el-sag.com";
const char* url = "/bearssl.txt";
const int httpsPort = 443;
long init_ms;
String data = "{}";
bool TOUT;
int c_len;
char c_buf[512];
int bytes;
void setup() {
// put your setup code here, to run once:
init_ms = millis();
Serial.begin(74880);
Serial.print("Connecting to Wifi");
WiFi.begin();
while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(200); }
Serial.println();
logger("Free HEAP: " + String(ESP.getFreeHeap()));
}
void loop() {
myWdt = millis();
BearSSL::WiFiClientSecure client;
client.setInsecure();
//WiFiClientSecure client;
client.setTimeout(API_TIMEOUT);
logger("Client Secure started " + String(millis() - myWdt) + " ms");
logger("Free HEAP: " + String(ESP.getFreeHeap()));
logger("connecting to " + String(host));
myWdt = millis();
if (!client.connect(host, httpsPort)) {
logger("Connection failed " + String(millis() - myWdt) + " ms");
res.code = 0; res.content = F("connection failed");
return; // 1 = connection failed
}
logger("Free HEAP: " + String(ESP.getFreeHeap()));
logger("Connected " + String(millis() - myWdt) + " ms");
myWdt = millis();
logger("Free HEAP: " + String(ESP.getFreeHeap()));
logger("requesting URL: " + String(url) + " with data: " + String(data));
myWdt = millis();
client.print(String("POST ") + url + " HTTP/1.0\r\n" +
"Host: " + host + "\r\n"
+ "Content-Type: application/json\r\n"
+ "Content-Length: " + data.length() + "\r\n\r\n"
+ data);
logger("Request sent " + String(millis() - myWdt) + " ms");
logger("Free HEAP: " + String(ESP.getFreeHeap()));
client.setTimeout(API_TIMEOUT);
myWdt = millis();
TOUT=1;
while (client.connected()) {
line = client.readStringUntil('\n');
if (line.startsWith("HTTP/1.")) {
res.code = line.substring(9, 12).toInt();
logger("Got HTTP code " + String(res.code));
}
if (line.startsWith("Content-Length: ")) {
c_len = line.substring(15).toInt();
logger("Got Content-length: " + String(c_len));
}
if (line == "\r") {
logger("Headers received " + String(millis() - myWdt) + " ms");
logger("Free HEAP: " + String(ESP.getFreeHeap()));
TOUT=0;
break;
}
}
if(TOUT) {
logger("\n*** Timeout receiving headers\n");
return;
}
myWdt = millis();
if (client.available()) {
TOUT=1;
//res.content += String(client.read());
bytes = client.readBytes(c_buf, c_len);
c_buf[c_len] = '\0';
TOUT=0;
}
if(TOUT) {
logger("\n*** Timeout receiving body\n" + String());
return;
}
res.content = String(c_buf);
logger("Result length: " + String(res.content.length()) + " | " + String(bytes));
logger("Content received " + String(millis() - myWdt) + " ms");
logger("Free HEAP: " + String(ESP.getFreeHeap()));
myWdt = millis();
client.stop();
logger("Client stop " + String(millis() - myWdt) + " ms");
logger("Free HEAP: " + String(ESP.getFreeHeap()));
logger("\n*** Result: " + res.content);
}
void printTS() {
long ts = millis() - init_ms;
int m = ts / 60000;
int s = (ts) / 1000 - m * 60;
int ms = ts - m * 60000 - s * 1000;
Serial.printf("%02d:%02d:%03d ", m, s, ms);
}
void logger(String str) {
printTS();
Serial.println(str);
} Debug (BearSSL)
Debug (axTLS)
|
Looks like a bug in |
The SSL pipeline is multi-stage, and the TCP connection can go down even though there is still data waiting to be decrypted or in the decryption buffer. Explicitly check that there if there can be any data made available to the app, and if so report that we are still connected(). When there is no data and there is no TCP connection, report disconnected. Fixes esp8266#4738
@earlephilhower When it will be merged to master so I can check? |
Please make a branch that has this PR in your own repo and try it out with your test...I'll be waiting on your response before it gets into master. :) https://help.github.com/articles/checking-out-pull-requests-locally/ |
@earlephilhower yes, now it's working. Update: now it gives me timeouts with another host (powered by cloudflare, so using modern ciphers).
^^^ here I set timeout to 15000ms |
Can you leave that URL accessible for a while? I'll try tonight (12hrs or so). In the meantime, can you add a call to the client.getLastSSLError() and dump that on "timeout" as well as the state of connected()/etc. The code I saw kind of mushed up socket timeout with !connected() so it's hard to say what you're seeing from the dump.
Best I can about the speed is tell you to use 160MHz, not 80MHz (avail from the menus). There's no HW acceleration of any kind in the system. Even 32-bit multiply is emulated. For EC key exchange @Adam5Wu and I have seen multi-second handshakes even at 160MHz. |
Sure, it will be accessible.
If I understood it right:
|
That'll do. Can you also run using axTLS and verify that it works? Might be something related to other bits, that'd passing would help ensure it's related to BSSL. Thx! |
Thought deleting the fixed bit would make this not close. Guess not! Re-opening. |
Try pull #4756 . You found two bugs in the code! This second one had to do with the way partial reads from the SSL buffer were handled when the server responds fast and closes down the connection. I've run against your server and it seems to work all the time. |
Now working perfectly. Thanks! 01:38:003 Cycles: 91 Head TOUTs: 0 Body TOUTs: 0 |
@artua, if you have a fixed system you're connecting to, you can use the client.setKnownKey(key) to hardcode the public key of the other system. That should take connection time down dramatically as it ignores the x509 certificate completely and uses the server public key you code to encrypt things. Check the BearSSL_Validation example for more info. Closing this for now. |
Thanks. Will try it later.
…On Thu, May 24, 2018 at 4:43 PM Earle F. Philhower, III < ***@***.***> wrote:
@artua <https://github.com/artua>, if you have a fixed system you're
connecting to, you can use the client.setKnownKey(key) to hardcode the
public key of the other system. That should take connection time down
dramatically as it ignores the x509 certificate completely and uses the
server public key you code to encrypt things.
Check the BearSSL_Validation example for more info.
Closing this for now.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4738 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AGV_3UCGFHv3kcTOKWMkqRSKx_elYFOrks5t1rkAgaJpZM4UDJEB>
.
|
Hi @earlephilhower Is it ok? Because you told me the last method should dramatically increase TLS handshake... setInsecure()
setKnownKey()
For example, the same timings for the same server via HTTP:
Any ideas how can I find TLS timings breakdown? |
@artua There's no way in BearSSL of getting a detailed breakdown, but I misspoke so this is expected, actually. The way a TLS handshake works is that you check the x509 and signing up through the cert chain until you find one you trust, then you use the public key to do some exchange of entropy. So you still need to do the EC stuff if the public key is EC. |
I got something like 120ms with curl on my macbook. I know it is
incomparable in terms of computing power but maybe you know some way to speed up the connection? I have access to server configuration also, so I
can set up any cipher/options on server side.
Maybe if we put known cipher on server side also the same on client side then we can speed up this challenge?
…On Mon, Jun 4, 2018 at 12:11 AM Earle F. Philhower, III < ***@***.***> wrote:
@artua <https://github.com/artua> There's no way in BearSSL of getting a
detailed breakdown, but I misspoke so this is expected, actually. The way a
TLS handshake works is that you check the x509 and signing up through the
cert chain until you find one you trust, then you use the public key to do
some exchange of entropy. So you still need to do the EC stuff if the
public key is EC.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4738 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AGV_3WOL9cKzQn9G4vq1UVRI0i0JcrLNks5t5FDygaJpZM4UDJEB>
.
|
I recall that SSL do have some part of the protocol for fast reconnection, if the client can remember something, subsequent connection can be much faster than the first one. Is that supported/implemented with BearSSL? |
They're SSL sessions, like HTTP. It's dependant on the server and client, of course. As of now the BearSSL::WiFiClientSecure does NOT enable them, as they take some amount of RAM and we're not exactly drowning in available heap. The session ID is stored as well as the last encryption params by the client, and then it sends it back to the server on a reconnect sometime later who either accepts it (and uses the last settings) or starts a new negotiation. If there's a real demand I (or someone else!) can add a patch that adds a "bool enableSessions(uint count)" method. Feel free to open an issue or pull request. :) First, though, I want to get the CertStore changes accepted, though, as that's a more common issue since PIO's default is unsafe but common and tripping up folks. I think axTLS also has the option, but it's also not implemented in the wrapper class. |
I also met same error with client.connect, but I use connect(IPAddress, port). host_name = "google.com", "api.github.com", that works, but when I change to 192.168.1.210, it always connect fail !! I followed following link to create a web server (apache2) + php + mysql + phpMyAdmin, I can use browser to login https://192.168.1.210/phpMyAdmin correctly, but I cannot use sketch to access it with WiFiClientSecure client. I use dos command line to check port 443 with following here is my sketch.
============================== |
@devyte
|
@artua thank you for a great performance testing blueprint, much appreciated! While investigating https://stackoverflow.com/q/52143894 I found this issue and tinkered with your sketch. It's not the scope of this issue but I can confirm the devastating (performance) findings for BearSSL. I was only testing insecure SSL:
=> no-go for battery powered devices Side note: BearSSL is also consuming considerably more heap. |
@marcelstoer @artua please open a new issue to discuss axtls vs. bearssl performance, and add the perf numbers shown here. |
Yep, wanted to do that anyhow. |
Interesting notes, @marcelstoer! Please make sure both are using the exact same handshake and encryption methods, as BearSSL often negotiates a more secure but slower running cypher. You can do so by limiting the receiving end's connection capabilities in your SSL configuration. |
@earlephilhower Does "larger bandwidth" make a difference ? |
@marcelstoer <https://github.com/marcelstoer> thanks! please post a link to
new thread here, so I can participate too.
|
@d-a-v Are you suggesting BW tests, too? Sounds like a good idea. But it's not really actionable (nor is the connect time) as I'm simply calling the BearSSL internal code to do the real work. Also, @marcelstoer, it may look like BearSSL is using more heap as it allocates everything all at once. But, in reality, axTLS does lots of heap allocations while it's working on a function call. So your |
@earlephilhower No, only wondering if you checked the impact of MSS. |
Do you know or could you say if the line is secure encrypted if you use setInsecure to a backend with a not expited certificate? I understand setInsecure will not validate the certtifcate at the backend but is it correct the data cannot be read by anybody? Second how do i read the attributes from the backend certificate, i would like to check the common name and domeinname. |
As to your first question: without checking a certificate the communication is vulnerable to MITM attack. It is encrypted, obviously, but the MITM is able to decrypt it. Edit: Let me add that TLS without checking the certificate (the setInsecure option) is secure against eavesdroppers though. |
Platform
Settings in IDE
Problem Description
BearSSL::WiFiClientSecure does not connect. No debug messages at all (debug tls+ssl+http client). My custom logs attached.
MCVE Sketch
Debug Messages
The text was updated successfully, but these errors were encountered: