2 * wpa_supplicant - WPA/RSN IE and KDE processing
3 * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
13 #include "pmksa_cache.h"
14 #include "common/ieee802_11_defs.h"
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
26 * Parse the contents of WPA or RSN IE and write the parsed data into data.
28 int wpa_parse_wpa_ie(const u8
*wpa_ie
, size_t wpa_ie_len
,
29 struct wpa_ie_data
*data
)
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
);
34 return wpa_parse_wpa_ie_wpa(wpa_ie
, wpa_ie_len
, data
);
38 static int wpa_gen_wpa_ie_wpa(u8
*wpa_ie
, size_t wpa_ie_len
,
39 int pairwise_cipher
, int group_cipher
,
43 struct wpa_ie_hdr
*hdr
;
46 if (wpa_ie_len
< sizeof(*hdr
) + WPA_SELECTOR_LEN
+
47 2 + WPA_SELECTOR_LEN
+ 2 + WPA_SELECTOR_LEN
)
50 hdr
= (struct wpa_ie_hdr
*) wpa_ie
;
51 hdr
->elem_id
= WLAN_EID_VENDOR_SPECIFIC
;
52 RSN_SELECTOR_PUT(hdr
->oui
, WPA_OUI_TYPE
);
53 WPA_PUT_LE16(hdr
->version
, WPA_VERSION
);
54 pos
= (u8
*) (hdr
+ 1);
56 suite
= wpa_cipher_to_suite(WPA_PROTO_WPA
, group_cipher
);
58 wpa_printf(MSG_WARNING
, "Invalid group cipher (%d).",
62 RSN_SELECTOR_PUT(pos
, suite
);
63 pos
+= WPA_SELECTOR_LEN
;
67 suite
= wpa_cipher_to_suite(WPA_PROTO_WPA
, pairwise_cipher
);
69 (!wpa_cipher_valid_pairwise(pairwise_cipher
) &&
70 pairwise_cipher
!= WPA_CIPHER_NONE
)) {
71 wpa_printf(MSG_WARNING
, "Invalid pairwise cipher (%d).",
75 RSN_SELECTOR_PUT(pos
, suite
);
76 pos
+= WPA_SELECTOR_LEN
;
80 if (key_mgmt
== WPA_KEY_MGMT_IEEE8021X
) {
81 RSN_SELECTOR_PUT(pos
, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X
);
82 } else if (key_mgmt
== WPA_KEY_MGMT_PSK
) {
83 RSN_SELECTOR_PUT(pos
, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X
);
84 } else if (key_mgmt
== WPA_KEY_MGMT_WPA_NONE
) {
85 RSN_SELECTOR_PUT(pos
, WPA_AUTH_KEY_MGMT_NONE
);
86 } else if (key_mgmt
== WPA_KEY_MGMT_CCKM
) {
87 RSN_SELECTOR_PUT(pos
, WPA_AUTH_KEY_MGMT_CCKM
);
89 wpa_printf(MSG_WARNING
, "Invalid key management type (%d).",
93 pos
+= WPA_SELECTOR_LEN
;
95 /* WPA Capabilities; use defaults, so no need to include it */
97 hdr
->len
= (pos
- wpa_ie
) - 2;
99 WPA_ASSERT((size_t) (pos
- wpa_ie
) <= wpa_ie_len
);
105 static int wpa_gen_wpa_ie_rsn(u8
*rsn_ie
, size_t rsn_ie_len
,
106 int pairwise_cipher
, int group_cipher
,
107 int key_mgmt
, int mgmt_group_cipher
,
111 struct rsn_ie_hdr
*hdr
;
115 if (rsn_ie_len
< sizeof(*hdr
) + RSN_SELECTOR_LEN
+
116 2 + RSN_SELECTOR_LEN
+ 2 + RSN_SELECTOR_LEN
+ 2 +
117 (sm
->cur_pmksa
? 2 + PMKID_LEN
: 0)) {
118 wpa_printf(MSG_DEBUG
, "RSN: Too short IE buffer (%lu bytes)",
119 (unsigned long) rsn_ie_len
);
123 hdr
= (struct rsn_ie_hdr
*) rsn_ie
;
124 hdr
->elem_id
= WLAN_EID_RSN
;
125 WPA_PUT_LE16(hdr
->version
, RSN_VERSION
);
126 pos
= (u8
*) (hdr
+ 1);
128 suite
= wpa_cipher_to_suite(WPA_PROTO_RSN
, group_cipher
);
130 wpa_printf(MSG_WARNING
, "Invalid group cipher (%d).",
134 RSN_SELECTOR_PUT(pos
, suite
);
135 pos
+= RSN_SELECTOR_LEN
;
139 suite
= wpa_cipher_to_suite(WPA_PROTO_RSN
, pairwise_cipher
);
141 (!wpa_cipher_valid_pairwise(pairwise_cipher
) &&
142 pairwise_cipher
!= WPA_CIPHER_NONE
)) {
143 wpa_printf(MSG_WARNING
, "Invalid pairwise cipher (%d).",
147 RSN_SELECTOR_PUT(pos
, suite
);
148 pos
+= RSN_SELECTOR_LEN
;
152 if (key_mgmt
== WPA_KEY_MGMT_IEEE8021X
) {
153 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X
);
154 } else if (key_mgmt
== WPA_KEY_MGMT_PSK
) {
155 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X
);
156 } else if (key_mgmt
== WPA_KEY_MGMT_CCKM
) {
157 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_CCKM
);
158 #ifdef CONFIG_IEEE80211R
159 } else if (key_mgmt
== WPA_KEY_MGMT_FT_IEEE8021X
) {
160 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_FT_802_1X
);
161 } else if (key_mgmt
== WPA_KEY_MGMT_FT_PSK
) {
162 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_FT_PSK
);
163 #endif /* CONFIG_IEEE80211R */
164 #ifdef CONFIG_IEEE80211W
165 } else if (key_mgmt
== WPA_KEY_MGMT_IEEE8021X_SHA256
) {
166 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_802_1X_SHA256
);
167 } else if (key_mgmt
== WPA_KEY_MGMT_PSK_SHA256
) {
168 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_PSK_SHA256
);
169 #endif /* CONFIG_IEEE80211W */
171 } else if (key_mgmt
== WPA_KEY_MGMT_SAE
) {
172 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_SAE
);
173 } else if (key_mgmt
== WPA_KEY_MGMT_FT_SAE
) {
174 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_FT_SAE
);
175 #endif /* CONFIG_SAE */
177 wpa_printf(MSG_WARNING
, "Invalid key management type (%d).",
181 pos
+= RSN_SELECTOR_LEN
;
183 /* RSN Capabilities */
185 #ifdef CONFIG_IEEE80211W
187 capab
|= WPA_CAPABILITY_MFPC
;
189 capab
|= WPA_CAPABILITY_MFPR
;
190 #endif /* CONFIG_IEEE80211W */
191 WPA_PUT_LE16(pos
, capab
);
195 /* PMKID Count (2 octets, little endian) */
199 os_memcpy(pos
, sm
->cur_pmksa
->pmkid
, PMKID_LEN
);
203 #ifdef CONFIG_IEEE80211W
204 if (mgmt_group_cipher
== WPA_CIPHER_AES_128_CMAC
) {
205 if (!sm
->cur_pmksa
) {
207 WPA_PUT_LE16(pos
, 0);
211 /* Management Group Cipher Suite */
212 RSN_SELECTOR_PUT(pos
, RSN_CIPHER_SUITE_AES_128_CMAC
);
213 pos
+= RSN_SELECTOR_LEN
;
215 #endif /* CONFIG_IEEE80211W */
217 hdr
->len
= (pos
- rsn_ie
) - 2;
219 WPA_ASSERT((size_t) (pos
- rsn_ie
) <= rsn_ie_len
);
226 static int wpa_gen_wpa_ie_osen(u8
*wpa_ie
, size_t wpa_ie_len
,
227 int pairwise_cipher
, int group_cipher
,
233 if (wpa_ie_len
< 2 + 4 + RSN_SELECTOR_LEN
+
234 2 + RSN_SELECTOR_LEN
+ 2 + RSN_SELECTOR_LEN
)
238 *pos
++ = WLAN_EID_VENDOR_SPECIFIC
;
239 len
= pos
++; /* to be filled */
240 WPA_PUT_BE24(pos
, OUI_WFA
);
242 *pos
++ = HS20_OSEN_OUI_TYPE
;
244 /* Group Data Cipher Suite */
245 suite
= wpa_cipher_to_suite(WPA_PROTO_RSN
, group_cipher
);
247 wpa_printf(MSG_WARNING
, "Invalid group cipher (%d).",
251 RSN_SELECTOR_PUT(pos
, suite
);
252 pos
+= RSN_SELECTOR_LEN
;
254 /* Pairwise Cipher Suite Count and List */
255 WPA_PUT_LE16(pos
, 1);
257 suite
= wpa_cipher_to_suite(WPA_PROTO_RSN
, pairwise_cipher
);
259 (!wpa_cipher_valid_pairwise(pairwise_cipher
) &&
260 pairwise_cipher
!= WPA_CIPHER_NONE
)) {
261 wpa_printf(MSG_WARNING
, "Invalid pairwise cipher (%d).",
265 RSN_SELECTOR_PUT(pos
, suite
);
266 pos
+= RSN_SELECTOR_LEN
;
268 /* AKM Suite Count and List */
269 WPA_PUT_LE16(pos
, 1);
271 RSN_SELECTOR_PUT(pos
, RSN_AUTH_KEY_MGMT_OSEN
);
272 pos
+= RSN_SELECTOR_LEN
;
274 *len
= pos
- len
- 1;
276 WPA_ASSERT((size_t) (pos
- wpa_ie
) <= wpa_ie_len
);
280 #endif /* CONFIG_HS20 */
284 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
285 * @sm: Pointer to WPA state machine data from wpa_sm_init()
286 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
287 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
288 * Returns: Length of the generated WPA/RSN IE or -1 on failure
290 int wpa_gen_wpa_ie(struct wpa_sm
*sm
, u8
*wpa_ie
, size_t wpa_ie_len
)
292 if (sm
->proto
== WPA_PROTO_RSN
)
293 return wpa_gen_wpa_ie_rsn(wpa_ie
, wpa_ie_len
,
296 sm
->key_mgmt
, sm
->mgmt_group_cipher
,
299 else if (sm
->proto
== WPA_PROTO_OSEN
)
300 return wpa_gen_wpa_ie_osen(wpa_ie
, wpa_ie_len
,
304 #endif /* CONFIG_HS20 */
306 return wpa_gen_wpa_ie_wpa(wpa_ie
, wpa_ie_len
,
314 * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
315 * @pos: Pointer to the IE header
316 * @end: Pointer to the end of the Key Data buffer
317 * @ie: Pointer to parsed IE data
318 * Returns: 0 on success, 1 if end mark is found, -1 on failure
320 static int wpa_parse_generic(const u8
*pos
, const u8
*end
,
321 struct wpa_eapol_ie_parse
*ie
)
327 RSN_SELECTOR_GET(pos
+ 2) == WPA_OUI_TYPE
&&
328 pos
[2 + WPA_SELECTOR_LEN
] == 1 &&
329 pos
[2 + WPA_SELECTOR_LEN
+ 1] == 0) {
331 ie
->wpa_ie_len
= pos
[1] + 2;
332 wpa_hexdump(MSG_DEBUG
, "WPA: WPA IE in EAPOL-Key",
333 ie
->wpa_ie
, ie
->wpa_ie_len
);
337 if (pos
+ 1 + RSN_SELECTOR_LEN
< end
&&
338 pos
[1] >= RSN_SELECTOR_LEN
+ PMKID_LEN
&&
339 RSN_SELECTOR_GET(pos
+ 2) == RSN_KEY_DATA_PMKID
) {
340 ie
->pmkid
= pos
+ 2 + RSN_SELECTOR_LEN
;
341 wpa_hexdump(MSG_DEBUG
, "WPA: PMKID in EAPOL-Key",
346 if (pos
[1] > RSN_SELECTOR_LEN
+ 2 &&
347 RSN_SELECTOR_GET(pos
+ 2) == RSN_KEY_DATA_GROUPKEY
) {
348 ie
->gtk
= pos
+ 2 + RSN_SELECTOR_LEN
;
349 ie
->gtk_len
= pos
[1] - RSN_SELECTOR_LEN
;
350 wpa_hexdump_key(MSG_DEBUG
, "WPA: GTK in EAPOL-Key",
355 if (pos
[1] > RSN_SELECTOR_LEN
+ 2 &&
356 RSN_SELECTOR_GET(pos
+ 2) == RSN_KEY_DATA_MAC_ADDR
) {
357 ie
->mac_addr
= pos
+ 2 + RSN_SELECTOR_LEN
;
358 ie
->mac_addr_len
= pos
[1] - RSN_SELECTOR_LEN
;
359 wpa_hexdump(MSG_DEBUG
, "WPA: MAC Address in EAPOL-Key",
364 #ifdef CONFIG_PEERKEY
365 if (pos
[1] > RSN_SELECTOR_LEN
+ 2 &&
366 RSN_SELECTOR_GET(pos
+ 2) == RSN_KEY_DATA_SMK
) {
367 ie
->smk
= pos
+ 2 + RSN_SELECTOR_LEN
;
368 ie
->smk_len
= pos
[1] - RSN_SELECTOR_LEN
;
369 wpa_hexdump_key(MSG_DEBUG
, "WPA: SMK in EAPOL-Key",
374 if (pos
[1] > RSN_SELECTOR_LEN
+ 2 &&
375 RSN_SELECTOR_GET(pos
+ 2) == RSN_KEY_DATA_NONCE
) {
376 ie
->nonce
= pos
+ 2 + RSN_SELECTOR_LEN
;
377 ie
->nonce_len
= pos
[1] - RSN_SELECTOR_LEN
;
378 wpa_hexdump(MSG_DEBUG
, "WPA: Nonce in EAPOL-Key",
383 if (pos
[1] > RSN_SELECTOR_LEN
+ 2 &&
384 RSN_SELECTOR_GET(pos
+ 2) == RSN_KEY_DATA_LIFETIME
) {
385 ie
->lifetime
= pos
+ 2 + RSN_SELECTOR_LEN
;
386 ie
->lifetime_len
= pos
[1] - RSN_SELECTOR_LEN
;
387 wpa_hexdump(MSG_DEBUG
, "WPA: Lifetime in EAPOL-Key",
392 if (pos
[1] > RSN_SELECTOR_LEN
+ 2 &&
393 RSN_SELECTOR_GET(pos
+ 2) == RSN_KEY_DATA_ERROR
) {
394 ie
->error
= pos
+ 2 + RSN_SELECTOR_LEN
;
395 ie
->error_len
= pos
[1] - RSN_SELECTOR_LEN
;
396 wpa_hexdump(MSG_DEBUG
, "WPA: Error in EAPOL-Key",
400 #endif /* CONFIG_PEERKEY */
402 #ifdef CONFIG_IEEE80211W
403 if (pos
[1] > RSN_SELECTOR_LEN
+ 2 &&
404 RSN_SELECTOR_GET(pos
+ 2) == RSN_KEY_DATA_IGTK
) {
405 ie
->igtk
= pos
+ 2 + RSN_SELECTOR_LEN
;
406 ie
->igtk_len
= pos
[1] - RSN_SELECTOR_LEN
;
407 wpa_hexdump_key(MSG_DEBUG
, "WPA: IGTK in EAPOL-Key",
411 #endif /* CONFIG_IEEE80211W */
414 if (pos
[1] >= RSN_SELECTOR_LEN
+ 1 &&
415 RSN_SELECTOR_GET(pos
+ 2) == WFA_KEY_DATA_IP_ADDR_REQ
) {
416 ie
->ip_addr_req
= pos
+ 2 + RSN_SELECTOR_LEN
;
417 wpa_hexdump(MSG_DEBUG
, "WPA: IP Address Request in EAPOL-Key",
418 ie
->ip_addr_req
, pos
[1] - RSN_SELECTOR_LEN
);
422 if (pos
[1] >= RSN_SELECTOR_LEN
+ 3 * 4 &&
423 RSN_SELECTOR_GET(pos
+ 2) == WFA_KEY_DATA_IP_ADDR_ALLOC
) {
424 ie
->ip_addr_alloc
= pos
+ 2 + RSN_SELECTOR_LEN
;
425 wpa_hexdump(MSG_DEBUG
,
426 "WPA: IP Address Allocation in EAPOL-Key",
427 ie
->ip_addr_alloc
, pos
[1] - RSN_SELECTOR_LEN
);
430 #endif /* CONFIG_P2P */
437 * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
438 * @buf: Pointer to the Key Data buffer
439 * @len: Key Data Length
440 * @ie: Pointer to parsed IE data
441 * Returns: 0 on success, -1 on failure
443 int wpa_supplicant_parse_ies(const u8
*buf
, size_t len
,
444 struct wpa_eapol_ie_parse
*ie
)
449 os_memset(ie
, 0, sizeof(*ie
));
450 for (pos
= buf
, end
= pos
+ len
; pos
+ 1 < end
; pos
+= 2 + pos
[1]) {
451 if (pos
[0] == 0xdd &&
452 ((pos
== buf
+ len
- 1) || pos
[1] == 0)) {
456 if (pos
+ 2 + pos
[1] > end
) {
457 wpa_printf(MSG_DEBUG
, "WPA: EAPOL-Key Key Data "
458 "underflow (ie=%d len=%d pos=%d)",
459 pos
[0], pos
[1], (int) (pos
- buf
));
460 wpa_hexdump_key(MSG_DEBUG
, "WPA: Key Data",
465 if (*pos
== WLAN_EID_RSN
) {
467 ie
->rsn_ie_len
= pos
[1] + 2;
468 wpa_hexdump(MSG_DEBUG
, "WPA: RSN IE in EAPOL-Key",
469 ie
->rsn_ie
, ie
->rsn_ie_len
);
470 } else if (*pos
== WLAN_EID_MOBILITY_DOMAIN
) {
472 ie
->mdie_len
= pos
[1] + 2;
473 wpa_hexdump(MSG_DEBUG
, "WPA: MDIE in EAPOL-Key",
474 ie
->mdie
, ie
->mdie_len
);
475 } else if (*pos
== WLAN_EID_FAST_BSS_TRANSITION
) {
477 ie
->ftie_len
= pos
[1] + 2;
478 wpa_hexdump(MSG_DEBUG
, "WPA: FTIE in EAPOL-Key",
479 ie
->ftie
, ie
->ftie_len
);
480 } else if (*pos
== WLAN_EID_TIMEOUT_INTERVAL
&& pos
[1] >= 5) {
481 if (pos
[2] == WLAN_TIMEOUT_REASSOC_DEADLINE
) {
482 ie
->reassoc_deadline
= pos
;
483 wpa_hexdump(MSG_DEBUG
, "WPA: Reassoc Deadline "
485 ie
->reassoc_deadline
, pos
[1] + 2);
486 } else if (pos
[2] == WLAN_TIMEOUT_KEY_LIFETIME
) {
487 ie
->key_lifetime
= pos
;
488 wpa_hexdump(MSG_DEBUG
, "WPA: KeyLifetime "
490 ie
->key_lifetime
, pos
[1] + 2);
492 wpa_hexdump(MSG_DEBUG
, "WPA: Unrecognized "
493 "EAPOL-Key Key Data IE",
496 } else if (*pos
== WLAN_EID_LINK_ID
) {
499 ie
->lnkid_len
= pos
[1] + 2;
501 } else if (*pos
== WLAN_EID_EXT_CAPAB
) {
503 ie
->ext_capab_len
= pos
[1] + 2;
504 } else if (*pos
== WLAN_EID_SUPP_RATES
) {
505 ie
->supp_rates
= pos
;
506 ie
->supp_rates_len
= pos
[1] + 2;
507 } else if (*pos
== WLAN_EID_EXT_SUPP_RATES
) {
508 ie
->ext_supp_rates
= pos
;
509 ie
->ext_supp_rates_len
= pos
[1] + 2;
510 } else if (*pos
== WLAN_EID_HT_CAP
) {
511 ie
->ht_capabilities
= pos
+ 2;
512 ie
->ht_capabilities_len
= pos
[1];
513 } else if (*pos
== WLAN_EID_VHT_AID
) {
515 ie
->aid
= WPA_GET_LE16(pos
+ 2);
516 } else if (*pos
== WLAN_EID_VHT_CAP
) {
517 ie
->vht_capabilities
= pos
+ 2;
518 ie
->vht_capabilities_len
= pos
[1];
519 } else if (*pos
== WLAN_EID_QOS
&& pos
[1] >= 1) {
520 ie
->qosinfo
= pos
[2];
521 } else if (*pos
== WLAN_EID_SUPPORTED_CHANNELS
) {
522 ie
->supp_channels
= pos
+ 2;
523 ie
->supp_channels_len
= pos
[1];
524 } else if (*pos
== WLAN_EID_SUPPORTED_OPERATING_CLASSES
) {
526 * The value of the Length field of the Supported
527 * Operating Classes element is between 2 and 253.
528 * Silently skip invalid elements to avoid interop
529 * issues when trying to use the value.
531 if (pos
[1] >= 2 && pos
[1] <= 253) {
532 ie
->supp_oper_classes
= pos
+ 2;
533 ie
->supp_oper_classes_len
= pos
[1];
535 } else if (*pos
== WLAN_EID_VENDOR_SPECIFIC
) {
536 ret
= wpa_parse_generic(pos
, end
, ie
);
544 wpa_hexdump(MSG_DEBUG
, "WPA: Unrecognized EAPOL-Key "
545 "Key Data IE", pos
, 2 + pos
[1]);