How to connect to raspberrypi with self signed SSL certificate

Hello everybody,

I am using an Arduino Nano 33 IoT and am trying to connect to my Raspberrypi 4 using a self signed SSL certificate. However, it does not work and after googling hours over hours, I tought to ask the Arduino Community.

On my raspberrypi I've set up an Nginx-Server that is using the desired client-certificate. Next I uploaded the certificate following these instructions: https://support.arduino.cc/hc/en-us/articles/360016119219-How-to-add-certificates-to-Wifi-Nina-Wifi-101-Modules-
I got a message from the FirmwareUpdater, that all certificates were successfully uploaded.

As for the next step, I took the WiFiSSLClient sample code and adjusted the code to my needs.

/*
This example creates a client object that connects and transfers
data using always SSL.

It is compatible with the methods normally related to plain
connections, like client.connect(host, port).

Written by Arturo Guadalupi
last revision November 2015

*/

#include <SPI.h>
#include <WiFiNINA.h>

#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key index number (needed only for WEP)

int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
char server[] = "raspberrypi";    

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiSSLClient client;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // 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. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to WiFi");
  printWiFiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 443)) {
    Serial.println("connected to server");
    // Make a HTTP request:
    client.println("Host: raspberrypi");
    client.println("Connection: close");
    client.println();
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}


void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

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

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

I get the following output:

grafik

As you can see, I am able to connect to my WiFi, but not to my raspberrypi. However, I can connect to my raspberrypi over https using the browser of my PC (after installing the self signed certificates manually in my browser, of course).
Also, I already tried connecting to the raspberrypi from the arduino without SSL and that worked just fine.

Does anyone have a clue why I can't connect to my raspberrypi over SSL using the arduino?
Thanks in advance!

1 Like

First question, why do you need SSL? If you're convinced you need then either you need the full SSL chain trusted by the Arduino. Either you need to add the root ca, or you need to tell the arduino to ignore certificate errors. Are you actually seeing any errors?

I don't necessarily need SSL, but I am interested in how it works. Also, I don't get any errors from the arduino. However, as my goal is to use the SSL certificate to connect to a mosquitto broker on my raspberrypi over TLS, I get the following error in the mosquitto.log:

1625169344: New connection from 192.168.xxx.xx on port 8883.
1625169344: OpenSSL Error: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
1625169344: Socket error on client , disconnecting.

I can connect with the MQTTX client for example using the client.crt, client.key and ca.crt easily. But I am not sure if the arduino even has the correct certificates installed and if it connects via the mqtts protocol using the WiFiSSLClient. The problem is, that I don't know how i can check which certificates are actually installed on the arduino as I only get a message that the certificate was uploaded successfully using the mentioned approach.

I recommend you have a look at WireShark. It is an open-source network analyzer.

https://www.wireshark.org/

On my laptop (Win10) I can create a Mobile Hotspot that will share the network. I can connect the Arduino to the hotspot and watch all traffic from the Arduino to the target e.g., a Raspberry Pi.

You should be able to see a difference between encrypted and standard connections.

In the end it worked using a Let's Encrypt certificate. But I could not find a way to use a self signed certificate.

1 Like

Thank you for the update.

May I ask whether you could provide a few lines of instructions that might be helpful for others to try this?

Sorry for the late answer! Of course, I can do that. :slight_smile:


So for the setup I am using a Raspberry Pi 4, an Arduino Nano 33 IoT and DuckDNS as a DNS-Server. DuckDNS is free to use and works just fine for private and small projects as mine.

For the next lines, I am providing the rough approach on how I've done it. At the end of this post I will provide some http-links that I've used as sources and to gain new knowledge. You should have a look at them as well, if this solution does not work for you.

So let's start.


Port Forwarding:
You have to do some port forwarding on your router. The process on how to do that depends on the router, you are using.

I am using a FritzBox with following ports. The ports depend on your mosquitto and nginx configurations. The nginx server, I am using for DuckDNS and to create a Let's Encrypt certificate runs on the default port 80 and 443. The other ports are for the websocket and mqtt protocols (and their secure versions).
grafik

On the Raspberry side:

I am using a raspberry pi 4 with the default raspbian 32bit OS.

Prerequirements:

  • install mosquitto mqtt
  • install nginx
  • open the required ports with ufw allow <port> on your raspberry

There are plenty of tutorials around the web on how to install and configure nginx and mosquitto on a raspberry pi. I didn't have any problems with that, so you should be fine as well.

  1. You have to install certbot to generate the Let's encrypt certificates.
  2. Register an account at https://www.duckdns.org/
  3. Configure nginx according to your DuckDNS domain. (For more information see the links in the section below).
  4. Create a new certificate with following command:
    sudo certbot certonly --standalone --preferred-challenged http -d <your-subdomain>.duckdns.org -d *.<your-subdomain>.duckdns.org
  5. Copy the following files to your mosquitto directory (optionally you can also provide the path to your Let's Encrypt certificate in your mosquitto.conf file. However, you may have to configure some rights of your linux system in order for it to work).
sudo cp /etc/letsencrypt/live/<your-subdomain>.duckdns.org/cert.pem /etc/mosquitto/certs/
sudo cp /etc/letsencrypt/live/<your-subdomain>.duckdns.org/chain.pem /etc/mosquitto/certs/
sudo cp /etc/letsencrypt/live/<your-subdomain>.duckdns.org/privkey.pem /etc/mosquitto/certs/
  1. Configure your mosquitto.conf file to your needs using the copied certificate files.
    The configuration bwlow allows clients to connect via TLS and without TLS.
listener 1883

listener 8883
# TLS/SSL
certfile /etc/mosquitto/certs/cert.pem
cafile /etc/mosquitto/certs/chain.pem
keyfile /etc/mosquitto/certs/privkey.pem

listener 9001
protocol websockets

listener 8083
protocol websockets
# TLS/SSL
certfile /etc/mosquitto/certs/cert.pem
cafile /etc/mosquitto/certs/chain.pem
keyfile /etc/mosquitto/certs/privkey.pem
  1. You must configure your nginx-server to use the certificates and make it accessable via https. This is required to install the certificate on the Arduino later on. Also, you should provide a basic index.html file in order to have a "website" that can be certificated.
sudo nano /etc/nginx/conf.d/<your-domain>.duckdns.org.conf
server {
        listen 80 default_server;
        server_name <your-domain>.duckdns.org;
        return 301 https://$server_name$request_uri;
        root /var/www/<your-domain>.duckdns.org;
        index index.php index.htm index.html;
}

server {
        listen 443 ssl default_server;
        server_name <your-domain>.duckdns.org;

        ##
        # SSL
        ##

        ssl on;
    ssl_certificate /etc/letsencrypt/live/<your-domain>.duckdns.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/<your-domain>.duckdns.org/privkey.pem; # managed by Certbot
        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_ciphers  HIGH:!aNULL:!MD5:!RC4;

        ##
        # HSTS
        ##

        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        ##
        # global
        ##

        root /var/www/<your-domain>.duckdns.org;
        index index.php index.htm index.html;

        location / {
                try_files $uri $uri/ =404;
        }
}
  1. Don't forget to restart your mosquitto server and nginx server.

DONE! Now, you should have access to your mosquitto server via TLS using a trusted Let's Encrypt certificate. You can test this with any MQTT-Client. For example, I am using MQTT X (https://mqttx.app/) for testing.

Edit:
You can renew the Let's Encrypt certificate by using following command:

sudo certbot --authenticator standalone --installer nginx -d <your-domain>.duckdns.org -d *.<your-domain>.duckdns.org --pre-hook "service nginx stop" --post-hook "service nginx start"

Arduino:

  1. First you have to use thw WiFiSSLClient instead of the WiFiClient in your code.
WiFiSSLClient wifiClient;
PubSubClient client(wifiClient);
  1. Next you have to update your credentials according to your new configurations. Your server name will be your new DuckDNS domain and you might want to change the port according to the port you chose for TLS/SSL connections.
  2. I have update the NINA firmware of my Arduino to version 1.4.5, which requires to use the WiFiNINA library v 1.8.10. However, I am not sure if this is even required but it works.
    Updating the firmware is pretty easy. Just flash the FirmwareUpdater example on your Arduino, choose your Arudino port and the version, you want to update to and click on "Update Firmware".

  1. Install the Let's Encrypt certificate from your nginx website according to following instructions by using your DuckDNS domain: https://support.arduino.cc/hc/en-us/articles/360016119219-How-to-add-certificates-to-Wifi-Nina-Wifi-101-Modules-

DONE! Because Let's Encrypt is already a trusted CA to the Arduino Nano 33 IoT, you don't have to do any further steps to trust the certificate.


Resources:

Side notes:
In this post, I am explaining for what I am using the mosquitto server and how to use it to control pwm-fans if anyone is interested. This might also help to write some code for your Arduino project.


I hope this post can help some people even though it does not provide every details of the whole process. However, I didn't want to pollute this post with writing too much about nginx and mosquitto itself.

2 Likes

Thank you. I am sure this will we be useful. Encryption is becoming an increasingly important technology and more often mandatory.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.