Skip to content
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

WifiClientSecure::connect does not give any certificate-fail clarification #1361

Closed
Rob58329 opened this issue Apr 27, 2018 · 5 comments

Comments

Projects
None yet
3 participants
@Rob58329
Copy link

commented Apr 27, 2018

Hardware:

Board: ESP32 "NodeMCU-32S"
Core Installation/update date: GitHub as at 26Apr18
IDE name: Arduino IDE

Description:

WiFi_Client_secure.connect [WifiClientSecure::connect] does not distinguish between a [fail due to no-connection-to-server/no-reply-from-server] and a [fail due to bad security-certificate/"test_root_ca"]

Details:

I note that using the current GitHub (as at 26Apr18), when the command "WiFi_Client_secure.connect(address, port)" fails for any reason, it returns zero. IE. it appears not possible to determine if the failure was due to (a) no reply from the server, or (b) a "test_root_ca" or other security-certificate-failure (due to expiry or other reason).

In my application, if the failure is due to a "security-certificate failure", I would like to be able to note this and then continue (or re-start) the connection ignoring the security-certificate-failure (which is possible by resetting the "*test_root_ca=NULL;"). However to do this I need know if the "WiFi_Client_secure.connect(address, port)" failure was due to the security-certificate or due to a connection failure (ie. the server not replying).

This was possible for the ESP8266 (as the [WiFi_Client_secure.verify] was a separate command). But for the ESP32 (which does the verify within .connect) there currently seems to be no way to distinguish these 2 different failure reasons (as the "WiFi_Client_secure.connect" just returns zero for any type of failure).

Is there any way to determine/identify these 2 different failure reasons?

[PS. I note that the "espressif erno.h" has an error message "#define EKEYEXPIRED 127 /* Key has expired */", but don't think this is currently made use of in the above?]

Any info would be appreciated!


Update (29Apr): Many thanks to [copercini] for the below info!

The code:

int cert_result=WiFi_Client_secure.lastError(NULL,0);
if (cert_result==-1) Serial.println(F("ERR: No Server Connection"));
else if (cert_result<0) Serial.println(F("ERR: Certificate or Certificate-Chain Error"));

does exactly what I was after! :-)

@copercini

This comment has been minimized.

Copy link
Collaborator

commented Apr 27, 2018

If you are just debugging, enable the verbose logs of arduino IDE and it will give you the exactly error, but if you want to catch it in the code, WifiClientSecure::lastError() can be used like this:

  if (WiFi_Client_secure.connected()) {
      Serial.println("Connected!");
  } else {
      Serial.println("Connection failed!");
      char err_buf[100];
      if (WiFi_Client_secure.lastError(err_buf, 100) < 0) {
          Serial.println(err_buf);
      } else {
          Serial.println("Connection error");
      }
  }

@Rob58329 Rob58329 closed this Apr 29, 2018

@iamneo2416

This comment has been minimized.

Copy link

commented Jun 15, 2018

ME TOO, I meet the same problem !! Strange thing that when I add code you provide, and I got compile error. "'class WiFiClientSecure' has no member named 'lastError'"

if (WiFi_Client_secure.connected()) {
      Serial.println("Connected!");
  } else {
      Serial.println("Connection failed!");
      char err_buf[100];
      if (WiFi_Client_secure.lastError(err_buf, 100) < 0) {
          Serial.println(err_buf);
      } else {
          Serial.println("Connection error");
      }
  }

Hardware:

Board: ESP8266 NodeMCU V2
Core Installation/update date: 2018/03/21
IDE name: Arduino IDE
Flash Frequency: 80Mhz
Upload Speed: 115200

Description:

I installed ubuntu 16.04 apache web server with self-signed certificate in LAN environment and use browser to access https://192.168.1.210/ web page always successfully.

I even use dos command line to telnet 192.168.1.210 443 to check port listening. It's working perfectly.
C:> telnet 192.168.1.210 443

But when I use WiFiClientSecure client.connect(ip, 443). It always get fail return. Is this a bug for ipv4 connect in connect function ?

Here is the exact step I followed to build this virtual machine (192.168.1.210) w/self-signed certificate.
https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-ubuntu-16-04

Sketch:

//Change the code below by your sketch
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>

const char * host = "192.168.1.210";
const int port = 443;

static WiFiClientSecure g_client;
String wifi = "ssid";
String pass = "pass";

unsigned char root_ca[] = {
  0x30, 0x82, 0x04, 0x02, 0x30, 0x82, 0x02, 0xea, 0xa0, 0x03, 0x02, 0x01,
  0x02, 0x02, 0x09, 0x00, 0xc5, 0xb6, 0xe0, 0xe5, 0x41, 0x5f, 0x08, 0xa6,
  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
  0x0b, 0x05, 0x00, 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
  0x55, 0x04, 0x06, 0x13, 0x02, 0x54, 0x57, 0x31, 0x0f, 0x30, 0x0d, 0x06,
  0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x54, 0x61, 0x69, 0x77, 0x61, 0x6e,
  0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x06, 0x54,
  0x61, 0x69, 0x70, 0x65, 0x69, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
  0x04, 0x0a, 0x0c, 0x0c, 0x42, 0x61, 0x79, 0x65, 0x73, 0x74, 0x65, 0x6b,
  0x20, 0x43, 0x4f, 0x2e, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04,
  0x0b, 0x0c, 0x03, 0x4d, 0x49, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03,
  0x55, 0x04, 0x03, 0x0c, 0x0d, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38,
  0x2e, 0x31, 0x2e, 0x32, 0x31, 0x30, 0x31, 0x26, 0x30, 0x24, 0x06, 0x09,
  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x17, 0x74,
  0x6f, 0x6d, 0x6d, 0x79, 0x2e, 0x79, 0x61, 0x6e, 0x67, 0x40, 0x62, 0x61,
  0x79, 0x65, 0x73, 0x74, 0x65, 0x6b, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x20,
  0x17, 0x0d, 0x31, 0x38, 0x30, 0x36, 0x31, 0x31, 0x31, 0x30, 0x33, 0x30,
  0x33, 0x37, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x31, 0x38, 0x30, 0x35, 0x31,
  0x38, 0x31, 0x30, 0x33, 0x30, 0x33, 0x37, 0x5a, 0x30, 0x81, 0x94, 0x31,
  0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54, 0x57,
  0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x54,
  0x61, 0x69, 0x77, 0x61, 0x6e, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55,
  0x04, 0x07, 0x0c, 0x06, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x31, 0x15,
  0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x42, 0x61, 0x79,
  0x65, 0x73, 0x74, 0x65, 0x6b, 0x20, 0x43, 0x4f, 0x2e, 0x31, 0x0c, 0x30,
  0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x4d, 0x49, 0x53, 0x31,
  0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0d, 0x31, 0x39,
  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x31, 0x2e, 0x32, 0x31, 0x30, 0x31,
  0x26, 0x30, 0x24, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
  0x09, 0x01, 0x16, 0x17, 0x74, 0x6f, 0x6d, 0x6d, 0x79, 0x2e, 0x79, 0x61,
  0x6e, 0x67, 0x40, 0x62, 0x61, 0x79, 0x65, 0x73, 0x74, 0x65, 0x6b, 0x2e,
  0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
  0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
  0xbb, 0xff, 0x54, 0xfa, 0xd9, 0x2b, 0xab, 0x39, 0xf8, 0xb9, 0x5c, 0x22,
  0xe0, 0x07, 0xea, 0x06, 0x52, 0xe4, 0x09, 0x1a, 0x06, 0xd3, 0x31, 0xca,
  0x3c, 0xa3, 0x91, 0x3f, 0x2c, 0x8a, 0xea, 0x9d, 0x60, 0x49, 0x50, 0x09,
  0xf4, 0x93, 0xe3, 0x84, 0x54, 0x03, 0xe0, 0x26, 0x84, 0xc6, 0xa9, 0xbf,
  0x19, 0x32, 0x44, 0xd1, 0xfe, 0x83, 0x50, 0xa5, 0x85, 0x6c, 0x94, 0xc2,
  0xc0, 0xe4, 0xf8, 0xbe, 0x1e, 0xa5, 0x48, 0xfa, 0xae, 0x00, 0xe2, 0x43,
  0x7f, 0x8d, 0x83, 0x4b, 0xf7, 0x40, 0x03, 0xb1, 0xe6, 0x36, 0x16, 0xb8,
  0x32, 0xbe, 0x81, 0x17, 0x22, 0x99, 0x8d, 0xd4, 0xfa, 0xf8, 0x72, 0x9c,
  0x1b, 0xd4, 0x71, 0x30, 0xcf, 0xc5, 0x61, 0xf0, 0x8c, 0x94, 0x49, 0x32,
  0xaa, 0x28, 0x4b, 0x55, 0x42, 0x80, 0x2b, 0x25, 0x87, 0xa6, 0xab, 0x82,
  0x08, 0x3f, 0xfc, 0x27, 0xff, 0xae, 0xbd, 0x4e, 0xf6, 0x07, 0x65, 0x5d,
  0x90, 0xb5, 0xb4, 0x1f, 0x05, 0x9d, 0x83, 0xd0, 0x63, 0x1f, 0x42, 0x67,
  0x35, 0xbc, 0xf2, 0x52, 0x0a, 0x3d, 0x6a, 0x9f, 0x3f, 0xe3, 0x2a, 0x92,
  0xfa, 0xa6, 0x43, 0xeb, 0x15, 0x73, 0xb0, 0x06, 0xc4, 0xe9, 0x06, 0x40,
  0x6c, 0x8d, 0xc4, 0xb1, 0x54, 0xb6, 0x73, 0x08, 0xf0, 0x33, 0xfc, 0xd4,
  0x2e, 0x74, 0xc3, 0x0b, 0x5c, 0x7f, 0x90, 0x83, 0xf2, 0x12, 0x19, 0xf5,
  0xe3, 0x83, 0xee, 0x3e, 0x16, 0xea, 0x18, 0xb2, 0xfe, 0xb0, 0x89, 0xfe,
  0xd3, 0x3a, 0x1f, 0xc6, 0x08, 0x71, 0x6f, 0x8a, 0x23, 0x44, 0x1c, 0xfe,
  0x45, 0x47, 0x3a, 0x4b, 0xe7, 0x68, 0x4d, 0x04, 0x85, 0xe2, 0x26, 0xea,
  0x49, 0x8b, 0x52, 0xfa, 0x0d, 0x20, 0x94, 0x23, 0x5e, 0x19, 0x5d, 0x66,
  0xa8, 0x24, 0x72, 0x35, 0x91, 0x76, 0x0e, 0xea, 0xe7, 0x6a, 0x7f, 0x5a,
  0x07, 0x76, 0x3b, 0x31, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30,
  0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
  0x0e, 0x24, 0x5e, 0xd3, 0xf8, 0xda, 0x44, 0x9a, 0xdc, 0x0a, 0xf2, 0x09,
  0x53, 0xa1, 0xdf, 0xae, 0x0b, 0x92, 0x17, 0xff, 0x30, 0x1f, 0x06, 0x03,
  0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x0e, 0x24, 0x5e,
  0xd3, 0xf8, 0xda, 0x44, 0x9a, 0xdc, 0x0a, 0xf2, 0x09, 0x53, 0xa1, 0xdf,
  0xae, 0x0b, 0x92, 0x17, 0xff, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
  0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d,
  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
  0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x54, 0x0d, 0xbf, 0xf1, 0x81, 0x9b,
  0x36, 0x68, 0x95, 0x2d, 0xf9, 0x7f, 0xb8, 0x01, 0xd1, 0xd4, 0x96, 0xb7,
  0x4d, 0x09, 0x4f, 0xcd, 0xfe, 0x8a, 0x3f, 0x62, 0xa1, 0xe1, 0x9e, 0x2f,
  0x28, 0x83, 0xee, 0xfb, 0x72, 0x90, 0x7b, 0xb7, 0xa2, 0xc6, 0x99, 0xd5,
  0x4d, 0x40, 0xa7, 0xa1, 0xc1, 0x1c, 0x17, 0x92, 0xe2, 0x98, 0xc5, 0x72,
  0x28, 0x7d, 0x7a, 0x7b, 0x05, 0x43, 0x27, 0x2e, 0x19, 0x74, 0x64, 0x3b,
  0x67, 0xe2, 0x74, 0xeb, 0xac, 0xcd, 0xc4, 0x0c, 0xa2, 0x9a, 0xb6, 0xb0,
  0x00, 0x69, 0xd9, 0xca, 0xc2, 0x1f, 0xe0, 0xe3, 0x88, 0x2b, 0x13, 0xa8,
  0x15, 0xba, 0xd5, 0xe2, 0x05, 0x6c, 0x9c, 0x20, 0xb5, 0xec, 0xdb, 0xca,
  0xe2, 0x57, 0x40, 0xed, 0xbe, 0x3c, 0x27, 0xe1, 0x53, 0x8c, 0x91, 0x2d,
  0x3f, 0xe8, 0x9b, 0x4c, 0x41, 0x84, 0x3e, 0x25, 0xae, 0x10, 0xe2, 0x1d,
  0xf4, 0x42, 0x74, 0xa7, 0x71, 0x3c, 0xa1, 0x54, 0x9a, 0x18, 0xb0, 0xae,
  0xf1, 0xcc, 0x96, 0x1d, 0x38, 0x5a, 0xce, 0x74, 0x55, 0xa2, 0x41, 0x51,
  0xcf, 0x72, 0x38, 0x72, 0xac, 0x49, 0x38, 0x5c, 0xb1, 0xdc, 0x48, 0x16,
  0xd4, 0x69, 0x41, 0xb0, 0xa9, 0x40, 0x6b, 0x27, 0x0d, 0xbf, 0x74, 0xbb,
  0x64, 0xb0, 0xf6, 0xd1, 0x9c, 0xd5, 0x7f, 0x46, 0x47, 0x78, 0x91, 0xd8,
  0xf1, 0xad, 0x7b, 0x1a, 0xf7, 0xfb, 0x03, 0xcf, 0x2e, 0xdc, 0xc3, 0x83,
  0xac, 0x76, 0x58, 0x00, 0x7f, 0xa4, 0xd8, 0x55, 0x43, 0x1c, 0xce, 0x20,
  0x0f, 0x0b, 0xb0, 0x39, 0x81, 0x35, 0xdf, 0x63, 0x58, 0x84, 0xd5, 0x73,
  0xbf, 0x44, 0x5c, 0xdf, 0x5e, 0xd5, 0x3c, 0x8c, 0x43, 0x5f, 0x53, 0x45,
  0x4d, 0x9d, 0xc2, 0x10, 0xf7, 0xae, 0xbb, 0xde, 0x03, 0x9f, 0x99, 0x36,
  0xd1, 0x1d, 0x3d, 0x78, 0xe9, 0xf9, 0x53, 0xe1, 0xaa, 0x53
};


void setup()
{
  Serial.begin(115200);
  
  WiFi.begin(wifi.c_str(), pass.c_str());

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
    Serial.print(".");
  }

  Serial.println("Set CA Cert");
  if (!g_client.setCACert(root_ca, sizeof(root_ca)))
  {
    Serial.println("Failed to load CA certificate");
    while(true) yield();
  }
  Serial.println("CA Cert set");

  Serial.print("Connecting to ");
  Serial.println(host);
  if(!g_client.connect(host, port))  **//<== always failed on this line and return. not even go to varify().**
  {
    Serial.println("Connection failed");
    return;
  }
//============================
  if(g_client.verifyCertChain(host))
  {
    Serial.println("Server certificate verified");
  }
  else
  {
    Serial.println("ERROR: certificate verification failed!");
    return;
  }

  g_client.stop();

}

void loop() {}


### Debug Messages:
SDK:2.2.1(cfd48f3)/Core:2.4.1/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1)
scandone
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 2
cnt 

connected with ssid, channel 1
dhcp client start...
......ip:192.168.1.132,mask:255.255.255.0,gw:192.168.1.1
.Set CA Cert
=== CERTIFICATE ISSUED TO ===
Common Name (CN):	192.168.1.210
Organization (O):		BestMe CO.
Organizational Unit (OU):MIS
Location (L):			Tokyo
Country (C):			JPN
State (ST):			Japan
Basic Constraints:		critical, CA:TRUE, pathlen:10000
=== CERTIFICATE ISSUED BY ===
Common Name (CN):	192.168.1.210
Organization (O):		BestMe CO.
Organizational Unit (OU):MIS
Location (L):			Tokyo
Country (C):			JPN
State (ST):			Japan
Not Before:			Mon Jun 11 10:30:37 2018
Not After:			Sun Apr 11 04:02:21 1982
RSA bitsize:			2048
Sig Type:				SHA256
CA Cert set
Connecting to 192.168.1.210
State:	sending Client Hello (1)
Alert: handshake failure **<== why failed, but browser always sucess ?**
Error: SSL error 40
Alert: unexpected message **<== why strange message here?**
Error: SSL error 40
Alert: close notify
Connection failed
pm open,type:2 0

@Rob58329

This comment has been minimized.

Copy link
Author

commented Jun 15, 2018

@iamneo2416

I have a couple of comments on your above code:
(1) If you are using an ESP32, then I believe that you should use "#include <WiFi.h>" and not "#include <ESP8266WiFi.h>"
(2) If you are using an ESP8266, then I believe it does not have the ability to use a certificate as above, the only thing you can do with an ESP8266 is to check the FINGERPRINT.
(3) If you are getting the message "'class WiFiClientSecure' has no member named 'lastError'" then I suspect you are not using the "github.com/espressif/arduino-esp32" version of the software (current last commit was 31May18).

@iamneo2416

This comment has been minimized.

Copy link

commented Jun 19, 2018

  1. YES, I use ESP8266 chip. (I picked NodeMCU 1.0 ESP-12E option from Arduino IDE)

  2. from debug message I think CA was set and loaded successfully. That's why CA was printed on the debug log. Check debug log and you will see CA was loaded w/succeed.
    === CERTIFICATE ISSUED TO === and
    === CERTIFICATE ISSUED BY ===

  3. when it runs to next line if(!g_client.connect(host, port)), it always get fail and return. I use wireshark to listen to network packets, and it always show SSL error 40 with unexpected message sent from client. There must be some bugs inside SSL handshake sequence. I don't think SSL provider will do thing wrong. I installed it from public domain and it runs for a very long time wo/errors. Server receive some message unexpected that was send by client which I use WiFiClientSecure client.connect(). That means SSL handshake meet some unexpected error sequence.

Simple test will know this bug. Browser (Chrome, Firefox, IE) all connect https://192.168.1.210/ successfully and show apache2 index.html page entirely without any error, but use WiFiClientSecure client.connect() will get unexpected message from client on handshake sequence. Those messages show on both sides, one from Arduino IDE w/debug option opened (pasted in previous post above) and also shows on wireshark network message w/Code Error 40 SSL error.

wireshark link: https://www.wireshark.org/download.html

Actually, I don't even has a chance to run to line client.verify(), it gets connect fail and return right before verify(). Please check code above again.

  1. wifi.begin()
  2. client.connect() <== this line always get failed and return.
  3. client.verify() <== does not have chance to run this line.
@Rob58329

This comment has been minimized.

Copy link
Author

commented Jun 19, 2018

@iamneo2416

This is the "ESP32-issues" section of github, and not for "ESP8266-issues".
(The ESP32 is a much more powerful chip than the ESP8266.)

As I said, "If you are using an ESP8266, then I believe it does not have the ability to use a certificate as above, the only thing you can do with an ESP8266 is to check the FINGERPRINT."

I think this is because the ESP8266 does not have sufficient RAM to hold and process the full certificate as well as run the "WiFi_Client_secure." routines. Instead, you have to only store the "Certificate-Fingerprint" on the ESP8266 (ie. NOT the full certificate as in your example code), and then use the ESP8266's "WiFi_Client_secure.verify()" command to check this Fingerprint. Your errors are probably because the ESP8266 is running out of RAM.

ESP8266 code examples can be found at:
"https://github.com/esp8266/Arduino/blob/master/doc/esp8266wifi/client-secure-examples.rst"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.