nodemcu / nodemcu-firmware

Lua based interactive firmware for ESP8266, ESP8285 and ESP32

Home Page:https://nodemcu.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

secure websocket "wss://" not working

lyakh opened this issue · comments

Problem description

Both WebSocket connections to wss://echo.websocket.org and to ws://echo.websocket.org should work, whereas only the latter is working and the former isn't, error code -99.

Test code

Not a complete example, but the essence:

ws = websocket.createClient()
ws:on("close", function(_, status)
	ws_closed = true
	print("closed for", status)
	ws = nil
	end)
ws:on("connection", ws_connect)
ws:on("receive", ws_receive)
ws:config({})

ws:connect("wss://echo.websocket.org/")

NodeMCU startup banner

NodeMCU 3.0.0.0 built on nodemcu-build.com provided by frightanic.com
branch: release
commit: 4f67927
release: 3.0-release_20201107
release DTS: 202011071523
SSL: true
build type: float
LFS: 0x0 bytes total capacity
modules: adc,file,gpio,http,net,node,sjson,tmr,uart,websocket,wifi,tls
build 2020-12-09 22:25 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)

Hardware

NodeMCU ESP8266

Update: a naive socat test per

socat openssl-listen:443,reuseaddr,cert=/tmp/test.pem TCP4:echo.websocket.org:443

returned an error:

peer did not return a certificate

Please build a debug firmware, turn on tls debug with tls.setDebug(2), and paste the full transcript of your example program.

I am suspicious that your socat test is not doing the right thing. TCP4:...:443 seems unlikely to be right, especially in combination with openssl-listen: you're going to locally decapsulate SSL and shove the plaintext byte stream at an endpoint expecting SSL. Moreover, you don't say which peer it was that failed to return a certificate, but I think it is the openssl-listen bit. You should add ,verify=0 to that half of the command. You've not, I think, given socat a key to work with, either, which is going to be tricky. I'd be more curious to know about something like socat openssl-listen:443,reuseaddr,cert=/tmp/test.crt,key=/tmp/test.key,verify=0 STDIO, I think?

@mwf A debug firmware build is running. In the meantime I tried some other options, in the direction that you suggested, although why did you suggest STDIO? I want traffic to go to the websocket echo service? I captured socat traffic with wireshark and I see a "Change Cipher Spec" request from the NodeMCU to which socat then replies with "Handshake Failure." Socat debugging says, that SSL_accept(3) returned an error:

E SSL_accept(): error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate

@mwf I just managed to re-launch a debug build (the first one never completed) and here's the debug log:

websocket_createClient
websocketclient_on
close
websocketclient_on
connection
websocketclient_on
receive
websocketclient_config is called.
websocketclient_connect is called.
ws_connect called
secure protocol = 1
hostname = my.webhookrelay.com
port = 443
path = /v1/socket
DNS pending
dns_callback
secure connecting 
DNS found my.webhookrelay.com 104.155.59.108 
client handshake start.
client handshake failed!
Reason:[-0x7780]
error_callback 9
disconnect_callback
ws->hostname 1073681864
ws->path 1073682160
 conn 1073684480
freeing conn1 
websocketclient_onCloseCallback
closed for      -91

@mwf A debug firmware build is running. In the meantime I tried some other options, in the direction that you suggested, although why did you suggest STDIO?

Because seeing the plaintext might have been informative, and your stated command line was not doing the right thing.

I captured socat traffic with wireshark and I see a "Change Cipher Spec" request from the NodeMCU to which socat then replies with "Handshake Failure." Socat debugging says, that SSL_accept(3) returned an error:

E SSL_accept(): error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate

I believe that is because socat is expecting your NodeMCU device to send a client certificate, which is why I suggested verify=0.

@mwf I just managed to re-launch a debug build (the first one never completed) and here's the debug log:

This transcript does not appear as if you had run tls.setDebug(2). In any case...

client handshake failed!
Reason:[-0x7780]
error_callback 9
disconnect_callback
ws->hostname 1073681864
ws->path 1073682160
 conn 1073684480
freeing conn1 
websocketclient_onCloseCallback
closed for      -91

0x7780 is MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE. my.webhookrelay.com is not happy about some part of the TLS bringup; it's hard to say what without more information. You'll probably have to turn up TLS debugging or read the TLS handshake packets in wireshark quite thoroughly.

As far as I can tell from here, which is, admittedly, not very far, NodeMCU's TLS stack is doing the right thing.

@nwf Sorry, here comes TLS debugging turned on:

hostname = my.webhookrelay.com
port = 443
path = /v1/socket
DNS pending
dns_callback
secure connecting 
DNS found my.webhookrelay.com 104.155.59.108 
client handshake start.
TLS<2> (heap=13760): ssl_tls.c:8084 => handshake
TLS<2> (heap=13760): ssl_cli.c:3510 client state: 0
TLS<2> (heap=13760): ssl_tls.c:2755 => flush output
TLS<2> (heap=13760): ssl_tls.c:2767 <= flush output
TLS<2> (heap=13760): ssl_cli.c:3510 client state: 1
TLS<2> (heap=13760): ssl_tls.c:2755 => flush output
TLS<2> (heap=13760): ssl_tls.c:2767 <= flush output
TLS<2> (heap=13760): ssl_cli.c:774 => write client hello
TLS<2> (heap=13760): ssl_tls.c:3184 => write handshake message
TLS<2> (heap=13760): ssl_tls.c:3343 => write record
TLS<2> (heap=13760): ssl_tls.c:2755 => flush output
TLS<2> (heap=13760): ssl_tls.c:2774 message length: 203, out_left: 203
TLS<2> (heap=12144): ssl_tls.c:2779 ssl->f_send() returned 203 (-0xffffff35)
TLS<2> (heap=12144): ssl_tls.c:2807 <= flush output
TLS<2> (heap=12144): ssl_tls.c:3476 <= write record
TLS<2> (heap=12144): ssl_tls.c:3320 <= write handshake message
TLS<2> (heap=12144): ssl_cli.c:1106 <= write client hello
TLS<2> (heap=12144): ssl_cli.c:3510 client state: 2
TLS<2> (heap=12144): ssl_tls.c:2755 => flush output
TLS<2> (heap=12144): ssl_tls.c:2767 <= flush output
TLS<2> (heap=12144): ssl_cli.c:1499 => parse server hello
TLS<2> (heap=12144): ssl_tls.c:4311 => read record
TLS<2> (heap=12144): ssl_tls.c:2536 => fetch input
TLS<2> (heap=12144): ssl_tls.c:2697 in_left: 0, nb_want: 5
TLS<2> (heap=12144): ssl_tls.c:2721 in_left: 0, nb_want: 5
TLS<2> (heap=12144): ssl_tls.c:8094 <= handshake
TLS<2> (heap=13752): ssl_tls.c:8084 => handshake
TLS<2> (heap=13752): ssl_cli.c:3510 client state: 2
TLS<2> (heap=13752): ssl_tls.c:2755 => flush output
TLS<2> (heap=13752): ssl_tls.c:2767 <= flush output
TLS<2> (heap=13752): ssl_cli.c:1499 => parse server hello
TLS<2> (heap=13752): ssl_tls.c:4311 => read record
TLS<2> (heap=13752): ssl_tls.c:2536 => fetch input
TLS<2> (heap=13752): ssl_tls.c:2697 in_left: 0, nb_want: 5
TLS<2> (heap=13752): ssl_tls.c:2721 in_left: 0, nb_want: 5
TLS<2> (heap=13752): ssl_tls.c:2722 ssl->f_recv(_timeout)() returned 5 (-0xfffffffb)
TLS<2> (heap=13752): ssl_tls.c:2742 <= fetch input
TLS<2> (heap=13752): ssl_tls.c:2536 => fetch input
TLS<2> (heap=13752): ssl_tls.c:2697 in_left: 5, nb_want: 7
TLS<2> (heap=13752): ssl_tls.c:2721 in_left: 5, nb_want: 7
TLS<2> (heap=13752): ssl_tls.c:2722 ssl->f_recv(_timeout)() returned 2 (-0xfffffffe)
TLS<2> (heap=13752): ssl_tls.c:2742 <= fetch input
TLS<2> (heap=13752): ssl_tls.c:5170 got an alert message, type: [2:80]
TLS<1> (heap=13752): ssl_tls.c:5178 is a fatal alert message (msg 80)
TLS<1> (heap=13752): ssl_tls.c:4369 mbedtls_ssl_handle_message_type() returned -30592 (-0x7780)
TLS<1> (heap=13752): ssl_cli.c:1506 mbedtls_ssl_read_record() returned -30592 (-0x7780)
TLS<2> (heap=13752): ssl_tls.c:8094 <= handshake
client handshake failed!
Reason:[-0x7780]

Also sorry for not explaining properly: these two logs aren't talking to socat or to apache proxy, they're talking to the target server (my.webhookrelay.com) directly. BTW, I also tried with an apache proxy, talking with encryption turned off to it and encrypting the other side of the proxy. That seems to work when talking to echo.websocket.org but that fails too when talking to my.webhookrelay.com

IIUC error 80 / 0x50 is MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.