wpa_ie.c revision 61d9df3e62aaa0e87ad05452fcb95142159a17b6
1/* 2 * wpa_supplicant - WPA/RSN IE and KDE processing 3 * Copyright (c) 2003-2008, 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 */ 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); 33 else 34 return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); 35} 36 37 38static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, 39 int pairwise_cipher, int group_cipher, 40 int key_mgmt) 41{ 42 u8 *pos; 43 struct wpa_ie_hdr *hdr; 44 45 if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + 46 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) 47 return -1; 48 49 hdr = (struct wpa_ie_hdr *) wpa_ie; 50 hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; 51 RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); 52 WPA_PUT_LE16(hdr->version, WPA_VERSION); 53 pos = (u8 *) (hdr + 1); 54 55 if (group_cipher == WPA_CIPHER_CCMP) { 56 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 57 } else if (group_cipher == WPA_CIPHER_TKIP) { 58 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 59 } else if (group_cipher == WPA_CIPHER_WEP104) { 60 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); 61 } else if (group_cipher == WPA_CIPHER_WEP40) { 62 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); 63 } else { 64 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 65 group_cipher); 66 return -1; 67 } 68 pos += WPA_SELECTOR_LEN; 69 70 *pos++ = 1; 71 *pos++ = 0; 72 if (pairwise_cipher == WPA_CIPHER_CCMP) { 73 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); 74 } else if (pairwise_cipher == WPA_CIPHER_TKIP) { 75 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); 76 } else if (pairwise_cipher == WPA_CIPHER_NONE) { 77 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); 78 } else { 79 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 80 pairwise_cipher); 81 return -1; 82 } 83 pos += WPA_SELECTOR_LEN; 84 85 *pos++ = 1; 86 *pos++ = 0; 87 if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 88 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); 89 } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 90 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); 91 } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { 92 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); 93 } else { 94 wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 95 key_mgmt); 96 return -1; 97 } 98 pos += WPA_SELECTOR_LEN; 99 100 /* WPA Capabilities; use defaults, so no need to include it */ 101 102 hdr->len = (pos - wpa_ie) - 2; 103 104 WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 105 106 return pos - wpa_ie; 107} 108 109 110static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, 111 int pairwise_cipher, int group_cipher, 112 int key_mgmt, int mgmt_group_cipher, 113 struct wpa_sm *sm) 114{ 115#ifndef CONFIG_NO_WPA2 116 u8 *pos; 117 struct rsn_ie_hdr *hdr; 118 u16 capab; 119 120 if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 121 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + 122 (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { 123 wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", 124 (unsigned long) rsn_ie_len); 125 return -1; 126 } 127 128 hdr = (struct rsn_ie_hdr *) rsn_ie; 129 hdr->elem_id = WLAN_EID_RSN; 130 WPA_PUT_LE16(hdr->version, RSN_VERSION); 131 pos = (u8 *) (hdr + 1); 132 133 if (group_cipher == WPA_CIPHER_CCMP) { 134 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 135 } else if (group_cipher == WPA_CIPHER_GCMP) { 136 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); 137 } else if (group_cipher == WPA_CIPHER_TKIP) { 138 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 139 } else if (group_cipher == WPA_CIPHER_WEP104) { 140 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); 141 } else if (group_cipher == WPA_CIPHER_WEP40) { 142 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); 143 } else { 144 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 145 group_cipher); 146 return -1; 147 } 148 pos += RSN_SELECTOR_LEN; 149 150 *pos++ = 1; 151 *pos++ = 0; 152 if (pairwise_cipher == WPA_CIPHER_CCMP) { 153 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 154 } else if (pairwise_cipher == WPA_CIPHER_GCMP) { 155 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); 156 } else if (pairwise_cipher == WPA_CIPHER_TKIP) { 157 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); 158 } else if (pairwise_cipher == WPA_CIPHER_NONE) { 159 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); 160 } else { 161 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 162 pairwise_cipher); 163 return -1; 164 } 165 pos += RSN_SELECTOR_LEN; 166 167 *pos++ = 1; 168 *pos++ = 0; 169 if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 170 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 171 } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 172 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 173#ifdef CONFIG_IEEE80211R 174 } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { 175 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 176 } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { 177 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 178#endif /* CONFIG_IEEE80211R */ 179#ifdef CONFIG_IEEE80211W 180 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { 181 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 182 } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { 183 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 184#endif /* CONFIG_IEEE80211W */ 185 } else { 186 wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 187 key_mgmt); 188 return -1; 189 } 190 pos += RSN_SELECTOR_LEN; 191 192 /* RSN Capabilities */ 193 capab = 0; 194#ifdef CONFIG_IEEE80211W 195 if (sm->mfp) 196 capab |= WPA_CAPABILITY_MFPC; 197 if (sm->mfp == 2) 198 capab |= WPA_CAPABILITY_MFPR; 199#endif /* CONFIG_IEEE80211W */ 200 WPA_PUT_LE16(pos, capab); 201 pos += 2; 202 203 if (sm->cur_pmksa) { 204 /* PMKID Count (2 octets, little endian) */ 205 *pos++ = 1; 206 *pos++ = 0; 207 /* PMKID */ 208 os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); 209 pos += PMKID_LEN; 210 } 211 212#ifdef CONFIG_IEEE80211W 213 if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { 214 if (!sm->cur_pmksa) { 215 /* PMKID Count */ 216 WPA_PUT_LE16(pos, 0); 217 pos += 2; 218 } 219 220 /* Management Group Cipher Suite */ 221 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 222 pos += RSN_SELECTOR_LEN; 223 } 224#endif /* CONFIG_IEEE80211W */ 225 226 hdr->len = (pos - rsn_ie) - 2; 227 228 WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); 229 230 return pos - rsn_ie; 231#else /* CONFIG_NO_WPA2 */ 232 return -1; 233#endif /* CONFIG_NO_WPA2 */ 234} 235 236 237/** 238 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy 239 * @sm: Pointer to WPA state machine data from wpa_sm_init() 240 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE 241 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE 242 * Returns: Length of the generated WPA/RSN IE or -1 on failure 243 */ 244int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) 245{ 246 if (sm->proto == WPA_PROTO_RSN) 247 return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, 248 sm->pairwise_cipher, 249 sm->group_cipher, 250 sm->key_mgmt, sm->mgmt_group_cipher, 251 sm); 252 else 253 return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, 254 sm->pairwise_cipher, 255 sm->group_cipher, 256 sm->key_mgmt); 257} 258 259 260/** 261 * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 262 * @pos: Pointer to the IE header 263 * @end: Pointer to the end of the Key Data buffer 264 * @ie: Pointer to parsed IE data 265 * Returns: 0 on success, 1 if end mark is found, -1 on failure 266 */ 267static int wpa_parse_generic(const u8 *pos, const u8 *end, 268 struct wpa_eapol_ie_parse *ie) 269{ 270 if (pos[1] == 0) 271 return 1; 272 273 if (pos[1] >= 6 && 274 RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 275 pos[2 + WPA_SELECTOR_LEN] == 1 && 276 pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 277 ie->wpa_ie = pos; 278 ie->wpa_ie_len = pos[1] + 2; 279 wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", 280 ie->wpa_ie, ie->wpa_ie_len); 281 return 0; 282 } 283 284 if (pos + 1 + RSN_SELECTOR_LEN < end && 285 pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 286 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 287 ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 288 wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", 289 pos, pos[1] + 2); 290 return 0; 291 } 292 293 if (pos[1] > RSN_SELECTOR_LEN + 2 && 294 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { 295 ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 296 ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 297 wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", 298 pos, pos[1] + 2); 299 return 0; 300 } 301 302 if (pos[1] > RSN_SELECTOR_LEN + 2 && 303 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 304 ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 305 ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 306 wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", 307 pos, pos[1] + 2); 308 return 0; 309 } 310 311#ifdef CONFIG_PEERKEY 312 if (pos[1] > RSN_SELECTOR_LEN + 2 && 313 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 314 ie->smk = pos + 2 + RSN_SELECTOR_LEN; 315 ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 316 wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", 317 pos, pos[1] + 2); 318 return 0; 319 } 320 321 if (pos[1] > RSN_SELECTOR_LEN + 2 && 322 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 323 ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 324 ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 325 wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", 326 pos, pos[1] + 2); 327 return 0; 328 } 329 330 if (pos[1] > RSN_SELECTOR_LEN + 2 && 331 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 332 ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 333 ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 334 wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", 335 pos, pos[1] + 2); 336 return 0; 337 } 338 339 if (pos[1] > RSN_SELECTOR_LEN + 2 && 340 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 341 ie->error = pos + 2 + RSN_SELECTOR_LEN; 342 ie->error_len = pos[1] - RSN_SELECTOR_LEN; 343 wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", 344 pos, pos[1] + 2); 345 return 0; 346 } 347#endif /* CONFIG_PEERKEY */ 348 349#ifdef CONFIG_IEEE80211W 350 if (pos[1] > RSN_SELECTOR_LEN + 2 && 351 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 352 ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 353 ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 354 wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", 355 pos, pos[1] + 2); 356 return 0; 357 } 358#endif /* CONFIG_IEEE80211W */ 359 360 return 0; 361} 362 363 364/** 365 * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs 366 * @buf: Pointer to the Key Data buffer 367 * @len: Key Data Length 368 * @ie: Pointer to parsed IE data 369 * Returns: 0 on success, -1 on failure 370 */ 371int wpa_supplicant_parse_ies(const u8 *buf, size_t len, 372 struct wpa_eapol_ie_parse *ie) 373{ 374 const u8 *pos, *end; 375 int ret = 0; 376 377 os_memset(ie, 0, sizeof(*ie)); 378 for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 379 if (pos[0] == 0xdd && 380 ((pos == buf + len - 1) || pos[1] == 0)) { 381 /* Ignore padding */ 382 break; 383 } 384 if (pos + 2 + pos[1] > end) { 385 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 386 "underflow (ie=%d len=%d pos=%d)", 387 pos[0], pos[1], (int) (pos - buf)); 388 wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 389 buf, len); 390 ret = -1; 391 break; 392 } 393 if (*pos == WLAN_EID_RSN) { 394 ie->rsn_ie = pos; 395 ie->rsn_ie_len = pos[1] + 2; 396 wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", 397 ie->rsn_ie, ie->rsn_ie_len); 398 } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 399 ie->mdie = pos; 400 ie->mdie_len = pos[1] + 2; 401 wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", 402 ie->mdie, ie->mdie_len); 403 } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { 404 ie->ftie = pos; 405 ie->ftie_len = pos[1] + 2; 406 wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", 407 ie->ftie, ie->ftie_len); 408 } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { 409 if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { 410 ie->reassoc_deadline = pos; 411 wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " 412 "in EAPOL-Key", 413 ie->reassoc_deadline, pos[1] + 2); 414 } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { 415 ie->key_lifetime = pos; 416 wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " 417 "in EAPOL-Key", 418 ie->key_lifetime, pos[1] + 2); 419 } else { 420 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " 421 "EAPOL-Key Key Data IE", 422 pos, 2 + pos[1]); 423 } 424 } else if (*pos == WLAN_EID_LINK_ID) { 425 if (pos[1] >= 18) { 426 ie->lnkid = pos; 427 ie->lnkid_len = pos[1] + 2; 428 } 429 } else if (*pos == WLAN_EID_EXT_CAPAB) { 430 ie->ext_capab = pos; 431 ie->ext_capab_len = pos[1] + 2; 432 } else if (*pos == WLAN_EID_SUPP_RATES) { 433 ie->supp_rates = pos; 434 ie->supp_rates_len = pos[1] + 2; 435 } else if (*pos == WLAN_EID_EXT_SUPP_RATES) { 436 ie->ext_supp_rates = pos; 437 ie->ext_supp_rates_len = pos[1] + 2; 438 } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 439 ret = wpa_parse_generic(pos, end, ie); 440 if (ret < 0) 441 break; 442 if (ret > 0) { 443 ret = 0; 444 break; 445 } 446 } else { 447 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 448 "Key Data IE", pos, 2 + pos[1]); 449 } 450 } 451 452 return ret; 453} 454