1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 #include "wifi_provision_internal.h"
5 
6 #ifndef AWSS_DISABLE_ENROLLEE
7 
8 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
9 extern "C" {
10 #endif
11 
12 const uint8_t probe_req_frame[ZC_PROBE_LEN] = {
13     0x40, 0x00,                         /* mgnt type, frame control */
14     0x00, 0x00,                         /* duration */
15     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* DA */
16     0x28, 0xC2, 0xDD, 0x61, 0x68, 0x83, /* SA, to be replaced with wifi mac */
17     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* BSSID */
18     0xC0, 0x79,                         /* seq */
19     0x00, 0x00,                         /* hide ssid, */
20     0x01, 0x08, 0x82, 0x84, 0x8B, 0x96,
21     0x8C, 0x92, 0x98, 0xA4,             /* supported rates */
22     0x32, 0x04, 0xB0, 0x48, 0x60, 0x6C, /* extended supported rates */
23     0x3F, 0x84, 0x10, 0x9E              /* FCS */
24 };
25 
26 static uint8_t *g_dev_sign;    /* pointer to dev_name_len start pos */
27 static uint8_t *g_product_key; /* pointer to model_len start pos */
28 static uint8_t *enrollee_frame;
29 static uint16_t enrollee_frame_len;
30 
31 static int decrypt_ssid_passwd(uint8_t *ie, uint8_t ie_len,
32                                uint8_t out_ssid[OS_MAX_SSID_LEN],
33                                uint8_t out_passwd[OS_MAX_PASSWD_LEN],
34                                uint8_t out_bssid[ETH_ALEN]);
35 
awss_init_enrollee_info(void)36 void awss_init_enrollee_info(void) /* void enrollee_raw_frame_init(void) */
37 {
38     char *pk = NULL, *dev_name = NULL, *text = NULL;
39     uint8_t sign[ENROLLEE_SIGN_SIZE + 1] = { 0 };
40     char key[OS_DEVICE_SECRET_LEN + 1] = { 0 };
41     int dev_name_len, pk_len;
42     int len, ie_len;
43 
44     if (enrollee_frame_len)
45         return;
46 
47     dev_name = awss_zalloc(OS_DEVICE_NAME_LEN + 1);
48     if (NULL == dev_name) {
49         return;
50     }
51     pk = awss_zalloc(OS_PRODUCT_KEY_LEN + 1);
52     if (NULL == pk) {
53         HAL_Free(dev_name);
54         return;
55     }
56     printf("pk:%s\r\n", pk);
57     HAL_GetProductKey(pk);
58     pk_len = strlen(pk);
59 
60     HAL_GetDeviceName(dev_name);
61     dev_name_len = strlen(dev_name);
62     printf("dev_name:%s\r\n", dev_name);
63     len = RANDOM_MAX_LEN + dev_name_len + pk_len;
64     text = awss_zalloc(len + 1); /* +1 for string print */
65 
66     awss_build_sign_src(text, &len);
67 
68     for (int i = 0; i < len; i++) {
69         printf("0x%x ", *(unsigned char *)(text + i));
70     }
71     printf("\r\n");
72     if (awss_get_encrypt_type() == 3) { /* aes-key per product */
73         HAL_GetProductSecret(key);
74     } else { /* aes-key per device */
75         HAL_GetDeviceSecret(key);
76     }
77 
78     printf("key:%s\r\n", key);
79     produce_signature(sign, (uint8_t *)text, len, key);
80     for (int i = 0; i < SHA1_DIGEST_SIZE; i++) {
81         printf("0x%x ", *(unsigned char *)(sign + i));
82     }
83     printf("\r\n");
84 
85     HAL_Free(text);
86 
87     ie_len = pk_len + dev_name_len + ENROLLEE_IE_FIX_LEN;
88     enrollee_frame_len = sizeof(probe_req_frame) + ie_len;
89 
90     enrollee_frame = awss_zalloc(enrollee_frame_len);
91 
92     /* construct the enrollee frame right now */
93     len = sizeof(probe_req_frame) - FCS_SIZE;
94     memcpy(enrollee_frame, probe_req_frame, len);
95 
96     enrollee_frame[len++] = 221;        /* vendor ie */
97     enrollee_frame[len++] = ie_len - 2; /* exclude 221 & len */
98     enrollee_frame[len++] = 0xD8;
99     enrollee_frame[len++] = 0x96;
100     enrollee_frame[len++] = 0xE0;
101     enrollee_frame[len++] = 0xAA;                /* OUI type */
102     enrollee_frame[len++] = DEVICE_TYPE_VERSION; /* version & dev type */
103 
104     enrollee_frame[len++] = dev_name_len; /* dev name len*/
105     memcpy(&enrollee_frame[len], dev_name, dev_name_len);
106     len += dev_name_len;
107 
108     enrollee_frame[len++] = ENROLLEE_FRAME_TYPE; /* frame type */
109 
110     g_product_key =
111         &enrollee_frame[len]; /* pointer to pk len, see decrypt func */
112     enrollee_frame[len++] = pk_len;
113     memcpy(&enrollee_frame[len], pk, pk_len);
114     len += pk_len;
115 
116     enrollee_frame[len++] = RANDOM_MAX_LEN;
117     memcpy(&enrollee_frame[len], aes_random, RANDOM_MAX_LEN);
118     len += RANDOM_MAX_LEN;
119 
120     enrollee_frame[len++] = awss_get_encrypt_type(); /*encrypt type */
121     enrollee_frame[len++] =
122         0; /* signature method, 0: hmacsha1, 1: hmacsha256 */
123     enrollee_frame[len++] = ENROLLEE_SIGN_SIZE; /* signature length */
124     g_dev_sign = &enrollee_frame[len];
125     memcpy(&enrollee_frame[len], sign, ENROLLEE_SIGN_SIZE);
126     len += ENROLLEE_SIGN_SIZE;
127 
128     memcpy(&enrollee_frame[len],
129            &probe_req_frame[sizeof(probe_req_frame) - FCS_SIZE], FCS_SIZE);
130 
131     /* update probe request frame src mac */
132     os_wifi_get_mac(enrollee_frame + SA_POS);
133 
134     for (int i = 0; i < 6; i++) {
135         printf("0x%x ", *(unsigned char *)(enrollee_frame + SA_POS + i));
136     }
137 
138     HAL_Free(pk);
139     HAL_Free(dev_name);
140 }
141 
awss_destroy_enrollee_info(void)142 void awss_destroy_enrollee_info(void)
143 {
144     if (enrollee_frame_len) {
145         if (NULL != enrollee_frame) {
146             HAL_Free(enrollee_frame);
147         }
148         enrollee_frame_len = 0;
149         enrollee_frame = NULL;
150         g_dev_sign = NULL;
151         g_product_key = NULL;
152     }
153 }
154 
awss_broadcast_enrollee_info(void)155 void awss_broadcast_enrollee_info(void)
156 {
157     if (enrollee_frame_len == 0 || enrollee_frame == NULL)
158         return;
159 
160     HAL_Wifi_Send_80211_Raw_Frame(FRAME_PROBE_REQ, enrollee_frame,
161                                   enrollee_frame_len);
162 }
163 
164 /* return 0 for success, -1 dev_name not match, otherwise return -2 */
decrypt_ssid_passwd(uint8_t * ie,uint8_t ie_len,uint8_t out_ssid[OS_MAX_SSID_LEN],uint8_t out_passwd[OS_MAX_PASSWD_LEN],uint8_t out_bssid[ETH_ALEN])165 static int decrypt_ssid_passwd(uint8_t *ie, uint8_t ie_len,
166                                uint8_t out_ssid[OS_MAX_SSID_LEN],
167                                uint8_t out_passwd[OS_MAX_PASSWD_LEN],
168                                uint8_t out_bssid[ETH_ALEN])
169 {
170     uint8_t tmp_ssid[OS_MAX_SSID_LEN + 1] = { 0 },
171                                        tmp_passwd[OS_MAX_PASSWD_LEN + 1] = {
172                                            0
173                                        };
174     uint8_t *p_dev_name_sign = NULL, *p_ssid = NULL, *p_passwd = NULL,
175             *p_bssid = NULL;
176 
177     /* ignore ie hdr: 221, len, oui[3], type(0xAB) */
178 #define REGISTRAR_IE_HDR (6)
179     ie += REGISTRAR_IE_HDR;
180     printf("ethan registrar(devtype/ver=%d\r\n", ie[0]);
181     if (ie[0] != DEVICE_TYPE_VERSION) {
182         awss_debug("registrar(devtype/ver=%d not supported!", ie[0]);
183         return -1;
184     }
185 
186     ie++; /* skip version */
187     p_dev_name_sign = ie;
188 
189     if (!g_dev_sign ||
190         memcmp(g_dev_sign, p_dev_name_sign + 1, p_dev_name_sign[0])) {
191         p_dev_name_sign[p_dev_name_sign[0]] = '\0';
192         awss_debug("dev_name not match, expect:");
193         printf("dev_name not match, expect\r\n");
194         if (g_dev_sign)
195             dump_hex(g_dev_sign, p_dev_name_sign[0], 16);
196         awss_debug("\r\nbut recv:");
197         dump_hex(p_dev_name_sign + 1, p_dev_name_sign[0], 16);
198         return -2;
199     }
200     ie += ie[0] + 1; /* eating device name sign length & device name sign[n] */
201     printf("ethan registrar(frametype/ver=%d\r\n", ie[0]);
202     if (ie[0] != REGISTRAR_FRAME_TYPE) {
203         awss_debug("registrar(frametype=%d not supported!", ie[0]);
204         return -1;
205     }
206 
207     ie++; /* eating frame type */
208     p_ssid = ie;
209     if (ie[0] >= OS_MAX_SSID_LEN) {
210         awss_debug("registrar(ssidlen=%d invalid!", ie[0]);
211         printf("registrar(ssidlen=%d invalid!\r\n", ie[0]);
212         return -1;
213     }
214     memcpy(tmp_ssid, &p_ssid[1], p_ssid[0]);
215     awss_debug("Registrar ssid:%s", tmp_ssid);
216     printf("Registrar ssid:%s\r\n", tmp_ssid);
217 
218     ie += ie[0] + 1; /* eating ssid_len & ssid[n] */
219 
220     p_passwd = ie;
221     if (p_passwd[0] >= OS_MAX_PASSWD_LEN) {
222         awss_debug("registrar(passwdlen=%d invalid!", p_passwd[0]);
223         printf("registrar(passwdlen=%d invalid!\r\n", p_passwd[0]);
224         return -1;
225     }
226 
227     ie += ie[0] + 1; /* eating passwd_len & passwd */
228 
229     p_bssid = ie;
230     ie += ETH_ALEN; /* eating bssid len */
231 
232     AWSS_UPDATE_STATIS(AWSS_STATIS_ZCONFIG_IDX, AWSS_STATIS_TYPE_TIME_START);
233 
234     aes_decrypt_string((char *)p_passwd + 1, (char *)tmp_passwd, p_passwd[0], 1,
235                        awss_get_encrypt_type(), 0,
236                        (const char *)aes_random); /* aes128 cfb */
237     if (is_utf8((const char *)tmp_passwd, p_passwd[0]) != 1) {
238         awss_debug("registrar(passwd invalid!");
239         printf("registrar(passwd invalid!\r\n");
240         AWSS_UPDATE_STATIS(AWSS_STATIS_ZCONFIG_IDX,
241                            AWSS_STATIS_TYPE_PASSWD_ERR);
242         return -1;
243     }
244     awss_debug("ssid:%s\r\n", tmp_ssid);
245     printf("ssid:%s, tmp_passwd:%s\r\n", tmp_ssid, tmp_passwd);
246     strncpy((char *)out_passwd, (const char *)tmp_passwd,
247             OS_MAX_PASSWD_LEN - 1);
248     strncpy((char *)out_ssid, (const char *)tmp_ssid, OS_MAX_SSID_LEN - 1);
249     memcpy((char *)out_bssid, (char *)p_bssid, ETH_ALEN);
250 
251     return 0; /* success */
252 }
253 
awss_ieee80211_zconfig_process(uint8_t * mgmt_header,int len,int link_type,struct parser_res * res,signed char rssi)254 int awss_ieee80211_zconfig_process(uint8_t *mgmt_header, int len, int link_type,
255                                    struct parser_res *res, signed char rssi)
256 {
257     const uint8_t *registrar_ie = NULL;
258     struct ieee80211_hdr *hdr;
259     uint16_t ieoffset;
260     int fc;
261 
262     /*
263      * when device try to connect current router (include aha)
264      * skip the new aha and process the new aha in the next scope.
265      */
266     if (mgmt_header == NULL || zconfig_finished)
267         return ALINK_INVALID;
268 
269     /*
270      * we don't process zconfig used by enrollee until user press configure
271      * button
272      */
273     if (awss_get_config_press() == 0)
274         return ALINK_INVALID;
275     hdr = (struct ieee80211_hdr *)mgmt_header;
276     fc = hdr->frame_control;
277 
278     if (!ieee80211_is_probe_resp(fc))
279         return ALINK_INVALID;
280     ieoffset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
281     if (ieoffset > len)
282         return ALINK_INVALID;
283 
284     registrar_ie = (const uint8_t *)cfg80211_find_vendor_ie(
285         WLAN_OUI_ALIBABA, WLAN_OUI_TYPE_REGISTRAR, mgmt_header + ieoffset,
286         len - ieoffset);
287     if (registrar_ie == NULL)
288         return ALINK_INVALID;
289 
290     res->u.ie.alink_ie_len = len - (registrar_ie - mgmt_header);
291     res->u.ie.alink_ie = (uint8_t *)registrar_ie;
292     return ALINK_ZERO_CONFIG;
293 }
294 
awss_recv_callback_zconfig(struct parser_res * res)295 int awss_recv_callback_zconfig(struct parser_res *res)
296 {
297     uint8_t tods = res->tods;
298     uint8_t channel = res->channel;
299 
300     uint8_t *ie = res->u.ie.alink_ie;
301     uint8_t ie_len = ie[1];
302     int ret;
303     if (res->u.ie.alink_ie_len < ie_len)
304         return PKG_INVALID;
305 
306     ret = decrypt_ssid_passwd(ie, ie_len, zc_ssid, zc_passwd, zc_bssid);
307     if (ret)
308         return PKG_INVALID;
309 
310     zconfig_set_state(STATE_RCV_DONE, tods, channel);
311 
312     AWSS_UPDATE_STATIS(AWSS_STATIS_ROUTE_IDX, AWSS_STATIS_TYPE_TIME_SUC);
313 
314     return PKG_END;
315 }
316 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
317 }
318 #endif
319 
320 #endif
321