1 /*
2  * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netdb.h>
14 
15 #include <http_parser.h>
16 #include "esp_tls.h"
17 #include "esp_tls_error_capture_internal.h"
18 #include <errno.h>
19 static const char *TAG = "esp-tls";
20 
21 #ifdef CONFIG_ESP_TLS_USING_MBEDTLS
22 #include "esp_tls_mbedtls.h"
23 #elif CONFIG_ESP_TLS_USING_WOLFSSL
24 #include "esp_tls_wolfssl.h"
25 #endif
26 
27 #ifdef ESP_PLATFORM
28 #include <esp_log.h>
29 #else
30 #define ESP_LOGD(TAG, ...) //printf(__VA_ARGS__);
31 #define ESP_LOGE(TAG, ...) printf(__VA_ARGS__);
32 #endif
33 
34 #ifdef CONFIG_ESP_TLS_USING_MBEDTLS
35 #define _esp_create_ssl_handle              esp_create_mbedtls_handle
36 #define _esp_tls_handshake                  esp_mbedtls_handshake
37 #define _esp_tls_read                       esp_mbedtls_read
38 #define _esp_tls_write                      esp_mbedtls_write
39 #define _esp_tls_conn_delete                esp_mbedtls_conn_delete
40 #define _esp_tls_net_init                   esp_mbedtls_net_init
41 #define _esp_tls_get_client_session         esp_mbedtls_get_client_session
42 #ifdef CONFIG_ESP_TLS_SERVER
43 #define _esp_tls_server_session_create      esp_mbedtls_server_session_create
44 #define _esp_tls_server_session_delete      esp_mbedtls_server_session_delete
45 #define _esp_tls_server_session_ticket_ctx_init    esp_mbedtls_server_session_ticket_ctx_init
46 #define _esp_tls_server_session_ticket_ctx_free    esp_mbedtls_server_session_ticket_ctx_free
47 #endif  /* CONFIG_ESP_TLS_SERVER */
48 #define _esp_tls_get_bytes_avail            esp_mbedtls_get_bytes_avail
49 #define _esp_tls_init_global_ca_store       esp_mbedtls_init_global_ca_store
50 #define _esp_tls_set_global_ca_store        esp_mbedtls_set_global_ca_store                 /*!< Callback function for setting global CA store data for TLS/SSL */
51 #define _esp_tls_get_global_ca_store        esp_mbedtls_get_global_ca_store
52 #define _esp_tls_free_global_ca_store       esp_mbedtls_free_global_ca_store                /*!< Callback function for freeing global ca store for TLS/SSL */
53 #elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */
54 #define _esp_create_ssl_handle              esp_create_wolfssl_handle
55 #define _esp_tls_handshake                  esp_wolfssl_handshake
56 #define _esp_tls_read                       esp_wolfssl_read
57 #define _esp_tls_write                      esp_wolfssl_write
58 #define _esp_tls_conn_delete                esp_wolfssl_conn_delete
59 #define _esp_tls_net_init                   esp_wolfssl_net_init
60 #ifdef CONFIG_ESP_TLS_SERVER
61 #define _esp_tls_server_session_create      esp_wolfssl_server_session_create
62 #define _esp_tls_server_session_delete      esp_wolfssl_server_session_delete
63 #endif  /* CONFIG_ESP_TLS_SERVER */
64 #define _esp_tls_get_bytes_avail            esp_wolfssl_get_bytes_avail
65 #define _esp_tls_init_global_ca_store       esp_wolfssl_init_global_ca_store
66 #define _esp_tls_set_global_ca_store        esp_wolfssl_set_global_ca_store                 /*!< Callback function for setting global CA store data for TLS/SSL */
67 #define _esp_tls_free_global_ca_store       esp_wolfssl_free_global_ca_store                /*!< Callback function for freeing global ca store for TLS/SSL */
68 #else   /* ESP_TLS_USING_WOLFSSL */
69 #error "No TLS stack configured"
70 #endif
71 
create_ssl_handle(const char * hostname,size_t hostlen,const void * cfg,esp_tls_t * tls)72 static esp_err_t create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls)
73 {
74     return _esp_create_ssl_handle(hostname, hostlen, cfg, tls);
75 }
76 
esp_tls_handshake(esp_tls_t * tls,const esp_tls_cfg_t * cfg)77 static esp_err_t esp_tls_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg)
78 {
79     return _esp_tls_handshake(tls, cfg);
80 }
81 
tcp_read(esp_tls_t * tls,char * data,size_t datalen)82 static ssize_t tcp_read(esp_tls_t *tls, char *data, size_t datalen)
83 {
84     return recv(tls->sockfd, data, datalen, 0);
85 }
86 
tcp_write(esp_tls_t * tls,const char * data,size_t datalen)87 static ssize_t tcp_write(esp_tls_t *tls, const char *data, size_t datalen)
88 {
89     return send(tls->sockfd, data, datalen, 0);
90 }
91 
92 /**
93  * @brief      Close the TLS connection and free any allocated resources.
94  */
esp_tls_conn_delete(esp_tls_t * tls)95 void esp_tls_conn_delete(esp_tls_t *tls)
96 {
97     esp_tls_conn_destroy(tls);
98 }
99 
esp_tls_conn_destroy(esp_tls_t * tls)100 int esp_tls_conn_destroy(esp_tls_t *tls)
101 {
102     if (tls != NULL) {
103         int ret = 0;
104         _esp_tls_conn_delete(tls);
105         if (tls->sockfd >= 0) {
106             ret = close(tls->sockfd);
107         }
108         esp_tls_internal_event_tracker_destroy(tls->error_handle);
109         free(tls);
110         return ret;
111     }
112     return -1; // invalid argument
113 }
114 
esp_tls_init(void)115 esp_tls_t *esp_tls_init(void)
116 {
117     esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t));
118     if (!tls) {
119         return NULL;
120     }
121     tls->error_handle = esp_tls_internal_event_tracker_create();
122     if (!tls->error_handle) {
123         free(tls);
124         return NULL;
125     }
126     _esp_tls_net_init(tls);
127     tls->sockfd = -1;
128     return tls;
129 }
130 
esp_tls_hostname_to_fd(const char * host,size_t hostlen,int port,struct sockaddr_storage * address,int * fd)131 static esp_err_t esp_tls_hostname_to_fd(const char *host, size_t hostlen, int port, struct sockaddr_storage *address, int* fd)
132 {
133     struct addrinfo *address_info;
134     struct addrinfo hints;
135     memset(&hints, 0, sizeof(hints));
136     hints.ai_family = AF_UNSPEC;
137     hints.ai_socktype = SOCK_STREAM;
138 
139     char *use_host = strndup(host, hostlen);
140     if (!use_host) {
141         return ESP_ERR_NO_MEM;
142     }
143 
144     ESP_LOGD(TAG, "host:%s: strlen %lu", use_host, (unsigned long)hostlen);
145     int res = getaddrinfo(use_host, NULL, &hints, &address_info);
146     if (res != 0 || address_info == NULL) {
147         ESP_LOGE(TAG, "couldn't get hostname for :%s: "
148                       "getaddrinfo() returns %d, addrinfo=%p", use_host, res, address_info);
149         free(use_host);
150         return ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME;
151     }
152     free(use_host);
153     *fd = socket(address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
154     if (*fd < 0) {
155         ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
156         freeaddrinfo(address_info);
157         return ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET;
158     }
159 
160     if (address_info->ai_family == AF_INET) {
161         struct sockaddr_in *p = (struct sockaddr_in *)address_info->ai_addr;
162         p->sin_port = htons(port);
163         ESP_LOGD(TAG, "[sock=%d] Resolved IPv4 address: %s", *fd, ipaddr_ntoa((const ip_addr_t*)&p->sin_addr.s_addr));
164         memcpy(address, p, sizeof(struct sockaddr ));
165     }
166 #if CONFIG_LWIP_IPV6
167     else if (address_info->ai_family == AF_INET6) {
168         struct sockaddr_in6 *p = (struct sockaddr_in6 *)address_info->ai_addr;
169         p->sin6_port = htons(port);
170         p->sin6_family = AF_INET6;
171         ESP_LOGD(TAG, "[sock=%d] Resolved IPv6 address: %s", *fd, ip6addr_ntoa((const ip6_addr_t*)&p->sin6_addr));
172         memcpy(address, p, sizeof(struct sockaddr_in6 ));
173     }
174 #endif
175     else {
176         ESP_LOGE(TAG, "Unsupported protocol family %d", address_info->ai_family);
177         close(*fd);
178         freeaddrinfo(address_info);
179         return ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY;
180     }
181 
182     freeaddrinfo(address_info);
183     return ESP_OK;
184 }
185 
ms_to_timeval(int timeout_ms,struct timeval * tv)186 static void ms_to_timeval(int timeout_ms, struct timeval *tv)
187 {
188     tv->tv_sec = timeout_ms / 1000;
189     tv->tv_usec = (timeout_ms % 1000) * 1000;
190 }
191 
esp_tls_set_socket_options(int fd,const esp_tls_cfg_t * cfg)192 static esp_err_t esp_tls_set_socket_options(int fd, const esp_tls_cfg_t *cfg)
193 {
194     if (cfg) {
195         if (cfg->timeout_ms >= 0) {
196             struct timeval tv;
197             ms_to_timeval(cfg->timeout_ms, &tv);
198             if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) {
199                 ESP_LOGE(TAG, "Fail to setsockopt SO_RCVTIMEO");
200                 return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
201             }
202             if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) {
203                 ESP_LOGE(TAG, "Fail to setsockopt SO_SNDTIMEO");
204                 return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
205             }
206         }
207         if (cfg->keep_alive_cfg && cfg->keep_alive_cfg->keep_alive_enable) {
208             int keep_alive_enable = 1;
209             int keep_alive_idle = cfg->keep_alive_cfg->keep_alive_idle;
210             int keep_alive_interval = cfg->keep_alive_cfg->keep_alive_interval;
211             int keep_alive_count = cfg->keep_alive_cfg->keep_alive_count;
212 
213             ESP_LOGD(TAG, "Enable TCP keep alive. idle: %d, interval: %d, count: %d", keep_alive_idle, keep_alive_interval, keep_alive_count);
214             if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) {
215                 ESP_LOGE(TAG, "Fail to setsockopt SO_KEEPALIVE");
216                 return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
217             }
218             if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_idle, sizeof(keep_alive_idle)) != 0) {
219                 ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPIDLE");
220                 return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
221             }
222             if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) != 0) {
223                 ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPINTVL");
224                 return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
225             }
226             if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) != 0) {
227                 ESP_LOGE(TAG, "Fail to setsockopt TCP_KEEPCNT");
228                 return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
229             }
230         }
231         if (cfg->if_name) {
232             if (cfg->if_name->ifr_name[0] != 0) {
233                 ESP_LOGD(TAG, "Bind [sock=%d] to interface %s", fd, cfg->if_name->ifr_name);
234                 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,  cfg->if_name, sizeof(struct ifreq)) != 0) {
235                     ESP_LOGE(TAG, "Bind [sock=%d] to interface %s fail", fd, cfg->if_name->ifr_name);
236                     return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
237                 }
238             }
239         }
240     }
241     return ESP_OK;
242 }
243 
esp_tls_set_socket_non_blocking(int fd,bool non_blocking)244 static esp_err_t esp_tls_set_socket_non_blocking(int fd, bool non_blocking)
245 {
246     int flags;
247     if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
248         ESP_LOGE(TAG, "[sock=%d] get file flags error: %s", fd, strerror(errno));
249         return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
250     }
251 
252     if (non_blocking) {
253         flags |= O_NONBLOCK;
254     } else {
255         flags &= ~O_NONBLOCK;
256     }
257 
258     if (fcntl(fd, F_SETFL, flags) < 0) {
259         ESP_LOGE(TAG, "[sock=%d] set blocking/nonblocking error: %s", fd, strerror(errno));
260         return ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
261     }
262     return ESP_OK;
263 }
264 
tcp_connect(const char * host,int hostlen,int port,const esp_tls_cfg_t * cfg,esp_tls_error_handle_t error_handle,int * sockfd)265 static inline esp_err_t tcp_connect(const char *host, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_error_handle_t error_handle, int *sockfd)
266 {
267     struct sockaddr_storage address;
268     int fd;
269     esp_err_t ret = esp_tls_hostname_to_fd(host, hostlen, port, &address, &fd);
270     if (ret != ESP_OK) {
271         ESP_INT_EVENT_TRACKER_CAPTURE(error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno);
272         return ret;
273     }
274 
275     // Set timeout options, keep-alive options and bind device options if configured
276     ret = esp_tls_set_socket_options(fd, cfg);
277     if (ret != ESP_OK) {
278         goto err;
279     }
280 
281     // Set to non block before connecting to better control connection timeout
282     ret = esp_tls_set_socket_non_blocking(fd, true);
283     if (ret != ESP_OK) {
284         goto err;
285     }
286 
287     ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST;
288     ESP_LOGD(TAG, "[sock=%d] Connecting to server. HOST: %s, Port: %d", fd, host, port);
289     if (connect(fd, (struct sockaddr *)&address, sizeof(struct sockaddr)) < 0) {
290         if (errno == EINPROGRESS) {
291             fd_set fdset;
292             struct timeval tv = { .tv_usec = 0, .tv_sec = 10 }; // Default connection timeout is 10 s
293 
294             if (cfg && cfg->non_block) {
295                 // Non-blocking mode -> just return successfully at this stage
296                 *sockfd = fd;
297                 return ESP_OK;
298             }
299 
300             if ( cfg && cfg->timeout_ms > 0 ) {
301                 ms_to_timeval(cfg->timeout_ms, &tv);
302             }
303             FD_ZERO(&fdset);
304             FD_SET(fd, &fdset);
305 
306             int res = select(fd+1, NULL, &fdset, NULL, &tv);
307             if (res < 0) {
308                 ESP_LOGE(TAG, "[sock=%d] select() error: %s", fd, strerror(errno));
309                 ESP_INT_EVENT_TRACKER_CAPTURE(error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno);
310                 goto err;
311             }
312             else if (res == 0) {
313                 ESP_LOGE(TAG, "[sock=%d] select() timeout", fd);
314                 ret = ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT;
315                 goto err;
316             } else {
317                 int sockerr;
318                 socklen_t len = (socklen_t)sizeof(int);
319 
320                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
321                     ESP_LOGE(TAG, "[sock=%d] getsockopt() error: %s", fd, strerror(errno));
322                     ret = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
323                     goto err;
324                 }
325                 else if (sockerr) {
326                     ESP_INT_EVENT_TRACKER_CAPTURE(error_handle, ESP_TLS_ERR_TYPE_SYSTEM, sockerr);
327                     ESP_LOGE(TAG, "[sock=%d] delayed connect error: %s", fd, strerror(sockerr));
328                     goto err;
329                 }
330             }
331         } else {
332             ESP_LOGE(TAG, "[sock=%d] connect() error: %s", fd, strerror(errno));
333             goto err;
334         }
335     }
336 
337     if (cfg && cfg->non_block == false) {
338         // reset back to blocking mode (unless non_block configured)
339         ret = esp_tls_set_socket_non_blocking(fd, false);
340         if (ret != ESP_OK) {
341             goto err;
342         }
343     }
344 
345     *sockfd = fd;
346     return ESP_OK;
347 
348 err:
349     close(fd);
350     return ret;
351 }
352 
esp_tls_low_level_conn(const char * hostname,int hostlen,int port,const esp_tls_cfg_t * cfg,esp_tls_t * tls)353 static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls)
354 {
355     if (!tls) {
356         ESP_LOGE(TAG, "empty esp_tls parameter");
357         return -1;
358     }
359     esp_err_t esp_ret;
360     /* These states are used to keep a tab on connection progress in case of non-blocking connect,
361     and in case of blocking connect these cases will get executed one after the other */
362     switch (tls->conn_state) {
363     case ESP_TLS_INIT:
364         tls->sockfd = -1;
365         if (cfg != NULL && cfg->is_plain_tcp == false) {
366             _esp_tls_net_init(tls);
367             tls->is_tls = true;
368         }
369         if ((esp_ret = tcp_connect(hostname, hostlen, port, cfg, tls->error_handle, &tls->sockfd)) != ESP_OK) {
370             ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, esp_ret);
371             return -1;
372         }
373         if (tls->is_tls == false) {
374             tls->read = tcp_read;
375             tls->write = tcp_write;
376             ESP_LOGD(TAG, "non-tls connection established");
377             return 1;
378         }
379         if (cfg && cfg->non_block) {
380             FD_ZERO(&tls->rset);
381             FD_SET(tls->sockfd, &tls->rset);
382             tls->wset = tls->rset;
383         }
384         tls->conn_state = ESP_TLS_CONNECTING;
385     /* falls through */
386     case ESP_TLS_CONNECTING:
387         if (cfg && cfg->non_block) {
388             ESP_LOGD(TAG, "connecting...");
389             struct timeval tv;
390             ms_to_timeval(cfg->timeout_ms, &tv);
391 
392             /* In case of non-blocking I/O, we use the select() API to check whether
393                connection has been established or not*/
394             if (select(tls->sockfd + 1, &tls->rset, &tls->wset, NULL,
395                        cfg->timeout_ms>0 ? &tv : NULL) == 0) {
396                 ESP_LOGD(TAG, "select() timed out");
397                 return 0;
398             }
399             if (FD_ISSET(tls->sockfd, &tls->rset) || FD_ISSET(tls->sockfd, &tls->wset)) {
400                 int error;
401                 socklen_t len = sizeof(error);
402                 /* pending error check */
403                 if (getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
404                     ESP_LOGD(TAG, "Non blocking connect failed");
405                     ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_SYSTEM, errno);
406                     ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED);
407                     tls->conn_state = ESP_TLS_FAIL;
408                     return -1;
409                 }
410             }
411         }
412         /* By now, the connection has been established */
413         esp_ret = create_ssl_handle(hostname, hostlen, cfg, tls);
414         if (esp_ret != ESP_OK) {
415             ESP_LOGE(TAG, "create_ssl_handle failed");
416             ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, esp_ret);
417             tls->conn_state = ESP_TLS_FAIL;
418             return -1;
419         }
420         tls->read = _esp_tls_read;
421         tls->write = _esp_tls_write;
422         tls->conn_state = ESP_TLS_HANDSHAKE;
423     /* falls through */
424     case ESP_TLS_HANDSHAKE:
425         ESP_LOGD(TAG, "handshake in progress...");
426         return esp_tls_handshake(tls, cfg);
427         break;
428     case ESP_TLS_FAIL:
429         ESP_LOGE(TAG, "failed to open a new connection");;
430         break;
431     default:
432         ESP_LOGE(TAG, "invalid esp-tls state");
433         break;
434     }
435     return -1;
436 }
437 
438 /**
439  * @brief Create a new plain TCP connection
440  */
esp_tls_plain_tcp_connect(const char * host,int hostlen,int port,const esp_tls_cfg_t * cfg,esp_tls_error_handle_t error_handle,int * sockfd)441 esp_err_t esp_tls_plain_tcp_connect(const char *host, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_error_handle_t error_handle, int *sockfd)
442 {
443     if (sockfd == NULL || error_handle == NULL) {
444         return ESP_ERR_INVALID_ARG;
445     }
446     return tcp_connect(host, hostlen, port, cfg, error_handle, sockfd);
447 }
448 
449 /**
450  * @brief      Create a new TLS/SSL connection
451  */
esp_tls_conn_new(const char * hostname,int hostlen,int port,const esp_tls_cfg_t * cfg)452 esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg)
453 {
454     esp_tls_t *tls = esp_tls_init();
455     if (!tls) {
456         return NULL;
457     }
458     /* esp_tls_conn_new() API establishes connection in a blocking manner thus this loop ensures that esp_tls_conn_new()
459        API returns only after connection is established unless there is an error*/
460     size_t start = xTaskGetTickCount();
461     while (1) {
462         int ret = esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls);
463         if (ret == 1) {
464             return tls;
465         } else if (ret == -1) {
466             esp_tls_conn_delete(tls);
467             ESP_LOGE(TAG, "Failed to open new connection");
468             return NULL;
469         } else if (ret == 0 && cfg->timeout_ms >= 0) {
470             size_t timeout_ticks = pdMS_TO_TICKS(cfg->timeout_ms);
471             uint32_t expired = xTaskGetTickCount() - start;
472             if (expired >= timeout_ticks) {
473                 esp_tls_conn_delete(tls);
474                 ESP_LOGE(TAG, "Failed to open new connection in specified timeout");
475                 return NULL;
476             }
477         }
478     }
479     return NULL;
480 }
481 
esp_tls_conn_new_sync(const char * hostname,int hostlen,int port,const esp_tls_cfg_t * cfg,esp_tls_t * tls)482 int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls)
483 {
484     /* esp_tls_conn_new_sync() is a sync alternative to esp_tls_conn_new_async() with symmetric function prototype
485     it is an alternative to esp_tls_conn_new() which is left for compatibility reasons */
486     size_t start = xTaskGetTickCount();
487     while (1) {
488         int ret = esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls);
489         if (ret == 1) {
490             return ret;
491         } else if (ret == -1) {
492             ESP_LOGE(TAG, "Failed to open new connection");
493             return -1;
494         } else if (ret == 0 && cfg->timeout_ms >= 0) {
495             size_t timeout_ticks = pdMS_TO_TICKS(cfg->timeout_ms);
496             uint32_t expired = xTaskGetTickCount() - start;
497             if (expired >= timeout_ticks) {
498                 ESP_LOGW(TAG, "Failed to open new connection in specified timeout");
499                 ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT);
500                 return 0;
501             }
502         }
503     }
504     return 0;
505 }
506 
507 /*
508  * @brief      Create a new TLS/SSL non-blocking connection
509  */
esp_tls_conn_new_async(const char * hostname,int hostlen,int port,const esp_tls_cfg_t * cfg,esp_tls_t * tls)510 int esp_tls_conn_new_async(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls)
511 {
512     return esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls);
513 }
514 
get_port(const char * url,struct http_parser_url * u)515 static int get_port(const char *url, struct http_parser_url *u)
516 {
517     if (u->field_data[UF_PORT].len) {
518         return strtol(&url[u->field_data[UF_PORT].off], NULL, 10);
519     } else {
520         if (strncasecmp(&url[u->field_data[UF_SCHEMA].off], "http", u->field_data[UF_SCHEMA].len) == 0) {
521             return 80;
522         } else if (strncasecmp(&url[u->field_data[UF_SCHEMA].off], "https", u->field_data[UF_SCHEMA].len) == 0) {
523             return 443;
524         }
525     }
526     return 0;
527 }
528 
529 /**
530  * @brief      Create a new TLS/SSL connection with a given "HTTP" url
531  */
esp_tls_conn_http_new(const char * url,const esp_tls_cfg_t * cfg)532 esp_tls_t *esp_tls_conn_http_new(const char *url, const esp_tls_cfg_t *cfg)
533 {
534     /* Parse URI */
535     struct http_parser_url u;
536     http_parser_url_init(&u);
537     http_parser_parse_url(url, strlen(url), 0, &u);
538     esp_tls_t *tls = esp_tls_init();
539     if (!tls) {
540         return NULL;
541     }
542     /* Connect to host */
543     if (esp_tls_conn_new_sync(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len,
544                               get_port(url, &u), cfg, tls) == 1) {
545         return tls;
546     }
547     esp_tls_conn_delete(tls);
548     return NULL;
549 }
550 
551 /**
552  * @brief      Create a new non-blocking TLS/SSL connection with a given "HTTP" url
553  */
esp_tls_conn_http_new_async(const char * url,const esp_tls_cfg_t * cfg,esp_tls_t * tls)554 int esp_tls_conn_http_new_async(const char *url, const esp_tls_cfg_t *cfg, esp_tls_t *tls)
555 {
556     /* Parse URI */
557     struct http_parser_url u;
558     http_parser_url_init(&u);
559     http_parser_parse_url(url, strlen(url), 0, &u);
560 
561     /* Connect to host */
562     return esp_tls_conn_new_async(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len,
563                                   get_port(url, &u), cfg, tls);
564 }
565 
566 #ifdef CONFIG_ESP_TLS_USING_MBEDTLS
567 
esp_tls_get_global_ca_store(void)568 mbedtls_x509_crt *esp_tls_get_global_ca_store(void)
569 {
570     return _esp_tls_get_global_ca_store();
571 }
572 
573 #endif /* CONFIG_ESP_TLS_USING_MBEDTLS */
574 
575 #ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS
esp_tls_get_client_session(esp_tls_t * tls)576 esp_tls_client_session_t *esp_tls_get_client_session(esp_tls_t *tls)
577 {
578     return _esp_tls_get_client_session(tls);
579 }
580 #endif /* CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS */
581 
582 
583 #ifdef CONFIG_ESP_TLS_SERVER
esp_tls_cfg_server_session_tickets_init(esp_tls_cfg_server_t * cfg)584 esp_err_t esp_tls_cfg_server_session_tickets_init(esp_tls_cfg_server_t *cfg)
585 {
586 #if defined(CONFIG_ESP_TLS_SERVER_SESSION_TICKETS)
587     if (!cfg || cfg->ticket_ctx) {
588         return ESP_ERR_INVALID_ARG;
589     }
590     cfg->ticket_ctx = calloc(1, sizeof(esp_tls_server_session_ticket_ctx_t));
591     if (!cfg->ticket_ctx) {
592         return ESP_ERR_NO_MEM;
593     }
594     esp_err_t ret =  _esp_tls_server_session_ticket_ctx_init(cfg->ticket_ctx);
595     if (ret != ESP_OK) {
596         free(cfg->ticket_ctx);
597     }
598     return ret;
599 #else
600     return ESP_ERR_NOT_SUPPORTED;
601 #endif
602 }
603 
esp_tls_cfg_server_session_tickets_free(esp_tls_cfg_server_t * cfg)604 void esp_tls_cfg_server_session_tickets_free(esp_tls_cfg_server_t *cfg)
605 {
606 #if defined(CONFIG_ESP_TLS_SERVER_SESSION_TICKETS)
607     if (cfg && cfg->ticket_ctx) {
608         _esp_tls_server_session_ticket_ctx_free(cfg->ticket_ctx);
609     }
610 #endif
611 }
612 
613 /**
614  * @brief      Create a server side TLS/SSL connection
615  */
esp_tls_server_session_create(esp_tls_cfg_server_t * cfg,int sockfd,esp_tls_t * tls)616 int esp_tls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls)
617 {
618     return _esp_tls_server_session_create(cfg, sockfd, tls);
619 }
620 /**
621  * @brief      Close the server side TLS/SSL connection and free any allocated resources.
622  */
esp_tls_server_session_delete(esp_tls_t * tls)623 void esp_tls_server_session_delete(esp_tls_t *tls)
624 {
625     return _esp_tls_server_session_delete(tls);
626 }
627 #endif /* CONFIG_ESP_TLS_SERVER */
628 
esp_tls_get_bytes_avail(esp_tls_t * tls)629 ssize_t esp_tls_get_bytes_avail(esp_tls_t *tls)
630 {
631     return _esp_tls_get_bytes_avail(tls);
632 }
633 
esp_tls_get_conn_sockfd(esp_tls_t * tls,int * sockfd)634 esp_err_t esp_tls_get_conn_sockfd(esp_tls_t *tls, int *sockfd)
635 {
636     if (!tls || !sockfd) {
637         ESP_LOGE(TAG, "Invalid arguments passed");
638         return ESP_ERR_INVALID_ARG;
639     }
640     *sockfd = tls->sockfd;
641     return ESP_OK;
642 }
643 
esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h,int * esp_tls_code,int * esp_tls_flags)644 esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *esp_tls_code, int *esp_tls_flags)
645 {
646     if (!h) {
647         return ESP_ERR_INVALID_STATE;
648     }
649     esp_err_t last_err = h->last_error;
650     if (esp_tls_code) {
651         *esp_tls_code = h->esp_tls_error_code;
652     }
653     if (esp_tls_flags) {
654         *esp_tls_flags = h->esp_tls_flags;
655     }
656     memset(h, 0, sizeof(esp_tls_last_error_t));
657     return last_err;
658 }
659 
esp_tls_init_global_ca_store(void)660 esp_err_t esp_tls_init_global_ca_store(void)
661 {
662     return _esp_tls_init_global_ca_store();
663 }
664 
esp_tls_set_global_ca_store(const unsigned char * cacert_pem_buf,const unsigned int cacert_pem_bytes)665 esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes)
666 {
667     return _esp_tls_set_global_ca_store(cacert_pem_buf, cacert_pem_bytes);
668 }
669 
esp_tls_free_global_ca_store(void)670 void esp_tls_free_global_ca_store(void)
671 {
672     return _esp_tls_free_global_ca_store();
673 }
674