1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 #include "linkkit/infra/infra_config.h"
5 
6 #ifdef INFRA_PREAUTH
7 
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 
12 #include "linkkit/infra/infra_types.h"
13 #include "linkkit/infra/infra_defs.h"
14 #include "linkkit/infra/infra_httpc.h"
15 #include "linkkit/infra/infra_preauth.h"
16 #include "linkkit/infra/infra_string.h"
17 
18 #define PREAUTH_HTTP_REQ_LEN     300
19 #define PREAUTH_HTTP_RSP_LEN     300
20 
21 #define PREAUTH_IOT_ID_MAXLEN    (64)
22 #define PREAUTH_IOT_TOKEN_MAXLEN (65)
23 #define PREAUTH_IOT_HOST_MAXLEN  (64)
24 
25 #ifndef CONFIG_GUIDER_AUTH_TIMEOUT
26 #define CONFIG_GUIDER_AUTH_TIMEOUT (10 * 1000)
27 #endif
28 
29 #ifdef SUPPORT_TLS
30 extern const char *iotx_ca_crt;
31 #endif
32 
33 typedef struct {
34     char *payload;
35     int payload_len;
36 } preauth_http_response_t;
37 
_preauth_assemble_auth_req_string(const iotx_dev_meta_info_t * dev_meta,const char * sign,const char * device_id,char * request_buff,uint32_t buff_len)38 int _preauth_assemble_auth_req_string(const iotx_dev_meta_info_t *dev_meta,
39                                       const char *sign, const char *device_id,
40                                       char *request_buff, uint32_t buff_len)
41 {
42     uint8_t i = 0;
43     const char *kv[][2] = {
44         { "productKey", NULL },           { "deviceName", NULL },
45         { "signmethod", "hmacsha256" },   { "sign", NULL },
46         { "version", "default" },         { "clientId", NULL },
47         { "timestamp", "2524608000000" }, { "resources", "mqtt" }
48     };
49 
50     if (dev_meta == NULL || sign == NULL || device_id == NULL ||
51         request_buff == NULL) {
52         return FAIL_RETURN;
53     }
54 
55     kv[0][1] = dev_meta->product_key;
56     kv[1][1] = dev_meta->device_name;
57     kv[3][1] = sign;
58     kv[5][1] = device_id;
59 
60     for (i = 0; i < (sizeof(kv) / (sizeof(kv[0]))); i++) {
61         if ((strlen(request_buff) + strlen(kv[i][0]) + strlen(kv[i][1]) + 2) >=
62             buff_len) {
63             return FAIL_RETURN;
64         }
65 
66         memcpy(request_buff + strlen(request_buff), kv[i][0], strlen(kv[i][0]));
67         memcpy(request_buff + strlen(request_buff), "=", 1);
68         memcpy(request_buff + strlen(request_buff), kv[i][1], strlen(kv[i][1]));
69         memcpy(request_buff + strlen(request_buff), "&", 1);
70     }
71 
72     memset(request_buff + strlen(request_buff) - 1, '\0', 1);
73     return SUCCESS_RETURN;
74 }
75 
_preauth_get_string_value(char * p_string,char * value_buff,uint32_t buff_len)76 static int _preauth_get_string_value(char *p_string, char *value_buff,
77                                      uint32_t buff_len)
78 {
79     char *p = p_string;
80     char *p_start = NULL;
81     char *p_end = NULL;
82     uint32_t len = 0;
83 
84     while (*(++p) != ',' || *p != '}') {
85         if (*p == '\"') {
86             if (p_start) {
87                 p_end = p;
88                 break;
89             } else {
90                 p_start = p + 1;
91             }
92         }
93     }
94 
95     if (p_start == NULL || p_end == NULL) {
96         return FAIL_RETURN;
97     }
98 
99     len = p_end - p_start;
100     if (len > buff_len) {
101         return FAIL_RETURN;
102     }
103 
104     memcpy(value_buff, p_start, len);
105     return SUCCESS_RETURN;
106 }
107 
_preauth_parse_auth_rsp_string(char * json_string,uint32_t string_len,iotx_sign_mqtt_t * output)108 static int _preauth_parse_auth_rsp_string(char *json_string,
109                                           uint32_t string_len,
110                                           iotx_sign_mqtt_t *output)
111 {
112     int res = FAIL_RETURN;
113     char *p = json_string;
114     char *p_start, *p_end, *pt;
115     uint8_t len;
116     int code = 0;
117 
118     while (p < (json_string + string_len)) {
119         while (*(++p) != ':') {
120             if (p >= (json_string + string_len)) {
121                 if (code != 200) {
122                     return FAIL_RETURN;
123                 } else {
124                     return SUCCESS_RETURN;
125                 }
126             }
127         }
128 
129         pt = p;
130         p_start = p_end = NULL;
131         while (--pt > json_string) {
132             if (*pt == '\"') {
133                 if (p_end != NULL) {
134                     p_start = pt + 1;
135                     break;
136                 } else {
137                     p_end = pt;
138                 }
139             }
140         }
141 
142         if (p_start == NULL || p_end == NULL) {
143             return FAIL_RETURN;
144         }
145         len = p_end - p_start;
146 
147         if (strlen("code") == len && !memcmp(p_start, "code", len)) {
148             infra_str2int(++p, &code);
149             if (code != 200) {
150                 return FAIL_RETURN;
151             }
152         } else if (strlen("iotId") == len && !memcmp(p_start, "iotId", len)) {
153             res = _preauth_get_string_value(p, output->username,
154                                             PREAUTH_IOT_ID_MAXLEN);
155             if (res < SUCCESS_RETURN) {
156                 return res;
157             }
158         } else if (strlen("iotToken") == len &&
159                    !memcmp(p_start, "iotToken", len)) {
160             res = _preauth_get_string_value(p, output->password,
161                                             PREAUTH_IOT_TOKEN_MAXLEN);
162             if (res < SUCCESS_RETURN) {
163                 return res;
164             }
165         } else if (strlen("host") == len && !memcmp(p_start, "host", len)) {
166             res = _preauth_get_string_value(p, output->hostname,
167                                             PREAUTH_IOT_HOST_MAXLEN);
168             if (res < SUCCESS_RETURN) {
169                 return res;
170             }
171         } else if (strlen("port") == len && !memcmp(p_start, "port", len)) {
172             int port_temp;
173             infra_str2int(++p, &port_temp);
174             output->port = port_temp;
175         }
176     }
177 
178     return SUCCESS_RETURN;
179 }
180 
_preauth_recv_callback(char * ptr,int length,int total_length,void * userdata)181 static int _preauth_recv_callback(char *ptr, int length, int total_length,
182                                   void *userdata)
183 {
184     preauth_http_response_t *response = (preauth_http_response_t *)userdata;
185     if (strlen(response->payload) + length > response->payload_len) {
186         return FAIL_RETURN;
187     }
188     memcpy(response->payload + strlen(response->payload), ptr, length);
189 
190     return length;
191 }
192 
preauth_get_connection_info(iotx_mqtt_region_types_t region,iotx_dev_meta_info_t * dev_meta,const char * sign,const char * device_id,iotx_sign_mqtt_t * preauth_output)193 int preauth_get_connection_info(iotx_mqtt_region_types_t region,
194                                 iotx_dev_meta_info_t *dev_meta,
195                                 const char *sign, const char *device_id,
196                                 iotx_sign_mqtt_t *preauth_output)
197 {
198     char http_url[128] = "http://";
199     char http_url_frag[] = "/auth/devicename";
200 #ifdef SUPPORT_TLS
201     int http_port = 443;
202     char *pub_key = (char *)iotx_ca_crt;
203 #else
204     int http_port = 80;
205     char *pub_key = NULL;
206 #endif
207     int res = FAIL_RETURN;
208     void *http_handle = NULL;
209     iotx_http_method_t http_method = IOTX_HTTP_POST;
210     int http_timeout_ms = CONFIG_GUIDER_AUTH_TIMEOUT;
211     preauth_http_response_t response;
212     char *http_header =
213         "Accept: text/xml,text/javascript,text/html,application/json\r\n"
214         "Content-Type: application/x-www-form-urlencoded;charset=utf-8\r\n";
215     int http_recv_maxlen = PREAUTH_HTTP_RSP_LEN;
216     char request_buff[PREAUTH_HTTP_REQ_LEN] = { 0 };
217     char response_buff[PREAUTH_HTTP_RSP_LEN] = { 0 };
218 
219     if (g_infra_http_domain[region] == NULL) {
220         return FAIL_RETURN;
221     }
222 
223     memset(&response, 0, sizeof(preauth_http_response_t));
224     memcpy(http_url + strlen(http_url), g_infra_http_domain[region],
225            strlen(g_infra_http_domain[region]));
226     memcpy(http_url + strlen(http_url), http_url_frag, sizeof(http_url_frag));
227 
228     _preauth_assemble_auth_req_string(dev_meta, sign, device_id, request_buff,
229                                       sizeof(request_buff));
230 
231     response.payload = response_buff;
232     response.payload_len = PREAUTH_HTTP_RSP_LEN;
233 
234     http_handle = wrapper_http_init();
235     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_URL, (void *)http_url);
236     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_PORT, (void *)&http_port);
237     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_METHOD, (void *)&http_method);
238     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_HEADER, (void *)http_header);
239     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_CERT, (void *)pub_key);
240     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_TIMEOUT,
241                         (void *)&http_timeout_ms);
242     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVCALLBACK,
243                         (void *)_preauth_recv_callback);
244     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVMAXLEN,
245                         (void *)&http_recv_maxlen);
246     wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVCONTEXT,
247                         (void *)&response);
248 
249     res = wrapper_http_perform(http_handle, request_buff, strlen(request_buff));
250     wrapper_http_deinit(&http_handle);
251 
252     if (res < SUCCESS_RETURN) {
253         return res;
254     }
255 
256 #ifdef INFRA_LOG_NETWORK_PAYLOAD
257     preauth_info("Downstream Payload:");
258     iotx_facility_json_print(response_buff, LOG_INFO_LEVEL, '<');
259 #endif
260     res = _preauth_parse_auth_rsp_string(response_buff, strlen(response_buff),
261                                          preauth_output);
262 
263     return res;
264 }
265 
266 #endif /* #ifdef MQTT_PRE_AUTH */
267