SSL/TLS server on ESP crashes when client disconnects

Npt
Posts: 16
Joined: Thu Sep 03, 2015 2:21 pm

SSL/TLS server on ESP crashes when client disconnects

Postby Npt » Wed Sep 16, 2015 6:40 pm

Update: Please see post further down (viewtopic.php?f=7&t=1114#p3801) for an updated error description and some example code for reproducing the crash. The problem persists in SDK 1.4.0.
---

Hi everyone!

I'm trying to write a very simple SSL/TLS server. I can connect to it and send and receive data, but when the client closes the connection, discon_cb is not called. Instead I get the following message on the UART: "server's data invalid protocol"
Can anyone tell me what this message means and how I can fix it? Any help would be appreciated.

Here's some more details (sorry it's a bit long):
I'm trying to put a very simple HTTPS server together. For now, all it does is set up a listener, read the incoming data and send a minimal HTTP reply (something like "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-type: text/html\r\nContent-length: 30\r\n\r\n<html><body>Test</body></html>"). Everything works fine when SSL is off.

Now I turn on SSL by doing the following:
  • Change all calls of espconn_send to espconn_secure_send.
  • Replace espconn_accept with:

    Code: Select all

    espconn_secure_set_size(0x02, 8192);
    espconn_secure_ca_disable(0x02); // Not sure if this is needed, but it shouldn't hurt, right? I'm assuming
                                     // this means "Don't try to authenicate the client".
    espconn_secure_accept(&listenConn);
  • Create a key and a certificate for the ESP, convert it into cert.h and private_key.h as described in the documentation, and include those headers. (By the way, this is a bit odd. I think there should be an API call to set the cert&key. Maybe one which takes a flash sector like espconn_secure_ca_enable does?) I tried a 2048 bit key but that made the ESP crash right away. So I chose a 1024 bit one instead. I pretty much followed the SSL guide PDF except I signed the certificate with my existing CA rather than a newly created one.

This is what happens when I run the thing:
  • After espconn_secure_accept I have 36880 free bytes on the heap.
  • Connect from a client (Firefox in my case).
  • UART prints "server handshake start." and "server handshake ok!"
  • connect_cb is called. 17376 free heap. Everything seems fine, IP address etc is correct.
  • recv_cb is called. 16976 free heap. Still everything's fine, the received data is exactly what the client sent.
  • Calling espconn_secure_send with the HTTP response.
  • sent_cb is called. 13712 free heap.
  • UART prints "server's data invalid protocol"

The client does receive the data correctly but after that nothing happens. In particular, discon_cb is not called. The ESP seems to hang in a weird limbo state. It does occasionally respond to data sent via UART, but any major operation will make it crash. I assume memory is leaking both internally and in my code since I don't get the discon_cb to free it up.

Another thing I've tried is using sslscan on the ESP. I'm getting this:
Testing SSL server Node001 on port 443

Supported Server Cipher(s):
Failed SSLv3 256 bits ECDHE-RSA-AES256-GCM-SHA384
Failed SSLv3 256 bits ECDHE-ECDSA-AES256-GCM-SHA384

and then the ESP crashes.
Last edited by Npt on Fri Sep 25, 2015 11:45 pm, edited 4 times in total.

hdrut
Posts: 25
Joined: Fri Feb 13, 2015 11:02 am
Location: Argentina

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby hdrut » Wed Sep 16, 2015 11:16 pm

I am getting the same error. If server closes de connection then no problems. However , when is the client who closes it, I get
"server's data invalid protocol".

I tried using more memory, like 4096 and even 8192, but nothing changes. I am not using CA verification.
Any idea what can be wrong?


Thks in advance.

Npt
Posts: 16
Joined: Thu Sep 03, 2015 2:21 pm

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby Npt » Wed Sep 16, 2015 11:51 pm

@hdrut: That's interesting to hear. I send the HTTP header "Connection: close" to make the client close the connection. That's mostly because you're not allowed to call espconn_secure_disconnect from within a callback and I wanted to avoid using a task just for this. Anyway, the stability of the system shouldn't depend on the client not prematurely shutting down the connection.

There's another strange thing I just discovered. When debugging the non-SSL server, I used telnet to manually send requests to the ESP, so I thought I'd do the same with SSL. I dicovered that you can do that with openssl s_client. I tested it on several HTTPS servers on the internet and it worked. However, with the ESP the connection shuts down after about a second which is not even enough time for me to type a GET request. Not sure what causes this, it might just be me not understanding how openssl works. Surely there can't be such a short timeout, right? Normally, that is to say without SSL, the ESP kills idle connections after ~10s.
Still, that little experiment proved that all the certificate and encryption stuff works fine. Yet it brings me no closer to a working HTTPS server.

ESP_Faye
Posts: 1646
Joined: Mon Oct 27, 2014 11:08 am

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby ESP_Faye » Thu Sep 17, 2015 5:12 pm

Hi,

Here is an example of SSL connection http://bbs.espressif.com/viewtopic.php?f=31&t=389

"server's data invalid protocol" means that the data sent from SSL server seems to be a invalid protocol.

1. You could try to call espconn_secure_set_size to set the SSL buffer to be 8KB, maybe the buffer is not large enough for a whole SSL packet from your SSL server. If the SSL data size is larger than 8KB, ESP8266 can not support it because of the limitation of RAM.

2. You need to check the packets sent by your SSL server, maybe it ends the SSL connection with ESP8266.

Npt
Posts: 16
Joined: Thu Sep 03, 2015 2:21 pm

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby Npt » Thu Sep 17, 2015 5:21 pm

I think we might have a misunderstanding here. In my case the ESP is the server, whereas some other computer (with Firefox or some other software) acts as the client.
I have set the SSL buffer to 8k and that seems to be enough since I can exchange data in both directions without any problem. The problem arises when the client (not the ESP) closes the connection. Then the UART prints "server's data invalid protocol" which is strange since the ESP itself is the server.

hdrut
Posts: 25
Joined: Fri Feb 13, 2015 11:02 am
Location: Argentina

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby hdrut » Thu Sep 17, 2015 7:36 pm

Yes, in my case too, ESP is the server, while the client is an android device.
Tested with openssl too, got the same error.

Please check this error, because it may be a bug.

Thank you for your support!

Npt
Posts: 16
Joined: Thu Sep 03, 2015 2:21 pm

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby Npt » Tue Sep 22, 2015 4:17 pm

Today I had some time to take another look at the ESP and this problem in particular. It seems that moving to 1.4.0 has not fixed things. I wrote a (somewhat) minimal example, in case anyone wants to replicate the problem.

  1. Run makecert.sh to create a CA and a certificate for the server (i.e. the ESP). Import myca.crt in your browser.
  2. Compile user_main.c together with the two .h files that were generated in the last step and a user_config.h where you provide your WiFi credentials.
  3. Flash the ESP, run it, and make sure that in your network it is accessible via the hostname "myesp". This might be bit tricky depending on your router or other hardware, but in order for the certificate to pass, the ESP needs to be addressed via the hostname that the certificate was issued for.
  4. Open https://myesp/ in your browser.

Here's what happens on my machine:
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 2
cnt

connected with <SSID>, channel 1
ip:192.168.2.200,mask:255.255.255.0,gw:192.168.2.1
WiFi is up, starting HTTPS server...
HTTPS server started.
pm open phy_2,type:2 0 0
server handshake start.
server handshake ok!
Client connected from 192.168.2.105:41708.
Received 292 bytes from client:
--begin data--
GET / HTTP/1.1
Host: myesp
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive


--end data--
Sent data to client.
server's data invalid protocol
3ffefff0 already freed
3fff0010 already freed
Fatal exception 29(StoreProhibitedCause):
epc1=0x4000df98, epc2=0x00000000, epc3=0x00000000, excvaddr=0x0000000c, depc=0x00000000

The browser does receive the HTML page correctly and without showing security warnings, so both authentication and encryption work fine. But neither discon_cb nor recon_cb is called and instead the ESP crashes.

Here's my code:

Code: Select all

#include"ets_sys.h"
#include"osapi.h"
#include"gpio.h"
#include"os_type.h"
#include"user_interface.h"
#include"mem.h"
#include"espconn.h"
#include"driver/uart.h"

// Make your own user_config.h
#include"user_config.h"   // defines WIFI_SSID and WIFI_PSWD

// These files are created by makecert.sh
#include"cert.h"      // defines myesp_crt_DER and myesp_crt_DER_len
#include"private_key.h"   // defines myesp_key_DER and myesp_key_DER_len

// listener connection data
struct espconn   listenConn;
esp_tcp         listenConnTcp;

// standard HTTP reply
uint8_t* reply = "HTTP/1.1 200 OK\r\n"
      "Connection: close\r\n"   // make the client (browser) close the connection after receipt
      "Content-type: text/html\r\n"
      "Content-length: 30\r\n\r\n"
      "<html><body>Test</body></html>\0";

void ICACHE_FLASH_ATTR
onRecv(void* arg, char* data, unsigned short length)
{
   os_printf("Received %d bytes from client:\n--begin data--\n", length);
   uart0_tx_buffer(data, length);
   os_printf("\n--end data--\n");
   // send reply
   struct espconn* clientConn = (struct espconn*)arg;
   espconn_secure_send(clientConn, reply, os_strlen(reply));
   /*
    * (Under normal circumstances you should check the received data first,
    * making sure in particular that the complete HTTP request has been
    * received. Most of the time, it will arrive in one piece, but there's
    * no guarantee. It could be split up into multiple callbacks. But since
    * this is a minimal example, we'll ignore such things and just send the
    * reply. Just keep in mind that this might result in multiple responses,
    * especially when the client is not a browser but a slowly typing human
    * on an SSL console.)
    */
}

void ICACHE_FLASH_ATTR
onSent(void* arg)
{
   os_printf("Sent data to client.\n");
}

void ICACHE_FLASH_ATTR
onError(void* arg, int8_t err)
{
   os_printf("Connection error: %d\n", err);
}

void ICACHE_FLASH_ATTR
onDisconn(void* arg)
{
   os_printf("Client disconnected.\n");
}

void ICACHE_FLASH_ATTR
onClientConnected(void* arg)
{
   struct espconn* clientConn = (struct espconn*)arg;
   os_printf("Client connected from %d.%d.%d.%d:%d.\n",
         clientConn->proto.tcp->remote_ip[0],
         clientConn->proto.tcp->remote_ip[1],
         clientConn->proto.tcp->remote_ip[2],
         clientConn->proto.tcp->remote_ip[3],
         clientConn->proto.tcp->remote_port);
   // register callback functions
   espconn_regist_recvcb(clientConn, onRecv);
   espconn_regist_sentcb(clientConn, onSent);
   espconn_regist_reconcb(clientConn, onError);
   espconn_regist_disconcb(clientConn, onDisconn);
}

void ICACHE_FLASH_ATTR
onWifiEvent(System_Event_t *event)
{
   if(event->event != EVENT_STAMODE_CONNECTED)
      return;
   os_printf("WiFi is up, starting HTTPS server...\n");
   // set listener configuration and register callback
   listenConn.type = ESPCONN_TCP;
   listenConn.state = ESPCONN_NONE;
   listenConn.proto.tcp = &listenConnTcp;
   listenConnTcp.local_port = 443;
   espconn_regist_connectcb(&listenConn, onClientConnected);
   // SSL configuration
   espconn_secure_set_size(0x02, 8192);   // use maximum amount of space possible
   espconn_secure_ca_disable(0x02);
   /*
    * I'm not quite sure what this function does. I'm assuming the previous
    * line turns off client authentication (which as far as I know is never
    * used in HTTPS).
    * See http://bbs.espressif.com/viewtopic.php?f=7&t=1129 for a discussion
    * on this.
    */
   // set server certificate (defined in user_config.h and cert.h)
   espconn_secure_set_default_certificate(myesp_crt_DER, myesp_crt_DER_len);
   espconn_secure_set_default_private_key(myesp_key_DER, myesp_key_DER_len);
   // start listening
   espconn_secure_accept(&listenConn);
   os_printf("HTTPS server started.\n");
}

void ICACHE_FLASH_ATTR
onInitDone()
{
   // WiFi configuration
   wifi_set_opmode(STATION_MODE);
   struct station_config config;
   strcpy(config.ssid, WIFI_SSID);               // defined in user_config.h
   strcpy(config.password, WIFI_PSWD);            // defined in user_config.h
   config.bssid_set = 0;
   wifi_station_set_config(&config);
   wifi_station_set_hostname("myesp");            // ESP's host name (matches certificate)
   // set static IP (seems more appropriate for a server)
   wifi_station_dhcpc_stop();
   struct ip_info ipInfo;
   IP4_ADDR(&ipInfo.ip, 192, 168, 2, 200);         // static IP
   IP4_ADDR(&ipInfo.netmask, 255, 255, 255, 0);   // netmask
   IP4_ADDR(&ipInfo.gw, 192, 168, 2, 1);         // gateway
   wifi_set_ip_info(STATION_IF, &ipInfo);
   ip_addr_t dns;
   IP4_ADDR(&dns, 192, 168, 2, 1);               // DNS server
   espconn_dns_setserver(1, &dns);
   // connect
   wifi_set_event_handler_cb(onWifiEvent);
   wifi_station_connect();
}

void ICACHE_FLASH_ATTR
user_init()
{
   // initialise UART
   uart_init(BIT_RATE_9600, BIT_RATE_9600);      // 9600 baud
   system_set_os_print(1);
   // register post-initialisation callback
   system_init_done_cb(onInitDone);
}


And this is how I create the certificates:

Code: Select all

#!/bin/bash
#------------------------------------------------------------------------------
# cleanup any previously created files
rm -f myca.* myesp.* cert.h private_key.h

#------------------------------------------------------------------------------
# create a CA called "myca"

# create a private key
openssl genrsa -out myca.key 1024
# create certificate
cat > myca.conf << EOF 
[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no
[ req_distinguished_name ]
C = FR
ST = IDF
L = Paris
O = MyCompany
OU = MyDept
CN = myca
EOF
openssl req -new -x509 -days 3650 -key myca.key -out myca.crt -config myca.conf
# create serial number file
echo "01" > myca.srl

#------------------------------------------------------------------------------
# create a certificate for the ESP (hostname: "myesp")

# create a private key
openssl genrsa -out myesp.key 1024
# create certificate signing request
cat > myesp.conf << EOF 
[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no
[ req_distinguished_name ]
C = FR
ST = IDF
L = Paris
O = MyCompany
OU = MyDept
CN = myesp
EOF
openssl req -new -key myesp.key -out myesp.csr -config myesp.conf
# have myca sign the certificate
openssl x509 -days 3650 -CA myca.crt -CAkey myca.key -in myesp.csr -req -out myesp.crt
# verify
openssl verify -CAfile myca.crt myesp.crt
# convert private key and certificate into DER format
openssl rsa -in myesp.key -outform DER -out myesp.key.DER
openssl x509 -in myesp.crt -outform DER -out myesp.crt.DER
# create header files
xxd -i myesp.crt.DER > cert.h
xxd -i myesp.key.DER > private_key.h
Attachments
ssl_server.zip
(2.61 KiB) Downloaded 494 times

Npt
Posts: 16
Joined: Thu Sep 03, 2015 2:21 pm

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby Npt » Fri Sep 25, 2015 12:58 am

Any chance that someone at Espressif could have a look at this? By now I'm pretty sure this is a bug in the SDK, and quite a big one as well. Please look at the code I attached to my last post. If there's anything else I can do to help you reproduce this error, let me know.

There are practically no examples on the web where someone has programmed the ESP as an SSL server, so I don't have much to go by. Still I can't see any way in which my code could be so flawed that it would cause these crashes. It doesn't seems to be a lack of memory because the crash happens after the transmission is finished.
Even if the client side does something wrong as Espressif_Faye suggested, what the ESP should do is report the error in an orderly fashion (via callback for example), not just crash. Note that a TCP connection can be closed at any time by any of the participants and only the higher level protocol may consider this an error. In any case, if clients can crash the server by closing the connection, that's a massive security risk.

hdrut
Posts: 25
Joined: Fri Feb 13, 2015 11:02 am
Location: Argentina

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby hdrut » Fri Sep 25, 2015 4:38 am

Hi Npt,


it seems to me we are the only people working on SSL.
I can confirm the crash you experience, so I also ask Espressif to please consider the issue.

By the way, something that also surprises me is the way anyone can make a connection to ESP SSL server
by using, for example:

> openssl s_client -connect 192.168.1.70:1112

No certificates are requested by server, so I don't understand the new functionality "bi-directional authentication".

What are your thoughts about this? ?

Kind regards,


Horacio

Npt
Posts: 16
Joined: Thu Sep 03, 2015 2:21 pm

Re: SSL/TLS server: what does "invalid protocol" mean?

Postby Npt » Fri Sep 25, 2015 2:03 pm

Hi Horacio,
I haven't even tried client authentication yet since I'm going for HTTPS where this is hardly ever done. Also, I think we should first get server authentication working before adding another layer of complexity. Right now, we can't even be 100% sure if we're calling the right functions as we've not had an answer here: viewtopic.php?f=7&t=1129
Thanks for pointing me to bi-directional authentication which lead me to this page: viewtopic.php?f=51&t=1025 I hadn't discovered that one yet. Unfortunately there's no code that shows how to actually use these certificates on the ESP. I'm assuming they are for when the ESP is the client, because as a server my device can't even get a successful handshake with 2048 bit certs.

@Espressif: We could really use some help here! Please, could you post a working example of the ESP running as an SSL server? Or look at the code I posted above?

Who is online

Users browsing this forum: No registered users and 84 guests