MQTT and TLS

How would it be possible to use TLS with MQTT?

I have the following sketch using PubSubClient.h on a MKR1000 and would like to fit it to communicate over TLS instead of in the clear.

#include <SPI.h>
#include <WiFi101.h>
#include <PubSubClient.h>

#include "arduino_secrets.h"
// wifi data in arduino_secrets.h
char ssid[] = SECRET_SSID;        // network SSID (name)
char pass[] = SECRET_PASS;        //  network password

int status = WL_IDLE_STATUS;

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
}

void setup() {
  WiFi.hostname("mkr1000");

  if (WiFi.status() == WL_NO_SHIELD) {
    while (true);       // don't continue
  }

  // attempt to connect to WiFi network:
  while ( status != WL_CONNECTED) {
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection
    delay(10000);
  }
}

WiFiClient mqtt;
PubSubClient mqttclient(mqttserver, 1883, callback, mqtt);

void loop() {
  if (mqttclient.connect("arduinoClient", MQTT_ACCT, MQTT_PASS)) {
    int status=1;
    mqttclient.publish("DemoTopic", String(status).c_str());
    mqttclient.disconnect();
  }
  delay(1500);
}

Try changing

WiFiClient mqtt;

to

WiFiSSLClient mqtt;

Thanks. I'm looking at the documentation for that:

https://www.arduino.cc/en/Reference/WiFi101ClientConnectSSL

Where would the client certificate be added? Custom certificates must be added for the client for the connection to the broker (server) to work.

https://www.instructables.com/id/Arduino-Using-AWS-IoT-Serivce/ Hope that helps.

Thanks. That uses wifi.h and the MKR1000 uses only wifi101.h

On the machine I am trying to connect to from the MKR1000, I have mosquitto’s certificates also added to nginx and was able to use the Firmware Updater to fetch them, or at least it acted like that. Now when I run the following sketch:

#include <SPI.h>
#include <WiFi101.h>        // 
#include <PubSubClient.h>   // 

#include "arduino_secrets.h"
// wifi data in arduino_secrets.h
char ssid[] = SECRET_SSID;        // network SSID (name)
char pass[] = SECRET_PASS;        // network password

int status = WL_IDLE_STATUS;

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
}

void setup() {
  WiFi.hostname("mkr1000");
  Serial.begin(9600);

  if (WiFi.status() == WL_NO_SHIELD) {
    while (true);       // don't continue
  }
  Serial.println("Wifi shield present");
  // attempt to connect to WiFi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Wifi connected");
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // MKR1000's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

// WiFiClient mqtt;
WiFiSSLClient mqtt;
PubSubClient mqttclient(mqttserver, 8883, callback, mqtt);

void loop() {
  if (mqttclient.connect("arduinoClient", MQTT_ACCT, MQTT_PASS)) {
    int status = 1;
    mqttclient.publish("DemoTopic", String(status).c_str());
    Serial.println("DemoTopic");
    mqttclient.disconnect();
  } else {
    Serial.println("oops");
  }
  delay(60000);
}

It connects to the WiFi network ok and prints SSID, IPv4 address, and signal strength (which is -59dB by the way). The MQTT server’s logs show a two lines for each time I upload the sketch:

1594739840: New connection from 192.168.x.y on port 8883.
1594739840: Socket error on client <unknown>, disconnecting.

I know that the MQTT server (broker) is ok because I can connect to it from other machines using mosquitto_pub and mosquitto_sub and tcpdump there shows use of TLS. The if-then-else clause in loop() indicates that the MQTT connection is not established.

Where would the client certificate be added? Custom certificates must be added for the client for the connection to the broker (server) to work.

I'm not aware of an MQTT server that uses client certificates to authenticate. What kind of server are you using? If it's an open source implementatuon, post the configuration you use.

Do you use a valid SSL certificate?

pylon: I'm not aware of an MQTT server that uses client certificates to authenticate. What kind of server are you using? If it's an open source implementatuon, post the configuration you use.

Do you use a valid SSL certificate?

I am using Mosquitto for the server. Here is the configuration with TLS:

$ cat /etc/mosquitto/mosquitto.conf
# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example

pid_file /var/run/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d

$ cat  /etc/mosquitto/conf.d/tls.conf 
user mosquitto
port 8883
cafile   /etc/mosquitto/certs/certificate_authority.crt
keyfile  /etc/mosquitto/certs/server.key
certfile /etc/mosquitto/certs/server.crt
password_file /etc/mosquitto/passwd

protocol mqtt

It launches fine:

$ sudo mosquitto -d -v -c /etc/mosquitto/mosquitto.conf 

$ ps -p $(pgrep -x mosquitto) -o user,pid,args
USER       PID COMMAND
mosquit+  1474 mosquitto -v -d -c /etc/mosquitto/mosquitto.conf

$ sudo tail -f /var/log/mosquitto/mosquitto.log

I can connect to it (from another machine) with the mosquitto_sub and mosquitto_pub, if those use client certificates.

$ mosquitto_sub \
        --verbose \
        -p 8883 \
        -i other-sub \
        -u foo \
        -P bar \
        --cafile /home/me/mosquitto/server.crt \
        --key    /home/me/mosquitto/other.key \
        --cert   /home/me/mosquitto/other.crt \
        -t DemoTopic \
        -h 192.168.x.y

and then I can feed the above data with the following

$ mosquitto_pub \
        --verbose \
        -p 8883 \
        -i other-pub \
        -u foo \
        -P bar \
        --cafile /home/me/mosquitto/server.crt \
        --key    /home/me/mosquitto/other.key \
        --cert   /home/me/mosquitto/other.crt \
        -t DemoTopic \
        -h 192.168.x.y \
        -m "$(date +'%H%M')"

And using tcpdump to watch the connections between the machines, I can see that the connection is not done in clear text like it is without the --cafile, --key, and --cert options.

The server certificate seems valid because I can transfer it to nginx and use it for HTTPS. I was able to fetch it to the MKR1000 that way.

You are trying to figure out how to open your cert file with a text editor, copy the contents, paste into the skectch and convert it for use with your open/connect parameters like so

const char AWS_PUBLIC_CERT[] = ("-----BEGIN CERTIFICATE-----\n\
MIIDWjCCAkKgAwIBAgIVAPTQPproTtQouWYi7ct1lYtzrvXDMA0GCSqGSIb3DQEB\n\
CwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\n\
IEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0yMDA1MDYyMDMz\n\
MzZaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh\n\
dGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRi+OiTJqfoRrRnxu1\n\
Wkg7lDElRZxFe4d8TxcTHYwua1Dm0COkXo5FxqXiMps2xYZ8i8R7Hr+fsyaANpBU\n\
LogYTuneDyFWlvXMreN6t+R8hQHAT9Lj7yg1c6jdXYxArfIocwpVOnE4LPnVdcuw\n\
kS8XIt4xn4VzwzjgAwRq2VIsex3E65QALURxiMB69hOluE+zUU7HWa1xfGxlQir7\n\
7sEchZusU7byc9zzF163dgN3FtP/lQz3v6nEeSAWxMTRQKSerK3huaq1Y6nDqrRf\n\
FiiHB1IbtMKOI4EtYF355lrSvholVnIrR4/SoLILP/iyBEXT9oaEy5AH1+JO4VQt\n\
2aQ3AgMBAAGjYDBeMB8GA1UdIwQYMBaAFOiwyMjBte3X9plChr+7dOL5UnskMB0G\n\
A1UdDgQWBBQKIqet6Ijg7v5gqDDSrnbMNvbWxTAMBgNVHRMBAf8EAjAAMA4GA1Ud\n\
DwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAi85RDng3sZDoYXM2rhonVn9Z\n\
gvbpSxhr+ot1bNmqd1vsuwQl9vVOX6bghJZk1ISgPk54KRQCYkEWNmd2JFa9tTXr\n\
K51eVBi/Q+qfzaNZAQUEw+KetIK9vHrSoM9IjJETN8y4HzZntFqvB31rqZSR7+ZV\n\
5HM6/Qts6ITLb/VxSc8p/uthBhRINZsayiBnv6y2xYUaqYTfCjvVXZu2tGHaIUWe\n\
P6Jo/uJ40nu8PzR4PQGHuVPBKYPMtpH46jtyZ3hKlQhkoWPNTxcutmPMz0hypTJN\n\
ovS0z2uG38JuXUw99d/Mcv4QkzZVY/IzGlEzLqw+8d0qv6ue/CyEdrwqvMIRCQ==\n\
-----END CERTIFICATE-----\n");

?

Idahowalker:
… and convert it for use with your open/connect parameters …

How would I find the documentation about how to apply the certificate to the MQTT API?

You could look it up on the internet or, as I’ll do, have someone show you

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include "certs.h"
 
WiFiClientSecure secureClient = WiFiClientSecure();
PubSubClient mqttClient(secureClient);
 
void connectToAWS() 
{
  mqttClient.setServer(AWS_END_POINT, 8883);
  secureClient.setCACert(AWS_PUBLIC_CERT);
  secureClient.setCertificate(AWS_DEVICE_CERT);
  secureClient.setPrivateKey(AWS_PRIVATE_KEY);
 
  mqttClient.connect(DEVICE_NAME);
  
}

I better get a Karma point for that.

Thanks. I appreciate the concrete example. It will take some time to digest and experiment on it.

You are welcome.

add a new file to your project, name it certs.h, and put your passwords, id, and certs into the tab. When you paste and copy your code the actual info is not telegraphed.

I am trying to this all (still on a MKR1000) using WiFi101, SSLClient, and PubSubClient and think I gotten rather far, but am wondering about the final steps, again involving the keys and certs. I can connect to the broker over TLS from a full GNU/Linux system using the mosquitto client using designated client keys and certificates, as seen here,

mosquitto_sub -v \
	-h x.y.z.a \
	-u xxxxxxxxx \
	-P 'xxxxxxxxxx' \
	--key  mkr1000.key \
	--cert mkr1000.crt \
	--cafile mqtt-server.crt \
	-t 'outTopic' \
	-p 8883 \
	--tls-version tlsv1.2 \
	-I mkr1000

Then I have tweaked the example sketch from SSLClient EthernetMQTT, as seen in the sketch below near the end of the post, so that I can reach to the MQTT broker over WiFi. But because I have not set the key and certificates correctly, it is (as expected) rejecting the connection. I need pointers as to what to write where as far as the keys and certificates go.

Even without the correct key and certificates I can see that the MKR1000 is reaching the broker. Here is an excerpt from the mosquitto broker log, behaving as expected given the lack of certs and a key,

...
1596828429: Socket error on client <unknown>, disconnecting.
1596828429: New connection from x.y.z.b on port 8883.
1596828434: Socket error on client <unknown>, disconnecting.
1596828434: New connection from x.y.z.b on port 8883.
1596828439: Socket error on client <unknown>, disconnecting.
1596828439: New connection from x.y.z.b on port 8883.
1596828444: Socket error on client <unknown>, disconnecting.
1596828444: New connection from x.y.z.b on port 8883.
1596828449: Socket error on client <unknown>, disconnecting.
1596828449: New connection from x.y.z.b on port 8883.
1596828455: Socket error on client <unknown>, disconnecting.
1596828455: New connection from x.y.z.b on port 8883.
...

And also from the MKR1000’s serial console I see about the same thing, re-confirming that the client and the broker are in contact,

...
Attempting MQTT connection...(SSLClient)(SSL_WARN)(connect): Arduino client is already connected? Continuing anyway...
(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, rc=-2 try again in 5 seconds
Attempting MQTT connection...(SSLClient)(SSL_WARN)(connect): Arduino client is already connected? Continuing anyway...
(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, rc=-2 try again in 5 seconds
...

The sketch file certificates.h looks like this so far (I have truncated the data) and would like to know where to put the broker’s certificate and if I have the client key and certificate in the right place and in the right format:

#ifndef _CERTIFICATES_H_
#define _CERTIFICATES_H_

#ifdef __cplusplus
extern "C"
{
#endif

/* You will need to generate the information in this file manually
 * using pycert_bearssl. For more information, please see
 * https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md
 */

const char my_cert[] = "-----BEGIN CERTIFICATE-----\n\
MIIC/TCCAeUCFDgSCNPj6HFzyoqxmzmLoL14ORNdMA0GCSqGSIb3DQEBCwUAMDsx\n\
...
PmXbA913XcEBUmqLRTmb+F4/asqO/jv6kGObFgF9Br+bEASRGwZwRrYZhXCTbVgd\n\
kg==\n\
-----END CERTIFICATE-----";

const char my_key[]  = "-----BEGIN RSA PRIVATE KEY-----\n\
MIIEowIBAAKCAQEA1Wnb6coeB2lvVk/IH14AqLNIzKffIKCGFPIbpA6JUDRLOyzI\n\
...
uy+yivfHWDwgISrS0MET6pGSUg1+/ubfoNSn0IhJWOz+CLe0Ae8I\n\
-----END RSA PRIVATE KEY-----";

#define TAs_NUM 1

static const unsigned char TA_DN0[] = {
    // FIXME
};

static const unsigned char TA_RSA_N0[] = {
    // FIXME
};

static const unsigned char TA_RSA_E0[] = {
    // FIXME
};

static const br_x509_trust_anchor TAs[] = {
    {
        { (unsigned char *)TA_DN0, sizeof TA_DN0 },
        BR_X509_TA_CA,
        {
            BR_KEYTYPE_RSA,
            { .rsa = {
                (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
                (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
            } }
        }
    },
};

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* ifndef _CERTIFICATES_H_ */

I have tried to put the contents of client key (mkr1000.key as seen in the mosquitto_sub listing) in my_key and the contents of client certificate (mkr1000.crt as seen in the mosquitto_sub listing) in my_cert.

Here is the sketch I have so far:

/*
 . . . 
  You will need to populate "certificates.h" with your trust anchors
  (see https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md)
  and my_cert/my_key with your certificate/private key pair
  (see https://github.com/OPEnSLab-OSU/SSLClient#mtls).
*/
#include <SPI.h>
#include <WiFi101.h>        // https://www.arduino.cc/en/Reference/WiFi101
#include <SSLClient.h>      // https://github.com/OPEnSLab-OSU/SSLClient
#include <PubSubClient.h>   // https://pubsubclient.knolleary.net/api

#include "certificates.h"    // This file must be regenerated
#include "arduino_secrets.h" // network connection data in arduino_secrets.h

char ssid[] = SECRET_SSID;       // network SSID
char pass[] = SECRET_PASS;       // network password
int status  = WL_IDLE_STATUS;    // the WiFi radio's status

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

byte mac[] = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
const char* mqttServer = "x.y.z.a"; // Broker address
IPAddress ip (x, y, z, b); // Custom client static IP

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;
WiFiClient wifiClient;
SSLClient wifiClientSSL(wifiClient, TAs, (size_t)TAs_NUM, A5);
PubSubClient mqttclient(mqttServer, 8883, callback, wifiClientSSL);

void reconnect() {
  // Loop until we're reconnected
  while (!mqttclient.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (mqttclient.connect("arduinoClient", MQTT_ACCT, MQTT_PASS)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      mqttclient.publish("outTopic", "hello world");
      // This is a workaround to address https://github.com/OPEnSLab-OSU/SSLClient/issues/9
      wifiClientSSL.flush();
      // ... and resubscribe
      mqttclient.subscribe("inTopic");
      // This is a workaround to address https://github.com/OPEnSLab-OSU/SSLClient/issues/9
      wifiClientSSL.flush();
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttclient.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

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
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to WiFi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);

    // wait 5 seconds for connection:
    delay(5000);
  }
  Serial.println("You're connected to the network");

}

void loop() {
  if (!mqttclient.connected()) {
    reconnect();
  }
  mqttclient.loop();
}

How do I add in the chosen server certificate, the client certificate, and the client key to all that so that the sketch completes the TLS connection? Specifically the question is about what to populate the variables TA_DN0, TA_RSA_N0, TA_RSA_E0, and br_x509_trust_anchor with and is my current attempt at filling my_cert and my_key looking ok?

Post #8 and #10 do not show you what you are looking for?

I think that posts #8 and #10 help me see the right direction but they are also clearly for WiFi not WiFi101. WiFi.h is not available for the MKR1000. I've double checked just to be sure and it reports not finding the WiFi shield when I try it. It's also listed as deprecated. The WiFi101 + SSLClient approach looks like what should work for the MKR1000. However, for that I am confused as how to map the keys and certificates to the right variables. There are quite a few variables in certificates.h

I've read quite a bit more, especially about BearSSL. I now have some BearSSL utilities installed on a spare machine. I have used them to try generate the C data structures, but due to lack of knowledge about the process have to take a guess at both the method and the choice of files since the guides are oriented towards downloading commercial certificates not using ones I have signed myself. I have tried using the brssl utility

brssl chain ca.crt;         # the CA cert
brssl chain server.crt;    # the server's signed certificate

to process the .crt file for my certificate authority and put the output into the variable TA_DN0 and the server's certificate (signed by the aforementioned certificate) into TA_RSA_N0 in the following C data structure:

#ifndef _CERTIFICATES_H_
#define _CERTIFICATES_H_

#ifdef __cplusplus
extern "C"
{
#endif

/* You will need to generate the information in this file manually
   using pycert_bearssl. For more information, please see
   https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md
*/

#define TAs_NUM 1

static const unsigned char TA_DN0[] = {
  // FIXME
};

static const unsigned char TA_RSA_N0[] = {
  // FIXME
};

static const unsigned char TA_RSA_E0[] = {
  // FIXME
};

static const br_x509_trust_anchor TAs[] = {
  {
    { (unsigned char *)TA_DN0, sizeof TA_DN0 },
    BR_X509_TA_CA,
    {
      BR_KEYTYPE_RSA,
      { .rsa = {
          (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
          (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
        }
      }
    }
  },
};

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* ifndef _CERTIFICATES_H_ */

Not surprisingly it gives an error:

Attempting MQTT connection...(SSLClient)(SSL_WARN)(connect): Arduino client is already connected? Continuing anyway...
(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.

Which web page or manual page should I be studying to stop flailing around randomly like that? As mentioned earlier, I can use both these certificates with mosquitto just fine, but that is not Arduino.

Is this GitHub issue helpful? MQTT SSL possible? · Issue #7 · OPEnSLab-OSU/SSLClient · GitHub

The link looks promising. I will examine it closely. Good timing, I am getting ready to work some more on the task in a few days.

Thanks. I’ve had a chance to look at that thread now and it seems focused on the client.setMutualAuthParams(mTLS); part which I think I have set ok. I think that, in part, because I am getting a very different error. The error I have is about the trust auhtority.

I am using a self-signed certificate, not a commercial certificate. So I am probably not converting the CA.crt (the certificate authority cert) and server.crt (the MQTT server’s own certificate) files properly. I could certainly use more ideas about how to get both of those into the right format so they can be used by the SSLClient library. The library Example sketch shows three places marked // FIX ME but I am puzzled as to precisely what to put there in the three variables.

Here is the current error message:

You're connected to the network
Attempting MQTT connection...(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.

from this sketch:

/*
  Basic MQTT example (with SSL!)
  This sketch demonstrates the basic capabilities of the library.
  It connects to an MQTT server then:
  - publishes "hello world" to the topic "outTopic"
  - subscribes to the topic "inTopic", printing out any messages
    it receives. NB - it assumes the received payloads are strings not binary
  It will reconnect to the server if the connection is lost using a blocking
  reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
  achieve the same result without blocking the main loop.

  You will need to populate "certificates.h" with your trust anchors
  (see https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md)
  and my_cert/my_key with your certificate/private key pair
  (see https://github.com/OPEnSLab-OSU/SSLClient#mtls).
*/
#include <SPI.h>
#include <WiFi101.h>        // https://www.arduino.cc/en/Reference/WiFi101
#include <SSLClient.h>      // https://github.com/OPEnSLab-OSU/SSLClient
#include <PubSubClient.h>   // https://pubsubclient.knolleary.net/api

#include "certificates.h"    // This file must be regenerated
#include "arduino_secrets.h" // network connection data in arduino_secrets.h
char ssid[] = SECRET_SSID;       // network SSID
char pass[] = SECRET_PASS;       // network password
int status  = WL_IDLE_STATUS;    // the WiFi radio's status

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

byte mac[] = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };

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;
WiFiClient wifiClient;
SSLClient wifiClientSSL(wifiClient, TAs, (size_t)TAs_NUM, A5);
PubSubClient mqttclient(mqttServer, 8883, callback, wifiClientSSL);

void reconnect() {
  // Loop until we're reconnected
  while (!mqttclient.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (mqttclient.connect("arduinoClient", MQTT_ACCT, MQTT_PASS)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      mqttclient.publish("outTopic", "hello world");
      // This is a workaround to address https://github.com/OPEnSLab-OSU/SSLClient/issues/9
      wifiClientSSL.flush();
      // ... and resubscribe
      mqttclient.subscribe("inTopic");
      // This is a workaround to address https://github.com/OPEnSLab-OSU/SSLClient/issues/9
      wifiClientSSL.flush();
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttclient.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  // Start Serial
  Serial.begin(115200);
  while (!Serial);
  // Enable mutual TLS with SSLClient
  //ethClientSSL.setMutualAuthParams(mTLS);
  wifiClientSSL.setMutualAuthParams(mTLS);  
  // You can use Ethernet.init(pin) to configure the CS pin
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to WiFi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);

    // wait 5 seconds for connection:
    delay(5000);
  }
  Serial.println("You're connected to the network");

}

void loop() {
  if (!mqttclient.connected()) {
    reconnect();
  }
  mqttclient.loop();
}

and here is the certificates.h file (with abbreviated data):

#ifndef _CERTIFICATES_H_
#define _CERTIFICATES_H_

#ifdef __cplusplus
extern "C"
{
#endif

/* You will need to generate the information in this file manually
   using pycert_bearssl. For more information, please see
   https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md
*/

const char my_cert[] = "-----BEGIN CERTIFICATE-----\n\
MIIC/TCCAeUCFDgSCNPj6HFzyoqxmzmLoL14ORNdMA0GCSqGSIb3DQEBCwUAMDsx\n\
...
PmXbA913XcEBUmqLRTmb+F4/asqO/jv6kGObFgF9Br+bEASRGwZwRrYZhXCTbVgd\n\
kg==\n\
-----END CERTIFICATE-----";

const char my_key[]  = "-----BEGIN RSA PRIVATE KEY-----\n\
MIIEowIBAAKCAQEA1Wnb6coeB2lvVk/IH14AqLNIzKffIKCGFPIbpA6JUDRLOyzI\n\
...
Bhb+NUPFJEOHTjBlT8auEUi23xSo9Q/6g+pHQprMHXtNzeujnnVftI+KIDOvJd8y\n\
uy+yivfHWDwgISrS0MET6pGSUg1+/ubfoNSn0IhJWOz+CLe0Ae8I\n\
-----END RSA PRIVATE KEY-----";

#define TAs_NUM 1

static const unsigned char TA_DN0[] = {
  // FIXME
  0x30, 0x82, 0x03, 0x57, 0x30, 0x82, 0x02, 0x3F, 0xA0, 0x03, 0x02, 0x01,
...
  0x38, 0x52, 0xA9, 0xB1, 0xE3, 0x78, 0xB8, 0xFA, 0x5A, 0x87, 0x68, 0x70,
  0xE7, 0x1F, 0xF8, 0x69, 0x05, 0x4C, 0x33
};

static const unsigned char TA_RSA_N0[] = {
  // FIXME
  0x30, 0x82, 0x03, 0x17, 0x30, 0x82, 0x01, 0xFF, 0xA0, 0x03, 0x02, 0x01,
  0x02, 0x02, 0x14, 0x38, 0x12, 0x08, 0xD3, 0xE3, 0xE8, 0x71, 0x73, 0xCA,
...
  0x84, 0x3C, 0x0E, 0x53, 0xD4, 0xDF, 0xBA, 0x10, 0xFF, 0xA6, 0xFF, 0x0F,
  0x87, 0x6D, 0x7B
};

static const unsigned char TA_RSA_E0[] = {
  // FIXME
  0x01, 0x00, 0x01,

};

static const br_x509_trust_anchor TAs[] = {
  {
    { (unsigned char *)TA_DN0, sizeof TA_DN0 },
    BR_X509_TA_CA,
    {
      BR_KEYTYPE_RSA,
      { .rsa = {
          (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
          (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
        }
      }
    }
  },
};

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* ifndef _CERTIFICATES_H_ */