SkillAgentSearch skills...

SSLClient

🔒Add SSL/TLS functionality to any Arduino library

Install / Use

/learn @OPEnSLab-OSU/SSLClient
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

SSLClient

CI

SSLClient adds TLS 1.2 functionality to any network library implementing the Arduino Client interface, including the Arduino EthernetClient and WiFiClient classes. SSLClient was created to integrate TLS seamlessly with the Arduino infrastructure using BearSSL as an underlying TLS engine. Unlike ArduinoBearSSL, SSLClient is completly self-contained, and does not require any additional hardware (other than a network connection).

SSLClient officially supports SAMD21, SAM3X, ESP32, TIVA C, STM32F7, and Teensy >= 3.0; but it should work on any board with at least 110kB flash and 7kB RAM. SSClient does not currently support ESP8266 (see this issue) or AVR due to memory constraints on both platforms.

You can also view this README in doxygen.

Overview

Using SSLClient is similar to using any other Arduino-based Client class, as this library was developed around compatibility with EthernetClient. There are a few extra things, however, that you will need to get started:

  1. Board and Network Peripheral - Your board should have a lot of resources (>110kB flash and >7kB RAM), and your network peripheral should have a large internal buffer (>7kB). This library was tested with the Adafruit Feather M0 (256K flash, 32K RAM) and the Adafruit Ethernet Featherwing (16kB Buffer), and we still had to modify the Arduino Ethernet library to support larger internal buffers per socket (see the Implementation Gotchas).
  2. Trust Anchors - You will need a header containing array of trust anchors (example), which are used to verify the SSL connection later on. This file must generated for every project. Check out TrustAnchors.md on how to generate this file for your project, and for more information about what a trust anchor is.
  3. Network Peripheral Driver Implementing Client - Examples include EthernetClient, WiFiClient, and so on—SSLClient will run on top of any network driver exposing the Client interface.
  4. Analog Pin - Used for generating random data at the start of the connection (see the Implementation Gotchas).

Once all those are ready, you can create an SSLClient object like this:

BaseClientType baseClientInstance;
SSLClient client(baseClientInstance, TAs, (size_t)TAs_NUM, AnalogPin);

Where:

  • BaseClientType - The type of baseClientInstance
  • BaseClientInstance - An instance of the class you are using for SSLClient (the class associated with the network interface, from step 3). It is important that this instance be stored outside the SSLClient declaration (for instance, SSLClient(BaseClientType() ...) wouldn't work).
  • TAs - The name of the trust anchor array created in step 2. If you generated a header using the tutorial this will probably be TAs.
  • TAs_NUM - The number of trust anchors in TAs. If you generated a header using the tutorial this will probably be TAs_NUM.
  • AnalogPin - The analog pin to pull random data from (step 4).

For example, if I am using EthernetClient, a generated array of 2 trust anchors, and the analog pin A7, I would declare an SSLClient instance using:

EthernetClient baseClient;
SSLClient client(baseClient, TAs, 2, A7);

Given this client, simply use SSLClient as you would the base client class:

// connect to ardiuino.cc over ssl (port 443 for websites)
client.connect("www.arduino.cc", 443);
// Make a HTTP request
client.println("GET /asciilogo.txt HTTP/1.1");
client.println("User-Agent: AdafruitFeatherM0WiFi");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
client.flush();
// read and print the data
...

Note: client.connect("www.arduino.cc", 443) can take 5-15 seconds to finish on some low-power devices. This an unavoidable consequence of the SSL protocol, and is detailed more in Implementation Gotchas.

For more information on SSLClient, check out the examples, API documentation, or the rest of this README.

Other Features

Logging

SSLClient also allows for changing the debugging level by adding an additional parameter to the constructor:

EthernetClient baseClient;
SSLClient client(baseClient, TAs, (size_t)2, A7, 1, SSLClient::SSL_INFO);

Logging is always outputted through the Arduino Serial interface, so you'll need to setup Serial before you can view the SSL logs. Log levels are enumerated in ::DebugLevel. The log level is set to SSL_WARN by default.

Errors

When SSLClient encounters an error, it will attempt to terminate the SSL session gracefully if possible, and then close the socket. Simple error information can be found from SSLClient::getWriteError, which will return a value from the ::Error enum. For more detailed diagnostics, you can look at the serial logs, which will be displayed if the log level is at SSL_ERROR or lower.

Write Buffering

As you may have noticed in the documentation for SSLClient::write, calling this function does not actually write to the network. Instead, you must call SSLClient::available or SSLClient::flush, which will detect that the buffer is ready and write to the network (see SSLClient::write for details).

This was implemented as a buffered function because examples in Arduino libraries will often write to the network like so:

EthernetClient client;
// ...
// connect to ardiuino.cc over ssl (port 443 for websites)
client.connect("www.arduino.cc", 443);
// ...
// write an http request to the network
client.write("GET /asciilogo.txt HTTP/1.1\r\n");
client.write("Host: arduino.cc\r\n");
client.write("Connection: close\r\n");
// wait for response
while (!client.available()) { /* ... */ }
// ...

Notice that every single client.write() call immediately writes to the network. This behavior is fine for most network clients; with SSL, however, it results in many small encryption tasks that consume resources. To reduce the overhead of an SSL connection, SSLClient::write implicitly buffers until the developer states that they are waiting for data to be received with SSLClient::available. A simple example can be found below:

EthernetClient baseClient;
SSLClient client(baseClient, TAs, (size_t)2, A7);
// ...
// connect to ardiuino.cc over ssl (port 443 for websites)
client.connect("www.arduino.cc", 443);
// ...
// add http request to the buffer
client.write("GET /asciilogo.txt HTTP/1.1\r\n");
client.write("Host: arduino.cc\r\n");
client.write("Connection: close\r\n");
// write the bytes to the network, then wait for response
while (!client.available()) { /* ... */ }
// ...

If you would like to trigger a network write manually without using the SSLClient::available, you can also call SSLClient::flush, which will write all data and return when finished.

Session Caching

As detailed in the resources section, SSL handshakes take an extended period (1-4sec) to negotiate. BearSSL is able to keep a SSL session cache of the clients it has connected to which can drastically reduce this time: if BearSSL successfully resumes an SSL session, connection time is typically 100-500ms.

In order to use SSL session resumption:

  • The website you are connecting to must support it. Support is widespread, and you can verify it using SSLLabs.
  • You must reuse the same SSLClient object (SSL Sessions are stored in the object itself).
  • You must reconnect to the exact same server (detailed below).

NOTE: SSLClient automatically stores an IP address and hostname in each session, ensuring that if you call connect("www.google.com") SSLClient will use the same SSL session for that hostname. Unfortunately some websites have multiple servers on a single IP address (github.com being an example), so you may find that even if you are connecting to the same host the connection will not resume. This is a flaw in the SSL session protocol—though it has been resolved in TLS 1.3, the lack of widespread adoption of the new protocol prevents it from being resolved here.

SSL sessions can also expire based on server criteria (ex. timeout), which will result in a standard 4-10 second connection.

SSL sessions take memory to store, so by default SSLClient will only store one at a time. You can change this behavior by adding the following to your SSLClient declaration:

EthernetClient baseClient;
SSLClient client(baseClient, TAs, (size_t)2, A7, SomeNumber);

Where SomeNumber is the number of sessions you would like to store. For example this declaration can store 3 sessions:

EthernetClient baseClient;
SSLClient client(baseClient, TAs, (size_t)2, A7, 3);

Sessions are managed internally using the SSLSession::getSession function. This function will cycle through sessions in a rotating order, allowing the session cache to continually overwrite old sessions. In general, it is a good idea to use a SessionCache size equal to the number of domains you plan on connecting to.

If you need to clear a session, you can do so using the SSLSession::removeSession f

View on GitHub
GitHub Stars173
CategoryDevelopment
Updated19d ago
Forks55

Languages

C

Security Score

100/100

Audited on Mar 13, 2026

No findings