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