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