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