1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #include <stdio.h>
6 
7 #include "linkkit/coap_api.h"
8 #include "iotx_coap_internal.h"
9 #include "Cloud_CoAPPlatform.h"
10 #include "Cloud_CoAPPlatform.h"
11 #include "Cloud_CoAPMessage.h"
12 #include "Cloud_CoAPExport.h"
13 #include "linkkit/infra/infra_aes.h"
14 
15 #define IOTX_SIGN_LENGTH     (40 + 1)
16 #define IOTX_SIGN_SOURCE_LEN (256)
17 #define IOTX_AUTH_TOKEN_LEN  (192 + 1)
18 #define IOTX_COAP_INIT_TOKEN (0x01020304)
19 #define IOTX_LIST_MAX_ITEM   (10)
20 
21 #ifndef INFRA_LOG
22 #undef HEXDUMP_DEBUG
23 #undef HEXDUMP_INFO
24 
25 #define HEXDUMP_DEBUG(...)
26 #define HEXDUMP_INFO(...)
27 #endif
28 
29 #define IOTX_AUTH_STR              "auth"
30 #define IOTX_SIGN_SRC_STR          "clientId%sdeviceName%sproductKey%s"
31 #define IOTX_SIGN_SRC_STR_WITH_SEQ "clientId%sdeviceName%sproductKey%sseq%d"
32 
33 #define IOTX_AUTH_DEVICENAME_STR                                        \
34     "{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"clientId\":\"%s\"," \
35     "\"sign\":\"%s\"}"
36 #define IOTX_AUTH_DEVICENAME_STR_WITH_SEQ                               \
37     "{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"clientId\":\"%s\"," \
38     "\"sign\":\"%s\",\"seq\":\"%d\"}"
39 
40 #define IOTX_COAP_ONLINE_DTLS_SERVER_URL \
41     "coaps://%s.coap.cn-shanghai.link.aliyuncs.com:5684"
42 #define IOTX_COAP_ONLINE_PSK_SERVER_URL \
43     "coap-psk://%s.coap.cn-shanghai.link.aliyuncs.com:5682"
44 
45 iotx_coap_context_t *g_coap_context = NULL;
46 
47 typedef struct {
48     char *p_auth_token;
49     int auth_token_len;
50     char is_authed;
51     iotx_coap_device_info_t *p_devinfo;
52     Cloud_CoAPContext *p_coap_ctx;
53     unsigned int coap_token;
54     unsigned int seq;
55     unsigned char key[32];
56     iotx_event_handle_t event_handle;
57 } iotx_coap_t;
58 
iotx_calc_sign(const char * p_device_secret,const char * p_client_id,const char * p_device_name,const char * p_product_key,char sign[IOTX_SIGN_LENGTH])59 int iotx_calc_sign(const char *p_device_secret, const char *p_client_id,
60                    const char *p_device_name, const char *p_product_key,
61                    char sign[IOTX_SIGN_LENGTH])
62 {
63     char *p_msg = NULL;
64 
65     p_msg = (char *)coap_malloc(IOTX_SIGN_SOURCE_LEN);
66     if (NULL == p_msg) {
67         return IOTX_ERR_NO_MEM;
68     }
69     memset(sign, 0x00, IOTX_SIGN_LENGTH);
70     memset(p_msg, 0x00, IOTX_SIGN_SOURCE_LEN);
71 
72     HAL_Snprintf(p_msg, IOTX_SIGN_SOURCE_LEN, IOTX_SIGN_SRC_STR, p_client_id,
73                  p_device_name, p_product_key);
74     utils_hmac_md5(p_msg, strlen(p_msg), sign, p_device_secret,
75                    strlen(p_device_secret));
76 
77     coap_free(p_msg);
78     COAP_DEBUG("The device name sign: %s", sign);
79     return IOTX_SUCCESS;
80 }
81 
iotx_calc_sign_with_seq(const char * p_device_secret,const char * p_client_id,const char * p_device_name,const char * p_product_key,unsigned int seq,char sign[IOTX_SIGN_LENGTH])82 int iotx_calc_sign_with_seq(const char *p_device_secret,
83                             const char *p_client_id, const char *p_device_name,
84                             const char *p_product_key, unsigned int seq,
85                             char sign[IOTX_SIGN_LENGTH])
86 {
87     char *p_msg = NULL;
88 
89     p_msg = (char *)coap_malloc(IOTX_SIGN_SOURCE_LEN);
90     if (NULL == p_msg) {
91         return IOTX_ERR_NO_MEM;
92     }
93     memset(sign, 0x00, IOTX_SIGN_LENGTH);
94     memset(p_msg, 0x00, IOTX_SIGN_SOURCE_LEN);
95 
96     HAL_Snprintf(p_msg, IOTX_SIGN_SOURCE_LEN, IOTX_SIGN_SRC_STR_WITH_SEQ,
97                  p_client_id, p_device_name, p_product_key, seq);
98     COAP_DEBUG("The source string: %s", p_msg);
99     utils_hmac_md5(p_msg, strlen(p_msg), sign, p_device_secret,
100                    strlen(p_device_secret));
101 
102     coap_free(p_msg);
103     COAP_DEBUG("The device name sign with seq: %s", sign);
104     return IOTX_SUCCESS;
105 }
106 
iotx_get_token_from_json(char * p_str,char * p_token,int len)107 static int iotx_get_token_from_json(char *p_str, char *p_token, int len)
108 {
109     char *p_value = NULL;
110     if (NULL == p_str || NULL == p_token) {
111         COAP_ERR("Invalid paramter p_str %p, p_token %p", p_str, p_token);
112         return IOTX_ERR_INVALID_PARAM;
113     }
114 
115     p_value = LITE_json_value_of("token", p_str, 0x1234, "coap.cloud");
116     if (NULL != p_value) {
117         if (len - 1 < strlen(p_value)) {
118             return IOTX_ERR_BUFF_TOO_SHORT;
119         }
120         memset(p_token, 0x00, len);
121         strncpy(p_token, p_value, strlen(p_value));
122 #ifdef INFRA_MEM_STATS
123         LITE_free(p_value);
124 #else
125         HAL_Free((void *)p_value);
126 #endif
127         return IOTX_SUCCESS;
128     }
129 
130     return IOTX_ERR_AUTH_FAILED;
131 }
132 
iotx_parse_auth_from_json(char * p_str,iotx_coap_t * p_iotx_coap)133 static int iotx_parse_auth_from_json(char *p_str, iotx_coap_t *p_iotx_coap)
134 {
135     int ret = -1;
136     lite_cjson_t root;
137     lite_cjson_t node;
138     unsigned char key[32] = { 0 };
139     unsigned char buff[128] = { 0 };
140     unsigned char random[32 + 1] = { 0 };
141 
142     if (NULL == p_str || NULL == p_iotx_coap) {
143         return IOTX_ERR_INVALID_PARAM;
144     }
145 
146     memset(&root, 0x00, sizeof(lite_cjson_t));
147     memset(&node, 0x00, sizeof(lite_cjson_t));
148     ret = lite_cjson_parse(p_str, strlen(p_str), &root);
149     if (-1 == ret) {
150         return IOTX_ERR_AUTH_FAILED;
151     }
152 
153     ret = lite_cjson_object_item(&root, "token", strlen("token"), &node);
154     if (-1 == ret) {
155         return IOTX_ERR_AUTH_FAILED;
156     }
157     if (p_iotx_coap->auth_token_len - 1 < node.value_length) {
158         return IOTX_ERR_BUFF_TOO_SHORT;
159     }
160     memset(p_iotx_coap->p_auth_token, 0x00, node.value_length);
161     strncpy(p_iotx_coap->p_auth_token, node.value, node.value_length);
162 
163     memset(&node, 0x00, sizeof(lite_cjson_t));
164     ret =
165         lite_cjson_object_item(&root, "seqOffset", strlen("seqOffset"), &node);
166     if (-1 == ret) {
167         return IOTX_ERR_AUTH_FAILED;
168     }
169     p_iotx_coap->seq = node.value_int;
170 
171     memset(&node, 0x00, sizeof(lite_cjson_t));
172     ret = lite_cjson_object_item(&root, "random", strlen("random"), &node);
173     if (-1 == ret) {
174         return IOTX_ERR_AUTH_FAILED;
175     }
176 
177     if (node.value_length > 32) {
178         return IOTX_ERR_BUFF_TOO_SHORT;
179     }
180     memcpy(random, node.value, node.value_length);
181     HAL_Snprintf((char *)buff, sizeof(buff), "%s,%s",
182                  p_iotx_coap->p_devinfo->device_secret, random);
183     COAP_DEBUG("The src:%s", buff);
184     utils_sha256(buff, strlen((char *)buff), key);
185     memcpy(p_iotx_coap->key, key + 8, 16);
186     COAP_DEBUG("The key is:");
187     HEXDUMP_DEBUG(key, 32);
188     COAP_DEBUG("The short key:");
189     HEXDUMP_DEBUG(p_iotx_coap->key, 16);
190 
191     return IOTX_SUCCESS;
192 }
193 
iotx_device_name_auth_callback(void * user,void * p_message)194 static void iotx_device_name_auth_callback(void *user, void *p_message)
195 {
196     int ret_code = IOTX_SUCCESS;
197     iotx_coap_t *p_iotx_coap = NULL;
198     Cloud_CoAPMessage *message = (Cloud_CoAPMessage *)p_message;
199 
200     if (NULL == user) {
201         COAP_ERR("Invalid paramter, p_arg %p", user);
202         return;
203     }
204     p_iotx_coap = (iotx_coap_t *)user;
205 
206     if (NULL == message) {
207         COAP_ERR("Invalid paramter, message %p", message);
208         return;
209     }
210     COAP_DEBUG("Receive response message:");
211     COAP_DEBUG("* Response Code : 0x%x", message->header.code);
212     COAP_DEBUG("* Payload: %s", message->payload);
213 
214     switch (message->header.code) {
215     case COAP_MSG_CODE_205_CONTENT:
216         {
217             if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) {
218                 ret_code = iotx_parse_auth_from_json((char *)message->payload,
219                                                      p_iotx_coap);
220             } else {
221                 ret_code = iotx_get_token_from_json(
222                     (char *)message->payload, p_iotx_coap->p_auth_token,
223                     p_iotx_coap->auth_token_len);
224             }
225 
226             if (IOTX_SUCCESS == ret_code) {
227                 p_iotx_coap->is_authed = IOT_TRUE;
228                 COAP_INFO("CoAP authenticate success!!!");
229             }
230             break;
231         }
232     case COAP_MSG_CODE_500_INTERNAL_SERVER_ERROR:
233         {
234             COAP_INFO(
235                 "CoAP internal server error, authenticate failed, will retry "
236                 "it");
237             HAL_SleepMs(1000);
238             IOT_CoAP_DeviceNameAuth((iotx_coap_context_t *)p_iotx_coap);
239             break;
240         }
241     default:
242         break;
243     }
244 }
245 
iotx_get_coap_token(iotx_coap_t * p_iotx_coap,unsigned char * p_encoded_data)246 static unsigned int iotx_get_coap_token(iotx_coap_t *p_iotx_coap,
247                                         unsigned char *p_encoded_data)
248 {
249     unsigned int value = p_iotx_coap->coap_token;
250     p_encoded_data[0] = (unsigned char)((value & 0x00FF) >> 0);
251     p_encoded_data[1] = (unsigned char)((value & 0xFF00) >> 8);
252     p_encoded_data[2] = (unsigned char)((value & 0xFF0000) >> 16);
253     p_encoded_data[3] = (unsigned char)((value & 0xFF000000) >> 24);
254     p_iotx_coap->coap_token++;
255     return sizeof(unsigned int);
256 }
257 
iotx_event_notifyer(unsigned int code,Cloud_CoAPMessage * message)258 void iotx_event_notifyer(unsigned int code, Cloud_CoAPMessage *message)
259 {
260     if (NULL == message) {
261         COAP_ERR("Invalid paramter, message %p", message);
262         return;
263     }
264 
265     COAP_DEBUG("Error code: 0x%x, payload: %s", code, message->payload);
266     switch (code) {
267     case COAP_MSG_CODE_402_BAD_OPTION:
268     case COAP_MSG_CODE_401_UNAUTHORIZED:
269         {
270             iotx_coap_t *p_context = NULL;
271             if (NULL != message->user) {
272                 p_context = (iotx_coap_t *)message->user;
273                 p_context->is_authed = IOT_FALSE;
274                 IOT_CoAP_DeviceNameAuth(p_context);
275                 COAP_INFO("IoTx token expired, will reauthenticate");
276             }
277             /* TODO: call event handle to notify application */
278             /* p_context->event_handle(); */
279             break;
280         }
281 
282     default:
283         break;
284     }
285 }
286 
iotx_get_well_known_handler(void * arg,void * p_response)287 static void iotx_get_well_known_handler(void *arg, void *p_response)
288 {
289     int len = 0;
290     unsigned char *p_payload = NULL;
291     iotx_coap_resp_code_t resp_code;
292     IOT_CoAP_GetMessageCode(p_response, &resp_code);
293     IOT_CoAP_GetMessagePayload(p_response, &p_payload, &len);
294     COAP_INFO("[APPL]: Message response code: %d", resp_code);
295     COAP_INFO("[APPL]: Len: %d, Payload: %s, ", len, p_payload);
296 }
297 
iotx_get_well_known(iotx_coap_context_t * p_context)298 int iotx_get_well_known(iotx_coap_context_t *p_context)
299 {
300     int len = 0;
301     Cloud_CoAPContext *p_coap_ctx = NULL;
302     iotx_coap_t *p_iotx_coap = NULL;
303     Cloud_CoAPMessage message;
304     unsigned char token[8] = { 0 };
305 
306     p_iotx_coap = (iotx_coap_t *)p_context;
307     p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx;
308 
309     CoAPMessage_init(&message);
310     CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_CON);
311     CoAPMessageCode_set(&message, COAP_MSG_CODE_GET);
312     CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx));
313     len = iotx_get_coap_token(p_iotx_coap, token);
314     CoAPMessageToken_set(&message, token, len);
315     Cloud_CoAPMessageHandler_set(&message, iotx_get_well_known_handler);
316     CoAPStrOption_add(&message, COAP_OPTION_URI_PATH,
317                       (unsigned char *)".well-known", strlen(".well-known"));
318     CoAPStrOption_add(&message, COAP_OPTION_URI_PATH, (unsigned char *)"core",
319                       strlen("core"));
320     CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_LINK_FORMAT);
321     CoAPMessageUserData_set(&message, (void *)p_iotx_coap);
322     Cloud_CoAPMessage_send(p_coap_ctx, &message);
323     CoAPMessage_destory(&message);
324     return IOTX_SUCCESS;
325 }
326 
iotx_coap_report_rsphdl(void * arg,void * p_response)327 static void iotx_coap_report_rsphdl(void *arg, void *p_response)
328 {
329     int p_payload_len = 0;
330     unsigned char *p_payload = NULL;
331     iotx_coap_resp_code_t resp_code;
332 
333     IOT_CoAP_GetMessageCode(p_response, &resp_code);
334     IOT_CoAP_GetMessagePayload(p_response, &p_payload, &p_payload_len);
335     COAP_DEBUG("Report response: CoAP response code = %d", resp_code);
336     COAP_DEBUG("Report response: CoAP msg_len = %d", p_payload_len);
337     if (p_payload_len > 0) {
338         COAP_DEBUG("Report response: CoAP msg = '%.*s'", p_payload_len,
339                    p_payload);
340     } else {
341         COAP_WRN("Report response: CoAP response payload_len = 0");
342     }
343 }
344 
coap_report_func(void * handle,const char * topic_name,int req_ack,void * data,int len)345 static int coap_report_func(void *handle, const char *topic_name, int req_ack,
346                             void *data, int len)
347 {
348     iotx_message_t message;
349     char coap_topic[100] = { 0 };
350     (void)req_ack;
351 
352     memset(&message, 0, sizeof(iotx_message_t));
353     message.p_payload = (unsigned char *)data;
354     message.payload_len = len;
355     message.resp_callback = iotx_coap_report_rsphdl;
356     message.msg_type = IOTX_MESSAGE_NON;
357     message.content_type = IOTX_CONTENT_TYPE_JSON;
358     HAL_Snprintf(coap_topic, 100, "/topic%s", topic_name);
359     return IOT_CoAP_SendMessage(handle, (char *)coap_topic, &message);
360 }
361 
iotx_aes_cbc_encrypt(const unsigned char * src,int len,const unsigned char * key,void * out)362 int iotx_aes_cbc_encrypt(const unsigned char *src, int len,
363                          const unsigned char *key, void *out)
364 {
365     char *iv = "543yhjy97ae7fyfg";
366 
367     int len1 = len & 0xfffffff0;
368     int len2 = len1 + 16;
369     int pad = len2 - len;
370     int ret = 0;
371 
372     p_Aes128_t aes_e_h = infra_aes128_init((unsigned char *)key,
373                                            (unsigned char *)iv, AES_ENCRYPTION);
374     if (len1) {
375         ret = infra_aes128_cbc_encrypt(aes_e_h, src, len1 >> 4, out);
376     }
377     if (!ret && pad) {
378         char buf[16] = { 0 };
379         memcpy(buf, src + len1, len - len1);
380         memset(buf + len - len1, pad, pad);
381         ret = infra_aes128_cbc_encrypt(aes_e_h, buf, 1,
382                                        (unsigned char *)out + len1);
383     }
384 
385     infra_aes128_destroy(aes_e_h);
386 
387     COAP_DEBUG("to encrypt src: %s, len: %d", src, len2);
388     return ret == 0 ? len2 : 0;
389 }
390 
iotx_aes_cbc_decrypt(const unsigned char * src,int len,const unsigned char * key,void * out)391 int iotx_aes_cbc_decrypt(const unsigned char *src, int len,
392                          const unsigned char *key, void *out)
393 {
394     char *iv = "543yhjy97ae7fyfg";
395 
396     p_Aes128_t aes_d_h;
397     int ret = 0;
398     int n = len >> 4;
399 
400     aes_d_h = infra_aes128_init((uint8_t *)key, (uint8_t *)iv, AES_DECRYPTION);
401     if (!aes_d_h) {
402         COAP_INFO("fail to decrypt");
403         return 0;
404     }
405     if (n > 1) {
406         ret = infra_aes128_cbc_decrypt(aes_d_h, src, n - 1, out);
407     }
408 
409     if (ret == 0) {
410         char *out_c = (char *)out;
411         int offset = n > 0 ? ((n - 1) << 4) : 0;
412         out_c[offset] = 0;
413 
414         if (aes_d_h) {
415             ret = infra_aes128_cbc_decrypt(aes_d_h, src + offset, 1,
416                                            out_c + offset);
417         } else {
418             COAP_ERR("fail to decrypt remain data");
419         }
420 
421         if (ret == 0) {
422             char pad = out_c[len - 1];
423             out_c[len - pad] = 0;
424             /*
425             COAP_DEBUG("decrypt data:%s, len:%d", out_c, len - pad);
426             */
427             infra_aes128_destroy(aes_d_h);
428             return len - pad;
429         }
430     }
431     infra_aes128_destroy(aes_d_h);
432 
433     return 0;
434 }
435 
436 #if AES_CFB_NOPADDING
iotx_aes_cfb_encrypt(const unsigned char * src,int len,const unsigned char * key,void * out)437 static int iotx_aes_cfb_encrypt(const unsigned char *src, int len,
438                                 const unsigned char *key, void *out)
439 {
440     int ret = -1;
441     char *iv = "543yhjy97ae7fyfg";
442 
443     p_Aes128_t aes_e_h = infra_aes128_init((unsigned char *)key,
444                                            (unsigned char *)iv, AES_ENCRYPTION);
445     ret = infra_aes128_cfb_encrypt(aes_e_h, src, len, out);
446     infra_aes128_destroy(aes_e_h);
447 
448     COAP_DEBUG("to encrypt src:%s, len:%d", src, len);
449     return len;
450 }
451 
iotx_aes_cfb_decrypt(const unsigned char * src,int len,const unsigned char * key,void * out)452 int iotx_aes_cfb_decrypt(const unsigned char *src, int len,
453                          const unsigned char *key, void *out)
454 {
455     int ret = -1;
456     char *iv = "543yhjy97ae7fyfg";
457 
458     p_Aes128_t aes_d_h = infra_aes128_init((unsigned char *)key,
459                                            (unsigned char *)iv, AES_ENCRYPTION);
460     ret = infra_aes128_cfb_decrypt(aes_d_h, src, len, out);
461     infra_aes128_destroy(aes_d_h);
462 
463     return ret;
464 }
465 #endif
466 
IOT_CoAP_DeviceNameAuth(iotx_coap_context_t * p_context)467 int IOT_CoAP_DeviceNameAuth(iotx_coap_context_t *p_context)
468 {
469     int len = 0;
470     int ret = COAP_SUCCESS;
471     Cloud_CoAPContext *p_coap_ctx = NULL;
472     iotx_coap_t *p_iotx_coap = NULL;
473     Cloud_CoAPMessage message;
474     unsigned char *p_payload = NULL;
475     unsigned char token[8] = { 0 };
476     char sign[IOTX_SIGN_LENGTH] = { 0 };
477 
478     p_iotx_coap = (iotx_coap_t *)p_context;
479     if (NULL == p_iotx_coap ||
480         (NULL != p_iotx_coap && (NULL == p_iotx_coap->p_auth_token ||
481                                  NULL == p_iotx_coap->p_coap_ctx ||
482                                  0 == p_iotx_coap->auth_token_len))) {
483         COAP_DEBUG("Invalid paramter");
484         return IOTX_ERR_INVALID_PARAM;
485     }
486 
487     p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx;
488 
489     CoAPMessage_init(&message);
490     CoAPMessageType_set(&message, COAP_MESSAGE_TYPE_CON);
491     CoAPMessageCode_set(&message, COAP_MSG_CODE_POST);
492     CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx));
493     len = iotx_get_coap_token(p_iotx_coap, token);
494     CoAPMessageToken_set(&message, token, len);
495     Cloud_CoAPMessageHandler_set(&message, iotx_device_name_auth_callback);
496 
497     CoAPStrOption_add(&message, COAP_OPTION_URI_PATH,
498                       (unsigned char *)IOTX_AUTH_STR, strlen(IOTX_AUTH_STR));
499     CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT, COAP_CT_APP_JSON);
500     CoAPUintOption_add(&message, COAP_OPTION_ACCEPT, COAP_CT_APP_JSON);
501 
502     CoAPMessageUserData_set(&message, (void *)p_iotx_coap);
503 
504     p_payload = coap_malloc(COAP_MSG_MAX_PDU_LEN);
505     if (NULL == p_payload) {
506         CoAPMessage_destory(&message);
507         return IOTX_ERR_NO_MEM;
508     }
509     memset(p_payload, 0x00, COAP_MSG_MAX_PDU_LEN);
510 
511     if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) {
512         iotx_calc_sign_with_seq(p_iotx_coap->p_devinfo->device_secret,
513                                 p_iotx_coap->p_devinfo->device_id,
514                                 p_iotx_coap->p_devinfo->device_name,
515                                 p_iotx_coap->p_devinfo->product_key,
516                                 p_iotx_coap->seq, sign);
517         HAL_Snprintf((char *)p_payload, COAP_MSG_MAX_PDU_LEN,
518                      IOTX_AUTH_DEVICENAME_STR_WITH_SEQ,
519                      p_iotx_coap->p_devinfo->product_key,
520                      p_iotx_coap->p_devinfo->device_name,
521                      p_iotx_coap->p_devinfo->device_id, sign, p_iotx_coap->seq);
522 
523     } else {
524         iotx_calc_sign(p_iotx_coap->p_devinfo->device_secret,
525                        p_iotx_coap->p_devinfo->device_id,
526                        p_iotx_coap->p_devinfo->device_name,
527                        p_iotx_coap->p_devinfo->product_key, sign);
528         HAL_Snprintf((char *)p_payload, COAP_MSG_MAX_PDU_LEN,
529                      IOTX_AUTH_DEVICENAME_STR,
530                      p_iotx_coap->p_devinfo->product_key,
531                      p_iotx_coap->p_devinfo->device_name,
532                      p_iotx_coap->p_devinfo->device_id, sign);
533     }
534     CoAPMessagePayload_set(&message, p_payload, strlen((char *)p_payload));
535     COAP_DEBUG("The payload is: %s", message.payload);
536     COAP_DEBUG("Send authentication message to server");
537     ret = Cloud_CoAPMessage_send(p_coap_ctx, &message);
538     coap_free(p_payload);
539     CoAPMessage_destory(&message);
540 
541     if (COAP_SUCCESS != ret) {
542         COAP_DEBUG("Send authentication message to server failed, ret = %d",
543                    ret);
544         return IOTX_ERR_SEND_MSG_FAILED;
545     }
546 
547     ret = Cloud_CoAPMessage_recv(p_coap_ctx, CONFIG_COAP_AUTH_TIMEOUT, 2);
548     if (0 < ret && !p_iotx_coap->is_authed) {
549         COAP_INFO("CoAP authenticate failed");
550         return IOTX_ERR_AUTH_FAILED;
551     }
552 
553     iotx_set_report_func(coap_report_func);
554     /* report module id */
555     ret = iotx_report_mid(p_context);
556     if (SUCCESS_RETURN != ret) {
557         COAP_WRN("Send ModuleId message to server(CoAP) failed, ret = %d", ret);
558     }
559     /* report device information */
560     ret = iotx_report_devinfo(p_context);
561     if (SUCCESS_RETURN != ret) {
562         COAP_WRN("Send devinfo message to server(CoAP) failed, ret = %d", ret);
563     }
564 
565     return IOTX_SUCCESS;
566 }
567 
iotx_split_path_2_option(char * uri,Cloud_CoAPMessage * message)568 static int iotx_split_path_2_option(char *uri, Cloud_CoAPMessage *message)
569 {
570     char *ptr = NULL;
571     char *pstr = NULL;
572     char path[COAP_MSG_MAX_PATH_LEN] = { 0 };
573 
574     if (NULL == uri || NULL == message) {
575         COAP_ERR("Invalid paramter p_path %p, p_message %p", uri, message);
576         return IOTX_ERR_INVALID_PARAM;
577     }
578     if (IOTX_URI_MAX_LEN < strlen(uri)) {
579         COAP_ERR("The uri length is too loog,len = %d", (int)strlen(uri));
580         return IOTX_ERR_URI_TOO_LOOG;
581     }
582     COAP_DEBUG("The uri is %s", uri);
583     ptr = pstr = uri;
584     while ('\0' != *ptr) {
585         if ('/' == *ptr) {
586             if (ptr != pstr) {
587                 memset(path, 0x00, sizeof(path));
588                 strncpy(path, pstr, ptr - pstr);
589                 COAP_DEBUG("path: %s,len=%d", path, (int)(ptr - pstr));
590                 CoAPStrOption_add(message, COAP_OPTION_URI_PATH,
591                                   (unsigned char *)path, (int)strlen(path));
592             }
593             pstr = ptr + 1;
594         }
595         if ('\0' == *(ptr + 1) && '\0' != *pstr) {
596             memset(path, 0x00, sizeof(path));
597             strncpy(path, pstr, sizeof(path) - 1);
598             COAP_DEBUG("path: %s,len=%d", path, (int)strlen(path));
599             CoAPStrOption_add(message, COAP_OPTION_URI_PATH,
600                               (unsigned char *)path, (int)strlen(path));
601         }
602         ptr++;
603     }
604     return IOTX_SUCCESS;
605 }
606 
IOT_CoAP_GetCurToken(iotx_coap_context_t * p_context)607 uint32_t IOT_CoAP_GetCurToken(iotx_coap_context_t *p_context)
608 {
609     iotx_coap_t *p_iotx_coap = NULL;
610 
611     if (p_context == NULL) {
612         return IOTX_ERR_INVALID_PARAM;
613     }
614     p_iotx_coap = (iotx_coap_t *)p_context;
615 
616     return p_iotx_coap->coap_token;
617 }
618 
IOT_CoAP_SendMessage(iotx_coap_context_t * p_context,char * p_path,iotx_message_t * p_message)619 int IOT_CoAP_SendMessage(iotx_coap_context_t *p_context, char *p_path,
620                          iotx_message_t *p_message)
621 {
622     int len = 0;
623     int ret = IOTX_SUCCESS;
624     Cloud_CoAPContext *p_coap_ctx = NULL;
625     iotx_coap_t *p_iotx_coap = NULL;
626     Cloud_CoAPMessage message;
627     unsigned char token[8] = { 0 };
628     unsigned char *payload = NULL;
629 
630     p_iotx_coap = (iotx_coap_t *)p_context;
631 
632     if (NULL == p_context || NULL == p_path || NULL == p_message ||
633         (NULL != p_iotx_coap && NULL == p_iotx_coap->p_coap_ctx)) {
634         COAP_ERR("Invalid paramter p_context %p, p_uri %p, p_message %p",
635                  p_context, p_path, p_message);
636         return IOTX_ERR_INVALID_PARAM;
637     }
638 
639 #ifdef INFRA_LOG_NETWORK_PAYLOAD
640     COAP_INFO("Upstream Topic: '%s'", p_path);
641     COAP_INFO("Upstream Payload:");
642     iotx_facility_json_print((const char *)p_message->p_payload, LOG_INFO_LEVEL,
643                              '>');
644 #endif
645 
646     /* as this function only support POST request message, type ACK and RST
647      * shall be considered error parameters */
648     if (p_message->msg_type != IOTX_MESSAGE_CON &&
649         p_message->msg_type != IOTX_MESSAGE_NON) {
650         return IOTX_ERR_INVALID_PARAM;
651     }
652 
653     if (p_message->payload_len >= COAP_MSG_MAX_PDU_LEN) {
654         COAP_ERR("The payload length %d is too loog", p_message->payload_len);
655         return IOTX_ERR_MSG_TOO_LOOG;
656     }
657 
658     p_coap_ctx = (Cloud_CoAPContext *)p_iotx_coap->p_coap_ctx;
659     if (p_iotx_coap->is_authed) {
660         /* CoAPMessage_init(&message); */
661         CoAPMessage_init(&message);
662         CoAPMessageType_set(&message, p_message->msg_type);
663         CoAPMessageCode_set(&message, COAP_MSG_CODE_POST);
664         CoAPMessageId_set(&message, Cloud_CoAPMessageId_gen(p_coap_ctx));
665         len = iotx_get_coap_token(p_iotx_coap, token);
666         CoAPMessageToken_set(&message, token, len);
667         CoAPMessageUserData_set(&message, (void *)p_message->user_data);
668         Cloud_CoAPMessageHandler_set(&message, p_message->resp_callback);
669 
670         ret = iotx_split_path_2_option(p_path, &message);
671         if (IOTX_SUCCESS != ret) {
672             return ret;
673         }
674 
675         if (IOTX_CONTENT_TYPE_CBOR == p_message->content_type) {
676             CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT,
677                                COAP_CT_APP_CBOR);
678             CoAPUintOption_add(&message, COAP_OPTION_ACCEPT,
679                                COAP_CT_APP_OCTET_STREAM);
680         } else {
681             CoAPUintOption_add(&message, COAP_OPTION_CONTENT_FORMAT,
682                                COAP_CT_APP_JSON);
683             CoAPUintOption_add(&message, COAP_OPTION_ACCEPT,
684                                COAP_CT_APP_OCTET_STREAM);
685         }
686         CoAPStrOption_add(&message, COAP_OPTION_AUTH_TOKEN,
687                           (unsigned char *)p_iotx_coap->p_auth_token,
688                           strlen(p_iotx_coap->p_auth_token));
689         if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) {
690             unsigned char buff[32] = { 0 };
691             unsigned char seq[33] = { 0 };
692             HAL_Snprintf((char *)buff, sizeof(buff) - 1, "%d",
693                          p_iotx_coap->seq++);
694             len = iotx_aes_cbc_encrypt(buff, strlen((char *)buff),
695                                        p_iotx_coap->key, seq);
696             if (0 < len) {
697                 CoAPStrOption_add(&message, COAP_OPTION_SEQ,
698                                   (unsigned char *)seq, len);
699             } else {
700                 COAP_INFO("Encrypt seq failed");
701             }
702             HEXDUMP_DEBUG(seq, len);
703 
704             payload = (unsigned char *)coap_malloc(COAP_MSG_MAX_PDU_LEN);
705             if (NULL == payload) {
706                 return IOTX_ERR_NO_MEM;
707             }
708             memset(payload, 0x00, COAP_MSG_MAX_PDU_LEN);
709             len = iotx_aes_cbc_encrypt(p_message->p_payload,
710                                        p_message->payload_len, p_iotx_coap->key,
711                                        payload);
712             if (0 == len) {
713                 coap_free(payload);
714                 payload = NULL;
715                 return IOTX_ERR_INVALID_PARAM;
716             }
717 
718             HEXDUMP_DEBUG(payload, len);
719             CoAPMessagePayload_set(&message, payload, len);
720         } else {
721             CoAPMessagePayload_set(&message, p_message->p_payload,
722                                    p_message->payload_len);
723         }
724         ret = Cloud_CoAPMessage_send(p_coap_ctx, &message);
725         CoAPMessage_destory(&message);
726         if (NULL != payload) {
727             coap_free(payload);
728             payload = NULL;
729         }
730 
731         if (COAP_ERROR_DATA_SIZE == ret) {
732             return IOTX_ERR_MSG_TOO_LOOG;
733         }
734 
735         return IOTX_SUCCESS;
736     } else {
737         COAP_ERR("The client [%s/%s] still un-authorized yet, return %d",
738                  p_iotx_coap->p_devinfo->product_key,
739                  p_iotx_coap->p_devinfo->device_name, IOTX_ERR_NOT_AUTHED);
740         return IOTX_ERR_NOT_AUTHED;
741     }
742 }
743 
IOT_CoAP_GetMessagePayload(void * p_message,unsigned char ** pp_payload,int * p_len)744 int IOT_CoAP_GetMessagePayload(void *p_message, unsigned char **pp_payload,
745                                int *p_len)
746 {
747     Cloud_CoAPMessage *message = NULL;
748     iotx_coap_t *p_iotx_coap = NULL;
749 
750     if (NULL == p_message || NULL == pp_payload || NULL == p_len ||
751         NULL == g_coap_context) {
752         COAP_ERR("Invalid parameter: p_message=%p, pp_payload=%p, p_len=%p",
753                  p_message, pp_payload, p_len);
754         return IOTX_ERR_INVALID_PARAM;
755     }
756 
757     p_iotx_coap = (iotx_coap_t *)g_coap_context;
758     message = (Cloud_CoAPMessage *)p_message;
759 
760     COAP_DEBUG("message->payload: %p", message->payload);
761     COAP_DEBUG("message->payloadlen: %d", message->payloadlen);
762 
763     if (message->payloadlen >= COAP_MSG_MAX_PDU_LEN) {
764         COAP_ERR("Invalid parameter: message->payloadlen(%d) out of [0, %d]",
765                  message->payloadlen, COAP_MSG_MAX_PDU_LEN);
766         return IOTX_ERR_INVALID_PARAM;
767     }
768 
769     if (COAP_ENDPOINT_PSK == p_iotx_coap->p_coap_ctx->network.ep_type) {
770         int len = 0;
771         unsigned char *payload = NULL;
772         payload = coap_malloc(COAP_MSG_MAX_PDU_LEN);
773         if (NULL == payload) {
774             return IOTX_ERR_NO_MEM;
775         }
776         memset(payload, 0x00, COAP_MSG_MAX_PDU_LEN);
777 
778         HEXDUMP_DEBUG(message->payload, message->payloadlen);
779 
780         len = iotx_aes_cbc_decrypt(message->payload, message->payloadlen,
781                                    p_iotx_coap->key, payload);
782         if (len > 0) {
783             COAP_DEBUG("payload: %.*s, len %d", len, payload, len);
784         }
785         if (len != 0) {
786             memcpy(message->payload, payload, len);
787             message->payloadlen = len;
788             HEXDUMP_DEBUG(payload, len);
789         }
790 
791         coap_free(payload);
792     }
793 
794     *pp_payload = message->payload;
795     *p_len = message->payloadlen;
796 
797     return IOTX_SUCCESS;
798 }
799 
IOT_CoAP_GetMessageToken(void * p_message,unsigned int * token)800 int IOT_CoAP_GetMessageToken(void *p_message, unsigned int *token)
801 {
802     Cloud_CoAPMessage *message = NULL;
803 
804     if (NULL == p_message || NULL == token) {
805         COAP_ERR("Invalid paramter p_message %p, token= %p", p_message, token);
806         return -1;
807     }
808     message = (Cloud_CoAPMessage *)p_message;
809 
810     *token = ((unsigned int)(message->token[3]) & 0xff) << 24;
811     *token += ((unsigned int)(message->token[2]) & 0xff) << 16;
812     *token += ((unsigned int)(message->token[1]) & 0xff) << 8;
813     *token += ((unsigned int)(message->token[0]) & 0xff);
814     return 0;
815 }
816 
IOT_CoAP_GetMessageCode(void * p_message,iotx_coap_resp_code_t * p_resp_code)817 int IOT_CoAP_GetMessageCode(void *p_message, iotx_coap_resp_code_t *p_resp_code)
818 {
819     Cloud_CoAPMessage *message = NULL;
820 
821     if (NULL == p_message || NULL == p_resp_code) {
822         COAP_ERR("Invalid paramter p_message %p, p_resp_code %p", p_message,
823                  p_resp_code);
824         return IOTX_ERR_INVALID_PARAM;
825     }
826     message = (Cloud_CoAPMessage *)p_message;
827     *p_resp_code = (iotx_coap_resp_code_t)message->header.code;
828 
829     return IOTX_SUCCESS;
830 }
831 
iotx_get_seq(void)832 static unsigned int iotx_get_seq(void)
833 {
834     HAL_Srandom((unsigned int)HAL_UptimeMs());
835     return HAL_Random(0xffffffff) % 10000;
836 }
837 
IOT_CoAP_Init(iotx_coap_config_t * p_config)838 iotx_coap_context_t *IOT_CoAP_Init(iotx_coap_config_t *p_config)
839 {
840     Cloud_CoAPInitParam param;
841     char url[128] = { 0 };
842     iotx_coap_t *p_iotx_coap = NULL;
843 
844     if (NULL == p_config) {
845         COAP_ERR("Invalid paramter p_config %p", p_config);
846         return NULL;
847     }
848     if (NULL == p_config->p_devinfo) {
849         COAP_ERR("Invalid paramter p_devinfo %p", p_config->p_devinfo);
850         return NULL;
851     }
852 
853     p_iotx_coap = coap_malloc(sizeof(iotx_coap_t));
854     if (NULL == p_iotx_coap) {
855         COAP_ERR(" Allocate memory for iotx_coap_context_t failed");
856         return NULL;
857     }
858     memset(p_iotx_coap, 0x00, sizeof(iotx_coap_t));
859 
860     p_iotx_coap->p_auth_token = coap_malloc(IOTX_AUTH_TOKEN_LEN);
861     if (NULL == p_iotx_coap->p_auth_token) {
862         COAP_ERR(" Allocate memory for auth token failed");
863         goto err;
864     }
865     memset(p_iotx_coap->p_auth_token, 0x00, IOTX_AUTH_TOKEN_LEN);
866 
867     /*Set the client isn't authed*/
868     p_iotx_coap->is_authed = IOT_FALSE;
869     p_iotx_coap->auth_token_len = IOTX_AUTH_TOKEN_LEN;
870 
871     /*Get deivce information*/
872     p_iotx_coap->p_devinfo = coap_malloc(sizeof(iotx_coap_device_info_t));
873     if (NULL == p_iotx_coap->p_devinfo) {
874         COAP_ERR(" Allocate memory for iotx_coap_device_info_t failed");
875         goto err;
876     }
877     memset(p_iotx_coap->p_devinfo, 0x00, sizeof(iotx_coap_device_info_t));
878 
879     /*It should be implement by the user*/
880     if (NULL != p_config->p_devinfo) {
881         memset(p_iotx_coap->p_devinfo, 0x00, sizeof(iotx_coap_device_info_t));
882         strncpy(p_iotx_coap->p_devinfo->device_id,
883                 p_config->p_devinfo->device_id,
884                 strlen(p_config->p_devinfo->device_id));
885         strncpy(p_iotx_coap->p_devinfo->product_key,
886                 p_config->p_devinfo->product_key,
887                 strlen(p_config->p_devinfo->product_key));
888         strncpy(p_iotx_coap->p_devinfo->device_secret,
889                 p_config->p_devinfo->device_secret,
890                 strlen(p_config->p_devinfo->device_secret));
891         strncpy(p_iotx_coap->p_devinfo->device_name,
892                 p_config->p_devinfo->device_name,
893                 strlen(p_config->p_devinfo->device_name));
894     }
895 
896     /*Init coap token*/
897     p_iotx_coap->coap_token = IOTX_COAP_INIT_TOKEN;
898     p_iotx_coap->seq = iotx_get_seq();
899     memset(p_iotx_coap->key, 0x00, sizeof(p_iotx_coap->key));
900 
901     /*Create coap context*/
902     memset(&param, 0x00, sizeof(Cloud_CoAPInitParam));
903 
904     if (NULL != p_config->p_url) {
905         param.url = p_config->p_url;
906     } else {
907         HAL_Snprintf(url, sizeof(url), IOTX_COAP_ONLINE_PSK_SERVER_URL,
908                      p_iotx_coap->p_devinfo->product_key);
909         param.url = url;
910         COAP_INFO("Using default CoAP server: %s", url);
911     }
912     param.maxcount = IOTX_LIST_MAX_ITEM;
913     param.notifier = (Cloud_CoAPEventNotifier)iotx_event_notifyer;
914     param.waittime = p_config->wait_time_ms;
915     p_iotx_coap->p_coap_ctx = Cloud_CoAPContext_create(&param);
916     if (NULL == p_iotx_coap->p_coap_ctx) {
917         COAP_ERR(" Create coap context failed");
918         goto err;
919     }
920 
921     /*Register the event handle to notify the application */
922     p_iotx_coap->event_handle = p_config->event_handle;
923 
924     g_coap_context = (iotx_coap_context_t *)p_iotx_coap;
925     return (iotx_coap_context_t *)p_iotx_coap;
926 err:
927     /* Error, release the memory */
928     if (NULL != p_iotx_coap) {
929         if (NULL != p_iotx_coap->p_devinfo) {
930             coap_free(p_iotx_coap->p_devinfo);
931         }
932         if (NULL != p_iotx_coap->p_auth_token) {
933             coap_free(p_iotx_coap->p_auth_token);
934         }
935         if (NULL != p_iotx_coap->p_coap_ctx) {
936             Cloud_CoAPContext_free(p_iotx_coap->p_coap_ctx);
937         }
938 
939         p_iotx_coap->auth_token_len = 0;
940         p_iotx_coap->is_authed = IOT_FALSE;
941         coap_free(p_iotx_coap);
942     }
943     return NULL;
944 }
945 
IOT_CoAP_Deinit(iotx_coap_context_t ** pp_context)946 void IOT_CoAP_Deinit(iotx_coap_context_t **pp_context)
947 {
948     iotx_coap_t *p_iotx_coap = NULL;
949 
950     if (NULL != pp_context && NULL != *pp_context) {
951         p_iotx_coap = (iotx_coap_t *)*pp_context;
952         p_iotx_coap->is_authed = IOT_FALSE;
953         p_iotx_coap->auth_token_len = 0;
954         p_iotx_coap->coap_token = IOTX_COAP_INIT_TOKEN;
955 
956         if (NULL != p_iotx_coap->p_auth_token) {
957             coap_free(p_iotx_coap->p_auth_token);
958             p_iotx_coap->p_auth_token = NULL;
959         }
960 
961         if (NULL != p_iotx_coap->p_devinfo) {
962             coap_free(p_iotx_coap->p_devinfo);
963             p_iotx_coap->p_devinfo = NULL;
964         }
965 
966         if (NULL != p_iotx_coap->p_coap_ctx) {
967             Cloud_CoAPContext_free(p_iotx_coap->p_coap_ctx);
968             p_iotx_coap->p_coap_ctx = NULL;
969         }
970         coap_free(p_iotx_coap);
971         *pp_context = NULL;
972         g_coap_context = NULL;
973     }
974 }
975 
IOT_CoAP_Yield(iotx_coap_context_t * p_context)976 int IOT_CoAP_Yield(iotx_coap_context_t *p_context)
977 {
978     iotx_coap_t *p_iotx_coap = NULL;
979     p_iotx_coap = (iotx_coap_t *)p_context;
980     if (NULL == p_iotx_coap ||
981         (NULL != p_iotx_coap && NULL == p_iotx_coap->p_coap_ctx)) {
982         COAP_ERR("Invalid paramter");
983         return IOTX_ERR_INVALID_PARAM;
984     }
985 
986     return Cloud_CoAPMessage_cycle(p_iotx_coap->p_coap_ctx);
987 }
988