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