]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/rsn_supp/wpa_ie.c
STA: Support Extended Key ID
[thirdparty/hostap.git] / src / rsn_supp / wpa_ie.c
CommitLineData
6fc6879b
JM
1/*
2 * wpa_supplicant - WPA/RSN IE and KDE processing
c22bb5bb 3 * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "wpa.h"
13#include "pmksa_cache.h"
90973fb2 14#include "common/ieee802_11_defs.h"
6fc6879b
JM
15#include "wpa_i.h"
16#include "wpa_ie.h"
17
18
6fc6879b
JM
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 */
28int 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);
0f8385e6
BG
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);
6fc6879b
JM
36 else
37 return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
38}
39
40
41static 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;
c3550295 47 u32 suite;
6fc6879b
JM
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
c3550295
JM
59 suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
60 if (suite == 0) {
6fc6879b
JM
61 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
62 group_cipher);
63 return -1;
64 }
c3550295 65 RSN_SELECTOR_PUT(pos, suite);
6fc6879b
JM
66 pos += WPA_SELECTOR_LEN;
67
68 *pos++ = 1;
69 *pos++ = 0;
c3550295
JM
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)) {
6fc6879b
JM
74 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
75 pairwise_cipher);
76 return -1;
77 }
c3550295 78 RSN_SELECTOR_PUT(pos, suite);
6fc6879b
JM
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);
369c8d7b
JM
89 } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
90 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
6fc6879b
JM
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
108static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
109 int pairwise_cipher, int group_cipher,
110 int key_mgmt, int mgmt_group_cipher,
111 struct wpa_sm *sm)
112{
6fc6879b
JM
113 u8 *pos;
114 struct rsn_ie_hdr *hdr;
115 u16 capab;
c3550295 116 u32 suite;
6fc6879b
JM
117
118 if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
119 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
120 (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
121 wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
122 (unsigned long) rsn_ie_len);
123 return -1;
124 }
125
126 hdr = (struct rsn_ie_hdr *) rsn_ie;
127 hdr->elem_id = WLAN_EID_RSN;
128 WPA_PUT_LE16(hdr->version, RSN_VERSION);
129 pos = (u8 *) (hdr + 1);
130
c3550295
JM
131 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
132 if (suite == 0) {
6fc6879b
JM
133 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
134 group_cipher);
135 return -1;
136 }
c3550295 137 RSN_SELECTOR_PUT(pos, suite);
6fc6879b
JM
138 pos += RSN_SELECTOR_LEN;
139
140 *pos++ = 1;
141 *pos++ = 0;
c3550295
JM
142 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
143 if (suite == 0 ||
144 (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
145 pairwise_cipher != WPA_CIPHER_NONE)) {
6fc6879b
JM
146 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
147 pairwise_cipher);
148 return -1;
149 }
c3550295 150 RSN_SELECTOR_PUT(pos, suite);
6fc6879b
JM
151 pos += RSN_SELECTOR_LEN;
152
153 *pos++ = 1;
154 *pos++ = 0;
155 if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
156 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
157 } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
158 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
369c8d7b
JM
159 } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
160 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
6fc6879b
JM
161#ifdef CONFIG_IEEE80211R
162 } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
163 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
c22bb5bb
JM
164#ifdef CONFIG_SHA384
165 } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
166 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
167#endif /* CONFIG_SHA384 */
6fc6879b
JM
168 } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
169 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
170#endif /* CONFIG_IEEE80211R */
56586197
JM
171 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
172 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
173 } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
174 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
c10347f2
JM
175#ifdef CONFIG_SAE
176 } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
177 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
178 } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
179 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
180#endif /* CONFIG_SAE */
5e3b5197
JM
181 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
182 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
666497c8
JM
183 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
184 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
94318a0d
JM
185#ifdef CONFIG_FILS
186 } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
187 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
188 } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
189 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
190#ifdef CONFIG_IEEE80211R
191 } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
192 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
193 } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
194 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
195#endif /* CONFIG_IEEE80211R */
196#endif /* CONFIG_FILS */
a1ea1b45
JM
197#ifdef CONFIG_OWE
198 } else if (key_mgmt & WPA_KEY_MGMT_OWE) {
199 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
200#endif /* CONFIG_OWE */
567da5bb
JM
201#ifdef CONFIG_DPP
202 } else if (key_mgmt & WPA_KEY_MGMT_DPP) {
203 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
204#endif /* CONFIG_DPP */
f5a60216
JM
205#ifdef CONFIG_HS20
206 } else if (key_mgmt & WPA_KEY_MGMT_OSEN) {
207 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
208#endif /* CONFIG_HS20 */
6fc6879b
JM
209 } else {
210 wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
211 key_mgmt);
212 return -1;
213 }
214 pos += RSN_SELECTOR_LEN;
215
216 /* RSN Capabilities */
217 capab = 0;
e820cf95 218 if (sm->mfp)
0b60b0aa 219 capab |= WPA_CAPABILITY_MFPC;
e820cf95
JM
220 if (sm->mfp == 2)
221 capab |= WPA_CAPABILITY_MFPR;
55c12f5d
MV
222 if (sm->ocv)
223 capab |= WPA_CAPABILITY_OCVC;
b17b7a8e
AW
224 if (sm->ext_key_id)
225 capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
6fc6879b
JM
226 WPA_PUT_LE16(pos, capab);
227 pos += 2;
228
229 if (sm->cur_pmksa) {
230 /* PMKID Count (2 octets, little endian) */
231 *pos++ = 1;
232 *pos++ = 0;
233 /* PMKID */
234 os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
235 pos += PMKID_LEN;
236 }
237
8dd9f9cd 238 if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
6fc6879b
JM
239 if (!sm->cur_pmksa) {
240 /* PMKID Count */
241 WPA_PUT_LE16(pos, 0);
242 pos += 2;
243 }
244
245 /* Management Group Cipher Suite */
8dd9f9cd
JM
246 RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
247 mgmt_group_cipher));
6fc6879b
JM
248 pos += RSN_SELECTOR_LEN;
249 }
6fc6879b
JM
250
251 hdr->len = (pos - rsn_ie) - 2;
252
253 WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
254
255 return pos - rsn_ie;
6fc6879b
JM
256}
257
258
df0f01d9
JM
259#ifdef CONFIG_HS20
260static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
261 int pairwise_cipher, int group_cipher,
262 int key_mgmt)
263{
264 u8 *pos, *len;
265 u32 suite;
266
267 if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
268 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
269 return -1;
270
271 pos = wpa_ie;
272 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
273 len = pos++; /* to be filled */
274 WPA_PUT_BE24(pos, OUI_WFA);
275 pos += 3;
276 *pos++ = HS20_OSEN_OUI_TYPE;
277
278 /* Group Data Cipher Suite */
279 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
280 if (suite == 0) {
281 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
282 group_cipher);
283 return -1;
284 }
285 RSN_SELECTOR_PUT(pos, suite);
286 pos += RSN_SELECTOR_LEN;
287
288 /* Pairwise Cipher Suite Count and List */
289 WPA_PUT_LE16(pos, 1);
290 pos += 2;
291 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
292 if (suite == 0 ||
293 (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
294 pairwise_cipher != WPA_CIPHER_NONE)) {
295 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
296 pairwise_cipher);
297 return -1;
298 }
299 RSN_SELECTOR_PUT(pos, suite);
300 pos += RSN_SELECTOR_LEN;
301
302 /* AKM Suite Count and List */
303 WPA_PUT_LE16(pos, 1);
304 pos += 2;
305 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
306 pos += RSN_SELECTOR_LEN;
307
308 *len = pos - len - 1;
309
310 WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
311
312 return pos - wpa_ie;
313}
314#endif /* CONFIG_HS20 */
315
316
6fc6879b
JM
317/**
318 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
319 * @sm: Pointer to WPA state machine data from wpa_sm_init()
320 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
321 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
322 * Returns: Length of the generated WPA/RSN IE or -1 on failure
323 */
324int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
325{
326 if (sm->proto == WPA_PROTO_RSN)
327 return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
328 sm->pairwise_cipher,
329 sm->group_cipher,
330 sm->key_mgmt, sm->mgmt_group_cipher,
331 sm);
df0f01d9
JM
332#ifdef CONFIG_HS20
333 else if (sm->proto == WPA_PROTO_OSEN)
334 return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
335 sm->pairwise_cipher,
336 sm->group_cipher,
337 sm->key_mgmt);
338#endif /* CONFIG_HS20 */
6fc6879b
JM
339 else
340 return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
341 sm->pairwise_cipher,
342 sm->group_cipher,
343 sm->key_mgmt);
344}
345
346
6d6c8877
JM
347int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
348{
349 u8 *pos = rsnxe;
350
351 if (!wpa_key_mgmt_sae(sm->key_mgmt))
352 return 0; /* SAE not in use */
353 if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
354 return 0; /* no supported extended RSN capabilities */
355
356 if (rsnxe_len < 3)
357 return -1;
358
359 *pos++ = WLAN_EID_RSNX;
360 *pos++ = 1;
361 /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
362 * used for now */
363 *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
364
365 return pos - rsnxe;
366}