xref: /freebsd/contrib/wpa/src/rsn_supp/wpa_ie.c (revision 61e21613)
1 /*
2  * wpa_supplicant - WPA/RSN IE and KDE processing
3  * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "wpa.h"
13 #include "pmksa_cache.h"
14 #include "common/ieee802_11_defs.h"
15 #include "wpa_i.h"
16 #include "wpa_ie.h"
17 
18 
19 /**
20  * wpa_parse_wpa_ie - Parse WPA/RSN IE
21  * @wpa_ie: Pointer to WPA or RSN IE
22  * @wpa_ie_len: Length of the WPA/RSN IE
23  * @data: Pointer to data area for parsing results
24  * Returns: 0 on success, -1 on failure
25  *
26  * Parse the contents of WPA or RSN IE and write the parsed data into data.
27  */
28 int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
29 		     struct wpa_ie_data *data)
30 {
31 	if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
32 		return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
33 	if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
34 	    wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE)
35 		return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
36 	else
37 		return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
38 }
39 
40 
41 static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
42 			      int pairwise_cipher, int group_cipher,
43 			      int key_mgmt)
44 {
45 	u8 *pos;
46 	struct wpa_ie_hdr *hdr;
47 	u32 suite;
48 
49 	if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
50 	    2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
51 		return -1;
52 
53 	hdr = (struct wpa_ie_hdr *) wpa_ie;
54 	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
55 	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
56 	WPA_PUT_LE16(hdr->version, WPA_VERSION);
57 	pos = (u8 *) (hdr + 1);
58 
59 	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
60 	if (suite == 0) {
61 		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
62 			   group_cipher);
63 		return -1;
64 	}
65 	RSN_SELECTOR_PUT(pos, suite);
66 	pos += WPA_SELECTOR_LEN;
67 
68 	*pos++ = 1;
69 	*pos++ = 0;
70 	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
71 	if (suite == 0 ||
72 	    (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
73 	     pairwise_cipher != WPA_CIPHER_NONE)) {
74 		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
75 			   pairwise_cipher);
76 		return -1;
77 	}
78 	RSN_SELECTOR_PUT(pos, suite);
79 	pos += WPA_SELECTOR_LEN;
80 
81 	*pos++ = 1;
82 	*pos++ = 0;
83 	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
84 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
85 	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
86 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
87 	} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
88 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
89 	} else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
90 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
91 	} else {
92 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
93 			   key_mgmt);
94 		return -1;
95 	}
96 	pos += WPA_SELECTOR_LEN;
97 
98 	/* WPA Capabilities; use defaults, so no need to include it */
99 
100 	hdr->len = (pos - wpa_ie) - 2;
101 
102 	WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
103 
104 	return pos - wpa_ie;
105 }
106 
107 
108 u16 rsn_supp_capab(struct wpa_sm *sm)
109 {
110 	u16 capab = 0;
111 
112 	if (sm->mfp)
113 		capab |= WPA_CAPABILITY_MFPC;
114 	if (sm->mfp == 2)
115 		capab |= WPA_CAPABILITY_MFPR;
116 	if (sm->ocv)
117 		capab |= WPA_CAPABILITY_OCVC;
118 	if (sm->ext_key_id)
119 		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
120 
121 	return capab;
122 }
123 
124 
125 static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
126 			      int pairwise_cipher, int group_cipher,
127 			      int key_mgmt, int mgmt_group_cipher,
128 			      struct wpa_sm *sm)
129 {
130 	u8 *pos;
131 	struct rsn_ie_hdr *hdr;
132 	u32 suite;
133 
134 	if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
135 	    2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
136 	    (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
137 		wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
138 			   (unsigned long) rsn_ie_len);
139 		return -1;
140 	}
141 
142 	hdr = (struct rsn_ie_hdr *) rsn_ie;
143 	hdr->elem_id = WLAN_EID_RSN;
144 	WPA_PUT_LE16(hdr->version, RSN_VERSION);
145 	pos = (u8 *) (hdr + 1);
146 
147 	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
148 	if (suite == 0) {
149 		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
150 			   group_cipher);
151 		return -1;
152 	}
153 	RSN_SELECTOR_PUT(pos, suite);
154 	pos += RSN_SELECTOR_LEN;
155 
156 	*pos++ = 1;
157 	*pos++ = 0;
158 	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
159 	if (suite == 0 ||
160 	    (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
161 	     pairwise_cipher != WPA_CIPHER_NONE)) {
162 		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
163 			   pairwise_cipher);
164 		return -1;
165 	}
166 	RSN_SELECTOR_PUT(pos, suite);
167 	pos += RSN_SELECTOR_LEN;
168 
169 	*pos++ = 1;
170 	*pos++ = 0;
171 	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
172 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
173 	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
174 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
175 	} else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
176 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
177 #ifdef CONFIG_IEEE80211R
178 	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
179 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
180 #ifdef CONFIG_SHA384
181 	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
182 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
183 #endif /* CONFIG_SHA384 */
184 	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
185 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
186 #endif /* CONFIG_IEEE80211R */
187 	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
188 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
189 	} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
190 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
191 #ifdef CONFIG_SAE
192 	} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
193 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
194 	} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
195 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
196 #endif /* CONFIG_SAE */
197 	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
198 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
199 	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
200 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
201 #ifdef CONFIG_FILS
202 	} else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
203 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
204 	} else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
205 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
206 #ifdef CONFIG_IEEE80211R
207 	} else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
208 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
209 	} else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
210 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
211 #endif /* CONFIG_IEEE80211R */
212 #endif /* CONFIG_FILS */
213 #ifdef CONFIG_OWE
214 	} else if (key_mgmt & WPA_KEY_MGMT_OWE) {
215 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
216 #endif /* CONFIG_OWE */
217 #ifdef CONFIG_DPP
218 	} else if (key_mgmt & WPA_KEY_MGMT_DPP) {
219 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
220 #endif /* CONFIG_DPP */
221 #ifdef CONFIG_HS20
222 	} else if (key_mgmt & WPA_KEY_MGMT_OSEN) {
223 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
224 #endif /* CONFIG_HS20 */
225 	} else {
226 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
227 			   key_mgmt);
228 		return -1;
229 	}
230 	pos += RSN_SELECTOR_LEN;
231 
232 	/* RSN Capabilities */
233 	WPA_PUT_LE16(pos, rsn_supp_capab(sm));
234 	pos += 2;
235 
236 	if (sm->cur_pmksa) {
237 		/* PMKID Count (2 octets, little endian) */
238 		*pos++ = 1;
239 		*pos++ = 0;
240 		/* PMKID */
241 		os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
242 		pos += PMKID_LEN;
243 	}
244 
245 	if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
246 		if (!sm->cur_pmksa) {
247 			/* PMKID Count */
248 			WPA_PUT_LE16(pos, 0);
249 			pos += 2;
250 		}
251 
252 		/* Management Group Cipher Suite */
253 		RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
254 							  mgmt_group_cipher));
255 		pos += RSN_SELECTOR_LEN;
256 	}
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 #ifdef CONFIG_HS20
267 static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
268 			       int pairwise_cipher, int group_cipher,
269 			       int key_mgmt)
270 {
271 	u8 *pos, *len;
272 	u32 suite;
273 
274 	if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
275 	    2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
276 		return -1;
277 
278 	pos = wpa_ie;
279 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
280 	len = pos++; /* to be filled */
281 	WPA_PUT_BE24(pos, OUI_WFA);
282 	pos += 3;
283 	*pos++ = HS20_OSEN_OUI_TYPE;
284 
285 	/* Group Data Cipher Suite */
286 	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
287 	if (suite == 0) {
288 		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
289 			   group_cipher);
290 		return -1;
291 	}
292 	RSN_SELECTOR_PUT(pos, suite);
293 	pos += RSN_SELECTOR_LEN;
294 
295 	/* Pairwise Cipher Suite Count and List */
296 	WPA_PUT_LE16(pos, 1);
297 	pos += 2;
298 	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
299 	if (suite == 0 ||
300 	    (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
301 	     pairwise_cipher != WPA_CIPHER_NONE)) {
302 		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
303 			   pairwise_cipher);
304 		return -1;
305 	}
306 	RSN_SELECTOR_PUT(pos, suite);
307 	pos += RSN_SELECTOR_LEN;
308 
309 	/* AKM Suite Count and List */
310 	WPA_PUT_LE16(pos, 1);
311 	pos += 2;
312 	RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
313 	pos += RSN_SELECTOR_LEN;
314 
315 	*len = pos - len - 1;
316 
317 	WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
318 
319 	return pos - wpa_ie;
320 }
321 #endif /* CONFIG_HS20 */
322 
323 
324 /**
325  * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
326  * @sm: Pointer to WPA state machine data from wpa_sm_init()
327  * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
328  * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
329  * Returns: Length of the generated WPA/RSN IE or -1 on failure
330  */
331 int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
332 {
333 	if (sm->proto == WPA_PROTO_RSN)
334 		return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
335 					  sm->pairwise_cipher,
336 					  sm->group_cipher,
337 					  sm->key_mgmt, sm->mgmt_group_cipher,
338 					  sm);
339 #ifdef CONFIG_HS20
340 	else if (sm->proto == WPA_PROTO_OSEN)
341 		return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
342 					   sm->pairwise_cipher,
343 					   sm->group_cipher,
344 					   sm->key_mgmt);
345 #endif /* CONFIG_HS20 */
346 	else
347 		return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
348 					  sm->pairwise_cipher,
349 					  sm->group_cipher,
350 					  sm->key_mgmt);
351 }
352 
353 
354 int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
355 {
356 	u8 *pos = rsnxe;
357 	u16 capab = 0;
358 	size_t flen;
359 
360 	if (wpa_key_mgmt_sae(sm->key_mgmt) &&
361 	    (sm->sae_pwe == 1 || sm->sae_pwe == 2 || sm->sae_pk)) {
362 		capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
363 #ifdef CONFIG_SAE_PK
364 		if (sm->sae_pk)
365 			capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
366 #endif /* CONFIG_SAE_PK */
367 	}
368 
369 	if (sm->secure_ltf)
370 		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
371 	if (sm->secure_rtt)
372 		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
373 	if (sm->prot_range_neg)
374 		capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
375 
376 	flen = (capab & 0xff00) ? 2 : 1;
377 	if (!capab)
378 		return 0; /* no supported extended RSN capabilities */
379 	if (rsnxe_len < 2 + flen)
380 		return -1;
381 	capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
382 
383 	*pos++ = WLAN_EID_RSNX;
384 	*pos++ = flen;
385 	*pos++ = capab & 0x00ff;
386 	capab >>= 8;
387 	if (capab)
388 		*pos++ = capab;
389 
390 	return pos - rsnxe;
391 }
392