1 /*
2 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3 */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <sys/time.h>
8 #include <unistd.h>
9
10 #include "httpclient.h"
11 #include "http_opts.h"
12 #include "http_wrappers.h"
13 #include <netdb.h>
14 #include <sys/socket.h>
15
16 #if CONFIG_HTTP_SECURE
17 #include "mbedtls/net.h"
18 #include "mbedtls/ssl.h"
19 #include "mbedtls/certs.h"
20 #include "mbedtls/entropy.h"
21 #include "mbedtls/ctr_drbg.h"
22
23 /** @brief This structure defines the httpclient ssl structure. */
24 typedef struct {
25 mbedtls_ssl_context ssl_ctx; /**< mbedtls ssl context */
26 mbedtls_net_context net_ctx; /**< fill in socket id */
27 mbedtls_ssl_config ssl_conf; /**< entropy context */
28 mbedtls_entropy_context entropy; /**< ssl configuration */
29 mbedtls_ctr_drbg_context ctr_drbg; /**< ctr drbg context */
30 mbedtls_x509_crt_profile profile; /**< x509 cacert profile */
31 mbedtls_x509_crt cacert; /**< x509 cacert */
32 mbedtls_x509_crt clicert; /**< x509 client cacert */
33 mbedtls_pk_context pkey; /**< pkey context */
34 } httpclient_ssl_t;
35
36
37 #if defined(MBEDTLS_DEBUG_C)
38 #define DEBUG_LEVEL 2
39 #endif
40 #endif
41
42
43 /*
44 * Conncection wrapper function for HTTP
45 * @param[in] client pointer to the httpclient.
46 * @param[in] host host url
47 * @return 0 success other failed
48 */
http_tcp_conn_wrapper(httpclient_t * client,const char * host)49 int http_tcp_conn_wrapper(httpclient_t *client, const char *host)
50 {
51 struct addrinfo hints, *addr_list, *cur;
52 int ret = 0;
53 char port[10] = {0};
54
55 memset( &hints, 0, sizeof( hints ) );
56 hints.ai_family = AF_UNSPEC;
57 hints.ai_socktype = SOCK_STREAM;
58 hints.ai_protocol = IPPROTO_TCP;
59
60 snprintf(port, sizeof(port), "%d", client->remote_port) ;
61 if ( getaddrinfo( host, port , &hints, &addr_list ) != 0 ) {
62 http_err("getaddrinfo != 0, return EDNS");
63 return HTTP_EDNS;
64 }
65
66 /* Try the sockaddrs until a connection succeeds */
67 ret = HTTP_EDNS;
68 for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
69 client->socket = (int) socket( cur->ai_family, cur->ai_socktype,
70 cur->ai_protocol );
71 if ( client->socket < 0 ) {
72 ret = HTTP_ECONN;
73 continue;
74 }
75
76 if ( connect( client->socket, cur->ai_addr, (int)cur->ai_addrlen ) == 0 ) {
77 ret = 0;
78 break;
79 }
80
81 close(client->socket);
82 ret = HTTP_ECONN;
83 }
84
85 freeaddrinfo( addr_list );
86
87 return ret;
88 }
89
http_tcp_close_wrapper(httpclient_t * client)90 int http_tcp_close_wrapper(httpclient_t *client)
91 {
92 close(client->socket);
93 client->socket = -1;
94 return 0;
95 }
96
http_tcp_send_wrapper(httpclient_t * client,const char * data,int length)97 int http_tcp_send_wrapper(httpclient_t *client, const char *data, int length)
98 {
99 int written_len = 0;
100
101 while (written_len < length) {
102 int ret = send(client->socket, data + written_len, length - written_len, 0);
103 if (ret > 0) {
104 written_len += ret;
105 continue;
106 } else if (ret == 0) {
107 return written_len;
108 } else {
109 http_err("Connection err ret=%d errno=%d\n", ret, errno);
110 return -1; /* Connnection error */
111 }
112 }
113
114 return written_len;
115 }
116
http_tcp_recv_wrapper(httpclient_t * client,char * buf,int buflen,int timeout_ms,int * p_read_len)117 int http_tcp_recv_wrapper(httpclient_t *client, char *buf, int buflen, int timeout_ms, int *p_read_len)
118 {
119 int ret = 0, select_ret;
120 size_t readLen = 0;
121 struct timeval timeout;
122 fd_set sets;
123 int err_record;
124 int sockfd = client->socket;
125
126 timeout.tv_sec = timeout_ms / 1000;
127 timeout.tv_usec = 0;
128
129 while (readLen < buflen) {
130 FD_ZERO(&sets);
131 FD_SET(sockfd, &sets);
132
133 select_ret = select(sockfd + 1, &sets, NULL, NULL, &timeout);
134 err_record = errno;
135 if (select_ret > 0) {
136 if (0 == FD_ISSET(sockfd, &sets)) {
137 ret = 0;
138 http_debug("select continue");
139 continue;
140 }
141
142 ret = recv(sockfd, buf + readLen, buflen - readLen, 0);
143 err_record = errno;
144 if (ret < 0 ) {
145 if ((EINTR == err_record) || (EAGAIN == err_record) || (EWOULDBLOCK == err_record) ||
146 (EPROTOTYPE == err_record) || (EALREADY == err_record) || (EINPROGRESS == err_record)) {
147 http_debug("recv continue %d ret %d", err_record, ret);
148 continue;
149 }
150 } else if (ret == 0) {
151 http_debug("recv return 0 disconnected");
152 ret = HTTP_ECLSD;
153 }
154 } else if (select_ret == 0) {
155 http_info("select return 0 may disconnected");
156 ret = HTTP_ECLSD;
157 } else {
158 http_debug("select return %d errno %d", select_ret, err_record);
159 if (err_record == EINTR) {
160 continue;
161 }
162
163 ret = select_ret;
164 }
165
166 if (ret > 0) {
167 readLen += ret;
168 } else if (ret == HTTP_ECLSD) {
169 break;
170 } else {
171 http_err("Connection error (recv returned %d readLen:%d)", ret,readLen);
172 *p_read_len = readLen;
173 return HTTP_ECONN;
174 }
175 }
176
177 *p_read_len = readLen;
178 if (ret == HTTP_ECLSD) {
179 return ret;
180 } else {
181 return HTTP_SUCCESS;
182 }
183 }
184
185 #if CONFIG_HTTP_SECURE
186
http_ssl_send_wrapper(httpclient_t * client,const char * data,size_t length)187 int http_ssl_send_wrapper(httpclient_t *client, const char *data, size_t length)
188 {
189 size_t written_len = 0;
190
191 httpclient_ssl_t *ssl = (httpclient_ssl_t *) client->ssl;
192 if (!ssl) {
193 return -1;
194 }
195
196 while (written_len < length) {
197 int ret = mbedtls_ssl_write(&ssl->ssl_ctx, (unsigned char *)(data + written_len), (length - written_len));
198 if (ret > 0) {
199 written_len += ret;
200 continue;
201 } else if (ret == 0) {
202 return written_len;
203 } else {
204 return -1; /* Connnection error */
205 }
206 }
207
208 return written_len;
209 }
210
httpclient_debug(void * ctx,int level,const char * file,int line,const char * str)211 static void httpclient_debug( void *ctx, int level, const char *file, int line, const char *str )
212 {
213 http_debug("%s", str);
214 }
215
httpclient_random(void * prng,unsigned char * output,size_t output_len)216 static int httpclient_random(void *prng, unsigned char *output, size_t output_len)
217 {
218 uint32_t rnglen = output_len;
219 uint8_t rngoffset = 0;
220 struct timeval time;
221
222 memset(&time, 0, sizeof(struct timeval));
223 gettimeofday(&time, NULL);
224
225 aos_srand((unsigned int)(time.tv_sec * 1000 + time.tv_usec / 1000) + aos_rand());
226
227 while (rnglen > 0) {
228 *(output + rngoffset) = (uint8_t)aos_rand();
229 rngoffset++;
230 rnglen--;
231 }
232
233 return 0;
234 }
235
http_ssl_conn_wrapper(httpclient_t * client,const char * host)236 int http_ssl_conn_wrapper(httpclient_t *client, const char *host)
237 {
238 int authmode = MBEDTLS_SSL_VERIFY_NONE;
239 #ifdef MBEDTLS_ENTROPY_C
240 const char *pers = "https";
241 #endif
242 int value, ret = 0;
243 uint32_t flags;
244 char port[10] = {0};
245 httpclient_ssl_t *ssl;
246
247 client->ssl = (httpclient_ssl_t *)calloc(1, sizeof(httpclient_ssl_t));
248
249 if (!client->ssl) {
250 http_err("Memory malloc error.");
251 ret = -1;
252 goto exit;
253 }
254 ssl = (httpclient_ssl_t *)client->ssl;
255
256 if (client->server_cert)
257 authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
258
259 /*
260 * Initialize the RNG and the session data
261 */
262 #if defined(MBEDTLS_DEBUG_C)
263 mbedtls_debug_set_threshold(DEBUG_LEVEL);
264 #endif
265 mbedtls_net_init(&ssl->net_ctx);
266 mbedtls_ssl_init(&ssl->ssl_ctx);
267 mbedtls_ssl_config_init(&ssl->ssl_conf);
268 #ifdef MBEDTLS_X509_CRT_PARSE_C
269 mbedtls_x509_crt_init(&ssl->cacert);
270 mbedtls_x509_crt_init(&ssl->clicert);
271 #endif
272 mbedtls_pk_init(&ssl->pkey);
273 #ifdef MBEDTLS_ENTROPY_C
274 mbedtls_ctr_drbg_init(&ssl->ctr_drbg);
275 mbedtls_entropy_init(&ssl->entropy);
276 if ((value = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg,
277 mbedtls_entropy_func,
278 &ssl->entropy,
279 (const unsigned char*)pers,
280 strlen(pers))) != 0) {
281 http_err("mbedtls_ctr_drbg_seed() failed, value:-0x%x.", -value);
282 ret = -1;
283 goto exit;
284 }
285 #endif
286 /*
287 * Load the Client certificate
288 */
289 if (client->client_cert && client->client_pk) {
290 #ifdef MBEDTLS_X509_CRT_PARSE_C
291 ret = mbedtls_x509_crt_parse(&ssl->clicert, (const unsigned char *)client->client_cert, client->client_cert_len);
292 if (ret < 0) {
293 http_err("Loading cli_cert failed! mbedtls_x509_crt_parse returned -0x%x.", -ret);
294 ret = -1;
295 goto exit;
296 }
297 #endif
298 ret = mbedtls_pk_parse_key(&ssl->pkey, (const unsigned char *)client->client_pk, client->client_pk_len, NULL, 0);
299 if (ret != 0) {
300 http_err("failed! mbedtls_pk_parse_key returned -0x%x.", -ret);
301 ret = -1;
302 goto exit;
303 }
304 }
305
306 /*
307 * Load the trusted CA
308 */
309 /* cert_len passed in is gotten from sizeof not strlen */
310 #ifdef MBEDTLS_X509_CRT_PARSE_C
311 if (client->server_cert && ((value = mbedtls_x509_crt_parse(&ssl->cacert,
312 (const unsigned char *)client->server_cert,
313 client->server_cert_len)) < 0)) {
314 http_err("mbedtls_x509_crt_parse() failed, value:-0x%x.", -value);
315 ret = -1;
316 goto exit;
317 }
318 #endif
319
320 /*
321 * Start the connection
322 */
323 snprintf(port, sizeof(port), "%d", client->remote_port) ;
324 if ((ret = mbedtls_net_connect(&ssl->net_ctx, host, port, MBEDTLS_NET_PROTO_TCP)) != 0) {
325 http_err("failed! mbedtls_net_connect returned %d, port:%s.", ret, port);
326 ret = -1;
327 goto exit;
328 }
329
330 client->socket = ssl->net_ctx.fd;
331
332 /*
333 * Setup stuff
334 */
335 if ((value = mbedtls_ssl_config_defaults(&ssl->ssl_conf,
336 MBEDTLS_SSL_IS_CLIENT,
337 MBEDTLS_SSL_TRANSPORT_STREAM,
338 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
339 http_err("mbedtls_ssl_config_defaults() failed, value:-0x%x.", -value);
340 ret = -1;
341 goto exit;
342 }
343
344 // TODO: add customerization encryption algorithm
345 #ifdef MBEDTLS_X509_CRT_PARSE_C
346 memcpy(&ssl->profile, ssl->ssl_conf.cert_profile, sizeof(mbedtls_x509_crt_profile));
347 ssl->profile.allowed_mds = ssl->profile.allowed_mds | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_MD5);
348 mbedtls_ssl_conf_cert_profile(&ssl->ssl_conf, &ssl->profile);
349
350 mbedtls_ssl_conf_authmode(&ssl->ssl_conf, authmode);
351 mbedtls_ssl_conf_ca_chain(&ssl->ssl_conf, &ssl->cacert, NULL);
352
353 if (client->client_cert && (ret = mbedtls_ssl_conf_own_cert(&ssl->ssl_conf, &ssl->clicert, &ssl->pkey)) != 0) {
354 http_err(" failed! mbedtls_ssl_conf_own_cert returned %d.", ret );
355 ret = -1;
356 goto exit;
357 }
358 #endif
359
360 mbedtls_ssl_conf_rng(&ssl->ssl_conf, httpclient_random, &ssl->ctr_drbg);
361 mbedtls_ssl_conf_dbg(&ssl->ssl_conf, httpclient_debug, NULL);
362
363 if ((value = mbedtls_ssl_setup(&ssl->ssl_ctx, &ssl->ssl_conf)) != 0) {
364 http_err("mbedtls_ssl_setup() failed, value:-0x%x.", -value);
365 ret = -1;
366 goto exit;
367 }
368
369 mbedtls_ssl_set_bio(&ssl->ssl_ctx, &ssl->net_ctx, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
370 mbedtls_ssl_conf_read_timeout(&ssl->ssl_conf, 10000);
371
372 /*
373 * Handshake
374 */
375 while ((ret = mbedtls_ssl_handshake(&ssl->ssl_ctx)) != 0) {
376 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
377 http_err("mbedtls_ssl_handshake() failed, ret:-0x%x.", -ret);
378 ret = -1;
379 goto exit;
380 }
381 }
382
383 /*
384 * Verify the server certificate
385 */
386 if ((flags = mbedtls_ssl_get_verify_result(&ssl->ssl_ctx)) != 0) {
387 char vrfy_buf[512];
388 http_err("svr_cert varification failed.");
389 mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
390 http_debug("%s", vrfy_buf);
391 ret = -1;
392 } else {
393 http_info("svr_cert varification ok.");
394 }
395
396 exit:
397 if (ret != 0) {
398 http_debug("ret=%d.", ret);
399 http_ssl_close_wrapper(client);
400 }
401 return ret;
402 }
403
http_ssl_close_wrapper(httpclient_t * client)404 int http_ssl_close_wrapper(httpclient_t *client)
405 {
406 httpclient_ssl_t *ssl = (httpclient_ssl_t *)client->ssl;
407
408 if (!ssl)
409 return -1;
410
411 client->ssl = NULL;
412 client->client_cert = NULL;
413 client->server_cert = NULL;
414 client->client_pk = NULL;
415 client->socket = -1;
416
417 mbedtls_ssl_close_notify(&ssl->ssl_ctx);
418 mbedtls_net_free(&ssl->net_ctx);
419 #ifdef MBEDTLS_X509_CRT_PARSE_C
420 mbedtls_x509_crt_free(&ssl->cacert);
421 mbedtls_x509_crt_free(&ssl->clicert);
422 #endif
423 mbedtls_pk_free(&ssl->pkey);
424 mbedtls_ssl_free(&ssl->ssl_ctx);
425 mbedtls_ssl_config_free(&ssl->ssl_conf);
426 #ifdef MBEDTLS_ENTROPY_C
427 mbedtls_ctr_drbg_free(&ssl->ctr_drbg);
428 mbedtls_entropy_free(&ssl->entropy);
429 #endif
430 free(ssl);
431 ssl = NULL;
432 return 0;
433 }
434
http_ssl_recv_wrapper(httpclient_t * client,char * buf,int buflen,int timeout_ms,int * p_read_len)435 int http_ssl_recv_wrapper(httpclient_t *client, char *buf, int buflen, int timeout_ms, int *p_read_len)
436 {
437 int ret = 0;
438 size_t readLen = 0;
439
440 httpclient_ssl_t *ssl = (httpclient_ssl_t *) client->ssl;
441 if (!ssl) {
442 return HTTP_ECONN;
443 }
444
445 mbedtls_ssl_conf_read_timeout(&ssl->ssl_conf, timeout_ms);
446
447 while (readLen < buflen) {
448 ret = mbedtls_ssl_read(&ssl->ssl_ctx, (unsigned char *)buf + readLen, buflen - readLen);
449 if (ret == 0) {
450 ret = HTTP_ECLSD;
451 } else if (ret < 0) {
452 http_debug("mbedtls_ssl_read, return:%d", ret);
453 if ((MBEDTLS_ERR_SSL_TIMEOUT == ret)
454 || (MBEDTLS_ERR_SSL_CONN_EOF == ret)
455 || (MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED == ret)
456 || (MBEDTLS_ERR_SSL_NON_FATAL == ret)) {
457 /* read already complete */
458 /* if call mbedtls_ssl_read again, it will return 0 (means EOF) */
459 }
460
461 if (MBEDTLS_ERR_SSL_WANT_READ == ret) {
462 continue;
463 }
464
465 if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
466 ret = HTTP_ECLSD;
467 }
468 }
469
470 if (ret > 0) {
471 readLen += ret;
472 } else if (ret == HTTP_ECLSD) {
473 break;
474 } else {
475 http_err("Connection error (recv returned %d readLen:%d)", ret,readLen);
476 *p_read_len = readLen;
477 return HTTP_ECONN;
478 }
479 }
480
481 *p_read_len = readLen;
482
483 if (ret == HTTP_ECLSD) {
484 return ret;
485 } else {
486 return HTTP_SUCCESS;
487 }
488 }
489
490 #endif
491