From patchwork Mon Feb 24 09:15:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peer, Ilan" X-Patchwork-Id: 1242964 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20170209 header.b=bAj1Rn16; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48Qxyx4GZ4z9sPk for ; Mon, 24 Feb 2020 20:46:17 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=bfzosBk1yp+v82G78a7aDPUS6E8NDIiqPPg2GZfF9Ew=; b=bAj1Rn16147cLEaT8VDKqetTC8 mVtzOEEtVK9ZpTpztil9mMtfUjQYgMNrfzRICw8OpMw3xGeJ3PmbPAPPTQbq0y84zulOff6mnB5qH kMa2D62mqdLbm5aPEiCu8C3cCV8UY5EtcvHbDUJsm1wVupV5F0d+NWRwIiV2kyet/Q7GwKAyz2L+c OdAZgo99UDS0U6LoBeZ5p0mmeSSes7EH93EmfLcQfdtVqfqb8cYeSX+4KK5YPhpZ0cjnObOViWggZ 1y+mHypCwROZIT7B0u34e2lNqt7qyyUQ1JvDH4tUVsYCRuYGjYR+6brjjU5UVw2PBQdbGaoRWikOB 1XVv6jeQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1j6AJV-0008Jy-0y; Mon, 24 Feb 2020 09:46:09 +0000 Received: from mga17.intel.com ([192.55.52.151]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1j69qS-0007nA-3r for hostap@lists.infradead.org; Mon, 24 Feb 2020 09:16:18 +0000 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Feb 2020 01:15:53 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,479,1574150400"; d="scan'208";a="225914548" Received: from jed01681.jer.intel.com ([10.12.190.127]) by orsmga007.jf.intel.com with ESMTP; 24 Feb 2020 01:15:51 -0800 From: Ilan Peer To: hostap@lists.infradead.org Subject: [PATCH 13/14] AP: Add support for PASN processing to the SME Date: Mon, 24 Feb 2020 11:15:28 +0200 Message-Id: <20200224091529.15259-14-ilan.peer@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200224091529.15259-1-ilan.peer@intel.com> References: <20200224091529.15259-1-ilan.peer@intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200224_011608_289541_998E1809 X-CRM114-Status: GOOD ( 18.68 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.3 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [192.55.52.151 listed in list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Ilan Peer MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Signed-off-by: Ilan Peer --- src/ap/ieee802_11.c | 517 +++++++++++++++++++++++++++++++++++++++++++- src/ap/sta_info.c | 20 ++ src/ap/sta_info.h | 20 ++ 3 files changed, 556 insertions(+), 1 deletion(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 26b5a06ed2..7a16ec66b6 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2224,6 +2224,496 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, } +#ifdef CONFIG_PASN + +static struct wpabuf *pasn_get_wrapped_data(struct hostapd_data *hapd, + struct sta_info *sta) +{ + switch (sta->pasn->akmp) { + case WPA_KEY_MGMT_PASN: + /* no wrapped data */ + return NULL; + case WPA_KEY_MGMT_SAE: + case WPA_KEY_MGMT_FILS_SHA256: + case WPA_KEY_MGMT_FILS_SHA384: + 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", + sta->pasn->akmp); + return NULL; + } +} + + +static int +pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta, + struct rsn_pmksa_cache_entry *pmksa, + 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 (!pmksa) + wpa_printf(MSG_DEBUG, "PASN: no valid PMKSA entry"); + + if (sta->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 (pmksa) { + wpa_printf(MSG_DEBUG, "PASN: using PMKSA entry"); + + pmk_len = pmksa->pmk_len; + os_memcpy(pmk, pmksa->pmk, pmksa->pmk_len); + } else { + /* TODO: derive PMK based on wrapped data */ + wpa_printf(MSG_DEBUG, + "PASN: missing implementation to derive PMK"); + + return -1; + } + + ret = pasn_pmk_to_ptk(pmk, pmk_len, + sta->addr, hapd->own_addr, + wpabuf_head(secret), wpabuf_len(secret), + &sta->pasn->ptk, sta->pasn->akmp, + sta->pasn->cipher, + WPA_HLTK_MAX_LEN); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: failed to derive PTK"); + return -1; + } + + wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived"); + return 0; +} + + +static int handle_auth_pasn_resp(struct hostapd_data *hapd, + struct sta_info *sta, + struct rsn_pmksa_cache_entry *pmksa, + u16 status) +{ + struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL; + u8 mic[WPA_PASN_MAX_MIC_LEN]; + u8 mic_len, data_len; + u8 *ptr; + const u8 *data, *rsn_ie; + size_t rsn_ie_len; + int ret; + + 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, hapd->own_addr, hapd->own_addr, + sta->addr, 2, status); + + if (status != WLAN_STATUS_SUCCESS) + goto done; + + wpa_pasn_add_rsne(buf, pmksa ? pmksa->pmkid : NULL, + sta->pasn->akmp, sta->pasn->cipher); + + /* No need to derive PMK if PMKSA is given */ + if (!pmksa) + wrapped_data_buf = pasn_get_wrapped_data(hapd, sta); + else + sta->pasn->wrapped_data_format = WPA_PASN_NO_WRAPPED_DATA; + + /* Get public key */ + pubkey = crypto_ecdh_get_pubkey(sta->pasn->ecdh, 0); + pubkey = wpabuf_zeropad(pubkey, + crypto_ecdh_prime_len(sta->pasn->ecdh)); + if (!pubkey) { + wpa_printf(MSG_DEBUG, "PASN: failed to get pubkey"); + goto fail; + } + + wpa_pasn_add_parameter_ie(buf, sta->pasn->group, + sta->pasn->wrapped_data_format, + pubkey, NULL, 0); + + wpa_pasn_add_wrapped_data(buf, wrapped_data_buf); + + wpabuf_free(wrapped_data_buf); + wrapped_data_buf = NULL; + wpabuf_free(pubkey); + pubkey = NULL; + + /* Add the mic */ + mic_len = pasn_mic_len(sta->pasn->akmp, sta->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); + + data = wpabuf_head(buf) + IEEE80211_HDRLEN; + data_len = wpabuf_len(buf) - IEEE80211_HDRLEN; + + rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len); + if (!rsn_ie || !rsn_ie_len) + goto fail; + + /* + * Note: the wpa_auth_get_wpa_ie() might return not only the RSN IE but + * also the MD IE etc. Thus, do not use the returned length but instead + * use the length specified in the IE header. + */ + ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher, + hapd->own_addr, sta->addr, + rsn_ie, rsn_ie[1] + 2, + data, data_len, + mic); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: frame 3: Failed mic calculation"); + goto fail; + } + + os_memcpy(ptr, mic, mic_len); + +done: + wpa_printf(MSG_DEBUG, "PASN: building frame 2: success"); + + wpa_printf(MSG_DEBUG, "PANS: resp: STA=" MACSTR, MAC2STR(sta->addr)); + + ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0, + NULL, 0, 0); + if (ret) + wpa_printf(MSG_INFO, "send_auth_reply: send failed"); + + wpabuf_free(buf); + return ret; +fail: + wpabuf_free(wrapped_data_buf); + wpabuf_free(pubkey); + wpabuf_free(buf); + return -1; +} + + +static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta, + 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; + struct wpabuf *wrapped_data = NULL, *secret = NULL; + int *groups = hapd->conf->pasn_groups; + int default_groups[] = { 19, 0 }; + u16 status = WLAN_STATUS_SUCCESS; + int ret; + 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 & hapd->conf->wpa_key_mgmt) || + !(rsn_data.pairwise_cipher & hapd->conf->rsn_pairwise)) { + wpa_printf(MSG_DEBUG, "PASN: mismatch in akmp/cipher"); + status = WLAN_STATUS_INVALID_RSNIE; + goto send_resp; + } + + sta->pasn->akmp = rsn_data.key_mgmt; + sta->pasn->cipher = rsn_data.pairwise_cipher; + + 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, + &pasn_params); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: failed validation 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; + } + + sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group); + if (!sta->pasn->ecdh) { + wpa_printf(MSG_DEBUG, "PASN: Failed init ECDH"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + sta->pasn->group = pasn_params.group; + + secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, 0, + pasn_params.pubkey, + pasn_params.pubkey_len); + if (!secret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive secret"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + if (pasn_params.wrapped_data_format != WPA_PASN_NO_WRAPPED_DATA) { + 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; + } + } + + sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format; + + if (rsn_data.num_pmkid) { + wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry"); + + pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, + rsn_data.pmkid); + } else { + wpa_printf(MSG_DEBUG, "PASN: No PMKID specified"); + pmksa = NULL; + } + + ret = pasn_derive_keys(hapd, sta, pmksa, &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(sta->pasn->akmp, sta->pasn->cipher, + ((u8 *)mgmt) + IEEE80211_HDRLEN, + len - IEEE80211_HDRLEN, + sta->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(hapd, sta, 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) + ap_free_sta(hapd, sta); +} + + +static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta, + 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(sta->pasn->akmp, sta->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); + 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, + &pasn_params); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: failed validation 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(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher, + sta->addr, hapd->own_addr, + sta->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)) { + wpa_printf(MSG_DEBUG, "PASN: failed MIC verification"); + goto fail; + } + + if (pasn_params.wrapped_data_format != WPA_PASN_NO_WRAPPED_DATA) { + 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; + } + + /* TODO: handle wrapped data */ + wpabuf_free(wrapped_data); + } + + wpa_printf(MSG_INFO, + "PASN: success handling transaction == 3. Store PTK"); + + ptksa_cache_add(hapd->ptksa, sta->addr, sta->pasn->cipher, 43200, + &sta->pasn->ptk); +fail: + ap_free_sta(hapd, sta); +} + + +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) +{ + if (hapd->conf->wpa != WPA_PROTO_RSN) { + wpa_printf(MSG_INFO, "PASN: RSN is not configured"); + return; + } + + wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR, + MAC2STR(sta->addr)); + + if (trans_seq == 1) { + if (sta->pasn) { + wpa_printf(MSG_DEBUG, + "PASN: not expecting transaction == 1"); + return; + } + + if (status != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, + "PASN: failure status in transaction == 1"); + return; + } + + sta->pasn = os_zalloc(sizeof(*sta->pasn)); + if (!sta->pasn) { + wpa_printf(MSG_DEBUG, + "PASN: failed to allocate pasn context"); + return; + } + + handle_auth_pasn_1(hapd, sta, mgmt, len); + } else if (trans_seq == 3) { + if (!sta->pasn) { + wpa_printf(MSG_DEBUG, + "PASN: not expecting transaction == 3"); + return; + } + + if (status != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, + "PASN: failure status in transaction == 3"); + ap_free_sta_pasn(hapd, sta); + return; + } + + handle_auth_pasn_3(hapd, sta, mgmt, len); + } else { + wpa_printf(MSG_DEBUG, + "PASN: invalid transaction. ignore"); + } +} + +#endif /* CONFIG_PASN */ + + static void handle_auth(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int rssi, int from_queue) @@ -2310,6 +2800,11 @@ static void handle_auth(struct hostapd_data *hapd, hapd->conf->fils_dh_group && auth_alg == WLAN_AUTH_FILS_SK_PFS) || #endif /* CONFIG_FILS */ +#ifdef CONFIG_PASN + (hapd->conf->wpa && + (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) && + auth_alg == WLAN_AUTH_PASN) || +#endif /* CONFIG_PASN*/ ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && auth_alg == WLAN_AUTH_SHARED_KEY))) { wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)", @@ -2319,6 +2814,9 @@ static void handle_auth(struct hostapd_data *hapd, } if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE || +#ifdef CONFIG_PASN + (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) || +#endif /* CONFIG_PASN*/ (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)", auth_transaction); @@ -2440,6 +2938,14 @@ static void handle_auth(struct hostapd_data *hapd, return; } #endif /* CONFIG_MESH */ +#ifdef CONFIG_PASN + if (auth_alg == WLAN_AUTH_PASN && sta->flags & WLAN_STA_ASSOC) { + wpa_printf(MSG_DEBUG, + "PASN: auth: existing station: " MACSTR, + MAC2STR(sta->addr)); + return; + } +#endif /* CONFIG_PASN */ } else { #ifdef CONFIG_MESH if (hapd->conf->mesh & MESH_ENABLED) { @@ -2500,11 +3006,14 @@ static void handle_auth(struct hostapd_data *hapd, * to allow the original connection work until the attempt can complete * (re)association, so that unprotected Authentication frame cannot be * used to bypass PMF protection. + * + * PASN authentication does not require adding/removing station to the + * driver so skip this flow in case of PASN authentication. */ if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) && (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) && !(hapd->conf->mesh & MESH_ENABLED) && - !(sta->added_unassoc)) { + !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) { /* * If a station that is already associated to the AP, is trying * to authenticate again, remove the STA entry, in order to make @@ -2611,6 +3120,12 @@ static void handle_auth(struct hostapd_data *hapd, handle_auth_fils_finish); return; #endif /* CONFIG_FILS */ +#ifdef CONFIG_PASN + case WLAN_AUTH_PASN: + handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction, + status_code); + return; +#endif /* CONFIG_PASN */ } fail: diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 87a9fd409c..bb2566d65b 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -155,6 +155,22 @@ void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta) sta_ip6addr_del(hapd, sta); } +#ifdef CONFIG_PASN + +void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta) +{ + wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR, + MAC2STR(sta->addr)); + + if (sta->pasn) { + if (sta->pasn->ecdh) + crypto_ecdh_deinit(sta->pasn->ecdh); + os_free(sta->pasn); + sta->pasn = NULL; + } +} + +#endif /* CONFIG_PASN */ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) { @@ -369,6 +385,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta); #endif /* CONFIG_WNM_AP */ +#ifdef CONFIG_PASN + ap_free_sta_pasn(hapd, sta); +#endif /* CONFIG_PASN */ + os_free(sta->ifname_wds); #ifdef CONFIG_TESTING_OPTIONS diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 8ff6ac62fe..1957d8ecd4 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -14,6 +14,7 @@ #include "vlan.h" #include "common/wpa_common.h" #include "common/ieee802_11_defs.h" +#include "crypto/sha384.h" /* STA flags */ #define WLAN_STA_AUTH BIT(0) @@ -62,6 +63,19 @@ struct pending_eapol_rx { struct os_reltime rx_time; }; +struct pasn_data { + int akmp; + int cipher; + u16 group; + u8 trans_seq; + u8 status; + u8 wrapped_data_format; + + u8 hash[SHA384_MAC_LEN]; + struct wpa_ptk ptk; + struct crypto_ecdh *ecdh; +}; + struct sta_info { struct sta_info *next; /* next entry in sta list */ struct sta_info *hnext; /* next entry in hash table list */ @@ -283,6 +297,10 @@ struct sta_info { unsigned int airtime_weight; struct os_reltime backlogged_until; #endif /* CONFIG_AIRTIME_POLICY */ + +#ifdef CONFIG_PASN + struct pasn_data *pasn; +#endif /* CONFIG_PASN */ }; @@ -359,4 +377,6 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, struct sta_info *sta); +void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta); + #endif /* STA_INFO_H */