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:
parent
0fb5e5ca11
commit
8ab3231e31
@ -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
|
||||||
|
}
|
35
libraries/WiFiClientSecure/keywords.txt
Normal file
35
libraries/WiFiClientSecure/keywords.txt
Normal 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)
|
||||||
|
#######################################
|
9
libraries/WiFiClientSecure/library.properties
Normal file
9
libraries/WiFiClientSecure/library.properties
Normal 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
|
190
libraries/WiFiClientSecure/src/WiFiClientSecure.cpp
Normal file
190
libraries/WiFiClientSecure/src/WiFiClientSecure.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
92
libraries/WiFiClientSecure/src/WiFiClientSecure.h
Normal file
92
libraries/WiFiClientSecure/src/WiFiClientSecure.h
Normal 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_ */
|
327
libraries/WiFiClientSecure/src/ssl_client.cpp
Normal file
327
libraries/WiFiClientSecure/src/ssl_client.cpp
Normal 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;
|
||||||
|
}
|
37
libraries/WiFiClientSecure/src/ssl_client.h
Normal file
37
libraries/WiFiClientSecure/src/ssl_client.h
Normal 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
|
Loading…
Reference in New Issue
Block a user