1 /*
2  * wpa_supplicant - WPA/RSN IE and KDE processing
3  * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14  #ifdef ESP_SUPPLICANT
15 
16 #include "utils/includes.h"
17 
18 #include "utils/common.h"
19 #include "rsn_supp/wpa.h"
20 #include "common/ieee802_11_defs.h"
21 #include "rsn_supp/wpa_ie.h"
22 #include "rsn_supp/pmksa_cache.h"
23 
24 /**
25  * wpa_parse_wpa_ie - Parse WPA/RSN IE
26  * @wpa_ie: Pointer to WPA or RSN IE
27  * @wpa_ie_len: Length of the WPA/RSN IE
28  * @data: Pointer to data area for parsing results
29  * Returns: 0 on success, -1 on failure
30  *
31  * Parse the contents of WPA or RSN IE and write the parsed data into data.
32  */
wpa_parse_wpa_ie(const u8 * wpa_ie,size_t wpa_ie_len,struct wpa_ie_data * data)33 int  wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
34 		     struct wpa_ie_data *data)
35 {
36     if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) {
37         return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
38     } else if (wpa_ie[0] == WLAN_EID_WAPI) {
39         return 0;
40     }
41 
42     return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
43 }
44 
45 
wpa_gen_wpa_ie_wpa(u8 * wpa_ie,size_t wpa_ie_len,int pairwise_cipher,int group_cipher,int key_mgmt)46 static int  wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
47                   int pairwise_cipher, int group_cipher,
48                   int key_mgmt)
49 {
50     u8 *pos;
51     struct wpa_ie_hdr *hdr;
52 
53     if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
54         2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
55         return -1;
56 
57     hdr = (struct wpa_ie_hdr *) wpa_ie;
58     hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
59     RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
60     WPA_PUT_LE16(hdr->version, WPA_VERSION);
61     pos = (u8 *) (hdr + 1);
62 
63     if (group_cipher == WPA_CIPHER_CCMP) {
64         RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
65     } else if (group_cipher == WPA_CIPHER_TKIP) {
66         RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
67     } else if (group_cipher == WPA_CIPHER_WEP104) {
68         RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
69     } else if (group_cipher == WPA_CIPHER_WEP40) {
70         RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
71     } else {
72         wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
73                group_cipher);
74         return -1;
75     }
76     pos += WPA_SELECTOR_LEN;
77 
78     *pos++ = 1;
79     *pos++ = 0;
80     if (pairwise_cipher == WPA_CIPHER_CCMP) {
81         RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
82     } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
83         RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
84     } else if (pairwise_cipher == WPA_CIPHER_NONE) {
85         RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
86     } else {
87         wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
88                pairwise_cipher);
89         return -1;
90     }
91     pos += WPA_SELECTOR_LEN;
92 
93     *pos++ = 1;
94     *pos++ = 0;
95     if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
96         RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
97     } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
98         RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
99     } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
100         RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
101     } else {
102         wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
103                key_mgmt);
104         return -1;
105     }
106     pos += WPA_SELECTOR_LEN;
107 
108     /* WPA Capabilities; use defaults, so no need to include it */
109 
110     hdr->len = (pos - wpa_ie) - 2;
111 
112     WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
113 
114     return pos - wpa_ie;
115 }
116 
117 
wpa_gen_wpa_ie_rsn(u8 * rsn_ie,size_t rsn_ie_len,int pairwise_cipher,int group_cipher,int key_mgmt,int mgmt_group_cipher,struct wpa_sm * sm)118 static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
119                   int pairwise_cipher, int group_cipher,
120                   int key_mgmt, int mgmt_group_cipher,
121                   struct wpa_sm *sm)
122 {
123     u8 *pos;
124     struct rsn_ie_hdr *hdr;
125     u16 capab;
126     u8 min_len = 0;
127     u32 suite;
128 
129     if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
130             2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
131             (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
132         wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
133                 (unsigned long) rsn_ie_len);
134         return -1;
135     }
136 
137     if ( (sm->ap_notify_completed_rsne == true) || (key_mgmt == WPA_KEY_MGMT_IEEE8021X) ) {
138         min_len = sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2;
139     } else {
140         min_len = sizeof(*hdr) + RSN_SELECTOR_LEN;
141     }
142 
143     if (rsn_ie_len < min_len) {
144         wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", (unsigned long) rsn_ie_len);
145     }
146 
147     hdr = (struct rsn_ie_hdr *) rsn_ie;
148     hdr->elem_id = WLAN_EID_RSN;
149     WPA_PUT_LE16(hdr->version, RSN_VERSION);
150     pos = (u8 *) (hdr + 1);
151 
152     suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
153     if (suite == 0) {
154             wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
155                        group_cipher);
156             return -1;
157     }
158     RSN_SELECTOR_PUT(pos, suite);
159     pos += RSN_SELECTOR_LEN;
160 
161     if ( (sm->ap_notify_completed_rsne == false) && (key_mgmt != WPA_KEY_MGMT_IEEE8021X) ) {
162         hdr->len = (pos - rsn_ie) - 2;
163         return (pos - rsn_ie);
164     }
165 
166     *pos++ = 1;
167     *pos++ = 0;
168     suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
169     if (suite == 0 ||
170          (pairwise_cipher == WPA_CIPHER_NONE)) {
171             wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
172                        pairwise_cipher);
173             return -1;
174     }
175     RSN_SELECTOR_PUT(pos, suite);
176     pos += RSN_SELECTOR_LEN;
177 
178     *pos++ = 1;
179     *pos++ = 0;
180 
181     if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
182         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
183     } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
184         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
185 #ifdef CONFIG_IEEE80211R
186     } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
187         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
188     } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
189         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
190 #endif /* CONFIG_IEEE80211R */
191 #ifdef CONFIG_IEEE80211W
192     } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
193         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
194     } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
195         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
196 #ifdef CONFIG_WPA3_SAE
197     } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
198         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
199 #endif /* CONFIG_WPA3_SAE */
200 #endif /* CONFIG_IEEE80211W */
201     } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
202         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
203     } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
204         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
205     } else {
206         wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
207                key_mgmt);
208         return -1;
209     }
210     pos += RSN_SELECTOR_LEN;
211 
212     /* RSN Capabilities */
213     capab = 0;
214 #ifdef CONFIG_IEEE80211W
215     if (sm->pmf_cfg.capable) {
216         capab |= WPA_CAPABILITY_MFPC;
217         if (sm->pmf_cfg.required || key_mgmt == WPA_KEY_MGMT_SAE) {
218             capab |= WPA_CAPABILITY_MFPR;
219         }
220     }
221 #endif /* CONFIG_IEEE80211W */
222 
223     if (sm->spp_sup.capable) {
224         capab |= WPA_CAPABILITY_SPP_CAPABLE;
225     }
226 
227     if (sm->spp_sup.require) {
228         capab |= WPA_CAPABILITY_SPP_REQUIRED;
229     }
230 
231     WPA_PUT_LE16(pos, capab);
232     pos += 2;
233 
234     if (sm->cur_pmksa) {
235         /* PMKID Count (2 octets, little endian) */
236         *pos++ = 1;
237         *pos++ = 0;
238         /* PMKID */
239         os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
240         pos += PMKID_LEN;
241     }
242 
243 #ifdef CONFIG_IEEE80211W
244     if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
245         if (!sm->cur_pmksa) {
246             /* 0 PMKID Count */
247             WPA_PUT_LE16(pos, 0);
248             pos += 2;
249         }
250 
251         /* Management Group Cipher Suite */
252         RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
253                                                   mgmt_group_cipher));;
254         pos += RSN_SELECTOR_LEN;
255     }
256 #endif /* CONFIG_IEEE80211W */
257 
258     hdr->len = (pos - rsn_ie) - 2;
259 
260     WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
261 
262     return pos - rsn_ie;
263 }
264 
265 
266 /**
267  * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
268  * @sm: Pointer to WPA state machine data from wpa_sm_init()
269  * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
270  * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
271  * Returns: Length of the generated WPA/RSN IE or -1 on failure
272  */
wpa_gen_wpa_ie(struct wpa_sm * sm,u8 * wpa_ie,size_t wpa_ie_len)273 int  wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
274 {
275     if (sm->proto == WPA_PROTO_RSN) {
276         return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
277                       sm->pairwise_cipher,
278                       sm->group_cipher,
279                       sm->key_mgmt, sm->mgmt_group_cipher,
280                       sm);
281     } else if (sm->proto == WPA_PROTO_WAPI) {
282         return 0;
283     }
284 
285     return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
286                     sm->pairwise_cipher,
287                     sm->group_cipher,
288                     sm->key_mgmt);
289 }
290 
291 
292 /**
293  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
294  * @pos: Pointer to the IE header
295  * @end: Pointer to the end of the Key Data buffer
296  * @ie: Pointer to parsed IE data
297  * Returns: 0 on success, 1 if end mark is found, -1 on failure
298  */
wpa_parse_generic(const u8 * pos,const u8 * end,struct wpa_eapol_ie_parse * ie)299 static int  wpa_parse_generic(const u8 *pos, const u8 *end,
300 			     struct wpa_eapol_ie_parse *ie)
301 {
302 	if (pos[1] == 0)
303 		return 1;
304 
305 	if (pos[1] >= 6 &&
306 	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
307 	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
308 	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
309 		ie->wpa_ie = pos;
310 		ie->wpa_ie_len = pos[1] + 2;
311 		wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
312 			    ie->wpa_ie, ie->wpa_ie_len);
313 		return 0;
314 	}
315 
316 	if (pos + 1 + RSN_SELECTOR_LEN < end &&
317 	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
318 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
319 		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
320 		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
321 			    pos, pos[1] + 2);
322 		return 0;
323 	}
324 
325 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
326 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
327 		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
328 		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
329 		wpa_hexdump(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
330 				pos, pos[1] + 2);
331 		return 0;
332 	}
333 
334 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
335 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
336 		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
337 		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
338 		wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
339 			    pos, pos[1] + 2);
340 		return 0;
341 	}
342 #ifdef CONFIG_IEEE80211W
343 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
344 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
345 		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
346 		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
347 		wpa_hexdump(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
348 				pos, pos[1] + 2);
349 		return 0;
350 	}
351 #endif
352 	return 0;
353 }
354 
355 
356 /**
357  * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
358  * @buf: Pointer to the Key Data buffer
359  * @len: Key Data Length
360  * @ie: Pointer to parsed IE data
361  * Returns: 0 on success, -1 on failure
362  */
wpa_supplicant_parse_ies(const u8 * buf,size_t len,struct wpa_eapol_ie_parse * ie)363 int  wpa_supplicant_parse_ies(const u8 *buf, size_t len,
364 			     struct wpa_eapol_ie_parse *ie)
365 {
366 	const u8 *pos, *end;
367 	int ret = 0;
368 
369 	memset(ie, 0, sizeof(*ie));
370 	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
371 		if (pos[0] == 0xdd &&
372 		    ((pos == buf + len - 1) || pos[1] == 0)) {
373 			/* Ignore padding */
374 			break;
375 		}
376 		if (pos + 2 + pos[1] > end) {
377 		    #ifdef DEBUG_PRINT
378 			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
379 				   "underflow (ie=%d len=%d pos=%d)",
380 				   pos[0], pos[1], (int) (pos - buf));
381 		    #endif
382 			wpa_hexdump(MSG_DEBUG, "WPA: Key Data",
383 					buf, len);
384 			ret = -1;
385 			break;
386 		}
387 		if (*pos == WLAN_EID_RSN) {
388 			ie->rsn_ie = pos;
389 			ie->rsn_ie_len = pos[1] + 2;
390 			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
391 				    ie->rsn_ie, ie->rsn_ie_len);
392 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
393 			ret = wpa_parse_generic(pos, end, ie);
394 			if (ret < 0)
395 				break;
396 			if (ret > 0) {
397 				ret = 0;
398 				break;
399 			}
400 		} else {
401 			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
402 				    "Key Data IE", pos, 2 + pos[1]);
403 		}
404 	}
405 
406 	return ret;
407 }
408 
409 
410 #endif // ESP_SUPPLICANT
411