From 5ceb4db38a4ada1ea49eb84c327ebc8991113f74 Mon Sep 17 00:00:00 2001 From: Bob Mooij Date: Wed, 15 Apr 2020 17:31:08 +0200 Subject: [PATCH 1/8] Init server implementation --- src/AsyncTCP.cpp | 303 +++++++++++++++++++++++++++++++++++++++++++++- src/AsyncTCP.h | 21 +++- src/tcp_mbedtls.c | 59 ++++++++- src/tcp_mbedtls.h | 3 +- 4 files changed, 376 insertions(+), 10 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 169c098a..6ad8d348 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -662,7 +662,7 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other){ _handshake_done = false; tcp_ssl_arg(_pcb, this); tcp_ssl_data(_pcb, &_s_data); - tcp_ssl_handshake(_pcb, &_s_handshake); + tcp_ssl_handshake(_pcb, this, &_s_handshake); tcp_ssl_err(_pcb, &_s_ssl_error); } else { _pcb_secure = false; @@ -775,6 +775,7 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){ tcp_sent(pcb, &_tcp_sent); tcp_poll(pcb, &_tcp_poll, 1); //_tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); + log_d("_tcp_connect"); _tcp_connect(pcb, _closed_slot, &addr, port,(tcp_connected_fn)&_tcp_connected); return true; } @@ -1000,7 +1001,7 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ } tcp_ssl_data(_pcb, &_s_data); - tcp_ssl_handshake(_pcb, &_s_handshake); + tcp_ssl_handshake(_pcb, this, &_s_handshake); tcp_ssl_err(_pcb, &_s_ssl_error); } #endif // ASYNC_TCP_SSL_ENABLED @@ -1091,6 +1092,7 @@ int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { } int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { + log_d("_recv_recv_recv_recv_recv_recv_recv"); while(pb != NULL) { _rx_last_packet = millis(); pbuf *nxt = pb->next; @@ -1462,6 +1464,9 @@ AsyncServer::AsyncServer(IPAddress addr, uint16_t port) , _pcb(0) , _connect_cb(0) , _connect_cb_arg(0) +#if ASYNC_TCP_SSL_ENABLED +, _pcb_secure(false) +#endif // ASYNC_TCP_SSL_ENABLED {} AsyncServer::AsyncServer(uint16_t port) @@ -1471,6 +1476,9 @@ AsyncServer::AsyncServer(uint16_t port) , _pcb(0) , _connect_cb(0) , _connect_cb_arg(0) +#if ASYNC_TCP_SSL_ENABLED +, _pcb_secure(false) +#endif // ASYNC_TCP_SSL_ENABLED {} AsyncServer::~AsyncServer(){ @@ -1534,10 +1542,16 @@ void AsyncServer::end(){ int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ //ets_printf("+A: 0x%08x\n", pcb); if(_connect_cb){ + log_d("Create AsyncClient"); AsyncClient *c = new AsyncClient(pcb); - if(c){ + tcp_ssl_new_server_client(pcb, c, &ssl, &conf); + if (c) { c->setNoDelay(_noDelay); + c->_pcb_secure = true; + c->_handshake_done = false; return _tcp_accept(this, c); + } else if (c) { + delete c; } } if(tcp_close(pcb) != ERR_OK){ @@ -1547,8 +1561,20 @@ int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ return ERR_OK; } +struct BlaBla { + AsyncClient* cllient; + AsyncServer* server; +}; + int8_t AsyncServer::_accepted(AsyncClient* client){ - if(_connect_cb){ + if (_pcb_secure) { + BlaBla *b = new BlaBla { + client, this + }; + tcp_ssl_data(client->pcb(), &AsyncClient::_s_data); + tcp_ssl_err(client->pcb(), &AsyncClient::_s_ssl_error); + tcp_ssl_handshake(client->pcb(), b, &_s_handshake); + } else if(_connect_cb){ _connect_cb(_connect_cb_arg, client); } return ERR_OK; @@ -1569,6 +1595,14 @@ uint8_t AsyncServer::status(){ return _pcb->state; } +void AsyncServer::_handshake(AsyncClient* client){ + log_d("handshake completed"); + client->_handshake_done = true; + if(_connect_cb){ + _connect_cb(_connect_cb_arg, client); + } +} + int8_t AsyncServer::_s_accept(void * arg, tcp_pcb * pcb, int8_t err){ return reinterpret_cast(arg)->_accept(pcb, err); } @@ -1576,3 +1610,264 @@ int8_t AsyncServer::_s_accept(void * arg, tcp_pcb * pcb, int8_t err){ int8_t AsyncServer::_s_accepted(void *arg, AsyncClient* client){ return reinterpret_cast(arg)->_accepted(client); } + +void AsyncServer::_s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl){ + BlaBla *b = reinterpret_cast(arg); + b->server->_handshake(b->cllient); + delete b; +} + +static int handle_ssl_error(int err) { + if(err == -30848){ + return err; + } +#ifdef MBEDTLS_ERROR_C + char error_buf[100]; + mbedtls_strerror(err, error_buf, 100); + log_e("%s\n", error_buf); +#endif + log_e("MbedTLS message code: %d\n", err); + return err; +} + +#define HTTP_RESPONSE \ + "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \ + "

mbed TLS Test Server

\r\n" \ + "

Successful connection using: %s

\r\n" + +void AsyncServer::beginSecure(const char *cert, const char *private_key_file, const char *password) { + _pcb_secure = true; + + mbedtls_net_init( &listen_fd ); + mbedtls_net_init( &client_fd ); + mbedtls_ssl_init( &ssl ); + mbedtls_ssl_config_init( &conf ); + mbedtls_x509_crt_init( &srvcert ); + mbedtls_pk_init( &pkey ); + mbedtls_entropy_init( &entropy ); + mbedtls_ctr_drbg_init( &ctr_drbg ); + + /* + * 1. Load the certificates and private RSA key + */ + log_d( "Loading the server cert. and key..." ); + + /* + * This demonstration program uses embedded test certificates. + * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the + * server and CA certificates, as well as mbedtls_pk_parse_keyfile(). + */ + const char* mbedtls_test_srv_crt = cert; + size_t mbedtls_test_srv_crt_len = strlen(cert) + 1; + int ret, len; + ret = mbedtls_x509_crt_parse( &srvcert, (const unsigned char *) mbedtls_test_srv_crt, mbedtls_test_srv_crt_len ); + + if( ret != 0 ) + { + log_e( " failed\n ! mbedtls_x509_crt_parse returned %d", ret ); + handle_ssl_error(ret); + end(); return; // TODO: clear stugg + } + + const char* mbedtls_test_srv_key = private_key_file; + size_t mbedtls_test_srv_key_len = strlen(private_key_file) + 1; + + ret = mbedtls_pk_parse_key( &pkey, (const unsigned char *) mbedtls_test_srv_key, + mbedtls_test_srv_key_len, NULL, 0 ); + if( ret != 0 ) + { + log_e( " failed\n ! mbedtls_pk_parse_key returned %d", ret ); + handle_ssl_error(ret); + end(); return; // TODO: clear stugg + } + log_d("ok"); + + /* + * 3. Seed the RNG + */ + log_d( " . Seeding the random number generator..." ); + const char *pers = "dtls_server"; + + if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char *) pers, + strlen( pers ) ) ) != 0 ) + { + log_d( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret ); + end(); return; // TODO: clear stugg + } + log_d("ok"); + + /* + * 4. Setup stuff + */ + log_d( " . Setting up the SSL data..." ); + + if( ( ret = mbedtls_ssl_config_defaults( &conf, + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) + { + log_d( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); + end(); return; // TODO: clear stugg + } + + mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); + + + mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL ); + if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 ) + { + log_d( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret ); + end(); return; // TODO: clear stugg + } + + if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) + { + log_d( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); + end(); return; // TODO: clear stugg + } + + log_d( " ok\n" ); + + begin(); + return; +/********************************************************? + + /* + * 2. Setup the "listening" TCP socket + */ + log_d( " . Bind on tcp/*/443 ..." ); + if( ( ret = mbedtls_net_bind( &listen_fd, NULL, "443", MBEDTLS_NET_PROTO_TCP ) ) != 0 ) + { + printf( " failed\n ! mbedtls_net_bind returned %d\n\n", ret ); + handle_ssl_error(ret); + end(); return; // TODO: clear stugg + } + + log_d("ok"); +reset: + mbedtls_net_free( &client_fd ); + mbedtls_ssl_session_reset( &ssl ); + + /* + * 3. Wait until a client connects + */ + log_d( " . Waiting for a remote connection ..." ); + + if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd, NULL, 0, NULL ) ) != 0 ) + { + log_d( " failed\n ! mbedtls_net_accept returned %d\n\n", ret ); + end(); return; // TODO: clear stugg + } + + mbedtls_ssl_set_bio( &ssl, &client_fd, + mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout ); + + log_d( " ok\n" ); + + /* + * 5. Handshake + */ + log_d( " . Performing the SSL/TLS handshake..." ); + + while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + log_d( " failed\n ! mbedtls_ssl_handshake returned %d\n\n", ret ); + goto reset; + // end(); return; // TODO: clear stugg + } + } + + log_d( " ok\n" ); + + /* + * 6. Read the HTTP Request + */ + log_d( " < Read from client:" ); + unsigned char buf[1024]; + do + { + len = sizeof( buf ) - 1; + memset( buf, 0, sizeof( buf ) ); + ret = mbedtls_ssl_read( &ssl, buf, len ); + + if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ) + continue; + + if( ret <= 0 ) + { + switch( ret ) + { + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + log_d( " connection was closed gracefully\n" ); + break; + + case MBEDTLS_ERR_NET_CONN_RESET: + log_d( " connection was reset by peer\n" ); + break; + + default: + log_d( " mbedtls_ssl_read returned -0x%x\n", -ret ); + break; + } + + break; + } + + len = ret; + log_d( " %d bytes read\n\n%s", len, (char *) buf ); + + if( ret > 0 ) + break; + } + while( 1 ); + + + + + /* + * 7. Write the 200 Response + */ + log_d( " > Write to client:" ); + + len = sprintf( (char *) buf, HTTP_RESPONSE, + mbedtls_ssl_get_ciphersuite( &ssl ) ); + + while( ( ret = mbedtls_ssl_write( &ssl, buf, len ) ) <= 0 ) + { + if( ret == MBEDTLS_ERR_NET_CONN_RESET ) + { + log_d( " failed\n ! peer closed the connection\n\n" ); + goto reset; + } + + if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + log_d( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); + end(); return; // TODO: clear stugg + } + } + + len = ret; + log_d( " %d bytes written\n\n%s\n", len, (char *) buf ); + + log_d( " . Closing the connection..." ); + + while( ( ret = mbedtls_ssl_close_notify( &ssl ) ) < 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + log_d( " failed\n ! mbedtls_ssl_close_notify returned %d\n\n", ret ); + goto reset; + } + } + + log_d( " ok\n" ); + + ret = 0; + goto reset; + +} \ No newline at end of file diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 48d9b68a..863fdce2 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -58,8 +58,12 @@ typedef std::function AcTimeoutHandler struct tcp_pcb; struct ip_addr; +class AsyncServer; + class AsyncClient { public: + friend class AsyncServer; + AsyncClient(tcp_pcb* pcb = 0); ~AsyncClient(); @@ -236,9 +240,8 @@ class AsyncServer { ~AsyncServer(); void onClient(AcConnectHandler cb, void* arg); #if ASYNC_TCP_SSL_ENABLED - // Dummy, so it compiles with ESP Async WebServer library enabled. void onSslFileRequest(AcSSlFileHandler cb, void* arg) {}; - void beginSecure(const char *cert, const char *private_key_file, const char *password) {}; + void beginSecure(const char *cert, const char *private_key_file, const char *password); #endif void begin(); void end(); @@ -249,6 +252,9 @@ class AsyncServer { //Do not use any of the functions below! static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); static int8_t _s_accepted(void *arg, AsyncClient* client); +#if ASYNC_TCP_SSL_ENABLED + static void _s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); +#endif // ASYNC_TCP_SSL_ENABLED protected: uint16_t _port; @@ -257,9 +263,20 @@ class AsyncServer { tcp_pcb* _pcb; AcConnectHandler _connect_cb; void* _connect_cb_arg; +#if ASYNC_TCP_SSL_ENABLED + bool _pcb_secure; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_net_context listen_fd, client_fd; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_x509_crt srvcert; + mbedtls_pk_context pkey; +#endif int8_t _accept(tcp_pcb* newpcb, int8_t err); int8_t _accepted(AsyncClient* client); + void _handshake(AsyncClient* client); }; diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index c6d69bde..6b3c8422 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -74,6 +74,7 @@ struct tcp_ssl_pcb { void* arg; tcp_ssl_data_cb_t on_data; tcp_ssl_handshake_cb_t on_handshake; + void* on_handshake_arg; tcp_ssl_error_cb_t on_error; size_t last_wr; struct pbuf *tcp_pbuf; @@ -326,6 +327,41 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con return ERR_OK; } +int tcp_ssl_new_server_client(struct tcp_pcb *tcp, void *arg, mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf) { + tcp_ssl_t* tcp_ssl; + + if(tcp == NULL) { + return -1; + } + + if(tcp_ssl_get(tcp) != NULL){ + return -1; + } + + tcp_ssl = tcp_ssl_new(tcp, arg); + if(tcp_ssl == NULL){ + return -1; + } + + mbedtls_ssl_init(&tcp_ssl->ssl_ctx); + int ret; + if( ( ret = mbedtls_ssl_setup( &tcp_ssl->ssl_ctx, conf ) ) != 0 ) { + TCP_SSL_DEBUG("failed: mbedtls_ssl_setup returned -0x%04x\n", -ret ); + return handle_error(ret); + } + + mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, (void*)tcp_ssl, tcp_ssl_send, tcp_ssl_recv, NULL); + + // // Start handshake. + // int ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); + // if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + // TCP_SSL_DEBUG("handshake error!\n"); + // return handle_error(ret); + // } + + return ERR_OK; +} + // Open an SSL connection using a PSK (pre-shared-key) cipher suite. int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident, const char* pskey) { tcp_ssl_t* tcp_ssl; @@ -494,7 +530,7 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { } if(tcp_ssl->on_handshake) - tcp_ssl->on_handshake(tcp_ssl->arg, tcp_ssl->tcp, tcp_ssl); + tcp_ssl->on_handshake(tcp_ssl->on_handshake_arg, tcp_ssl->tcp, tcp_ssl); } else if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { TCP_SSL_DEBUG("handshake error: %d\n", ret); handle_error(ret); @@ -526,11 +562,27 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { tcp_ssl->tcp_pbuf = NULL; + TCP_SSL_DEBUG("tcp_ssl_read: return total_bytes: %d\r\n", total_bytes >= 0 ? 0 : total_bytes); return total_bytes >= 0 ? 0 : total_bytes; // return error code } +int tcp_ssl_handshake_step(struct tcp_pcb *tcp) { + TCP_SSL_DEBUG("tcp_ssl_handshake_step(%x)\n", tcp); + if(tcp == NULL) { + return -1; + } + + tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); + if(tcp_ssl == NULL){ + return 0; + } + + return ERR_OK; +} + int tcp_ssl_free(struct tcp_pcb *tcp) { TCP_SSL_DEBUG("tcp_ssl_free(%x)\n", tcp); + return -1; if(tcp == NULL) { return -1; } @@ -593,10 +645,11 @@ void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg){ } } -void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg){ +void tcp_ssl_handshake(struct tcp_pcb *tcp, void *arg, tcp_ssl_handshake_cb_t ssl_handshake_cb){ tcp_ssl_t * item = tcp_ssl_get(tcp); if(item) { - item->on_handshake = arg; + item->on_handshake = ssl_handshake_cb; + item->on_handshake_arg = arg; } } diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index 7a741fdc..4c2ee013 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -32,6 +32,7 @@ typedef void (* tcp_ssl_error_cb_t)(void *arg, struct tcp_pcb *tcp, int8_t error uint8_t tcp_ssl_has_client(); int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, const char* root_ca, const size_t root_ca_len, const char* cli_cert, const size_t cli_cert_len, const char* cli_key, const size_t cli_key_len); +int tcp_ssl_new_server_client(struct tcp_pcb *tcp, void *arg, mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf); int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident, const char* psk); int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len); int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p); @@ -40,7 +41,7 @@ int tcp_ssl_free(struct tcp_pcb *tcp); bool tcp_ssl_has(struct tcp_pcb *tcp); void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg); void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg); -void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg); +void tcp_ssl_handshake(struct tcp_pcb *tcp, void *arg, tcp_ssl_handshake_cb_t ssl_handshake_cb); void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg); #ifdef __cplusplus From 6bac001ba3df80ab8819c042ffcd0aeb44b2b83c Mon Sep 17 00:00:00 2001 From: Bob Mooij Date: Thu, 16 Apr 2020 09:52:56 +0200 Subject: [PATCH 2/8] Move stuff from AsyncTCP to tcp_mbedtls --- src/AsyncTCP.cpp | 295 ++++++++-------------------------------------- src/AsyncTCP.h | 9 +- src/tcp_mbedtls.c | 118 +++++++++++++++++-- src/tcp_mbedtls.h | 3 +- 4 files changed, 157 insertions(+), 268 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 6ad8d348..19b0b25c 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -1465,7 +1465,7 @@ AsyncServer::AsyncServer(IPAddress addr, uint16_t port) , _connect_cb(0) , _connect_cb_arg(0) #if ASYNC_TCP_SSL_ENABLED -, _pcb_secure(false) +, _secure(false) #endif // ASYNC_TCP_SSL_ENABLED {} @@ -1477,7 +1477,7 @@ AsyncServer::AsyncServer(uint16_t port) , _connect_cb(0) , _connect_cb_arg(0) #if ASYNC_TCP_SSL_ENABLED -, _pcb_secure(false) +, _secure(false) #endif // ASYNC_TCP_SSL_ENABLED {} @@ -1494,6 +1494,9 @@ void AsyncServer::begin(){ if(_pcb) { return; } +#if ASYNC_TCP_SSL_ENABLED + _secure = false; +#endif // ASYNC_TCP_SSL_ENABLED if(!_start_async_task()){ log_e("failed to start task"); @@ -1523,12 +1526,18 @@ void AsyncServer::begin(){ log_e("listen_pcb == NULL"); return; } + log_d("pcb 0x%08x", _pcb); tcp_arg(_pcb, (void*) this); tcp_accept(_pcb, &_s_accept); } void AsyncServer::end(){ if(_pcb){ +#if ASYNC_TCP_SSL_ENABLED + if(_secure){ + tcp_ssl_free(_pcb); + } +#endif // ASYNC_TCP_SSL_ENABLED tcp_arg(_pcb, NULL); tcp_accept(_pcb, NULL); if(tcp_close(_pcb) != ERR_OK){ @@ -1540,11 +1549,12 @@ void AsyncServer::end(){ //runs on LwIP thread int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ + log_d("pcb 0x%08x", _pcb); //ets_printf("+A: 0x%08x\n", pcb); if(_connect_cb){ log_d("Create AsyncClient"); AsyncClient *c = new AsyncClient(pcb); - tcp_ssl_new_server_client(pcb, c, &ssl, &conf); + tcp_ssl_new_server_client(pcb, c, _pcb); if (c) { c->setNoDelay(_noDelay); c->_pcb_secure = true; @@ -1567,7 +1577,7 @@ struct BlaBla { }; int8_t AsyncServer::_accepted(AsyncClient* client){ - if (_pcb_secure) { + if (_secure) { BlaBla *b = new BlaBla { client, this }; @@ -1617,257 +1627,48 @@ void AsyncServer::_s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pc delete b; } -static int handle_ssl_error(int err) { - if(err == -30848){ - return err; - } -#ifdef MBEDTLS_ERROR_C - char error_buf[100]; - mbedtls_strerror(err, error_buf, 100); - log_e("%s\n", error_buf); -#endif - log_e("MbedTLS message code: %d\n", err); - return err; -} - -#define HTTP_RESPONSE \ - "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \ - "

mbed TLS Test Server

\r\n" \ - "

Successful connection using: %s

\r\n" - +#if ASYNC_TCP_SSL_ENABLED void AsyncServer::beginSecure(const char *cert, const char *private_key_file, const char *password) { - _pcb_secure = true; - - mbedtls_net_init( &listen_fd ); - mbedtls_net_init( &client_fd ); - mbedtls_ssl_init( &ssl ); - mbedtls_ssl_config_init( &conf ); - mbedtls_x509_crt_init( &srvcert ); - mbedtls_pk_init( &pkey ); - mbedtls_entropy_init( &entropy ); - mbedtls_ctr_drbg_init( &ctr_drbg ); - - /* - * 1. Load the certificates and private RSA key - */ - log_d( "Loading the server cert. and key..." ); - - /* - * This demonstration program uses embedded test certificates. - * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the - * server and CA certificates, as well as mbedtls_pk_parse_keyfile(). - */ - const char* mbedtls_test_srv_crt = cert; - size_t mbedtls_test_srv_crt_len = strlen(cert) + 1; - int ret, len; - ret = mbedtls_x509_crt_parse( &srvcert, (const unsigned char *) mbedtls_test_srv_crt, mbedtls_test_srv_crt_len ); - - if( ret != 0 ) - { - log_e( " failed\n ! mbedtls_x509_crt_parse returned %d", ret ); - handle_ssl_error(ret); - end(); return; // TODO: clear stugg - } - - const char* mbedtls_test_srv_key = private_key_file; - size_t mbedtls_test_srv_key_len = strlen(private_key_file) + 1; - - ret = mbedtls_pk_parse_key( &pkey, (const unsigned char *) mbedtls_test_srv_key, - mbedtls_test_srv_key_len, NULL, 0 ); - if( ret != 0 ) - { - log_e( " failed\n ! mbedtls_pk_parse_key returned %d", ret ); - handle_ssl_error(ret); - end(); return; // TODO: clear stugg - } - log_d("ok"); - - /* - * 3. Seed the RNG - */ - log_d( " . Seeding the random number generator..." ); - const char *pers = "dtls_server"; - - if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, - (const unsigned char *) pers, - strlen( pers ) ) ) != 0 ) - { - log_d( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret ); - end(); return; // TODO: clear stugg - } - log_d("ok"); - - /* - * 4. Setup stuff - */ - log_d( " . Setting up the SSL data..." ); - - if( ( ret = mbedtls_ssl_config_defaults( &conf, - MBEDTLS_SSL_IS_SERVER, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) - { - log_d( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); - end(); return; // TODO: clear stugg - } - - mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); - - - mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL ); - if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 ) - { - log_d( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret ); - end(); return; // TODO: clear stugg - } - - if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) - { - log_d( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); - end(); return; // TODO: clear stugg - } - - log_d( " ok\n" ); - - begin(); - return; -/********************************************************? - - /* - * 2. Setup the "listening" TCP socket - */ - log_d( " . Bind on tcp/*/443 ..." ); - if( ( ret = mbedtls_net_bind( &listen_fd, NULL, "443", MBEDTLS_NET_PROTO_TCP ) ) != 0 ) - { - printf( " failed\n ! mbedtls_net_bind returned %d\n\n", ret ); - handle_ssl_error(ret); - end(); return; // TODO: clear stugg + if(_pcb) { + return; } + _secure = true; - log_d("ok"); -reset: - mbedtls_net_free( &client_fd ); - mbedtls_ssl_session_reset( &ssl ); - - /* - * 3. Wait until a client connects - */ - log_d( " . Waiting for a remote connection ..." ); - - if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd, NULL, 0, NULL ) ) != 0 ) - { - log_d( " failed\n ! mbedtls_net_accept returned %d\n\n", ret ); - end(); return; // TODO: clear stugg + if(!_start_async_task()){ + log_e("failed to start task"); + return; } - - mbedtls_ssl_set_bio( &ssl, &client_fd, - mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout ); - - log_d( " ok\n" ); - - /* - * 5. Handshake - */ - log_d( " . Performing the SSL/TLS handshake..." ); - - while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 ) - { - if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) - { - log_d( " failed\n ! mbedtls_ssl_handshake returned %d\n\n", ret ); - goto reset; - // end(); return; // TODO: clear stugg - } + int8_t err; + _pcb = tcp_new_ip_type(IPADDR_TYPE_V4); + if (!_pcb){ + log_e("_pcb == NULL"); + return; } - log_d( " ok\n" ); - - /* - * 6. Read the HTTP Request - */ - log_d( " < Read from client:" ); - unsigned char buf[1024]; - do - { - len = sizeof( buf ) - 1; - memset( buf, 0, sizeof( buf ) ); - ret = mbedtls_ssl_read( &ssl, buf, len ); - - if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ) - continue; - - if( ret <= 0 ) - { - switch( ret ) - { - case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: - log_d( " connection was closed gracefully\n" ); - break; - - case MBEDTLS_ERR_NET_CONN_RESET: - log_d( " connection was reset by peer\n" ); - break; - - default: - log_d( " mbedtls_ssl_read returned -0x%x\n", -ret ); - break; - } - - break; - } - - len = ret; - log_d( " %d bytes read\n\n%s", len, (char *) buf ); + ip_addr_t local_addr; + local_addr.type = IPADDR_TYPE_V4; + local_addr.u_addr.ip4.addr = (uint32_t) _addr; + err = _tcp_bind(_pcb, &local_addr, _port); - if( ret > 0 ) - break; + if (err != ERR_OK) { + _tcp_close(_pcb, -1); + log_e("bind error: %d", err); + return; } - while( 1 ); - - - - - /* - * 7. Write the 200 Response - */ - log_d( " > Write to client:" ); - - len = sprintf( (char *) buf, HTTP_RESPONSE, - mbedtls_ssl_get_ciphersuite( &ssl ) ); - - while( ( ret = mbedtls_ssl_write( &ssl, buf, len ) ) <= 0 ) - { - if( ret == MBEDTLS_ERR_NET_CONN_RESET ) - { - log_d( " failed\n ! peer closed the connection\n\n" ); - goto reset; - } - if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) - { - log_d( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); - end(); return; // TODO: clear stugg - } + static uint8_t backlog = 5; + _pcb = _tcp_listen_with_backlog(_pcb, backlog); + if (!_pcb) { + log_e("listen_pcb == NULL"); + return; } - - len = ret; - log_d( " %d bytes written\n\n%s\n", len, (char *) buf ); - - log_d( " . Closing the connection..." ); - - while( ( ret = mbedtls_ssl_close_notify( &ssl ) ) < 0 ) - { - if( ret != MBEDTLS_ERR_SSL_WANT_READ && - ret != MBEDTLS_ERR_SSL_WANT_WRITE ) - { - log_d( " failed\n ! mbedtls_ssl_close_notify returned %d\n\n", ret ); - goto reset; - } + log_d("pcb 0x%08x", _pcb); + if (tcp_ssl_new_server(_pcb, this, cert, strlen(cert) + 1, private_key_file, strlen(private_key_file) + 1, password) == 0) { + log_d("start accepting clients"); + tcp_arg(_pcb, (void*) this); + tcp_accept(_pcb, &_s_accept); + } else { + end(); } - - log_d( " ok\n" ); - - ret = 0; - goto reset; - -} \ No newline at end of file +} +#endif // ASYNC_TCP_SSL_ENABLED diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 863fdce2..b68f9898 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -264,14 +264,7 @@ class AsyncServer { AcConnectHandler _connect_cb; void* _connect_cb_arg; #if ASYNC_TCP_SSL_ENABLED - bool _pcb_secure; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_net_context listen_fd, client_fd; - mbedtls_ssl_context ssl; - mbedtls_ssl_config conf; - mbedtls_x509_crt srvcert; - mbedtls_pk_context pkey; + bool _secure; #endif int8_t _accept(tcp_pcb* newpcb, int8_t err); diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 6b3c8422..260a3dce 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -10,7 +10,7 @@ extern esp_err_t _tcp_output4ssl(struct tcp_pcb * pcb, void* client); extern esp_err_t _tcp_write4ssl(struct tcp_pcb * pcb, const char* data, size_t size, uint8_t apiflags, void* client); -#if 0 +#if 1 #define TCP_SSL_DEBUG(...) do { ets_printf("T %s- ", pcTaskGetTaskName(xTaskGetCurrentTaskHandle())); ets_printf(__VA_ARGS__); } while(0) #else #define TCP_SSL_DEBUG(...) @@ -327,7 +327,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con return ERR_OK; } -int tcp_ssl_new_server_client(struct tcp_pcb *tcp, void *arg, mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf) { +int tcp_ssl_new_server(struct tcp_pcb *tcp, void *arg, const char *cert, const size_t cert_len, const char *private_key, const size_t private_key_len, const char *password) { tcp_ssl_t* tcp_ssl; if(tcp == NULL) { @@ -343,21 +343,115 @@ int tcp_ssl_new_server_client(struct tcp_pcb *tcp, void *arg, mbedtls_ssl_contex return -1; } - mbedtls_ssl_init(&tcp_ssl->ssl_ctx); int ret; - if( ( ret = mbedtls_ssl_setup( &tcp_ssl->ssl_ctx, conf ) ) != 0 ) { - TCP_SSL_DEBUG("failed: mbedtls_ssl_setup returned -0x%04x\n", -ret ); + mbedtls_ssl_init( &tcp_ssl->ssl_ctx ); + mbedtls_ssl_config_init( &tcp_ssl->ssl_conf ); + mbedtls_x509_crt_init( &tcp_ssl->ca_cert ); + mbedtls_pk_init( &tcp_ssl->client_key ); + mbedtls_entropy_init( &tcp_ssl->entropy_ctx ); + mbedtls_ctr_drbg_init( &tcp_ssl->drbg_ctx ); + + /* + * 1. Load the certificates and private RSA key + */ + TCP_SSL_DEBUG("Loading the server cert\n"); + ret = mbedtls_x509_crt_parse(&tcp_ssl->ca_cert, (const unsigned char *) cert, cert_len); + if (ret != 0) { + TCP_SSL_DEBUG("failed loading server cert, returned %d\n", ret); + tcp_ssl_free(tcp); return handle_error(ret); } - mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, (void*)tcp_ssl, tcp_ssl_send, tcp_ssl_recv, NULL); + TCP_SSL_DEBUG("Loading the server key\n"); + ret = mbedtls_pk_parse_key(&tcp_ssl->client_key, (const unsigned char *) private_key, private_key_len, NULL, 0); + if (ret != 0) { + TCP_SSL_DEBUG("failed loading server private key, returned %d\n", ret); + tcp_ssl_free(tcp); + return handle_error(ret); + } + + /* + * 3. Seed the RNG + */ + TCP_SSL_DEBUG("Seeding the random number generator...\n" ); + ret = mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, &tcp_ssl->entropy_ctx, + (const unsigned char *) pers, + strlen(pers)); + if (ret != 0) { + TCP_SSL_DEBUG("failed seeding the random number generator, returned %d\n", ret); + tcp_ssl_free(tcp); + return handle_error(ret); + } + + /* + * 4. Setup stuff + */ + TCP_SSL_DEBUG("Setting up the SSL data...\n" ); + ret = mbedtls_ssl_config_defaults( &tcp_ssl->ssl_conf, + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT ); + if (ret != 0) { + TCP_SSL_DEBUG("failed mbedtls_ssl_config_defaults returned %d\n", ret); + tcp_ssl_free(tcp); + return handle_error(ret); + } + + mbedtls_ssl_conf_rng(&tcp_ssl->ssl_conf, mbedtls_ctr_drbg_random, &tcp_ssl->drbg_ctx); + + + mbedtls_ssl_conf_ca_chain(&tcp_ssl->ssl_conf, tcp_ssl->ca_cert.next, NULL); + ret = mbedtls_ssl_conf_own_cert(&tcp_ssl->ssl_conf, &tcp_ssl->ca_cert, &tcp_ssl->client_key); + if (ret != 0) { + TCP_SSL_DEBUG("failed mbedtls_ssl_conf_own_cert returned %d\n", ret); + tcp_ssl_free(tcp); + return handle_error(ret); + } + + ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf); + if (ret != 0) { + TCP_SSL_DEBUG("failed mbedtls_ssl_setup returned %d\n", ret); + tcp_ssl_free(tcp); + return handle_error(ret); + } + + TCP_SSL_DEBUG("tcp_ssl_new_server completed succesfully\n"); + + return ERR_OK; +} + +int tcp_ssl_new_server_client(struct tcp_pcb *tcp, void *arg, struct tcp_pcb *server_tcp) { + tcp_ssl_t* tcp_ssl; + tcp_ssl_t* server_tcp_ssl; + + if(tcp == NULL || server_tcp == NULL) { + return -1; + } + + if(tcp_ssl_get(tcp) != NULL){ + return -1; + } - // // Start handshake. - // int ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); - // if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - // TCP_SSL_DEBUG("handshake error!\n"); - // return handle_error(ret); - // } + server_tcp_ssl = tcp_ssl_get(server_tcp); + if (server_tcp_ssl == NULL) { + return -1; + } + + tcp_ssl = tcp_ssl_new(tcp, arg); + if(tcp_ssl == NULL){ + return -1; + } + + int ret; + + mbedtls_ssl_init(&tcp_ssl->ssl_ctx); + ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &server_tcp_ssl->ssl_conf); + if (ret != 0) { + TCP_SSL_DEBUG("failed: mbedtls_ssl_setup returned -0x%04x\n", -ret ); + return handle_error(ret); + } + + mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, (void*)tcp_ssl, tcp_ssl_send, tcp_ssl_recv, NULL); return ERR_OK; } diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index 4c2ee013..9bdb8a0e 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -32,7 +32,8 @@ typedef void (* tcp_ssl_error_cb_t)(void *arg, struct tcp_pcb *tcp, int8_t error uint8_t tcp_ssl_has_client(); int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, const char* root_ca, const size_t root_ca_len, const char* cli_cert, const size_t cli_cert_len, const char* cli_key, const size_t cli_key_len); -int tcp_ssl_new_server_client(struct tcp_pcb *tcp, void *arg, mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf); +int tcp_ssl_new_server(struct tcp_pcb *tcp, void *arg, const char *cert, const size_t cert_len, const char *private_key, const size_t private_key_len, const char *password); +int tcp_ssl_new_server_client(struct tcp_pcb *tcp, void *arg, struct tcp_pcb *server_tcp); int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident, const char* psk); int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len); int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p); From dbe391c52ab3363543aded3afa3fc1c680011d6d Mon Sep 17 00:00:00 2001 From: Bob Mooij Date: Thu, 16 Apr 2020 12:30:44 +0200 Subject: [PATCH 3/8] implement free ssl free for server clients --- src/tcp_mbedtls.c | 79 ++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 260a3dce..404d5b90 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -61,13 +61,16 @@ struct tcp_ssl_pcb { struct tcp_pcb *tcp; int fd; mbedtls_ssl_context ssl_ctx; + bool has_ssl_conf; mbedtls_ssl_config ssl_conf; mbedtls_x509_crt ca_cert; bool has_ca_cert; mbedtls_x509_crt client_cert; bool has_client_cert; mbedtls_pk_context client_key; + bool has_drbg_ctx; mbedtls_ctr_drbg_context drbg_ctx; + bool has_entropy_ctx; mbedtls_entropy_context entropy_ctx; uint8_t type; // int handshake; @@ -192,6 +195,9 @@ tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp, void* arg) { new_item->next = NULL; new_item->has_ca_cert = false; new_item->has_client_cert = false; + new_item->has_entropy_ctx = false; + new_item->has_ssl_conf = false; + new_item->has_drbg_ctx = false; if(tcp_ssl_array == NULL){ tcp_ssl_array = new_item; @@ -237,6 +243,9 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con mbedtls_ctr_drbg_init(&tcp_ssl->drbg_ctx); mbedtls_ssl_init(&tcp_ssl->ssl_ctx); mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); + tcp_ssl->has_entropy_ctx = true; + tcp_ssl->has_drbg_ctx = true; + tcp_ssl->has_ssl_conf = true; if(root_ca != NULL) { mbedtls_x509_crt_init(&tcp_ssl->ca_cert); tcp_ssl->has_ca_cert = true; @@ -351,6 +360,11 @@ int tcp_ssl_new_server(struct tcp_pcb *tcp, void *arg, const char *cert, const s mbedtls_entropy_init( &tcp_ssl->entropy_ctx ); mbedtls_ctr_drbg_init( &tcp_ssl->drbg_ctx ); + tcp_ssl->has_entropy_ctx = true; + tcp_ssl->has_ssl_conf = true; + tcp_ssl->has_client_cert = true; + tcp_ssl->has_drbg_ctx = true; + /* * 1. Load the certificates and private RSA key */ @@ -482,6 +496,10 @@ int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident mbedtls_ssl_init(&tcp_ssl->ssl_ctx); mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); + tcp_ssl->has_entropy_ctx = true; + tcp_ssl->has_ssl_conf = true; + tcp_ssl->has_drbg_ctx = true; + mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, &tcp_ssl->entropy_ctx, (const uint8_t*)pers, sizeof(pers)); @@ -676,47 +694,50 @@ int tcp_ssl_handshake_step(struct tcp_pcb *tcp) { int tcp_ssl_free(struct tcp_pcb *tcp) { TCP_SSL_DEBUG("tcp_ssl_free(%x)\n", tcp); - return -1; if(tcp == NULL) { return -1; } tcp_ssl_t * item = tcp_ssl_array; - if(item->tcp == tcp){ + if (item == NULL) { + return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found + } + + if (item->tcp == tcp) { tcp_ssl_array = tcp_ssl_array->next; - if(item->tcp_pbuf != NULL) { - pbuf_free(item->tcp_pbuf); + } else { + while(item->next && item->next->tcp != tcp) + item = item->next; + + if(item->next == NULL || item->next->tcp != tcp){ + return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found } - mbedtls_ssl_free(&item->ssl_ctx); + + tcp_ssl_t * thisItem = item->next; + item->next = item->next->next; + item = thisItem; + } + + if(item->tcp_pbuf != NULL) { + pbuf_free(item->tcp_pbuf); + } + mbedtls_ssl_free(&item->ssl_ctx); + if(item->has_ssl_conf) { mbedtls_ssl_config_free(&item->ssl_conf); + } + if(item->has_drbg_ctx) { mbedtls_ctr_drbg_free(&item->drbg_ctx); + } + if(item->has_entropy_ctx) { mbedtls_entropy_free(&item->entropy_ctx); - if(item->has_ca_cert) { - mbedtls_x509_crt_free(&item->ca_cert); - } - if (item->has_client_cert) { - mbedtls_x509_crt_free(&item->client_cert); - mbedtls_pk_free(&item->client_key); - } - free(item); - return 0; } - - while(item->next && item->next->tcp != tcp) - item = item->next; - - if(item->next == NULL){ - return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found + if(item->has_ca_cert) { + mbedtls_x509_crt_free(&item->ca_cert); } - tcp_ssl_t * i = item->next; - item->next = i->next; - if(i->tcp_pbuf != NULL){ - pbuf_free(i->tcp_pbuf); + if (item->has_client_cert) { + mbedtls_x509_crt_free(&item->client_cert); + mbedtls_pk_free(&item->client_key); } - mbedtls_ssl_free(&i->ssl_ctx); - mbedtls_ssl_config_free(&i->ssl_conf); - mbedtls_ctr_drbg_free(&i->drbg_ctx); - mbedtls_entropy_free(&i->entropy_ctx); - free(i); + free(item); return 0; } From 4c260fb0760da3ed91f74247ed621c5c9a7e94c8 Mon Sep 17 00:00:00 2001 From: Bob Mooij Date: Thu, 16 Apr 2020 14:52:20 +0200 Subject: [PATCH 4/8] Update server handshake flow --- src/AsyncTCP.cpp | 64 +++++++++++++++++++++-------------------------- src/AsyncTCP.h | 8 +++--- src/tcp_mbedtls.c | 6 ++--- src/tcp_mbedtls.h | 2 +- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 19b0b25c..4a4f6d1b 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -580,8 +580,11 @@ extern "C" { /* Async TCP Client */ - -AsyncClient::AsyncClient(tcp_pcb* pcb) +#if ASYNC_TCP_SSL_ENABLED +AsyncClient::AsyncClient(tcp_pcb* pcb, tcp_pcb* server_pcb) +#else +AsyncClient::AsyncClient(tcp_pcb* pcb): +#endif : _connect_cb(0) , _connect_cb_arg(0) , _discard_cb(0) @@ -628,6 +631,20 @@ AsyncClient::AsyncClient(tcp_pcb* pcb) tcp_sent(_pcb, &_tcp_sent); tcp_err(_pcb, &_tcp_error); tcp_poll(_pcb, &_tcp_poll, 1); +#if ASYNC_TCP_SSL_ENABLED + if(server_pcb){ + if(tcp_ssl_new_server_client(_pcb, this, server_pcb) < 0){ + _close(); + return; + } + tcp_ssl_data(_pcb, &_s_data); + tcp_ssl_handshake(_pcb, &_s_handshake); + tcp_ssl_err(_pcb, &_s_ssl_error); + + _pcb_secure = true; + _handshake_done = false; + } +#endif } } @@ -662,7 +679,7 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other){ _handshake_done = false; tcp_ssl_arg(_pcb, this); tcp_ssl_data(_pcb, &_s_data); - tcp_ssl_handshake(_pcb, this, &_s_handshake); + tcp_ssl_handshake(_pcb, &_s_handshake); tcp_ssl_err(_pcb, &_s_ssl_error); } else { _pcb_secure = false; @@ -924,7 +941,7 @@ void AsyncClient::ackPacket(struct pbuf * pb){ * */ int8_t AsyncClient::_close(){ - //ets_printf("X: 0x%08x\n", (uint32_t)this); + log_d("X: 0x%08x", (uint32_t)this); int8_t err = ERR_OK; if(_pcb) { //log_i(""); @@ -1001,7 +1018,7 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ } tcp_ssl_data(_pcb, &_s_data); - tcp_ssl_handshake(_pcb, this, &_s_handshake); + tcp_ssl_handshake(_pcb, &_s_handshake); tcp_ssl_err(_pcb, &_s_ssl_error); } #endif // ASYNC_TCP_SSL_ENABLED @@ -1549,16 +1566,15 @@ void AsyncServer::end(){ //runs on LwIP thread int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ - log_d("pcb 0x%08x", _pcb); + log_d("pcb 0x%08x", pcb); //ets_printf("+A: 0x%08x\n", pcb); if(_connect_cb){ log_d("Create AsyncClient"); - AsyncClient *c = new AsyncClient(pcb); - tcp_ssl_new_server_client(pcb, c, _pcb); + // if (tcp_ssl_has(pcb)) tcp_ssl_free(pcb); + if (tcp_ssl_has(pcb)) return ERR_OK; + AsyncClient *c = new AsyncClient(pcb, _pcb); if (c) { c->setNoDelay(_noDelay); - c->_pcb_secure = true; - c->_handshake_done = false; return _tcp_accept(this, c); } else if (c) { delete c; @@ -1571,19 +1587,11 @@ int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ return ERR_OK; } -struct BlaBla { - AsyncClient* cllient; - AsyncServer* server; -}; - int8_t AsyncServer::_accepted(AsyncClient* client){ if (_secure) { - BlaBla *b = new BlaBla { - client, this - }; - tcp_ssl_data(client->pcb(), &AsyncClient::_s_data); - tcp_ssl_err(client->pcb(), &AsyncClient::_s_ssl_error); - tcp_ssl_handshake(client->pcb(), b, &_s_handshake); + client->onConnect([this](void * arg, AsyncClient *c) { + _connect_cb(_connect_cb_arg, c); + }, this); } else if(_connect_cb){ _connect_cb(_connect_cb_arg, client); } @@ -1605,14 +1613,6 @@ uint8_t AsyncServer::status(){ return _pcb->state; } -void AsyncServer::_handshake(AsyncClient* client){ - log_d("handshake completed"); - client->_handshake_done = true; - if(_connect_cb){ - _connect_cb(_connect_cb_arg, client); - } -} - int8_t AsyncServer::_s_accept(void * arg, tcp_pcb * pcb, int8_t err){ return reinterpret_cast(arg)->_accept(pcb, err); } @@ -1621,12 +1621,6 @@ int8_t AsyncServer::_s_accepted(void *arg, AsyncClient* client){ return reinterpret_cast(arg)->_accepted(client); } -void AsyncServer::_s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl){ - BlaBla *b = reinterpret_cast(arg); - b->server->_handshake(b->cllient); - delete b; -} - #if ASYNC_TCP_SSL_ENABLED void AsyncServer::beginSecure(const char *cert, const char *private_key_file, const char *password) { if(_pcb) { diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index b68f9898..cf5cfddd 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -64,7 +64,11 @@ class AsyncClient { public: friend class AsyncServer; +#if ASYNC_TCP_SSL_ENABLED + AsyncClient(tcp_pcb* pcb = 0, tcp_pcb* server_pcb = 0); +#else AsyncClient(tcp_pcb* pcb = 0); +#endif ~AsyncClient(); AsyncClient & operator=(const AsyncClient &other); @@ -252,9 +256,6 @@ class AsyncServer { //Do not use any of the functions below! static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); static int8_t _s_accepted(void *arg, AsyncClient* client); -#if ASYNC_TCP_SSL_ENABLED - static void _s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); -#endif // ASYNC_TCP_SSL_ENABLED protected: uint16_t _port; @@ -269,7 +270,6 @@ class AsyncServer { int8_t _accept(tcp_pcb* newpcb, int8_t err); int8_t _accepted(AsyncClient* client); - void _handshake(AsyncClient* client); }; diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 404d5b90..884b8594 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -77,7 +77,6 @@ struct tcp_ssl_pcb { void* arg; tcp_ssl_data_cb_t on_data; tcp_ssl_handshake_cb_t on_handshake; - void* on_handshake_arg; tcp_ssl_error_cb_t on_error; size_t last_wr; struct pbuf *tcp_pbuf; @@ -642,7 +641,7 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { } if(tcp_ssl->on_handshake) - tcp_ssl->on_handshake(tcp_ssl->on_handshake_arg, tcp_ssl->tcp, tcp_ssl); + tcp_ssl->on_handshake(tcp_ssl->arg, tcp_ssl->tcp, tcp_ssl); } else if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { TCP_SSL_DEBUG("handshake error: %d\n", ret); handle_error(ret); @@ -760,11 +759,10 @@ void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg){ } } -void tcp_ssl_handshake(struct tcp_pcb *tcp, void *arg, tcp_ssl_handshake_cb_t ssl_handshake_cb){ +void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t ssl_handshake_cb){ tcp_ssl_t * item = tcp_ssl_get(tcp); if(item) { item->on_handshake = ssl_handshake_cb; - item->on_handshake_arg = arg; } } diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index 9bdb8a0e..746de97e 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -42,7 +42,7 @@ int tcp_ssl_free(struct tcp_pcb *tcp); bool tcp_ssl_has(struct tcp_pcb *tcp); void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg); void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg); -void tcp_ssl_handshake(struct tcp_pcb *tcp, void *arg, tcp_ssl_handshake_cb_t ssl_handshake_cb); +void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t ssl_handshake_cb); void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg); #ifdef __cplusplus From 535aa27d4c90e1d6788175c8b8d7fd0c18106c88 Mon Sep 17 00:00:00 2001 From: Bob Mooij Date: Thu, 16 Apr 2020 21:46:03 +0200 Subject: [PATCH 5/8] Fix code when ASYNC_TCP_SSL_ENABLED is not enabled --- src/AsyncTCP.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 4a4f6d1b..8678b7e3 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -583,7 +583,7 @@ extern "C" { #if ASYNC_TCP_SSL_ENABLED AsyncClient::AsyncClient(tcp_pcb* pcb, tcp_pcb* server_pcb) #else -AsyncClient::AsyncClient(tcp_pcb* pcb): +AsyncClient::AsyncClient(tcp_pcb* pcb) #endif : _connect_cb(0) , _connect_cb_arg(0) @@ -1571,8 +1571,12 @@ int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ if(_connect_cb){ log_d("Create AsyncClient"); // if (tcp_ssl_has(pcb)) tcp_ssl_free(pcb); - if (tcp_ssl_has(pcb)) return ERR_OK; + // if (tcp_ssl_has(pcb)) return ERR_OK; +#if ASYNC_TCP_SSL_ENABLED AsyncClient *c = new AsyncClient(pcb, _pcb); +#else + AsyncClient *c = new AsyncClient(pcb); +#endif if (c) { c->setNoDelay(_noDelay); return _tcp_accept(this, c); @@ -1588,11 +1592,14 @@ int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ } int8_t AsyncServer::_accepted(AsyncClient* client){ +#if ASYNC_TCP_SSL_ENABLED if (_secure) { client->onConnect([this](void * arg, AsyncClient *c) { _connect_cb(_connect_cb_arg, c); }, this); - } else if(_connect_cb){ + } else +#endif + if(_connect_cb){ _connect_cb(_connect_cb_arg, client); } return ERR_OK; From ab8091edab5937effd1aadfd7b7a63d5bea0647a Mon Sep 17 00:00:00 2001 From: Bob Mooij Date: Thu, 16 Apr 2020 22:42:36 +0200 Subject: [PATCH 6/8] Fix 2 issues found by PR Quality Review --- src/AsyncTCP.cpp | 2 -- src/tcp_mbedtls.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 8678b7e3..2a5dd341 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -1580,8 +1580,6 @@ int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ if (c) { c->setNoDelay(_noDelay); return _tcp_accept(this, c); - } else if (c) { - delete c; } } if(tcp_close(pcb) != ERR_OK){ diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 884b8594..083f4721 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -389,7 +389,7 @@ int tcp_ssl_new_server(struct tcp_pcb *tcp, void *arg, const char *cert, const s TCP_SSL_DEBUG("Seeding the random number generator...\n" ); ret = mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, &tcp_ssl->entropy_ctx, (const unsigned char *) pers, - strlen(pers)); + sizeof(pers)); if (ret != 0) { TCP_SSL_DEBUG("failed seeding the random number generator, returned %d\n", ret); tcp_ssl_free(tcp); From d763bf16b69c9941f6c6e748774cf931d58887b1 Mon Sep 17 00:00:00 2001 From: Bob Mooij Date: Thu, 16 Apr 2020 22:44:56 +0200 Subject: [PATCH 7/8] Fix freeing ssl tcp --- src/tcp_mbedtls.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 083f4721..6b7afc5b 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -63,10 +63,11 @@ struct tcp_ssl_pcb { mbedtls_ssl_context ssl_ctx; bool has_ssl_conf; mbedtls_ssl_config ssl_conf; - mbedtls_x509_crt ca_cert; bool has_ca_cert; - mbedtls_x509_crt client_cert; + mbedtls_x509_crt ca_cert; bool has_client_cert; + mbedtls_x509_crt client_cert; + bool has_client_key; mbedtls_pk_context client_key; bool has_drbg_ctx; mbedtls_ctr_drbg_context drbg_ctx; @@ -194,6 +195,7 @@ tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp, void* arg) { new_item->next = NULL; new_item->has_ca_cert = false; new_item->has_client_cert = false; + new_item->has_client_key = false; new_item->has_entropy_ctx = false; new_item->has_ssl_conf = false; new_item->has_drbg_ctx = false; @@ -253,6 +255,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con mbedtls_x509_crt_init(&tcp_ssl->client_cert); mbedtls_pk_init(&tcp_ssl->client_key); tcp_ssl->has_client_cert = true; + tcp_ssl->has_client_key = true; } mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, @@ -361,7 +364,8 @@ int tcp_ssl_new_server(struct tcp_pcb *tcp, void *arg, const char *cert, const s tcp_ssl->has_entropy_ctx = true; tcp_ssl->has_ssl_conf = true; - tcp_ssl->has_client_cert = true; + tcp_ssl->has_ca_cert = true; + tcp_ssl->has_client_key = true; tcp_ssl->has_drbg_ctx = true; /* @@ -734,6 +738,8 @@ int tcp_ssl_free(struct tcp_pcb *tcp) { } if (item->has_client_cert) { mbedtls_x509_crt_free(&item->client_cert); + } + if (item->has_client_key) { mbedtls_pk_free(&item->client_key); } free(item); From 51df5daec3abea2f0a69267456db7b7551b77f8c Mon Sep 17 00:00:00 2001 From: Bob Mooij Date: Fri, 17 Apr 2020 14:22:39 +0200 Subject: [PATCH 8/8] Fix cleaning ssl connection --- src/AsyncTCP.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 2a5dd341..bbf9403b 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -1124,7 +1124,9 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { pbuf_free(pb); // handle errors if(err < 0){ - if (err != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + if (err == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + tcp_ssl_free(pcb); + } else { log_e("_recv err: %d\n", err); _close(); } @@ -1568,10 +1570,7 @@ void AsyncServer::end(){ int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ log_d("pcb 0x%08x", pcb); //ets_printf("+A: 0x%08x\n", pcb); - if(_connect_cb){ - log_d("Create AsyncClient"); - // if (tcp_ssl_has(pcb)) tcp_ssl_free(pcb); - // if (tcp_ssl_has(pcb)) return ERR_OK; + if(_connect_cb){ #if ASYNC_TCP_SSL_ENABLED AsyncClient *c = new AsyncClient(pcb, _pcb); #else