Home | History | Annotate | Download | only in rsn_supp
      1 /*
      2  * wpa_supplicant - WPA/RSN IE and KDE processing
      3  * Copyright (c) 2003-2008, Jouni Malinen <j (at) 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 {
     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 
     38 static 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 
    110 static 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_TKIP) {
    136 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
    137 	} else if (group_cipher == WPA_CIPHER_WEP104) {
    138 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
    139 	} else if (group_cipher == WPA_CIPHER_WEP40) {
    140 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
    141 	} else {
    142 		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
    143 			   group_cipher);
    144 		return -1;
    145 	}
    146 	pos += RSN_SELECTOR_LEN;
    147 
    148 	*pos++ = 1;
    149 	*pos++ = 0;
    150 	if (pairwise_cipher == WPA_CIPHER_CCMP) {
    151 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
    152 	} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
    153 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
    154 	} else if (pairwise_cipher == WPA_CIPHER_NONE) {
    155 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
    156 	} else {
    157 		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
    158 			   pairwise_cipher);
    159 		return -1;
    160 	}
    161 	pos += RSN_SELECTOR_LEN;
    162 
    163 	*pos++ = 1;
    164 	*pos++ = 0;
    165 	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
    166 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
    167 	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
    168 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
    169 #ifdef CONFIG_IEEE80211R
    170 	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
    171 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
    172 	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
    173 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
    174 #endif /* CONFIG_IEEE80211R */
    175 #ifdef CONFIG_IEEE80211W
    176 	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
    177 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
    178 	} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
    179 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
    180 #endif /* CONFIG_IEEE80211W */
    181 	} else {
    182 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
    183 			   key_mgmt);
    184 		return -1;
    185 	}
    186 	pos += RSN_SELECTOR_LEN;
    187 
    188 	/* RSN Capabilities */
    189 	capab = 0;
    190 #ifdef CONFIG_IEEE80211W
    191 	if (sm->mfp)
    192 		capab |= WPA_CAPABILITY_MFPC;
    193 	if (sm->mfp == 2)
    194 		capab |= WPA_CAPABILITY_MFPR;
    195 #endif /* CONFIG_IEEE80211W */
    196 	WPA_PUT_LE16(pos, capab);
    197 	pos += 2;
    198 
    199 	if (sm->cur_pmksa) {
    200 		/* PMKID Count (2 octets, little endian) */
    201 		*pos++ = 1;
    202 		*pos++ = 0;
    203 		/* PMKID */
    204 		os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
    205 		pos += PMKID_LEN;
    206 	}
    207 
    208 #ifdef CONFIG_IEEE80211W
    209 	if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
    210 		if (!sm->cur_pmksa) {
    211 			/* PMKID Count */
    212 			WPA_PUT_LE16(pos, 0);
    213 			pos += 2;
    214 		}
    215 
    216 		/* Management Group Cipher Suite */
    217 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
    218 		pos += RSN_SELECTOR_LEN;
    219 	}
    220 #endif /* CONFIG_IEEE80211W */
    221 
    222 	hdr->len = (pos - rsn_ie) - 2;
    223 
    224 	WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
    225 
    226 	return pos - rsn_ie;
    227 #else /* CONFIG_NO_WPA2 */
    228 	return -1;
    229 #endif /* CONFIG_NO_WPA2 */
    230 }
    231 
    232 
    233 /**
    234  * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
    235  * @sm: Pointer to WPA state machine data from wpa_sm_init()
    236  * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
    237  * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
    238  * Returns: Length of the generated WPA/RSN IE or -1 on failure
    239  */
    240 int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
    241 {
    242 	if (sm->proto == WPA_PROTO_RSN)
    243 		return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
    244 					  sm->pairwise_cipher,
    245 					  sm->group_cipher,
    246 					  sm->key_mgmt, sm->mgmt_group_cipher,
    247 					  sm);
    248 	else
    249 		return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
    250 					  sm->pairwise_cipher,
    251 					  sm->group_cipher,
    252 					  sm->key_mgmt);
    253 }
    254 
    255 
    256 /**
    257  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
    258  * @pos: Pointer to the IE header
    259  * @end: Pointer to the end of the Key Data buffer
    260  * @ie: Pointer to parsed IE data
    261  * Returns: 0 on success, 1 if end mark is found, -1 on failure
    262  */
    263 static int wpa_parse_generic(const u8 *pos, const u8 *end,
    264 			     struct wpa_eapol_ie_parse *ie)
    265 {
    266 	if (pos[1] == 0)
    267 		return 1;
    268 
    269 	if (pos[1] >= 6 &&
    270 	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
    271 	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
    272 	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
    273 		ie->wpa_ie = pos;
    274 		ie->wpa_ie_len = pos[1] + 2;
    275 		wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
    276 			    ie->wpa_ie, ie->wpa_ie_len);
    277 		return 0;
    278 	}
    279 
    280 	if (pos + 1 + RSN_SELECTOR_LEN < end &&
    281 	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
    282 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
    283 		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
    284 		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
    285 			    pos, pos[1] + 2);
    286 		return 0;
    287 	}
    288 
    289 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    290 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
    291 		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
    292 		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
    293 		wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
    294 				pos, pos[1] + 2);
    295 		return 0;
    296 	}
    297 
    298 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    299 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
    300 		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
    301 		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
    302 		wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
    303 			    pos, pos[1] + 2);
    304 		return 0;
    305 	}
    306 
    307 #ifdef CONFIG_PEERKEY
    308 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    309 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
    310 		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
    311 		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
    312 		wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
    313 				pos, pos[1] + 2);
    314 		return 0;
    315 	}
    316 
    317 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    318 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
    319 		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
    320 		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
    321 		wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
    322 			    pos, pos[1] + 2);
    323 		return 0;
    324 	}
    325 
    326 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    327 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
    328 		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
    329 		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
    330 		wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
    331 			    pos, pos[1] + 2);
    332 		return 0;
    333 	}
    334 
    335 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    336 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
    337 		ie->error = pos + 2 + RSN_SELECTOR_LEN;
    338 		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
    339 		wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
    340 			    pos, pos[1] + 2);
    341 		return 0;
    342 	}
    343 #endif /* CONFIG_PEERKEY */
    344 
    345 #ifdef CONFIG_IEEE80211W
    346 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    347 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
    348 		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
    349 		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
    350 		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
    351 				pos, pos[1] + 2);
    352 		return 0;
    353 	}
    354 #endif /* CONFIG_IEEE80211W */
    355 
    356 	return 0;
    357 }
    358 
    359 
    360 /**
    361  * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
    362  * @buf: Pointer to the Key Data buffer
    363  * @len: Key Data Length
    364  * @ie: Pointer to parsed IE data
    365  * Returns: 0 on success, -1 on failure
    366  */
    367 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
    368 			     struct wpa_eapol_ie_parse *ie)
    369 {
    370 	const u8 *pos, *end;
    371 	int ret = 0;
    372 
    373 	os_memset(ie, 0, sizeof(*ie));
    374 	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
    375 		if (pos[0] == 0xdd &&
    376 		    ((pos == buf + len - 1) || pos[1] == 0)) {
    377 			/* Ignore padding */
    378 			break;
    379 		}
    380 		if (pos + 2 + pos[1] > end) {
    381 			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
    382 				   "underflow (ie=%d len=%d pos=%d)",
    383 				   pos[0], pos[1], (int) (pos - buf));
    384 			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
    385 					buf, len);
    386 			ret = -1;
    387 			break;
    388 		}
    389 		if (*pos == WLAN_EID_RSN) {
    390 			ie->rsn_ie = pos;
    391 			ie->rsn_ie_len = pos[1] + 2;
    392 			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
    393 				    ie->rsn_ie, ie->rsn_ie_len);
    394 		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
    395 			ie->mdie = pos;
    396 			ie->mdie_len = pos[1] + 2;
    397 			wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
    398 				    ie->mdie, ie->mdie_len);
    399 		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
    400 			ie->ftie = pos;
    401 			ie->ftie_len = pos[1] + 2;
    402 			wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
    403 				    ie->ftie, ie->ftie_len);
    404 		} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
    405 			if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
    406 				ie->reassoc_deadline = pos;
    407 				wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
    408 					    "in EAPOL-Key",
    409 					    ie->reassoc_deadline, pos[1] + 2);
    410 			} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
    411 				ie->key_lifetime = pos;
    412 				wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
    413 					    "in EAPOL-Key",
    414 					    ie->key_lifetime, pos[1] + 2);
    415 			} else {
    416 				wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
    417 					    "EAPOL-Key Key Data IE",
    418 					    pos, 2 + pos[1]);
    419 			}
    420 		} else if (*pos == WLAN_EID_LINK_ID) {
    421 			if (pos[1] >= 18) {
    422 				ie->lnkid = pos;
    423 				ie->lnkid_len = pos[1] + 2;
    424 			}
    425 		} else if (*pos == WLAN_EID_EXT_CAPAB) {
    426 			ie->ext_capab = pos;
    427 			ie->ext_capab_len = pos[1] + 2;
    428 		} else if (*pos == WLAN_EID_SUPP_RATES) {
    429 			ie->supp_rates = pos;
    430 			ie->supp_rates_len = pos[1] + 2;
    431 		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
    432 			ie->ext_supp_rates = pos;
    433 			ie->ext_supp_rates_len = pos[1] + 2;
    434 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
    435 			ret = wpa_parse_generic(pos, end, ie);
    436 			if (ret < 0)
    437 				break;
    438 			if (ret > 0) {
    439 				ret = 0;
    440 				break;
    441 			}
    442 		} else {
    443 			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
    444 				    "Key Data IE", pos, 2 + pos[1]);
    445 		}
    446 	}
    447 
    448 	return ret;
    449 }
    450