1 #include <stdio.h>
2 #include <string.h>
3 #include "linkkit/infra/infra_defs.h"
4 #include "linkkit/infra/infra_config.h"
5 #include "linkkit/infra/infra_sha256.h"
6 
7 #include "linkkit/dev_sign_api.h"
8 #include "linkkit/wrappers/wrappers.h"
9 
10 /* all secure mode define */
11 #define MODE_TLS_GUIDER       "-1"
12 #define MODE_TLS_DIRECT       "2"
13 #define MODE_TCP_DIRECT_PLAIN "3"
14 #define MODE_ITLS_DNS_ID2     "8"
15 
16 #if defined(MQTT_PRE_AUTH)
17 #define SECURE_MODE MODE_TLS_GUIDER
18 #elif defined(SUPPORT_TLS)
19 #define SECURE_MODE MODE_TLS_DIRECT
20 #else
21 #define SECURE_MODE MODE_TCP_DIRECT_PLAIN
22 #endif
23 
24 /* use fixed timestamp */
25 #define TIMESTAMP_VALUE "2524608000000"
26 
27 /* clientid key value pair define */
28 const char *clientid_kv[][2] = {
29     { "timestamp", TIMESTAMP_VALUE },
30     { "_v", "sdk-c-" IOTX_SDK_VERSION },
31     { "securemode", SECURE_MODE },
32 #ifdef SIGN_CIPHER_HMAC_SHA256
33     { "signmethod", "hmacsha256" },
34 #elif defined(SIGN_CIPHER_HMAC_SHA1)
35     { "signmethod", "hmacsha1" },
36 #else
37 #error "SIGN CIPHER is not defined"
38 #endif
39     { "lan", "C" },
40 #ifdef MQTT_AUTO_SUBSCRIBE
41     { "_ss", "1" },
42 #endif
43     { "gw", "0" },
44     { "ext", "0" },
45 };
46 
_hex2str(uint8_t * input,uint16_t input_len,char * output)47 static void _hex2str(uint8_t *input, uint16_t input_len, char *output)
48 {
49     char *zEncode = "0123456789abcdef";
50     int i = 0, j = 0;
51 
52     for (i = 0; i < input_len; i++) {
53         output[j++] = zEncode[(input[i] >> 4) & 0xf];
54         output[j++] = zEncode[(input[i]) & 0xf];
55     }
56 }
57 
_sign_get_clientid(char * clientid_string,const char * device_id,const char * custom_kv,uint8_t enable_itls)58 int _sign_get_clientid(char *clientid_string, const char *device_id,
59                        const char *custom_kv, uint8_t enable_itls)
60 {
61     uint8_t i;
62 
63     if (clientid_string == NULL || device_id == NULL) {
64         return FAIL_RETURN;
65     }
66     if (strlen(device_id) + 1 >= DEV_SIGN_CLIENT_ID_MAXLEN) {
67         return FAIL_RETURN;
68     }
69     memset(clientid_string, 0, DEV_SIGN_CLIENT_ID_MAXLEN);
70     memcpy(clientid_string, device_id, strlen(device_id));
71     memcpy(clientid_string + strlen(clientid_string), "|", 1);
72 
73     if (enable_itls > 0) {
74         clientid_kv[2][1] = MODE_ITLS_DNS_ID2;
75     } else {
76         clientid_kv[2][1] = SECURE_MODE;
77     }
78 
79     for (i = 0; i < (sizeof(clientid_kv) / (sizeof(clientid_kv[0]))); i++) {
80         if ((strlen(clientid_string) + strlen(clientid_kv[i][0]) +
81              strlen(clientid_kv[i][1]) + 2) >= DEV_SIGN_CLIENT_ID_MAXLEN) {
82             return FAIL_RETURN;
83         }
84 
85         memcpy(clientid_string + strlen(clientid_string), clientid_kv[i][0],
86                strlen(clientid_kv[i][0]));
87         memcpy(clientid_string + strlen(clientid_string), "=", 1);
88         memcpy(clientid_string + strlen(clientid_string), clientid_kv[i][1],
89                strlen(clientid_kv[i][1]));
90         memcpy(clientid_string + strlen(clientid_string), ",", 1);
91     }
92 
93     if (custom_kv != NULL) {
94         if ((strlen(clientid_string) + strlen(custom_kv) + 1) >=
95             DEV_SIGN_CLIENT_ID_MAXLEN) {
96             return FAIL_RETURN;
97         }
98         memcpy(clientid_string + strlen(clientid_string), custom_kv,
99                strlen(custom_kv));
100         memcpy(clientid_string + strlen(clientid_string), ",", 1);
101     }
102 
103     memcpy(clientid_string + strlen(clientid_string) - 1, "|", 1);
104 
105     return SUCCESS_RETURN;
106 }
107 
108 #define SIGN_FMT_LEN 50 /*  "clientId%sdeviceName%sproductKey%stimestamp%s";*/
109 
110 #ifdef SIGN_CIPHER_HMAC_SHA256
_iotx_generate_sign_string(const char * device_id,const char * device_name,const char * product_key,const char * device_secret,char * sign_string)111 int _iotx_generate_sign_string(const char *device_id, const char *device_name,
112                                const char *product_key,
113                                const char *device_secret, char *sign_string)
114 {
115     char signsource[DEV_SIGN_SOURCE_MAXLEN] = { 0 };
116     uint16_t signsource_len = 0;
117     uint8_t sign_hex[32] = { 0 };
118 
119     signsource_len = SIGN_FMT_LEN + strlen(device_id) + strlen(device_name) +
120                      strlen(product_key) + strlen(TIMESTAMP_VALUE);
121     if (signsource_len >= DEV_SIGN_SOURCE_MAXLEN) {
122         return ERROR_DEV_SIGN_SOURCE_TOO_SHORT;
123     }
124 
125     memset(signsource, 0, DEV_SIGN_SOURCE_MAXLEN);
126     memcpy(signsource, "clientId", strlen("clientId"));
127     memcpy(signsource + strlen(signsource), device_id, strlen(device_id));
128     memcpy(signsource + strlen(signsource), "deviceName", strlen("deviceName"));
129     memcpy(signsource + strlen(signsource), device_name, strlen(device_name));
130     memcpy(signsource + strlen(signsource), "productKey", strlen("productKey"));
131     memcpy(signsource + strlen(signsource), product_key, strlen(product_key));
132     memcpy(signsource + strlen(signsource), "timestamp", strlen("timestamp"));
133     memcpy(signsource + strlen(signsource), TIMESTAMP_VALUE,
134            strlen(TIMESTAMP_VALUE));
135 
136     utils_hmac_sha256((uint8_t *)signsource, strlen(signsource),
137                       (uint8_t *)device_secret, strlen(device_secret),
138                       sign_hex);
139 
140     _hex2str(sign_hex, 32, sign_string);
141 
142     return SUCCESS_RETURN;
143 }
144 #elif defined(SIGN_CIPHER_HMAC_SHA1)
_iotx_generate_sign_string(const char * device_id,const char * device_name,const char * product_key,const char * device_secret,char * sign_string)145 int _iotx_generate_sign_string(const char *device_id, const char *device_name,
146                                const char *product_key,
147                                const char *device_secret, char *sign_string)
148 {
149     char signsource[DEV_SIGN_SOURCE_MAXLEN] = { 0 };
150     uint16_t signsource_len = 0;
151     uint8_t sign_hex[32] = { 0 };
152 
153     signsource_len = SIGN_FMT_LEN + strlen(device_id) + strlen(device_name) +
154                      strlen(product_key) + strlen(TIMESTAMP_VALUE);
155     if (signsource_len >= DEV_SIGN_SOURCE_MAXLEN) {
156         return ERROR_DEV_SIGN_SOURCE_TOO_SHORT;
157     }
158     memset(signsource, 0, DEV_SIGN_SOURCE_MAXLEN);
159     memcpy(signsource, "clientId", strlen("clientId"));
160     memcpy(signsource + strlen(signsource), device_id, strlen(device_id));
161     memcpy(signsource + strlen(signsource), "deviceName", strlen("deviceName"));
162     memcpy(signsource + strlen(signsource), device_name, strlen(device_name));
163     memcpy(signsource + strlen(signsource), "productKey", strlen("productKey"));
164     memcpy(signsource + strlen(signsource), product_key, strlen(product_key));
165     memcpy(signsource + strlen(signsource), "timestamp", strlen("timestamp"));
166     memcpy(signsource + strlen(signsource), TIMESTAMP_VALUE,
167            strlen(TIMESTAMP_VALUE));
168     utils_hmac_sha1((uint8_t *)signsource, strlen(signsource), sign_hex,
169                     (uint8_t *)device_secret, strlen(device_secret));
170     snprintf(sign_string, 41, "%s", sign_hex);
171 
172     return SUCCESS_RETURN;
173 }
174 #else
175 #error "SIGN CIPHER is not defined"
176 #endif
177 
IOT_Sign_MQTT(iotx_mqtt_region_types_t region,iotx_dev_meta_info_t * meta,iotx_sign_mqtt_t * signout)178 int32_t IOT_Sign_MQTT(iotx_mqtt_region_types_t region,
179                       iotx_dev_meta_info_t *meta, iotx_sign_mqtt_t *signout)
180 {
181     uint16_t length = 0;
182     char device_id[IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN + 1] = { 0 };
183     int res;
184 
185     if (region >= IOTX_MQTT_DOMAIN_NUMBER || meta == NULL) {
186         return -1;
187     }
188 
189     memset(signout, 0, sizeof(iotx_sign_mqtt_t));
190 
191     memcpy(device_id, meta->product_key, strlen(meta->product_key));
192     memcpy(device_id + strlen(device_id), ".", strlen("."));
193     memcpy(device_id + strlen(device_id), meta->device_name,
194            strlen(meta->device_name));
195 
196     /* setup clientid */
197     if (_sign_get_clientid(signout->clientid, device_id, NULL, 0) !=
198         SUCCESS_RETURN) {
199         return ERROR_DEV_SIGN_CLIENT_ID_TOO_SHORT;
200     }
201 
202     /* setup password */
203     memset(signout->password, 0, DEV_SIGN_PASSWORD_MAXLEN);
204     res = _iotx_generate_sign_string(device_id, meta->device_name,
205                                      meta->product_key, meta->device_secret,
206                                      signout->password);
207     if (res < SUCCESS_RETURN) {
208         return res;
209     }
210 
211     /* setup hostname */
212     if (IOTX_CLOUD_REGION_CUSTOM == region) {
213         if (g_infra_mqtt_domain[region] == NULL) {
214             return ERROR_DEV_SIGN_CUSTOM_DOMAIN_IS_NULL;
215         }
216 
217         length = strlen(g_infra_mqtt_domain[region]) + 1;
218         if (length >= DEV_SIGN_HOSTNAME_MAXLEN) {
219             return ERROR_DEV_SIGN_HOST_NAME_TOO_SHORT;
220         }
221 
222         memset(signout->hostname, 0, DEV_SIGN_HOSTNAME_MAXLEN);
223         memcpy(signout->hostname, g_infra_mqtt_domain[region],
224                strlen(g_infra_mqtt_domain[region]));
225     } else {
226         length =
227             strlen(meta->product_key) + strlen(g_infra_mqtt_domain[region]) + 2;
228         if (length >= DEV_SIGN_HOSTNAME_MAXLEN) {
229             return ERROR_DEV_SIGN_HOST_NAME_TOO_SHORT;
230         }
231         memset(signout->hostname, 0, DEV_SIGN_HOSTNAME_MAXLEN);
232         memcpy(signout->hostname, meta->product_key, strlen(meta->product_key));
233         memcpy(signout->hostname + strlen(signout->hostname), ".", strlen("."));
234         memcpy(signout->hostname + strlen(signout->hostname),
235                g_infra_mqtt_domain[region],
236                strlen(g_infra_mqtt_domain[region]));
237     }
238 
239     /* setup username */
240     length = strlen(meta->device_name) + strlen(meta->product_key) + 2;
241     if (length >= DEV_SIGN_USERNAME_MAXLEN) {
242         return ERROR_DEV_SIGN_USERNAME_TOO_SHORT;
243     }
244     memset(signout->username, 0, DEV_SIGN_USERNAME_MAXLEN);
245     memcpy(signout->username, meta->device_name, strlen(meta->device_name));
246     memcpy(signout->username + strlen(signout->username), "&", strlen("&"));
247     memcpy(signout->username + strlen(signout->username), meta->product_key,
248            strlen(meta->product_key));
249 
250     /* setup port */
251 
252     signout->port = 1883;
253 
254     return SUCCESS_RETURN;
255 }
256