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
0 commit comments