diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 02abf740d..3a243d13b 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -1037,6 +1037,7 @@ ifdef NEED_AP_MLME OBJS += src/ap/wmm.c OBJS += src/ap/ap_list.c OBJS += src/ap/comeback_token.c +OBJS += src/pasn/pasn_responder.c OBJS += src/ap/ieee802_11.c OBJS += src/ap/hw_features.c OBJS += src/ap/dfs.c diff --git a/hostapd/Makefile b/hostapd/Makefile index f37d48c12..51702439c 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -1183,6 +1183,7 @@ ifdef NEED_AP_MLME OBJS += ../src/ap/wmm.o OBJS += ../src/ap/ap_list.o OBJS += ../src/ap/comeback_token.o +OBJS += ../src/pasn/pasn_responder.o OBJS += ../src/ap/ieee802_11.o OBJS += ../src/ap/hw_features.o OBJS += ../src/ap/dfs.o diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 304d57661..4691f91ee 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -70,12 +70,6 @@ prepare_auth_resp_fils(struct hostapd_data *hapd, #endif /* CONFIG_FILS */ #ifdef CONFIG_PASN - -static int handle_auth_pasn_resp(struct wpas_pasn *pasn, const u8 *own_addr, - const u8 *peer_addr, - struct rsn_pmksa_cache_entry *pmksa, - u16 status); - #ifdef CONFIG_FILS static void pasn_fils_auth_resp(struct hostapd_data *hapd, @@ -2281,234 +2275,8 @@ int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_PASN -#ifdef CONFIG_SAE - -static int pasn_wd_handle_sae_commit(struct wpas_pasn *pasn, - const u8 *own_addr, const u8 *peer_addr, - struct wpabuf *wd) -{ - const u8 *data; - size_t buf_len; - u16 res, alg, seq, status; - int groups[] = { pasn->group, 0 }; - int ret; - - if (!wd) - return -1; - - data = wpabuf_head_u8(wd); - buf_len = wpabuf_len(wd); - - if (buf_len < 6) { - wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu", - buf_len); - return -1; - } - - alg = WPA_GET_LE16(data); - seq = WPA_GET_LE16(data + 2); - status = WPA_GET_LE16(data + 4); - - wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u", - alg, seq, status); - - if (alg != WLAN_AUTH_SAE || seq != 1 || - status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { - wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit"); - return -1; - } - - sae_clear_data(&pasn->sae); - pasn->sae.state = SAE_NOTHING; - - ret = sae_set_group(&pasn->sae, pasn->group); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group"); - return -1; - } - - if (!pasn->password || !pasn->pt) { - wpa_printf(MSG_DEBUG, "PASN: No SAE PT found"); - return -1; - } - - ret = sae_prepare_commit_pt(&pasn->sae, pasn->pt, own_addr, peer_addr, - NULL, NULL); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit"); - return -1; - } - - res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0, - groups, 0); - if (res != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit"); - return -1; - } - - /* Process the commit message and derive the PMK */ - ret = sae_process_commit(&pasn->sae); - if (ret) { - wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit"); - return -1; - } - - pasn->sae.state = SAE_COMMITTED; - - return 0; -} - - -static int pasn_wd_handle_sae_confirm(struct wpas_pasn *pasn, - const u8 *peer_addr, struct wpabuf *wd) -{ - const u8 *data; - size_t buf_len; - u16 res, alg, seq, status; - - if (!wd) - return -1; - - data = wpabuf_head_u8(wd); - buf_len = wpabuf_len(wd); - - if (buf_len < 6) { - wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu", - buf_len); - return -1; - } - - alg = WPA_GET_LE16(data); - seq = WPA_GET_LE16(data + 2); - status = WPA_GET_LE16(data + 4); - - wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u", - alg, seq, status); - - if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm"); - return -1; - } - - res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6); - if (res != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm"); - return -1; - } - - pasn->sae.state = SAE_ACCEPTED; - - /* - * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with - * PASN/SAE should only be allowed with future PASN only. For now do not - * restrict this only for PASN. - */ - if (pasn->disable_pmksa_caching) - return 0; - - wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", - pasn->sae.pmk, pasn->sae.pmk_len); - if (!pasn->sae.akmp) - pasn->sae.akmp = WPA_KEY_MGMT_SAE; - - pmksa_cache_auth_add(pasn->pmksa, pasn->sae.pmk, pasn->sae.pmk_len, - pasn->sae.pmkid, NULL, 0, pasn->own_addr, - peer_addr, 0, NULL, pasn->sae.akmp); - return 0; -} - - -static struct wpabuf * pasn_get_sae_wd(struct wpas_pasn *pasn) -{ - struct wpabuf *buf = NULL; - u8 *len_ptr; - size_t len; - - /* Need to add the entire Authentication frame body */ - buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN); - if (!buf) { - wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer"); - return NULL; - } - - /* Need to add the entire authentication frame body for the commit */ - len_ptr = wpabuf_put(buf, 2); - wpabuf_put_le16(buf, WLAN_AUTH_SAE); - wpabuf_put_le16(buf, 1); - wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); - - /* Write the actual commit and update the length accordingly */ - sae_write_commit(&pasn->sae, buf, NULL, 0); - len = wpabuf_len(buf); - WPA_PUT_LE16(len_ptr, len - 2); - - /* Need to add the entire Authentication frame body for the confirm */ - len_ptr = wpabuf_put(buf, 2); - wpabuf_put_le16(buf, WLAN_AUTH_SAE); - wpabuf_put_le16(buf, 2); - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); - - sae_write_confirm(&pasn->sae, buf); - WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2); - - pasn->sae.state = SAE_CONFIRMED; - - return buf; -} - -#endif /* CONFIG_SAE */ - - #ifdef CONFIG_FILS -static struct wpabuf * pasn_get_fils_wd(struct wpas_pasn *pasn) -{ - struct pasn_fils *fils = &pasn->fils; - struct wpabuf *buf = NULL; - - if (!fils->erp_resp) { - wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp"); - return NULL; - } - - buf = wpabuf_alloc(1500); - if (!buf) - return NULL; - - /* Add the authentication algorithm */ - wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK); - - /* Authentication Transaction seq# */ - wpabuf_put_le16(buf, 2); - - /* Status Code */ - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); - - /* Own RSNE */ - wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher); - - /* FILS Nonce */ - wpabuf_put_u8(buf, WLAN_EID_EXTENSION); - wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN); - wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE); - wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN); - - /* FILS Session */ - wpabuf_put_u8(buf, WLAN_EID_EXTENSION); - wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN); - wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION); - wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN); - - /* Wrapped Data */ - wpabuf_put_u8(buf, WLAN_EID_EXTENSION); - wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp)); - wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA); - wpabuf_put_buf(buf, fils->erp_resp); - - return buf; -} - - static void pasn_fils_auth_resp(struct hostapd_data *hapd, struct sta_info *sta, u16 status, struct wpabuf *erp_resp, @@ -2723,38 +2491,6 @@ static int hapd_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len, } -static struct wpabuf * pasn_get_wrapped_data(struct wpas_pasn *pasn) -{ - switch (pasn->akmp) { - case WPA_KEY_MGMT_PASN: - /* no wrapped data */ - return NULL; - case WPA_KEY_MGMT_SAE: -#ifdef CONFIG_SAE - return pasn_get_sae_wd(pasn); -#else /* CONFIG_SAE */ - wpa_printf(MSG_ERROR, - "PASN: SAE: Cannot derive wrapped data"); - return NULL; -#endif /* CONFIG_SAE */ - case WPA_KEY_MGMT_FILS_SHA256: - case WPA_KEY_MGMT_FILS_SHA384: -#ifdef CONFIG_FILS - return pasn_get_fils_wd(pasn); -#endif /* CONFIG_FILS */ - /* fall through */ - case WPA_KEY_MGMT_FT_PSK: - case WPA_KEY_MGMT_FT_IEEE8021X: - case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: - default: - wpa_printf(MSG_ERROR, - "PASN: TODO: Wrapped data for akmp=0x%x", - pasn->akmp); - return NULL; - } -} - - static void hapd_initialize_pasn(struct hostapd_data *hapd, struct sta_info *sta) { @@ -2819,302 +2555,6 @@ static int pasn_set_keys_from_cache(struct hostapd_data *hapd, } -static int -pasn_derive_keys(struct wpas_pasn *pasn, - const u8 *own_addr, const u8 *peer_addr, - const u8 *cached_pmk, size_t cached_pmk_len, - struct wpa_pasn_params_data *pasn_data, - struct wpabuf *wrapped_data, - struct wpabuf *secret) -{ - static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'}; - u8 pmk[PMK_LEN_MAX]; - u8 pmk_len; - int ret; - - os_memset(pmk, 0, sizeof(pmk)); - pmk_len = 0; - - if (!cached_pmk || !cached_pmk_len) - wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry"); - - if (pasn->akmp == WPA_KEY_MGMT_PASN) { - wpa_printf(MSG_DEBUG, "PASN: Using default PMK"); - - pmk_len = WPA_PASN_PMK_LEN; - os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk)); - } else if (cached_pmk && cached_pmk_len) { - wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry"); - - pmk_len = cached_pmk_len; - os_memcpy(pmk, cached_pmk, cached_pmk_len); - } else { - switch (pasn->akmp) { -#ifdef CONFIG_SAE - case WPA_KEY_MGMT_SAE: - if (pasn->sae.state == SAE_COMMITTED) { - pmk_len = PMK_LEN; - os_memcpy(pmk, pasn->sae.pmk, PMK_LEN); - break; - } -#endif /* CONFIG_SAE */ - /* fall through */ - default: - /* TODO: Derive PMK based on wrapped data */ - wpa_printf(MSG_DEBUG, - "PASN: Missing PMK derivation"); - return -1; - } - } - - ret = pasn_pmk_to_ptk(pmk, pmk_len, peer_addr, own_addr, - wpabuf_head(secret), wpabuf_len(secret), - &pasn->ptk, pasn->akmp, - pasn->cipher, pasn->kdk_len); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK"); - return -1; - } - - if (pasn->secure_ltf) { - ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, - pasn->cipher); - if (ret) { - wpa_printf(MSG_DEBUG, - "PASN: Failed to derive LTF keyseed"); - return -1; - } - } - - wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived"); - return 0; -} - - -static void handle_auth_pasn_comeback(struct wpas_pasn *pasn, - const u8 *own_addr, const u8 *peer_addr, - u16 group) -{ - struct wpabuf *buf, *comeback; - int ret; - - wpa_printf(MSG_DEBUG, - "PASN: Building comeback frame 2. Comeback after=%u", - pasn->comeback_after); - - buf = wpabuf_alloc(1500); - if (!buf) - return; - - wpa_pasn_build_auth_header(buf, own_addr, own_addr, peer_addr, 2, - WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY); - - /* - * Do not include the group as a part of the token since it is not going - * to be used. - */ - comeback = auth_build_token_req(&pasn->last_comeback_key_update, - pasn->comeback_key, pasn->comeback_idx, - pasn->comeback_pending_idx, - sizeof(u16) * COMEBACK_PENDING_IDX_SIZE, - 0, peer_addr, 0); - if (!comeback) { - wpa_printf(MSG_DEBUG, - "PASN: Failed sending auth with comeback"); - wpabuf_free(buf); - return; - } - - wpa_pasn_add_parameter_ie(buf, group, - WPA_PASN_WRAPPED_DATA_NO, - NULL, 0, comeback, - pasn->comeback_after); - wpabuf_free(comeback); - - wpa_printf(MSG_DEBUG, - "PASN: comeback: STA=" MACSTR, MAC2STR(peer_addr)); - - ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf), - wpabuf_len(buf), 0, 0, 0); - if (ret) - wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2"); - - wpabuf_free(buf); -} - - -static int handle_auth_pasn_resp(struct wpas_pasn *pasn, const u8 *own_addr, - const u8 *peer_addr, - struct rsn_pmksa_cache_entry *pmksa, - u16 status) -{ - struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL; - struct wpabuf *rsn_buf = NULL; - u8 mic[WPA_PASN_MAX_MIC_LEN]; - u8 mic_len; - u8 *ptr; - const u8 *frame, *data, *rsn_ie, *rsnxe_ie; - u8 *data_buf = NULL; - size_t frame_len, data_len; - int ret; - const u8 *pmkid = NULL; - - wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status); - - buf = wpabuf_alloc(1500); - if (!buf) - goto fail; - - wpa_pasn_build_auth_header(buf, own_addr, own_addr, peer_addr, 2, - status); - - if (status != WLAN_STATUS_SUCCESS) - goto done; - - if (pmksa && pasn->custom_pmkid_valid) - pmkid = pasn->custom_pmkid; - else if (pmksa) { - pmkid = pmksa->pmkid; -#ifdef CONFIG_SAE - } else if (pasn->akmp == WPA_KEY_MGMT_SAE) { - wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID"); - pmkid = pasn->sae.pmkid; -#endif /* CONFIG_SAE */ -#ifdef CONFIG_FILS - } else if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || - pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { - wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID"); - pmkid = pasn->fils.erp_pmkid; -#endif /* CONFIG_FILS */ - } - - if (wpa_pasn_add_rsne(buf, pmkid, - pasn->akmp, pasn->cipher) < 0) - goto fail; - - /* No need to derive PMK if PMKSA is given */ - if (!pmksa) - wrapped_data_buf = pasn_get_wrapped_data(pasn); - else - pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO; - - /* Get public key */ - pubkey = crypto_ecdh_get_pubkey(pasn->ecdh, 0); - pubkey = wpabuf_zeropad(pubkey, - crypto_ecdh_prime_len(pasn->ecdh)); - if (!pubkey) { - wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey"); - goto fail; - } - - wpa_pasn_add_parameter_ie(buf, pasn->group, - pasn->wrapped_data_format, - pubkey, true, NULL, 0); - - if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0) - goto fail; - - wpabuf_free(wrapped_data_buf); - wrapped_data_buf = NULL; - wpabuf_free(pubkey); - pubkey = NULL; - - /* Add RSNXE if needed */ - rsnxe_ie = pasn->rsnxe_ie; - if (rsnxe_ie) - wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]); - - /* Add the mic */ - mic_len = pasn_mic_len(pasn->akmp, pasn->cipher); - wpabuf_put_u8(buf, WLAN_EID_MIC); - wpabuf_put_u8(buf, mic_len); - ptr = wpabuf_put(buf, mic_len); - - os_memset(ptr, 0, mic_len); - - frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN; - frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN; - - if (pasn->rsn_ie && pasn->rsn_ie_len) { - rsn_ie = pasn->rsn_ie; - } else { - /* - * Note: when pasn->rsn_ie is NULL, it is likely that Beacon - * frame RSNE is not initialized. This is possible in case of - * PASN authentication used for Wi-Fi Aware for which Beacon - * frame RSNE and RSNXE are same as RSNE and RSNXE in the - * Authentication frame. - */ - rsn_buf = wpabuf_alloc(500); - if (!rsn_buf) - goto fail; - - if (wpa_pasn_add_rsne(rsn_buf, pmkid, - pasn->akmp, pasn->cipher) < 0) - goto fail; - - rsn_ie = wpabuf_head_u8(rsn_buf); - } - - /* - * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also - * MDE, etc. Thus, do not use the returned length but instead use the - * length specified in the IE header. - */ - data_len = rsn_ie[1] + 2; - if (rsnxe_ie) { - data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2); - if (!data_buf) - goto fail; - - os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2); - os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2); - data_len += rsnxe_ie[1] + 2; - data = data_buf; - } else { - data = rsn_ie; - } - - ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher, - own_addr, peer_addr, data, data_len, - frame, frame_len, mic); - os_free(data_buf); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation"); - goto fail; - } - -#ifdef CONFIG_TESTING_OPTIONS - if (pasn->corrupt_mic) { - wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC"); - mic[0] = ~mic[0]; - } -#endif /* CONFIG_TESTING_OPTIONS */ - - os_memcpy(ptr, mic, mic_len); - -done: - wpa_printf(MSG_DEBUG, - "PASN: Building frame 2: success; resp STA=" MACSTR, - MAC2STR(peer_addr)); - - ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf), - wpabuf_len(buf), 0, 0, 0); - if (ret) - wpa_printf(MSG_INFO, "send_auth_reply: Send failed"); - - wpabuf_free(rsn_buf); - wpabuf_free(buf); - return ret; -fail: - wpabuf_free(wrapped_data_buf); - wpabuf_free(pubkey); - wpabuf_free(rsn_buf); - wpabuf_free(buf); - return -1; -} - - static void hapd_pasn_update_params(struct hostapd_data *hapd, struct sta_info *sta, const struct ieee80211_mgmt *mgmt, @@ -3189,422 +2629,6 @@ static void hapd_pasn_update_params(struct hostapd_data *hapd, } -static int handle_auth_pasn_1(struct wpas_pasn *pasn, - const u8 *own_addr, const u8 *peer_addr, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - struct ieee802_11_elems elems; - struct wpa_ie_data rsn_data; - struct wpa_pasn_params_data pasn_params; - struct rsn_pmksa_cache_entry *pmksa = NULL; - const u8 *cached_pmk = NULL; - size_t cached_pmk_len = 0; - struct wpabuf *wrapped_data = NULL, *secret = NULL; - const int *groups = pasn->pasn_groups; - static const int default_groups[] = { 19, 0 }; - u16 status = WLAN_STATUS_SUCCESS; - int ret, inc_y; - bool derive_keys; - u32 i; - - if (!groups) - groups = default_groups; - - if (ieee802_11_parse_elems(mgmt->u.auth.variable, - len - offsetof(struct ieee80211_mgmt, - u.auth.variable), - &elems, 0) == ParseFailed) { - wpa_printf(MSG_DEBUG, - "PASN: Failed parsing Authentication frame"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - - ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2, - &rsn_data); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE"); - status = WLAN_STATUS_INVALID_RSNIE; - goto send_resp; - } - - ret = wpa_pasn_validate_rsne(&rsn_data); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE"); - status = WLAN_STATUS_INVALID_RSNIE; - goto send_resp; - } - - if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) || - !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) { - wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher"); - status = WLAN_STATUS_INVALID_RSNIE; - goto send_resp; - } - - pasn->akmp = rsn_data.key_mgmt; - pasn->cipher = rsn_data.pairwise_cipher; - - if (pasn->derive_kdk && - ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, - WLAN_RSNX_CAPAB_SECURE_LTF)) - pasn->secure_ltf = true; - - if (pasn->derive_kdk) - pasn->kdk_len = WPA_KDK_MAX_LEN; - else - pasn->kdk_len = 0; - - wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len); - - if (!elems.pasn_params || !elems.pasn_params_len) { - wpa_printf(MSG_DEBUG, - "PASN: No PASN Parameters element found"); - status = WLAN_STATUS_INVALID_PARAMETERS; - goto send_resp; - } - - ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3, - elems.pasn_params_len + 3, - false, &pasn_params); - if (ret) { - wpa_printf(MSG_DEBUG, - "PASN: Failed validation of PASN Parameters IE"); - status = WLAN_STATUS_INVALID_PARAMETERS; - goto send_resp; - } - - for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++) - ; - - if (!pasn_params.group || groups[i] != pasn_params.group) { - wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed", - pasn_params.group); - status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; - goto send_resp; - } - - if (!pasn_params.pubkey || !pasn_params.pubkey_len) { - wpa_printf(MSG_DEBUG, "PASN: Invalid public key"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - - if (pasn_params.comeback) { - wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token"); - - ret = check_comeback_token(pasn->comeback_key, - pasn->comeback_pending_idx, - peer_addr, - pasn_params.comeback, - pasn_params.comeback_len); - - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - } else if (pasn->use_anti_clogging) { - wpa_printf(MSG_DEBUG, "PASN: Respond with comeback"); - handle_auth_pasn_comeback(pasn, own_addr, peer_addr, - pasn_params.group); - return -1; - } - - pasn->ecdh = crypto_ecdh_init(pasn_params.group); - if (!pasn->ecdh) { - wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - - pasn->group = pasn_params.group; - - if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) { - inc_y = 1; - } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 || - pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) { - inc_y = 0; - } else { - wpa_printf(MSG_DEBUG, - "PASN: Invalid first octet in pubkey=0x%x", - pasn_params.pubkey[0]); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - - secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y, - pasn_params.pubkey + 1, - pasn_params.pubkey_len - 1); - if (!secret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - - derive_keys = true; - if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) { - wrapped_data = ieee802_11_defrag(&elems, - WLAN_EID_EXTENSION, - WLAN_EID_EXT_WRAPPED_DATA); - if (!wrapped_data) { - wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - -#ifdef CONFIG_SAE - if (pasn->akmp == WPA_KEY_MGMT_SAE) { - ret = pasn_wd_handle_sae_commit(pasn, own_addr, - peer_addr, - wrapped_data); - if (ret) { - wpa_printf(MSG_DEBUG, - "PASN: Failed processing SAE commit"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - } -#endif /* CONFIG_SAE */ -#ifdef CONFIG_FILS - if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || - pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { - if (!pasn->fils_wd_valid) { - wpa_printf(MSG_DEBUG, - "PASN: Invalid FILS wrapped data"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - - wpa_printf(MSG_DEBUG, - "PASN: FILS: Pending AS response"); - - /* - * With PASN/FILS, keys can be derived only after a - * response from the AS is processed. - */ - derive_keys = false; - } -#endif /* CONFIG_FILS */ - } - - pasn->wrapped_data_format = pasn_params.wrapped_data_format; - - ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher, - ((const u8 *) mgmt) + IEEE80211_HDRLEN, - len - IEEE80211_HDRLEN, pasn->hash); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - - if (!derive_keys) { - wpa_printf(MSG_DEBUG, "PASN: Storing secret"); - pasn->secret = secret; - wpabuf_free(wrapped_data); - return 0; - } - - if (rsn_data.num_pmkid) { - if (wpa_key_mgmt_ft(pasn->akmp)) { -#ifdef CONFIG_IEEE80211R_AP - wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1"); - - if (!pasn->pmk_r1_len) { - wpa_printf(MSG_DEBUG, - "PASN: FT: Failed getting PMK-R1"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - cached_pmk = pasn->pmk_r1; - cached_pmk_len = pasn->pmk_r1_len; -#else /* CONFIG_IEEE80211R_AP */ - wpa_printf(MSG_DEBUG, "PASN: FT: Not supported"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; -#endif /* CONFIG_IEEE80211R_AP */ - } else { - wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry"); - - if (pasn->pmksa) { - const u8 *pmkid = NULL; - - if (pasn->custom_pmkid_valid) { - ret = pasn->validate_custom_pmkid( - pasn->cb_ctx, peer_addr, - rsn_data.pmkid); - if (ret) { - wpa_printf(MSG_DEBUG, - "PASN: Failed custom PMKID validation"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - } else { - pmkid = rsn_data.pmkid; - } - - pmksa = pmksa_cache_auth_get(pasn->pmksa, - peer_addr, - pmkid); - if (pmksa) { - cached_pmk = pmksa->pmk; - cached_pmk_len = pmksa->pmk_len; - } - } - } - } else { - wpa_printf(MSG_DEBUG, "PASN: No PMKID specified"); - } - - ret = pasn_derive_keys(pasn, own_addr, peer_addr, - cached_pmk, cached_pmk_len, - &pasn_params, wrapped_data, secret); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - - ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher, - ((const u8 *) mgmt) + IEEE80211_HDRLEN, - len - IEEE80211_HDRLEN, pasn->hash); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - } - -send_resp: - ret = handle_auth_pasn_resp(pasn, own_addr, peer_addr, pmksa, status); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to send response"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - } else { - wpa_printf(MSG_DEBUG, - "PASN: Success handling transaction == 1"); - } - - wpabuf_free(secret); - wpabuf_free(wrapped_data); - - if (status != WLAN_STATUS_SUCCESS) - return -1; - - return 0; -} - - -static int handle_auth_pasn_3(struct wpas_pasn *pasn, const u8 *own_addr, - const u8 *peer_addr, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - struct ieee802_11_elems elems; - struct wpa_pasn_params_data pasn_params; - struct wpabuf *wrapped_data = NULL; - u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN]; - u8 mic_len; - int ret; - - if (ieee802_11_parse_elems(mgmt->u.auth.variable, - len - offsetof(struct ieee80211_mgmt, - u.auth.variable), - &elems, 0) == ParseFailed) { - wpa_printf(MSG_DEBUG, - "PASN: Failed parsing Authentication frame"); - goto fail; - } - - /* Check that the MIC IE exists. Save it and zero out the memory. */ - mic_len = pasn_mic_len(pasn->akmp, pasn->cipher); - if (!elems.mic || elems.mic_len != mic_len) { - wpa_printf(MSG_DEBUG, - "PASN: Invalid MIC. Expecting len=%u", mic_len); - goto fail; - } else { - os_memcpy(mic, elems.mic, mic_len); - /* TODO: Clean this up.. Should not modify received frame - * buffer. */ - os_memset((u8 *) elems.mic, 0, mic_len); - } - - if (!elems.pasn_params || !elems.pasn_params_len) { - wpa_printf(MSG_DEBUG, - "PASN: No PASN Parameters element found"); - goto fail; - } - - ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3, - elems.pasn_params_len + 3, - false, &pasn_params); - if (ret) { - wpa_printf(MSG_DEBUG, - "PASN: Failed validation of PASN Parameters IE"); - goto fail; - } - - if (pasn_params.pubkey || pasn_params.pubkey_len) { - wpa_printf(MSG_DEBUG, - "PASN: Public key should not be included"); - goto fail; - } - - /* Verify the MIC */ - ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher, - peer_addr, own_addr, - pasn->hash, mic_len * 2, - (u8 *) &mgmt->u.auth, - len - offsetof(struct ieee80211_mgmt, u.auth), - out_mic); - - wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len); - if (ret || os_memcmp(mic, out_mic, mic_len) != 0) { - wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification"); - goto fail; - } - - if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) { - wrapped_data = ieee802_11_defrag(&elems, - WLAN_EID_EXTENSION, - WLAN_EID_EXT_WRAPPED_DATA); - - if (!wrapped_data) { - wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data"); - goto fail; - } - -#ifdef CONFIG_SAE - if (pasn->akmp == WPA_KEY_MGMT_SAE) { - ret = pasn_wd_handle_sae_confirm(pasn, peer_addr, - wrapped_data); - if (ret) { - wpa_printf(MSG_DEBUG, - "PASN: Failed processing SAE confirm"); - wpabuf_free(wrapped_data); - goto fail; - } - } -#endif /* CONFIG_SAE */ -#ifdef CONFIG_FILS - if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || - pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { - if (wrapped_data) { - wpa_printf(MSG_DEBUG, - "PASN: FILS: Ignore wrapped data"); - } - } -#endif /* CONFIG_FILS */ - wpabuf_free(wrapped_data); - } - - wpa_printf(MSG_INFO, - "PASN: Success handling transaction == 3. Store PTK"); - return 0; - -fail: - return -1; -} - - static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta, const struct ieee80211_mgmt *mgmt, size_t len, u16 trans_seq, u16 status) diff --git a/src/pasn/Makefile b/src/pasn/Makefile index 4bde46b48..a5b2c6b3f 100644 --- a/src/pasn/Makefile +++ b/src/pasn/Makefile @@ -10,6 +10,7 @@ CFLAGS += -DCONFIG_SHA512 CFLAGS += -DCONFIG_PASN LIB_OBJS= \ - pasn_initiator.o + pasn_initiator.o \ + pasn_responder.o include ../lib.rules diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h index d6aa00f93..d34bde302 100644 --- a/src/pasn/pasn_common.h +++ b/src/pasn/pasn_common.h @@ -150,6 +150,17 @@ int wpa_pasn_auth_rx(struct wpas_pasn *pasn, const u8 *data, size_t len, int wpa_pasn_auth_tx_status(struct wpas_pasn *pasn, const u8 *data, size_t data_len, u8 acked); +/* Responder */ +int handle_auth_pasn_1(struct wpas_pasn *pasn, + const u8 *own_addr, const u8 *peer_addr, + const struct ieee80211_mgmt *mgmt, size_t len); +int handle_auth_pasn_3(struct wpas_pasn *pasn, const u8 *own_addr, + const u8 *peer_addr, + const struct ieee80211_mgmt *mgmt, size_t len); +int handle_auth_pasn_resp(struct wpas_pasn *pasn, const u8 *own_addr, + const u8 *peer_addr, + struct rsn_pmksa_cache_entry *pmksa, u16 status); + #endif /* CONFIG_PASN */ #ifdef __cplusplus diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c new file mode 100644 index 000000000..30fc51204 --- /dev/null +++ b/src/pasn/pasn_responder.c @@ -0,0 +1,1000 @@ +/* + * PASN responder processing + * + * Copyright (C) 2019, Intel Corporation + * Copyright (C) 2022, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/wpa_common.h" +#include "common/sae.h" +#include "common/ieee802_11_common.h" +#include "common/ieee802_11_defs.h" +#include "crypto/sha384.h" +#include "crypto/sha256.h" +#include "crypto/random.h" +#include "crypto/crypto.h" +#include "ap/hostapd.h" +#include "ap/comeback_token.h" +#include "ap/ieee802_1x.h" +#include "ap/pmksa_cache_auth.h" +#include "pasn_common.h" + +#ifdef CONFIG_PASN +#ifdef CONFIG_SAE + +static int pasn_wd_handle_sae_commit(struct wpas_pasn *pasn, + const u8 *own_addr, const u8 *peer_addr, + struct wpabuf *wd) +{ + const u8 *data; + size_t buf_len; + u16 res, alg, seq, status; + int groups[] = { pasn->group, 0 }; + int ret; + + if (!wd) + return -1; + + data = wpabuf_head_u8(wd); + buf_len = wpabuf_len(wd); + + if (buf_len < 6) { + wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu", + buf_len); + return -1; + } + + alg = WPA_GET_LE16(data); + seq = WPA_GET_LE16(data + 2); + status = WPA_GET_LE16(data + 4); + + wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u", + alg, seq, status); + + if (alg != WLAN_AUTH_SAE || seq != 1 || + status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { + wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit"); + return -1; + } + + sae_clear_data(&pasn->sae); + pasn->sae.state = SAE_NOTHING; + + ret = sae_set_group(&pasn->sae, pasn->group); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group"); + return -1; + } + + if (!pasn->password || !pasn->pt) { + wpa_printf(MSG_DEBUG, "PASN: No SAE PT found"); + return -1; + } + + ret = sae_prepare_commit_pt(&pasn->sae, pasn->pt, own_addr, peer_addr, + NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit"); + return -1; + } + + res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0, + groups, 0); + if (res != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit"); + return -1; + } + + /* Process the commit message and derive the PMK */ + ret = sae_process_commit(&pasn->sae); + if (ret) { + wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit"); + return -1; + } + + pasn->sae.state = SAE_COMMITTED; + + return 0; +} + + +static int pasn_wd_handle_sae_confirm(struct wpas_pasn *pasn, + const u8 *peer_addr, struct wpabuf *wd) +{ + const u8 *data; + size_t buf_len; + u16 res, alg, seq, status; + + if (!wd) + return -1; + + data = wpabuf_head_u8(wd); + buf_len = wpabuf_len(wd); + + if (buf_len < 6) { + wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu", + buf_len); + return -1; + } + + alg = WPA_GET_LE16(data); + seq = WPA_GET_LE16(data + 2); + status = WPA_GET_LE16(data + 4); + + wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u", + alg, seq, status); + + if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm"); + return -1; + } + + res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6); + if (res != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm"); + return -1; + } + + pasn->sae.state = SAE_ACCEPTED; + + /* + * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with + * PASN/SAE should only be allowed with future PASN only. For now do not + * restrict this only for PASN. + */ + if (pasn->disable_pmksa_caching) + return 0; + + wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", + pasn->sae.pmk, pasn->sae.pmk_len); + if (!pasn->sae.akmp) + pasn->sae.akmp = WPA_KEY_MGMT_SAE; + + pmksa_cache_auth_add(pasn->pmksa, pasn->sae.pmk, pasn->sae.pmk_len, + pasn->sae.pmkid, NULL, 0, pasn->own_addr, + peer_addr, 0, NULL, pasn->sae.akmp); + return 0; +} + + +static struct wpabuf * pasn_get_sae_wd(struct wpas_pasn *pasn) +{ + struct wpabuf *buf = NULL; + u8 *len_ptr; + size_t len; + + /* Need to add the entire Authentication frame body */ + buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN); + if (!buf) { + wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer"); + return NULL; + } + + /* Need to add the entire authentication frame body for the commit */ + len_ptr = wpabuf_put(buf, 2); + wpabuf_put_le16(buf, WLAN_AUTH_SAE); + wpabuf_put_le16(buf, 1); + wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); + + /* Write the actual commit and update the length accordingly */ + sae_write_commit(&pasn->sae, buf, NULL, 0); + len = wpabuf_len(buf); + WPA_PUT_LE16(len_ptr, len - 2); + + /* Need to add the entire Authentication frame body for the confirm */ + len_ptr = wpabuf_put(buf, 2); + wpabuf_put_le16(buf, WLAN_AUTH_SAE); + wpabuf_put_le16(buf, 2); + wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + + sae_write_confirm(&pasn->sae, buf); + WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2); + + pasn->sae.state = SAE_CONFIRMED; + + return buf; +} + +#endif /* CONFIG_SAE */ + + +#ifdef CONFIG_FILS + +static struct wpabuf * pasn_get_fils_wd(struct wpas_pasn *pasn) +{ + struct pasn_fils *fils = &pasn->fils; + struct wpabuf *buf = NULL; + + if (!fils->erp_resp) { + wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp"); + return NULL; + } + + buf = wpabuf_alloc(1500); + if (!buf) + return NULL; + + /* Add the authentication algorithm */ + wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK); + + /* Authentication Transaction seq# */ + wpabuf_put_le16(buf, 2); + + /* Status Code */ + wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + + /* Own RSNE */ + wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher); + + /* FILS Nonce */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN); + wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE); + wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN); + + /* FILS Session */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN); + wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION); + wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN); + + /* Wrapped Data */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp)); + wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA); + wpabuf_put_buf(buf, fils->erp_resp); + + return buf; +} + +#endif /* CONFIG_FILS */ + +static struct wpabuf * pasn_get_wrapped_data(struct wpas_pasn *pasn) +{ + switch (pasn->akmp) { + case WPA_KEY_MGMT_PASN: + /* no wrapped data */ + return NULL; + case WPA_KEY_MGMT_SAE: +#ifdef CONFIG_SAE + return pasn_get_sae_wd(pasn); +#else /* CONFIG_SAE */ + wpa_printf(MSG_ERROR, + "PASN: SAE: Cannot derive wrapped data"); + return NULL; +#endif /* CONFIG_SAE */ + case WPA_KEY_MGMT_FILS_SHA256: + case WPA_KEY_MGMT_FILS_SHA384: +#ifdef CONFIG_FILS + return pasn_get_fils_wd(pasn); +#endif /* CONFIG_FILS */ + /* fall through */ + case WPA_KEY_MGMT_FT_PSK: + case WPA_KEY_MGMT_FT_IEEE8021X: + case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: + default: + wpa_printf(MSG_ERROR, + "PASN: TODO: Wrapped data for akmp=0x%x", + pasn->akmp); + return NULL; + } +} + + +static int +pasn_derive_keys(struct wpas_pasn *pasn, + const u8 *own_addr, const u8 *peer_addr, + const u8 *cached_pmk, size_t cached_pmk_len, + struct wpa_pasn_params_data *pasn_data, + struct wpabuf *wrapped_data, + struct wpabuf *secret) +{ + static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'}; + u8 pmk[PMK_LEN_MAX]; + u8 pmk_len; + int ret; + + os_memset(pmk, 0, sizeof(pmk)); + pmk_len = 0; + + if (!cached_pmk || !cached_pmk_len) + wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry"); + + if (pasn->akmp == WPA_KEY_MGMT_PASN) { + wpa_printf(MSG_DEBUG, "PASN: Using default PMK"); + + pmk_len = WPA_PASN_PMK_LEN; + os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk)); + } else if (cached_pmk && cached_pmk_len) { + wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry"); + + pmk_len = cached_pmk_len; + os_memcpy(pmk, cached_pmk, cached_pmk_len); + } else { + switch (pasn->akmp) { +#ifdef CONFIG_SAE + case WPA_KEY_MGMT_SAE: + if (pasn->sae.state == SAE_COMMITTED) { + pmk_len = PMK_LEN; + os_memcpy(pmk, pasn->sae.pmk, PMK_LEN); + break; + } +#endif /* CONFIG_SAE */ + /* fall through */ + default: + /* TODO: Derive PMK based on wrapped data */ + wpa_printf(MSG_DEBUG, + "PASN: Missing PMK derivation"); + return -1; + } + } + + ret = pasn_pmk_to_ptk(pmk, pmk_len, peer_addr, own_addr, + wpabuf_head(secret), wpabuf_len(secret), + &pasn->ptk, pasn->akmp, + pasn->cipher, pasn->kdk_len); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK"); + return -1; + } + + if (pasn->secure_ltf) { + ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, + pasn->cipher); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed to derive LTF keyseed"); + return -1; + } + } + + wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived"); + return 0; +} + + +static void handle_auth_pasn_comeback(struct wpas_pasn *pasn, + const u8 *own_addr, const u8 *peer_addr, + u16 group) +{ + struct wpabuf *buf, *comeback; + int ret; + + wpa_printf(MSG_DEBUG, + "PASN: Building comeback frame 2. Comeback after=%u", + pasn->comeback_after); + + buf = wpabuf_alloc(1500); + if (!buf) + return; + + wpa_pasn_build_auth_header(buf, own_addr, own_addr, peer_addr, 2, + WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY); + + /* + * Do not include the group as a part of the token since it is not going + * to be used. + */ + comeback = auth_build_token_req(&pasn->last_comeback_key_update, + pasn->comeback_key, pasn->comeback_idx, + pasn->comeback_pending_idx, + sizeof(u16) * COMEBACK_PENDING_IDX_SIZE, + 0, peer_addr, 0); + if (!comeback) { + wpa_printf(MSG_DEBUG, + "PASN: Failed sending auth with comeback"); + wpabuf_free(buf); + return; + } + + wpa_pasn_add_parameter_ie(buf, group, + WPA_PASN_WRAPPED_DATA_NO, + NULL, 0, comeback, + pasn->comeback_after); + wpabuf_free(comeback); + + wpa_printf(MSG_DEBUG, + "PASN: comeback: STA=" MACSTR, MAC2STR(peer_addr)); + + ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf), + wpabuf_len(buf), 0, 0, 0); + if (ret) + wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2"); + + wpabuf_free(buf); +} + + +int handle_auth_pasn_resp(struct wpas_pasn *pasn, const u8 *own_addr, + const u8 *peer_addr, + struct rsn_pmksa_cache_entry *pmksa, u16 status) +{ + struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL; + struct wpabuf *rsn_buf = NULL; + u8 mic[WPA_PASN_MAX_MIC_LEN]; + u8 mic_len; + u8 *ptr; + const u8 *frame, *data, *rsn_ie, *rsnxe_ie; + u8 *data_buf = NULL; + size_t frame_len, data_len; + int ret; + const u8 *pmkid = NULL; + + wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status); + + buf = wpabuf_alloc(1500); + if (!buf) + goto fail; + + wpa_pasn_build_auth_header(buf, own_addr, own_addr, peer_addr, 2, + status); + + if (status != WLAN_STATUS_SUCCESS) + goto done; + + if (pmksa && pasn->custom_pmkid_valid) + pmkid = pasn->custom_pmkid; + else if (pmksa) { + pmkid = pmksa->pmkid; +#ifdef CONFIG_SAE + } else if (pasn->akmp == WPA_KEY_MGMT_SAE) { + wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID"); + pmkid = pasn->sae.pmkid; +#endif /* CONFIG_SAE */ +#ifdef CONFIG_FILS + } else if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || + pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { + wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID"); + pmkid = pasn->fils.erp_pmkid; +#endif /* CONFIG_FILS */ + } + + if (wpa_pasn_add_rsne(buf, pmkid, + pasn->akmp, pasn->cipher) < 0) + goto fail; + + /* No need to derive PMK if PMKSA is given */ + if (!pmksa) + wrapped_data_buf = pasn_get_wrapped_data(pasn); + else + pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO; + + /* Get public key */ + pubkey = crypto_ecdh_get_pubkey(pasn->ecdh, 0); + pubkey = wpabuf_zeropad(pubkey, + crypto_ecdh_prime_len(pasn->ecdh)); + if (!pubkey) { + wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey"); + goto fail; + } + + wpa_pasn_add_parameter_ie(buf, pasn->group, + pasn->wrapped_data_format, + pubkey, true, NULL, 0); + + if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0) + goto fail; + + wpabuf_free(wrapped_data_buf); + wrapped_data_buf = NULL; + wpabuf_free(pubkey); + pubkey = NULL; + + /* Add RSNXE if needed */ + rsnxe_ie = pasn->rsnxe_ie; + if (rsnxe_ie) + wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]); + + /* Add the mic */ + mic_len = pasn_mic_len(pasn->akmp, pasn->cipher); + wpabuf_put_u8(buf, WLAN_EID_MIC); + wpabuf_put_u8(buf, mic_len); + ptr = wpabuf_put(buf, mic_len); + + os_memset(ptr, 0, mic_len); + + frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN; + frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN; + + if (pasn->rsn_ie && pasn->rsn_ie_len) { + rsn_ie = pasn->rsn_ie; + } else { + /* + * Note: when pasn->rsn_ie is NULL, it is likely that Beacon + * frame RSNE is not initialized. This is possible in case of + * PASN authentication used for Wi-Fi Aware for which Beacon + * frame RSNE and RSNXE are same as RSNE and RSNXE in the + * Authentication frame. + */ + rsn_buf = wpabuf_alloc(500); + if (!rsn_buf) + goto fail; + + if (wpa_pasn_add_rsne(rsn_buf, pmkid, + pasn->akmp, pasn->cipher) < 0) + goto fail; + + rsn_ie = wpabuf_head_u8(rsn_buf); + } + + /* + * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also + * MDE, etc. Thus, do not use the returned length but instead use the + * length specified in the IE header. + */ + data_len = rsn_ie[1] + 2; + if (rsnxe_ie) { + data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2); + if (!data_buf) + goto fail; + + os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2); + os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2); + data_len += rsnxe_ie[1] + 2; + data = data_buf; + } else { + data = rsn_ie; + } + + ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher, + own_addr, peer_addr, data, data_len, + frame, frame_len, mic); + os_free(data_buf); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation"); + goto fail; + } + +#ifdef CONFIG_TESTING_OPTIONS + if (pasn->corrupt_mic) { + wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC"); + mic[0] = ~mic[0]; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + os_memcpy(ptr, mic, mic_len); + +done: + wpa_printf(MSG_DEBUG, + "PASN: Building frame 2: success; resp STA=" MACSTR, + MAC2STR(peer_addr)); + + ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf), + wpabuf_len(buf), 0, 0, 0); + if (ret) + wpa_printf(MSG_INFO, "send_auth_reply: Send failed"); + + wpabuf_free(rsn_buf); + wpabuf_free(buf); + return ret; +fail: + wpabuf_free(wrapped_data_buf); + wpabuf_free(pubkey); + wpabuf_free(rsn_buf); + wpabuf_free(buf); + return -1; +} + + +int handle_auth_pasn_1(struct wpas_pasn *pasn, + const u8 *own_addr, const u8 *peer_addr, + const struct ieee80211_mgmt *mgmt, size_t len) +{ + struct ieee802_11_elems elems; + struct wpa_ie_data rsn_data; + struct wpa_pasn_params_data pasn_params; + struct rsn_pmksa_cache_entry *pmksa = NULL; + const u8 *cached_pmk = NULL; + size_t cached_pmk_len = 0; + struct wpabuf *wrapped_data = NULL, *secret = NULL; + const int *groups = pasn->pasn_groups; + static const int default_groups[] = { 19, 0 }; + u16 status = WLAN_STATUS_SUCCESS; + int ret, inc_y; + bool derive_keys; + u32 i; + + if (!groups) + groups = default_groups; + + if (ieee802_11_parse_elems(mgmt->u.auth.variable, + len - offsetof(struct ieee80211_mgmt, + u.auth.variable), + &elems, 0) == ParseFailed) { + wpa_printf(MSG_DEBUG, + "PASN: Failed parsing Authentication frame"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2, + &rsn_data); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE"); + status = WLAN_STATUS_INVALID_RSNIE; + goto send_resp; + } + + ret = wpa_pasn_validate_rsne(&rsn_data); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE"); + status = WLAN_STATUS_INVALID_RSNIE; + goto send_resp; + } + + if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) || + !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) { + wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher"); + status = WLAN_STATUS_INVALID_RSNIE; + goto send_resp; + } + + pasn->akmp = rsn_data.key_mgmt; + pasn->cipher = rsn_data.pairwise_cipher; + + if (pasn->derive_kdk && + ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, + WLAN_RSNX_CAPAB_SECURE_LTF)) + pasn->secure_ltf = true; + + if (pasn->derive_kdk) + pasn->kdk_len = WPA_KDK_MAX_LEN; + else + pasn->kdk_len = 0; + + wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len); + + if (!elems.pasn_params || !elems.pasn_params_len) { + wpa_printf(MSG_DEBUG, + "PASN: No PASN Parameters element found"); + status = WLAN_STATUS_INVALID_PARAMETERS; + goto send_resp; + } + + ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3, + elems.pasn_params_len + 3, + false, &pasn_params); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed validation of PASN Parameters IE"); + status = WLAN_STATUS_INVALID_PARAMETERS; + goto send_resp; + } + + for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++) + ; + + if (!pasn_params.group || groups[i] != pasn_params.group) { + wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed", + pasn_params.group); + status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + goto send_resp; + } + + if (!pasn_params.pubkey || !pasn_params.pubkey_len) { + wpa_printf(MSG_DEBUG, "PASN: Invalid public key"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + if (pasn_params.comeback) { + wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token"); + + ret = check_comeback_token(pasn->comeback_key, + pasn->comeback_pending_idx, + peer_addr, + pasn_params.comeback, + pasn_params.comeback_len); + + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + } else if (pasn->use_anti_clogging) { + wpa_printf(MSG_DEBUG, "PASN: Respond with comeback"); + handle_auth_pasn_comeback(pasn, own_addr, peer_addr, + pasn_params.group); + return -1; + } + + pasn->ecdh = crypto_ecdh_init(pasn_params.group); + if (!pasn->ecdh) { + wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + pasn->group = pasn_params.group; + + if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) { + inc_y = 1; + } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 || + pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) { + inc_y = 0; + } else { + wpa_printf(MSG_DEBUG, + "PASN: Invalid first octet in pubkey=0x%x", + pasn_params.pubkey[0]); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y, + pasn_params.pubkey + 1, + pasn_params.pubkey_len - 1); + if (!secret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + derive_keys = true; + if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) { + wrapped_data = ieee802_11_defrag(&elems, + WLAN_EID_EXTENSION, + WLAN_EID_EXT_WRAPPED_DATA); + if (!wrapped_data) { + wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + +#ifdef CONFIG_SAE + if (pasn->akmp == WPA_KEY_MGMT_SAE) { + ret = pasn_wd_handle_sae_commit(pasn, own_addr, + peer_addr, + wrapped_data); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed processing SAE commit"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + } +#endif /* CONFIG_SAE */ +#ifdef CONFIG_FILS + if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || + pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { + if (!pasn->fils_wd_valid) { + wpa_printf(MSG_DEBUG, + "PASN: Invalid FILS wrapped data"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + wpa_printf(MSG_DEBUG, + "PASN: FILS: Pending AS response"); + + /* + * With PASN/FILS, keys can be derived only after a + * response from the AS is processed. + */ + derive_keys = false; + } +#endif /* CONFIG_FILS */ + } + + pasn->wrapped_data_format = pasn_params.wrapped_data_format; + + ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher, + ((const u8 *) mgmt) + IEEE80211_HDRLEN, + len - IEEE80211_HDRLEN, pasn->hash); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + if (!derive_keys) { + wpa_printf(MSG_DEBUG, "PASN: Storing secret"); + pasn->secret = secret; + wpabuf_free(wrapped_data); + return 0; + } + + if (rsn_data.num_pmkid) { + if (wpa_key_mgmt_ft(pasn->akmp)) { +#ifdef CONFIG_IEEE80211R_AP + wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1"); + + if (!pasn->pmk_r1_len) { + wpa_printf(MSG_DEBUG, + "PASN: FT: Failed getting PMK-R1"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + cached_pmk = pasn->pmk_r1; + cached_pmk_len = pasn->pmk_r1_len; +#else /* CONFIG_IEEE80211R_AP */ + wpa_printf(MSG_DEBUG, "PASN: FT: Not supported"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; +#endif /* CONFIG_IEEE80211R_AP */ + } else { + wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry"); + + if (pasn->pmksa) { + const u8 *pmkid = NULL; + + if (pasn->custom_pmkid_valid) { + ret = pasn->validate_custom_pmkid( + pasn->cb_ctx, peer_addr, + rsn_data.pmkid); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed custom PMKID validation"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + } else { + pmkid = rsn_data.pmkid; + } + + pmksa = pmksa_cache_auth_get(pasn->pmksa, + peer_addr, + pmkid); + if (pmksa) { + cached_pmk = pmksa->pmk; + cached_pmk_len = pmksa->pmk_len; + } + } + } + } else { + wpa_printf(MSG_DEBUG, "PASN: No PMKID specified"); + } + + ret = pasn_derive_keys(pasn, own_addr, peer_addr, + cached_pmk, cached_pmk_len, + &pasn_params, wrapped_data, secret); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher, + ((const u8 *) mgmt) + IEEE80211_HDRLEN, + len - IEEE80211_HDRLEN, pasn->hash); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } + +send_resp: + ret = handle_auth_pasn_resp(pasn, own_addr, peer_addr, pmksa, status); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to send response"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } else { + wpa_printf(MSG_DEBUG, + "PASN: Success handling transaction == 1"); + } + + wpabuf_free(secret); + wpabuf_free(wrapped_data); + + if (status != WLAN_STATUS_SUCCESS) + return -1; + + return 0; +} + + +int handle_auth_pasn_3(struct wpas_pasn *pasn, const u8 *own_addr, + const u8 *peer_addr, + const struct ieee80211_mgmt *mgmt, size_t len) +{ + struct ieee802_11_elems elems; + struct wpa_pasn_params_data pasn_params; + struct wpabuf *wrapped_data = NULL; + u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN]; + u8 mic_len; + int ret; + + if (ieee802_11_parse_elems(mgmt->u.auth.variable, + len - offsetof(struct ieee80211_mgmt, + u.auth.variable), + &elems, 0) == ParseFailed) { + wpa_printf(MSG_DEBUG, + "PASN: Failed parsing Authentication frame"); + goto fail; + } + + /* Check that the MIC IE exists. Save it and zero out the memory. */ + mic_len = pasn_mic_len(pasn->akmp, pasn->cipher); + if (!elems.mic || elems.mic_len != mic_len) { + wpa_printf(MSG_DEBUG, + "PASN: Invalid MIC. Expecting len=%u", mic_len); + goto fail; + } else { + os_memcpy(mic, elems.mic, mic_len); + /* TODO: Clean this up.. Should not modify received frame + * buffer. */ + os_memset((u8 *) elems.mic, 0, mic_len); + } + + if (!elems.pasn_params || !elems.pasn_params_len) { + wpa_printf(MSG_DEBUG, + "PASN: No PASN Parameters element found"); + goto fail; + } + + ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3, + elems.pasn_params_len + 3, + false, &pasn_params); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed validation of PASN Parameters IE"); + goto fail; + } + + if (pasn_params.pubkey || pasn_params.pubkey_len) { + wpa_printf(MSG_DEBUG, + "PASN: Public key should not be included"); + goto fail; + } + + /* Verify the MIC */ + ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher, + peer_addr, own_addr, + pasn->hash, mic_len * 2, + (u8 *) &mgmt->u.auth, + len - offsetof(struct ieee80211_mgmt, u.auth), + out_mic); + + wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len); + if (ret || os_memcmp(mic, out_mic, mic_len) != 0) { + wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification"); + goto fail; + } + + if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) { + wrapped_data = ieee802_11_defrag(&elems, + WLAN_EID_EXTENSION, + WLAN_EID_EXT_WRAPPED_DATA); + + if (!wrapped_data) { + wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data"); + goto fail; + } + +#ifdef CONFIG_SAE + if (pasn->akmp == WPA_KEY_MGMT_SAE) { + ret = pasn_wd_handle_sae_confirm(pasn, peer_addr, + wrapped_data); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed processing SAE confirm"); + wpabuf_free(wrapped_data); + goto fail; + } + } +#endif /* CONFIG_SAE */ +#ifdef CONFIG_FILS + if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || + pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { + if (wrapped_data) { + wpa_printf(MSG_DEBUG, + "PASN: FILS: Ignore wrapped data"); + } + } +#endif /* CONFIG_FILS */ + wpabuf_free(wrapped_data); + } + + wpa_printf(MSG_INFO, + "PASN: Success handling transaction == 3. Store PTK"); + return 0; + +fail: + return -1; +} + +#endif /* CONFIG_PASN */ diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index ba7f7588a..158612765 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -950,6 +950,7 @@ ifdef NEED_AP_MLME OBJS += src/ap/wmm.c OBJS += src/ap/ap_list.c OBJS += src/ap/comeback_token.c +OBJS += src/pasn/pasn_responder.c OBJS += src/ap/ieee802_11.c OBJS += src/ap/hw_features.c OBJS += src/ap/dfs.c diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 35577cabe..6dd5432a7 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -985,6 +985,7 @@ ifdef NEED_AP_MLME OBJS += ../src/ap/wmm.o OBJS += ../src/ap/ap_list.o OBJS += ../src/ap/comeback_token.o +OBJS += ../src/pasn/pasn_responder.o OBJS += ../src/ap/ieee802_11.o OBJS += ../src/ap/hw_features.o OBJS += ../src/ap/dfs.o