1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include "aos/errno.h"
11 #include "aos/kernel.h"
12 #include "ulog/ulog.h"
13 #include "itls/ssl.h"
14 #include "itls/net.h"
15 #include "itls/debug.h"
16 #include "itls/platform.h"
17 #include "linkkit/wrappers/wrappers_defs.h"
18 #include "linkkit/wrappers/wrappers_os.h"
19 
20 #define LOG_TAG                    "HAL_iTLS"
21 
22 #define platform_info(format, ...) LOGI(LOG_TAG, format, ##__VA_ARGS__)
23 #define platform_err(format, ...)  LOGE(LOG_TAG, format, ##__VA_ARGS__)
24 
25 #define SEND_TIMEOUT_SECONDS       (10)
26 
27 typedef struct _TLSDataParams {
28     mbedtls_ssl_context ssl; /**< iTLS control context. */
29     mbedtls_net_context fd;  /**< iTLS network context. */
30     mbedtls_ssl_config conf; /**< iTLS configuration context. */
31 } TLSDataParams_t, *TLSDataParams_pt;
32 
33 /**< set debug log level, 0 close*/
34 #define DEBUG_LEVEL               0
35 
36 #define ITLS_READ_HEADER_TIMEOUT  30
37 #define ITLS_READ_PAYLOAD_TIMEOUT 20000
38 
39 #if defined(CONFIG_ITLS_TIME_TEST)
40 #include <sys/time.h>
41 static struct timeval tv1, tv2;
42 #endif
43 
_avRandom()44 static unsigned int _avRandom()
45 {
46     return ((unsigned int)rand() << 16) + rand();
47 }
48 
_ssl_random(void * p_rng,unsigned char * output,size_t output_len)49 static int _ssl_random(void *p_rng, unsigned char *output, size_t output_len)
50 {
51     uint32_t rnglen = output_len;
52     uint8_t rngoffset = 0;
53 
54     while (rnglen > 0) {
55         *(output + rngoffset) = (unsigned char)_avRandom();
56         rngoffset++;
57         rnglen--;
58     }
59     return 0;
60 }
61 
_ssl_debug(void * ctx,int level,const char * file,int line,const char * str)62 static void _ssl_debug(void *ctx, int level, const char *file, int line,
63                        const char *str)
64 {
65     ((void)ctx);
66     ((void)level);
67 
68     platform_info("%s:%04d: %s", file, line, str);
69 }
70 
71 #if defined(_PLATFORM_IS_LINUX_)
72 #include "aos/errno.h"
73 extern int errno;
74 
net_prepare(void)75 static int net_prepare(void)
76 {
77 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
78     !defined(EFI32)
79     WSADATA wsaData;
80     static int wsa_init_done = 0;
81 
82     if (wsa_init_done == 0) {
83         if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
84             return MBEDTLS_ERR_NET_SOCKET_FAILED;
85         }
86 
87         wsa_init_done = 1;
88     }
89 #else
90 #if !defined(EFIX64) && !defined(EFI32)
91     signal(SIGPIPE, SIG_IGN);
92 #endif
93 #endif
94     return 0;
95 }
96 
mbedtls_net_connect_timeout(mbedtls_net_context * ctx,const char * host,const char * port,int proto,unsigned int timeout)97 static int mbedtls_net_connect_timeout(mbedtls_net_context *ctx,
98                                        const char *host, const char *port,
99                                        int proto, unsigned int timeout)
100 {
101     int ret;
102     struct addrinfo hints, *addr_list, *cur;
103     struct timeval sendtimeout;
104 
105     if ((ret = net_prepare()) != 0) {
106         return ret;
107     }
108 
109     /* Do name resolution with both IPv6 and IPv4 */
110     memset(&hints, 0, sizeof(hints));
111     hints.ai_family = AF_UNSPEC;
112     hints.ai_socktype =
113         proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
114     hints.ai_protocol =
115         proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
116 
117     if (getaddrinfo(host, port, &hints, &addr_list) != 0) {
118         return MBEDTLS_ERR_NET_UNKNOWN_HOST;
119     }
120 
121     /* Try the sockaddrs until a connection succeeds */
122     ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
123     for (cur = addr_list; cur != NULL; cur = cur->ai_next) {
124         ctx->fd =
125             (int)socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
126         if (ctx->fd < 0) {
127             ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
128             continue;
129         }
130 
131         sendtimeout.tv_sec = timeout;
132         sendtimeout.tv_usec = 0;
133 
134         if (0 != setsockopt(ctx->fd, SOL_SOCKET, SO_SNDTIMEO, &sendtimeout,
135                             sizeof(sendtimeout))) {
136             perror("setsockopt");
137             platform_err("setsockopt error");
138         }
139 
140         platform_info("setsockopt SO_SNDTIMEO timeout: %ds",
141                       sendtimeout.tv_sec);
142 
143         if (connect(ctx->fd, cur->ai_addr, cur->ai_addrlen) == 0) {
144             ret = 0;
145             break;
146         }
147 
148         close(ctx->fd);
149         ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
150     }
151 
152     freeaddrinfo(addr_list);
153 
154     return ret;
155 }
156 #endif
157 
158 /**
159  * @brief This function connects to the specific SSL server with TLS.
160  * @param[in] n is the the network structure pointer.
161  * @param[in] addr is the Server Host name or IP address.
162  * @param[in] port is the Server Port.
163  * @param[in] product_key is the product name.
164  * @param[in] product_secret is the product secret.
165  *
166  * @retval       0 : success.
167  * @retval     < 0 : fail.
168  */
_TLSConnectNetwork(TLSDataParams_t * pTlsData,const char * addr,const char * port,const char * product_key,const char * product_secret)169 static int _TLSConnectNetwork(TLSDataParams_t *pTlsData, const char *addr,
170                               const char *port, const char *product_key,
171                               const char *product_secret)
172 {
173     int ret = -1;
174 
175     /*
176      * 0. Initialize the RNG and the session data
177      */
178 #if defined(MBEDTLS_DEBUG_C)
179     mbedtls_debug_set_threshold(DEBUG_LEVEL);
180 #endif
181     mbedtls_ssl_init(&(pTlsData->ssl));
182     mbedtls_net_init(&(pTlsData->fd));
183     mbedtls_ssl_config_init(&(pTlsData->conf));
184 
185     /*
186      * 1. Start the connection
187      */
188     platform_info("Connecting to /%s/%s...", addr, port);
189 #if defined(_PLATFORM_IS_LINUX_)
190     ret = mbedtls_net_connect_timeout(&(pTlsData->fd), addr, port,
191                                       MBEDTLS_NET_PROTO_TCP,
192                                       SEND_TIMEOUT_SECONDS);
193     if (ret != 0) {
194         platform_err(" failed ! net_connect returned -0x%04x", -ret);
195         return ret;
196     }
197 #else
198     ret = mbedtls_net_connect(&(pTlsData->fd), addr, port,
199                                 MBEDTLS_NET_PROTO_TCP);
200     if (ret != 0) {
201         platform_err(" failed ! net_connect returned -0x%04x", -ret);
202         return ret;
203     }
204 #endif
205     platform_info(" ok");
206 
207     /*
208      * 2. Setup stuff
209      */
210     platform_info("  . Setting up the SSL/TLS structure...");
211     ret = mbedtls_ssl_config_defaults(
212              &(pTlsData->conf), MBEDTLS_SSL_IS_CLIENT,
213              MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
214     if (ret != 0) {
215         platform_err(" failed! mbedtls_ssl_config_defaults returned %d", ret);
216         goto _out;
217     }
218 
219     mbedtls_ssl_conf_max_version(&pTlsData->conf, MBEDTLS_SSL_MAJOR_VERSION_3,
220                                  MBEDTLS_SSL_MINOR_VERSION_3);
221     mbedtls_ssl_conf_min_version(&pTlsData->conf, MBEDTLS_SSL_MAJOR_VERSION_3,
222                                  MBEDTLS_SSL_MINOR_VERSION_3);
223 
224     platform_info(" ok");
225 
226     mbedtls_ssl_conf_rng(&(pTlsData->conf), _ssl_random, NULL);
227     mbedtls_ssl_conf_dbg(&(pTlsData->conf), _ssl_debug, NULL);
228 
229     /* "OPTIONAL", set extra data for client authentication */
230     ret = mbedtls_ssl_conf_auth_extra(&(pTlsData->conf), product_key,
231                                       strlen(product_key));
232     if (ret != 0) {
233         platform_err(" failed! mbedtls_ssl_config_auth_extra returned %d", ret);
234         goto _out;
235     }
236 
237     /* "OPTIONAL", token for id2 one-time provisioning */
238     ret = mbedtls_ssl_conf_auth_token(&(pTlsData->conf), product_secret,
239                                       strlen(product_secret));
240     if (ret != 0) {
241         platform_err(" failed\n  ! mbedtls_ssl_conf_auth_token returned %d\n\n",
242                      ret);
243         goto _out;
244     }
245 
246 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
247     ret = mbedtls_ssl_conf_max_frag_len(
248              &(pTlsData->conf), MBEDTLS_SSL_MAX_FRAG_LEN_1024);
249     if (ret != 0) {
250         platform_err(
251             " failed\n  ! mbedtls_ssl_conf_max_frag_len returned %d\n\n", ret);
252         goto _out;
253     }
254 #endif
255 
256     ret = mbedtls_ssl_setup(&(pTlsData->ssl), &(pTlsData->conf));
257     if (ret != 0) {
258         platform_err(" failed! mbedtls_ssl_setup returned %d", ret);
259         goto _out;
260     }
261 
262     mbedtls_ssl_set_bio(&(pTlsData->ssl), &(pTlsData->fd), mbedtls_net_send,
263                         mbedtls_net_recv, mbedtls_net_recv_timeout);
264 
265     /*
266      * 3. Handshake
267      */
268     platform_info("Performing the SSL/TLS handshake...");
269 #if defined(CONFIG_ITLS_TIME_TEST)
270     gettimeofday(&tv1, NULL);
271 #endif
272 
273     while ((ret = mbedtls_ssl_handshake(&(pTlsData->ssl))) != 0) {
274         if ((ret != MBEDTLS_ERR_SSL_WANT_READ) &&
275             (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) {
276             platform_err("failed  ! mbedtls_ssl_handshake returned -0x%04x",
277                          -ret);
278             goto _out;
279         }
280     }
281 
282 #if defined(CONFIG_ITLS_TIME_TEST)
283     gettimeofday(&tv2, NULL);
284     platform_info(
285         "=========================== iTLS handshake used time(usec): %d\n",
286         (int)((tv2.tv_sec - tv1.tv_sec) * 1000000 +
287               (tv2.tv_usec - tv1.tv_usec)));
288 #endif
289 
290     platform_info(" ok");
291 
292 _out:
293     if (ret != 0) {
294         mbedtls_net_free(&(pTlsData->fd));
295         mbedtls_ssl_free(&(pTlsData->ssl));
296         mbedtls_ssl_config_free(&(pTlsData->conf));
297     }
298 
299     return ret;
300 }
301 
_network_ssl_read(TLSDataParams_t * pTlsData,char * buffer,int len,int timeout_ms)302 static int _network_ssl_read(TLSDataParams_t *pTlsData, char *buffer, int len,
303                              int timeout_ms)
304 {
305     uint32_t readLen = 0;
306     static int net_status = 0;
307     int ret = -1;
308 
309 #if defined(CONFIG_ITLS_TIME_TEST)
310     gettimeofday(&tv1, NULL);
311 #endif
312 
313     if (len > 1) { /* len > 1 indicates that trying to read payload */
314         timeout_ms = ITLS_READ_PAYLOAD_TIMEOUT;
315     } else if (timeout_ms < ITLS_READ_HEADER_TIMEOUT) {
316         timeout_ms =
317             ITLS_READ_HEADER_TIMEOUT; /* wait for at least 30ms for header type
318                                          or packet length */
319     }
320 
321     mbedtls_ssl_conf_read_timeout(&(pTlsData->conf), timeout_ms);
322     while (readLen < len) {
323         ret = mbedtls_ssl_read(&(pTlsData->ssl),
324                                (unsigned char *)(buffer + readLen),
325                                (len - readLen));
326         if (ret > 0) {
327             readLen += ret;
328             net_status = 0;
329         } else if (ret == 0) {
330             /* if ret is 0 and net_status is -2, indicate the connection is
331              * closed during last call */
332             return (net_status == -2) ? net_status : readLen;
333         } else {
334             if (MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY == ret) {
335                 platform_err("ssl recv peer close notify");
336                 net_status = -2; /* connection is closed */
337                 break;
338             } else if ((MBEDTLS_ERR_SSL_TIMEOUT == ret) ||
339                        (MBEDTLS_ERR_SSL_CONN_EOF == ret) ||
340                        (MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED == ret) ||
341                        (MBEDTLS_ERR_SSL_NON_FATAL == ret)) {
342                 /* read already complete */
343                 /* if call mbedtls_ssl_read again, it will return 0 (means EOF)
344                  */
345 
346                 return readLen;
347             } else {
348 #ifdef CSP_LINUXHOST
349                 if (MBEDTLS_ERR_SSL_WANT_READ == ret && errno == EINTR) {
350                     continue;
351                 }
352 #endif
353                 platform_err("ssl recv error: code = %d", ret);
354                 net_status = -1;
355                 return -1; /* Connection error */
356             }
357         }
358     }
359 
360 #if defined(CONFIG_ITLS_TIME_TEST)
361     gettimeofday(&tv2, NULL);
362     platform_info(
363         "=========================== iTLS receive data(%d bytes) used "
364         "time(usec): %d\n",
365         readLen,
366         (int)((tv2.tv_sec - tv1.tv_sec) * 1000000 +
367               (tv2.tv_usec - tv1.tv_usec)));
368 #endif
369 
370     return (readLen > 0) ? readLen : net_status;
371 }
372 
_network_ssl_write(TLSDataParams_t * pTlsData,const char * buffer,int len,int timeout_ms)373 static int _network_ssl_write(TLSDataParams_t *pTlsData, const char *buffer,
374                               int len, int timeout_ms)
375 {
376     uint32_t writtenLen = 0;
377     int ret = -1;
378 
379 #if defined(CONFIG_ITLS_TIME_TEST)
380     gettimeofday(&tv1, NULL);
381 #endif
382 
383     while (writtenLen < len) {
384         ret = mbedtls_ssl_write(&(pTlsData->ssl),
385                                 (unsigned char *)(buffer + writtenLen),
386                                 (len - writtenLen));
387         if (ret > 0) {
388             writtenLen += ret;
389             continue;
390         } else if (ret == 0) {
391             platform_err("ssl write timeout");
392             return 0;
393         } else {
394             platform_err("ssl write error, code = %d", ret);
395             return -1;
396         }
397     }
398 
399 #if defined(CONFIG_ITLS_TIME_TEST)
400     gettimeofday(&tv2, NULL);
401     platform_info("iTLS send data(%d bytes) used time(usec): %d\n", writtenLen,
402                   (int)((tv2.tv_sec - tv1.tv_sec) * 1000000 +
403                         (tv2.tv_usec - tv1.tv_usec)));
404 #endif
405 
406     return writtenLen;
407 }
408 
_network_ssl_disconnect(TLSDataParams_t * pTlsData)409 static void _network_ssl_disconnect(TLSDataParams_t *pTlsData)
410 {
411     mbedtls_ssl_close_notify(&(pTlsData->ssl));
412     mbedtls_net_free(&(pTlsData->fd));
413     mbedtls_ssl_free(&(pTlsData->ssl));
414     mbedtls_ssl_config_free(&(pTlsData->conf));
415     platform_info("ssl_disconnect");
416 }
417 
HAL_SSL_Establish(const char * host,uint16_t port,const char * ca_crt,size_t ca_crt_len)418 uintptr_t HAL_SSL_Establish(const char *host, uint16_t port, const char *ca_crt,
419                             size_t ca_crt_len)
420 {
421     char port_str[6];
422     TLSDataParams_pt pTlsData;
423 
424     char _product_key[IOTX_PRODUCT_KEY_LEN + 1] = { 0 };
425     char _product_secret[IOTX_PRODUCT_SECRET_LEN + 1] = { 0 };
426 
427     if (host == NULL) {
428         platform_err("input params are NULL");
429         return 0;
430     }
431     HAL_GetProductKey(_product_key);
432     HAL_GetProductSecret(_product_secret);
433 
434     pTlsData = HAL_Malloc(sizeof(TLSDataParams_t));
435     if (NULL == pTlsData) {
436         return (uintptr_t)NULL;
437     }
438 
439     memset(pTlsData, 0x0, sizeof(TLSDataParams_t));
440 
441     sprintf(port_str, "%u", port);
442 
443     if (0 != _TLSConnectNetwork(pTlsData, host, port_str, _product_key,
444                                 _product_secret)) {
445         HAL_Free((void *)pTlsData);
446         return (uintptr_t)NULL;
447     }
448 
449     return (uintptr_t)pTlsData;
450 }
451 
HAL_SSL_Destroy(uintptr_t handle)452 int32_t HAL_SSL_Destroy(uintptr_t handle)
453 {
454     if ((uintptr_t)NULL == handle) {
455         platform_err("handle is NULL");
456         return 0;
457     }
458 
459     _network_ssl_disconnect((TLSDataParams_t *)handle);
460     HAL_Free((void *)handle);
461 
462     return 0;
463 }
464 
HAL_SSL_Write(uintptr_t handle,const char * buf,int len,int timeout_ms)465 int32_t HAL_SSL_Write(uintptr_t handle, const char *buf, int len,
466                       int timeout_ms)
467 {
468     return _network_ssl_write((TLSDataParams_t *)handle, buf, len, timeout_ms);
469 }
470 
HAL_SSL_Read(uintptr_t handle,char * buf,int len,int timeout_ms)471 int32_t HAL_SSL_Read(uintptr_t handle, char *buf, int len, int timeout_ms)
472 {
473     return _network_ssl_read((TLSDataParams_t *)handle, buf, len, timeout_ms);
474     ;
475 }
476