From a251e596c5a5bac2de740bb18ebbdc279991f17b Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Wed, 26 Sep 2018 10:00:42 +0200 Subject: [PATCH 01/29] - very early version with mbed TLS support. --- src/AsyncTCP.cpp | 147 +++++++++++++-- src/AsyncTCP.h | 14 +- src/tcp_mbedtls.c | 469 ++++++++++++++++++++++++++++++++++++++++++++++ src/tcp_mbedtls.h | 46 +++++ 4 files changed, 653 insertions(+), 23 deletions(-) create mode 100644 src/tcp_mbedtls.c create mode 100644 src/tcp_mbedtls.h diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index e604095..3e1ede9 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -215,6 +215,7 @@ static int8_t _tcp_poll(void * arg, struct tcp_pcb * pcb) { } static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) { + log_i("_tcp_recv"); lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); e->event = LWIP_TCP_RECV; e->arg = arg; @@ -228,6 +229,7 @@ static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_ } static int8_t _tcp_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { + log_e("_tcp_sent"); lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); e->event = LWIP_TCP_SENT; e->arg = arg; @@ -432,8 +434,6 @@ AsyncClient::AsyncClient(tcp_pcb* pcb) , next(NULL) , _in_lwip_thread(false) { - //ets_printf("+: 0x%08x\n", (uint32_t)this); - _pcb = pcb; if(_pcb){ _rx_last_packet = millis(); @@ -449,11 +449,9 @@ AsyncClient::AsyncClient(tcp_pcb* pcb) AsyncClient::~AsyncClient(){ if(_pcb) _close(); - - //ets_printf("-: 0x%08x\n", (uint32_t)this); } -bool AsyncClient::connect(IPAddress ip, uint16_t port){ +bool AsyncClient::connect(IPAddress ip, uint16_t port, bool secure){ if (_pcb){ log_w("already connected, state %d", _pcb->state); return false; @@ -473,11 +471,19 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){ return false; } + Serial.print("connect res ip: "); + Serial.println(secure); + + _pcb_secure = secure; + _handshake_done = !secure; + tcp_arg(pcb, this); tcp_err(pcb, &_tcp_error); if(_in_lwip_thread){ + log_i("tcp_connect-1: _in_lwip_thread: %d", _in_lwip_thread); tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); } else { + log_i("tcp_connect-2: _in_lwip_thread: %d", _in_lwip_thread); _tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); } return true; @@ -495,37 +501,64 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other){ tcp_sent(_pcb, &_tcp_sent); tcp_err(_pcb, &_tcp_error); tcp_poll(_pcb, &_tcp_poll, 1); + + if(tcp_ssl_has(_pcb)){ + _pcb_secure = true; + _handshake_done = false; + tcp_ssl_arg(_pcb, this); + tcp_ssl_data(_pcb, &_s_data); + tcp_ssl_handshake(_pcb, &_s_handshake); + tcp_ssl_err(_pcb, &_s_ssl_error); + } else { + _pcb_secure = false; + _handshake_done = true; + } } return *this; } int8_t AsyncClient::_connected(void* pcb, int8_t err){ _pcb = reinterpret_cast(pcb); + + log_i("error: %d", err); if(_pcb){ _rx_last_packet = millis(); _pcb_busy = false; tcp_recv(_pcb, &_tcp_recv); tcp_sent(_pcb, &_tcp_sent); tcp_poll(_pcb, &_tcp_poll, 1); + + if(_pcb_secure){ + tcp_ssl_arg(_pcb, this); + log_e("_pcb: 0x%x", _pcb); + if(tcp_ssl_new_client(_pcb) < 0){ + return _close(); + } + + tcp_ssl_arg(_pcb, this); + tcp_ssl_data(_pcb, &_s_data); + tcp_ssl_handshake(_pcb, &_s_handshake); + tcp_ssl_err(_pcb, &_s_ssl_error); + } } _in_lwip_thread = true; - if(_connect_cb) + if(!_pcb_secure && _connect_cb) _connect_cb(_connect_cb_arg, this); _in_lwip_thread = false; return ERR_OK; } int8_t AsyncClient::_close(){ - //ets_printf("X: 0x%08x\n", (uint32_t)this); int8_t err = ERR_OK; if(_pcb) { - //log_i(""); + if(_pcb_secure){ + tcp_ssl_free(_pcb); + } tcp_arg(_pcb, NULL); tcp_sent(_pcb, NULL); tcp_recv(_pcb, NULL); tcp_err(_pcb, NULL); tcp_poll(_pcb, NULL, 0); - _tcp_clear_events(this); if(_in_lwip_thread){ err = tcp_close(_pcb); } else { @@ -535,6 +568,7 @@ int8_t AsyncClient::_close(){ err = abort(); } _pcb = NULL; + // _tcp_clear_events(this); if(_discard_cb) _discard_cb(_discard_cb_arg, this); } @@ -542,6 +576,7 @@ int8_t AsyncClient::_close(){ } void AsyncClient::_error(int8_t err) { + log_e("Error!! %d", err); if(_pcb){ tcp_arg(_pcb, NULL); tcp_sent(_pcb, NULL); @@ -556,7 +591,16 @@ void AsyncClient::_error(int8_t err) { _discard_cb(_discard_cb_arg, this); } +void AsyncClient::_ssl_error(int8_t err){ + if(_error_cb) + _error_cb(_error_cb_arg, this, err+64); +} + int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { + log_e("_sent"); + if (_pcb_secure && !_handshake_done) + return ERR_OK; + _in_lwip_thread = false; _rx_last_packet = millis(); //log_i("%u", len); @@ -567,13 +611,15 @@ int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { } int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { + log_e("_recv"); if(!_pcb || pcb != _pcb){ - log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - if(pb){ - pbuf_free(pb); - } - return ERR_OK; - } + log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + if(pb){ + pbuf_free(pb); + } + return ERR_OK; + } + _in_lwip_thread = false; if(pb == NULL){ return _close(); @@ -581,6 +627,18 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { while(pb != NULL){ _rx_last_packet = millis(); + if(_pcb_secure){ + // log_i("_recv: %d\n", pb->tot_len); + int read_bytes = tcp_ssl_read(pcb, pb); + if(read_bytes < 0){ + if (read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + log_e("_recv err: %d\n", read_bytes); + _close(); + } + //return read_bytes; + } + return ERR_OK; + } //we should not ack before we assimilate the data //log_i("%u", pb->len); //Serial.write((const uint8_t *)pb->payload, pb->len); @@ -627,6 +685,10 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ _close(); return ERR_OK; } + if(_pcb_secure && !_handshake_done && (now - _rx_last_packet) >= 2000){ + _close(); + return ERR_OK; + } // Everything is fine if(_poll_cb) _poll_cb(_poll_cb_arg, this); @@ -636,7 +698,7 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ void AsyncClient::_dns_found(struct ip_addr *ipaddr){ _in_lwip_thread = true; if(ipaddr){ - connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port); + connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port, _pcb_secure); } else { log_e("dns fail"); if(_error_cb) @@ -651,13 +713,26 @@ bool AsyncClient::operator==(const AsyncClient &other) { return _pcb == other._pcb; } -bool AsyncClient::connect(const char* host, uint16_t port){ +bool AsyncClient::connect(const char* host, uint16_t port, bool secure){ ip_addr_t addr; + + Serial.print("connect ip: "); + Serial.println(secure); + err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_s_dns_found, this); if(err == ERR_OK) { - return connect(IPAddress(addr.u_addr.ip4.addr), port); + Serial.print("connect a ip: "); + Serial.println(secure); + + return connect(IPAddress(addr.u_addr.ip4.addr), port, secure); } else if(err == ERR_INPROGRESS) { + + Serial.print("connect b ip: "); + Serial.println(secure); + _connect_port = port; + _pcb_secure = secure; + _handshake_done = !secure; return true; } log_e("error: %d", err); @@ -723,13 +798,22 @@ size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) { return will_send; } - size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { if(!_pcb || size == 0 || data == NULL) return 0; size_t room = space(); if(!room) return 0; + if(_pcb_secure){ + int sent = tcp_ssl_write(_pcb, (uint8_t*)data, size); + if(sent >= 0){ + // @ToDo: ??? + //_tx_unacked_len += sent; + return sent; + } + _close(); + return 0; + } size_t will_send = (room < size) ? room : size; int8_t err = ERR_OK; if(_in_lwip_thread){ @@ -743,6 +827,9 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { } bool AsyncClient::send(){ + if(_pcb_secure) + return true; + int8_t err = ERR_OK; if(_in_lwip_thread){ err = tcp_output(_pcb); @@ -955,6 +1042,7 @@ void AsyncClient::onPoll(AcConnectHandler cb, void* arg){ } +// void AsyncClient::_s_dns_found(const char * name, ip_addr_t * ipaddr, void * arg){ void AsyncClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg){ if(arg){ reinterpret_cast(arg)->_dns_found(ipaddr); @@ -977,7 +1065,7 @@ int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, i reinterpret_cast(arg)->_recv(pcb, pb, err); } else { if(pb){ - pbuf_free(pb); + pbuf_free(pb); } log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); } @@ -1010,6 +1098,25 @@ int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){ return ERR_OK; } +void AsyncClient::_s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len){ + log_i("_s_data"); + AsyncClient *c = reinterpret_cast(arg); + if(c->_recv_cb) + c->_recv_cb(c->_recv_cb_arg, c, data, len); +} + +void AsyncClient::_s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl){ + AsyncClient *c = reinterpret_cast(arg); + log_i("_s_handshake: done!"); + c->_handshake_done = true; + if(c->_connect_cb) + c->_connect_cb(c->_connect_cb_arg, c); +} + +void AsyncClient::_s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err){ + reinterpret_cast(arg)->_ssl_error(err); +} + const char * AsyncClient::errorToString(int8_t error){ switch(error){ case 0: return "OK"; diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 6cd0fca..b8a417f 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -24,10 +24,12 @@ #include "IPAddress.h" #include +#include extern "C" { #include "freertos/semphr.h" #include "lwip/pbuf.h" } +#include "tcp_mbedtls.h" class AsyncClient; @@ -48,6 +50,7 @@ struct ip_addr; class AsyncClient { protected: tcp_pcb* _pcb; + // sslclient_context* _ssl_context; AcConnectHandler _connect_cb; void* _connect_cb_arg; @@ -67,6 +70,8 @@ class AsyncClient { void* _poll_cb_arg; bool _pcb_busy; + bool _pcb_secure; + bool _handshake_done; uint32_t _pcb_sent_at; bool _close_pcb; bool _ack_pcb; @@ -79,10 +84,13 @@ class AsyncClient { int8_t _close(); int8_t _connected(void* pcb, int8_t err); void _error(int8_t err); + void _ssl_error(int8_t err); int8_t _poll(tcp_pcb* pcb); int8_t _sent(tcp_pcb* pcb, uint16_t len); void _dns_found(struct ip_addr *ipaddr); - + static void _s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); + static void _s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); + static void _s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err); public: AsyncClient* prev; @@ -99,8 +107,8 @@ class AsyncClient { bool operator!=(const AsyncClient &other) { return !(*this == other); } - bool connect(IPAddress ip, uint16_t port); - bool connect(const char* host, uint16_t port); + bool connect(IPAddress ip, uint16_t port, bool secure = false); + bool connect(const char* host, uint16_t port, bool secure = false); void close(bool now = false); void stop(); int8_t abort(); diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c new file mode 100644 index 0000000..db9db21 --- /dev/null +++ b/src/tcp_mbedtls.c @@ -0,0 +1,469 @@ +#include "tcp_mbedtls.h" +#include "lwip/tcp.h" +#include "mbedtls/debug.h" +#include + +#define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) + +static const char pers[] = "esp32-tls"; + +static int handle_error(int err) +{ + if(err == -30848){ + return err; + } +#ifdef MBEDTLS_ERROR_C + char error_buf[100]; + mbedtls_strerror(err, error_buf, 100); + TCP_SSL_DEBUG("%s\n", error_buf); +#endif + TCP_SSL_DEBUG("MbedTLS message code: %d\n", err); + return err; +} + +static uint8_t _tcp_ssl_has_client = 0; + +struct tcp_ssl_pcb { + struct tcp_pcb *tcp; + int fd; + mbedtls_ssl_context ssl_ctx; + mbedtls_ssl_config ssl_conf; + mbedtls_ctr_drbg_context drbg_ctx; + mbedtls_entropy_context entropy_ctx; + uint8_t type; + // int handshake; + void* arg; + tcp_ssl_data_cb_t on_data; + tcp_ssl_handshake_cb_t on_handshake; + tcp_ssl_error_cb_t on_error; + int last_wr; + struct pbuf *tcp_pbuf; + int pbuf_offset; + struct tcp_ssl_pcb* next; +}; + +typedef struct tcp_ssl_pcb tcp_ssl_t; + +static tcp_ssl_t * tcp_ssl_array = NULL; +static int tcp_ssl_next_fd = 0; + +int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { + tcp_ssl_t *fd_data = (tcp_ssl_t*)ctx; + uint8_t *read_buf = NULL; + uint8_t *pread_buf = NULL; + u16_t recv_len = 0; + + if(fd_data->tcp_pbuf == NULL || fd_data->tcp_pbuf->tot_len == 0) { + return 0; + } + + read_buf =(uint8_t*)calloc(fd_data->tcp_pbuf->len + 1, sizeof(uint8_t)); + pread_buf = read_buf; + if (pread_buf != NULL){ + recv_len = pbuf_copy_partial(fd_data->tcp_pbuf, read_buf, len, fd_data->pbuf_offset); + fd_data->pbuf_offset += recv_len; + } + + if (recv_len != 0) { + memcpy(buf, read_buf, recv_len); + } + + if(len < recv_len) { + TCP_SSL_DEBUG("tcp_ssl_recv: got %d bytes more than expected\n", recv_len - len); + } + + free(pread_buf); + pread_buf = NULL; + + return recv_len; +} + +int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t size) { + if(ctx == NULL) { + TCP_SSL_DEBUG("tcp_ssl_send: no context set\n"); + return -1; + } + + if(buf == NULL) { + TCP_SSL_DEBUG("tcp_ssl_send: buf not set\n"); + return -1; + } + + tcp_ssl_t *tcp = (tcp_ssl_t*)ctx; + + size_t room = tcp_sndbuf(tcp->tcp); + size_t will_send = (room < size) ? room : size; + + TCP_SSL_DEBUG("len: %d, has space? %d\n", size, room); + + int8_t ret = tcp_write(tcp->tcp, buf, will_send, 0); + if(ret == ERR_OK) { + TCP_SSL_DEBUG("oki!\n"); + } + + return will_send; +} + +uint8_t tcp_ssl_has_client() { + return _tcp_ssl_has_client; +} + +tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) { + + if(tcp_ssl_next_fd < 0){ + tcp_ssl_next_fd = 0;//overflow + } + + tcp_ssl_t * new_item = (tcp_ssl_t*)malloc(sizeof(tcp_ssl_t)); + if(!new_item){ + TCP_SSL_DEBUG("tcp_ssl_new: failed to allocate tcp_ssl\n"); + return NULL; + } + + new_item->tcp = tcp; + new_item->arg = NULL; + new_item->on_data = NULL; + new_item->on_handshake = NULL; + new_item->on_error = NULL; + new_item->tcp_pbuf = NULL; + new_item->pbuf_offset = 0; + new_item->next = NULL; + // new_item->ssl_ctx = NULL; + // new_item->ssl = NULL; + new_item->fd = tcp_ssl_next_fd++; + + if(tcp_ssl_array == NULL){ + tcp_ssl_array = new_item; + } else { + tcp_ssl_t * item = tcp_ssl_array; + while(item->next != NULL) + item = item->next; + item->next = new_item; + } + + TCP_SSL_DEBUG("tcp_ssl_new: %d: 0x%x\n", new_item->fd, tcp); + return new_item; +} + +tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) { + if(tcp == NULL) { + return NULL; + } + tcp_ssl_t * item = tcp_ssl_array; + while(item && item->tcp != tcp){ + item = item->next; + } + return item; +} + +int tcp_ssl_new_client(struct tcp_pcb *tcp) { + tcp_ssl_t* tcp_ssl; + + TCP_SSL_DEBUG("tcp_ssl_new_client\n"); + + if(tcp == NULL) { + return -1; + } + + if(tcp_ssl_get(tcp) != NULL){ + TCP_SSL_DEBUG("tcp_ssl_new_client: tcp_ssl already exists\n"); + return -1; + } + + tcp_ssl = tcp_ssl_new(tcp); + if(tcp_ssl == NULL){ + return -1; + } + + // + mbedtls_entropy_init(&tcp_ssl->entropy_ctx); + mbedtls_ctr_drbg_init(&tcp_ssl->drbg_ctx); + mbedtls_ssl_init(&tcp_ssl->ssl_ctx); + mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); + + mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, + &tcp_ssl->entropy_ctx, (const unsigned char*)pers, strlen(pers)); + + if(mbedtls_ssl_config_defaults(&tcp_ssl->ssl_conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) { + TCP_SSL_DEBUG("error setting SSL config.\n"); + + // tcp_ssl_free(tcp); + return -1; + } + + mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); + int ret = 0; + + // @ToDo: there's no hostname at this stage, set it later. + // if((ret = mbedtls_ssl_set_hostname(&ctx->ssl_ctx, host)) != 0){ + // return handle_error(ret); + // } + + mbedtls_ssl_conf_rng(&tcp_ssl->ssl_conf, mbedtls_ctr_drbg_random, &tcp_ssl->drbg_ctx); + + if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) { + // 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 ); + mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, (void*)tcp_ssl, tcp_ssl_send, tcp_ssl_recv, NULL); + // mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, &tcp_ssl->fd, mbedtls_net_send, mbedtls_net_recv, NULL ); + + // @ToDo: do we need this here? + ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); + handle_error(ret); + TCP_SSL_DEBUG("ret mbedtls_ssl_handshake: %d, want read: %d, write: %d\n", ret, MBEDTLS_ERR_SSL_WANT_READ, MBEDTLS_ERR_SSL_WANT_WRITE); + // if (ret != 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + // TCP_SSL_DEBUG("tcp_ssl_new_client: mbedtls_ssl_handshake: %d.\n", ret); + // // if(tcp_ssl->on_error) + // // tcp_ssl->on_error(tcp_ssl->arg, tcp_ssl->tcp, ret); + // } + + TCP_SSL_DEBUG("end tcp_ssl_new_client %d.\n", tcp_ssl->fd); + + return tcp_ssl->fd; +} + +int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { + if(tcp == NULL) { + return -1; + } + + tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); + + TCP_SSL_DEBUG("tcp_ssl_write %x\n, state: %d\n", tcp_ssl, tcp->state); + + if(tcp_ssl == NULL){ + TCP_SSL_DEBUG("tcp_ssl_write: tcp_ssl is NULL\n"); + return 0; + } + + tcp_ssl->last_wr = 0; + + TCP_SSL_DEBUG("about to call mbedtls_ssl_write\n"); + int rc = mbedtls_ssl_write(&tcp_ssl->ssl_ctx, data, len); + + TCP_SSL_DEBUG("tcp_ssl_write: %u -> %d (%d)\r\n", len, tcp_ssl->last_wr, rc); + + if (rc < 0){ + // @ToDO: ??? + // if(rc != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + TCP_SSL_DEBUG("tcp_ssl_write error: %d\r\n", rc); + // } + return rc; + } + + return tcp_ssl->last_wr; +} + +int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { + TCP_SSL_DEBUG("tcp_ssl_ssl_read\n"); + + if(tcp == NULL) { + return -1; + } + tcp_ssl_t* fd_data = NULL; + + int read_bytes = 0; + int total_bytes = 0; + uint8_t *read_buf; + + fd_data = tcp_ssl_get(tcp); + if(fd_data == NULL) { + TCP_SSL_DEBUG("tcp_ssl_read: tcp_ssl is NULL\n"); + return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; + } + + if(p == NULL) { + TCP_SSL_DEBUG("tcp_ssl_read:p == NULL\n"); + return ERR_TCP_SSL_INVALID_DATA; + } + + TCP_SSL_DEBUG("READY TO READ SOME DATA\n"); + + fd_data->tcp_pbuf = p; + fd_data->pbuf_offset = 0; + + do { + if(fd_data->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { + TCP_SSL_DEBUG("start handshake: %d\n", fd_data->ssl_ctx.state); + int ret = mbedtls_ssl_handshake(&fd_data->ssl_ctx); + if(ret == 0) { + if(fd_data->on_handshake) + fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data); + } else if(ret != MBEDTLS_ERR_SSL_WANT_READ || ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + // if(fd_data->on_error) + // fd_data->on_error(fd_data->arg, fd_data->tcp, ret); + + TCP_SSL_DEBUG("handshake error: %d\n", ret); + // return ret; + //return 0; + } + } else { + uint8_t readb[1024]; + read_bytes = mbedtls_ssl_read(&fd_data->ssl_ctx, &readb, 1024); + TCP_SSL_DEBUG("start read: %d.\n", read_bytes); + if(read_bytes < 0) { + handle_error(read_bytes); + if(read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); + } + total_bytes = read_bytes; + break; + } else if(read_bytes > 0) { + if(fd_data->on_data){ + fd_data->on_data(fd_data->arg, tcp, &readb, read_bytes); + } + total_bytes+= read_bytes; + } + } + // if(fd_data->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { + // TCP_SSL_DEBUG("start handshake.\n"); + // int ret = mbedtls_ssl_handshake(&fd_data->ssl_ctx); + // if(ret == 0) { + // if(fd_data->on_handshake) + // fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data); + // } else if(ret != MBEDTLS_ERR_SSL_WANT_READ || ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + // if(fd_data->on_error) + // fd_data->on_error(fd_data->arg, fd_data->tcp, ret); + // return ret; + // } + // } + // // @TODO: FIX! + // read_bytes = mbedtls_ssl_read(&fd_data->ssl_ctx, &read_buf, 0); + // TCP_SSL_DEBUG("tcp_ssl_ssl_read: read_bytes: %d (%d)\n", read_bytes, MBEDTLS_SSL_HANDSHAKE_OVER); + // if(read_bytes < 0) { + // handle_error(read_bytes); + // if(read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + // TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); + // } + // total_bytes = read_bytes; + // break; + // } else if(read_bytes > 0){ + // if(fd_data->on_data){ + // fd_data->on_data(fd_data->arg, tcp, read_buf, read_bytes); + // } + // total_bytes+= read_bytes; + // } else { + // TCP_SSL_DEBUG("start handshake? %d.\n", fd_data->ssl_ctx.state); + // if(fd_data->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { + // TCP_SSL_DEBUG("start handshake.\n"); + // int ret = mbedtls_ssl_handshake(&fd_data->ssl_ctx); + // if(ret == 0) { + // if(fd_data->on_handshake) + // fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data); + // } else if(ret != MBEDTLS_ERR_SSL_WANT_READ || ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + // if(fd_data->on_error) + // fd_data->on_error(fd_data->arg, fd_data->tcp, ret); + // return ret; + // } + // } + // } + } while (p->tot_len - fd_data->pbuf_offset > 0); + + // OLD + // if(fd_data->handshake != MBEDTLS_SSL_HANDSHAKE_OVER) { + // fd_data->handshake = mbedtls_ssl_handshake(&fd_data->ssl_ctx); + // if(fd_data->handshake == 0){ + // TCP_SSL_DEBUG("tcp_ssl_read: handshake OK\n"); + // if(fd_data->on_handshake) + // fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data); + // } else if(fd_data->handshake != 0){ + // TCP_SSL_DEBUG("tcp_ssl_read: handshake error: %d\n", fd_data->handshake); + // if(fd_data->on_error) + // fd_data->on_error(fd_data->arg, fd_data->tcp, fd_data->handshake); + // return fd_data->handshake; + // } + // } + + tcp_recved(tcp, p->tot_len); + fd_data->tcp_pbuf = NULL; + pbuf_free(p); + + TCP_SSL_DEBUG("tcp_ssl_read: eof: %d\n", total_bytes); + + return total_bytes; +} + +int tcp_ssl_free(struct tcp_pcb *tcp) { + TCP_SSL_DEBUG("tcp_ssl_free: 1\n"); + if(tcp == NULL) { + return -1; + } + TCP_SSL_DEBUG("tcp_ssl_free: 2\n"); + tcp_ssl_t * item = tcp_ssl_array; + TCP_SSL_DEBUG("tcp_ssl_free: 2a 0x%x\n", item); + if(item->tcp == tcp){ + TCP_SSL_DEBUG("tcp_ssl_free: 3\n"); + tcp_ssl_array = tcp_ssl_array->next; + if(item->tcp_pbuf != NULL) { + pbuf_free(item->tcp_pbuf); + } + TCP_SSL_DEBUG("tcp_ssl_free: %d\n", item->fd); + mbedtls_ssl_free(&item->ssl_ctx); + mbedtls_ssl_config_free(&item->ssl_conf); + mbedtls_ctr_drbg_free(&item->drbg_ctx); + mbedtls_entropy_free(&item->entropy_ctx); + free(item); + return 0; + } + + TCP_SSL_DEBUG("tcp_ssl_free: 4\n"); + while(item->next && item->next->tcp != tcp) + item = item->next; + + TCP_SSL_DEBUG("tcp_ssl_free: 5\n"); + if(item->next == NULL){ + return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found + } + TCP_SSL_DEBUG("tcp_ssl_free: 6\n"); + tcp_ssl_t * i = item->next; + item->next = i->next; + if(i->tcp_pbuf != NULL){ + pbuf_free(i->tcp_pbuf); + } + TCP_SSL_DEBUG("tcp_ssl_free: %d\n", i->fd); + 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); + + return 0; +} + +bool tcp_ssl_has(struct tcp_pcb *tcp) { + return tcp_ssl_get(tcp) != NULL; +} + +void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg) { + tcp_ssl_t * item = tcp_ssl_get(tcp); + if(item) { + item->arg = arg; + } +} + +void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg){ + tcp_ssl_t * item = tcp_ssl_get(tcp); + if(item) { + item->on_data = arg; + } +} + +void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg){ + tcp_ssl_t * item = tcp_ssl_get(tcp); + if(item) { + item->on_handshake = arg; + } +} + +void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg){ + tcp_ssl_t * item = tcp_ssl_get(tcp); + if(item) { + item->on_error = arg; + } +} diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h new file mode 100644 index 0000000..20d1504 --- /dev/null +++ b/src/tcp_mbedtls.h @@ -0,0 +1,46 @@ +#ifndef LWIPR_MBEDTLS_H +#define LWIPR_MBEDTLS_H + +#include "mbedtls/platform.h" +#include "mbedtls/net.h" +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ERR_TCP_SSL_INVALID_SSL -101 +#define ERR_TCP_SSL_INVALID_TCP -102 +#define ERR_TCP_SSL_INVALID_CLIENTFD -103 +#define ERR_TCP_SSL_INVALID_CLIENTFD_DATA -104 +#define ERR_TCP_SSL_INVALID_DATA -105 + +struct tcp_pcb; +struct pbuf; +struct tcp_ssl_pcb; + +typedef void (* tcp_ssl_data_cb_t)(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); +typedef void (* tcp_ssl_handshake_cb_t)(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); +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); +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); +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_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg); + +#ifdef __cplusplus +} +#endif + + +#endif // LWIPR_MBEDTLS_H From d4257e6af75aff8a778411afd4c02133048ca8d5 Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Thu, 25 Oct 2018 12:42:33 +0200 Subject: [PATCH 02/29] improved TLS support, removed some not needed debug statements. --- src/AsyncTCP.cpp | 38 +++--- src/AsyncTCP.h | 3 +- src/tcp_mbedtls.c | 300 +++++++++++++++++++++++++--------------------- src/tcp_mbedtls.h | 3 +- 4 files changed, 185 insertions(+), 159 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 3e1ede9..9b57063 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -215,7 +215,6 @@ static int8_t _tcp_poll(void * arg, struct tcp_pcb * pcb) { } static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) { - log_i("_tcp_recv"); lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); e->event = LWIP_TCP_RECV; e->arg = arg; @@ -229,7 +228,6 @@ static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_ } static int8_t _tcp_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { - log_e("_tcp_sent"); lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); e->event = LWIP_TCP_SENT; e->arg = arg; @@ -520,7 +518,6 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other){ int8_t AsyncClient::_connected(void* pcb, int8_t err){ _pcb = reinterpret_cast(pcb); - log_i("error: %d", err); if(_pcb){ _rx_last_packet = millis(); _pcb_busy = false; @@ -529,12 +526,11 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ tcp_poll(_pcb, &_tcp_poll, 1); if(_pcb_secure){ - tcp_ssl_arg(_pcb, this); - log_e("_pcb: 0x%x", _pcb); - if(tcp_ssl_new_client(_pcb) < 0){ + if(tcp_ssl_new_client(_pcb, _hostname.empty() ? NULL : _hostname.c_str()) < 0){ + log_e("closing...."); return _close(); } - + tcp_ssl_arg(_pcb, this); tcp_ssl_data(_pcb, &_s_data); tcp_ssl_handshake(_pcb, &_s_handshake); @@ -550,6 +546,7 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ int8_t AsyncClient::_close(){ int8_t err = ERR_OK; + if(_pcb) { if(_pcb_secure){ tcp_ssl_free(_pcb); @@ -597,7 +594,6 @@ void AsyncClient::_ssl_error(int8_t err){ } int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { - log_e("_sent"); if (_pcb_secure && !_handshake_done) return ERR_OK; @@ -611,7 +607,6 @@ int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { } int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { - log_e("_recv"); if(!_pcb || pcb != _pcb){ log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); if(pb){ @@ -689,6 +684,13 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ _close(); return ERR_OK; } + // if(!_handshake_done) { + // _in_lwip_thread = true; + // tcp_ssl_handshake_step(pcb); + // _in_lwip_thread = false; + + // return ERR_OK; + // } // Everything is fine if(_poll_cb) _poll_cb(_poll_cb_arg, this); @@ -697,6 +699,9 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ void AsyncClient::_dns_found(struct ip_addr *ipaddr){ _in_lwip_thread = true; + Serial.print("ip: "); + Serial.println(ipaddr_ntoa(ipaddr)); + if(ipaddr){ connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port, _pcb_secure); } else { @@ -716,19 +721,15 @@ bool AsyncClient::operator==(const AsyncClient &other) { bool AsyncClient::connect(const char* host, uint16_t port, bool secure){ ip_addr_t addr; - Serial.print("connect ip: "); - Serial.println(secure); - err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_s_dns_found, this); if(err == ERR_OK) { - Serial.print("connect a ip: "); - Serial.println(secure); + // @ToDo: do this at one place. + _hostname = std::string(host); return connect(IPAddress(addr.u_addr.ip4.addr), port, secure); } else if(err == ERR_INPROGRESS) { - - Serial.print("connect b ip: "); - Serial.println(secure); + // @ToDo: do this at one place. + _hostname = std::string(host); _connect_port = port; _pcb_secure = secure; @@ -811,6 +812,7 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { //_tx_unacked_len += sent; return sent; } + log_i("add: tcp_ssl_write: %d", sent); _close(); return 0; } @@ -1041,8 +1043,6 @@ void AsyncClient::onPoll(AcConnectHandler cb, void* arg){ _poll_cb_arg = arg; } - -// void AsyncClient::_s_dns_found(const char * name, ip_addr_t * ipaddr, void * arg){ void AsyncClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg){ if(arg){ reinterpret_cast(arg)->_dns_found(ipaddr); diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index b8a417f..b68731f 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -50,7 +50,8 @@ struct ip_addr; class AsyncClient { protected: tcp_pcb* _pcb; - // sslclient_context* _ssl_context; + // char* _hostname; + std::string _hostname; AcConnectHandler _connect_cb; void* _connect_cb_arg; diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index db9db21..bd06a6b 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -1,9 +1,17 @@ +#define DEBUG true +#define CONFIG_MBEDTLS_DEBUG true +#define DEBUG_LEVEL 4 + #include "tcp_mbedtls.h" #include "lwip/tcp.h" #include "mbedtls/debug.h" +#include "mbedtls/esp_debug.h" #include -#define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) +#include "mbedtls/debug.h" + +// #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) +#define TCP_SSL_DEBUG(...) static const char pers[] = "esp32-tls"; @@ -21,6 +29,49 @@ static int handle_error(int err) return err; } +static void my_debug(void *ctx, int level, const char *file, int line, + const char *str) + { + const char *p, *basename; + (void) ctx; + + /* Extract basename from file */ + for(p = basename = file; *p != '\0'; p++) { + if(*p == '/' || *p == '\\') { + basename = p + 1; + } + } + + mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); + } + + /** + * Certificate verification callback for mbed TLS + * Here we only use it to display information on each cert in the chain + */ + static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) + { + const uint32_t buf_size = 1024; + //char *buf = new char[buf_size]; + char buf[buf_size]; + (void) data; + + mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); + mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); + mbedtls_printf("%s", buf); + + if (*flags == 0) + mbedtls_printf("No verification issue for this certificate\n"); + else + { + mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); + mbedtls_printf("%s\n", buf); + } + + //delete[] buf; + return 0; + } + static uint8_t _tcp_ssl_has_client = 0; struct tcp_ssl_pcb { @@ -36,7 +87,7 @@ struct tcp_ssl_pcb { tcp_ssl_data_cb_t on_data; tcp_ssl_handshake_cb_t on_handshake; tcp_ssl_error_cb_t on_error; - int last_wr; + size_t last_wr; struct pbuf *tcp_pbuf; int pbuf_offset; struct tcp_ssl_pcb* next; @@ -48,20 +99,23 @@ static tcp_ssl_t * tcp_ssl_array = NULL; static int tcp_ssl_next_fd = 0; int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { - tcp_ssl_t *fd_data = (tcp_ssl_t*)ctx; + tcp_ssl_t *tcp_ssl = (tcp_ssl_t*)ctx; uint8_t *read_buf = NULL; uint8_t *pread_buf = NULL; u16_t recv_len = 0; - if(fd_data->tcp_pbuf == NULL || fd_data->tcp_pbuf->tot_len == 0) { - return 0; + TCP_SSL_DEBUG("tcp_ssl_recv: ctx: 0x%X, buf: 0x%X, len: %d\n", ctx, buf, len); + + if(tcp_ssl->tcp_pbuf == NULL || tcp_ssl->tcp_pbuf->tot_len == 0) { + TCP_SSL_DEBUG("tcp_ssl_recv: not yet ready to read: tcp_pbuf: 0x%X.\n", tcp_ssl->tcp_pbuf); + return MBEDTLS_ERR_SSL_WANT_READ; } - read_buf =(uint8_t*)calloc(fd_data->tcp_pbuf->len + 1, sizeof(uint8_t)); + read_buf =(uint8_t*)calloc(tcp_ssl->tcp_pbuf->len + 1, sizeof(uint8_t)); pread_buf = read_buf; if (pread_buf != NULL){ - recv_len = pbuf_copy_partial(fd_data->tcp_pbuf, read_buf, len, fd_data->pbuf_offset); - fd_data->pbuf_offset += recv_len; + recv_len = pbuf_copy_partial(tcp_ssl->tcp_pbuf, read_buf, len, tcp_ssl->pbuf_offset); + tcp_ssl->pbuf_offset += recv_len; } if (recv_len != 0) { @@ -78,7 +132,9 @@ int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { return recv_len; } -int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t size) { +int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { + TCP_SSL_DEBUG("tcp_ssl_send: ctx: 0x%X, buf: 0x%X, len: %d\n", ctx, buf, len); + if(ctx == NULL) { TCP_SSL_DEBUG("tcp_ssl_send: no context set\n"); return -1; @@ -89,19 +145,44 @@ int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t size) { return -1; } - tcp_ssl_t *tcp = (tcp_ssl_t*)ctx; - - size_t room = tcp_sndbuf(tcp->tcp); - size_t will_send = (room < size) ? room : size; + tcp_ssl_t *tcp_ssl = (tcp_ssl_t*)ctx; + size_t tcp_len = 0; + int err = ERR_OK; - TCP_SSL_DEBUG("len: %d, has space? %d\n", size, room); + if (tcp_sndbuf(tcp_ssl->tcp) < len) { + tcp_len = tcp_sndbuf(tcp_ssl->tcp); + if(tcp_len == 0) { + TCP_SSL_DEBUG("ax_port_write: tcp_sndbuf is zero: %d\n", len); + return ERR_MEM; + } + } else { + tcp_len = len; + } + + if (tcp_len > 2 * tcp_ssl->tcp->mss) { + tcp_len = 2 * tcp_ssl->tcp->mss; + } - int8_t ret = tcp_write(tcp->tcp, buf, will_send, 0); - if(ret == ERR_OK) { - TCP_SSL_DEBUG("oki!\n"); + err = tcp_write(tcp_ssl->tcp, buf, tcp_len, TCP_WRITE_FLAG_COPY); + if(err < ERR_OK) { + if (err == ERR_MEM) { + TCP_SSL_DEBUG("ax_port_write: No memory %d (%d)\n", tcp_len, len); + return err; + } + TCP_SSL_DEBUG("ax_port_write: tcp_write error: %d\n", err); + return err; + } else if (err == ERR_OK) { + //TCP_SSL_DEBUG("ax_port_write: tcp_output: %d / %d\n", tcp_len, len); + err = tcp_output(tcp_ssl->tcp); + if(err != ERR_OK) { + TCP_SSL_DEBUG("ax_port_write: tcp_output err: %d\n", err); + return err; + } } - return will_send; + tcp_ssl->last_wr += tcp_len; + + return tcp_len; } uint8_t tcp_ssl_has_client() { @@ -128,9 +209,7 @@ tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) { new_item->tcp_pbuf = NULL; new_item->pbuf_offset = 0; new_item->next = NULL; - // new_item->ssl_ctx = NULL; - // new_item->ssl = NULL; - new_item->fd = tcp_ssl_next_fd++; + // new_item->fd = tcp_ssl_next_fd++; if(tcp_ssl_array == NULL){ tcp_ssl_array = new_item; @@ -141,7 +220,6 @@ tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) { item->next = new_item; } - TCP_SSL_DEBUG("tcp_ssl_new: %d: 0x%x\n", new_item->fd, tcp); return new_item; } @@ -156,7 +234,7 @@ tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) { return item; } -int tcp_ssl_new_client(struct tcp_pcb *tcp) { +int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { tcp_ssl_t* tcp_ssl; TCP_SSL_DEBUG("tcp_ssl_new_client\n"); @@ -166,7 +244,6 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp) { } if(tcp_ssl_get(tcp) != NULL){ - TCP_SSL_DEBUG("tcp_ssl_new_client: tcp_ssl already exists\n"); return -1; } @@ -175,7 +252,6 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp) { return -1; } - // mbedtls_entropy_init(&tcp_ssl->entropy_ctx); mbedtls_ctr_drbg_init(&tcp_ssl->drbg_ctx); mbedtls_ssl_init(&tcp_ssl->ssl_ctx); @@ -190,42 +266,50 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp) { MBEDTLS_SSL_PRESET_DEFAULT)) { TCP_SSL_DEBUG("error setting SSL config.\n"); - // tcp_ssl_free(tcp); + tcp_ssl_free(tcp); return -1; } + // @ToDo: allow setting a root CA, for now just not verify. mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); + // mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + int ret = 0; - // @ToDo: there's no hostname at this stage, set it later. - // if((ret = mbedtls_ssl_set_hostname(&ctx->ssl_ctx, host)) != 0){ - // return handle_error(ret); - // } + // @ToDo: required? + if(hostname != NULL) { + TCP_SSL_DEBUG("setting the hostname: %s\n", hostname); + if((ret = mbedtls_ssl_set_hostname(&tcp_ssl->ssl_ctx, hostname)) != 0){ + 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_verify(&tcp_ssl->ssl_conf, my_verify, NULL); + mbedtls_ssl_conf_dbg(&tcp_ssl->ssl_conf, my_debug, NULL); + //mbedtls_debug_set_threshold(2); + if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) { - // tcp_ssl_free(tcp); + 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 ); mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, (void*)tcp_ssl, tcp_ssl_send, tcp_ssl_recv, NULL); // mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, &tcp_ssl->fd, mbedtls_net_send, mbedtls_net_recv, NULL ); - // @ToDo: do we need this here? + // Start handshake. ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); - handle_error(ret); - TCP_SSL_DEBUG("ret mbedtls_ssl_handshake: %d, want read: %d, write: %d\n", ret, MBEDTLS_ERR_SSL_WANT_READ, MBEDTLS_ERR_SSL_WANT_WRITE); - // if (ret != 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - // TCP_SSL_DEBUG("tcp_ssl_new_client: mbedtls_ssl_handshake: %d.\n", ret); - // // if(tcp_ssl->on_error) - // // tcp_ssl->on_error(tcp_ssl->arg, tcp_ssl->tcp, ret); - // } - - TCP_SSL_DEBUG("end tcp_ssl_new_client %d.\n", tcp_ssl->fd); + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + TCP_SSL_DEBUG("handshake error!\n"); + return handle_error(ret); + } - return tcp_ssl->fd; + // @ToDo: don't need the fd? + return ERR_OK; } int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { @@ -235,7 +319,7 @@ int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - TCP_SSL_DEBUG("tcp_ssl_write %x\n, state: %d\n", tcp_ssl, tcp->state); + TCP_SSL_DEBUG("tcp_ssl_write %x, state: %d\n", tcp_ssl, tcp->state); if(tcp_ssl == NULL){ TCP_SSL_DEBUG("tcp_ssl_write: tcp_ssl is NULL\n"); @@ -250,10 +334,13 @@ int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { TCP_SSL_DEBUG("tcp_ssl_write: %u -> %d (%d)\r\n", len, tcp_ssl->last_wr, rc); if (rc < 0){ - // @ToDO: ??? - // if(rc != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE) { + TCP_SSL_DEBUG("about to call mbedtls_ssl_write\n"); + return handle_error(rc); + } + if(rc != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { TCP_SSL_DEBUG("tcp_ssl_write error: %d\r\n", rc); - // } + } return rc; } @@ -266,14 +353,15 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { if(tcp == NULL) { return -1; } - tcp_ssl_t* fd_data = NULL; + tcp_ssl_t* tcp_ssl = NULL; int read_bytes = 0; int total_bytes = 0; - uint8_t *read_buf; + static const size_t read_buf_size = 1024; + uint8_t read_buf[read_buf_size]; - fd_data = tcp_ssl_get(tcp); - if(fd_data == NULL) { + tcp_ssl = tcp_ssl_get(tcp); + if(tcp_ssl == NULL) { TCP_SSL_DEBUG("tcp_ssl_read: tcp_ssl is NULL\n"); return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; } @@ -285,103 +373,47 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { TCP_SSL_DEBUG("READY TO READ SOME DATA\n"); - fd_data->tcp_pbuf = p; - fd_data->pbuf_offset = 0; - - do { - if(fd_data->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { - TCP_SSL_DEBUG("start handshake: %d\n", fd_data->ssl_ctx.state); - int ret = mbedtls_ssl_handshake(&fd_data->ssl_ctx); + tcp_ssl->tcp_pbuf = p; + tcp_ssl->pbuf_offset = 0; + + do { + if(tcp_ssl->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { + TCP_SSL_DEBUG("start handshake: %d\n", tcp_ssl->ssl_ctx.state); + int ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); + handle_error(ret); if(ret == 0) { - if(fd_data->on_handshake) - fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data); + TCP_SSL_DEBUG("Protocol is %s Ciphersuite is %s\n", mbedtls_ssl_get_version(&tcp_ssl->ssl_ctx), mbedtls_ssl_get_ciphersuite(&tcp_ssl->ssl_ctx)); + + if(tcp_ssl->on_handshake) + 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) { // if(fd_data->on_error) // fd_data->on_error(fd_data->arg, fd_data->tcp, ret); - TCP_SSL_DEBUG("handshake error: %d\n", ret); // return ret; - //return 0; + return 0; } } else { - uint8_t readb[1024]; - read_bytes = mbedtls_ssl_read(&fd_data->ssl_ctx, &readb, 1024); - TCP_SSL_DEBUG("start read: %d.\n", read_bytes); - if(read_bytes < 0) { - handle_error(read_bytes); + read_bytes = mbedtls_ssl_read(&tcp_ssl->ssl_ctx, &read_buf, read_buf_size); + TCP_SSL_DEBUG("tcp_ssl_read: read_bytes: %d\n", read_bytes); + if(read_bytes < 0) { // SSL_OK + // MBEDTLS_ERR_SSL_CONN_EOF if(read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); } total_bytes = read_bytes; break; - } else if(read_bytes > 0) { - if(fd_data->on_data){ - fd_data->on_data(fd_data->arg, tcp, &readb, read_bytes); + } else if(read_bytes > 0){ + if(tcp_ssl->on_data){ + tcp_ssl->on_data(tcp_ssl->arg, tcp, read_buf, read_bytes); } total_bytes+= read_bytes; } } - // if(fd_data->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { - // TCP_SSL_DEBUG("start handshake.\n"); - // int ret = mbedtls_ssl_handshake(&fd_data->ssl_ctx); - // if(ret == 0) { - // if(fd_data->on_handshake) - // fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data); - // } else if(ret != MBEDTLS_ERR_SSL_WANT_READ || ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - // if(fd_data->on_error) - // fd_data->on_error(fd_data->arg, fd_data->tcp, ret); - // return ret; - // } - // } - // // @TODO: FIX! - // read_bytes = mbedtls_ssl_read(&fd_data->ssl_ctx, &read_buf, 0); - // TCP_SSL_DEBUG("tcp_ssl_ssl_read: read_bytes: %d (%d)\n", read_bytes, MBEDTLS_SSL_HANDSHAKE_OVER); - // if(read_bytes < 0) { - // handle_error(read_bytes); - // if(read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { - // TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); - // } - // total_bytes = read_bytes; - // break; - // } else if(read_bytes > 0){ - // if(fd_data->on_data){ - // fd_data->on_data(fd_data->arg, tcp, read_buf, read_bytes); - // } - // total_bytes+= read_bytes; - // } else { - // TCP_SSL_DEBUG("start handshake? %d.\n", fd_data->ssl_ctx.state); - // if(fd_data->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { - // TCP_SSL_DEBUG("start handshake.\n"); - // int ret = mbedtls_ssl_handshake(&fd_data->ssl_ctx); - // if(ret == 0) { - // if(fd_data->on_handshake) - // fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data); - // } else if(ret != MBEDTLS_ERR_SSL_WANT_READ || ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - // if(fd_data->on_error) - // fd_data->on_error(fd_data->arg, fd_data->tcp, ret); - // return ret; - // } - // } - // } - } while (p->tot_len - fd_data->pbuf_offset > 0); - - // OLD - // if(fd_data->handshake != MBEDTLS_SSL_HANDSHAKE_OVER) { - // fd_data->handshake = mbedtls_ssl_handshake(&fd_data->ssl_ctx); - // if(fd_data->handshake == 0){ - // TCP_SSL_DEBUG("tcp_ssl_read: handshake OK\n"); - // if(fd_data->on_handshake) - // fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data); - // } else if(fd_data->handshake != 0){ - // TCP_SSL_DEBUG("tcp_ssl_read: handshake error: %d\n", fd_data->handshake); - // if(fd_data->on_error) - // fd_data->on_error(fd_data->arg, fd_data->tcp, fd_data->handshake); - // return fd_data->handshake; - // } - // } + } while (p->tot_len - tcp_ssl->pbuf_offset > 0); tcp_recved(tcp, p->tot_len); - fd_data->tcp_pbuf = NULL; + tcp_ssl->tcp_pbuf = NULL; pbuf_free(p); TCP_SSL_DEBUG("tcp_ssl_read: eof: %d\n", total_bytes); @@ -390,20 +422,16 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { } int tcp_ssl_free(struct tcp_pcb *tcp) { - TCP_SSL_DEBUG("tcp_ssl_free: 1\n"); if(tcp == NULL) { return -1; } - TCP_SSL_DEBUG("tcp_ssl_free: 2\n"); tcp_ssl_t * item = tcp_ssl_array; - TCP_SSL_DEBUG("tcp_ssl_free: 2a 0x%x\n", item); if(item->tcp == tcp){ - TCP_SSL_DEBUG("tcp_ssl_free: 3\n"); tcp_ssl_array = tcp_ssl_array->next; if(item->tcp_pbuf != NULL) { pbuf_free(item->tcp_pbuf); } - TCP_SSL_DEBUG("tcp_ssl_free: %d\n", item->fd); + TCP_SSL_DEBUG("tcp_ssl_free: %x\n", item); mbedtls_ssl_free(&item->ssl_ctx); mbedtls_ssl_config_free(&item->ssl_conf); mbedtls_ctr_drbg_free(&item->drbg_ctx); @@ -412,21 +440,17 @@ int tcp_ssl_free(struct tcp_pcb *tcp) { return 0; } - TCP_SSL_DEBUG("tcp_ssl_free: 4\n"); while(item->next && item->next->tcp != tcp) item = item->next; - TCP_SSL_DEBUG("tcp_ssl_free: 5\n"); if(item->next == NULL){ return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found } - TCP_SSL_DEBUG("tcp_ssl_free: 6\n"); tcp_ssl_t * i = item->next; item->next = i->next; if(i->tcp_pbuf != NULL){ pbuf_free(i->tcp_pbuf); } - TCP_SSL_DEBUG("tcp_ssl_free: %d\n", i->fd); mbedtls_ssl_free(&i->ssl_ctx); mbedtls_ssl_config_free(&i->ssl_conf); mbedtls_ctr_drbg_free(&i->drbg_ctx); diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index 20d1504..b950331 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -28,9 +28,10 @@ typedef void (* tcp_ssl_handshake_cb_t)(void *arg, struct tcp_pcb *tcp, struct t 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); +int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname); 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); +int tcp_ssl_handshake_step(struct tcp_pcb *tcp); 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); From eeff609d2debfadf930bca388e15ccdb387a7c0f Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Thu, 25 Oct 2018 16:13:38 +0200 Subject: [PATCH 03/29] removed some more logging. --- src/AsyncTCP.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 9b57063..1fc31f0 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -1099,7 +1099,6 @@ int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){ } void AsyncClient::_s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len){ - log_i("_s_data"); AsyncClient *c = reinterpret_cast(arg); if(c->_recv_cb) c->_recv_cb(c->_recv_cb_arg, c, data, len); @@ -1107,7 +1106,6 @@ void AsyncClient::_s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t void AsyncClient::_s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl){ AsyncClient *c = reinterpret_cast(arg); - log_i("_s_handshake: done!"); c->_handshake_done = true; if(c->_connect_cb) c->_connect_cb(c->_connect_cb_arg, c); From f2127a087eb7e58e0c7cd02b773b610b5664691d Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Mon, 5 Nov 2018 22:18:27 +0100 Subject: [PATCH 04/29] getting there, seems to start working, there are still some issues with the handshake failing. --- src/AsyncTCP.h | 1 - src/tcp_mbedtls.c | 20 +++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index b68731f..ccbc9df 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -50,7 +50,6 @@ struct ip_addr; class AsyncClient { protected: tcp_pcb* _pcb; - // char* _hostname; std::string _hostname; AcConnectHandler _connect_cb; diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index bd06a6b..a8910f6 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -116,6 +116,8 @@ int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { if (pread_buf != NULL){ recv_len = pbuf_copy_partial(tcp_ssl->tcp_pbuf, read_buf, len, tcp_ssl->pbuf_offset); tcp_ssl->pbuf_offset += recv_len; + + TCP_SSL_DEBUG("tcp_ssl_recv: recv_len: %d, pbuf_offset: %d.\n", recv_len, tcp_ssl->pbuf_offset); } if (recv_len != 0) { @@ -129,6 +131,10 @@ int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { free(pread_buf); pread_buf = NULL; + if(recv_len == 0) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + return recv_len; } @@ -290,7 +296,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { mbedtls_ssl_conf_verify(&tcp_ssl->ssl_conf, my_verify, NULL); mbedtls_ssl_conf_dbg(&tcp_ssl->ssl_conf, my_debug, NULL); - //mbedtls_debug_set_threshold(2); + // mbedtls_debug_set_threshold(2); if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) { tcp_ssl_free(tcp); @@ -308,7 +314,6 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { return handle_error(ret); } - // @ToDo: don't need the fd? return ERR_OK; } @@ -386,12 +391,13 @@ 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); - } else if(ret != MBEDTLS_ERR_SSL_WANT_READ || ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - // if(fd_data->on_error) - // fd_data->on_error(fd_data->arg, fd_data->tcp, ret); + } else if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { TCP_SSL_DEBUG("handshake error: %d\n", ret); - // return ret; - return 0; + + if(tcp_ssl->on_error) + tcp_ssl->on_error(tcp_ssl->arg, tcp_ssl->tcp, ret); + + return ret; } } else { read_bytes = mbedtls_ssl_read(&tcp_ssl->ssl_ctx, &read_buf, read_buf_size); From 3c9fbd96de2c85f4909bede2a2f62b56c22ea954 Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Tue, 20 Nov 2018 12:00:19 +0100 Subject: [PATCH 05/29] add fix for reading larger amounts of data. --- src/AsyncTCP.cpp | 20 ++++----- src/tcp_mbedtls.c | 103 +++++++++++++++++++++------------------------- 2 files changed, 55 insertions(+), 68 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 1fc31f0..483b077 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -626,11 +626,12 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { // log_i("_recv: %d\n", pb->tot_len); int read_bytes = tcp_ssl_read(pcb, pb); if(read_bytes < 0){ - if (read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { - log_e("_recv err: %d\n", read_bytes); - _close(); - } - //return read_bytes; + if (read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + log_e("_recv err: %d\n", read_bytes); + _close(); + } + + //return read_bytes; } return ERR_OK; } @@ -684,13 +685,6 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ _close(); return ERR_OK; } - // if(!_handshake_done) { - // _in_lwip_thread = true; - // tcp_ssl_handshake_step(pcb); - // _in_lwip_thread = false; - - // return ERR_OK; - // } // Everything is fine if(_poll_cb) _poll_cb(_poll_cb_arg, this); @@ -812,7 +806,7 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { //_tx_unacked_len += sent; return sent; } - log_i("add: tcp_ssl_write: %d", sent); + //log_i("add: tcp_ssl_write: %d", sent); _close(); return 0; } diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index a8910f6..2fe306b 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -7,7 +7,6 @@ #include "mbedtls/debug.h" #include "mbedtls/esp_debug.h" #include - #include "mbedtls/debug.h" // #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) @@ -15,8 +14,7 @@ static const char pers[] = "esp32-tls"; -static int handle_error(int err) -{ +static int handle_error(int err) { if(err == -30848){ return err; } @@ -29,48 +27,45 @@ static int handle_error(int err) return err; } -static void my_debug(void *ctx, int level, const char *file, int line, - const char *str) +// static void my_debug(void *ctx, int level, const char *file, int line, const char *str) { +// const char *p, *basename; +// (void) ctx; + +// /* Extract basename from file */ +// for(p = basename = file; *p != '\0'; p++) { +// if(*p == '/' || *p == '\\') { +// basename = p + 1; +// } +// } + +// mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); +// } + +/** + * Certificate verification callback for mbed TLS + * Here we only use it to display information on each cert in the chain + */ +static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) { + const uint32_t buf_size = 1024; + //char *buf = new char[buf_size]; + char buf[buf_size]; + (void) data; + + mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); + mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); + mbedtls_printf("%s", buf); + + if (*flags == 0) + mbedtls_printf("No verification issue for this certificate\n"); + else { - const char *p, *basename; - (void) ctx; - - /* Extract basename from file */ - for(p = basename = file; *p != '\0'; p++) { - if(*p == '/' || *p == '\\') { - basename = p + 1; - } - } - - mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); + mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); + mbedtls_printf("%s\n", buf); } - /** - * Certificate verification callback for mbed TLS - * Here we only use it to display information on each cert in the chain - */ - static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) - { - const uint32_t buf_size = 1024; - //char *buf = new char[buf_size]; - char buf[buf_size]; - (void) data; - - mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); - mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); - mbedtls_printf("%s", buf); - - if (*flags == 0) - mbedtls_printf("No verification issue for this certificate\n"); - else - { - mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); - mbedtls_printf("%s\n", buf); - } - - //delete[] buf; - return 0; - } + //delete[] buf; + return 0; +} static uint8_t _tcp_ssl_has_client = 0; @@ -104,8 +99,6 @@ int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { uint8_t *pread_buf = NULL; u16_t recv_len = 0; - TCP_SSL_DEBUG("tcp_ssl_recv: ctx: 0x%X, buf: 0x%X, len: %d\n", ctx, buf, len); - if(tcp_ssl->tcp_pbuf == NULL || tcp_ssl->tcp_pbuf->tot_len == 0) { TCP_SSL_DEBUG("tcp_ssl_recv: not yet ready to read: tcp_pbuf: 0x%X.\n", tcp_ssl->tcp_pbuf); return MBEDTLS_ERR_SSL_WANT_READ; @@ -115,11 +108,11 @@ int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { pread_buf = read_buf; if (pread_buf != NULL){ recv_len = pbuf_copy_partial(tcp_ssl->tcp_pbuf, read_buf, len, tcp_ssl->pbuf_offset); + TCP_SSL_DEBUG("tcp_ssl_recv: len: %d, recv_len: %d, pbuf_offset: %d, tcp_pbuf len: %d.\n", len, recv_len, tcp_ssl->pbuf_offset, tcp_ssl->tcp_pbuf->len); tcp_ssl->pbuf_offset += recv_len; - - TCP_SSL_DEBUG("tcp_ssl_recv: recv_len: %d, pbuf_offset: %d.\n", recv_len, tcp_ssl->pbuf_offset); } + // Note: why copy again? if (recv_len != 0) { memcpy(buf, read_buf, recv_len); } @@ -295,7 +288,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { mbedtls_ssl_conf_rng(&tcp_ssl->ssl_conf, mbedtls_ctr_drbg_random, &tcp_ssl->drbg_ctx); mbedtls_ssl_conf_verify(&tcp_ssl->ssl_conf, my_verify, NULL); - mbedtls_ssl_conf_dbg(&tcp_ssl->ssl_conf, my_debug, NULL); + // mbedtls_ssl_conf_dbg(&tcp_ssl->ssl_conf, my_debug, NULL); // mbedtls_debug_set_threshold(2); if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) { @@ -324,8 +317,6 @@ int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - TCP_SSL_DEBUG("tcp_ssl_write %x, state: %d\n", tcp_ssl, tcp->state); - if(tcp_ssl == NULL){ TCP_SSL_DEBUG("tcp_ssl_write: tcp_ssl is NULL\n"); return 0; @@ -353,8 +344,6 @@ 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) { - TCP_SSL_DEBUG("tcp_ssl_ssl_read\n"); - if(tcp == NULL) { return -1; } @@ -397,13 +386,17 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { if(tcp_ssl->on_error) tcp_ssl->on_error(tcp_ssl->arg, tcp_ssl->tcp, ret); - return ret; + break; } } else { read_bytes = mbedtls_ssl_read(&tcp_ssl->ssl_ctx, &read_buf, read_buf_size); - TCP_SSL_DEBUG("tcp_ssl_read: read_bytes: %d\n", read_bytes); + TCP_SSL_DEBUG("tcp_ssl_read: read_bytes: %d, total_bytes: %d, tot_len: %d, pbuf_offset: %d\r\n", read_bytes, total_bytes, p->tot_len, tcp_ssl->pbuf_offset); + // TCP_SSL_DEBUG("tcp_ssl_read: %s<-\n", read_buf); if(read_bytes < 0) { // SSL_OK - // MBEDTLS_ERR_SSL_CONN_EOF + if(read_bytes == MBEDTLS_ERR_SSL_WANT_READ) { + TCP_SSL_DEBUG("tcp_ssl_read: need to wait\n"); + break; + } if(read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); } @@ -416,7 +409,7 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { total_bytes+= read_bytes; } } - } while (p->tot_len - tcp_ssl->pbuf_offset > 0); + } while (p->tot_len - tcp_ssl->pbuf_offset > 0 || read_bytes > 0); tcp_recved(tcp, p->tot_len); tcp_ssl->tcp_pbuf = NULL; From d501a90b68ede0c4e054c1f5b13db4f07f7b0a41 Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Thu, 29 Nov 2018 14:36:04 +0100 Subject: [PATCH 06/29] some code clean-up --- src/tcp_mbedtls.c | 76 +++++++++++++---------------------------------- 1 file changed, 21 insertions(+), 55 deletions(-) diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 2fe306b..3c07312 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -27,45 +27,29 @@ static int handle_error(int err) { return err; } -// static void my_debug(void *ctx, int level, const char *file, int line, const char *str) { -// const char *p, *basename; -// (void) ctx; - -// /* Extract basename from file */ -// for(p = basename = file; *p != '\0'; p++) { -// if(*p == '/' || *p == '\\') { -// basename = p + 1; -// } -// } - -// mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); -// } - /** * Certificate verification callback for mbed TLS * Here we only use it to display information on each cert in the chain */ -static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) { - const uint32_t buf_size = 1024; - //char *buf = new char[buf_size]; - char buf[buf_size]; - (void) data; - - mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); - mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); - mbedtls_printf("%s", buf); - - if (*flags == 0) - mbedtls_printf("No verification issue for this certificate\n"); - else - { - mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); - mbedtls_printf("%s\n", buf); - } +// static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) { +// const uint32_t buf_size = 1024; +// char buf[buf_size]; +// (void) data; + +// mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); +// mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); +// mbedtls_printf("%s", buf); + +// if (*flags == 0) +// mbedtls_printf("No verification issue for this certificate\n"); +// else +// { +// mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); +// mbedtls_printf("%s\n", buf); +// } - //delete[] buf; - return 0; -} +// return 0; +// } static uint8_t _tcp_ssl_has_client = 0; @@ -208,7 +192,6 @@ tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) { new_item->tcp_pbuf = NULL; new_item->pbuf_offset = 0; new_item->next = NULL; - // new_item->fd = tcp_ssl_next_fd++; if(tcp_ssl_array == NULL){ tcp_ssl_array = new_item; @@ -275,7 +258,6 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { int ret = 0; - // @ToDo: required? if(hostname != NULL) { TCP_SSL_DEBUG("setting the hostname: %s\n", hostname); if((ret = mbedtls_ssl_set_hostname(&tcp_ssl->ssl_ctx, hostname)) != 0){ @@ -286,10 +268,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { } mbedtls_ssl_conf_rng(&tcp_ssl->ssl_conf, mbedtls_ctr_drbg_random, &tcp_ssl->drbg_ctx); - - mbedtls_ssl_conf_verify(&tcp_ssl->ssl_conf, my_verify, NULL); - // mbedtls_ssl_conf_dbg(&tcp_ssl->ssl_conf, my_debug, NULL); - // mbedtls_debug_set_threshold(2); + // mbedtls_ssl_conf_verify(&tcp_ssl->ssl_conf, my_verify, NULL); if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) { tcp_ssl_free(tcp); @@ -298,7 +277,6 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { } mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, (void*)tcp_ssl, tcp_ssl_send, tcp_ssl_recv, NULL); - // mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, &tcp_ssl->fd, mbedtls_net_send, mbedtls_net_recv, NULL ); // Start handshake. ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); @@ -318,17 +296,13 @@ int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); if(tcp_ssl == NULL){ - TCP_SSL_DEBUG("tcp_ssl_write: tcp_ssl is NULL\n"); return 0; } tcp_ssl->last_wr = 0; - TCP_SSL_DEBUG("about to call mbedtls_ssl_write\n"); int rc = mbedtls_ssl_write(&tcp_ssl->ssl_ctx, data, len); - TCP_SSL_DEBUG("tcp_ssl_write: %u -> %d (%d)\r\n", len, tcp_ssl->last_wr, rc); - if (rc < 0){ if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE) { TCP_SSL_DEBUG("about to call mbedtls_ssl_write\n"); @@ -356,16 +330,14 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { tcp_ssl = tcp_ssl_get(tcp); if(tcp_ssl == NULL) { - TCP_SSL_DEBUG("tcp_ssl_read: tcp_ssl is NULL\n"); return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; } if(p == NULL) { - TCP_SSL_DEBUG("tcp_ssl_read:p == NULL\n"); return ERR_TCP_SSL_INVALID_DATA; } - TCP_SSL_DEBUG("READY TO READ SOME DATA\n"); + // TCP_SSL_DEBUG("READY TO READ SOME DATA\n"); tcp_ssl->tcp_pbuf = p; tcp_ssl->pbuf_offset = 0; @@ -391,13 +363,10 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { } else { read_bytes = mbedtls_ssl_read(&tcp_ssl->ssl_ctx, &read_buf, read_buf_size); TCP_SSL_DEBUG("tcp_ssl_read: read_bytes: %d, total_bytes: %d, tot_len: %d, pbuf_offset: %d\r\n", read_bytes, total_bytes, p->tot_len, tcp_ssl->pbuf_offset); - // TCP_SSL_DEBUG("tcp_ssl_read: %s<-\n", read_buf); if(read_bytes < 0) { // SSL_OK if(read_bytes == MBEDTLS_ERR_SSL_WANT_READ) { - TCP_SSL_DEBUG("tcp_ssl_read: need to wait\n"); break; - } - if(read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + } else if(read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); } total_bytes = read_bytes; @@ -415,8 +384,6 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { tcp_ssl->tcp_pbuf = NULL; pbuf_free(p); - TCP_SSL_DEBUG("tcp_ssl_read: eof: %d\n", total_bytes); - return total_bytes; } @@ -430,7 +397,6 @@ int tcp_ssl_free(struct tcp_pcb *tcp) { if(item->tcp_pbuf != NULL) { pbuf_free(item->tcp_pbuf); } - TCP_SSL_DEBUG("tcp_ssl_free: %x\n", item); mbedtls_ssl_free(&item->ssl_ctx); mbedtls_ssl_config_free(&item->ssl_conf); mbedtls_ctr_drbg_free(&item->drbg_ctx); From c9dd60883460869acba5c1dba1f57816bc48ed08 Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Thu, 29 Nov 2018 14:37:17 +0100 Subject: [PATCH 07/29] more code clean-up. --- src/tcp_mbedtls.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 3c07312..4bdb723 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -1,13 +1,8 @@ -#define DEBUG true -#define CONFIG_MBEDTLS_DEBUG true -#define DEBUG_LEVEL 4 - #include "tcp_mbedtls.h" #include "lwip/tcp.h" #include "mbedtls/debug.h" #include "mbedtls/esp_debug.h" #include -#include "mbedtls/debug.h" // #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) #define TCP_SSL_DEBUG(...) From 52e550beb6bab9890099c445dffe14b4bb443055 Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Wed, 9 Jan 2019 13:01:16 +0100 Subject: [PATCH 08/29] revert IDF changes, so it works with the latest stable IDF. --- src/AsyncTCP.cpp | 85 ++++++++++++++++++------------------------------ src/AsyncTCP.h | 10 +++--- 2 files changed, 37 insertions(+), 58 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 483b077..6e7ddf6 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -256,7 +256,7 @@ static void _tcp_error(void * arg, int8_t err) { #include "lwip/priv/tcpip_priv.h" typedef struct { - struct tcpip_api_call_data call; + struct tcpip_api_call call; tcp_pcb * pcb; int8_t err; union { @@ -279,7 +279,7 @@ typedef struct { }; } tcp_api_call_t; -static err_t _tcp_output_api(struct tcpip_api_call_data *api_call_msg){ +static err_t _tcp_output_api(struct tcpip_api_call *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_output(msg->pcb); return msg->err; @@ -288,11 +288,11 @@ static err_t _tcp_output_api(struct tcpip_api_call_data *api_call_msg){ static esp_err_t _tcp_output(tcp_pcb * pcb) { tcp_api_call_t msg; msg.pcb = pcb; - tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); + tcpip_api_call(_tcp_output_api, (struct tcpip_api_call*)&msg); return msg.err; } -static err_t _tcp_write_api(struct tcpip_api_call_data *api_call_msg){ +static err_t _tcp_write_api(struct tcpip_api_call *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); return msg->err; @@ -304,11 +304,11 @@ static esp_err_t _tcp_write(tcp_pcb * pcb, const char* data, size_t size, uint8_ msg.write.data = data; msg.write.size = size; msg.write.apiflags = apiflags; - tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); + tcpip_api_call(_tcp_write_api, (struct tcpip_api_call*)&msg); return msg.err; } -static err_t _tcp_recved_api(struct tcpip_api_call_data *api_call_msg){ +static err_t _tcp_recved_api(struct tcpip_api_call *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = 0; tcp_recved(msg->pcb, msg->received); @@ -319,11 +319,11 @@ static esp_err_t _tcp_recved(tcp_pcb * pcb, size_t len) { tcp_api_call_t msg; msg.pcb = pcb; msg.received = len; - tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); + tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call*)&msg); return msg.err; } -static err_t _tcp_connect_api(struct tcpip_api_call_data *api_call_msg){ +static err_t _tcp_connect_api(struct tcpip_api_call *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); return msg->err; @@ -335,11 +335,11 @@ static esp_err_t _tcp_connect(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port, tc msg.connect.addr = addr; msg.connect.port = port; msg.connect.cb = cb; - tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); + tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call*)&msg); return msg.err; } -static err_t _tcp_close_api(struct tcpip_api_call_data *api_call_msg){ +static err_t _tcp_close_api(struct tcpip_api_call *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_close(msg->pcb); return msg->err; @@ -349,11 +349,11 @@ static esp_err_t _tcp_close(tcp_pcb * pcb) { tcp_api_call_t msg; msg.pcb = pcb; //ets_printf("close 0x%08x\n", (uint32_t)pcb); - tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); + tcpip_api_call(_tcp_close_api, (struct tcpip_api_call*)&msg); return msg.err; } -static err_t _tcp_abort_api(struct tcpip_api_call_data *api_call_msg){ +static err_t _tcp_abort_api(struct tcpip_api_call *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = 0; tcp_abort(msg->pcb); @@ -364,11 +364,11 @@ static esp_err_t _tcp_abort(tcp_pcb * pcb) { tcp_api_call_t msg; msg.pcb = pcb; //ets_printf("abort 0x%08x\n", (uint32_t)pcb); - tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); + tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call*)&msg); return msg.err; } -static err_t _tcp_bind_api(struct tcpip_api_call_data *api_call_msg){ +static err_t _tcp_bind_api(struct tcpip_api_call *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); return msg->err; @@ -379,11 +379,11 @@ static esp_err_t _tcp_bind(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port) { msg.pcb = pcb; msg.bind.addr = addr; msg.bind.port = port; - tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); + tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call*)&msg); return msg.err; } -static err_t _tcp_listen_api(struct tcpip_api_call_data *api_call_msg){ +static err_t _tcp_listen_api(struct tcpip_api_call *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = 0; msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); @@ -394,7 +394,7 @@ static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { tcp_api_call_t msg; msg.pcb = pcb; msg.backlog = backlog?backlog:0xFF; - tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); + tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call*)&msg); return msg.pcb; } #define _tcp_listen(p) _tcp_listen_with_backlog(p, 0xFF); @@ -565,7 +565,7 @@ int8_t AsyncClient::_close(){ err = abort(); } _pcb = NULL; - // _tcp_clear_events(this); + _tcp_clear_events(this); if(_discard_cb) _discard_cb(_discard_cb_arg, this); } @@ -608,13 +608,12 @@ int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { if(!_pcb || pcb != _pcb){ - log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - if(pb){ - pbuf_free(pb); - } - return ERR_OK; - } - + log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + if(pb){ + pbuf_free(pb); + } + return ERR_OK; + } _in_lwip_thread = false; if(pb == NULL){ return _close(); @@ -691,7 +690,7 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ return ERR_OK; } -void AsyncClient::_dns_found(struct ip_addr *ipaddr){ +void AsyncClient::_dns_found(ip_addr_t *ipaddr){ _in_lwip_thread = true; Serial.print("ip: "); Serial.println(ipaddr_ntoa(ipaddr)); @@ -1037,20 +1036,12 @@ void AsyncClient::onPoll(AcConnectHandler cb, void* arg){ _poll_cb_arg = arg; } -void AsyncClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg){ - if(arg){ - reinterpret_cast(arg)->_dns_found(ipaddr); - } else { - log_e("Bad Arg: 0x%08x", arg); - } +void AsyncClient::_s_dns_found(const char * name, ip_addr_t * ipaddr, void * arg){ + reinterpret_cast(arg)->_dns_found(ipaddr); } int8_t AsyncClient::_s_poll(void * arg, struct tcp_pcb * pcb) { - if(arg && pcb){ - reinterpret_cast(arg)->_poll(pcb); - } else { - log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); - } + reinterpret_cast(arg)->_poll(pcb); return ERR_OK; } @@ -1059,7 +1050,7 @@ int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, i reinterpret_cast(arg)->_recv(pcb, pb, err); } else { if(pb){ - pbuf_free(pb); + pbuf_free(pb); } log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); } @@ -1067,28 +1058,16 @@ int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, i } int8_t AsyncClient::_s_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { - if(arg && pcb){ - reinterpret_cast(arg)->_sent(pcb, len); - } else { - log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); - } + reinterpret_cast(arg)->_sent(pcb, len); return ERR_OK; } void AsyncClient::_s_error(void * arg, int8_t err) { - if(arg){ - reinterpret_cast(arg)->_error(err); - } else { - log_e("Bad Arg: 0x%08x", arg); - } + reinterpret_cast(arg)->_error(err); } int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){ - if(arg && pcb){ - reinterpret_cast(arg)->_connected(pcb, err); - } else { - log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); - } + reinterpret_cast(arg)->_connected(pcb, err); return ERR_OK; } diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index ccbc9df..87d5f31 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -45,7 +45,7 @@ typedef std::function AcPacketHandle typedef std::function AcTimeoutHandler; struct tcp_pcb; -struct ip_addr; +struct _ip_addr; class AsyncClient { protected: @@ -87,7 +87,7 @@ class AsyncClient { void _ssl_error(int8_t err); int8_t _poll(tcp_pcb* pcb); int8_t _sent(tcp_pcb* pcb, uint16_t len); - void _dns_found(struct ip_addr *ipaddr); + void _dns_found(struct _ip_addr *ipaddr); static void _s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); static void _s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); static void _s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err); @@ -116,13 +116,13 @@ class AsyncClient { bool canSend();//ack is not pending size_t space(); - size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending + size_t add(const char* data, size_t size, uint8_t apiflags=0);//add for sending bool send();//send all data added with the method above size_t ack(size_t len); //ack data that you have not acked using the method below void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData size_t write(const char* data); - size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true + size_t write(const char* data, size_t size, uint8_t apiflags=0); //only when canSend() == true uint8_t state(); bool connecting(); @@ -169,7 +169,7 @@ class AsyncClient { static void _s_error(void *arg, int8_t err); static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); static int8_t _s_connected(void* arg, void* tpcb, int8_t err); - static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); + static void _s_dns_found(const char *name, struct _ip_addr *ipaddr, void *arg); bool _in_lwip_thread; }; From 001ae064576da7dcf7067d175e2eae231ec86a5b Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Thu, 10 Jan 2019 12:07:42 +0100 Subject: [PATCH 09/29] Not a fan of defines, but to keep things in line with the esp8266 version added all SSL stuff between defines. In order to enable SSL add -DASYNC_TCP_SSL_ENABLED to your build flags. --- src/AsyncTCP.cpp | 64 ++++++++++++++++++++++++++++++++++++++--------- src/AsyncTCP.h | 13 ++++++++++ src/tcp_mbedtls.c | 4 +++ src/tcp_mbedtls.h | 3 +++ 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 6e7ddf6..f4a4fad 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -421,6 +421,10 @@ AsyncClient::AsyncClient(tcp_pcb* pcb) , _timeout_cb(0) , _timeout_cb_arg(0) , _pcb_busy(false) +#if ASYNC_TCP_SSL_ENABLED +, _pcb_secure(false) +, _handshake_done(true) +#endif // ASYNC_TCP_SSL_ENABLED , _pcb_sent_at(0) , _close_pcb(false) , _ack_pcb(true) @@ -449,7 +453,11 @@ AsyncClient::~AsyncClient(){ _close(); } +#if ASYNC_TCP_SSL_ENABLED bool AsyncClient::connect(IPAddress ip, uint16_t port, bool secure){ +#else +bool AsyncClient::connect(IPAddress ip, uint16_t port){ +#endif // ASYNC_TCP_SSL_ENABLED if (_pcb){ log_w("already connected, state %d", _pcb->state); return false; @@ -469,19 +477,16 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port, bool secure){ return false; } - Serial.print("connect res ip: "); - Serial.println(secure); - +#if ASYNC_TCP_SSL_ENABLED _pcb_secure = secure; _handshake_done = !secure; +#endif // ASYNC_TCP_SSL_ENABLED tcp_arg(pcb, this); tcp_err(pcb, &_tcp_error); if(_in_lwip_thread){ - log_i("tcp_connect-1: _in_lwip_thread: %d", _in_lwip_thread); tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); } else { - log_i("tcp_connect-2: _in_lwip_thread: %d", _in_lwip_thread); _tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); } return true; @@ -500,6 +505,7 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other){ tcp_err(_pcb, &_tcp_error); tcp_poll(_pcb, &_tcp_poll, 1); +#if ASYNC_TCP_SSL_ENABLED if(tcp_ssl_has(_pcb)){ _pcb_secure = true; _handshake_done = false; @@ -511,6 +517,7 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other){ _pcb_secure = false; _handshake_done = true; } +#endif // ASYNC_TCP_SSL_ENABLED } return *this; } @@ -524,7 +531,7 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ tcp_recv(_pcb, &_tcp_recv); tcp_sent(_pcb, &_tcp_sent); tcp_poll(_pcb, &_tcp_poll, 1); - +#if ASYNC_TCP_SSL_ENABLED if(_pcb_secure){ if(tcp_ssl_new_client(_pcb, _hostname.empty() ? NULL : _hostname.c_str()) < 0){ log_e("closing...."); @@ -536,11 +543,18 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ tcp_ssl_handshake(_pcb, &_s_handshake); tcp_ssl_err(_pcb, &_s_ssl_error); } +#endif // ASYNC_TCP_SSL_ENABLED } + _in_lwip_thread = true; +#if ASYNC_TCP_SSL_ENABLED if(!_pcb_secure && _connect_cb) +#else + if(_connect_cb) +#endif // ASYNC_TCP_SSL_ENABLED _connect_cb(_connect_cb_arg, this); _in_lwip_thread = false; + return ERR_OK; } @@ -548,9 +562,11 @@ int8_t AsyncClient::_close(){ int8_t err = ERR_OK; if(_pcb) { +#if ASYNC_TCP_SSL_ENABLED if(_pcb_secure){ tcp_ssl_free(_pcb); } +#endif // ASYNC_TCP_SSL_ENABLED tcp_arg(_pcb, NULL); tcp_sent(_pcb, NULL); tcp_recv(_pcb, NULL); @@ -588,14 +604,18 @@ void AsyncClient::_error(int8_t err) { _discard_cb(_discard_cb_arg, this); } +#if ASYNC_TCP_SSL_ENABLED void AsyncClient::_ssl_error(int8_t err){ if(_error_cb) _error_cb(_error_cb_arg, this, err+64); } +#endif // ASYNC_TCP_SSL_ENABLED int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { +#if ASYNC_TCP_SSL_ENABLED if (_pcb_secure && !_handshake_done) return ERR_OK; +#endif // ASYNC_TCP_SSL_ENABLED _in_lwip_thread = false; _rx_last_packet = millis(); @@ -621,6 +641,7 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { while(pb != NULL){ _rx_last_packet = millis(); +#if ASYNC_TCP_SSL_ENABLED if(_pcb_secure){ // log_i("_recv: %d\n", pb->tot_len); int read_bytes = tcp_ssl_read(pcb, pb); @@ -634,6 +655,7 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { } return ERR_OK; } +#endif // ASYNC_TCP_SSL_ENABLED //we should not ack before we assimilate the data //log_i("%u", pb->len); //Serial.write((const uint8_t *)pb->payload, pb->len); @@ -680,10 +702,12 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ _close(); return ERR_OK; } +#if ASYNC_TCP_SSL_ENABLED if(_pcb_secure && !_handshake_done && (now - _rx_last_packet) >= 2000){ _close(); return ERR_OK; } +#endif // ASYNC_TCP_SSL_ENABLED // Everything is fine if(_poll_cb) _poll_cb(_poll_cb_arg, this); @@ -696,7 +720,11 @@ void AsyncClient::_dns_found(ip_addr_t *ipaddr){ Serial.println(ipaddr_ntoa(ipaddr)); if(ipaddr){ +#if ASYNC_TCP_SSL_ENABLED connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port, _pcb_secure); +#else + connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port); +#endif // ASYNC_TCP_SSL_ENABLED } else { log_e("dns fail"); if(_error_cb) @@ -711,22 +739,29 @@ bool AsyncClient::operator==(const AsyncClient &other) { return _pcb == other._pcb; } +#if ASYNC_TCP_SSL_ENABLED bool AsyncClient::connect(const char* host, uint16_t port, bool secure){ +#else +bool AsyncClient::connect(const char* host, uint16_t port){ +#endif // ASYNC_TCP_SSL_ENABLED ip_addr_t addr; err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_s_dns_found, this); if(err == ERR_OK) { - // @ToDo: do this at one place. - _hostname = std::string(host); + _hostname = host; +#if ASYNC_TCP_SSL_ENABLED return connect(IPAddress(addr.u_addr.ip4.addr), port, secure); +#else + return connect(IPAddress(addr.u_addr.ip4.addr), port); +#endif // ASYNC_TCP_SSL_ENABLED } else if(err == ERR_INPROGRESS) { - // @ToDo: do this at one place. - _hostname = std::string(host); - + _hostname = host; _connect_port = port; +#if ASYNC_TCP_SSL_ENABLED _pcb_secure = secure; _handshake_done = !secure; +#endif // ASYNC_TCP_SSL_ENABLED return true; } log_e("error: %d", err); @@ -798,6 +833,7 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { size_t room = space(); if(!room) return 0; +#if ASYNC_TCP_SSL_ENABLED if(_pcb_secure){ int sent = tcp_ssl_write(_pcb, (uint8_t*)data, size); if(sent >= 0){ @@ -809,6 +845,7 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { _close(); return 0; } +#endif // ASYNC_TCP_SSL_ENABLED size_t will_send = (room < size) ? room : size; int8_t err = ERR_OK; if(_in_lwip_thread){ @@ -822,9 +859,10 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { } bool AsyncClient::send(){ +#if ASYNC_TCP_SSL_ENABLED if(_pcb_secure) return true; - +#endif // ASYNC_TCP_SSL_ENABLED int8_t err = ERR_OK; if(_in_lwip_thread){ err = tcp_output(_pcb); @@ -1071,6 +1109,7 @@ int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){ return ERR_OK; } +#if ASYNC_TCP_SSL_ENABLED void AsyncClient::_s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len){ AsyncClient *c = reinterpret_cast(arg); if(c->_recv_cb) @@ -1087,6 +1126,7 @@ void AsyncClient::_s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pc void AsyncClient::_s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err){ reinterpret_cast(arg)->_ssl_error(err); } +#endif // ASYNC_TCP_SSL_ENABLED const char * AsyncClient::errorToString(int8_t error){ switch(error){ diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 87d5f31..f2aecbd 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -24,6 +24,7 @@ #include "IPAddress.h" #include +#include #include extern "C" { #include "freertos/semphr.h" @@ -70,8 +71,10 @@ class AsyncClient { void* _poll_cb_arg; bool _pcb_busy; +#if ASYNC_TCP_SSL_ENABLED bool _pcb_secure; bool _handshake_done; +#endif // ASYNC_TCP_SSL_ENABLED uint32_t _pcb_sent_at; bool _close_pcb; bool _ack_pcb; @@ -84,13 +87,17 @@ class AsyncClient { int8_t _close(); int8_t _connected(void* pcb, int8_t err); void _error(int8_t err); +#if ASYNC_TCP_SSL_ENABLED void _ssl_error(int8_t err); +#endif // ASYNC_TCP_SSL_ENABLED int8_t _poll(tcp_pcb* pcb); int8_t _sent(tcp_pcb* pcb, uint16_t len); void _dns_found(struct _ip_addr *ipaddr); +#if ASYNC_TCP_SSL_ENABLED static void _s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); static void _s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); static void _s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err); +#endif // ASYNC_TCP_SSL_ENABLED public: AsyncClient* prev; @@ -107,8 +114,14 @@ class AsyncClient { bool operator!=(const AsyncClient &other) { return !(*this == other); } + +#if ASYNC_TCP_SSL_ENABLED bool connect(IPAddress ip, uint16_t port, bool secure = false); bool connect(const char* host, uint16_t port, bool secure = false); +#else + bool connect(IPAddress ip, uint16_t port); + bool connect(const char* host, uint16_t port); +#endif // ASYNC_TCP_SSL_ENABLED void close(bool now = false); void stop(); int8_t abort(); diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 4bdb723..155b5d3 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -1,3 +1,5 @@ +#if ASYNC_TCP_SSL_ENABLED + #include "tcp_mbedtls.h" #include "lwip/tcp.h" #include "mbedtls/debug.h" @@ -451,3 +453,5 @@ void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg){ item->on_error = arg; } } + +#endif // ASYNC_TCP_SSL_ENABLED \ No newline at end of file diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index b950331..42c7487 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -1,6 +1,8 @@ #ifndef LWIPR_MBEDTLS_H #define LWIPR_MBEDTLS_H +#if ASYNC_TCP_SSL_ENABLED + #include "mbedtls/platform.h" #include "mbedtls/net.h" #include "mbedtls/debug.h" @@ -45,3 +47,4 @@ void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg); #endif // LWIPR_MBEDTLS_H +#endif // ASYNC_TCP_SSL_ENABLED From 9f7a918a3e014cafabeea384e5116986d66f586e Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Fri, 11 Jan 2019 11:45:04 +0100 Subject: [PATCH 10/29] clean-up --- src/AsyncTCP.cpp | 2 -- src/AsyncTCP.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index f4a4fad..d8cbbcd 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -716,8 +716,6 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ void AsyncClient::_dns_found(ip_addr_t *ipaddr){ _in_lwip_thread = true; - Serial.print("ip: "); - Serial.println(ipaddr_ntoa(ipaddr)); if(ipaddr){ #if ASYNC_TCP_SSL_ENABLED diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index f2aecbd..baf7e4d 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -22,6 +22,7 @@ #ifndef ASYNCTCP_H_ #define ASYNCTCP_H_ +#include "Arduino.h" #include "IPAddress.h" #include #include From 518767335f786eb3487aebd32c16e0fe89f63244 Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Fri, 11 Jan 2019 11:49:26 +0100 Subject: [PATCH 11/29] merge origin/idf-update into mbed-tls, as it's now part of the latest released version of arduino-esp32... --- src/AsyncTCP.cpp | 85 ++++++++++++++++++++++++++++++------------------ src/AsyncTCP.h | 10 +++--- 2 files changed, 58 insertions(+), 37 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index d8cbbcd..4caab4a 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -256,7 +256,7 @@ static void _tcp_error(void * arg, int8_t err) { #include "lwip/priv/tcpip_priv.h" typedef struct { - struct tcpip_api_call call; + struct tcpip_api_call_data call; tcp_pcb * pcb; int8_t err; union { @@ -279,7 +279,7 @@ typedef struct { }; } tcp_api_call_t; -static err_t _tcp_output_api(struct tcpip_api_call *api_call_msg){ +static err_t _tcp_output_api(struct tcpip_api_call_data *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_output(msg->pcb); return msg->err; @@ -288,11 +288,11 @@ static err_t _tcp_output_api(struct tcpip_api_call *api_call_msg){ static esp_err_t _tcp_output(tcp_pcb * pcb) { tcp_api_call_t msg; msg.pcb = pcb; - tcpip_api_call(_tcp_output_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); return msg.err; } -static err_t _tcp_write_api(struct tcpip_api_call *api_call_msg){ +static err_t _tcp_write_api(struct tcpip_api_call_data *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); return msg->err; @@ -304,11 +304,11 @@ static esp_err_t _tcp_write(tcp_pcb * pcb, const char* data, size_t size, uint8_ msg.write.data = data; msg.write.size = size; msg.write.apiflags = apiflags; - tcpip_api_call(_tcp_write_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); return msg.err; } -static err_t _tcp_recved_api(struct tcpip_api_call *api_call_msg){ +static err_t _tcp_recved_api(struct tcpip_api_call_data *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = 0; tcp_recved(msg->pcb, msg->received); @@ -319,11 +319,11 @@ static esp_err_t _tcp_recved(tcp_pcb * pcb, size_t len) { tcp_api_call_t msg; msg.pcb = pcb; msg.received = len; - tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); return msg.err; } -static err_t _tcp_connect_api(struct tcpip_api_call *api_call_msg){ +static err_t _tcp_connect_api(struct tcpip_api_call_data *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); return msg->err; @@ -335,11 +335,11 @@ static esp_err_t _tcp_connect(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port, tc msg.connect.addr = addr; msg.connect.port = port; msg.connect.cb = cb; - tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); return msg.err; } -static err_t _tcp_close_api(struct tcpip_api_call *api_call_msg){ +static err_t _tcp_close_api(struct tcpip_api_call_data *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_close(msg->pcb); return msg->err; @@ -349,11 +349,11 @@ static esp_err_t _tcp_close(tcp_pcb * pcb) { tcp_api_call_t msg; msg.pcb = pcb; //ets_printf("close 0x%08x\n", (uint32_t)pcb); - tcpip_api_call(_tcp_close_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); return msg.err; } -static err_t _tcp_abort_api(struct tcpip_api_call *api_call_msg){ +static err_t _tcp_abort_api(struct tcpip_api_call_data *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = 0; tcp_abort(msg->pcb); @@ -364,11 +364,11 @@ static esp_err_t _tcp_abort(tcp_pcb * pcb) { tcp_api_call_t msg; msg.pcb = pcb; //ets_printf("abort 0x%08x\n", (uint32_t)pcb); - tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); return msg.err; } -static err_t _tcp_bind_api(struct tcpip_api_call *api_call_msg){ +static err_t _tcp_bind_api(struct tcpip_api_call_data *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); return msg->err; @@ -379,11 +379,11 @@ static esp_err_t _tcp_bind(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port) { msg.pcb = pcb; msg.bind.addr = addr; msg.bind.port = port; - tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); return msg.err; } -static err_t _tcp_listen_api(struct tcpip_api_call *api_call_msg){ +static err_t _tcp_listen_api(struct tcpip_api_call_data *api_call_msg){ tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; msg->err = 0; msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); @@ -394,7 +394,7 @@ static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { tcp_api_call_t msg; msg.pcb = pcb; msg.backlog = backlog?backlog:0xFF; - tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call*)&msg); + tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); return msg.pcb; } #define _tcp_listen(p) _tcp_listen_with_backlog(p, 0xFF); @@ -581,7 +581,7 @@ int8_t AsyncClient::_close(){ err = abort(); } _pcb = NULL; - _tcp_clear_events(this); + // _tcp_clear_events(this); if(_discard_cb) _discard_cb(_discard_cb_arg, this); } @@ -628,12 +628,13 @@ int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { if(!_pcb || pcb != _pcb){ - log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - if(pb){ - pbuf_free(pb); - } - return ERR_OK; - } + log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + if(pb){ + pbuf_free(pb); + } + return ERR_OK; + } + _in_lwip_thread = false; if(pb == NULL){ return _close(); @@ -714,7 +715,7 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ return ERR_OK; } -void AsyncClient::_dns_found(ip_addr_t *ipaddr){ +void AsyncClient::_dns_found(struct ip_addr *ipaddr){ _in_lwip_thread = true; if(ipaddr){ @@ -1072,12 +1073,20 @@ void AsyncClient::onPoll(AcConnectHandler cb, void* arg){ _poll_cb_arg = arg; } -void AsyncClient::_s_dns_found(const char * name, ip_addr_t * ipaddr, void * arg){ - reinterpret_cast(arg)->_dns_found(ipaddr); +void AsyncClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg){ + if(arg){ + reinterpret_cast(arg)->_dns_found(ipaddr); + } else { + log_e("Bad Arg: 0x%08x", arg); + } } int8_t AsyncClient::_s_poll(void * arg, struct tcp_pcb * pcb) { - reinterpret_cast(arg)->_poll(pcb); + if(arg && pcb){ + reinterpret_cast(arg)->_poll(pcb); + } else { + log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); + } return ERR_OK; } @@ -1086,7 +1095,7 @@ int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, i reinterpret_cast(arg)->_recv(pcb, pb, err); } else { if(pb){ - pbuf_free(pb); + pbuf_free(pb); } log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); } @@ -1094,16 +1103,28 @@ int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, i } int8_t AsyncClient::_s_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { - reinterpret_cast(arg)->_sent(pcb, len); + if(arg && pcb){ + reinterpret_cast(arg)->_sent(pcb, len); + } else { + log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); + } return ERR_OK; } void AsyncClient::_s_error(void * arg, int8_t err) { - reinterpret_cast(arg)->_error(err); + if(arg){ + reinterpret_cast(arg)->_error(err); + } else { + log_e("Bad Arg: 0x%08x", arg); + } } int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){ - reinterpret_cast(arg)->_connected(pcb, err); + if(arg && pcb){ + reinterpret_cast(arg)->_connected(pcb, err); + } else { + log_e("Bad Args: 0x%08x 0x%08x", arg, pcb); + } return ERR_OK; } diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index baf7e4d..2ade859 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -47,7 +47,7 @@ typedef std::function AcPacketHandle typedef std::function AcTimeoutHandler; struct tcp_pcb; -struct _ip_addr; +struct ip_addr; class AsyncClient { protected: @@ -93,7 +93,7 @@ class AsyncClient { #endif // ASYNC_TCP_SSL_ENABLED int8_t _poll(tcp_pcb* pcb); int8_t _sent(tcp_pcb* pcb, uint16_t len); - void _dns_found(struct _ip_addr *ipaddr); + void _dns_found(struct ip_addr *ipaddr); #if ASYNC_TCP_SSL_ENABLED static void _s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); static void _s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); @@ -130,13 +130,13 @@ class AsyncClient { bool canSend();//ack is not pending size_t space(); - size_t add(const char* data, size_t size, uint8_t apiflags=0);//add for sending + size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending bool send();//send all data added with the method above size_t ack(size_t len); //ack data that you have not acked using the method below void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData size_t write(const char* data); - size_t write(const char* data, size_t size, uint8_t apiflags=0); //only when canSend() == true + size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true uint8_t state(); bool connecting(); @@ -183,7 +183,7 @@ class AsyncClient { static void _s_error(void *arg, int8_t err); static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); static int8_t _s_connected(void* arg, void* tpcb, int8_t err); - static void _s_dns_found(const char *name, struct _ip_addr *ipaddr, void *arg); + static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); bool _in_lwip_thread; }; From d631d7d1ecd359afd28f84bc6e23665e33d82bbb Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Tue, 15 Jan 2019 18:07:39 +0100 Subject: [PATCH 12/29] add some dummy functions so we can compile when the ESP Async WebServer library is also used. --- src/AsyncTCP.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 2ade859..3c73f61 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -188,6 +188,10 @@ class AsyncClient { bool _in_lwip_thread; }; +#if ASYNC_TCP_SSL_ENABLED +typedef std::function AcSSlFileHandler; +#endif + class AsyncServer { protected: uint16_t _port; @@ -204,6 +208,11 @@ class AsyncServer { AsyncServer(uint16_t port); ~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) {}; +#endif void begin(); void end(); void setNoDelay(bool nodelay); From 78f952eaccc1c6ac00caf23a6d63cb12968ba643 Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Thu, 17 Jan 2019 22:59:27 +0100 Subject: [PATCH 13/29] allow setting a root CA. --- src/AsyncTCP.cpp | 10 ++++++++-- src/AsyncTCP.h | 3 +++ src/tcp_mbedtls.c | 31 ++++++++++++++++++++++--------- src/tcp_mbedtls.h | 2 +- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index ab909d7..6bfa73e 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -408,7 +408,6 @@ static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { /* Async TCP Client */ - AsyncClient::AsyncClient(tcp_pcb* pcb) : _connect_cb(0) , _connect_cb_arg(0) @@ -426,6 +425,8 @@ AsyncClient::AsyncClient(tcp_pcb* pcb) , _timeout_cb_arg(0) , _pcb_busy(false) #if ASYNC_TCP_SSL_ENABLED +, _root_ca(NULL) +, _root_ca_len(0) , _pcb_secure(false) , _handshake_done(true) #endif // ASYNC_TCP_SSL_ENABLED @@ -496,6 +497,11 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){ return true; } +void AsyncClient::setRootCa(const char* rootca, const size_t len) { + _root_ca = (char*)rootca; + _root_ca_len = len; +} + AsyncClient& AsyncClient::operator=(const AsyncClient& other){ if (_pcb) _close(); @@ -537,7 +543,7 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ tcp_poll(_pcb, &_tcp_poll, 1); #if ASYNC_TCP_SSL_ENABLED if(_pcb_secure){ - if(tcp_ssl_new_client(_pcb, _hostname.empty() ? NULL : _hostname.c_str()) < 0){ + if(tcp_ssl_new_client(_pcb, _hostname.empty() ? NULL : _hostname.c_str(), _root_ca, _root_ca_len) < 0){ log_e("closing...."); return _close(); } diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 3c73f61..117f7ff 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -73,6 +73,8 @@ class AsyncClient { bool _pcb_busy; #if ASYNC_TCP_SSL_ENABLED + size_t _root_ca_len; + char* _root_ca; bool _pcb_secure; bool _handshake_done; #endif // ASYNC_TCP_SSL_ENABLED @@ -119,6 +121,7 @@ class AsyncClient { #if ASYNC_TCP_SSL_ENABLED bool connect(IPAddress ip, uint16_t port, bool secure = false); bool connect(const char* host, uint16_t port, bool secure = false); + void setRootCa(const char* rootca, const size_t len); #else bool connect(IPAddress ip, uint16_t port); bool connect(const char* host, uint16_t port); diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 155b5d3..0a653ac 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -6,8 +6,8 @@ #include "mbedtls/esp_debug.h" #include -// #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) -#define TCP_SSL_DEBUG(...) +#define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) +// #define TCP_SSL_DEBUG(...) static const char pers[] = "esp32-tls"; @@ -55,6 +55,7 @@ struct tcp_ssl_pcb { int fd; mbedtls_ssl_context ssl_ctx; mbedtls_ssl_config ssl_conf; + mbedtls_x509_crt ca_cert; mbedtls_ctr_drbg_context drbg_ctx; mbedtls_entropy_context entropy_ctx; uint8_t type; @@ -213,11 +214,9 @@ tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) { return item; } -int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { +int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname, const char* root_ca, const size_t root_ca_len) { tcp_ssl_t* tcp_ssl; - TCP_SSL_DEBUG("tcp_ssl_new_client\n"); - if(tcp == NULL) { return -1; } @@ -249,12 +248,26 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname) { return -1; } - // @ToDo: allow setting a root CA, for now just not verify. - mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); - // mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); - int ret = 0; + if(root_ca != NULL && root_ca_len > 0) { + TCP_SSL_DEBUG("setting the root ca.\n"); + + mbedtls_x509_crt_init(&tcp_ssl->ca_cert); + + mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); + + ret = mbedtls_x509_crt_parse(&tcp_ssl->ca_cert, (const unsigned char *)root_ca, root_ca_len); + if( ret < 0 ){ + TCP_SSL_DEBUG(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return handle_error(ret); + } + + mbedtls_ssl_conf_ca_chain(&tcp_ssl->ssl_conf, &tcp_ssl->ca_cert, NULL); + } else { + mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + } + if(hostname != NULL) { TCP_SSL_DEBUG("setting the hostname: %s\n", hostname); if((ret = mbedtls_ssl_set_hostname(&tcp_ssl->ssl_ctx, hostname)) != 0){ diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index 42c7487..ff0c9a8 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -30,7 +30,7 @@ typedef void (* tcp_ssl_handshake_cb_t)(void *arg, struct tcp_pcb *tcp, struct t 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, const char* hostname); +int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname, const char* root_ca, const size_t root_ca_len); 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); int tcp_ssl_handshake_step(struct tcp_pcb *tcp); From 0879ba248d1afd51a36fe2deba35d179bddfa90e Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Thu, 17 Jan 2019 23:00:30 +0100 Subject: [PATCH 14/29] oops, set debug disabled as default again. --- src/tcp_mbedtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 0a653ac..9748614 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -6,8 +6,8 @@ #include "mbedtls/esp_debug.h" #include -#define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) -// #define TCP_SSL_DEBUG(...) +// #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) +#define TCP_SSL_DEBUG(...) static const char pers[] = "esp32-tls"; From ef5035738f84e3f89ac71b467626ee3620aa0650 Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Fri, 18 Jan 2019 13:28:45 +0100 Subject: [PATCH 15/29] add ASYNC_TCP_SSL_ENABLED around setRootCa call. --- src/AsyncTCP.cpp | 2 ++ src/tcp_mbedtls.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 6bfa73e..1fe7119 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -497,10 +497,12 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){ return true; } +#if ASYNC_TCP_SSL_ENABLED void AsyncClient::setRootCa(const char* rootca, const size_t len) { _root_ca = (char*)rootca; _root_ca_len = len; } +#endif // ASYNC_TCP_SSL_ENABLED AsyncClient& AsyncClient::operator=(const AsyncClient& other){ if (_pcb) diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 9748614..55ec9cc 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -356,7 +356,7 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { if(tcp_ssl->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { TCP_SSL_DEBUG("start handshake: %d\n", tcp_ssl->ssl_ctx.state); int ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); - handle_error(ret); + //handle_error(ret); if(ret == 0) { TCP_SSL_DEBUG("Protocol is %s Ciphersuite is %s\n", mbedtls_ssl_get_version(&tcp_ssl->ssl_ctx), mbedtls_ssl_get_ciphersuite(&tcp_ssl->ssl_ctx)); From 3fa9abf6059190078a58e4284ca8906b35485a1b Mon Sep 17 00:00:00 2001 From: Maarten Fremouw Date: Sat, 2 Mar 2019 12:24:22 +0100 Subject: [PATCH 16/29] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 023849b..8a11cea 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,6 @@ This library is the base for [ESPAsyncWebServer](https://github.com/me-no-dev/ES ## AsyncClient and AsyncServer The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. + +## TLS support +Support for TLS is added using mbed TLS, for now only the client part is supported. You can enable this by adding the flag ASYNC_TCP_SSL_ENABLED to your build flags (-DASYNC_TCP_SSL_ENABLED). If you'd like to set a root certificate you can use the setRootCa function on AsyncClient. Feel free to add support for the server side as well :-) From 5e06389b732b31a0b97625444fdf633f2ab179f7 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 16 Apr 2019 13:59:49 -0700 Subject: [PATCH 17/29] add support for pre-shared key TLS cipher suites --- README.md | 4 ++ src/AsyncTCP.cpp | 19 ++++++++-- src/AsyncTCP.h | 3 ++ src/tcp_mbedtls.c | 96 +++++++++++++++++++++++++++++++++++++++++++---- src/tcp_mbedtls.h | 1 + 5 files changed, 112 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8a11cea..2d6b743 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,7 @@ The base classes on which everything else is built. They expose all possible sce ## TLS support Support for TLS is added using mbed TLS, for now only the client part is supported. You can enable this by adding the flag ASYNC_TCP_SSL_ENABLED to your build flags (-DASYNC_TCP_SSL_ENABLED). If you'd like to set a root certificate you can use the setRootCa function on AsyncClient. Feel free to add support for the server side as well :-) + +In addition to the regular certificate based cipher suites there is also support for Pre-Shared Key +cipher suites. Use `setPsk` to define the PSK identifier and PSK itself. The PSK needs to be +provided in the form of a hex string (and easy way to generate a PSK is to use md5sum). diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 1fe7119..aaaeb51 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -429,6 +429,8 @@ AsyncClient::AsyncClient(tcp_pcb* pcb) , _root_ca_len(0) , _pcb_secure(false) , _handshake_done(true) +, _psk_ident(0) +, _psk(0) #endif // ASYNC_TCP_SSL_ENABLED , _pcb_sent_at(0) , _close_pcb(false) @@ -502,6 +504,11 @@ void AsyncClient::setRootCa(const char* rootca, const size_t len) { _root_ca = (char*)rootca; _root_ca_len = len; } + +void AsyncClient::setPsk(const char* psk_ident, const char* psk) { + _psk_ident = psk_ident; + _psk = psk; +} #endif // ASYNC_TCP_SSL_ENABLED AsyncClient& AsyncClient::operator=(const AsyncClient& other){ @@ -545,11 +552,17 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ tcp_poll(_pcb, &_tcp_poll, 1); #if ASYNC_TCP_SSL_ENABLED if(_pcb_secure){ - if(tcp_ssl_new_client(_pcb, _hostname.empty() ? NULL : _hostname.c_str(), _root_ca, _root_ca_len) < 0){ + bool err = false; + if(_root_ca) { + err = tcp_ssl_new_client(_pcb, _hostname.empty() ? NULL : _hostname.c_str(), _root_ca, _root_ca_len) < 0; + } else { + err = tcp_ssl_new_psk_client(_pcb, _psk_ident, _psk) < 0; + } + if (err) { log_e("closing...."); return _close(); } - + tcp_ssl_arg(_pcb, this); tcp_ssl_data(_pcb, &_s_data); tcp_ssl_handshake(_pcb, &_s_handshake); @@ -663,7 +676,7 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { log_e("_recv err: %d\n", read_bytes); _close(); } - + //return read_bytes; } return ERR_OK; diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 117f7ff..8117a63 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -77,6 +77,8 @@ class AsyncClient { char* _root_ca; bool _pcb_secure; bool _handshake_done; + const char* _psk_ident; + const char* _psk; #endif // ASYNC_TCP_SSL_ENABLED uint32_t _pcb_sent_at; bool _close_pcb; @@ -122,6 +124,7 @@ class AsyncClient { bool connect(IPAddress ip, uint16_t port, bool secure = false); bool connect(const char* host, uint16_t port, bool secure = false); void setRootCa(const char* rootca, const size_t len); + void setPsk(const char* psk_ident, const char* psk); #else bool connect(IPAddress ip, uint16_t port); bool connect(const char* host, uint16_t port); diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 55ec9cc..fc06d72 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -7,7 +7,7 @@ #include // #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) -#define TCP_SSL_DEBUG(...) +#define TCP_SSL_DEBUG(...) static const char pers[] = "esp32-tls"; @@ -139,7 +139,7 @@ int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { } else { tcp_len = len; } - + if (tcp_len > 2 * tcp_ssl->tcp->mss) { tcp_len = 2 * tcp_ssl->tcp->mss; } @@ -243,7 +243,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname, const char* ro MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) { TCP_SSL_DEBUG("error setting SSL config.\n"); - + tcp_ssl_free(tcp); return -1; } @@ -267,7 +267,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname, const char* ro } else { mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); } - + if(hostname != NULL) { TCP_SSL_DEBUG("setting the hostname: %s\n", hostname); if((ret = mbedtls_ssl_set_hostname(&tcp_ssl->ssl_ctx, hostname)) != 0){ @@ -282,7 +282,87 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname, const char* ro if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) { 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); + + // Start handshake. + 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, const char* psk_ident, const char* pskey) { + tcp_ssl_t* tcp_ssl; + + if(tcp == NULL) return -1; + if(tcp_ssl_get(tcp) != NULL) return -1; + + tcp_ssl = tcp_ssl_new(tcp); + if(tcp_ssl == NULL) return -1; + + mbedtls_entropy_init(&tcp_ssl->entropy_ctx); + mbedtls_ctr_drbg_init(&tcp_ssl->drbg_ctx); + mbedtls_ssl_init(&tcp_ssl->ssl_ctx); + mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); + + mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, + &tcp_ssl->entropy_ctx, (const unsigned char*)pers, strlen(pers)); + + if(mbedtls_ssl_config_defaults(&tcp_ssl->ssl_conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) { + TCP_SSL_DEBUG("error setting SSL config.\n"); + + tcp_ssl_free(tcp); + return -1; + } + + int ret = 0; + + TCP_SSL_DEBUG("setting the pre-shared key.\n"); + // convert PSK from hex string to binary + if ((strlen(pskey) & 1) != 0 || strlen(pskey) > 2*MBEDTLS_PSK_MAX_LEN) { + TCP_SSL_DEBUG(" failed\n ! pre-shared key not valid hex or too long\n\n"); + return -1; + } + unsigned char psk[MBEDTLS_PSK_MAX_LEN]; + size_t psk_len = strlen(pskey)/2; + for (int j=0; j= '0' && c <= '9') c -= '0'; + else if (c >= 'A' && c <= 'F') c -= 'A' - 10; + else if (c >= 'a' && c <= 'f') c -= 'a' - 10; + else return -1; + psk[j/2] = c<<4; + c = pskey[j+1]; + if (c >= '0' && c <= '9') c -= '0'; + else if (c >= 'A' && c <= 'F') c -= 'A' - 10; + else if (c >= 'a' && c <= 'f') c -= 'a' - 10; + else return -1; + psk[j/2] |= c; + } + // set mbedtls config + ret = mbedtls_ssl_conf_psk(&tcp_ssl->ssl_conf, psk, psk_len, + (const unsigned char *)psk_ident, strlen(psk_ident)); + if (ret != 0) { + TCP_SSL_DEBUG(" failed\n ! mbedtls_ssl_conf_psk returned -0x%x\n\n", -ret); + return handle_error(ret); + } + + mbedtls_ssl_conf_rng(&tcp_ssl->ssl_conf, mbedtls_ctr_drbg_random, &tcp_ssl->drbg_ctx); + + if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) { + tcp_ssl_free(tcp); + return handle_error(ret); } @@ -302,7 +382,7 @@ int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { if(tcp == NULL) { return -1; } - + tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); if(tcp_ssl == NULL){ @@ -351,7 +431,7 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { tcp_ssl->tcp_pbuf = p; tcp_ssl->pbuf_offset = 0; - + do { if(tcp_ssl->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) { TCP_SSL_DEBUG("start handshake: %d\n", tcp_ssl->ssl_ctx.state); @@ -467,4 +547,4 @@ void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg){ } } -#endif // ASYNC_TCP_SSL_ENABLED \ No newline at end of file +#endif // ASYNC_TCP_SSL_ENABLED diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index ff0c9a8..492c70b 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -31,6 +31,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, const char* hostname, const char* root_ca, const size_t root_ca_len); +int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, 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); int tcp_ssl_handshake_step(struct tcp_pcb *tcp); From 8e55be46458e34ab4342f97b612395b30b345458 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 25 Jun 2019 12:50:13 -0700 Subject: [PATCH 18/29] don't assign _hostname unless necessary --- src/AsyncTCP.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index e6f5f68..3e0744b 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -710,16 +710,16 @@ bool AsyncClient::connect(const char* host, uint16_t port){ ip_addr_t addr; err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); if(err == ERR_OK) { - _hostname = host; #if ASYNC_TCP_SSL_ENABLED + _hostname = host; return connect(IPAddress(addr.u_addr.ip4.addr), port, secure); #else return connect(IPAddress(addr.u_addr.ip4.addr), port); #endif // ASYNC_TCP_SSL_ENABLED } else if(err == ERR_INPROGRESS) { - _hostname = host; _connect_port = port; #if ASYNC_TCP_SSL_ENABLED + _hostname = host; _pcb_secure = secure; _handshake_done = !secure; #endif // ASYNC_TCP_SSL_ENABLED From 9cba86eeb9bed1ffe00c1fdbaec9c73a07c3caa4 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 25 Jul 2019 20:53:58 -0700 Subject: [PATCH 19/29] fix indentation; make SSL timeout a #define --- src/AsyncTCP.cpp | 2 +- src/AsyncTCP.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 3e0744b..a65efcf 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -689,7 +689,7 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){ #if ASYNC_TCP_SSL_ENABLED _pcb_secure = secure; - _handshake_done = !secure; + _handshake_done = !secure; #endif // ASYNC_TCP_SSL_ENABLED tcp_arg(pcb, this); diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 976e9c9..0e85a57 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -44,6 +44,7 @@ class AsyncClient; #define ASYNC_MAX_ACK_TIME 5000 #define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given) #define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react. +#define SSL_HANDSHAKE_TIMEOUT 5000 // timeout to complete SSL handshake typedef std::function AcConnectHandler; typedef std::function AcAckHandler; From f34df7febfaf5bd8104e67afb31373b0edb7ba2a Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 25 Jul 2019 20:57:28 -0700 Subject: [PATCH 20/29] make SSL timeout a #define, 2nd try --- src/AsyncTCP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index a65efcf..cb67779 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -1038,7 +1038,7 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){ return ERR_OK; } #if ASYNC_TCP_SSL_ENABLED - if(_pcb_secure && !_handshake_done && (now - _rx_last_packet) >= 5000){ + if(_pcb_secure && !_handshake_done && (now - _rx_last_packet) >= SSL_HANDSHAKE_TIMEOUT){ log_w("ssl handshake timeout %d", pcb->state); _close(); return ERR_OK; From 8ef604bd9a071a6c59b00bab2f5c32f84baf7129 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Aug 2019 17:56:17 -0700 Subject: [PATCH 21/29] fix while loop in _recv; fix calls into LwIP; add some comments --- src/AsyncTCP.cpp | 21 ++++++++++++++++++--- src/tcp_mbedtls.c | 6 +++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 0f96257..c26b141 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -33,6 +33,11 @@ extern "C"{ /* * TCP/IP Event Task + * + * This task processes events that correspond to the various callbacks made by LwIP. The callbacks + * are handled by _tcp_* functions, which package the info into events, which are processed by this + * task. The purpose of this scheme is ??? (to be able to block or spend arbitrary time in the event + * handlers without thereby blocking LwIP???). * */ typedef enum { @@ -211,6 +216,9 @@ static bool _start_async_task(){ /* * LwIP Callbacks + * + * The following "_tcp_*" functions are called by LwIP on its thread. They all do nothing but + * package the callback info into an event, which is queued for the async event task (see above). * */ static int8_t _tcp_clear_events(void * arg) { @@ -320,6 +328,13 @@ static int8_t _tcp_accept(void * arg, AsyncClient * client) { /* * TCP/IP API Calls + * + * The following functions provide stubs to call into LwIP's TCP api functions on the LwIP thread + * itself. This ensures there are no race conditions between the application and LwIP. + * The way it works is that the `_tcp_xxx` functions synchronously call the corresponding + * `_tcp_xxx_api` functions on the LwIP thread using a `tcp_api_call` mechanism provided by LwIP. + * The `_tcp_xxx_api` function then finally calls the actual `tcp_xxx` function in LwIP and returns + * the result. * */ #include "lwip/priv/tcpip_priv.h" @@ -711,13 +726,13 @@ bool AsyncClient::connect(const char* host, uint16_t port, bool secure){ bool AsyncClient::connect(const char* host, uint16_t port){ #endif // ASYNC_TCP_SSL_ENABLED ip_addr_t addr; - + if(!_start_async_task()){ Serial.println("failed to start task"); log_e("failed to start task"); return false; } - + err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); if(err == ERR_OK) { #if ASYNC_TCP_SSL_ENABLED @@ -995,7 +1010,7 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { } return ERR_BUF; // for lack of a better error value } - return ERR_OK; + continue; } #endif // ASYNC_TCP_SSL_ENABLED diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 2e3eaa0..bfe451d 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -144,7 +144,7 @@ int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { tcp_len = 2 * tcp_ssl->tcp->mss; } - err = tcp_write(tcp_ssl->tcp, buf, tcp_len, TCP_WRITE_FLAG_COPY); + err = _tcp_write(tcp_ssl->tcp, buf, tcp_len, TCP_WRITE_FLAG_COPY); if(err < ERR_OK) { if (err == ERR_MEM) { TCP_SSL_DEBUG("ax_port_write: No memory %d (%d)\n", tcp_len, len); @@ -154,7 +154,7 @@ int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { return err; } else if (err == ERR_OK) { //TCP_SSL_DEBUG("ax_port_write: tcp_output: %d / %d\n", tcp_len, len); - err = tcp_output(tcp_ssl->tcp); + err = _tcp_output(tcp_ssl->tcp); if(err != ERR_OK) { TCP_SSL_DEBUG("ax_port_write: tcp_output err: %d\n", err); return err; @@ -470,7 +470,7 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { } } while (p->tot_len - tcp_ssl->pbuf_offset > 0 || read_bytes > 0); - tcp_recved(tcp, p->tot_len); + _tcp_recved(tcp, p->tot_len); tcp_ssl->tcp_pbuf = NULL; pbuf_free(p); From b7ee312798b325dd7123336c6b6cc1b600513fee Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Aug 2019 21:01:24 -0700 Subject: [PATCH 22/29] fix c/c++ linking from tcp_ssl to tcp code --- src/AsyncTCP.cpp | 16 ++++++++++++++++ src/tcp_mbedtls.c | 11 ++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index c26b141..98172e2 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -524,7 +524,23 @@ static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { return msg.pcb; } +#if ASYNC_TCP_SSL_ENABLED +extern "C" { + + esp_err_t _tcp_output4ssl(tcp_pcb * pcb, void* client) { + return _tcp_output(pcb, (AsyncClient *)client); + } + + esp_err_t _tcp_write4ssl(tcp_pcb * pcb, const char* data, size_t size, uint8_t apiflags, void* client) { + return _tcp_write(pcb, data, size, apiflags, (AsyncClient *)client); + } + esp_err_t _tcp_recved4ssl(tcp_pcb * pcb, size_t len, void* client) { + return _tcp_recved(pcb, len, (AsyncClient *)client); + } + +} +#endif /* Async TCP Client diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index bfe451d..ef50f8b 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -6,6 +6,11 @@ #include "mbedtls/esp_debug.h" #include +// stubs to call LwIP's tcp functions on the LwIP thread itself, implemented in AsyncTCP.cpp +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); +extern esp_err_t _tcp_recved4ssl(struct tcp_pcb * pcb, size_t len, void* client); + // #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) #define TCP_SSL_DEBUG(...) @@ -144,7 +149,7 @@ int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { tcp_len = 2 * tcp_ssl->tcp->mss; } - err = _tcp_write(tcp_ssl->tcp, buf, tcp_len, TCP_WRITE_FLAG_COPY); + err = _tcp_write4ssl(tcp_ssl->tcp, (char *)buf, tcp_len, TCP_WRITE_FLAG_COPY, tcp_ssl->arg); if(err < ERR_OK) { if (err == ERR_MEM) { TCP_SSL_DEBUG("ax_port_write: No memory %d (%d)\n", tcp_len, len); @@ -154,7 +159,7 @@ int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { return err; } else if (err == ERR_OK) { //TCP_SSL_DEBUG("ax_port_write: tcp_output: %d / %d\n", tcp_len, len); - err = _tcp_output(tcp_ssl->tcp); + err = _tcp_output4ssl(tcp_ssl->tcp, tcp_ssl->arg); if(err != ERR_OK) { TCP_SSL_DEBUG("ax_port_write: tcp_output err: %d\n", err); return err; @@ -470,7 +475,7 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { } } while (p->tot_len - tcp_ssl->pbuf_offset > 0 || read_bytes > 0); - _tcp_recved(tcp, p->tot_len); + _tcp_recved4ssl(tcp, p->tot_len, tcp_ssl->arg); tcp_ssl->tcp_pbuf = NULL; pbuf_free(p); From 73480f3fe36fa06750b08fbf74f701893b831859 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 9 Aug 2019 12:37:18 -0700 Subject: [PATCH 23/29] TLS fixes: pbuf free bug when reading; add debug printfs; useless extra copy in read --- src/AsyncTCP.cpp | 62 ++++++++++++++++++++------------------- src/tcp_mbedtls.c | 75 +++++++++++++++++++++++------------------------ src/tcp_mbedtls.h | 4 +-- 3 files changed, 71 insertions(+), 70 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 98172e2..cd2e103 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -143,6 +143,7 @@ static bool _remove_events_with_arg(void * arg){ } static void _handle_async_event(lwip_event_packet_t * e){ + //ets_printf("T %s- ", pcTaskGetTaskName(xTaskGetCurrentTaskHandle())); if(e->event == LWIP_TCP_CLEAR){ _remove_events_with_arg(e->arg); } else if(e->event == LWIP_TCP_RECV){ @@ -535,10 +536,6 @@ extern "C" { return _tcp_write(pcb, data, size, apiflags, (AsyncClient *)client); } - esp_err_t _tcp_recved4ssl(tcp_pcb * pcb, size_t len, void* client) { - return _tcp_recved(pcb, len, (AsyncClient *)client); - } - } #endif @@ -914,17 +911,16 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ if(_pcb_secure){ bool err = false; if(_root_ca) { - err = tcp_ssl_new_client(_pcb, _hostname.empty() ? NULL : _hostname.c_str(), + err = tcp_ssl_new_client(_pcb, this, _hostname.empty() ? NULL : _hostname.c_str(), _root_ca, _root_ca_len) < 0; } else { - err = tcp_ssl_new_psk_client(_pcb, _psk_ident, _psk) < 0; + err = tcp_ssl_new_psk_client(_pcb, this, _psk_ident, _psk) < 0; } if (err) { log_e("closing...."); return _close(); } - tcp_ssl_arg(_pcb, this); tcp_ssl_data(_pcb, &_s_data); tcp_ssl_handshake(_pcb, &_s_handshake); tcp_ssl_err(_pcb, &_s_ssl_error); @@ -1014,40 +1010,46 @@ int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { while(pb != NULL) { _rx_last_packet = millis(); + pbuf *nxt = pb->next; + pb->next = NULL; #if ASYNC_TCP_SSL_ENABLED if(_pcb_secure){ // log_i("_recv: %d\n", pb->tot_len); - int read_bytes = tcp_ssl_read(pcb, pb); - if(read_bytes < 0){ - if (read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { - log_e("_recv err: %d\n", read_bytes); + int err = tcp_ssl_read(pcb, pb); + // tcp_ssl_read always processes the full pbuf, so ack all of it + _tcp_recved(pcb, pb->len, this); + pbuf_free(pb); + // handle errors + if(err < 0){ + if (err != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + log_e("_recv err: %d\n", err); _close(); } return ERR_BUF; // for lack of a better error value } - continue; - } -#endif // ASYNC_TCP_SSL_ENABLED - //we should not ack before we assimilate the data - _ack_pcb = true; - pbuf *b = pb; - pb = b->next; - b->next = NULL; - if(_pb_cb){ - _pb_cb(_pb_cb_arg, this, b); - } else { - if(_recv_cb) { - _recv_cb(_recv_cb_arg, this, b->payload, b->len); - } - if(!_ack_pcb) { - _rx_ack_len += b->len; - } else if(_pcb) { - _tcp_recved(_pcb, b->len, this); + } else +#endif // ASYNC_TCP_SSL_ENABLED + { + //we should not ack before we assimilate the data + _ack_pcb = true; + if(_pb_cb){ + _pb_cb(_pb_cb_arg, this, pb); + } else { + if(_recv_cb) { + _recv_cb(_recv_cb_arg, this, pb->payload, pb->len); + } + if(!_ack_pcb) { + _rx_ack_len += pb->len; + } else if(_pcb) { + _tcp_recved(_pcb, pb->len, this); + } + pbuf_free(pb); } - pbuf_free(b); } + + pb = nxt; } return ERR_OK; } diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index ef50f8b..38574b7 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -9,10 +9,12 @@ // stubs to call LwIP's tcp functions on the LwIP thread itself, implemented in AsyncTCP.cpp 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); -extern esp_err_t _tcp_recved4ssl(struct tcp_pcb * pcb, size_t len, void* client); -// #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) +#if 0 +#define TCP_SSL_DEBUG(...) do { ets_printf("T %s- ", pcTaskGetTaskName(xTaskGetCurrentTaskHandle())); ets_printf(__VA_ARGS__); } while(0) +#else #define TCP_SSL_DEBUG(...) +#endif static const char pers[] = "esp32-tls"; @@ -80,10 +82,11 @@ typedef struct tcp_ssl_pcb tcp_ssl_t; static tcp_ssl_t * tcp_ssl_array = NULL; static int tcp_ssl_next_fd = 0; +// tcp_ssl_recv attempts to read up to len bytes into buf from data already received. +// It is called by mbedtls. int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { + TCP_SSL_DEBUG("tcp_ssl_recv: ctx: 0x%X, buf: 0x%X, len: %d\n", ctx, buf, len); tcp_ssl_t *tcp_ssl = (tcp_ssl_t*)ctx; - uint8_t *read_buf = NULL; - uint8_t *pread_buf = NULL; u16_t recv_len = 0; if(tcp_ssl->tcp_pbuf == NULL || tcp_ssl->tcp_pbuf->tot_len == 0) { @@ -91,33 +94,19 @@ int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) { return MBEDTLS_ERR_SSL_WANT_READ; } - read_buf =(uint8_t*)calloc(tcp_ssl->tcp_pbuf->len + 1, sizeof(uint8_t)); - pread_buf = read_buf; - if (pread_buf != NULL){ - recv_len = pbuf_copy_partial(tcp_ssl->tcp_pbuf, read_buf, len, tcp_ssl->pbuf_offset); - TCP_SSL_DEBUG("tcp_ssl_recv: len: %d, recv_len: %d, pbuf_offset: %d, tcp_pbuf len: %d.\n", len, recv_len, tcp_ssl->pbuf_offset, tcp_ssl->tcp_pbuf->len); - tcp_ssl->pbuf_offset += recv_len; - } - - // Note: why copy again? - if (recv_len != 0) { - memcpy(buf, read_buf, recv_len); - } - - if(len < recv_len) { - TCP_SSL_DEBUG("tcp_ssl_recv: got %d bytes more than expected\n", recv_len - len); - } - - free(pread_buf); - pread_buf = NULL; + recv_len = pbuf_copy_partial(tcp_ssl->tcp_pbuf, buf, len, tcp_ssl->pbuf_offset); + TCP_SSL_DEBUG("tcp_ssl_recv: len: %d, recv_len: %d, pbuf_offset: %d, tcp_pbuf len: %d.\n", + len, recv_len, tcp_ssl->pbuf_offset, tcp_ssl->tcp_pbuf->len); + tcp_ssl->pbuf_offset += recv_len; if(recv_len == 0) { return MBEDTLS_ERR_SSL_WANT_READ; } - return recv_len; } +// tcp_ssl_send attempts to send len bytes from buf. +// It is called by mbedtls. int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { TCP_SSL_DEBUG("tcp_ssl_send: ctx: 0x%X, buf: 0x%X, len: %d\n", ctx, buf, len); @@ -138,7 +127,7 @@ int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { if (tcp_sndbuf(tcp_ssl->tcp) < len) { tcp_len = tcp_sndbuf(tcp_ssl->tcp); if(tcp_len == 0) { - TCP_SSL_DEBUG("ax_port_write: tcp_sndbuf is zero: %d\n", len); + TCP_SSL_DEBUG("tcp_ssl_send: tcp_sndbuf is zero: %d\n", len); return ERR_MEM; } } else { @@ -149,19 +138,20 @@ int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) { tcp_len = 2 * tcp_ssl->tcp->mss; } + TCP_SSL_DEBUG("tcp_ssl_send: tcp_write(%x, %x, %d, %x)\n", tcp_ssl->tcp, (char *)buf, tcp_len, tcp_ssl->arg); err = _tcp_write4ssl(tcp_ssl->tcp, (char *)buf, tcp_len, TCP_WRITE_FLAG_COPY, tcp_ssl->arg); if(err < ERR_OK) { if (err == ERR_MEM) { - TCP_SSL_DEBUG("ax_port_write: No memory %d (%d)\n", tcp_len, len); + TCP_SSL_DEBUG("tcp_ssl_send: No memory %d (%d)\n", tcp_len, len); return err; } - TCP_SSL_DEBUG("ax_port_write: tcp_write error: %d\n", err); + TCP_SSL_DEBUG("tcp_ssl_send: tcp_write error: %d\n", err); return err; } else if (err == ERR_OK) { - //TCP_SSL_DEBUG("ax_port_write: tcp_output: %d / %d\n", tcp_len, len); + TCP_SSL_DEBUG("tcp_ssl_send: tcp_output: %d / %d\n", tcp_len, len); err = _tcp_output4ssl(tcp_ssl->tcp, tcp_ssl->arg); if(err != ERR_OK) { - TCP_SSL_DEBUG("ax_port_write: tcp_output err: %d\n", err); + TCP_SSL_DEBUG("tcp_ssl_send: tcp_output err: %d\n", err); return err; } } @@ -175,7 +165,7 @@ uint8_t tcp_ssl_has_client() { return _tcp_ssl_has_client; } -tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) { +tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp, void* arg) { if(tcp_ssl_next_fd < 0){ tcp_ssl_next_fd = 0;//overflow @@ -188,7 +178,7 @@ tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) { } new_item->tcp = tcp; - new_item->arg = NULL; + new_item->arg = arg; new_item->on_data = NULL; new_item->on_handshake = NULL; new_item->on_error = NULL; @@ -219,7 +209,7 @@ tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) { return item; } -int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname, const char* root_ca, const size_t root_ca_len) { +int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, const char* root_ca, const size_t root_ca_len) { tcp_ssl_t* tcp_ssl; if(tcp == NULL) { @@ -230,7 +220,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname, const char* ro return -1; } - tcp_ssl = tcp_ssl_new(tcp); + tcp_ssl = tcp_ssl_new(tcp, arg); if(tcp_ssl == NULL){ return -1; } @@ -304,13 +294,13 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, const char* hostname, const char* ro } // Open an SSL connection using a PSK (pre-shared-key) cipher suite. -int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, const char* psk_ident, const char* pskey) { +int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident, const char* pskey) { tcp_ssl_t* tcp_ssl; if(tcp == NULL) return -1; if(tcp_ssl_get(tcp) != NULL) return -1; - tcp_ssl = tcp_ssl_new(tcp); + tcp_ssl = tcp_ssl_new(tcp, arg); if(tcp_ssl == NULL) return -1; mbedtls_entropy_init(&tcp_ssl->entropy_ctx); @@ -331,6 +321,8 @@ int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, const char* psk_ident, const cha return -1; } + //mbedtls_esp_enable_debug_log(&tcp_ssl->ssl_conf, 4); // 4=verbose + int ret = 0; TCP_SSL_DEBUG("setting the pre-shared key.\n"); @@ -383,7 +375,10 @@ int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, const char* psk_ident, const cha return ERR_OK; } +// tcp_ssl_write writes len bytes from data into the TLS connection. I.e., data is plaintext, gets +// encrypted, and then transmitted on the TCP connection. int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { + TCP_SSL_DEBUG("tcp_ssl_write(%x, %x, len=%d)\n", tcp, data, len); if(tcp == NULL) { return -1; } @@ -412,7 +407,11 @@ int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { return tcp_ssl->last_wr; } +// tcp_ssl_read is a callback that reads from the TLS connection, i.e., it calls mbedtls, which then +// tries to read from the TCP connection and decrypts it, tcp_ssl_read then calls the application's +// onData callback with the decrypted data. int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { + TCP_SSL_DEBUG("tcp_ssl_read(%x, %x)\n", tcp, p); if(tcp == NULL) { return -1; } @@ -449,6 +448,7 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { 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); if(tcp_ssl->on_error) tcp_ssl->on_error(tcp_ssl->arg, tcp_ssl->tcp, ret); @@ -475,14 +475,13 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { } } while (p->tot_len - tcp_ssl->pbuf_offset > 0 || read_bytes > 0); - _tcp_recved4ssl(tcp, p->tot_len, tcp_ssl->arg); tcp_ssl->tcp_pbuf = NULL; - pbuf_free(p); - return total_bytes; + return total_bytes >= 0 ? 0 : total_bytes; // return error code } int tcp_ssl_free(struct tcp_pcb *tcp) { + TCP_SSL_DEBUG("tcp_ssl_free(%x)\n", tcp); if(tcp == NULL) { return -1; } diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index 492c70b..8b932c7 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -30,8 +30,8 @@ typedef void (* tcp_ssl_handshake_cb_t)(void *arg, struct tcp_pcb *tcp, struct t 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, const char* hostname, const char* root_ca, const size_t root_ca_len); -int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, const char* psk_ident, const char* psk); +int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, const char* root_ca, const size_t root_ca_len); +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); int tcp_ssl_handshake_step(struct tcp_pcb *tcp); From 8b52f6cfa0e297865970ebf3ca60754f6e6db9bf Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 9 Aug 2019 12:42:51 -0700 Subject: [PATCH 24/29] add minor comment --- src/AsyncTCP.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index cd2e103..c945f73 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -527,6 +527,8 @@ static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { #if ASYNC_TCP_SSL_ENABLED extern "C" { + // The following API stubs are for use in tcp_mbedtls.c + // They are callable from C and take a void* instead of an AsyncClient*. esp_err_t _tcp_output4ssl(tcp_pcb * pcb, void* client) { return _tcp_output(pcb, (AsyncClient *)client); From 8e77fe772a2da29eb376e05b82e9e7abf4f4505f Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Wed, 25 Sep 2019 16:23:43 -0700 Subject: [PATCH 25/29] fix Codacy issues --- src/AsyncTCP.cpp | 4 ++-- src/tcp_mbedtls.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index e65e235..3e383b9 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -542,11 +542,11 @@ extern "C" { // They are callable from C and take a void* instead of an AsyncClient*. esp_err_t _tcp_output4ssl(tcp_pcb * pcb, void* client) { - return _tcp_output(pcb, (AsyncClient *)client); + return _tcp_output(pcb, reinterpret_castclient); } esp_err_t _tcp_write4ssl(tcp_pcb * pcb, const char* data, size_t size, uint8_t apiflags, void* client) { - return _tcp_write(pcb, data, size, apiflags, (AsyncClient *)client); + return _tcp_write(pcb, data, size, apiflags, reinterpret_castclient); } } diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 38574b7..a0ec526 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -309,7 +309,7 @@ int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, - &tcp_ssl->entropy_ctx, (const unsigned char*)pers, strlen(pers)); + &tcp_ssl->entropy_ctx, (const uint8_t*)pers, strlen(pers)); if(mbedtls_ssl_config_defaults(&tcp_ssl->ssl_conf, MBEDTLS_SSL_IS_CLIENT, @@ -415,14 +415,13 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { if(tcp == NULL) { return -1; } - tcp_ssl_t* tcp_ssl = NULL; int read_bytes = 0; int total_bytes = 0; static const size_t read_buf_size = 1024; uint8_t read_buf[read_buf_size]; - tcp_ssl = tcp_ssl_get(tcp); + tcp_ssl_t *tcp_ssl = tcp_ssl_get(tcp); if(tcp_ssl == NULL) { return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; } From 3cc70486abe92d55a11be4030c59f8585c612e2f Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Wed, 25 Sep 2019 21:10:53 -0700 Subject: [PATCH 26/29] fix issues with closed_slots --- src/AsyncTCP.cpp | 22 +++++++++++++++++----- src/AsyncTCP.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index 6e73453..4e14f53 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -548,16 +548,28 @@ static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { } #if ASYNC_TCP_SSL_ENABLED +// Jump pads for _tcp_*4ssl function below to get access to _closed_slot. +// I'm sure there has to be a better way to do this... + +esp_err_t AsyncClient::_tcp_output4ssl(tcp_pcb * pcb) { + return _tcp_output(pcb, _closed_slot); +} + +esp_err_t AsyncClient::_tcp_write4ssl(tcp_pcb * pcb, const char* data, size_t size, uint8_t apiflags) { + return _tcp_write(pcb, _closed_slot, data, size, apiflags); +} + extern "C" { - // The following API stubs are for use in tcp_mbedtls.c - // They are callable from C and take a void* instead of an AsyncClient*. + // The following API stubs are callable from C for use in tcp_mbedtls.c esp_err_t _tcp_output4ssl(tcp_pcb * pcb, void* client) { - return _tcp_output(pcb, reinterpret_castclient); + AsyncClient *cli = reinterpret_cast(client); + return cli->_tcp_output4ssl(pcb); } esp_err_t _tcp_write4ssl(tcp_pcb * pcb, const char* data, size_t size, uint8_t apiflags, void* client) { - return _tcp_write(pcb, data, size, apiflags, reinterpret_castclient); + AsyncClient *cli = reinterpret_cast(client); + return cli->_tcp_write4ssl(pcb, data, size, apiflags); } } @@ -1057,7 +1069,7 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { // log_i("_recv: %d\n", pb->tot_len); int err = tcp_ssl_read(pcb, pb); // tcp_ssl_read always processes the full pbuf, so ack all of it - _tcp_recved(pcb, pb->len); + _tcp_recved(pcb, _closed_slot, pb->len); pbuf_free(pb); // handle errors if(err < 0){ diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index dc284df..9274a33 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -151,6 +151,8 @@ class AsyncClient { static void _s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); static void _s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); static void _s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err); + esp_err_t _tcp_output4ssl(tcp_pcb * pcb); + esp_err_t _tcp_write4ssl(tcp_pcb * pcb, const char* data, size_t size, uint8_t apiflags); #endif // ASYNC_TCP_SSL_ENABLED int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); From 44b3d6b12b6e89ddd31b89ce75bcdf8000fb2e5c Mon Sep 17 00:00:00 2001 From: Robert Alfaro Date: Tue, 21 Jan 2020 16:51:12 -0800 Subject: [PATCH 27/29] mbed-tls-try2 updates (#3) * Fix LoadProhibited (#73) * Use sizeof instead of strlen for const char[] * Add Kconfig option to control ASYNC_TCP_SSL_ENABLED * Optionally include ssl header files * Add null check for psk_ident and pskey * Do not default to PSK when root_ca is not explcitly set. tcp_ssl_new_client() has a case to handle this. * Move psk null checks to top of function, remove unneeded include, syntax cleanup. Authored-by: Bob --- CMakeLists.txt | 4 ++++ Kconfig.projbuild | 6 ++++++ src/AsyncTCP.cpp | 12 +++++++----- src/AsyncTCP.h | 2 ++ src/tcp_mbedtls.c | 9 +++++++-- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f52e1c9..c7ad8b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,3 +13,7 @@ set(COMPONENT_REQUIRES register_component() target_compile_options(${COMPONENT_TARGET} PRIVATE -fno-rtti) + +if(CONFIG_ASYNC_TCP_SSL_ENABLED) + target_compile_options(${COMPONENT_TARGET} PRIVATE -DASYNC_TCP_SSL_ENABLED) +endif() diff --git a/Kconfig.projbuild b/Kconfig.projbuild index 1774926..ab9ac57 100644 --- a/Kconfig.projbuild +++ b/Kconfig.projbuild @@ -27,4 +27,10 @@ config ASYNC_TCP_USE_WDT help Enable WDT for the AsyncTCP task, so it will trigger if a handler is locking the thread. +config ASYNC_TCP_SSL_ENABLED + bool "Enable SSL for AsyncTCP client" + default "n" + help + Enables mbedTLS support for AsyncTCP clients. + endmenu diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index c1616dc..abd5afd 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -157,8 +157,10 @@ static bool _remove_events_with_arg(void * arg){ } static void _handle_async_event(lwip_event_packet_t * e){ - //ets_printf("T %s- ", pcTaskGetTaskName(xTaskGetCurrentTaskHandle())); - if(e->event == LWIP_TCP_CLEAR){ + if(e->arg == NULL){ + // do nothing when arg is NULL + //ets_printf("event arg == NULL: 0x%08x\n", e->recv.pcb); + } else if(e->event == LWIP_TCP_CLEAR){ _remove_events_with_arg(e->arg); } else if(e->event == LWIP_TCP_RECV){ //ets_printf("-R: 0x%08x\n", e->recv.pcb); @@ -972,11 +974,11 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ #if ASYNC_TCP_SSL_ENABLED if(_pcb_secure){ bool err = false; - if(_root_ca) { + if (_psk_ident != NULL and _psk != NULL) { + err = tcp_ssl_new_psk_client(_pcb, this, _psk_ident, _psk) < 0; + } else { err = tcp_ssl_new_client(_pcb, this, _hostname.empty() ? NULL : _hostname.c_str(), _root_ca, _root_ca_len) < 0; - } else { - err = tcp_ssl_new_psk_client(_pcb, this, _psk_ident, _psk) < 0; } if (err) { log_e("closing...."); diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index d2e4f4e..8992279 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -26,8 +26,10 @@ #include "sdkconfig.h" #include #include +#if ASYNC_TCP_SSL_ENABLED #include #include "tcp_mbedtls.h" +#endif extern "C" { #include "freertos/semphr.h" #include "lwip/pbuf.h" diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index a0ec526..8288b8d 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -231,7 +231,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, - &tcp_ssl->entropy_ctx, (const unsigned char*)pers, strlen(pers)); + &tcp_ssl->entropy_ctx, (const unsigned char*)pers, sizeof(pers)); if(mbedtls_ssl_config_defaults(&tcp_ssl->ssl_conf, MBEDTLS_SSL_IS_CLIENT, @@ -297,6 +297,11 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident, const char* pskey) { tcp_ssl_t* tcp_ssl; + if (pskey == NULL || psk_ident == NULL) { + TCP_SSL_DEBUG(" failed\n ! pre-shared key or identity is NULL\n\n"); + return -1; + } + if(tcp == NULL) return -1; if(tcp_ssl_get(tcp) != NULL) return -1; @@ -309,7 +314,7 @@ int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, - &tcp_ssl->entropy_ctx, (const uint8_t*)pers, strlen(pers)); + &tcp_ssl->entropy_ctx, (const uint8_t*)pers, sizeof(pers)); if(mbedtls_ssl_config_defaults(&tcp_ssl->ssl_conf, MBEDTLS_SSL_IS_CLIENT, From 540bf7deb64e5ff1ef9bb50d6e502aa739242876 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 21 Jan 2020 17:18:17 -0800 Subject: [PATCH 28/29] fix codacity strlen issues --- src/tcp_mbedtls.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index 8288b8d..c482c61 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -305,6 +305,12 @@ int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident if(tcp == NULL) return -1; if(tcp_ssl_get(tcp) != NULL) return -1; + int pskey_len = strnlen(pskey, 2*MBEDTLS_PSK_MAX_LEN+1); + if ((pskey_len > 2*MBEDTLS_PSK_MAX_LEN) || (pskey_len & 1) != 0) { + TCP_SSL_DEBUG(" failed\n ! pre-shared key not valid hex or too long\n\n"); + return -1; + } + tcp_ssl = tcp_ssl_new(tcp, arg); if(tcp_ssl == NULL) return -1; @@ -332,13 +338,9 @@ int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident TCP_SSL_DEBUG("setting the pre-shared key.\n"); // convert PSK from hex string to binary - if ((strlen(pskey) & 1) != 0 || strlen(pskey) > 2*MBEDTLS_PSK_MAX_LEN) { - TCP_SSL_DEBUG(" failed\n ! pre-shared key not valid hex or too long\n\n"); - return -1; - } unsigned char psk[MBEDTLS_PSK_MAX_LEN]; - size_t psk_len = strlen(pskey)/2; - for (int j=0; j= '0' && c <= '9') c -= '0'; else if (c >= 'A' && c <= 'F') c -= 'A' - 10; @@ -354,7 +356,7 @@ int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident } // set mbedtls config ret = mbedtls_ssl_conf_psk(&tcp_ssl->ssl_conf, psk, psk_len, - (const unsigned char *)psk_ident, strlen(psk_ident)); + (const unsigned char *)psk_ident, strnlen(psk_ident, 64)); if (ret != 0) { TCP_SSL_DEBUG(" failed\n ! mbedtls_ssl_conf_psk returned -0x%x\n\n", -ret); return handle_error(ret); From 59f83d8ad4034e7672647472e7f40e653e2d1e20 Mon Sep 17 00:00:00 2001 From: Roman Ott Date: Thu, 2 Jan 2020 12:03:57 +0100 Subject: [PATCH 29/29] add client certificate authentication --- src/AsyncTCP.cpp | 16 +++++++++++++- src/AsyncTCP.h | 6 +++++ src/tcp_mbedtls.c | 56 ++++++++++++++++++++++++++++++++++++++++++++--- src/tcp_mbedtls.h | 3 ++- 4 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/AsyncTCP.cpp b/src/AsyncTCP.cpp index abd5afd..169c098 100644 --- a/src/AsyncTCP.cpp +++ b/src/AsyncTCP.cpp @@ -606,6 +606,10 @@ AsyncClient::AsyncClient(tcp_pcb* pcb) #if ASYNC_TCP_SSL_ENABLED , _root_ca_len(0) , _root_ca(NULL) +, _cli_cert_len(0) +, _cli_cert(NULL) +, _cli_key_len(0) +, _cli_key(NULL) , _pcb_secure(false) , _handshake_done(true) , _psk_ident(0) @@ -829,6 +833,16 @@ void AsyncClient::setRootCa(const char* rootca, const size_t len) { _root_ca_len = len; } +void AsyncClient::setClientCert(const char* cli_cert, const size_t len) { + _cli_cert = (char*)cli_cert; + _cli_cert_len = len; +} + +void AsyncClient::setClientKey(const char* cli_key, const size_t len) { + _cli_key = (char*)cli_key; + _cli_key_len = len; +} + void AsyncClient::setPsk(const char* psk_ident, const char* psk) { _psk_ident = psk_ident; _psk = psk; @@ -978,7 +992,7 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){ err = tcp_ssl_new_psk_client(_pcb, this, _psk_ident, _psk) < 0; } else { err = tcp_ssl_new_client(_pcb, this, _hostname.empty() ? NULL : _hostname.c_str(), - _root_ca, _root_ca_len) < 0; + _root_ca, _root_ca_len, _cli_cert, _cli_cert_len, _cli_key, _cli_key_len) < 0; } if (err) { log_e("closing...."); diff --git a/src/AsyncTCP.h b/src/AsyncTCP.h index 8992279..48d9b68 100644 --- a/src/AsyncTCP.h +++ b/src/AsyncTCP.h @@ -76,6 +76,8 @@ class AsyncClient { bool connect(IPAddress ip, uint16_t port, bool secure = false); bool connect(const char* host, uint16_t port, bool secure = false); void setRootCa(const char* rootca, const size_t len); + void setClientCert(const char* cli_cert, const size_t len); + void setClientKey(const char* cli_key, const size_t len); void setPsk(const char* psk_ident, const char* psk); #else bool connect(IPAddress ip, uint16_t port); @@ -194,6 +196,10 @@ class AsyncClient { #if ASYNC_TCP_SSL_ENABLED size_t _root_ca_len; char* _root_ca; + size_t _cli_cert_len; + char* _cli_cert; + size_t _cli_key_len; + char* _cli_key; bool _pcb_secure; bool _handshake_done; const char* _psk_ident; diff --git a/src/tcp_mbedtls.c b/src/tcp_mbedtls.c index c482c61..c6d69bd 100644 --- a/src/tcp_mbedtls.c +++ b/src/tcp_mbedtls.c @@ -63,6 +63,10 @@ struct tcp_ssl_pcb { mbedtls_ssl_context ssl_ctx; 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; mbedtls_ctr_drbg_context drbg_ctx; mbedtls_entropy_context entropy_ctx; uint8_t type; @@ -185,6 +189,8 @@ tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp, void* arg) { new_item->tcp_pbuf = NULL; new_item->pbuf_offset = 0; new_item->next = NULL; + new_item->has_ca_cert = false; + new_item->has_client_cert = false; if(tcp_ssl_array == NULL){ tcp_ssl_array = new_item; @@ -209,7 +215,8 @@ tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) { return item; } -int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, const char* root_ca, const size_t root_ca_len) { +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) { tcp_ssl_t* tcp_ssl; if(tcp == NULL) { @@ -229,6 +236,15 @@ 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); + if(root_ca != NULL) { + mbedtls_x509_crt_init(&tcp_ssl->ca_cert); + tcp_ssl->has_ca_cert = true; + } + if (cli_cert != NULL && cli_key != NULL) { + mbedtls_x509_crt_init(&tcp_ssl->client_cert); + mbedtls_pk_init(&tcp_ssl->client_key); + tcp_ssl->has_client_cert = true; + } mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, &tcp_ssl->entropy_ctx, (const unsigned char*)pers, sizeof(pers)); @@ -245,7 +261,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con int ret = 0; - if(root_ca != NULL && root_ca_len > 0) { + if(tcp_ssl->has_ca_cert) { TCP_SSL_DEBUG("setting the root ca.\n"); mbedtls_x509_crt_init(&tcp_ssl->ca_cert); @@ -255,6 +271,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con ret = mbedtls_x509_crt_parse(&tcp_ssl->ca_cert, (const unsigned char *)root_ca, root_ca_len); if( ret < 0 ){ TCP_SSL_DEBUG(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + tcp_ssl_free(tcp); return handle_error(ret); } @@ -263,6 +280,22 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); } + if (tcp_ssl->has_client_cert) { + TCP_SSL_DEBUG("loading client cert"); + ret = mbedtls_x509_crt_parse(&tcp_ssl->client_cert, (const unsigned char *) cli_cert, cli_cert_len); + if (ret < 0) { + tcp_ssl_free(tcp); + return handle_error(ret); + } + TCP_SSL_DEBUG("loading private key"); + ret = mbedtls_pk_parse_key(&tcp_ssl->client_key, (const unsigned char *) cli_key, cli_key_len, NULL, 0); + if (ret != 0) { + tcp_ssl_free(tcp); + return handle_error(ret); + } + mbedtls_ssl_conf_own_cert(&tcp_ssl->ssl_conf, &tcp_ssl->client_cert, &tcp_ssl->client_key); + } + if(hostname != NULL) { TCP_SSL_DEBUG("setting the hostname: %s\n", hostname); if((ret = mbedtls_ssl_set_hostname(&tcp_ssl->ssl_ctx, hostname)) != 0){ @@ -273,7 +306,6 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con } mbedtls_ssl_conf_rng(&tcp_ssl->ssl_conf, mbedtls_ctr_drbg_random, &tcp_ssl->drbg_ctx); - // mbedtls_ssl_conf_verify(&tcp_ssl->ssl_conf, my_verify, NULL); if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) { tcp_ssl_free(tcp); @@ -287,6 +319,7 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, con 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"); + tcp_ssl_free(tcp); return handle_error(ret); } @@ -450,6 +483,16 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { if(ret == 0) { TCP_SSL_DEBUG("Protocol is %s Ciphersuite is %s\n", mbedtls_ssl_get_version(&tcp_ssl->ssl_ctx), mbedtls_ssl_get_ciphersuite(&tcp_ssl->ssl_ctx)); + TCP_SSL_DEBUG("Verifying peer X.509 certificate..."); + if ((mbedtls_ssl_get_verify_result(&tcp_ssl->ssl_ctx)) != 0) { + TCP_SSL_DEBUG("handshake error: %d\n", ret); + handle_error(ret); + if(tcp_ssl->on_error) + tcp_ssl->on_error(tcp_ssl->arg, tcp_ssl->tcp, ret); + } else { + TCP_SSL_DEBUG("Certificate verified."); + } + if(tcp_ssl->on_handshake) 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) { @@ -501,6 +544,13 @@ int tcp_ssl_free(struct tcp_pcb *tcp) { mbedtls_ssl_config_free(&item->ssl_conf); mbedtls_ctr_drbg_free(&item->drbg_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; } diff --git a/src/tcp_mbedtls.h b/src/tcp_mbedtls.h index 8b932c7..7a741fd 100644 --- a/src/tcp_mbedtls.h +++ b/src/tcp_mbedtls.h @@ -30,7 +30,8 @@ typedef void (* tcp_ssl_handshake_cb_t)(void *arg, struct tcp_pcb *tcp, struct t 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); +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_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);