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