int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len) { if (ie1 == NULL || ie2 == NULL) return -1; if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) return 0; /* identical IEs */ #ifdef CONFIG_IEEE80211R if (ft_initial_assoc) { struct wpa_ie_data ie1d, ie2d; /* * The PMKID-List in RSN IE is different between Beacon/Probe * Response/(Re)Association Request frames and EAPOL-Key * messages in FT initial mobility domain association. Allow * for this, but verify that other parts of the RSN IEs are * identical. */ if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) return -1; if (ie1d.proto == ie2d.proto && ie1d.pairwise_cipher == ie2d.pairwise_cipher && ie1d.group_cipher == ie2d.group_cipher && ie1d.key_mgmt == ie2d.key_mgmt && ie1d.capabilities == ie2d.capabilities && ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) return 0; } #endif /* CONFIG_IEEE80211R */ return -1; }
/** * wpa_parse_wpa_ie - Parse WPA/RSN IE * @wpa_ie: Pointer to WPA or RSN IE * @wpa_ie_len: Length of the WPA/RSN IE * @data: Pointer to data area for parsing results * Returns: 0 on success, -1 on failure * * Parse the contents of WPA or RSN IE and write the parsed data into data. */ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data) { if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC && wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE) return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); else return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); }
static int ft_validate_rsnie(struct wpa_sm *sm, const unsigned char *src_addr, struct wpa_eapol_ie_parse *ie) { struct wpa_ie_data rsn; if (!ie->rsn_ie) return 0; /* * Verify that PMKR1Name from EAPOL-Key message 3/4 * matches with the value we derived. */ if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 || rsn.num_pmkid != 1 || rsn.pmkid == NULL) { wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in " "FT 4-way handshake message 3/4"); return -1; } if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: PMKR1Name mismatch in " "FT 4-way handshake message 3/4"); wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator", rsn.pmkid, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", sm->pmk_r1_name, WPA_PMK_NAME_LEN); return -1; } return 0; }
/** * wpa_parse_wpa_ie - Parse WPA/RSN IE * @wpa_ie: Pointer to WPA or RSN IE * @wpa_ie_len: Length of the WPA/RSN IE * @data: Pointer to data area for parsing results * Returns: 0 on success, -1 on failure * * Parse the contents of WPA or RSN IE and write the parsed data into data. */ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data) { if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); else return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); }
/** * wpa_parse_wpa_ie - Parse WPA/RSN IE * @wpa_ie: Pointer to WPA or RSN IE * @wpa_ie_len: Length of the WPA/RSN IE * @data: Pointer to data area for parsing results * Returns: 0 on success, -1 on failure * * Parse the contents of WPA or RSN IE and write the parsed data into data. */ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data) { if (wpa_ie_len >= 1 && wpa_ie[0] == RSN_INFO_ELEM) return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); else return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); }
static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, int ver, struct wpa_peerkey *peerkey, struct wpa_eapol_ie_parse *kde) { int cipher; struct wpa_ie_data ie; wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")", MAC2STR(kde->mac_addr)); if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN || wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) { wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5"); /* TODO: abort negotiation */ return -1; } if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) { wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does " "not match with INonce used in SMK M1"); return -1; } if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0) { wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not " "match with the one used in SMK M1"); return -1; } os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len); peerkey->rsnie_p_len = kde->rsn_ie_len; os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN); cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; if (cipher & WPA_CIPHER_CCMP) { wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); peerkey->cipher = WPA_CIPHER_CCMP; } else if (cipher & WPA_CIPHER_TKIP) { wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); peerkey->cipher = WPA_CIPHER_TKIP; } else { wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected " "unacceptable cipher", MAC2STR(kde->mac_addr)); wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr, STK_MUI_SMK, STK_ERR_CPHR_NS, ver); /* TODO: abort negotiation */ return -1; } return 0; }
static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse) { const u8 *end, *pos; struct wpa_ie_data data; int ret; os_memset(parse, 0, sizeof(*parse)); if (ies == NULL) return 0; pos = ies; end = ies + ies_len; while (pos + 2 <= end && pos + 2 + pos[1] <= end) { switch (pos[0]) { case WLAN_EID_RSN: parse->rsn = pos + 2; parse->rsn_len = pos[1]; ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, parse->rsn_len + 2, &data); if (ret < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to parse " "RSN IE: %d", ret); return -1; } if (data.num_pmkid == 1 && data.pmkid) parse->rsn_pmkid = data.pmkid; break; case WLAN_EID_MOBILITY_DOMAIN: parse->mdie = pos + 2; parse->mdie_len = pos[1]; break; case WLAN_EID_FAST_BSS_TRANSITION: if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) return -1; break; case WLAN_EID_TIMEOUT_INTERVAL: parse->tie = pos + 2; parse->tie_len = pos[1]; break; } pos += 2 + pos[1]; } return 0; }
static int rsn_ie_parse_tests(void) { int i, ret = 0; wpa_printf(MSG_INFO, "rsn_ie_parse tests"); for (i = 0; rsn_parse_tests[i].data; i++) { const struct rsn_ie_parse_test_data *test; struct wpa_ie_data data; test = &rsn_parse_tests[i]; if (wpa_parse_wpa_ie_rsn(test->data, test->len, &data) != test->result) { wpa_printf(MSG_ERROR, "rsn_ie_parse test %d failed", i); ret = -1; } } return ret; }
static int wpa_supplicant_process_smk_m2( struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, size_t extra_len, int ver) { struct wpa_peerkey *peerkey; struct wpa_eapol_ie_parse kde; struct wpa_ie_data ie; int cipher; struct rsn_ie_hdr *hdr; u8 *pos; wpa_printf(MSG_DEBUG, "RSN: Received SMK M2"); if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for " "the current network"); return -1; } if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2"); return -1; } if (kde.rsn_ie == NULL || kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN) { wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " "SMK M2"); return -1; } wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR, MAC2STR(kde.mac_addr)); if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) { wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK " "M2"); return -1; } if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2"); return -1; } cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; if (cipher & WPA_CIPHER_CCMP) { wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); cipher = WPA_CIPHER_CCMP; } else if (cipher & WPA_CIPHER_TKIP) { wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); cipher = WPA_CIPHER_TKIP; } else { wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2"); wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr, STK_MUI_SMK, STK_ERR_CPHR_NS, ver); return -1; } /* TODO: find existing entry and if found, use that instead of adding * a new one; how to handle the case where both ends initiate at the * same time? */ peerkey = os_zalloc(sizeof(*peerkey)); if (peerkey == NULL) return -1; os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN); os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); peerkey->rsnie_i_len = kde.rsn_ie_len; peerkey->cipher = cipher; #ifdef CONFIG_IEEE80211W if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_PSK_SHA256)) peerkey->use_sha256 = 1; #endif /* CONFIG_IEEE80211W */ if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for PNonce"); wpa_supplicant_peerkey_free(sm, peerkey); return -1; } hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); /* Group Suite can be anything for SMK RSN IE; receiver will just * ignore it. */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; /* Include only the selected cipher in pairwise cipher suite */ WPA_PUT_LE16(pos, 1); pos += 2; if (cipher == WPA_CIPHER_CCMP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); else if (cipher == WPA_CIPHER_TKIP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; hdr->len = (pos - peerkey->rsnie_p) - 2; peerkey->rsnie_p_len = pos - peerkey->rsnie_p; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", peerkey->rsnie_p, peerkey->rsnie_p_len); wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey); peerkey->next = sm->peerkey; sm->peerkey = peerkey; return 0; }
/** * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1) * @sm: Pointer to WPA state machine data from wpa_sm_init() * @peer: MAC address of the peer STA * Returns: 0 on success, or -1 on failure * * Send an EAPOL-Key Request to the current authenticator to start STK * handshake with the peer. */ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) { size_t rlen, kde_len; struct wpa_eapol_key *req; int key_info, ver; u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos; u16 count; struct rsn_ie_hdr *hdr; struct wpa_peerkey *peerkey; struct wpa_ie_data ie; if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled) return -1; if (sm->ap_rsn_ie && wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 && !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) { wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK"); return -1; } if (sm->pairwise_cipher == WPA_CIPHER_CCMP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; if (wpa_sm_get_bssid(sm, bssid) < 0) { wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key " "SMK M1"); return -1; } /* TODO: find existing entry and if found, use that instead of adding * a new one */ peerkey = os_zalloc(sizeof(*peerkey)); if (peerkey == NULL) return -1; peerkey->initiator = 1; os_memcpy(peerkey->addr, peer, ETH_ALEN); #ifdef CONFIG_IEEE80211W if (wpa_key_mgmt_sha256(sm->key_mgmt)) peerkey->use_sha256 = 1; #endif /* CONFIG_IEEE80211W */ /* SMK M1: * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, * MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE)) */ hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); /* Group Suite can be anything for SMK RSN IE; receiver will just * ignore it. */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; count_pos = pos; pos += 2; count = 0; if (sm->allowed_pairwise_cipher & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; count++; } if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; count++; } WPA_PUT_LE16(count_pos, count); hdr->len = (pos - peerkey->rsnie_i) - 2; peerkey->rsnie_i_len = pos - peerkey->rsnie_i; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", peerkey->rsnie_i, peerkey->rsnie_i_len); kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, sizeof(*req) + kde_len, &rlen, (void *) &req); if (rbuf == NULL) { wpa_supplicant_peerkey_free(sm, peerkey); return -1; } req->type = EAPOL_KEY_TYPE_RSN; key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver; WPA_PUT_BE16(req->key_info, key_info); WPA_PUT_BE16(req->key_length, 0); os_memcpy(req->replay_counter, sm->request_counter, WPA_REPLAY_COUNTER_LEN); inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for INonce"); os_free(rbuf); wpa_supplicant_peerkey_free(sm, peerkey); return -1; } os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake", req->key_nonce, WPA_NONCE_LEN); WPA_PUT_BE16(req->key_data_length, (u16) kde_len); pos = (u8 *) (req + 1); /* Initiator RSN IE */ pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); /* Peer MAC address KDE */ wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer " MACSTR ")", MAC2STR(peer)); wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, rbuf, rlen, req->key_mic); peerkey->next = sm->peerkey; sm->peerkey = peerkey; return 0; }
void sta_update_assoc(struct wlantest_sta *sta, struct ieee802_11_elems *elems) { struct wpa_ie_data data; struct wlantest_bss *bss = sta->bss; if (elems->wpa_ie && !bss->wpaie[0]) { wpa_printf(MSG_INFO, "WPA IE included in Association Request " "frame from " MACSTR " even though BSS does not " "use WPA - ignore IE", MAC2STR(sta->addr)); elems->wpa_ie = NULL; } if (elems->rsn_ie && !bss->rsnie[0]) { wpa_printf(MSG_INFO, "RSN IE included in Association Request " "frame from " MACSTR " even though BSS does not " "use RSN - ignore IE", MAC2STR(sta->addr)); elems->rsn_ie = NULL; } if (elems->wpa_ie && elems->rsn_ie) { wpa_printf(MSG_INFO, "Both WPA IE and RSN IE included in " "Association Request frame from " MACSTR, MAC2STR(sta->addr)); } if (elems->rsn_ie) { wpa_hexdump(MSG_DEBUG, "RSN IE", elems->rsn_ie - 2, elems->rsn_ie_len + 2); os_memcpy(sta->rsnie, elems->rsn_ie - 2, elems->rsn_ie_len + 2); if (wpa_parse_wpa_ie_rsn(sta->rsnie, 2 + sta->rsnie[1], &data) < 0) { wpa_printf(MSG_INFO, "Failed to parse RSN IE from " MACSTR, MAC2STR(sta->addr)); } } else if (elems->wpa_ie) { wpa_hexdump(MSG_DEBUG, "WPA IE", elems->wpa_ie - 2, elems->wpa_ie_len + 2); os_memcpy(sta->rsnie, elems->wpa_ie - 2, elems->wpa_ie_len + 2); if (wpa_parse_wpa_ie_wpa(sta->rsnie, 2 + sta->rsnie[1], &data) < 0) { wpa_printf(MSG_INFO, "Failed to parse WPA IE from " MACSTR, MAC2STR(sta->addr)); } } else { sta->rsnie[0] = 0; sta->proto = 0; sta->pairwise_cipher = 0; sta->key_mgmt = 0; sta->rsn_capab = 0; if (sta->assocreq_capab_info & WLAN_CAPABILITY_PRIVACY) sta->pairwise_cipher = WPA_CIPHER_WEP40; goto skip_rsn_wpa; } sta->proto = data.proto; sta->pairwise_cipher = data.pairwise_cipher; sta->key_mgmt = data.key_mgmt; sta->rsn_capab = data.capabilities; if (bss->proto && (sta->proto & bss->proto) == 0) { wpa_printf(MSG_INFO, "Mismatch in WPA/WPA2 proto: STA " MACSTR " 0x%x BSS " MACSTR " 0x%x", MAC2STR(sta->addr), sta->proto, MAC2STR(bss->bssid), bss->proto); } if (bss->pairwise_cipher && (sta->pairwise_cipher & bss->pairwise_cipher) == 0) { wpa_printf(MSG_INFO, "Mismatch in pairwise cipher: STA " MACSTR " 0x%x BSS " MACSTR " 0x%x", MAC2STR(sta->addr), sta->pairwise_cipher, MAC2STR(bss->bssid), bss->pairwise_cipher); } if (sta->proto && data.group_cipher != bss->group_cipher) { wpa_printf(MSG_INFO, "Mismatch in group cipher: STA " MACSTR " 0x%x != BSS " MACSTR " 0x%x", MAC2STR(sta->addr), data.group_cipher, MAC2STR(bss->bssid), bss->group_cipher); } if ((bss->rsn_capab & WPA_CAPABILITY_MFPR) && !(sta->rsn_capab & WPA_CAPABILITY_MFPC)) { wpa_printf(MSG_INFO, "STA " MACSTR " tries to associate " "without MFP to BSS " MACSTR " that advertises " "MFPR", MAC2STR(sta->addr), MAC2STR(bss->bssid)); } skip_rsn_wpa: wpa_printf(MSG_INFO, "STA " MACSTR " proto=%s%s%s" "pairwise=%s%s%s%s" "key_mgmt=%s%s%s%s%s%s%s%s" "rsn_capab=%s%s%s%s%s", MAC2STR(sta->addr), sta->proto == 0 ? "OPEN " : "", sta->proto & WPA_PROTO_WPA ? "WPA " : "", sta->proto & WPA_PROTO_RSN ? "WPA2 " : "", sta->pairwise_cipher == 0 ? "N/A " : "", sta->pairwise_cipher & WPA_CIPHER_NONE ? "NONE " : "", sta->pairwise_cipher & WPA_CIPHER_TKIP ? "TKIP " : "", sta->pairwise_cipher & WPA_CIPHER_CCMP ? "CCMP " : "", sta->key_mgmt == 0 ? "N/A " : "", sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X ? "EAP " : "", sta->key_mgmt & WPA_KEY_MGMT_PSK ? "PSK " : "", sta->key_mgmt & WPA_KEY_MGMT_WPA_NONE ? "WPA-NONE " : "", sta->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X ? "FT-EAP " : "", sta->key_mgmt & WPA_KEY_MGMT_FT_PSK ? "FT-PSK " : "", sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256 ? "EAP-SHA256 " : "", sta->key_mgmt & WPA_KEY_MGMT_PSK_SHA256 ? "PSK-SHA256 " : "", sta->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "", sta->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ? "NO_PAIRWISE " : "", sta->rsn_capab & WPA_CAPABILITY_MFPR ? "MFPR " : "", sta->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "", sta->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ? "PEERKEY " : ""); }
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, const u8 *wpa_ie, size_t wpa_ie_len, const u8 *mdie, size_t mdie_len) { struct wpa_ie_data data; int ciphers, key_mgmt, res, version; u32 selector; size_t i; const u8 *pmkid = NULL; if (wpa_auth == NULL || sm == NULL) return WPA_NOT_ENABLED; if (wpa_ie == NULL || wpa_ie_len < 1) return WPA_INVALID_IE; if (wpa_ie[0] == WLAN_EID_RSN) version = WPA_PROTO_RSN; else version = WPA_PROTO_WPA; if (!(wpa_auth->conf.wpa & version)) { wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, version, MAC2STR(sm->addr)); return WPA_INVALID_PROTO; } if (version == WPA_PROTO_RSN) { res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; if (0) { } #ifdef CONFIG_IEEE80211R else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) selector = RSN_AUTH_KEY_MGMT_FT_802_1X; else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) selector = RSN_AUTH_KEY_MGMT_FT_PSK; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE else if (data.key_mgmt & WPA_KEY_MGMT_SAE) selector = RSN_AUTH_KEY_MGMT_SAE; else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) selector = RSN_AUTH_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; else if (data.key_mgmt & WPA_KEY_MGMT_PSK) selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; selector = wpa_cipher_to_suite(WPA_PROTO_RSN, data.pairwise_cipher); if (!selector) selector = RSN_CIPHER_SUITE_CCMP; wpa_auth->dot11RSNAPairwiseCipherSelected = selector; selector = wpa_cipher_to_suite(WPA_PROTO_RSN, data.group_cipher); if (!selector) selector = RSN_CIPHER_SUITE_CCMP; wpa_auth->dot11RSNAGroupCipherSelected = selector; } else { res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; else if (data.key_mgmt & WPA_KEY_MGMT_PSK) selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; selector = wpa_cipher_to_suite(WPA_PROTO_WPA, data.pairwise_cipher); if (!selector) selector = RSN_CIPHER_SUITE_TKIP; wpa_auth->dot11RSNAPairwiseCipherSelected = selector; selector = wpa_cipher_to_suite(WPA_PROTO_WPA, data.group_cipher); if (!selector) selector = WPA_CIPHER_SUITE_TKIP; wpa_auth->dot11RSNAGroupCipherSelected = selector; } if (res) { wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " MACSTR " (res=%d)", MAC2STR(sm->addr), res); wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); return WPA_INVALID_IE; } if (data.group_cipher != wpa_auth->conf.wpa_group) { wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " MACSTR, data.group_cipher, MAC2STR(sm->addr)); return WPA_INVALID_GROUP; } key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; if (!key_mgmt) { wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " MACSTR, data.key_mgmt, MAC2STR(sm->addr)); return WPA_INVALID_AKMP; } if (0) { } #ifdef CONFIG_IEEE80211R else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE else if (key_mgmt & WPA_KEY_MGMT_SAE) sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE; else if (key_mgmt & WPA_KEY_MGMT_FT_SAE) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; else sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; if (version == WPA_PROTO_RSN) ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; else ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; if (!ciphers) { wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " "from " MACSTR, version == WPA_PROTO_RSN ? "RSN" : "WPA", data.pairwise_cipher, MAC2STR(sm->addr)); return WPA_INVALID_PAIRWISE; } #ifdef CONFIG_IEEE80211W if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { wpa_printf(MSG_DEBUG, "Management frame protection " "required, but client did not enable it"); return WPA_MGMT_FRAME_PROTECTION_VIOLATION; } if (ciphers & WPA_CIPHER_TKIP) { wpa_printf(MSG_DEBUG, "Management frame protection " "cannot use TKIP"); return WPA_MGMT_FRAME_PROTECTION_VIOLATION; } if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { wpa_printf(MSG_DEBUG, "Unsupported management group " "cipher %d", data.mgmt_group_cipher); return WPA_INVALID_MGMT_GROUP_CIPHER; } } if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || !(data.capabilities & WPA_CAPABILITY_MFPC)) sm->mgmt_frame_prot = 0; else sm->mgmt_frame_prot = 1; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but " "MDIE not included"); return WPA_INVALID_MDIE; } if (os_memcmp(mdie, wpa_auth->conf.mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) { wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); return WPA_INVALID_MDIE; } } #endif /* CONFIG_IEEE80211R */ if (ciphers & WPA_CIPHER_CCMP) sm->pairwise = WPA_CIPHER_CCMP; else if (ciphers & WPA_CIPHER_GCMP) sm->pairwise = WPA_CIPHER_GCMP; else sm->pairwise = WPA_CIPHER_TKIP; /* TODO: clear WPA/WPA2 state if STA changes from one to another */ if (wpa_ie[0] == WLAN_EID_RSN) sm->wpa = WPA_VERSION_WPA2; else sm->wpa = WPA_VERSION_WPA; sm->pmksa = NULL; for (i = 0; i < data.num_pmkid; i++) { wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", &data.pmkid[i * PMKID_LEN], PMKID_LEN); sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, &data.pmkid[i * PMKID_LEN]); if (sm->pmksa) { pmkid = sm->pmksa->pmkid; break; } } for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && i < data.num_pmkid; i++) { struct wpa_auth_okc_iter_data idata; idata.pmksa = NULL; idata.aa = wpa_auth->addr; idata.spa = sm->addr; idata.pmkid = &data.pmkid[i * PMKID_LEN]; wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata); if (idata.pmksa) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, "OKC match for PMKID"); sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa, idata.pmksa, wpa_auth->addr, idata.pmkid); pmkid = idata.pmkid; break; } } if (sm->pmksa) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, "PMKID found from PMKSA cache " "eap_type=%d vlan_id=%d", sm->pmksa->eap_type_authsrv, sm->pmksa->vlan_id); os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN); } if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { os_free(sm->wpa_ie); sm->wpa_ie = os_malloc(wpa_ie_len); if (sm->wpa_ie == NULL) return WPA_ALLOC_FAIL; } os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); sm->wpa_ie_len = wpa_ie_len; return WPA_IE_OK; }
void bss_update(struct wlantest *wt, struct wlantest_bss *bss, struct ieee802_11_elems *elems) { struct wpa_ie_data data; int update = 0; if (bss->capab_info != bss->prev_capab_info) update = 1; if (elems->ssid == NULL || elems->ssid_len > 32) { wpa_printf(MSG_INFO, "Invalid or missing SSID in a Beacon " "frame for " MACSTR, MAC2STR(bss->bssid)); bss->parse_error_reported = 1; return; } if (bss->ssid_len != elems->ssid_len || os_memcmp(bss->ssid, elems->ssid, bss->ssid_len) != 0) { wpa_printf(MSG_DEBUG, "Store SSID '%s' for BSSID " MACSTR, wpa_ssid_txt(elems->ssid, elems->ssid_len), MAC2STR(bss->bssid)); os_memcpy(bss->ssid, elems->ssid, elems->ssid_len); bss->ssid_len = elems->ssid_len; bss_add_pmk(wt, bss); } if (elems->osen == NULL) { if (bss->osenie[0]) { add_note(wt, MSG_INFO, "BSS " MACSTR " - OSEN IE removed", MAC2STR(bss->bssid)); bss->rsnie[0] = 0; update = 1; } } else { if (bss->osenie[0] == 0 || os_memcmp(bss->osenie, elems->osen - 2, elems->osen_len + 2) != 0) { wpa_printf(MSG_INFO, "BSS " MACSTR " - OSEN IE " "stored", MAC2STR(bss->bssid)); wpa_hexdump(MSG_DEBUG, "OSEN IE", elems->osen - 2, elems->osen_len + 2); update = 1; } os_memcpy(bss->osenie, elems->osen - 2, elems->osen_len + 2); } if (elems->rsn_ie == NULL) { if (bss->rsnie[0]) { add_note(wt, MSG_INFO, "BSS " MACSTR " - RSN IE removed", MAC2STR(bss->bssid)); bss->rsnie[0] = 0; update = 1; } } else { if (bss->rsnie[0] == 0 || os_memcmp(bss->rsnie, elems->rsn_ie - 2, elems->rsn_ie_len + 2) != 0) { wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE " "stored", MAC2STR(bss->bssid)); wpa_hexdump(MSG_DEBUG, "RSN IE", elems->rsn_ie - 2, elems->rsn_ie_len + 2); update = 1; } os_memcpy(bss->rsnie, elems->rsn_ie - 2, elems->rsn_ie_len + 2); } if (elems->wpa_ie == NULL) { if (bss->wpaie[0]) { add_note(wt, MSG_INFO, "BSS " MACSTR " - WPA IE removed", MAC2STR(bss->bssid)); bss->wpaie[0] = 0; update = 1; } } else { if (bss->wpaie[0] == 0 || os_memcmp(bss->wpaie, elems->wpa_ie - 2, elems->wpa_ie_len + 2) != 0) { wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE " "stored", MAC2STR(bss->bssid)); wpa_hexdump(MSG_DEBUG, "WPA IE", elems->wpa_ie - 2, elems->wpa_ie_len + 2); update = 1; } os_memcpy(bss->wpaie, elems->wpa_ie - 2, elems->wpa_ie_len + 2); } if (!update) return; bss->prev_capab_info = bss->capab_info; bss->proto = 0; bss->pairwise_cipher = 0; bss->group_cipher = 0; bss->key_mgmt = 0; bss->rsn_capab = 0; bss->mgmt_group_cipher = 0; if (bss->wpaie[0]) { if (wpa_parse_wpa_ie_wpa(bss->wpaie, 2 + bss->wpaie[1], &data) < 0) { add_note(wt, MSG_INFO, "Failed to parse WPA IE from " MACSTR, MAC2STR(bss->bssid)); } else { bss->proto |= data.proto; bss->pairwise_cipher |= data.pairwise_cipher; bss->group_cipher |= data.group_cipher; bss->key_mgmt |= data.key_mgmt; bss->rsn_capab = data.capabilities; bss->mgmt_group_cipher |= data.mgmt_group_cipher; } } if (bss->rsnie[0]) { if (wpa_parse_wpa_ie_rsn(bss->rsnie, 2 + bss->rsnie[1], &data) < 0) { add_note(wt, MSG_INFO, "Failed to parse RSN IE from " MACSTR, MAC2STR(bss->bssid)); } else { bss->proto |= data.proto; bss->pairwise_cipher |= data.pairwise_cipher; bss->group_cipher |= data.group_cipher; bss->key_mgmt |= data.key_mgmt; bss->rsn_capab = data.capabilities; bss->mgmt_group_cipher |= data.mgmt_group_cipher; } } if (bss->osenie[0]) { bss->proto |= WPA_PROTO_OSEN; bss->pairwise_cipher |= WPA_CIPHER_CCMP; bss->group_cipher |= WPA_CIPHER_CCMP; bss->key_mgmt |= WPA_KEY_MGMT_OSEN; } if (!(bss->proto & WPA_PROTO_RSN) || !(bss->rsn_capab & WPA_CAPABILITY_MFPC)) bss->mgmt_group_cipher = 0; if (!bss->wpaie[0] && !bss->rsnie[0] && !bss->osenie[0] && (bss->capab_info & WLAN_CAPABILITY_PRIVACY)) bss->group_cipher = WPA_CIPHER_WEP40; wpa_printf(MSG_INFO, "BSS " MACSTR " proto=%s%s%s%s" "pairwise=%s%s%s%s%s%s%s" "group=%s%s%s%s%s%s%s%s%s" "mgmt_group_cipher=%s%s%s%s%s" "key_mgmt=%s%s%s%s%s%s%s%s%s" "rsn_capab=%s%s%s%s%s", MAC2STR(bss->bssid), bss->proto == 0 ? "OPEN " : "", bss->proto & WPA_PROTO_WPA ? "WPA " : "", bss->proto & WPA_PROTO_RSN ? "WPA2 " : "", bss->proto & WPA_PROTO_OSEN ? "OSEN " : "", bss->pairwise_cipher == 0 ? "N/A " : "", bss->pairwise_cipher & WPA_CIPHER_NONE ? "NONE " : "", bss->pairwise_cipher & WPA_CIPHER_TKIP ? "TKIP " : "", bss->pairwise_cipher & WPA_CIPHER_CCMP ? "CCMP " : "", bss->pairwise_cipher & WPA_CIPHER_CCMP_256 ? "CCMP-256 " : "", bss->pairwise_cipher & WPA_CIPHER_GCMP ? "GCMP " : "", bss->pairwise_cipher & WPA_CIPHER_GCMP_256 ? "GCMP-256 " : "", bss->group_cipher == 0 ? "N/A " : "", bss->group_cipher & WPA_CIPHER_NONE ? "NONE " : "", bss->group_cipher & WPA_CIPHER_WEP40 ? "WEP40 " : "", bss->group_cipher & WPA_CIPHER_WEP104 ? "WEP104 " : "", bss->group_cipher & WPA_CIPHER_TKIP ? "TKIP " : "", bss->group_cipher & WPA_CIPHER_CCMP ? "CCMP " : "", bss->group_cipher & WPA_CIPHER_CCMP_256 ? "CCMP-256 " : "", bss->group_cipher & WPA_CIPHER_GCMP ? "GCMP " : "", bss->group_cipher & WPA_CIPHER_GCMP_256 ? "GCMP-256 " : "", bss->mgmt_group_cipher == 0 ? "N/A " : "", bss->mgmt_group_cipher & WPA_CIPHER_AES_128_CMAC ? "BIP " : "", bss->mgmt_group_cipher & WPA_CIPHER_BIP_GMAC_128 ? "BIP-GMAC-128 " : "", bss->mgmt_group_cipher & WPA_CIPHER_BIP_GMAC_256 ? "BIP-GMAC-256 " : "", bss->mgmt_group_cipher & WPA_CIPHER_BIP_CMAC_256 ? "BIP-CMAC-256 " : "", bss->key_mgmt == 0 ? "N/A " : "", bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X ? "EAP " : "", bss->key_mgmt & WPA_KEY_MGMT_PSK ? "PSK " : "", bss->key_mgmt & WPA_KEY_MGMT_WPA_NONE ? "WPA-NONE " : "", bss->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X ? "FT-EAP " : "", bss->key_mgmt & WPA_KEY_MGMT_FT_PSK ? "FT-PSK " : "", bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256 ? "EAP-SHA256 " : "", bss->key_mgmt & WPA_KEY_MGMT_PSK_SHA256 ? "PSK-SHA256 " : "", bss->key_mgmt & WPA_KEY_MGMT_OSEN ? "OSEN " : "", bss->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "", bss->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ? "NO_PAIRWISE " : "", bss->rsn_capab & WPA_CAPABILITY_MFPR ? "MFPR " : "", bss->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "", bss->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ? "PEERKEY " : ""); }
static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse) { const u8 *end, *pos; struct wpa_ie_data data; int ret; const struct rsn_ftie *ftie; int prot_ie_count = 0; os_memset(parse, 0, sizeof(*parse)); if (ies == NULL) return 0; pos = ies; end = ies + ies_len; while (pos + 2 <= end && pos + 2 + pos[1] <= end) { switch (pos[0]) { case WLAN_EID_RSN: parse->rsn = pos + 2; parse->rsn_len = pos[1]; ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, parse->rsn_len + 2, &data); if (ret < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to parse " "RSN IE: %d", ret); return -1; } if (data.num_pmkid == 1 && data.pmkid) parse->rsn_pmkid = data.pmkid; break; case WLAN_EID_MOBILITY_DOMAIN: parse->mdie = pos + 2; parse->mdie_len = pos[1]; break; case WLAN_EID_FAST_BSS_TRANSITION: if (pos[1] < sizeof(*ftie)) return -1; ftie = (const struct rsn_ftie *) (pos + 2); prot_ie_count = ftie->mic_control[1]; if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) return -1; break; case WLAN_EID_RIC_DATA: if (parse->ric == NULL) parse->ric = pos; } pos += 2 + pos[1]; } if (prot_ie_count == 0) return 0; /* no MIC */ /* * Check that the protected IE count matches with IEs included in the * frame. */ if (parse->rsn) prot_ie_count--; if (parse->mdie) prot_ie_count--; if (parse->ftie) prot_ie_count--; if (prot_ie_count < 0) { wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " "the protected IE count"); return -1; } if (prot_ie_count == 0 && parse->ric) { wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " "included in protected IE count"); return -1; } /* Determine the end of the RIC IE(s) */ pos = parse->ric; while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && prot_ie_count) { prot_ie_count--; pos += 2 + pos[1]; } parse->ric_len = pos - parse->ric; if (prot_ie_count) { wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " "frame", (int) prot_ie_count); return -1; } return 0; }