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