Skip to content

Client certs removed from connection when setInsecure called, causing SSL connect failure. #7455

Closed
@Gor-Ren

Description

@Gor-Ren

Basic Infos

  • This issue complies with the issue POLICY doc.
  • I have read the documentation at readthedocs and the issue is not addressed there.
  • I have tested that the issue is present in current master branch (aka latest git).
  • I have searched the issue tracker for a similar issue.
  • [NA] If there is a stack dump, I have decoded it.
  • I have filled out all fields below.

Platform

  • Hardware: ESP8266 device
  • Core Version: 2.7.2, 39c79d9
  • Development Env: Arduino IDE via VSCode + Visual Studio Code extension for Arduino
  • Operating System: Ubuntu 18.04

Settings in IDE

  • Module: NodeMCU v1.0 (ESP-12E Module)
  • Flash Mode: unknown
  • Flash Size: 4MB
  • lwip Variant: v2 Higher Bandwidth, also tried v1.4 Higher Bandwidth
  • Reset Method: unknown
  • Flash Frequency: unknown
  • CPU Frequency: tried both 80Mhz and 160MHz
  • Upload Using: SERIAL
  • Upload Speed: 115200

Problem Description

I am attempting to publish a "hello world" MQTT message over WiFi to an Amazon Web Services (AWS) IoT endpoint, which requires SSL encryption. I have been issued a CA cert, device cert and device public & private keys, plus my account-specific AWS endpoint to publish against.

I have configured my sketch to use these credentials (but not currently using PROGMEM to store them), and I populate the WifiClientSecure with my device certificate and private key. For now I am ignoring server certificate verification using WifiClientSecure::setInsecure.

my troubleshooting has included:

  • verified I am able to use a non-SSL WifiClient and successfully publish "hello worlds" to an unencrypted public MQTT broker.
  • reviewed the SSL client docs and example sketches
  • based on googling the error, I've variously tried the CPU at 80 Mhz and 160 MHz, SSL support at "All SSL ciphers" and "Basic SSL ciphers", lwIP variant v2 (Higher Bandwidth) and v1.4 (Higher Bandwidth) to no avail.
  • I am able to successfully authenticate from a computer on the same WiFi network for the same endpoint using the same certs using openssl s_client CLI helper (output provided in debug section)

The TLS handshake fails around BSSL:_wait_for_handshake: failed; please see debug output.

Further troubleshooting advice greatly appreciated.

MCVE Sketch

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

namespace Secrets {
const char wifiSsid[] = "myssid";
const char wifiPassword[] = "mypass";
const char awsIotEndpoint[] = "redacted.iot.eu-west-1.amazonaws.com";

const char awsCentralAuthorityCertificate[] = R"EOF(
-----BEGIN CERTIFICATE-----
redacted
-----END CERTIFICATE-----
)EOF";
const char awsDeviceCertificate[] = R"EOF(
-----BEGIN CERTIFICATE-----
redacted
-----END CERTIFICATE-----
)EOF";
const char awsDevicePrivateKey[] = R"EOF(
-----BEGIN RSA PRIVATE KEY-----
redacted
-----END RSA PRIVATE KEY-----
)EOF";
}  // namespace Secrets

void wifiConnect() {
  WiFi.mode(WIFI_STA);

  WiFi.begin(Secrets::wifiSsid, Secrets::wifiPassword);

  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.printf("WiFi connection failed (status=[%s])");
  } else {
    Serial.println("WiFi connected. IP address: ");
    Serial.println(WiFi.localIP());
  }
}

PubSubClient mqttClient;
WiFiClientSecure wifiClient;

void mqttSetup() {
  wifiClient.setClientRSACert(new X509List(Secrets::awsDeviceCertificate),
                              new PrivateKey(Secrets::awsDevicePrivateKey));
  wifiClient.setInsecure();  // TODO: verify server identity using CA cert

  mqttClient.setServer(Secrets::awsIotEndpoint, 8883);
  mqttClient.setClient(wifiClient);
}

void mqttReconnect() {
  while (!mqttClient.connected()) {
    Serial.printf("Connecting to MQTT broker... (MQTT client state: %d)\n",
                  mqttClient.state());
    if (!mqttClient.connect("test-client-id")) {
      char errorMessage[128];
      wifiClient.getLastSSLError(errorMessage, 128);
      Serial.printf(
          "Connecting to MQTT broker failed. (MQTT client state: %d, SSL "
          "error: %s)\n",
          mqttClient.state(), errorMessage);
    };
    delay(2500);
  }
  Serial.println("MQTT client connected to broker.");
}

void setup() {
  Serial.begin(115200);
  Serial.println("Booting");

  wifiConnect();
  mqttSetup();
}

void loop() {
  delay(5000);
  mqttReconnect();

  if (mqttClient.publish("testTopic", "hello world")) {
    Serial.println("MQTT message published successfully!");
  } else {
    Serial.println("MQTT message publish failed.");
  }

  Serial.println("Finished loop");
}

Debug Messages

[Info] Opened the serial port - /dev/ttyUSB0
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 2
cnt 

connected with MyWifiSSID, channel 11
dhcp client start...
wifi evt: 0
ip:192.168.86.249,mask:255.255.255.0,gw:192.168.86.1
wifi evt: 3
WiFi connected. IP address: 
192.168.86.249
Connecting to MQTT broker... (MQTT client state: -1)
[hostByName] request IP for: redacted.iot.eu-west-1.amazonaws.com
[hostByName] Host: redacted.iot.eu-west-1.amazonaws.com IP: 52.31.xxx.xx
:ref 1
BSSL:_connectSSL: start connection
:wr 251 0
:wrc 251 251 0
:ack 251
:rn 1414
:rd 5, 1414, 0
:rdi 1414, 5
:rd 1409, 1414, 5
:rdi 1409, 1409
:c0 1409, 1414
BSSL:CERT: aa bb cc etc. REDACTED
BSSL:CERT: aa bb cc etc. REDACTED
BSSL:CERT: aa bb cc etc. REDACTED
BSSL:CERT: aa bb cc etc. REDACTED
BSSL:CERT: aa bb cc etc. REDACTED
:rn 1414
:rch 1414, 1414
:rch 2828, 1108
:rd 3936, 3936, 0
:rdi 1414, 1414
:c 1414, 1414, 3936
:rdi 1414, 1414
:c 1414, 1414, 2522
:rdi 1108, 1108
:c0 1108, 1108
BSSL:CERT: aa bb cc etc. REDACTED
:wr 82 0
:wrc 82 82 0
:wr 6 0
:wrc 6 6 0
:wr 45 0
:wrc 45 45 0
:ack 82
:rn 7
:rcl pb=0x3fff88cc sz=7
:rd 5, 7, 0
:rdi 7, 5
:rd 2, 7, 5
:rdi 2, 2
:c0 2, 7
BSSL:_wait_for_handshake: failed
BSSL:Couldn't connect. Error = 'Unknown error code.'
Connecting to MQTT broker failed. (MQTT client state: -2, SSL error: Unknown error code.)
:ack 51
Connecting to MQTT broker... (MQTT client state: -2)
<repeats>

From a terminal, I can connect successfully using the same certificates:
(the certificates redacted in the sketch above are a copy-paste of the files referenced below)

openssl s_client -connect redacted.iot.eu-west-1.amazonaws.com:8443 -CAfile AmazonRootCA1.pem -cert redacted-certificate.pem.crt -key redacted-private.pem.key

And receive successful output:

CONNECTED(00000005)
depth=2 C = US, O = Amazon, CN = Amazon Root CA 1
verify return:1
depth=1 C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
verify return:1
depth=0 CN = *.iot.eu-west-1.amazonaws.com
verify return:1
---
Certificate chain
 0 s:CN = *.iot.eu-west-1.amazonaws.com
   i:C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
 1 s:C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
   i:C = US, O = Amazon, CN = Amazon Root CA 1
 2 s:C = US, O = Amazon, CN = Amazon Root CA 1
   i:C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Services Root Certificate Authority - G2
 3 s:C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Services Root Certificate Authority - G2
   i:C = US, O = "Starfield Technologies, Inc.", OU = Starfield Class 2 Certification Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
redacted
-----END CERTIFICATE-----
subject=CN = *.iot.eu-west-1.amazonaws.com

issuer=C = US, O = Amazon, OU = Server CA 1B, CN = Amazon

---
No client certificate CA names sent
Client Certificate Types: RSA sign, DSA sign, ECDSA sign
Requested Signature Algorithms: ECDSA+SHA512:RSA+SHA512:ECDSA+SHA384:RSA+SHA384:ECDSA+SHA256:RSA+SHA256:DSA+SHA256:ECDSA+SHA224:RSA+SHA224:DSA+SHA224:ECDSA+SHA1:RSA+SHA1:DSA+SHA1
Shared Requested Signature Algorithms: ECDSA+SHA512:RSA+SHA512:ECDSA+SHA384:RSA+SHA384:ECDSA+SHA256:RSA+SHA256:DSA+SHA256:ECDSA+SHA224:RSA+SHA224:DSA+SHA224:ECDSA+SHA1:RSA+SHA1:DSA+SHA1
Peer signing digest: SHA256
Peer signature type: RSA
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 5400 bytes and written 1620 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: redacted
    Session-ID-ctx: 
    Master-Key: redacted
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1594729814
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: yes
---

Metadata

Metadata

Assignees

No one assigned

    Labels

    waiting for feedbackWaiting on additional info. If it's not received, the issue may be closed.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions