diff --git a/libraries/WiFi/examples/WiFiSSLClient/WiFiSSLClient.ino b/libraries/WiFi/examples/WiFiSSLClient/WiFiSSLClient.ino new file mode 100644 index 00000000000..06682c5eab0 --- /dev/null +++ b/libraries/WiFi/examples/WiFiSSLClient/WiFiSSLClient.ino @@ -0,0 +1,72 @@ +/* + 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); + delay(100); + + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + WiFi.begin(ssid, pass); + + // attempt to connect to Wifi network: + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + // wait 1 second for re-trying + delay(1000); + } + + 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..cc1260e1c21 --- /dev/null +++ b/libraries/WiFi/src/WiFiSSLClient.cpp @@ -0,0 +1,308 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * by Evandro Copercini - 2017 - Public domain + */ +#include "WiFi.h" +#include "WiFiSSLClient.h" + + +WiFiSSLClient::WiFiSSLClient(){ + _connected = false; + + sslclient = new sslclient_context; + ssl_init(sslclient); + sslclient->fd = -1; + + _CA_cert = NULL; + _cert = NULL; + _private_key = NULL; +} + +WiFiSSLClient::WiFiSSLClient(uint8_t sock) { + + sslclient = new sslclient_context; + ssl_init(sslclient); + sslclient->fd = -1; + + if(sock >= 0) + _connected = true; + + _CA_cert = NULL; + _cert = NULL; + _private_key = NULL; +} + +uint8_t WiFiSSLClient::connected() { + if (sslclient->fd < 0) { + _connected = false; + return 0; + } + else { + if(_connected) + return 1; + else{ + stop(); + return 0; + } + } +} + +int WiFiSSLClient::available() { + int ret = 0; + int err; + + if(!_connected) + return 0; + if (sslclient->fd >= 0) + { + ret = availData(sslclient); + if (ret > 0) { + return 1; + } else { + printf("SSLclient: availData ERROR"); + _connected = false; + } + return 0; + } +} + +int WiFiSSLClient::read() { + int ret; + int err; + uint8_t b[1]; + + if (!available()) + return -1; + + ret = getData(sslclient, b); + if (ret > 0) { + return b[0]; + } else { + printf("SSLclient: read ERROR"); + _connected = false; + } + return -1; +} + +int WiFiSSLClient::read(uint8_t* buf, size_t size) { + uint16_t _size = size; + int ret; + int err; + + ret = getDataBuf(sslclient, buf, _size); + if (ret <= 0){ + printf("SSLclient: read ERROR"); + _connected = false; + } + return ret; +} + +void WiFiSSLClient::stop() { + + if (sslclient->fd < 0) + return; + + stopClient(sslclient); + _connected = false; + + sslclient->fd = -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 (!sendData(sslclient, buf, size)) + { + setWriteError(); + _connected = false; + return 0; + } + + return size; +} + +WiFiSSLClient::operator bool() { + return sslclient->fd >= 0; +} + +int WiFiSSLClient::connect(IPAddress ip, uint16_t port) { + connect(ip, port, _CA_cert, _cert, _private_key); +} + +int WiFiSSLClient::connect(const char *host, uint16_t port) { + connect(host, port, _CA_cert, _cert, _private_key); +} + + +int WiFiSSLClient::connect(const char* host, uint16_t port, unsigned char* CA_cert, unsigned char* cert, unsigned char* private_key) { + IPAddress remote_addr; + + if (WiFi.hostByName(host, remote_addr)) + { + return connect(remote_addr, port, CA_cert, cert, private_key); + } + return 0; +} + +int WiFiSSLClient::connect(IPAddress ip, uint16_t port, unsigned char* CA_cert, unsigned char* cert, unsigned char* private_key) { + int ret = 0; + + ret = startClient(sslclient, ip, port, CA_cert, cert, private_key); + + if (ret < 0) { + _connected = false; + return 0; + } else { + _connected = true; + } + + return 1; +} + +int WiFiSSLClient::peek() { + uint8_t b; + + if (!available()) + return -1; + + getData(sslclient, &b, 1); + + return b; +} +void WiFiSSLClient::flush() { + while (available()) + read(); +} + +void WiFiSSLClient::setCACert(unsigned char *rootCA) { + _CA_cert = rootCA; +} + +void WiFiSSLClient::setCertificate (unsigned char *client_ca){ + _cert = client_ca; +} + +void WiFiSSLClient::setPrivateKey (unsigned char *private_key) { + _private_key = private_key; +} + + +uint16_t WiFiSSLClient::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 WiFiSSLClient::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 WiFiSSLClient::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 WiFiSSLClient::stopClient(sslclient_context *ssl_client) +{ + stop_ssl_socket(ssl_client); + _available = false; +} + +bool WiFiSSLClient::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 WiFiSSLClient::startClient(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* CA_cert, unsigned char* cert, unsigned char* private_key) +{ + int ret; + + ret = start_ssl_client(ssl_client, ipAddress, port, CA_cert, cert, private_key); + + return ret; +} diff --git a/libraries/WiFi/src/WiFiSSLClient.h b/libraries/WiFi/src/WiFiSSLClient.h new file mode 100644 index 00000000000..f99d4644aed --- /dev/null +++ b/libraries/WiFi/src/WiFiSSLClient.h @@ -0,0 +1,62 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * by Evandro Copercini - 2017 - Public domain + */ + +#ifndef wifisslclient_h +#define wifisslclient_h +#include "Wifi.h" +#include "IPAddress.h" + +#include "include/ssl_client.h" + +struct ssl_context; + +class WiFiSSLClient : public WiFiClient { + +public: + + WiFiSSLClient(); + WiFiSSLClient(uint8_t sock); + + 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 setCACert(unsigned char *rootCA); + void setCertificate(unsigned char *client_ca); + void setPrivateKey (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); + + 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); + + using Print::write; + +private: + bool _connected; + sslclient_context* sslclient; + + unsigned char *_CA_cert; + unsigned char *_cert; + unsigned char *_private_key; + + bool _available; + uint8_t c[1]; + +}; +#endif diff --git a/libraries/WiFi/src/include/ssl_client.cpp b/libraries/WiFi/src/include/ssl_client.cpp new file mode 100644 index 00000000000..d9b4707068d --- /dev/null +++ b/libraries/WiFi/src/include/ssl_client.cpp @@ -0,0 +1,333 @@ +/* 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 "ssl_client.h" + +#define SSL_READ_TIMEOUT_MS 30000 + +const char *pers = "esp32-tls"; + +#define DEBUG true + +#ifdef DEBUG + #define DEBUG_PRINT(...) printf( __VA_ARGS__ ) +#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) { + printf("\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, (const unsigned char *)rootCABuff, sizeof(rootCABuff)); + 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, sizeof(rootCABuff)); + + 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, sizeof(rootCABuff), 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/include/ssl_client.h b/libraries/WiFi/src/include/ssl_client.h new file mode 100644 index 00000000000..9863af8cb51 --- /dev/null +++ b/libraries/WiFi/src/include/ssl_client.h @@ -0,0 +1,36 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * 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); + +#endif diff --git a/platform.txt b/platform.txt index d112108e2a3..e9662411730 100644 --- a/platform.txt +++ b/platform.txt @@ -14,7 +14,7 @@ compiler.warning_flags.all=-Wall -Werror=all -Wextra compiler.path={runtime.tools.xtensa-esp32-elf-gcc.path}/bin/ compiler.sdk.path={runtime.platform.path}/tools/sdk -compiler.cpreprocessor.flags=-DESP_PLATFORM -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H "-I{compiler.sdk.path}/include/config" "-I{compiler.sdk.path}/include/bt" "-I{compiler.sdk.path}/include/driver" "-I{compiler.sdk.path}/include/esp32" "-I{compiler.sdk.path}/include/ethernet" "-I{compiler.sdk.path}/include/fatfs" "-I{compiler.sdk.path}/include/freertos" "-I{compiler.sdk.path}/include/log" "-I{compiler.sdk.path}/include/mdns" "-I{compiler.sdk.path}/include/vfs" "-I{compiler.sdk.path}/include/ulp" "-I{compiler.sdk.path}/include/newlib" "-I{compiler.sdk.path}/include/nvs_flash" "-I{compiler.sdk.path}/include/spi_flash" "-I{compiler.sdk.path}/include/sdmmc" "-I{compiler.sdk.path}/include/openssl" "-I{compiler.sdk.path}/include/app_update" "-I{compiler.sdk.path}/include/tcpip_adapter" "-I{compiler.sdk.path}/include/xtensa-debug-module" "-I{compiler.sdk.path}/include/newlib" "-I{compiler.sdk.path}/include/coap" "-I{compiler.sdk.path}/include/wpa_supplicant" "-I{compiler.sdk.path}/include/expat" "-I{compiler.sdk.path}/include/json" "-I{compiler.sdk.path}/include/mbedtls" "-I{compiler.sdk.path}/include/nghttp" "-I{compiler.sdk.path}/include/lwip" +compiler.cpreprocessor.flags=-DESP_PLATFORM -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" -DHAVE_CONFIG_H "-I{compiler.sdk.path}/include/config" "-I{compiler.sdk.path}/include/bt" "-I{compiler.sdk.path}/include/driver" "-I{compiler.sdk.path}/include/esp32" "-I{compiler.sdk.path}/include/ethernet" "-I{compiler.sdk.path}/include/fatfs" "-I{compiler.sdk.path}/include/freertos" "-I{compiler.sdk.path}/include/log" "-I{compiler.sdk.path}/include/mdns" "-I{compiler.sdk.path}/include/vfs" "-I{compiler.sdk.path}/include/ulp" "-I{compiler.sdk.path}/include/newlib" "-I{compiler.sdk.path}/include/nvs_flash" "-I{compiler.sdk.path}/include/spi_flash" "-I{compiler.sdk.path}/include/sdmmc" "-I{compiler.sdk.path}/include/openssl" "-I{compiler.sdk.path}/include/app_update" "-I{compiler.sdk.path}/include/tcpip_adapter" "-I{compiler.sdk.path}/include/xtensa-debug-module" "-I{compiler.sdk.path}/include/newlib" "-I{compiler.sdk.path}/include/coap" "-I{compiler.sdk.path}/include/wpa_supplicant" "-I{compiler.sdk.path}/include/expat" "-I{compiler.sdk.path}/include/json" "-I{compiler.sdk.path}/include/mbedtls" "-I{compiler.sdk.path}/include/nghttp" "-I{compiler.sdk.path}/include/lwip" compiler.c.cmd=xtensa-esp32-elf-gcc compiler.c.flags=-std=gnu99 -Os -g3 -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wpointer-arith {compiler.warning_flags} -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -Wno-old-style-declaration -MMD -c diff --git a/tools/sdk/include/mbedtls/mbedtls/bignum.h b/tools/sdk/include/mbedtls/mbedtls/bignum.h index 23cd56348a7..431f67674c9 100644 --- a/tools/sdk/include/mbedtls/mbedtls/bignum.h +++ b/tools/sdk/include/mbedtls/mbedtls/bignum.h @@ -1,20 +1,712 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +/** + * \file bignum.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BIGNUM_H +#define MBEDTLS_BIGNUM_H + +#include "esp_config.h" + +#include +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#define MBEDTLS_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define MBEDTLS_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define MBEDTLS_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define MBEDTLS_ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MBEDTLS_MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define MBEDTLS_MPI_MAX_LIMBS 10000 + +#if !defined(MBEDTLS_MPI_WINDOW_SIZE) +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +#endif /* !MBEDTLS_MPI_WINDOW_SIZE */ + +#if !defined(MBEDTLS_MPI_MAX_SIZE) +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) + * + * Note: Calculations can results temporarily in larger MPIs. So the number + * of limbs required (MBEDTLS_MPI_MAX_LIMBS) is higher. + */ +#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ +#endif /* !MBEDTLS_MPI_MAX_SIZE */ + +#define MBEDTLS_MPI_MAX_BITS ( 8 * MBEDTLS_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mbedtls_mpi_read_file() and writing to files with + * mbedtls_mpi_write_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + * Autosized at compile time for at least a 10 char label, a minimum radix + * of 10 (decimal) for a number of MBEDTLS_MPI_MAX_BITS size. + * + * This used to be statically sized to 1250 for a maximum of 4096 bit + * numbers (1234 decimal chars). + * + * Calculate using the formula: + * MBEDTLS_MPI_RW_BUFFER_SIZE = ceil(MBEDTLS_MPI_MAX_BITS / ln(10) * ln(2)) + + * LabelSize + 6 + */ +#define MBEDTLS_MPI_MAX_BITS_SCALE100 ( 100 * MBEDTLS_MPI_MAX_BITS ) +#define MBEDTLS_LN_2_DIV_LN_10_SCALE100 332 +#define MBEDTLS_MPI_RW_BUFFER_SIZE ( ((MBEDTLS_MPI_MAX_BITS_SCALE100 + MBEDTLS_LN_2_DIV_LN_10_SCALE100 - 1) / MBEDTLS_LN_2_DIV_LN_10_SCALE100) + 10 + 6 ) + +/* + * Define the base integer type, architecture-wise. + * + * 32-bit integers can be forced on 64-bit arches (eg. for testing purposes) + * by defining MBEDTLS_HAVE_INT32 and undefining MBEDTLS_HAVE_ASM + */ +#if ( ! defined(MBEDTLS_HAVE_INT32) && \ + defined(_MSC_VER) && defined(_M_AMD64) ) + #define MBEDTLS_HAVE_INT64 + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; +#else + #if ( ! defined(MBEDTLS_HAVE_INT32) && \ + defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__s390x__) || defined(__mips64) ) ) + #define MBEDTLS_HAVE_INT64 + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + /* mbedtls_t_udbl defined as 128-bit unsigned int */ + typedef unsigned int mbedtls_t_udbl __attribute__((mode(TI))); + #define MBEDTLS_HAVE_UDBL + #else + #define MBEDTLS_HAVE_INT32 + typedef int32_t mbedtls_mpi_sint; + typedef uint32_t mbedtls_mpi_uint; + typedef uint64_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_HAVE_INT32 && __GNUC__ && 64-bit platform */ +#endif /* !MBEDTLS_HAVE_INT32 && _MSC_VER && _M_AMD64 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + mbedtls_mpi_uint *p; /*!< pointer to limbs */ +} +mbedtls_mpi; + +/** + * \brief Initialize one MPI (make internal references valid) + * This just makes it ready to be set or freed, + * but does not define a value for the MPI. + * + * \param X One MPI to initialize. + */ +void mbedtls_mpi_init( mbedtls_mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mbedtls_mpi_free( mbedtls_mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Resize down, keeping at least the specified number of limbs + * + * \param X MPI to shrink + * \param nblimbs The minimum number of limbs to keep + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); + +/** + * \brief Safe conditional assignement X = Y if assign is 1 + * + * \param X MPI to conditionally assign to + * \param Y Value to be assigned + * \param assign 1: perform the assignment, 0: keep X's original value + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_copy( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Safe conditional swap X <-> Y if swap is 1 + * + * \param X First mbedtls_mpi value + * \param Y Second mbedtls_mpi value + * \param assign 1: perform the swap, 0: keep X and Y's original values + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_swap( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ); + +/** + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of zero-bits before the least significant + * '1' bit + * + * Note: Thus also the zero-based index of the least significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ); + +/** + * \brief Return the number of bits up to and including the most + * significant '1' bit' + * + * Note: Thus also the one-based index of the most significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param buf Buffer to write the string to + * \param buflen Length of buf + * \param olen Length of the string written, including final NUL byte + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with buflen = 0 to obtain the + * minimum required buffer size in *olen. + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Read X from an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian. + * Always fills the whole buffer, which will start with zeros + * if the number is smaller. + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Unsigned subtraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed subtraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Signed subtraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The unsigned integer value to multiply with + * + * \note b is unsigned + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ); + +/** + * \brief Division by mbedtls_mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination mbedtls_mpi_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or even or + * if E is negative + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or nil + MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits + * ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_mpi_self_test( int verbose ); -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef __ESP_MBEDTLS_BIGNUM_H__ -#define __ESP_MBEDTLS_BIGNUM_H__ -#include_next "mbedtls/bignum.h" /** * This is a wrapper for the main mbedtls/bignum.h. This wrapper @@ -75,4 +767,12 @@ void esp_mpi_release_hardware(void); */ int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); + + +#ifdef __cplusplus +} #endif + +#endif /* bignum.h */ + +