Skip to content

ESP32: fix silent WSS connection failure (missing setInsecure path) - #175

Open
iollama wants to merge 2 commits into
gilmaimon:masterfrom
iollama:fix/esp32-wss-setinsecure
Open

ESP32: fix silent WSS connection failure (missing setInsecure path)#175
iollama wants to merge 2 commits into
gilmaimon:masterfrom
iollama:fix/esp32-wss-setinsecure

Conversation

@iollama

@iollama iollama commented Aug 22, 2026

Copy link
Copy Markdown

On ESP32, wss:// connections fail whenever the caller has not supplied TLS credentials -- and they
fail silently. connect() returns false with no message, no onEvent callback and nothing on
the serial console, so it reads as a network or credentials problem rather than a library one.

This appears to be what's behind #120, #101 and #152.

Cause

Two gaps that combine:

1. SecuredEsp32TcpClient has no setInsecure().

src/tiny_websockets/network/esp32/esp32_tcp.hpp wraps WiFiClientSecure and forwards
setCACert(), setCertificate() and setPrivateKey() -- but not setInsecure(), even though
WiFiClientSecure provides it. There is no way to reach it through this class.

2. The ESP32 branch of upgradeToSecuredConnection() has no fallback.

In src/websockets_client.cpp, the ESP8266 branch ends with:

} else {
    client->setInsecure();
}

The #elif defined(ESP32) branch below it applies each optional credential and then stops. With no
credentials supplied, nothing disables verification, so WiFiClientSecure stays in its default
certificate-verification mode with no CA bundle loaded. Verification cannot succeed and the
handshake dies.

WebsocketsClient::setInsecure() exists and clears the credential pointers, so calling it actually
guarantees you land in the broken path -- the API that should make this work is the one that
triggers the failure.

Reproduction

  • Board: ESP32-S3 (N16R8), Arduino-ESP32 core 3.3.8
  • Library: 0.5.4 / current master
  • Endpoint: any wss:// host
WebsocketsClient client;
client.setInsecure();
bool ok = client.connect("wss://example.org/socket");   // always false on ESP32

Expected: handshake completes, as it does on ESP8266 with the same code.
Actual: connect() returns false. No error, no callback, no output.

The same sketch against a plain ws:// endpoint connects fine, which is what sends people looking
at their network and their credentials instead of at TLS.

The change

Two commits, one per gap:

  • ESP32: add missing setInsecure() to SecuredEsp32TcpClient -- forwards to the underlying
    WiFiClientSecure, alongside the three setters already there.
  • ESP32: fall back to insecure when no TLS credentials are configured -- adds the else branch,
    mirroring ESP8266.

+6 lines, no deletions, no behaviour change for anyone who does supply a CA cert, client
certificate or private key -- the fallback only runs when none were given. ESP8266 and Teensy41 are
untouched.

Note on provenance

These two patches have been running in production for months in
VA5, an ESP32-S3 voice assistant that talks to the
OpenAI Realtime API over WSS. It currently vendors a patched copy of this library because of exactly
this bug. I'd much rather depend on upstream -- happy to reshape the patch however you prefer.

udijw added 2 commits August 22, 2026 13:36
SecuredEsp32TcpClient exposes setCACert(), setCertificate() and
setPrivateKey(), but has no setInsecure() -- even though the underlying
WiFiClientSecure provides one.

upgradeToSecuredConnection() is written as though the method exists. Because
it does not, there is no way to reach WiFiClientSecure::setInsecure() through
this class, and a client that asks for an insecure connection never gets one.
The TLS handshake then fails with no diagnostic.
The ESP8266 branch of upgradeToSecuredConnection() ends in an else that calls
setInsecure() when the caller supplied no fingerprint, trust anchors or client
certificate. The ESP32 branch has no such fallback.

The result is that on ESP32, calling WebsocketsClient::setInsecure() and then
connect() to a wss:// endpoint leaves WiFiClientSecure in its default
certificate-verification mode with no CA bundle loaded. Verification cannot
succeed, so the handshake fails.

It fails silently: connect() returns false with no message, no onEvent
callback and nothing on the serial console, so it presents as a network or
credentials problem rather than a library one. See issues gilmaimon#120, gilmaimon#101 and gilmaimon#152.

This mirrors the existing ESP8266 behaviour rather than introducing new
policy, and only takes effect when no credentials were supplied -- the
CA cert, client certificate and private key paths are unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants