diff --git a/libraries/WiFi/examples/WiFiSSLClient/WiFiSSLClient.ino b/libraries/WiFi/examples/WiFiSSLClient/WiFiSSLClient.ino new file mode 100644 index 00000000000..f91e186a6c7 --- /dev/null +++ b/libraries/WiFi/examples/WiFiSSLClient/WiFiSSLClient.ino @@ -0,0 +1,70 @@ +/* + Wifi secure connection example for ESP32 + Running on TLS 1.2 using mbedTLS + Suporting the folling chipersuites: + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_DHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_CCM","TLS_DHE_RSA_WITH_AES_256_CCM","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384","TLS_DHE_RSA_WITH_AES_256_CBC_SHA256","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA","TLS_DHE_RSA_WITH_AES_256_CBC_SHA","TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8","TLS_DHE_RSA_WITH_AES_256_CCM_8","TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384","TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384","TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256","TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","TLS_DHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CCM","TLS_DHE_RSA_WITH_AES_128_CCM","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256","TLS_DHE_RSA_WITH_AES_128_CBC_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA","TLS_DHE_RSA_WITH_AES_128_CBC_SHA","TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8","TLS_DHE_RSA_WITH_AES_128_CCM_8","TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA","TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA","TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA","TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA","TLS_DHE_PSK_WITH_AES_256_GCM_SHA384","TLS_DHE_PSK_WITH_AES_256_CCM","TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384","TLS_DHE_PSK_WITH_AES_256_CBC_SHA384","TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA","TLS_DHE_PSK_WITH_AES_256_CBC_SHA","TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384","TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384","TLS_PSK_DHE_WITH_AES_256_CCM_8","TLS_DHE_PSK_WITH_AES_128_GCM_SHA256","TLS_DHE_PSK_WITH_AES_128_CCM","TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256","TLS_DHE_PSK_WITH_AES_128_CBC_SHA256","TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA","TLS_DHE_PSK_WITH_AES_128_CBC_SHA","TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256","TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256","TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256","TLS_PSK_DHE_WITH_AES_128_CCM_8","TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA","TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA","TLS_RSA_WITH_AES_256_GCM_SHA384","TLS_RSA_WITH_AES_256_CCM","TLS_RSA_WITH_AES_256_CBC_SHA256","TLS_RSA_WITH_AES_256_CBC_SHA","TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA","TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA","TLS_RSA_WITH_AES_256_CCM_8","TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256","TLS_RSA_WITH_CAMELLIA_256_CBC_SHA","TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384","TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384","TLS_RSA_WITH_AES_128_GCM_SHA256","TLS_RSA_WITH_AES_128_CCM","TLS_RSA_WITH_AES_128_CBC_SHA256","TLS_RSA_WITH_AES_128_CBC_SHA","TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA","TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA","TLS_RSA_WITH_AES_128_CCM_8","TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_RSA_WITH_CAMELLIA_128_CBC_SHA","TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_RSA_WITH_3DES_EDE_CBC_SHA","TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA","TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA","TLS_RSA_PSK_WITH_AES_256_GCM_SHA384","TLS_RSA_PSK_WITH_AES_256_CBC_SHA384","TLS_RSA_PSK_WITH_AES_256_CBC_SHA","TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384","TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384","TLS_RSA_PSK_WITH_AES_128_GCM_SHA256","TLS_RSA_PSK_WITH_AES_128_CBC_SHA256","TLS_RSA_PSK_WITH_AES_128_CBC_SHA","TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256","TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256","TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA","TLS_PSK_WITH_AES_256_GCM_SHA384","TLS_PSK_WITH_AES_256_CCM","TLS_PSK_WITH_AES_256_CBC_SHA384","TLS_PSK_WITH_AES_256_CBC_SHA","TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384","TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384","TLS_PSK_WITH_AES_256_CCM_8","TLS_PSK_WITH_AES_128_GCM_SHA256","TLS_PSK_WITH_AES_128_CCM","TLS_PSK_WITH_AES_128_CBC_SHA256","TLS_PSK_WITH_AES_128_CBC_SHA","TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256","TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256","TLS_PSK_WITH_AES_128_CCM_8","TLS_PSK_WITH_3DES_EDE_CBC_SHA","TLS_EMPTY_RENEGOTIATION_INFO_SCSV"] + 2017 - Evandro Copercini - Public Domain +*/ + +#include + +char ssid[] = "your_network_name"; // your network SSID (name of wifi network) +char pass[] = "your_password"; // your network password + +char server[] = "www.howsmyssl.com"; // Server URL +// You can use x.509 certificates if you want +//unsigned char test_ca_cert[] = ""; //For the usage of verifying server +//unsigned char test_client_key[] = ""; //For the usage of verifying client +//unsigned char test_client_cert[] = ""; //For the usage of verifying client + + +WiFiSSLClient client; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(115200); + + WiFi.begin(ssid, pass); + // attempt to connect to Wifi network: + while (WiFi.status() != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + + // wait 5 seconds for re-trying + delay(5000); + } + + Serial.print("Connected to "); + Serial.println(ssid); + + Serial.println("\nStarting connection to server..."); + if (client.connect(server, 443)) { //client.connect(server, 443, test_ca_cert, test_client_cert, test_client_key) + Serial.println("Connected to server!"); + // Make a HTTP request: + client.println("GET https://www.howsmyssl.com/a/check HTTP/1.0"); + client.println("Host: www.howsmyssl.com"); + client.println("Connection: close"); + client.println(); + } + else + Serial.println("Connection failed!"); + + + // if there are incoming bytes available + // from the server, read them and print them: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting from server."); + client.stop(); + } +} + +void loop() { + // do nothing +} diff --git a/libraries/WiFi/src/WiFiSSLClient.cpp b/libraries/WiFi/src/WiFiSSLClient.cpp new file mode 100644 index 00000000000..c8166856862 --- /dev/null +++ b/libraries/WiFi/src/WiFiSSLClient.cpp @@ -0,0 +1,204 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * Ported from Ameba8195 (no license specified) to ESP32 by Evandro Copercini - 2017 - Public domain + */ +#include "WiFi.h" +#include "WiFiSSLClient.h" + +WiFiSSLClient::WiFiSSLClient(){ + _is_connected = false; + _sock = -1; + + sslclient = new sslclient_context; + ssl_init(sslclient); + sslclient->fd = -1; + + _rootCABuff = NULL; + _cli_cert = NULL; + _cli_key = NULL; +} + +WiFiSSLClient::WiFiSSLClient(uint8_t sock) { + _sock = sock; + + sslclient = new sslclient_context; + ssl_init(sslclient); + sslclient->fd = -1; + + if(sock >= 0) + _is_connected = true; + _rootCABuff = NULL; + _cli_cert = NULL; + _cli_key = NULL; +} + +uint8_t WiFiSSLClient::connected() { + if (sslclient->fd < 0) { + _is_connected = false; + return 0; + } + else { + if(_is_connected) + return 1; + else{ + stop(); + return 0; + } + } +} + +int WiFiSSLClient::available() { + int ret = 0; + int err; + + if(!_is_connected) + return 0; + if (sslclient->fd >= 0) + { + ret = ssldrv.availData(sslclient); + if (ret > 0) { + return 1; + } else { + err = ssldrv.getLastErrno(sslclient); + if (err != EAGAIN) { + _is_connected = false; + } + } + return 0; + } +} + +int WiFiSSLClient::read() { + int ret; + int err; + uint8_t b[1]; + + if (!available()) + return -1; + + ret = ssldrv.getData(sslclient, b); + if (ret > 0) { + return b[0]; + } else { + err = ssldrv.getLastErrno(sslclient); + if (err != EAGAIN) { + _is_connected = false; + } + } + return -1; +} + +int WiFiSSLClient::read(uint8_t* buf, size_t size) { + uint16_t _size = size; + int ret; + int err; + + ret = ssldrv.getDataBuf(sslclient, buf, _size); + if (ret <= 0){ + err = ssldrv.getLastErrno(sslclient); + if (err != EAGAIN) { + _is_connected = false; + } + } + return ret; +} + +void WiFiSSLClient::stop() { + + if (sslclient->fd < 0) + return; + + ssldrv.stopClient(sslclient); + _is_connected = false; + + sslclient->fd = -1; + _sock = -1; +} + +size_t WiFiSSLClient::write(uint8_t b) { + return write(&b, 1); +} + +size_t WiFiSSLClient::write(const uint8_t *buf, size_t size) { + if (sslclient->fd < 0) + { + setWriteError(); + return 0; + } + if (size == 0) + { + setWriteError(); + return 0; + } + + if (!ssldrv.sendData(sslclient, buf, size)) + { + setWriteError(); + _is_connected = false; + return 0; + } + + return size; +} + +WiFiSSLClient::operator bool() { + return sslclient->fd >= 0; +} + +int WiFiSSLClient::connect(IPAddress ip, uint16_t port) { + // +} + +int WiFiSSLClient::connect(const char *host, uint16_t port) { + connect(host, port, _rootCABuff, _cli_cert, _cli_key); +} + + +int WiFiSSLClient::connect(const char* host, uint16_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key) { + IPAddress remote_addr; + + if (WiFi.hostByName(host, remote_addr)) + { + return connect(remote_addr, port, rootCABuff, cli_cert, cli_key); + } + return 0; +} + +int WiFiSSLClient::connect(IPAddress ip, uint16_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key) { + int ret = 0; + + ret = ssldrv.startClient(sslclient, ip, port, rootCABuff, cli_cert, cli_key); + + if (ret < 0) { + _is_connected = false; + return 0; + } else { + _is_connected = true; + } + + return 1; +} + +int WiFiSSLClient::peek() { + uint8_t b; + + if (!available()) + return -1; + + ssldrv.getData(sslclient, &b, 1); + + return b; +} +void WiFiSSLClient::flush() { + while (available()) + read(); +} + +void WiFiSSLClient::setRootCA(unsigned char *rootCA) { + _rootCABuff = rootCA; +} + +void WiFiSSLClient::setClientCertificate(unsigned char *client_ca, unsigned char *private_key) { + _cli_cert = client_ca; + _cli_key = private_key; +} + diff --git a/libraries/WiFi/src/WiFiSSLClient.h b/libraries/WiFi/src/WiFiSSLClient.h new file mode 100644 index 00000000000..f4ab699bacb --- /dev/null +++ b/libraries/WiFi/src/WiFiSSLClient.h @@ -0,0 +1,52 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * Ported from Ameba8195 to ESP32 by Evandro Copercini - 2017 - Public domain + */ + +#ifndef wifisslclient_h +#define wifisslclient_h +#include "Wifi.h" +#include "IPAddress.h" +#include "ssl_drv.h" + +struct ssl_context; +class WiFiSSLClient : public Client { + +public: + + WiFiSSLClient(); + WiFiSSLClient(uint8_t sock); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + + void setRootCA(unsigned char *rootCA); + void setClientCertificate(unsigned char *client_ca, unsigned char *private_key); + + int connect(IPAddress ip, uint16_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key); + int connect(const char *host, uint16_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key); + + using Print::write; + +private: + int _sock; + bool _is_connected; + sslclient_context* sslclient; + SSLDrv ssldrv; + + unsigned char *_rootCABuff; + unsigned char *_cli_cert; + unsigned char *_cli_key; +}; + +#endif diff --git a/libraries/WiFi/src/ard_ssl.c b/libraries/WiFi/src/ard_ssl.c new file mode 100644 index 00000000000..8a51b875d27 --- /dev/null +++ b/libraries/WiFi/src/ard_ssl.c @@ -0,0 +1,342 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + +* Adapted from the ssl_client1 example in mbedtls. +* +* Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved, Apache 2.0 License. +* Additions Copyright (C) 2017 Evandro Luis Copercini, Apache 2.0 License. +*/ + +#include "Arduino.h" +#include +#include +#include +#include +#include + +#include "ard_ssl.h" + +#define SSL_READ_TIMEOUT_MS 30000 + +const char *pers = "esp32-tls"; + +#define DEBUG true + +#ifdef DEBUG + #define DEBUG_PRINT(x) printf x +#else + #define DEBUG_PRINT(x) +#endif + +#ifdef MBEDTLS_DEBUG_C + +#define MBEDTLS_DEBUG_LEVEL 4 + +/* mbedtls debug function that translates mbedTLS debug output +to ESP_LOGx debug output. + +MBEDTLS_DEBUG_LEVEL 4 means all mbedTLS debug output gets sent here, +and then filtered to the ESP logging mechanism. +*/ +static void mbedtls_debug(void *ctx, int level, +const char *file, int line, +const char *str) +{ + const char *MBTAG = "mbedtls"; + char *file_sep; + + /* Shorten 'file' from the whole file path to just the filename + + This is a bit wasteful because the macros are compiled in with + the full _FILE_ path in each case. + */ + file_sep = rindex(file, '/'); + if(file_sep) + file = file_sep+1; + + switch(level) { + case 1: + printf( "%s:%d %s \n", file, line, str); + break; + case 2: + case 3: + printf( "%s:%d %s \n", file, line, str); + case 4: + printf( "%s:%d %s \n", file, line, str); + break; + default: + printf( "Unexpected log level %d: %s \n", level, str); + break; + } +} + +#endif + + + + +void ssl_init(sslclient_context* ssl_client) { + /* + * Initialize the RNG and the session data + */ + // mbedtls_net_init(&ssl_client->net_ctx); + mbedtls_ssl_init(&ssl_client->ssl_ctx); + mbedtls_ssl_config_init(&ssl_client->ssl_conf); + + mbedtls_ctr_drbg_init(&ssl_client->drbg_ctx); + mbedtls_entropy_init(&ssl_client->entropy_ctx); + + +} + + + +int start_ssl_client(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key) +{ + + char buf[512]; + int ret, flags, len, timeout; + int enable = 1; + DEBUG_PRINT(("Free heap before TLS %u\n", xPortGetFreeHeapSize())); + + + do { + + ssl_client->fd = -1; + ssl_client->fd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (ssl_client->fd < 0) { + DEBUG_PRINT(("\r\nERROR opening socket\r\n")); + ret = -1; + break; + } + + struct sockaddr_in serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = ipAddress; + serv_addr.sin_port = htons(port); + + if(lwip_connect(ssl_client->fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) { + timeout = 30000; + lwip_setsockopt(ssl_client->fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + lwip_setsockopt(ssl_client->fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + lwip_setsockopt(ssl_client->fd, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)); + lwip_setsockopt(ssl_client->fd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)); + } + else{ + printf("\r\nConnect to Server failed!\r\n"); + ret = -1; + break; + } + + DEBUG_PRINT(( "Seeding the random number generator\n")); + + + if((ret = mbedtls_ctr_drbg_seed(&ssl_client->drbg_ctx, mbedtls_entropy_func, + &ssl_client->entropy_ctx, (const unsigned char *) pers, strlen(pers))) != 0) + { + printf( "mbedtls_ctr_drbg_seed returned %d \n", ret); + break; + } + + + /* MBEDTLS_SSL_VERIFY_REQUIRED if a CA certificate is defined on Arduino IDE and + MBEDTLS_SSL_VERIFY_NONE if not. + */ + if(rootCABuff != NULL) { + DEBUG_PRINT(( "Loading CA cert\n")); + mbedtls_x509_crt_init(&ssl_client->ca_cert); + mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); + ret = mbedtls_x509_crt_parse(&ssl_client->ca_cert, (uint8_t*)rootCABuff, strlen(rootCABuff) + 1); + mbedtls_ssl_conf_ca_chain(&ssl_client->ssl_conf, &ssl_client->ca_cert, NULL); + //mbedtls_ssl_conf_verify(&ssl_client->ssl_ctx, my_verify, NULL ); + if(ret < 0) + { + printf( "CA cert: mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + break; + } + } else + mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); + + + + if(cli_cert != NULL && cli_key != NULL) { + + mbedtls_x509_crt_init(&ssl_client->client_cert); + mbedtls_pk_init(&ssl_client->client_key); + + DEBUG_PRINT(( "Loading CRT cert\n")); + + ret = mbedtls_x509_crt_parse(&ssl_client->client_cert, (const unsigned char *)cli_cert, strlen(cli_cert) + 1); + + if (ret < 0) { + printf( "CRT cert: mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + break; + } + + + + DEBUG_PRINT(( "Loading private key\n")); + ret = mbedtls_pk_parse_key(&ssl_client->client_key, (const unsigned char *)cli_key, strlen(cli_key) + 1, NULL, 0); + + if (ret < 0) { + printf( "PRIVATE KEY: mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + break; + } + + mbedtls_ssl_conf_own_cert(&ssl_client->ssl_conf, &ssl_client->client_cert, &ssl_client->client_key); + + + } + + /* + DEBUG_PRINT(( "Setting hostname for TLS session...\n")); + + // Hostname set here should match CN in server certificate + if((ret = mbedtls_ssl_set_hostname(&ssl_client->ssl_ctx, host)) != 0) + { + printf( "mbedtls_ssl_set_hostname returned -0x%x\n", -ret); + break; + } + */ + + DEBUG_PRINT(( "Setting up the SSL/TLS structure...\n")); + + if((ret = mbedtls_ssl_config_defaults(&ssl_client->ssl_conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) + { + printf( "mbedtls_ssl_config_defaults returned %d\n", ret); + break; + } + + + + + mbedtls_ssl_conf_read_timeout(&ssl_client->ssl_conf, SSL_READ_TIMEOUT_MS); + mbedtls_ssl_conf_rng(&ssl_client->ssl_conf, mbedtls_ctr_drbg_random, &ssl_client->drbg_ctx); + #ifdef MBEDTLS_DEBUG_C + mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL); + mbedtls_ssl_conf_dbg(&ssl_client->ssl_conf, mbedtls_debug, NULL); + #endif + + if ((ret = mbedtls_ssl_setup(&ssl_client->ssl_ctx, &ssl_client->ssl_conf)) != 0) + { + printf( "mbedtls_ssl_setup returned -0x%x\n\n", -ret); + break; + } + + // int port_len = sizeof(port); + // char port_str[port_len]; + // sprintf(port_str, "%d", port); + // DEBUG_PRINT(( "Connecting to %s:%s...\n", host, port_str)); + + // if ((ret = mbedtls_net_connect(&ssl_client->net_ctx, host, + // port_str, MBEDTLS_NET_PROTO_TCP)) != 0) + // { + // printf( "mbedtls_net_connect returned -%x\n", -ret); + // break; + // } + // DEBUG_PRINT(( "Connected.\n")); + + + mbedtls_ssl_set_bio(&ssl_client->ssl_ctx, &ssl_client->fd, mbedtls_net_send, NULL, mbedtls_net_recv_timeout ); + + + DEBUG_PRINT(( "Performing the SSL/TLS handshake...\n")); + + while ((ret = mbedtls_ssl_handshake(&ssl_client->ssl_ctx)) != 0) + { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) + { + printf( "mbedtls_ssl_handshake returned -0x%x\n", -ret); + break; + } + } + + + if(cli_cert != NULL && cli_key != NULL) { + DEBUG_PRINT(("Protocol is %s \nCiphersuite is %s\n", mbedtls_ssl_get_version(&ssl_client->ssl_ctx), mbedtls_ssl_get_ciphersuite(&ssl_client->ssl_ctx))); + if ((ret = mbedtls_ssl_get_record_expansion(&ssl_client->ssl_ctx)) >= 0) { + DEBUG_PRINT(("Record expansion is %d\n", ret)); + } else { + DEBUG_PRINT(("Record expansion is unknown (compression)\n")); + } + } + + DEBUG_PRINT(( "Verifying peer X.509 certificate...\n")); + + if ((flags = mbedtls_ssl_get_verify_result(&ssl_client->ssl_ctx)) != 0) + { + /* In real life, we probably want to close connection if ret != 0 */ + printf( "Failed to verify peer certificate!\n"); + bzero(buf, sizeof(buf)); + mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); + printf( "verification info: %s\n", buf); + } + else { + DEBUG_PRINT(( "Certificate verified.\n")); + } + }while (0); + + DEBUG_PRINT(("Free heap after TLS %u\n", xPortGetFreeHeapSize())); + + + //ssl_client-> fd = ret; + return ssl_client->fd; + //return 1; +} + + + + +void stop_ssl_socket(sslclient_context* ssl_client) { + DEBUG_PRINT(( "\nCleaning SSL connection.\n")); + mbedtls_net_free(&ssl_client->fd); + ssl_client->fd = -1; + mbedtls_ssl_free(&ssl_client->ssl_ctx); + mbedtls_ssl_config_free(&ssl_client->ssl_conf); + mbedtls_ctr_drbg_free(&ssl_client->drbg_ctx); + mbedtls_entropy_free(&ssl_client->entropy_ctx); + //need to clean certs +} + + +int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len) +{ + + // DEBUG_PRINT(( "Writing HTTP request...\n")); + int ret = -1; + + while((ret = mbedtls_ssl_write(&ssl_client->ssl_ctx, data, len)) <= 0) + { + if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) + { + printf( "mbedtls_ssl_write returned -0x%x\n", -ret); + break; + } + } + + len = ret; + // DEBUG_PRINT(( "%d bytes written\n", len)); + return ret; + + + +} + + + +int get_ssl_receive(sslclient_context *ssl_client, uint8_t *data, int length, int flag) +{ + // DEBUG_PRINT(( "Reading HTTP response...\n")); + int ret = -1; + + ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, data, length); + + //DEBUG_PRINT(( "%d bytes readed\n", ret)); + return ret; + + + +} diff --git a/libraries/WiFi/src/ard_ssl.h b/libraries/WiFi/src/ard_ssl.h new file mode 100644 index 00000000000..46a474dfbe2 --- /dev/null +++ b/libraries/WiFi/src/ard_ssl.h @@ -0,0 +1,44 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * Ported from Ameba8195 (no license specified) to ESP32 by Evandro Copercini - 2017 - Public domain + */ + +#ifndef ARD_SSL_H +#define ARD_SSL_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" + +typedef struct sslclient_context { + int fd; + mbedtls_net_context net_ctx; + mbedtls_ssl_context ssl_ctx; + mbedtls_ssl_config ssl_conf; + + mbedtls_ctr_drbg_context drbg_ctx; + mbedtls_entropy_context entropy_ctx; + + mbedtls_x509_crt ca_cert; + mbedtls_x509_crt client_cert; + mbedtls_pk_context client_key; +} sslclient_context; + + +void ssl_init(sslclient_context* ssl_client); + +int start_ssl_client(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key); + +void stop_ssl_socket(sslclient_context *ssl_client); + +int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len); + +int get_ssl_receive(sslclient_context *ssl_client, uint8_t* data, int length, int flag); + +int get_ssl_sock_errno(sslclient_context *ssl_client); + +int get_ssl_bytes_avail(sslclient_context *ssl_client); + +#endif diff --git a/libraries/WiFi/src/ssl_drv.cpp b/libraries/WiFi/src/ssl_drv.cpp new file mode 100644 index 00000000000..823e6d60516 --- /dev/null +++ b/libraries/WiFi/src/ssl_drv.cpp @@ -0,0 +1,118 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * Ported from Ameba8195 (no license specified) to ESP32 by Evandro Copercini - 2017 - Public domain + */ + +#include "ssl_drv.h" + +uint16_t SSLDrv::availData(sslclient_context *ssl_client) +{ + int ret; + + if (ssl_client->fd < 0) + return 0; + + if(_available) { + return 1; + } else { + return getData(ssl_client, c, 1); + } +} + +bool SSLDrv::getData(sslclient_context *ssl_client, uint8_t *data, uint8_t peek) +{ + int ret = 0; + int flag = 0; + + if (_available) { + /* we already has data to read */ + data[0] = c[0]; + if (peek) { + } else { + /* It's not peek and the data has been taken */ + _available = false; + } + return true; + } + + if (peek) { + flag |= 1; + } + + ret = get_ssl_receive(ssl_client, c, 1, flag); + + if (ret == 1) { + data[0] = c[0]; + if (peek) { + _available = true; + } else { + _available = false; + } + return true; + } + + return false; +} + +int SSLDrv::getDataBuf(sslclient_context *ssl_client, uint8_t *_data, uint16_t _dataLen) +{ + int ret; + + if (_available) { + /* there is one byte cached */ + _data[0] = c[0]; + _available = false; + _dataLen--; + if (_dataLen > 0) { + ret = get_ssl_receive(ssl_client, _data, _dataLen, 0); + if (ret > 0) { + ret++; + return ret; + } else { + return 1; + } + } else { + return 1; + } + } else { + ret = get_ssl_receive(ssl_client, _data, _dataLen, 0); + } + + return ret; +} + +void SSLDrv::stopClient(sslclient_context *ssl_client) +{ + stop_ssl_socket(ssl_client); + _available = false; +} + +bool SSLDrv::sendData(sslclient_context *ssl_client, const uint8_t *data, uint16_t len) +{ + int ret; + + if (ssl_client->fd < 0) + return false; + + ret = send_ssl_data(ssl_client, data, len); + + if (ret == 0) { + return false; + } + + return true; +} + + +int SSLDrv::startClient(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key) +{ + int ret; + + ret = start_ssl_client(ssl_client, ipAddress, port, rootCABuff, cli_cert, cli_key); + + return ret; +} + +int SSLDrv::getLastErrno(sslclient_context *ssl_client) +{ + // return get_ssl_sock_errno(ssl_client); +} diff --git a/libraries/WiFi/src/ssl_drv.h b/libraries/WiFi/src/ssl_drv.h new file mode 100644 index 00000000000..2c7ac132615 --- /dev/null +++ b/libraries/WiFi/src/ssl_drv.h @@ -0,0 +1,33 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * Ported from Ameba8195 (no license specified) to ESP32 by Evandro Copercini - 2017 - Public domain + */ + +#ifndef SSL_DRV_H +#define SSL_DRV_H +#include + +#define DATA_LENTH 128 +#ifdef __cplusplus +extern "C" { +#include "ard_ssl.h" +} +#endif + +class SSLDrv +{ +public: + int startClient(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key); + void stopClient(sslclient_context *ssl_client); + bool getData(sslclient_context *ssl_client, uint8_t *data, uint8_t peek=0); + int getDataBuf(sslclient_context *ssl_client, uint8_t *_data, uint16_t _dataLen); + bool sendData(sslclient_context *ssl_client, const uint8_t *data, uint16_t len); + uint16_t availData(sslclient_context *ssl_client); + sslclient_context *init(void); + int getLastErrno(sslclient_context *ssl_client); + +private: + bool _available; + uint8_t c[1]; +}; + +#endif