Securing your IoT device using SSL

Frank Lynam
10 min readOct 22, 2018

--

Today, I want to talk to you about a technical problem that the team have been researching over the last number of days. We use an ESP8266 Arduino variant as one of the key components of our Internet of Things technology stack. When a user first receives one of our products, they need to configure the device, and in order to access the ESP8266, we run a HTTP web server that serves up a UI, which the user then uses to input their details. This works fine over an unencrypted link but we wanted to follow best practice by implementing a secure link between the client’s web browser and the ESP8266 web server. This blog post considers how you might go about creating a web server on an ESP8266 that supports SSL connections.

The simple theory behind SSL

Secure Sockets Layer or SSL is becoming an increasingly common addition to most web pages and to other communication stacks. You see it in action most obviously when you navigate to a web server in your browser that supports HTTPS addressing. This means that instead of the client connecting to the web server on the plain text TCP port 80, it does so on the encrypted port 443. SSL links are encrypted using public-private key cryptography.

In private key or symmetric cryptography, the sender and receiver both encrypt and decrypt each data packet using the same private key. The problem with this system is that both parties need to have the private key in their possession before they can process packets, which means that the key needs to be transported from one side to another in an unencrypted and therefore, compromised form.

Public-private key cryptography is asymmetrical in the sense that data that is encrypted using a private key can only be decrypted using the accompanying public key. The two keys are known as a key pair. In a client-server web setup, the data connection is first secured using this public-private key pair. This means that after the client says hello to the server, the server sends data to the client that has been encrypted using its private key. The client then decrypts this data using the server’s public key. The client sends a new private key to the server that it encrypts using the server’s public key. The server can read this new private key by decrypting it using its private key. Now and for the duration of the session, both sides will use this new private key to encrypt and decrypt all data that is to be sent and received. In other words, they use symmetric cryptography. Note that there are variants of this but the most popular approach is to use public key cryptography to exchange a per-session symmetric key as symmetric key encryption is much faster.

Public-private key cryptography allows a client to be confident that a received message really has come from the purported owner, which on the web is a domain. Public-private key cryptography also provides a mechanism for data to be sent between two peers that can only be read or decrypted by the other.

SSL in practice

In practice, SSL is implemented on the web using keys that have been created by trusted actors known as Certificate Authorities or CAs. They are known as Certificate Authorities and not Key Authorities because public keys are wrapped in a package that contains other useful information about the key, and these are called certificates. A CA is granted its authority by a second, more senior CA, which is higher up in the trust pyramid. This produces a chain of CAs that allow your key pair to be trusted as a function of its ancestry — i.e. if I trust a parent, then I trust its child.

A simple of way of looking at this in practice is by navigating to a secure website such as https://nytimes.com using a browser such as Chrome. Now click on the lock icon that appears to the left of the address and select to view the site’s certificate. This will display the key chain for the cert. It will look something like the following:

There are three certificates listed here. The innermost cert is the nytimes.com site’s certificate. It is tied to this domain name and cannot be used as the cert to secure any other website. Its trust parent, COMODO RSA Organization Validation Secure Server CA, is a cert itself, which may be used as the parent of a number of other children certs. Finally, this cert is itself a child of COMODO RSA Certificate Authority.

If you click on the nytimes.com cert, you will be able to find its expiry date. Depending on the cert in question, this may be quite soon. As you move further up the cert hierarchy this expiry date will move further into the future.

You can also view more details of each cert using your browser’s cert viewer. This will probably include information such as the street address of the individual or group who has created the cert. It will also show all of the domain names and subdomains that are associated with the cert and finally the public key itself. Remember that the primary function of these certs is to wrap a public key, which can then be used to carry out an encrypted and authenticated conversation with the owner of a hidden private key. In this case, the private key is stored securely somewhere in the nytimes.com server architecture.

Certificate Authorities

Certificate Authorities come in all shapes and sizes and because most certs are used to provide SSL web servers, they are often tied to the activities of hosting companies. Let’s Encrypt has become a popular choice among sys admins and developers because it offers a free service and it currently enjoys a high level of trust across most browsers. In order to obtain a key-pair that has been issued by Let’s Encrypt, you need to install the company’s certbot utility and run something like the following:

certbot certonly — standalone -d example.com

This means that you want to obtain a key-pair for example.com, a domain that you control. When you run this command, certbot, creates a temporary web server that listens on port 80. It then asks the Let’s Encrypt API to send a message to the example.com domain. If it finds the domain and its listening web server, it knows that you control the domain and it will grant a key-pair for that domain. Certbot will then save the key-pair data as four files in the Let’s Encrypt live folder on your server. The files and their contents are as follows:

privkey.pem private key

fullchain.pem the certificate file including all of the certificates in the chain

chain.pem a list of the root certificates used

cert.pem just the public certificate — i.e. no higher certificates in the chain

In order to get this to work, you need to make sure that your domain has been registered with a DNS provider to point to your server’s IP address. In a typical web scenario, you would then configure your web server to handle SSL connections and to use the key pair that the Let’s Encrypt certbot has outputted.

Note that if you have an Apache server already running on the server, you can use the — apache flag to use this server instead of certbot creating its own temporary web server. Certbot can also be instructed to automatically configure your web server. Personally, I find it better to do this manually. See here for a detailed description of how to run certbot on an Apache/Ubuntu 18 configuration.

The ESP8266 and the wonders of low-cost computing

The Arduino PCB came out of an educational project run during the early 2000s in Interaction Design Institute Ivrea (IDII) in Italy. The course was designed to teach students how to build embedded systems. The result was a super low cost mini computer that could be used to handle specific tasks in networked (typically TCP/IP) scenarios. The Raspberry Pi, which was developed just after the Arduino at the University of Cambridge was similarly targeted as a didactic aid at the beginning by its creators. Both, however, have increasingly come to be used as components in commercial solutions and their rise in popularity have tracked that of the Internet of Things.

Today, the Arduino is available as a number of different models manufactured by BCMI, and as a whole range of Arduino firmware compatible PCBs that provide a range of functionality and price options to the user. The ESP8266, a chipset produced by the Shanghai-based Chinese manufacturer, Espressif Systems, is used by many of these compatible PCBs. These variants appear on the market under a number of different brand names. One of these is the Adafruit Huzzah ESP8266, which is attractive for developers as single units can be bought for as little as $10 with bulk orders being cheaper still.

Arduinos typically run C/C++ stacks but firmwares have been developed to allow for JavaScript, Python, C# and Java programs as well. Most of the tutorials found online and questions on sites such as Stack Overflow tend to refer to C/C++ code, however.

Running a secure web server on the ESP8266

Now that you have a set of key-pair files from Let’s Encrypt and you understand something of what can be done with the ESP8266, it is time to put the two together and create an embedded secure web server using certificates that have been issued by Let’s Encrypt. This is an important last point to make. You will find a number of other guides out there that explain how to setup an SSL web server on an ESP8266. The problem with these guides is that they all (as far as I have seen) use self-signed certs. These are SSL key-pairs that can be created by anyone and therein lies the problem. If anyone can create them, then anyone can fabricate them and say that they own example.com or any other domain. All modern web browsers will by default deny access to sites served using self-signed certs and so, for real-world implementations, they are effectively useless.

So, how do you use Let’s Encrypt SSL certs on an ESP8266? Here’s a simple recipe that you can follow:

Step 1

Make sure your dev environment is setup correctly. This means, downloading and installing the Arduino IDE and configuring it for the particular flavour of ESP (or other Arduino compatible board — this guide with a few tweaks should work on a lot of Arduino setups) that you have.

Step 2

Create a new folder in your Sketchbook location and give it a name like sslserver. Now create a file called sslserver.ino in this folder.

Step 3

The first bit of code you have to add are your list of included libraries. We will need the following.

#include <ESP8266WiFi.h>
#include <ESP8266WebServerSecure.h>
#include <DNSServer.h>

Step 4

Now we need to add a couple of global constants and variables. These will be used to specify the SSID and password for the wifi access point you’ll be creating, and the port on which to listen for DNS requests. We’ll be using the BearSSL ESP8266WebServerSecure class to handle the secure server requests and the DNSServer class to handle DNS requests.

const char* ssid = "YOUR-SSID";
const char* password = "PASSWORD";
const byte DNS_PORT = 53;
BearSSL::ESP8266WebServerSecure server(443);
DNSServer dnsServer;

Step 5

Next, we need to add our SSL cert data. This is a crucial step. Run the Let’s Encrypt certbot utility as explained above and find the location of the four files that are created. Open the fullchain.pem file in a text editor. Copy and paste its contents in place of the BEGIN CERTIFICATE/END CERTIFICATE block. Make sure to include the begin and end lines. Note that there will be more than one certificate block included in this file, as it is a record of the full chain of certificates. Do the same with the contents of the privkey.pem file. Paste its contents in place of the BEGIN RSA PRIVATE KEY/END RSA PRIVATE KEY block.

static const char serverCert[] PROGMEM = R"EOF(
- - -BEGIN CERTIFICATE - - -
- - -END CERTIFICATE - - -
)EOF";
static const char serverKey[] PROGMEM = R"EOF(
- - -BEGIN RSA PRIVATE KEY - - -
- - -END RSA PRIVATE KEY - - -
)EOF";

Step 6

Now add the main function. This begins by setting up the wifi access point. This will allow wifi clients connect to the ESP using the credentials provided. It then goes on to specify a static IP address for the server and it initiates a DNS server that will point all requests to example.com to this IP address. Note that including a DNS server is required because the client’s browser will validate the served public cert on the basis that its associated domain (known as its Common Name) matches the requested domain name. You cannot create an SSL web server by using only IP addresses.

void setup(void){
Serial.begin(115200);
if (WiFi.softAP(ssid, password) == false) {
Serial.println("WiFi.softAP - error - exiting");
return;
}
Serial.println("Configuring Wifi AP");
IPAddress Ip(192, 168, 1, 1);
IPAddress NMask(255, 255, 255, 0);
if (WiFi.softAPConfig(Ip, Ip, NMask) == false) {
Serial.println("WiFi.softAPConfig - error - exiting");
return;
}
dnsServer.start(DNS_PORT, "example.com", Ip);
server.setRSACert(new BearSSLX509List(serverCert), new BearSSLPrivateKey(serverKey));
server.on("/", [](){
server.send(200, "text/plain", "Hello world!");
});
server.begin();
Serial.println("HTTPS server started");
}

Step 7

Lastly, add the loop function. This keeps both the web and DNS servers ticking over.

void loop(void){
server.handleClient();
dnsServer.processNextRequest();
}

Final thoughts

The ESP8266 is a really flexible low-cost device that can be used in a whole host of networked scenarios. As SSL web server support becomes increasingly a standard practice, embedded IoT devices that use chip cores based around the ESP8266 are going to have to start implementing their support using certificates issued by trusted CAs as a matter of course.

If you would like to learn more about the exciting technologies that MinFarm Tech are working on, including Internet of Things and Mixed Reality, follow us here on Medium or on your preferred social media channel.

--

--

Frank Lynam

Engineering Manager @WoebotLabs - PhD in #digitalhumanities