Skip to content
This repository was archived by the owner on Jan 20, 2025. It is now read-only.

Commit 081e750

Browse files
committed
WIP: start of TLS negotiation on nonblocking socket
1 parent d62f9c9 commit 081e750

2 files changed

Lines changed: 318 additions & 0 deletions

File tree

src/AsyncTCP_TLS_Context.cpp

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
#include <Arduino.h>
2+
#include <esp32-hal-log.h>
3+
#include <lwip/err.h>
4+
#include <lwip/sockets.h>
5+
#include <lwip/sys.h>
6+
#include <lwip/netdb.h>
7+
#include <mbedtls/sha256.h>
8+
#include <mbedtls/oid.h>
9+
10+
11+
#include "AsyncTCP_TLS_Context.h"
12+
13+
#if ASYNC_TCP_SSL_ENABLED
14+
#ifndef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
15+
# warning "Please configure IDF framework to include mbedTLS -> Enable pre-shared-key ciphersuites and activate at least one cipher"
16+
#else
17+
18+
static const char *pers = "esp32-tls";
19+
20+
static int _handle_error(int err, const char * function, int line)
21+
{
22+
if(err == -30848){
23+
return err;
24+
}
25+
#ifdef MBEDTLS_ERROR_C
26+
char error_buf[100];
27+
mbedtls_strerror(err, error_buf, 100);
28+
log_e("[%s():%d]: (%d) %s", function, line, err, error_buf);
29+
#else
30+
log_e("[%s():%d]: code %d", function, line, err);
31+
#endif
32+
return err;
33+
}
34+
35+
#define handle_error(e) _handle_error(e, __FUNCTION__, __LINE__)
36+
37+
AsyncTCP_TLS_Context::AsyncTCP_TLS_Context(void)
38+
{
39+
mbedtls_ssl_init(&ssl_ctx);
40+
mbedtls_ssl_config_init(&ssl_conf);
41+
mbedtls_ctr_drbg_init(&drbg_ctx);
42+
_socket = -1;
43+
_have_ca_cert = false;
44+
_have_client_cert = false;
45+
_have_client_key = false;
46+
handshake_timeout = 120000;
47+
}
48+
49+
int AsyncTCP_TLS_Context::startSSLClient(int sck, const char * host_or_ip, const char *rootCABuff,
50+
const char *cli_cert, const char *cli_key, const char *pskIdent,
51+
const char *psKey, bool insecure)
52+
{
53+
int ret;
54+
int enable = 1;
55+
56+
// The insecure flag will skip server certificate validation. Otherwise some
57+
// certificate is required.
58+
if (rootCABuff == NULL && pskIdent == NULL && psKey == NULL && !insecure) {
59+
return -1;
60+
}
61+
62+
#define ROE(x,msg) { if (((x)<0)) { log_e("LWIP Socket config of " msg " failed."); return -1; }}
63+
// ROE(lwip_setsockopt(sck, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)),"SO_RCVTIMEO");
64+
// ROE(lwip_setsockopt(sck, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)),"SO_SNDTIMEO");
65+
66+
ROE(lwip_setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)),"TCP_NODELAY");
67+
ROE(lwip_setsockopt(sck, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),"SO_KEEPALIVE");
68+
69+
log_v("Seeding the random number generator");
70+
mbedtls_entropy_init(&entropy_ctx);
71+
72+
ret = mbedtls_ctr_drbg_seed(&drbg_ctx, mbedtls_entropy_func,
73+
&entropy_ctx, (const unsigned char *) pers, strlen(pers));
74+
if (ret < 0) {
75+
return handle_error(ret);
76+
}
77+
78+
log_v("Setting up the SSL/TLS structure...");
79+
80+
if ((ret = mbedtls_ssl_config_defaults(&ssl_conf,
81+
MBEDTLS_SSL_IS_CLIENT,
82+
MBEDTLS_SSL_TRANSPORT_STREAM,
83+
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
84+
return handle_error(ret);
85+
}
86+
87+
if (insecure) {
88+
mbedtls_ssl_conf_authmode(&ssl_conf, MBEDTLS_SSL_VERIFY_NONE);
89+
log_i("WARNING: Skipping SSL Verification. INSECURE!");
90+
} else if (rootCABuff != NULL) {
91+
log_v("Loading CA cert");
92+
mbedtls_x509_crt_init(&ca_cert);
93+
mbedtls_ssl_conf_authmode(&ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
94+
ret = mbedtls_x509_crt_parse(&ca_cert, (const unsigned char *)rootCABuff, strlen(rootCABuff) + 1);
95+
_have_ca_cert = true;
96+
mbedtls_ssl_conf_ca_chain(&ssl_conf, &ca_cert, NULL);
97+
if (ret < 0) {
98+
// free the ca_cert in the case parse failed, otherwise, the old ca_cert still in the heap memory, that lead to "out of memory" crash.
99+
_deleteHandshakeCerts();
100+
return handle_error(ret);
101+
}
102+
} else if (pskIdent != NULL && psKey != NULL) {
103+
log_v("Setting up PSK");
104+
// convert PSK from hex to binary
105+
if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2*MBEDTLS_PSK_MAX_LEN) {
106+
log_e("pre-shared key not valid hex or too long");
107+
return -1;
108+
}
109+
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
110+
size_t psk_len = strlen(psKey)/2;
111+
for (int j=0; j<strlen(psKey); j+= 2) {
112+
char c = psKey[j];
113+
if (c >= '0' && c <= '9') c -= '0';
114+
else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
115+
else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
116+
else return -1;
117+
psk[j/2] = c<<4;
118+
c = psKey[j+1];
119+
if (c >= '0' && c <= '9') c -= '0';
120+
else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
121+
else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
122+
else return -1;
123+
psk[j/2] |= c;
124+
}
125+
// set mbedtls config
126+
ret = mbedtls_ssl_conf_psk(&ssl_conf, psk, psk_len,
127+
(const unsigned char *)pskIdent, strlen(pskIdent));
128+
if (ret != 0) {
129+
log_e("mbedtls_ssl_conf_psk returned %d", ret);
130+
return handle_error(ret);
131+
}
132+
} else {
133+
return -1;
134+
}
135+
136+
if (!insecure && cli_cert != NULL && cli_key != NULL) {
137+
mbedtls_x509_crt_init(&client_cert);
138+
mbedtls_pk_init(&client_key);
139+
140+
log_v("Loading CRT cert");
141+
142+
ret = mbedtls_x509_crt_parse(&client_cert, (const unsigned char *)cli_cert, strlen(cli_cert) + 1);
143+
_have_client_cert = true;
144+
if (ret < 0) {
145+
// free the client_cert in the case parse failed, otherwise, the old client_cert still in the heap memory, that lead to "out of memory" crash.
146+
_deleteHandshakeCerts();
147+
return handle_error(ret);
148+
}
149+
150+
log_v("Loading private key");
151+
ret = mbedtls_pk_parse_key(&client_key, (const unsigned char *)cli_key, strlen(cli_key) + 1, NULL, 0);
152+
_have_client_key = true;
153+
154+
if (ret != 0) {
155+
_deleteHandshakeCerts();
156+
return handle_error(ret);
157+
}
158+
159+
mbedtls_ssl_conf_own_cert(&ssl_conf, &client_cert, &client_key);
160+
}
161+
162+
log_v("Setting hostname for TLS session...");
163+
164+
// Hostname set here should match CN in server certificate
165+
if((ret = mbedtls_ssl_set_hostname(&ssl_ctx, host_or_ip)) != 0){
166+
_deleteHandshakeCerts();
167+
return handle_error(ret);
168+
}
169+
170+
mbedtls_ssl_conf_rng(&ssl_conf, mbedtls_ctr_drbg_random, &drbg_ctx);
171+
172+
if ((ret = mbedtls_ssl_setup(&ssl_ctx, &ssl_conf)) != 0) {
173+
_deleteHandshakeCerts();
174+
return handle_error(ret);
175+
}
176+
177+
_socket = sck;
178+
mbedtls_ssl_set_bio(&ssl_ctx, &_socket, mbedtls_net_send, mbedtls_net_recv, NULL );
179+
handshake_start_time = 0;
180+
181+
return 0;
182+
}
183+
184+
int AsyncTCP_TLS_Context::runSSLHandshake(void)
185+
{
186+
if (_socket < 0) return -1;
187+
188+
if (handshake_start_time == 0) handshake_start_time = millis();
189+
int ret = mbedtls_ssl_handshake(&ssl_ctx);
190+
if (ret != 0) {
191+
// Something happened before SSL handshake could be completed
192+
193+
// Negotiation error, other than socket not readable/writable when required
194+
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
195+
return handle_error(ret);
196+
}
197+
198+
// Handshake is taking too long
199+
if ((millis()-handshake_start_time) > ssl_client->handshake_timeout)
200+
return -1;
201+
202+
// Either MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE
203+
return ret;
204+
}
205+
206+
// Handshake completed, validate remote side if required...
207+
208+
if (_have_client_cert && _have_client_key) {
209+
log_d("Protocol is %s Ciphersuite is %s", mbedtls_ssl_get_version(&ssl_ctx), mbedtls_ssl_get_ciphersuite(&ssl_ctx));
210+
if ((ret = mbedtls_ssl_get_record_expansion(&ssl_ctx)) >= 0) {
211+
log_d("Record expansion is %d", ret);
212+
} else {
213+
log_w("Record expansion is unknown (compression)");
214+
}
215+
}
216+
217+
log_v("Verifying peer X.509 certificate...");
218+
219+
if ((flags = mbedtls_ssl_get_verify_result(&ssl_ctx)) != 0) {
220+
memset(buf, 0, sizeof(buf));
221+
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
222+
log_e("Failed to verify peer certificate! verification info: %s", buf);
223+
_deleteHandshakeCerts();
224+
return handle_error(ret);
225+
} else {
226+
log_v("Certificate verified.");
227+
}
228+
229+
_deleteHandshakeCerts();
230+
231+
log_v("Free internal heap after TLS %u", ESP.getFreeHeap());
232+
233+
return 0;
234+
}
235+
236+
void AsyncTCP_TLS_Context::_deleteHandshakeCerts(void)
237+
{
238+
if (_have_ca_cert) {
239+
mbedtls_x509_crt_free(&ca_cert);
240+
_have_ca_cert = false;
241+
}
242+
if (_have_client_cert) {
243+
mbedtls_x509_crt_free(&client_cert);
244+
_have_client_cert = false;
245+
}
246+
if (_have_client_key) {
247+
mbedtls_pk_free(&client_key);
248+
_have_client_key = false;
249+
}
250+
}
251+
252+
AsyncTCP_TLS_Context::~AsyncTCP_TLS_Context()
253+
{
254+
_deleteHandshakeCerts();
255+
256+
mbedtls_ssl_free(&ssl_ctx);
257+
mbedtls_ssl_config_free(&ssl_conf);
258+
mbedtls_ctr_drbg_free(&drbg_ctx);
259+
mbedtls_entropy_free(&entropy_ctx); // <-- Is this OK to free if mbedtls_entropy_init() has not been called on it?
260+
}
261+
262+
#endif
263+
#endif // ASYNC_TCP_SSL_ENABLED

src/AsyncTCP_TLS_Context.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#pragma once
2+
3+
// TODO: se debe quitar este #define para que pueda habilitarse a voluntad el SSL
4+
// según el proyecto. Se coloca aquí para probar el desarrollo
5+
#define ASYNC_TCP_SSL_ENABLED 1
6+
7+
#if ASYNC_TCP_SSL_ENABLED
8+
9+
#include "mbedtls/platform.h"
10+
#include "mbedtls/net.h"
11+
#include "mbedtls/debug.h"
12+
#include "mbedtls/ssl.h"
13+
#include "mbedtls/entropy.h"
14+
#include "mbedtls/ctr_drbg.h"
15+
#include "mbedtls/error.h"
16+
17+
class AsyncTCP_TLS_Context
18+
{
19+
private:
20+
// These fields must persist for the life of the encrypted connection, destroyed on
21+
// object destructor.
22+
mbedtls_ssl_context ssl_ctx;
23+
mbedtls_ssl_config ssl_conf;
24+
mbedtls_ctr_drbg_context drbg_ctx;
25+
mbedtls_entropy_context entropy_ctx;
26+
27+
// These allocate memory during handshake but must be freed on either success or failure
28+
mbedtls_x509_crt ca_cert;
29+
mbedtls_x509_crt client_cert;
30+
mbedtls_pk_context client_key;
31+
bool _have_ca_cert;
32+
bool _have_client_cert;
33+
bool _have_client_key;
34+
35+
unsigned long handshake_timeout;
36+
unsigned long handshake_start_time;
37+
38+
int _socket;
39+
40+
41+
42+
// Delete certificates used in handshake
43+
void _deleteHandshakeCerts(void);
44+
public:
45+
AsyncTCP_TLS_Context(void);
46+
virtual ~AsyncTCP_TLS_Context();
47+
48+
int startSSLClient(int sck, const char * host_or_ip, const char *rootCABuff,
49+
const char *cli_cert, const char *cli_key, const char *pskIdent,
50+
const char *psKey, bool insecure);
51+
52+
int runSSLHandshake(void);
53+
};
54+
55+
#endif // ASYNC_TCP_SSL_ENABLED

0 commit comments

Comments
 (0)