-
Notifications
You must be signed in to change notification settings - Fork 564
secure websocket server support #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
wss as client is supported for the ESP8266 |
saw that .. however WSS server is needed within esp8266 ... the reason is cross platform browser support for WSS. I checked your latest version with echo page of websockets.org .. below are the test results
I think SSL is yet to be supported from https://github.com/esp8266/Arduino Keep up the great work! |
yes SSL/TLS server is not Implemented for the ESP8266 yet, if it get there I will integrated here too. |
true! |
may because the websocket server will not send a |
the same applies to ESP8266 hosted WebSocketServer ( example provided by you ) chrome - does not work Can you add the response header into your source ? |
will add it as option, since when its there its a possible security hole. |
- Access-Control-Allow-Origin (#25) - Sec-WebSocket-Protocol () add _server->close(); for ESP
WebSocketsServer wsServer = WebSocketsServer(81, "*"); |
Thank you so much! Appreciate your prompt response Sent from my Windows Phone -----Original Message----- WebSocketsServer wsServer = WebSocketsServer(81, "*"); — |
WebSocketsServer wsServer = WebSocketsServer(80, ""); chrome - works (both port 80 & 9000) - but with delayed initial connection establishment |
is there an example for having WSS server on the ESP8266 ? |
@asmaklad Were you able to find a way to host a secure websocket server? |
@shrynshjn the real problem is you can't have a server HTTPS and WS out of the same server, modern browsers refuse mixed security webpages. |
I'm looking for this as well (in conjunction with |
I'm bumping this as well; I'd love to be able to run a secured server (I can provide the key/etc potentially via something like http://local-ip.co) from my ESP32 so I can connect to it from an HTTPS website. |
Oh yeah I did figure out a way but forgot to mention it here. :> Note that this is specific to Since this library still expects working with plaintext-related objects it does need some changes. I simply copied #ifndef __WEBSOCKETS4WEBSERVERSECURE_H
#define __WEBSOCKETS4WEBSERVERSECURE_H
#include <WebSocketsServer.h>
#include <ESP8266WebServerSecure.h>
#if WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
class WebSockets4WebServerSecure : public WebSocketsServerCore {
public:
WebSockets4WebServerSecure(const String &origin = "", const String &protocol = "arduino") : WebSocketsServerCore(origin, protocol) {
begin();
}
// Original: ESP8266WebServer::HookFunction hookForWebserver(const String &wsRootDir, WebSocketServerEvent event) {
BearSSL::ESP8266WebServerSecure::HookFunction hookForWebserver(const String &wsRootDir, WebSocketServerEvent event) {
onEvent(event);
// Original: return [&, wsRootDir](const String &method, const String &url, WiFiClient *tcpClient, ESP8266WebServer::ContentTypeFunction contentType) {
// Can't change the 'WiFiClient' type here because that is passed in by BearSSL
return [&, wsRootDir](const String &method, const String &url, WiFiClient *tcpClient, BearSSL::ESP8266WebServerSecure::ContentTypeFunction contentType) {
(void)contentType;
WiFiClientSecure *tcpClientSecure = (WiFiClientSecure *)tcpClient; // Added
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
// Original: return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
return BearSSL::ESP8266WebServerSecure::CLIENT_REQUEST_CAN_CONTINUE;
}
// Allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients())
// Original: WEBSOCKETS_NETWORK_CLASS *newTcpClient = new WEBSOCKETS_NETWORK_CLASS(*tcpClient);
WEBSOCKETS_NETWORK_SSL_CLASS *newTcpClient = new WEBSOCKETS_NETWORK_SSL_CLASS(*tcpClientSecure);
// Then initialize a new WSclient_t (like in WebSocketsServer::handleNewClient())
WSclient_t *client = handleNewClient(newTcpClient);
if(client) {
// Give "GET <url>"
String headerLine;
headerLine.reserve(url.length() + 5);
headerLine = "GET ";
headerLine += url;
handleHeader(client, &headerLine);
}
// Tell webserver to not close but forget about this client
// Original: return ESP8266WebServer::CLIENT_IS_GIVEN;
return BearSSL::ESP8266WebServerSecure::CLIENT_IS_GIVEN;
};
}
};
#else // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
#ifndef WEBSERVER_HAS_HOOK
#error Your current Framework / Arduino core version does not support Webserver Hook Functions
#else
#error Your Hardware Platform does not support Webserver Hook Functions
#endif
#endif // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
#endif // __WEBSOCKETS4WEBSERVERSECURE_H For the BearSSL::ESP8266WebServerSecure my_web(443);
WebSockets4WebServerSecure my_wss;
void setup(void) {
// After setting up BearSSL but before calling it's begin() function
my_web.addHook(my_wss.hookForWebserver("/wss", websocket_handle_event)); // Added
my_web.begin(); // Now you can call this
} See this repo's examples for the Note that if you have basic auth enabled for the main web server, you'll probably also need to enable it separately for websockets by putting If you wanted you could also override some methods from the |
I have tried implementing your solution, GottemHams. My webserver sockets are failing to connect though. Do I need to edit/create a WebSockets4WebServerSecure.cpp files as well as .h file? |
@Joshua-Brack Do you have BearSSL in itself working? As in, can you run a web server and visit a page served from it? I'm asking because my example code doesn't actually set up BearSSL, I'm simply assuming people already have that part working at least. Otherwise:
Also no, you don't need an additional |
No problem. =] And nah the |
That fixed it! Thank you so much! |
Is anyone able to provide a working example for this, I am trying to get it working but am not entirely sure how to go about it as some links provided are now broken too |
@FallenRecruit this should be a full basic working example for the ESP side. Note though that I took some of my code from a larger project and condensed it to just web server/socket stuff, so it may not be 100% correct. :> I didn't include any of the browser-related JavaScript for interacting with websockets, because that's really a different topic altogether. I do mention the URL needed to connect to this specific example though, as well as an example for the ESP to receive and send text over the socket.
#ifndef __WEBSOCKETS4WEBSERVERSECURE_H
#define __WEBSOCKETS4WEBSERVERSECURE_H
#include <WebSocketsServer.h>
#include <ESP8266WebServerSecure.h>
// This is basically a copy of the original WebSockets4Webserver class, with additions to handle SSL =]
#if WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
class WebSockets4WebServerSecure : public WebSocketsServerCore {
public:
WebSockets4WebServerSecure(const String &origin = "", const String &protocol = "arduino") : WebSocketsServerCore(origin, protocol) {
begin();
}
// Original: ESP8266WebServer::HookFunction hookForWebserver(const String &wsRootDir, WebSocketServerEvent event) {
BearSSL::ESP8266WebServerSecure::HookFunction hookForWebserver(const String &wsRootDir, WebSocketServerEvent event) {
onEvent(event);
// Original: return [&, wsRootDir](const String &method, const String &url, WiFiClient *tcpClient, ESP8266WebServer::ContentTypeFunction contentType) {
// Can't change the 'WiFiClient' type here because that is passed in by BearSSL
return [&, wsRootDir](const String &method, const String &url, WiFiClient *tcpClient, BearSSL::ESP8266WebServerSecure::ContentTypeFunction contentType) {
(void)contentType;
WiFiClientSecure *tcpClientSecure = (WiFiClientSecure *)tcpClient; // Added
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
// Original: return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
return BearSSL::ESP8266WebServerSecure::CLIENT_REQUEST_CAN_CONTINUE;
}
// Allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients())
// Original: WEBSOCKETS_NETWORK_CLASS *newTcpClient = new WEBSOCKETS_NETWORK_CLASS(*tcpClient);
WEBSOCKETS_NETWORK_SSL_CLASS *newTcpClient = new WEBSOCKETS_NETWORK_SSL_CLASS(*tcpClientSecure);
// Then initialize a new WSclient_t (like in WebSocketsServer::handleNewClient())
WSclient_t *client = handleNewClient(newTcpClient);
if(client) {
// Give "GET <url>"
String headerLine;
headerLine.reserve(url.length() + 5);
headerLine = "GET ";
headerLine += url;
handleHeader(client, &headerLine);
}
// Tell webserver to not close but forget about this client
// Original: return ESP8266WebServer::CLIENT_IS_GIVEN;
return BearSSL::ESP8266WebServerSecure::CLIENT_IS_GIVEN;
};
}
};
#else // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
#ifndef WEBSERVER_HAS_HOOK
#error Your current Framework / Arduino core version does not support Webserver Hook Functions
#else
#error Your Hardware Platform does not support Webserver Hook Functions
#endif
#endif // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
#endif // __WEBSOCKETS4WEBSERVERSECURE_H
#include <ESP8266WiFi.h>
//#include <ESP8266WebServerSecure.h> // Not necessary because it's included by WebSockets4WebServerSecure.h
//#include <WebSockets4WebServer.h> // Different version is implemented by WebSockets4WebServerSecure.h
#include "WebSockets4WebServerSecure.h"
// Using PROGMEM here to (better) accomodate large keys/certs, leaving more SRAM for actual processing (since PROGMEM makes it get stored in flash)
// All of these are simply in PEM format
static const char tls_key[] PROGMEM = R"EOF(
-----BEGIN PRIVATE KEY-----
.........PUT YOUR PRIVATE KEY HERE.........
-----END PRIVATE KEY-----
)EOF";
static const char tls_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
.........PUT YOUR ENDPOINT CERTIFICATE HERE.........
-----END CERTIFICATE-----
)EOF";
// Depending on certificate setup, you may not need to pass along any intermediate or root cert, otherwise the format is the same
// If you do need these, then remember to uncomment the relevant lines in setup_http() too
/*static const char tls_cert_intermediate[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
.........PUT YOUR INTERMEDIATE CA CERTIFICATE HERE.........
-----END CERTIFICATE-----
)EOF";
static const char tls_cert_root[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
.........PUT YOUR ROOT CA CERTIFICATE HERE.........
-----END CERTIFICATE-----
)EOF";*/
BearSSL::ESP8266WebServerSecure myweb_server(443);
WebSockets4WebServerSecure mywebsocket_server;
void setup(void) {
Serial.begin(115200);
setup_wifi();
setup_http();
}
void loop(void) {
myweb_server.handleClient();
mywebsocket_server.loop();
}
void setup_wifi(void) {
unsigned short int i;
WiFi.mode(WIFI_STA);
WiFi.setHostname("espwebsocket"); // Not really necessary but I prefer explicit hostnames
WiFi.begin("wifissid", "supersecretpassword");
Serial.printf("Connecting to WiFi");
for(i = 0; i < 5 && WiFi.status() != WL_CONNECTED; i++) {
Serial.printf(".");
delay(1000);
}
Serial.printf("\n");
if(WiFi.status() != WL_CONNECTED) {
// Do something here to abort further execution (send an error somehow and shut down, go into deep sleep and retry X minutes later, etc)
}
}
void setup_http(void) {
BearSSL::X509List *tls_chain;
tls_chain = new BearSSL::X509List(tls_cert);
//tls_chain->append(tls_cert_intermediate);
//tls_chain->append(tls_cert_root);
myweb_server.getServer().setRSACert(tls_chain, new BearSSL::PrivateKey(tls_key));
// Register some pages
myweb_server.on("/", http_handle_root);
myweb_server.onNotFound(http_handle_404);
// And here is how we make the websocket pass through the actual server, so we can (re)use SSL and all that
myweb_server.addHook(mywebsocket_server.hookForWebserver("/socket", websocket_handle_event));
myweb_server.begin();
}
void http_handle_root(void) {
myweb_server.sendHeader("Cache-Control", "no-cache");
myweb_server.sendHeader("Connection", "close");
myweb_server.send(200, "text/html", "<!DOCTYPE html><html><body>Some HTML page where you can interact with the websocket</body></html>");
// The above HTML should contain some JavaScript for connecting to the socket, like this: new WebSocket('wss://' + document.location.host + '/socket');
// The '/socket' at the end corresponds to the value from the myweb_server.addHook() call
}
void http_handle_404(void) {
myweb_server.sendHeader("Cache-Control", "no-cache");
myweb_server.sendHeader("Connection", "close");
myweb_server.send(404, "text/html", "<!DOCTYPE html><html><body>Some HTML page indicating a 404 error</body></html>");
}
void websocket_handle_event(uint8_t client_id, WStype_t event, uint8_t *payload, size_t length) {
char *payload_chr;
IPAddress client_ip;
switch(event) {
case WStype_DISCONNECTED:
// Maybe log a message or something if you want
break;
case WStype_CONNECTED:
client_ip = mywebsocket_server.remoteIP(client_id);
// Maybe log a message or something if you want, to get the IP as string you can just printf("%d.%d.%d.%d", client_ip[0], client_ip[1], client_ip[2], client_ip[3])
break;
case WStype_TEXT:
if(!length) {
websocket_send_response(client_id, "Received an empty payload");
break;
}
payload_chr = (char *)payload; // Should be no problem since 'payload' is uint8_t ;]
websocket_send_response(client_id, "Received data: %s", payload_chr);
break;
case WStype_PING:
case WStype_PONG:
// Don't need to do anything, should be handled automatically afaik
break;
default:
// Maybe log a message or something if you want
break;
}
}
void websocket_send_response(uint8_t client_id, const char *pattern, ...) {
char buf[384]; // Anything too long will simply be truncated to fit
va_list vl;
va_start(vl, pattern);
vsnprintf(buf, sizeof(buf), pattern, vl);
va_end(vl);
mywebsocket_server.sendTXT(client_id, buf);
} |
@GottemHams Can you help us with implementation for your code in esp32? |
I don't have an ESP32, does the code not work as-is? If there are problems with the library on its own when used on an ESP32, then I think that should probably be a separate issue. |
@GottemHams the bearssl not supported in esp32, try just compile your code using esp32 as target board |
It looks like there's no drop-in replacement for |
will wss (http://tools.ietf.org/html/rfc6455#section-3) be supported later ?
kindly guide
thanks
The text was updated successfully, but these errors were encountered: