I recently had some unfortunate production issues due to hard-coding a certificate in my firmware. As a result I dug deeper on TLS on the ESP32 and even after just scratching the surface I have learned a ton I want to share with you.
I spent a little over an hour going through this in a recent stream which you can watch on YouTube. The rest of this post is a summary from that stream.
On the ESP32 you have two main options for TLS (often referred to by the legacy term “SSL”):
By default, IDF uses MbedTLS which is what I used during the stream.
The IDF provides an API for you to do HTTPS which is pretty straightforward to use. At it’s core you provide a url endpoint to hit and a means for the TLS library to validate the domain of that endpoint during the TLS handshake.
There are 3 main ways you can provide a cert for MbedTLS to validate the domain you are trying to hit.
- Hard-coded string in source file
- Embedded binary file using
- Using a cert bundle
I cover how to do all 3 in the video above and show the flash size impact of each. The short story is that using a raw string in code versus embedding it as a binary file makes no difference in flash size and is simply a matter of preference. The cert bundle has additional flash impact we will discuss below.
So which approach should you use for embedding a cert in your firmware? The short answer is “Start with the partial cert bundle”. The more nuanced answer is “It depends on what your firmware does and what your flash constraints are.”
The following table illustrates the approximate flash impact of the 3 approaches.
|Flash Impact From Baseline
|0 bytes (baseline)
|Only domains associated with the single cert
|ESP Partial Cert Bundle
|90% absolute coverage with 99% market share coverage
|ESP Full Cert Bundle
|Basically all of the internet
If your firmware talks to one domain and one domain only, you can get away with embedding the single root cert for that domain. However, as I explain in the video, even this can bite you in unexpected ways (check out the video chapter “Danger of Cert Pinning” for more info).
If you have the flash space I highly recommend just using one of the cert bundle options. If you have to talk to a lot of domains or even domains that may be dynamic at runtime the bundle is the only real option. As you’ll see below, you can make using the bundle essentially “free”.
Out-of-the-box the IDF config for MbedTLS has almost all of the bells and whistles of TLS turned on. Depending on your application it is unlikely you will need all of them. By turning them off you can save flash space. In just a few tests I was able to reduce the flash size in the following ways:
- Turn off session tickets (-1K)
- Turn off session renegotiation (-1K)
- Turning off unnecessary ciphers (-33K)
These represent just a very small subset of the options available to tune MbedTLS for your application. As you can see, with the cipher change alone you make up more flash space (-33K) than you consume by using the partial ESP cert bundle(+16K). This makes using the cert bundle “free” in terms of flash usage.
- Use one of the ESP cert bundles unless you have a really good reason not to
- If you think you have a really good reason not to…think about it again
- Disable unused TLS features to conserve flash space
- Keep a close eye on cert expiration dates and issue an update so your devices don’t get stuck in a state where they can’t connect to your cloud endpoints
Configuring MbedTLS ties into the Deterministic pillar of the Pillars of Production. In a production environment it’s best to know exactly how your secure communications are configured and what features they support and don’t support. I didn’t and it caused a multi-day outage for my customers. HTTPS on the ESP32 is pretty simple but highly configurable should you need it. It’s easiest to use the defaults but remember there is a lot you can do to tweak ROM and RAM usage.
Join the community and get the weekly Production ESP32 newsletter. Concise, actionable content right in your inbox.