Add WiFiClient secure lib (#184)

* Provide SSL/TLS functions to ESP32 with Arduino IDE

* Generate a new random number in case of reconnection
This commit is contained in:
copercini 2017-02-10 20:20:24 -02:00 committed by Me No Dev
parent 0fb5e5ca11
commit 8ab3231e31
7 changed files with 766 additions and 0 deletions

View File

@ -0,0 +1,76 @@
/*
Wifi secure connection example for ESP32
Running on TLS 1.2 using mbedTLS
Suporting the following 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 - Apache 2.0 License.
*/
#include <WiFiClientSecure.h>
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
WiFiClientSecure 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!");
Serial.print("Waiting for response "); //WiFiClientSecure uses a non blocking implementation
while (!client.available()){
delay(50); //
Serial.print(".");
}
// 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
}

View File

@ -0,0 +1,35 @@
#######################################
# Syntax Coloring Map For WiFi
#######################################
#######################################
# Library (KEYWORD3)
#######################################
WiFiClientSecure KEYWORD3
#######################################
# Datatypes (KEYWORD1)
#######################################
WiFiClientSecure KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
connect KEYWORD2
write KEYWORD2
available KEYWORD2
config KEYWORD2
read KEYWORD2
flush KEYWORD2
stop KEYWORD2
connected KEYWORD2
setCACert KEYWORD2
setCertificate KEYWORD2
setPrivateKey KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,9 @@
name=WiFiClientSecure
version=1.0
author=Evandro Luis Copercini
maintainer=Github Community
sentence=Enables secure network connection (local and Internet) using the ESP32 built-in WiFi.
paragraph=With this library you can make a TLS or SSL connection to a remote server.
category=Communication
url=
architectures=esp32

View File

@ -0,0 +1,190 @@
/*
WiFiClientSecure.cpp - Client Secure class for ESP32
Copyright (c) 2016 Hristo Gochkov All right reserved.
Additions Copyright (C) 2017 Evandro Luis Copercini.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "WiFiClientSecure.h"
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include <errno.h>
#undef connect
#undef write
#undef read
WiFiClientSecure::WiFiClientSecure()
{
_connected = false;
sslclient = new sslclient_context;
ssl_init(sslclient);
sslclient->socket = -1;
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
}
WiFiClientSecure::WiFiClientSecure(int sock)
{
_connected = false;
sslclient = new sslclient_context;
ssl_init(sslclient);
sslclient->socket = sock;
if (sock >= 0) {
_connected = true;
}
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
}
WiFiClientSecure::~WiFiClientSecure()
{
stop();
}
WiFiClientSecure &WiFiClientSecure::operator=(const WiFiClientSecure &other)
{
stop();
sslclient->socket = other.sslclient->socket;
_connected = other._connected;
return *this;
}
void WiFiClientSecure::stop()
{
if (_connected && sslclient->socket >= 0) {
stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key);
sslclient->socket = -1;
_connected = false;
}
}
int WiFiClientSecure::connect(IPAddress ip, uint16_t port)
{
connect(ip, port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecure::connect(const char *host, uint16_t port)
{
connect(host, port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecure::connect(IPAddress ip, uint16_t port, unsigned char *_CA_cert, unsigned char *_cert, unsigned char *_private_key)
{
int ret = start_ssl_client(sslclient, ip, port, _CA_cert, _cert, _private_key);
if (ret < 0) {
log_e("lwip_connect_r: %d", errno);
}
_connected = true;
return 1;
}
int WiFiClientSecure::connect(const char *host, uint16_t port, unsigned char *_CA_cert, unsigned char *_cert, unsigned char *_private_key)
{
struct hostent *server;
server = gethostbyname(host);
if (server == NULL) {
return 0;
}
IPAddress srv((const uint8_t *)(server->h_addr));
return connect(srv, port, _CA_cert, _cert, _private_key);
}
size_t WiFiClientSecure::write(uint8_t data)
{
return write(&data, 1);
}
int WiFiClientSecure::read()
{
uint8_t data = 0;
int res = read(&data, 1);
if (res < 0) {
return res;
}
return data;
}
size_t WiFiClientSecure::write(const uint8_t *buf, size_t size)
{
if (!_connected) {
return 0;
}
int res = send_ssl_data(sslclient, buf, size);
if (res < 0) {
log_e("%d", errno);
stop();
res = 0;
}
return res;
}
int WiFiClientSecure::read(uint8_t *buf, size_t size)
{
if (!available()) {
return -1;
}
int res = get_ssl_receive(sslclient, buf, size);
if (res < 0 && errno != EWOULDBLOCK) {
printf("%d", errno);
stop();
}
return res;
}
int WiFiClientSecure::available()
{
if (!_connected) {
return 0;
}
int res = data_to_read(sslclient);
return res;
}
uint8_t WiFiClientSecure::connected()
{
uint8_t dummy = 0;
read(&dummy, 0);
return _connected;
}
void WiFiClientSecure::setCACert(unsigned char *rootCA)
{
_CA_cert = rootCA;
}
void WiFiClientSecure::setCertificate (unsigned char *client_ca)
{
_cert = client_ca;
}
void WiFiClientSecure::setPrivateKey (unsigned char *private_key)
{
_private_key = private_key;
}

View File

@ -0,0 +1,92 @@
/*
WiFiClientSecure.h - Base class that provides Client SSL to ESP32
Copyright (c) 2011 Adrian McEwen. All right reserved.
Additions Copyright (C) 2017 Evandro Luis Copercini.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef WiFiClientSecure_h
#define WiFiClientSecure_h
#include "Arduino.h"
#include "IPAddress.h"
#include <WiFi.h>
#include "ssl_client.h"
class WiFiClientSecure : public Client
{
protected:
bool _connected;
sslclient_context *sslclient;
unsigned char *_CA_cert;
unsigned char *_cert;
unsigned char *_private_key;
public:
WiFiClientSecure *next;
WiFiClientSecure();
WiFiClientSecure(int socket);
~WiFiClientSecure();
int connect(IPAddress ip, uint16_t port);
int connect(const char *host, uint16_t port);
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);
size_t write(uint8_t data);
size_t write(const uint8_t *buf, size_t size);
int available();
int read();
int read(uint8_t *buf, size_t size);
int peek()
{
return 0;
}
void flush() {}
void stop();
uint8_t connected();
void setCACert(unsigned char *rootCA);
void setCertificate(unsigned char *client_ca);
void setPrivateKey (unsigned char *private_key);
operator bool()
{
return connected();
}
WiFiClientSecure &operator=(const WiFiClientSecure &other);
bool operator==(const bool value)
{
return bool() == value;
}
bool operator!=(const bool value)
{
return bool() != value;
}
bool operator==(const WiFiClientSecure &);
bool operator!=(const WiFiClientSecure &rhs)
{
return !this->operator==(rhs);
};
int socket()
{
return sslclient->socket = -1;
}
//friend class WiFiServer;
using Print::write;
};
#endif /* _WIFICLIENT_H_ */

View File

@ -0,0 +1,327 @@
/* 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 <lwip/sockets.h>
#include <lwip/err.h>
#include <lwip/sockets.h>
#include <lwip/sys.h>
#include <lwip/netdb.h>
#include "ssl_client.h"
const char *pers = "esp32-tls";
#define DEBUG true //Set false to supress debug messages
#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_ssl_init(&ssl_client->ssl_ctx);
mbedtls_ssl_config_init(&ssl_client->ssl_conf);
mbedtls_ctr_drbg_init(&ssl_client->drbg_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->socket = -1;
ssl_client->socket = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ssl_client->socket < 0) {
printf("\r\nERROR opening socket\r\n");
return ssl_client->socket;
}
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->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) {
timeout = 30000;
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
} else {
printf("\r\nConnect to Server failed!\r\n");
ret = -1;
break;
}
fcntl( ssl_client->socket, F_SETFL, fcntl( ssl_client->socket, F_GETFL, 0 ) | O_NONBLOCK );
DEBUG_PRINT( "Seeding the random number generator\n");
mbedtls_entropy_init(&ssl_client->entropy_ctx);
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, strlen((const char *)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((const char *)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((const char *)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);
}
/*
// TODO: implement match CN verification
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_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;
}
mbedtls_ssl_set_bio(&ssl_client->ssl_ctx, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL );
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 && ret != -76) {
printf( "mbedtls_ssl_handshake returned -0x%x\n", -ret);
break;
}
delay(10);
vPortYield();
}
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) {
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);
stop_ssl_socket(ssl_client, rootCABuff, cli_cert, cli_key); //It's not safe continue.
} else {
DEBUG_PRINT( "Certificate verified.\n");
}
} while (0);
DEBUG_PRINT("Free heap after TLS %u\n", xPortGetFreeHeapSize());
return ssl_client->socket;
}
void stop_ssl_socket(sslclient_context *ssl_client, unsigned char *rootCABuff, unsigned char *cli_cert, unsigned char *cli_key)
{
DEBUG_PRINT( "\nCleaning SSL connection.\n");
close(ssl_client->socket);
ssl_client->socket = -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);
if (rootCABuff != NULL) {
mbedtls_x509_crt_free(&ssl_client->ca_cert);
}
if (cli_cert != NULL) {
mbedtls_x509_crt_free(&ssl_client->client_cert);
}
if (cli_key != NULL) {
mbedtls_pk_free(&ssl_client->client_key);
}
}
int data_to_read(sslclient_context *ssl_client)
{
int ret, res;
ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, NULL, 0);
//printf("RET: %i\n",ret); //for low level debug
res = mbedtls_ssl_get_bytes_avail(&ssl_client->ssl_ctx);
//printf("RES: %i\n",res);
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0 && ret != -76) {
printf("MbedTLS error %i", ret);
}
return res;
}
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len)
{
//DEBUG_PRINT( "Writing HTTP request...\n"); //for low level debug
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 && ret != -76) {
printf( "mbedtls_ssl_write returned -0x%x\n", -ret);
break;
}
}
len = ret;
//DEBUG_PRINT( "%d bytes written\n", len); //for low level debug
return ret;
}
int get_ssl_receive(sslclient_context *ssl_client, uint8_t *data, int length)
{
//DEBUG_PRINT( "Reading HTTP response...\n"); //for low level debug
int ret = -1;
ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, data, length);
//DEBUG_PRINT( "%d bytes readed\n", ret); //for low level debug
return ret;
}

View File

@ -0,0 +1,37 @@
/* Provide SSL/TLS functions to ESP32 with Arduino IDE
* by Evandro Copercini - 2017 - Apache 2.0 License
*/
#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 socket;
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, unsigned char *rootCABuff, unsigned char *cli_cert, unsigned char *cli_key);
int data_to_read(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);
#endif