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