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

ESP32 W5500 MQTT SSL #8

Closed
jhnwmr opened this issue Apr 15, 2020 · 7 comments
Closed

ESP32 W5500 MQTT SSL #8

jhnwmr opened this issue Apr 15, 2020 · 7 comments
Labels
question Further information is requested

Comments

@jhnwmr
Copy link

jhnwmr commented Apr 15, 2020

Hello,
I can easily connect to my MQTT server from my pc with the ca.cert file and on the port 8883. But the ESP32 says:

My IP address: 192.168.170.151.
Connecting to MQTT...
(SSLClient)(SSL_WARN)(m_run_until): Terminating because the ssl engine closed
(SSLClient)(SSL_ERROR)(m_start_ssl): Failed to initlalize the SSL layer
(SSLClient)(SSL_ERROR)(m_print_br_error): Expected server name was not found in the chain.
failed with state -2Connecting to MQTT...
(SSLClient)(SSL_ERROR)(connect): Cannot have two connections at the same time! Please create another SSLClient instance.
failed with state -2Connecting to MQTT...
(SSLClient)(SSL_ERROR)(connect): Cannot have two connections at the same time! Please create another SSLClient instance.
failed with state -2Connecting to MQTT...

The Server shows me an new connection with the IP 192.168.170.151 without any reaction.

My actually code:

#include <SPI.h>
#include <Ethernet2.h>
#include <SSLClient.h>
#include "certificates.h" // This file must be regenerated
#include <PubSubClient.h>


const char my_cert[] = 
"-----BEGIN CERTIFICATE-----\n" 
................
"-----END CERTIFICATE-----";

const char my_key[] = 
"-----BEGIN RSA PRIVATE KEY-----\n"
...............
"-----END RSA PRIVATE KEY-----\n";

SSLClientParameters mTLS = SSLClientParameters::fromPEM(my_cert, sizeof my_cert, my_key, sizeof my_key);

byte mac[] = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xEF };
const char* mqttServer = "192.168.170.143";
const int mqttPort = 8883;

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

EthernetClient ethClient;
SSLClient ethClientSSL(ethClient, TAs, (size_t)TAs_NUM, A5);
PubSubClient client(ethClientSSL);

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");

    if (client.connect("ESP32") {

      Serial.println("connected");
      client.subscribe("#");
    } else {

      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);

    }
  }
}

void setup(){
  Serial.begin(115200);
  while(!Serial);

  ethClientSSL.setMutualAuthParams(mTLS);
  Ethernet.init(27);  // Most Arduino shields
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for (;;)
      ;
  }
  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();

  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);
 
  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");
 
    if (client.connect("ESP32_Garage") {
 
      Serial.println("connected");   
    } else {
 
      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);
 
    }
  }
}

void loop(){
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}
@prototypicalpro
Copy link
Member

Hello!

It looks like SSLClient is verifying the domain name even though you are attempting to connect with only an IP address (e.g. there is no domain name to verify).

To clarify: when connecting with SSLClient::connect(const char* host, uint16_t port) SSLClient will use the domain name as part of the identity verification process, ensuring the server certificate matches the expected domain name (more info on that here). When connecting with just an IPAddress (SSLClient::connect(IPAddress ip, uint16_t port)), this verification should be disabled, as there is no domain name to verify against. For some reason, your SSLClient is attempting to verify the domain name even though you only specified an IP address. This verification fails (it was invalid to begin with), closing the connection and outputting an error.

I suspect this issue is caused by your incorrect use of PubSubClient::setServer. In your code you pass the desired IP address to the PubSubClient as a string:

const char* mqttServer = "192.168.170.143";
const int mqttPort = 8883;
PubSubClient client(ethClientSSL);
...
void setup() {
  ...
  client.setServer(mqttServer, mqttPort);
  ...
}

The definitions of PubSubClient::setServer, however, are as follows:

PubSubClient& setServer(IPAddress ip, uint16_t port);
PubSubClient& setServer(uint8_t * ip, uint16_t port);
PubSubClient& setServer(const char * domain, uint16_t port);

Your sketch invokes the third version by passing a string as the first parameter. This version expects a domain name, however, and eventually calls SSLClient::connect(const char* host, uint16_t port) with the IP address string. Since the IP address string is not a domain name, SSLClient throws an error.

You should be able to fix this issue by changing your IP address from a string to the IPAddress class:

IPAddress mqttServer(192, 168, 170, 143);

This will switch your setServer call to the first version from above, allowing PubSubClient to use SSLClient::connect(IPAddress ip, uint16_t port) and bypassing the verification.

Good luck, and let me know if that works!

@prototypicalpro prototypicalpro added the question Further information is requested label Apr 15, 2020
@jhnwmr
Copy link
Author

jhnwmr commented Apr 15, 2020

Many thanks for your efforts!!

Here my new Code, but the ESP32 make the same output without changes:

................
IPAddress mqttServer(192, 168, 170, 143);
const int mqttPort = 8883;

EthernetClient ethClient;
SSLClient ethClientSSL(ethClient, TAs, (size_t)TAs_NUM, A5);
PubSubClient client(ethClientSSL);

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");

    if (client.connect("ESP32") {

      Serial.println("connected");
      client.subscribe("#");
    } else {

      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);

    }
  }
}

void setup(){
  // Start Serial
  Serial.begin(115200);
  while(!Serial);
  // Enable mutual TLS with SSLClient
  ethClientSSL.setMutualAuthParams(mTLS);
  // You can use Ethernet.init(pin) to configure the CS pin
  Ethernet.init(27);  // Most Arduino shields
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for (;;)
      ;
  }
  // print your local IP address:
  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  Serial.println();

  client.setServer(mqttServer, mqttPort);

  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");
 
    if (client.connect("ESP32") {
 
      Serial.println("connected");   
    } else {
 
      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);
 
    }
  }
}
................

@prototypicalpro
Copy link
Member

Your sketch is missing a closing parenthesis:

if (client.connect("ESP32") {

Is this a typo?

I'm not sure what else the issue could be, but I can do some testing and get back to you.

@jhnwmr
Copy link
Author

jhnwmr commented Apr 15, 2020

Oh, yes that's right, but there is normal an username and password at the end. I deleted too much, but in the original code is it right.


Do you have another idea how I can use mqtt encrypted?

@prototypicalpro
Copy link
Member

Unfortunately not over Ethernet, though the ESP32 core developers are working on implementing TLS for all internet interfaces (I think here: esp8266/Arduino#6680).

After some investigation, I have a few more questions:

  • Are you using the latest version of both SSLClient and PubSubClient?
  • If SSLClient is attempting to connect using connect(IPAddress addr, uint16_t port) you should see the following line at least once in your output. Does your output contain this line?
(SSLClient)(SSL_WARN)(connect): Using a raw IP Address for an SSL connection bypasses some important verification steps. You should use a domain name (www.google.com) whenever possible.
  • How complicated is your certificate chain? I would be happy to inspect your certificates if you would be comfortable emailing them to me; you can use the email on my GitHub profile.

@jhnwmr
Copy link
Author

jhnwmr commented Apr 23, 2020

I did not create the certification.h correctly, what to do with the pycert_bearssl.
With the library update it also works perfectly.

@aremon78
Copy link

I did not create the certification.h correctly, what to do with the pycert_bearssl. With the library update it also works perfectly.

hi there, I cannot connect to mqtt ssl using eps32 w5500, I would like to know how to create certification.h correctly? because maybe mine also not coreected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants