/src/hostap/src/rsn_supp/wpa_ie.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
31 | 0 | if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) |
32 | 0 | return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); |
33 | 0 | if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC && |
34 | 0 | wpa_ie[1] >= 4 && |
35 | 0 | WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE) |
36 | 0 | return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); |
37 | 0 | if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC && |
38 | 0 | wpa_ie[1] >= 4 && |
39 | 0 | WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) |
40 | 0 | return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); |
41 | 0 | return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); |
42 | 0 | } |
43 | | |
44 | | |
45 | | static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, |
46 | | int pairwise_cipher, int group_cipher, |
47 | | int key_mgmt) |
48 | 0 | { |
49 | 0 | u8 *pos; |
50 | 0 | struct wpa_ie_hdr *hdr; |
51 | 0 | u32 suite; |
52 | |
|
53 | 0 | if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + |
54 | 0 | 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) |
55 | 0 | return -1; |
56 | | |
57 | 0 | hdr = (struct wpa_ie_hdr *) wpa_ie; |
58 | 0 | hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; |
59 | 0 | RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); |
60 | 0 | WPA_PUT_LE16(hdr->version, WPA_VERSION); |
61 | 0 | pos = (u8 *) (hdr + 1); |
62 | |
|
63 | 0 | suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher); |
64 | 0 | if (suite == 0) { |
65 | 0 | wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", |
66 | 0 | group_cipher); |
67 | 0 | return -1; |
68 | 0 | } |
69 | 0 | RSN_SELECTOR_PUT(pos, suite); |
70 | 0 | pos += WPA_SELECTOR_LEN; |
71 | |
|
72 | 0 | *pos++ = 1; |
73 | 0 | *pos++ = 0; |
74 | 0 | suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher); |
75 | 0 | if (suite == 0 || |
76 | 0 | (!wpa_cipher_valid_pairwise(pairwise_cipher) && |
77 | 0 | pairwise_cipher != WPA_CIPHER_NONE)) { |
78 | 0 | wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", |
79 | 0 | pairwise_cipher); |
80 | 0 | return -1; |
81 | 0 | } |
82 | 0 | RSN_SELECTOR_PUT(pos, suite); |
83 | 0 | pos += WPA_SELECTOR_LEN; |
84 | |
|
85 | 0 | *pos++ = 1; |
86 | 0 | *pos++ = 0; |
87 | 0 | if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { |
88 | 0 | RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); |
89 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_PSK) { |
90 | 0 | RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); |
91 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { |
92 | 0 | RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); |
93 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { |
94 | 0 | RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM); |
95 | 0 | } else { |
96 | 0 | wpa_printf(MSG_WARNING, "Invalid key management type (%d).", |
97 | 0 | key_mgmt); |
98 | 0 | return -1; |
99 | 0 | } |
100 | 0 | pos += WPA_SELECTOR_LEN; |
101 | | |
102 | | /* WPA Capabilities; use defaults, so no need to include it */ |
103 | |
|
104 | 0 | hdr->len = (pos - wpa_ie) - 2; |
105 | |
|
106 | 0 | WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); |
107 | |
|
108 | 0 | return pos - wpa_ie; |
109 | 0 | } |
110 | | |
111 | | |
112 | | u16 rsn_supp_capab(struct wpa_sm *sm) |
113 | 1.96k | { |
114 | 1.96k | u16 capab = 0; |
115 | | |
116 | 1.96k | if (sm->wmm_enabled) { |
117 | | /* Advertise 16 PTKSA replay counters when using WMM */ |
118 | 0 | capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; |
119 | 0 | } |
120 | 1.96k | if (sm->mfp) |
121 | 0 | capab |= WPA_CAPABILITY_MFPC; |
122 | 1.96k | if (sm->mfp == 2) |
123 | 0 | capab |= WPA_CAPABILITY_MFPR; |
124 | 1.96k | if (sm->ocv) |
125 | 0 | capab |= WPA_CAPABILITY_OCVC; |
126 | 1.96k | if (sm->ext_key_id) |
127 | 0 | capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; |
128 | | |
129 | 1.96k | return capab; |
130 | 1.96k | } |
131 | | |
132 | | |
133 | | static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, |
134 | | int pairwise_cipher, int group_cipher, |
135 | | int key_mgmt, int mgmt_group_cipher, |
136 | | struct wpa_sm *sm) |
137 | 1.96k | { |
138 | 1.96k | u8 *pos; |
139 | 1.96k | struct rsn_ie_hdr *hdr; |
140 | 1.96k | u32 suite; |
141 | | |
142 | 1.96k | if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + |
143 | 1.96k | 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + |
144 | 1.96k | (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { |
145 | 0 | wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", |
146 | 0 | (unsigned long) rsn_ie_len); |
147 | 0 | return -1; |
148 | 0 | } |
149 | | |
150 | 1.96k | hdr = (struct rsn_ie_hdr *) rsn_ie; |
151 | 1.96k | hdr->elem_id = WLAN_EID_RSN; |
152 | 1.96k | WPA_PUT_LE16(hdr->version, RSN_VERSION); |
153 | 1.96k | pos = (u8 *) (hdr + 1); |
154 | | |
155 | 1.96k | suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); |
156 | 1.96k | if (suite == 0) { |
157 | 0 | wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", |
158 | 0 | group_cipher); |
159 | 0 | return -1; |
160 | 0 | } |
161 | 1.96k | RSN_SELECTOR_PUT(pos, suite); |
162 | 1.96k | pos += RSN_SELECTOR_LEN; |
163 | | |
164 | 1.96k | *pos++ = 1; |
165 | 1.96k | *pos++ = 0; |
166 | 1.96k | suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); |
167 | 1.96k | if (suite == 0 || |
168 | 1.96k | (!wpa_cipher_valid_pairwise(pairwise_cipher) && |
169 | 1.96k | pairwise_cipher != WPA_CIPHER_NONE)) { |
170 | 0 | wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", |
171 | 0 | pairwise_cipher); |
172 | 0 | return -1; |
173 | 0 | } |
174 | 1.96k | RSN_SELECTOR_PUT(pos, suite); |
175 | 1.96k | pos += RSN_SELECTOR_LEN; |
176 | | |
177 | 1.96k | *pos++ = 1; |
178 | 1.96k | *pos++ = 0; |
179 | 1.96k | if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { |
180 | 0 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); |
181 | 1.96k | } else if (key_mgmt == WPA_KEY_MGMT_PSK) { |
182 | 1.96k | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); |
183 | 1.96k | } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { |
184 | 0 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM); |
185 | 0 | #ifdef CONFIG_IEEE80211R |
186 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { |
187 | 0 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); |
188 | | #ifdef CONFIG_SHA384 |
189 | | } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) { |
190 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384); |
191 | | #endif /* CONFIG_SHA384 */ |
192 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { |
193 | 0 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); |
194 | 0 | #endif /* CONFIG_IEEE80211R */ |
195 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { |
196 | 0 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); |
197 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { |
198 | 0 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); |
199 | | #ifdef CONFIG_SAE |
200 | | } else if (key_mgmt == WPA_KEY_MGMT_SAE) { |
201 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); |
202 | | } else if (key_mgmt == WPA_KEY_MGMT_SAE_EXT_KEY) { |
203 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY); |
204 | | } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) { |
205 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); |
206 | | } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) { |
207 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY); |
208 | | #endif /* CONFIG_SAE */ |
209 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { |
210 | 0 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192); |
211 | 0 | } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) { |
212 | 0 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B); |
213 | | #ifdef CONFIG_FILS |
214 | | } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) { |
215 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256); |
216 | | } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) { |
217 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384); |
218 | | #ifdef CONFIG_IEEE80211R |
219 | | } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { |
220 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256); |
221 | | } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) { |
222 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384); |
223 | | #endif /* CONFIG_IEEE80211R */ |
224 | | #endif /* CONFIG_FILS */ |
225 | | #ifdef CONFIG_OWE |
226 | | } else if (key_mgmt & WPA_KEY_MGMT_OWE) { |
227 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE); |
228 | | #endif /* CONFIG_OWE */ |
229 | | #ifdef CONFIG_DPP |
230 | | } else if (key_mgmt & WPA_KEY_MGMT_DPP) { |
231 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP); |
232 | | #endif /* CONFIG_DPP */ |
233 | | #ifdef CONFIG_SHA384 |
234 | | } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA384) { |
235 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384); |
236 | | #endif /* CONFIG_SHA384 */ |
237 | 0 | } else { |
238 | 0 | wpa_printf(MSG_WARNING, "Invalid key management type (%d).", |
239 | 0 | key_mgmt); |
240 | 0 | return -1; |
241 | 0 | } |
242 | 1.96k | pos += RSN_SELECTOR_LEN; |
243 | | |
244 | | /* RSN Capabilities */ |
245 | 1.96k | WPA_PUT_LE16(pos, rsn_supp_capab(sm)); |
246 | 1.96k | pos += 2; |
247 | | |
248 | 1.96k | if (sm->cur_pmksa) { |
249 | | /* PMKID Count (2 octets, little endian) */ |
250 | 0 | *pos++ = 1; |
251 | 0 | *pos++ = 0; |
252 | | /* PMKID */ |
253 | 0 | os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); |
254 | 0 | pos += PMKID_LEN; |
255 | 0 | } |
256 | | |
257 | 1.96k | if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) { |
258 | 0 | if (!sm->cur_pmksa) { |
259 | | /* PMKID Count */ |
260 | 0 | WPA_PUT_LE16(pos, 0); |
261 | 0 | pos += 2; |
262 | 0 | } |
263 | | |
264 | | /* Management Group Cipher Suite */ |
265 | 0 | RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, |
266 | 0 | mgmt_group_cipher)); |
267 | 0 | pos += RSN_SELECTOR_LEN; |
268 | 0 | } |
269 | | |
270 | 1.96k | hdr->len = (pos - rsn_ie) - 2; |
271 | | |
272 | 1.96k | WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); |
273 | | |
274 | 1.96k | return pos - rsn_ie; |
275 | 1.96k | } |
276 | | |
277 | | |
278 | | /** |
279 | | * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy |
280 | | * @sm: Pointer to WPA state machine data from wpa_sm_init() |
281 | | * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE |
282 | | * @wpa_ie_len: Maximum length of the generated WPA/RSN IE |
283 | | * Returns: Length of the generated WPA/RSN IE or -1 on failure |
284 | | */ |
285 | | int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) |
286 | 1.96k | { |
287 | 1.96k | if (sm->proto == WPA_PROTO_RSN) |
288 | 1.96k | return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, |
289 | 1.96k | sm->pairwise_cipher, |
290 | 1.96k | sm->group_cipher, |
291 | 1.96k | sm->key_mgmt, sm->mgmt_group_cipher, |
292 | 1.96k | sm); |
293 | 0 | else |
294 | 0 | return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, |
295 | 0 | sm->pairwise_cipher, |
296 | 0 | sm->group_cipher, |
297 | 0 | sm->key_mgmt); |
298 | 1.96k | } |
299 | | |
300 | | |
301 | | int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len) |
302 | 0 | { |
303 | 0 | u8 *pos = rsnxe; |
304 | 0 | u32 capab = 0, tmp; |
305 | 0 | size_t flen; |
306 | |
|
307 | 0 | if (wpa_key_mgmt_sae(sm->key_mgmt) && |
308 | 0 | (sm->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || |
309 | 0 | sm->sae_pwe == SAE_PWE_BOTH || sm->sae_pk)) { |
310 | 0 | capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); |
311 | | #ifdef CONFIG_SAE_PK |
312 | | if (sm->sae_pk) |
313 | | capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK); |
314 | | #endif /* CONFIG_SAE_PK */ |
315 | 0 | } |
316 | |
|
317 | 0 | if (sm->secure_ltf) |
318 | 0 | capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF); |
319 | 0 | if (sm->secure_rtt) |
320 | 0 | capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT); |
321 | 0 | if (sm->prot_range_neg) |
322 | 0 | capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR); |
323 | 0 | if (sm->ssid_protection) |
324 | 0 | capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION); |
325 | 0 | if (sm->spp_amsdu) |
326 | 0 | capab |= BIT(WLAN_RSNX_CAPAB_SPP_A_MSDU); |
327 | |
|
328 | 0 | if (!capab) |
329 | 0 | return 0; /* no supported extended RSN capabilities */ |
330 | 0 | tmp = capab; |
331 | 0 | flen = 0; |
332 | 0 | while (tmp) { |
333 | 0 | flen++; |
334 | 0 | tmp >>= 8; |
335 | 0 | } |
336 | 0 | if (rsnxe_len < 2 + flen) |
337 | 0 | return -1; |
338 | 0 | capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ |
339 | |
|
340 | 0 | *pos++ = WLAN_EID_RSNX; |
341 | 0 | *pos++ = flen; |
342 | 0 | while (capab) { |
343 | 0 | *pos++ = capab & 0xff; |
344 | 0 | capab >>= 8; |
345 | 0 | } |
346 | |
|
347 | 0 | return pos - rsnxe; |
348 | 0 | } |