WSS port not connecting

I've been trying to get a secure connection using the wss protocol with the ESP32Cam for some time now without any luck. To figure out what is going wrong i tested all possibilities at:

websocket.org

and this:

/*
	Secured Esp32 Websockets Client
	This sketch:
        1. Connects to a WiFi network
        2. Connects to a Websockets server (using WSS)
        3. Sends the websockets server a message ("Hello Server")
        4. Sends the websocket server a "ping"
        5. Prints all incoming messages while the connection is open
    NOTE:
    The sketch dosen't check or indicate about errors while connecting to 
    WiFi or to the websockets server. For full example you might want 
    to try the example named "Esp32-Client" (And use the ssl methods).
	Hardware:
        For this sketch you only need an Esp32 board.
	Created 15/02/2019
	By Gil Maimon
	https://github.com/gilmaimon/ArduinoWebsockets
*/

#include <ArduinoWebsockets.h>
#include <WiFi.h>

const char* ssid = "ssid"; //Enter SSID
const char* password = "password"; //Enter Password

const char* websockets_connection_string = "wss://echo.websocket.org/"; //Enter server adress

// This certificate was updated 15.04.2021, issues on Mar 15th 2021, expired on June 13th 2021
const char echo_org_ssl_ca_cert[] PROGMEM = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIEZTCCA02gAwIBAgIQQAF1BIMUpMghjISpDBbN3zANBgkqhkiG9w0BAQsFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTIwMTAwNzE5MjE0MFoXDTIxMDkyOTE5MjE0MFow\n" \
"MjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxCzAJBgNVBAMT\n" \
"AlIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwIVKMz2oJTTDxLs\n" \
"jVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKp\n" \
"Tm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnB\n" \
"U840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7\n" \
"gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel\n" \
"/xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1R\n" \
"oYvbFQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E\n" \
"BAMCAYYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5p\n" \
"ZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTE\n" \
"p7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEE\n" \
"AYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2Vu\n" \
"Y3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0\n" \
"LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYf\n" \
"r52LFMLGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B\n" \
"AQsFAAOCAQEA2UzgyfWEiDcx27sT4rP8i2tiEmxYt0l+PAK3qB8oYevO4C5z70kH\n" \
"ejWEHx2taPDY/laBL21/WKZuNTYQHHPD5b1tXgHXbnL7KqC401dk5VvCadTQsvd8\n" \
"S8MXjohyc9z9/G2948kLjmE6Flh9dDYrVYA9x2O+hEPGOaEOa1eePynBgPayvUfL\n" \
"qjBstzLhWVQLGAkXXmNs+5ZnPBxzDJOLxhF2JIbeQAcH5H0tZrUlo5ZYyOqA7s9p\n" \
"O5b85o3AM/OJ+CktFBQtfvBhcJVd9wvlwPsk+uyOy2HI7mNxKKgsBTt375teA2Tw\n" \
"UdHkhVNcsAKX1H7GNNLOEADksd86wuoXvg==\n" \
"-----END CERTIFICATE-----\n";

using namespace websockets;

void onMessageCallback(WebsocketsMessage message) {
    Serial.print("Got Message: ");
    Serial.println(message.data());
}

void onEventsCallback(WebsocketsEvent event, String data) {
    if(event == WebsocketsEvent::ConnectionOpened) {
        Serial.println("Connnection Opened");
    } else if(event == WebsocketsEvent::ConnectionClosed) {
        Serial.println("Connnection Closed");
    } else if(event == WebsocketsEvent::GotPing) {
        Serial.println("Got a Ping!");
    } else if(event == WebsocketsEvent::GotPong) {
        Serial.println("Got a Pong!");
    }
}

WebsocketsClient client;
void setup() {
    Serial.begin(115200);
    // Connect to wifi
    WiFi.begin(ssid, password);

    // Wait some time to connect to wifi
    for(int i = 0; i < 10 && WiFi.status() != WL_CONNECTED; i++) {
        Serial.print(".");
        delay(1000);
    }

    // run callback when messages are received
    client.onMessage(onMessageCallback);
    
    // run callback when events are occuring
    client.onEvent(onEventsCallback);

    // Before connecting, set the ssl fingerprint of the server
    client.setCACert(echo_org_ssl_ca_cert);

    // Connect to server
    client.connect(websockets_connection_string);

    // Send a message
    client.send("Hello Server");

    // Send a ping
    client.ping();
}

void loop() {
    client.poll();
}

They all work correctly. Until i try to connect to the server installed on my mac (using ip 192.168.2.3):

//nodejs/server.js
const path = require("path");
const express = require("express");
const WebSocket = require("ws");
const fs = require("fs");
const https = require("https");
// const { certificate } = require("crypto");

var privateKey = fs.readFileSync("server.key", "utf8");
var certificate = fs.readFileSync("server.cert", "utf8");
var credentials = { key: privateKey, cert: certificate };

const HTTPS_PORT = 443;
const app = express();
const httpsServer = https.createServer(credentials, app);
const wsServer = new WebSocket.Server({ server: httpsServer });

let connectedClients = [];
wsServer.on("connection", (ws, req) => {
	console.log("Connected");

	ws.on("message", (data) => {
		if (data.indexOf("WEB_CLIENT") !== -1) {
			connectedClients.push(ws);
			console.log("WEB_CLIENT ADDED");
			return;
		}

		connectedClients.forEach((ws, i) => {
			if (connectedClients[i] == ws && ws.readyState === ws.OPEN) {
				ws.send(data);
			} else {
				connectedClients.splice(i, 1);
			}
		});
	});

	ws.on("error", (error) => {
		console.error("WebSocket error observed: ", error);
	});
});

app.use(express.static("."));
app.get("/client", (req, res) => res.sendFile(path.resolve(__dirname, "./client.html")));
httpsServer.listen(HTTPS_PORT, () => console.log(`HTTPS server listening at ${HTTPS_PORT}`));

Any ideas to get this working?

If you want to do TLS start by understanding TLS! A secure connection to IP 192.168.2.3 will probably fail because the provided server certificate most probably doesn't contain the server name "192.168.2.3". So the client will deny the access and this is correct.

Why exactly do you think you need a TLS (SSL) connection to a server running on your Mac on the same network?

Did you change the CA cert in your sketch to match the CA of the certificate you use in your node.js hack?

I use unsigned certificates for example webmin for ages. Which I access with the ip address without a problem. Why wouldn't it work on a local environment?

Sending cam footage over an unencrypted WIFI connection is vulnerable for packet sniffers.

I doubt that. You may have used self-signed certificates but using non-ancient browsers you have to click away at least some errors to get access to such a site.

If you call these errors "no problem" and "working" you might be surprised that some embedded devices care for security and deny access to wrongly configured TLS sites.

If you don't care for any security, why do you use TLS/SSL at all?

Using TLS without checking the certificate (that's what you're trying to do) doesn't protect you from sniffing. If only needs a little higher level of knowledge or some better tools but the security is on an equal level.
That's the same as closing the safety belt behind your back. The car will be silent but in case of a crash it won't really protect you.

If you don't care, just provide the server's certificate as the CA to the ESP32 and it will be accepted (given you actually use self-signed certificates).

The goal is to send data over WiFi encrypted. I am the only one who created and uses the certificate. Data send of the Wifi is not thát confidential. It's just to keep the script kiddies out.

Is it?... without checking the cert? The 'error' messages that are being displayed are all about the fact that it is unsigned, meaning an unverified source, (knowing that certificates is big business) i would doubt the reasons of these messages.

Nevertheless, i am open for your arguments but i do need more 'proof'. What tools are you talking about? And I will dive deeper into it.

Are you talking about this: ?

/*
	Secured Esp32 Websockets Client

	This sketch:
        1. Connects to a WiFi network
        2. Connects to a Websockets server (using WSS)
        3. Sends the websockets server a message ("Hello Server")
        4. Sends the websocket server a "ping"
        5. Prints all incoming messages while the connection is open

    NOTE:
    The sketch dosen't check or indicate about errors while connecting to 
    WiFi or to the websockets server. For full example you might want 
    to try the example named "Esp32-Client" (And use the ssl methods).

	Hardware:
        For this sketch you only need an Esp32 board.

	Created 15/02/2019
	By Gil Maimon
	https://github.com/gilmaimon/ArduinoWebsockets

*/

#include <ArduinoWebsockets.h>
#include <WiFi.h>

const char* ssid = "ssid"; //Enter SSID
const char* password = "password"; //Enter Password

const char* websockets_connection_string = "wss://echo.websocket.org/"; //Enter server adress

// This certificate was updated 15.04.2021, issues on Mar 15th 2021, expired on June 13th 2021
const char echo_org_ssl_ca_cert[] PROGMEM = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIEZTCCA02gAwIBAgIQQAF1BIMUpMghjISpDBbN3zANBgkqhkiG9w0BAQsFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTIwMTAwNzE5MjE0MFoXDTIxMDkyOTE5MjE0MFow\n" \
"MjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxCzAJBgNVBAMT\n" \
"AlIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwIVKMz2oJTTDxLs\n" \
"jVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKp\n" \
"Tm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnB\n" \
"U840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7\n" \
"gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel\n" \
"/xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1R\n" \
"oYvbFQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E\n" \
"BAMCAYYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5p\n" \
"ZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTE\n" \
"p7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEE\n" \
"AYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2Vu\n" \
"Y3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0\n" \
"LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYf\n" \
"r52LFMLGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B\n" \
"AQsFAAOCAQEA2UzgyfWEiDcx27sT4rP8i2tiEmxYt0l+PAK3qB8oYevO4C5z70kH\n" \
"ejWEHx2taPDY/laBL21/WKZuNTYQHHPD5b1tXgHXbnL7KqC401dk5VvCadTQsvd8\n" \
"S8MXjohyc9z9/G2948kLjmE6Flh9dDYrVYA9x2O+hEPGOaEOa1eePynBgPayvUfL\n" \
"qjBstzLhWVQLGAkXXmNs+5ZnPBxzDJOLxhF2JIbeQAcH5H0tZrUlo5ZYyOqA7s9p\n" \
"O5b85o3AM/OJ+CktFBQtfvBhcJVd9wvlwPsk+uyOy2HI7mNxKKgsBTt375teA2Tw\n" \
"UdHkhVNcsAKX1H7GNNLOEADksd86wuoXvg==\n" \
"-----END CERTIFICATE-----\n";

using namespace websockets;

void onMessageCallback(WebsocketsMessage message) {
    Serial.print("Got Message: ");
    Serial.println(message.data());
}

void onEventsCallback(WebsocketsEvent event, String data) {
    if(event == WebsocketsEvent::ConnectionOpened) {
        Serial.println("Connnection Opened");
    } else if(event == WebsocketsEvent::ConnectionClosed) {
        Serial.println("Connnection Closed");
    } else if(event == WebsocketsEvent::GotPing) {
        Serial.println("Got a Ping!");
    } else if(event == WebsocketsEvent::GotPong) {
        Serial.println("Got a Pong!");
    }
}

WebsocketsClient client;
void setup() {
    Serial.begin(115200);
    // Connect to wifi
    WiFi.begin(ssid, password);

    // Wait some time to connect to wifi
    for(int i = 0; i < 10 && WiFi.status() != WL_CONNECTED; i++) {
        Serial.print(".");
        delay(1000);
    }

    // run callback when messages are received
    client.onMessage(onMessageCallback);
    
    // run callback when events are occuring
    client.onEvent(onEventsCallback);

    // Before connecting, set the ssl fingerprint of the server
    client.setCACert(echo_org_ssl_ca_cert);

    // Connect to server
    client.connect(websockets_connection_string);

    // Send a message
    client.send("Hello Server");

    // Send a ping
    client.ping();
}

void loop() {
    client.poll();
}

This test didn't work for me either.

Then use WPA2 WiFi, you'll get encryption on the Ethernet layer.

It is but only if you need a "online-banking-level" certificate. You have the possibility to create your own CA and sign your certificates with it or use Let's Encrypt certificates which are free for everyone.

Why? It's exactly that. You used a self-signed certificate, so the browser cannot check the certificate. If you ignore that error message, it means you want to accept any certificate for the connection, the certificate may also come from someone else who is trying to interfere your connection.
So given the script kiddie is on your WiFi network, it just has to catch the IP address and send the he's own self-signed certificate in the connection setup.

What other proof do you need?

No, that's the CA certificate of Let's Encrypt. You have to insert your own certificate here. And to make your code work you should insert the IP address as the DNS Subject Alternative Name or the CN value in the certificate subject.

Good point. I do use WPA2 Personal Wifi with AES encryption. Should upgrade to WPA2 Enterprise or WPA Auto Enterprise with TKIP+AES?

The reason i have doubts about the wifi security is because I have a couple of Raspberry Pi zero W cams around the house. Several times I have noticed individuals looking straight at the camera. However, it won't humanly possible to notice it IF you don't know it is there. The only conclusion: "somewhere is pickup it's footage".

Accessing/breaking into my Wifi network is merely impossible (WPA2 + 60 digit "ascii" password), so good luck with that.

No, WPA2 Personal is sufficient for you.

I doubt that someone broke WPA2 encryption to see your cameras. It's not impossible but needs to many resources for such a target.

Interesting, as you told us that you expect exactly that in the previous paragraph. So if no-one is accessing your WiFi network, how should he be picking up the footage of your camera?

And that is what I am wondering too. Fact is, they know the location the camera. From a visual point of view they would never noticed. It is simply impossible. So what gives.

If I had to bet I would say that you make the cameras accessible from the Internet and that connection is not very secure.

A ping from a cam does return positives, when pinging to ip only.
A port scan from an external server to my home ip returns with the message that all 1000 scanned ports are filtered.

So i would say that that isn't the case.

I don't see why this is relevant here.

That does only tell us that you don't have open ports on your router.

Do you have access to your cameras from the Internet?

BTW, why are you so sure that your Pi cameras are not visible?
The people that look into that cameras are they the type of hacker that is able to break your WiFi security?

Anyway, we left the topic. I already told you how to use your own CA. I'm a bit surprised that you secure the connection to the ESP but don't care about the video stream. You seem to be in another jurisdiction as taking video stream from public areas isn't allowed where I live.