Close

Connecting the ESP8266 with TLS

A project log for Garage Door Opener

An ESP8266-based garage door opening device

Myles EftosMyles Eftos 09/15/2016 at 10:474 Comments

While I want to do full CA verification, I'm waiting on some of the bugs to get ironed out of the ESP8266 Arduino library, so I'll take a shortcut for the moment, and use fingerprinting to verify the server certificate (It should be pretty easy to move to CA verification down the track).

To do this, we need three pieces of information:

  1. Client certificate
  2. Client secret key
  3. Server fingerprint

We have already generated the certificate and the secret key, so let''s generate a fingerprint for the server certificate. We can use OpenSSL to do this:

openssl x509 -in mosquitto/etc/certs/mqtt.local.crt.pem -sha1 -noout -fingerprint
This will generate a 160bit sha1 string, that may look a little like this:
SHA1 Fingerprint=DA:39:A3:EE:5E:6B:4B:0D:32:55:BF:EF:95:60:18:90:AF:D8:07:09

Convert PEM to DER

I was reading through the docs, and while the axTLS says it supports PEM, I found that I needed to convert the PEM format certificate (which is ASCII based) to DER which is binary.

Again, OpenSSL to the rescue:

openssl x509 -outform der -in garage.local.csr.pem -out garage.local.csr..der
openssl x509 -outform der -in garage.local.key.pem -out garage.local.key..der

Loading the certificates

Down the track, I'll be able to upload the certificate and key via the administration console (certificates expire, and need to be updated), which means storing them in the code makes little sense. Instead I'm going to store them on the flash as a file.

Thankfully there is a tool that makes uploading files to the SPIFFS filesystem super simple. Gratuitously stolen from the Filesystem Read Me:

ESP8266FS is a tool which integrates into the Arduino IDE. It adds a menu item to Tools menu for uploading the contents of sketch data directory into ESP8266 flash file system.

Copy the two der files in to the data directory, and run the data upload function (I renamed them client.key.der and client.crt.der because that kind of makes more sense in this context). To load the files, the code looks a little like this:

// We need to use WiFiCLientSecure to the encryption works
WiFiClientSecure wifiClient

SPIFFS.begin();
File ca = SPIFFS.open("/client.crt.der", "r");
if(!ca) {
  Serial.println("Couldn't load cert");
  return;  
}

if(wifiClient.loadCertificate(ca)) {
  Serial.println("Loaded Cert");
} else {
  Serial.println("Didn't load cert");
  return;
}
  
File key = SPIFFS.open("/client.key.der", "r");
if(!key) {
  Serial.println("Couldn't load key");
  return;  
}

if(wifiClient.loadPrivateKey(key)) {
  Serial.println("Loaded Key");
} else {
  Serial.println("Didn't load Key");
}

The device will connect at this point, and the mosquitto server will be happy. It will use the name on the certificate as the client name, and the connection will be encrypted.

However, I not verifing the server yet. I will do that using the verify function

PubSubClient client("mqtt.local", 8883, callback, wifiClient); //set  MQTT port number to 8883 as per //standard

wifiClient.connect("mqtt.local", 8883);
  
if(wifiClient.verify("DA 39 A3 EE 5E 6B 4B 0D 32 55 BF EF 95 60 18 90 AF D8 07 09", "mqtt.local")) {
  Serial.println("connection checks out");
  wifiClient.stop();

  if(client.connect("garage")) {
    Serial.println("Connected");
    client.subscribe("test");
    client.publish("test", "hello world");    
  } else {
    Serial.println("Not connected");
  }
} else {
  wifiClient.stop();
  Serial.println("connection doesn't check out");
}

Notice that all of the colons have been replace with spaces.

Because of the way the PubSubClient works, I need to make a (pre?)connection to the server to do the verification. It's pretty simple - connect, verify and disconnect, then continue with the PubSub connection.

There is a problem here - the mDNS name won't actually resolve at this point. Because the DNS resolver doesn't support it.

Ok, that isn't strictly true - every DNS resolver CAN resolve mDNS, but you need to hit a special DNS server and port (224.0.0.251 on port 5353), which I haven't worked out how to do with the Arduino library yet...

Discussions

Gavin Greene wrote 04/03/2019 at 18:44 point

Do you have the full sketch for the code above that includes the setup() and loop() functions. Getting errors when trying to use this code and cannot get it to work.

  Are you sure? yes | no

IoT enthusiast wrote 09/28/2017 at 00:32 point

Which TLS version does your mosquitto use? - I'v tried it with v1.2 and a client crt but it doesn't worked. Did you also tried with the:

espClient.setCertificate(bin_crt, bin_crt_len); and espClient.setPrivateKey(bin_key, bin_ke_len); functions?
Only if I use tlsv1.1 and have the setting require_certificate to false (or outcommented) it works. Whenever I use require_certificate true, my board won't connect.

I'm using this stage of lib: https://github.com/esp8266/Arduino/pull/3019/files

  Are you sure? yes | no

Bub Rascal wrote 12/05/2017 at 10:22 point

  Are you sure? yes | no

gollner.balazs wrote 12/28/2016 at 20:48 point

Hi, 

openssl x509 -outform der -in garage.local.key.pem -out garage.local.key..der

shouldn't be openssl rsa -outform der -in garage.local.key.pem -out garage.local.key.der ? The first version did not worked for me.

  Are you sure? yes | no