From patchwork Sun Mar 21 11:55:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peer, Ilan" X-Patchwork-Id: 1456280 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=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=dprAEv4P; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F3GLM439Qz9sSC for ; Sun, 21 Mar 2021 22:56:11 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:MIME-Version:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:Message-Id:Date:Subject:Cc:To:From:Reply-To: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Owner; bh=YZxDePqtHgTmmxTX4HAQGgWkdpvWha2vrch60goip+k=; b=dprAEv4PHW43nsUa3oPJnShaR4 9px/qZ8PDqTJnhHjXSPxXYqUMBnNRgdbJBarlBvbUYJOYgDk5CmcgSjpcUUbVRdBpe0yTuvt8X1+K F99DZp53dBI4nO0uHccaS3Tw+BTEiXQFQSRuzmbGCIsQ0DeHI3xG/2Vq/E36ALmMwzhQV6ziDcSxt M70S3bmwIlfARmM4+Qwv9BD04NyP1bI16oBaUReJ1XAonzRcOw6KAYexfOraBqETL/3rP1FPntiZd e5hlUjvISHzcRHF+bhzf35rFD+eNcGZgSIn5fAuosDlcnNumxua4mG4fXHK3JU1el/Q1aFiBDvXUy NIdc6IHg==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNwgA-009tVY-9z; Sun, 21 Mar 2021 11:55:34 +0000 Received: from mga04.intel.com ([192.55.52.120]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNwfy-009tTM-Is for hostap@lists.infradead.org; Sun, 21 Mar 2021 11:55:26 +0000 IronPort-SDR: 4pOzqtdypTwxnCcufTddq2ffFVq5q8xOTg/E2uUJhemhWEQHCG/1yTj48yxsP/TcnYqtOEqBMB +kvTo9CYf7PA== X-IronPort-AV: E=McAfee;i="6000,8403,9929"; a="187796386" X-IronPort-AV: E=Sophos;i="5.81,266,1610438400"; d="scan'208";a="187796386" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Mar 2021 04:55:20 -0700 IronPort-SDR: AK5kpfRDexammsbAXbvfjDpylrgtQ0Unxv1d4L7lWZ/TIV0DJjaZ3w0MH59p3bYWiBMEbVpO1e 0F3JbEzsrT7A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,266,1610438400"; d="scan'208";a="603607599" Received: from jed01615.jer.intel.com ([10.12.217.51]) by fmsmga006.fm.intel.com with ESMTP; 21 Mar 2021 04:55:19 -0700 From: Ilan Peer To: hostap@lists.infradead.org Cc: Ilan Peer Subject: [PATCH v2 1/3] AP: Add support for PASN comeback flow Date: Sun, 21 Mar 2021 13:55:08 +0200 Message-Id: <20210321115510.31582-1-ilan.peer@intel.com> X-Mailer: git-send-email 2.17.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210321_115523_442931_593160E1 X-CRM114-Status: GOOD ( 19.86 ) X-Spam-Score: -2.3 (--) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Signed-off-by: Ilan Peer --- hostapd/config_file.c | 2 + hostapd/hostapd.conf | 7 ++++ src/ap/ap_config.c | 5 +++ src/ap/ap_config.h | 6 +++ src/ap/ieee802_11.c | 88 ++++++++++++ [...] Content analysis details: (-2.3 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [192.55.52.120 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.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Signed-off-by: Ilan Peer --- hostapd/config_file.c | 2 + hostapd/hostapd.conf | 7 ++++ src/ap/ap_config.c | 5 +++ src/ap/ap_config.h | 6 +++ src/ap/ieee802_11.c | 88 +++++++++++++++++++++++++++++++++++++++---- 5 files changed, 101 insertions(+), 7 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index fd9bc0e9fc..d73a737821 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4675,6 +4675,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "pasn_comeback_after") == 0) { + bss->pasn_comeback_after = atoi(pos); #endif /* CONFIG_PASN */ } else { wpa_printf(MSG_ERROR, diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index d19db5a154..bb532763b5 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -2051,6 +2051,13 @@ own_ip_addr=127.0.0.1 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10 #pasn_groups=19 20 21 +# PASN comeback after. +# In case the AP is temporally unable to handle a PASN authentication exchange, +# this value would indicate to the peer after how many TUs it can try comeback +# and try the PASN exchange again. +# (default: 10 TUs) +# pasn_comeback_after=10 + ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 452386b7e5..7b6249bbe5 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -165,6 +165,11 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_TESTING_OPTIONS bss->sae_commit_status = -1; #endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_PASN + /* comeback after 10 TUs */ + bss->pasn_comeback_after = 10; +#endif /* CONFIG_PASN */ } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 8aeb03107a..26bdaf1317 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -880,6 +880,12 @@ struct hostapd_bss_config { #endif /* CONFIG_TESTING_OPTIONS */ int *pasn_groups; + + /* + * The time in TUs after which the non-AP STA is requested to retry the + * PASN authentication + */ + u16 pasn_comeback_after; #endif /* CONFIG_PASN */ unsigned int unsol_bcast_probe_resp_interval; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 72d102f44e..e31e4710da 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -702,13 +702,15 @@ static int use_anti_clogging(struct hostapd_data *hapd) for (sta = hapd->sta_list; sta; sta = sta->next) { #ifdef CONFIG_SAE - if (!sta->sae) - continue; - if (sta->sae->state != SAE_COMMITTED && - sta->sae->state != SAE_CONFIRMED) - continue; - open++; + if (sta->sae && + (sta->sae->state == SAE_COMMITTED || + sta->sae->state == SAE_CONFIRMED)) + open++; #endif /* CONFIG_SAE */ +#ifdef CONFIG_PASN + if (sta->pasn && sta->pasn->ecdh) + open++; +#endif /* CONFIG_PASN */ if (open >= hapd->conf->anti_clogging_threshold) return 1; } @@ -806,7 +808,8 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, if (buf == NULL) return NULL; - wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ + if (group) + wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ if (h2e) { /* Encapsulate Anti-clogging Token field in a container IE */ @@ -2891,6 +2894,57 @@ pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta, } +static void handle_auth_pasn_comeback(struct hostapd_data *hapd, + struct sta_info *sta, u16 group) +{ + struct wpabuf *buf, *comeback; + int ret; + + wpa_printf(MSG_DEBUG, + "PASN: Building comeback frame 2. Comeback after=%u", + hapd->conf->pasn_comeback_after); + + buf = wpabuf_alloc(1500); + if (!buf) + return; + + wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr, + sta->addr, 2, + WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY); + + /* + * Do not include the group as part of the token since it is not going + * to be used + */ + comeback = auth_build_token_req(hapd, 0, sta->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, + hapd->conf->pasn_comeback_after); + + wpabuf_free(comeback); + comeback = NULL; + + wpa_printf(MSG_DEBUG, + "PASN: comeback: 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, "PASN: Failed to send comeback frame 2"); + + wpabuf_free(buf); +} + + static int handle_auth_pasn_resp(struct hostapd_data *hapd, struct sta_info *sta, struct rsn_pmksa_cache_entry *pmksa, @@ -3133,6 +3187,26 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta, goto send_resp; } + if (pasn_params.comeback) { + wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token"); + + ret = check_comeback_token(hapd, sta->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 (use_anti_clogging(hapd)) { + wpa_printf(MSG_DEBUG, "PASN: Response with comeback"); + + handle_auth_pasn_comeback(hapd, sta, pasn_params.group); + ap_free_sta(hapd, sta); + return; + } + sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group); if (!sta->pasn->ecdh) { wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH"); From patchwork Sun Mar 21 11:55:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peer, Ilan" X-Patchwork-Id: 1456281 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=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=jcovV5Xb; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F3GLR03qcz9sRf for ; Sun, 21 Mar 2021 22:56:14 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:MIME-Version:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:References:In-Reply-To:Message-Id:Date:Subject:Cc:To :From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=zT8FnvRyYZqmNyUSFo6z9eB4ZTt4ZJdEaVjA/rx3U+U=; b=jcovV5Xb64HjvfTCCkfoIotjzS ncaIBJ3POsjAoWy5AG4i9dQ6s3SrbrtiEZmYlQ/g529lD1BiQmiWMEK0RaFZwKVL30FOmylEEBVsE FkGoQpQR0PRGtFNvbH01C1jjia9W8quhSeMq6kdgM7FWwMw+nzHQyYBzn3a92+p6h2rF2IBTdtTTd NiLQHifVIW+s2pw9BjaclOdnhkgfhcN5IdzTrLlx0CfrIUAbcyjIPhaYeavRotTmm/cK/eZe99Dyx 16IvVWvvTebp4/kcGRo6fz+gY/WPe046cX40Cl0BGEocelifo0n3KRG3JuVnkwK45y1mpjTw2gubj H/m0La1Q==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNwg5-009tUs-GR; Sun, 21 Mar 2021 11:55:29 +0000 Received: from mga04.intel.com ([192.55.52.120]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNwfz-009tTS-JQ for hostap@lists.infradead.org; Sun, 21 Mar 2021 11:55:26 +0000 IronPort-SDR: NRxF/hTBSYWFSJgqXyE8MsT4KEGR0M97USJWJJpXClrpl3brwpZO73idxDJw/1Zr3Wa8sJNqCt WiipJB68M+YQ== X-IronPort-AV: E=McAfee;i="6000,8403,9929"; a="187796387" X-IronPort-AV: E=Sophos;i="5.81,266,1610438400"; d="scan'208";a="187796387" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Mar 2021 04:55:22 -0700 IronPort-SDR: TlJenyKr7SUxpbVmmMNzSq7xkUWvS1AlsExR1UHUIQzKWGgkNcURyDFef8+nKljGUkC/MmEGex Ho/Ub8gbwXTg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,266,1610438400"; d="scan'208";a="603607606" Received: from jed01615.jer.intel.com ([10.12.217.51]) by fmsmga006.fm.intel.com with ESMTP; 21 Mar 2021 04:55:20 -0700 From: Ilan Peer To: hostap@lists.infradead.org Cc: Ilan Peer Subject: [PATCH v2 2/3] PASN: Add support for comeback flow to the wpa_supplicant Date: Sun, 21 Mar 2021 13:55:09 +0200 Message-Id: <20210321115510.31582-2-ilan.peer@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210321115510.31582-1-ilan.peer@intel.com> References: <20210321115510.31582-1-ilan.peer@intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210321_115524_254703_26058F47 X-CRM114-Status: GOOD ( 18.33 ) X-Spam-Score: -2.3 (--) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Signed-off-by: Ilan Peer --- wpa_supplicant/ctrl_iface.c | 26 +++++++- wpa_supplicant/pasn_supplicant.c | 107 +++++++++++++++++++++++++++--- wpa_supplicant/wpa_supplicant_i.h | 6 [...] Content analysis details: (-2.3 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [192.55.52.120 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.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Signed-off-by: Ilan Peer --- wpa_supplicant/ctrl_iface.c | 26 +++++++- wpa_supplicant/pasn_supplicant.c | 107 +++++++++++++++++++++++++++--- wpa_supplicant/wpa_supplicant_i.h | 6 +- 3 files changed, 126 insertions(+), 13 deletions(-) diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index b54d7d4968..44fd8afea4 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -10598,7 +10598,9 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd) u8 bssid[ETH_ALEN]; int akmp = -1, cipher = -1, got_bssid = 0; u16 group = 0xFFFF; - int id = 0; + u8 *comeback = NULL; + size_t comeback_len = 0; + int id = 0, ret; /* * Entry format: bssid= akmp= cipher= group= @@ -10640,6 +10642,21 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd) group = atoi(token + 6); } else if (os_strncmp(token, "nid=", 4) == 0) { id = atoi(token + 4); + } else if (os_strncmp(token, "comeback=", 9) == 0) { + comeback_len = os_strlen(token + 9); + + if (!comeback_len || comeback_len % 2) + return -1; + + comeback_len /= 2; + comeback = os_malloc(comeback_len); + if (!comeback) + return -1; + + if (hexstr2bin(token + 9, comeback, comeback_len)) { + os_free(comeback); + return -1; + } } else { wpa_printf(MSG_DEBUG, "CTRL: PASN Invalid parameter: '%s'", @@ -10650,10 +10667,15 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd) if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) { wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter"); + os_free(comeback); return -1; } - return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id); + ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id, + comeback, comeback_len); + + os_free(comeback); + return ret; } diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c index e6adf73f3e..1df8cfad24 100644 --- a/wpa_supplicant/pasn_supplicant.c +++ b/wpa_supplicant/pasn_supplicant.c @@ -33,6 +33,7 @@ struct wpa_pasn_auth_work { int cipher; u16 group; int network_id; + struct wpabuf *comeback; }; @@ -56,8 +57,30 @@ static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s) static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid, - int akmp, int cipher, u8 status) + int akmp, int cipher, u8 status, + struct wpabuf *comeback, + u16 comeback_after) { + if (comeback) { + size_t comeback_len = wpabuf_len(comeback); + char *comeback_txt = os_malloc(comeback_len * 2 + 1); + + if (comeback_txt) { + wpa_snprintf_hex(comeback_txt, comeback_len * 2 + 1, + wpabuf_head(comeback), comeback_len); + + wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR + " akmp=%s, status=%u comeback_after=%u" + " comeback=%s", + MAC2STR(bssid), + wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN), + status, comeback_after, comeback_txt); + + os_free(comeback_txt); + return; + } + } + wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u", MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN), @@ -612,7 +635,8 @@ static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn) } -static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s) +static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s, + struct wpabuf *comeback) { struct wpas_pasn *pasn = &wpa_s->pasn; struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL; @@ -680,7 +704,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s) wrapped_data = WPA_PASN_WRAPPED_DATA_NO; wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data, - pubkey, true, NULL, -1); + pubkey, true, comeback, -1); if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0) goto fail; @@ -828,6 +852,10 @@ static void wpas_pasn_reset(struct wpa_supplicant *wpa_s) wpabuf_free(pasn->beacon_rsne_rsnxe); pasn->beacon_rsne_rsnxe = NULL; + wpabuf_free(pasn->comeback); + pasn->comeback = NULL; + pasn->comeback_after = 0; + #ifdef CONFIG_SAE sae_clear_data(&pasn->sae); #endif /* CONFIG_SAE */ @@ -946,7 +974,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, int akmp, int cipher, u16 group, int freq, const u8 *beacon_rsne, u8 beacon_rsne_len, const u8 *beacon_rsnxe, u8 beacon_rsnxe_len, - int network_id) + int network_id, struct wpabuf *comeback) { struct wpas_pasn *pasn = &wpa_s->pasn; struct wpa_ssid *ssid = NULL; @@ -1023,7 +1051,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher, pasn->group); - frame = wpas_pasn_build_auth_1(wpa_s); + frame = wpas_pasn_build_auth_1(wpa_s, comeback); if (!frame) { wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame"); goto fail; @@ -1105,6 +1133,8 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) wpa_s, NULL); wpa_s->pasn_auth_work = NULL; } + + wpabuf_free(awork->comeback); os_free(awork); return; } @@ -1132,16 +1162,22 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher, awork->group, bss->freq, rsne, *(rsne + 1) + 2, rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0, - awork->network_id); + awork->network_id, awork->comeback); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to start PASN authentication"); goto fail; } + /* comeback token is no longer needed at this stage */ + wpabuf_free(awork->comeback); + awork->comeback = NULL; + wpa_s->pasn_auth_work = work; return; fail: + wpabuf_free(awork->comeback); + awork->comeback = NULL; os_free(awork); work->ctx = NULL; radio_work_done(work); @@ -1149,7 +1185,8 @@ fail: int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, - int akmp, int cipher, u16 group, int network_id) + int akmp, int cipher, u16 group, int network_id, + const u8 *comeback, size_t comeback_len) { struct wpa_pasn_auth_work *awork; struct wpa_bss *bss; @@ -1195,8 +1232,19 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, awork->group = group; awork->network_id = network_id; + if (comeback && comeback_len) { + awork->comeback = wpabuf_alloc(comeback_len); + if (!awork->comeback) { + os_free(awork); + return -1; + } + + wpabuf_put_data(awork->comeback, comeback, comeback_len); + } + if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1, wpas_pasn_auth_start_cb, awork) < 0) { + wpabuf_free(awork->comeback); os_free(awork); return -1; } @@ -1216,7 +1264,8 @@ void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "PASN: Stopping authentication"); wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher, - pasn->status); + pasn->status, pasn->comeback, + pasn->comeback_after); wpas_pasn_reset(wpa_s); } @@ -1315,10 +1364,44 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s, goto fail; } - /* TODO: handle comeback flow */ if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) { wpa_printf(MSG_DEBUG, "PASN: Authentication temporarily rejected"); + + if (pasn_params.comeback && pasn_params.comeback_len) { + wpa_printf(MSG_DEBUG, + "PASN: Comeback token available. After=%u", + pasn_params.after); + + if (!pasn_params.after) { + int akmp = pasn->akmp; + int cipher = pasn->cipher; + u16 group = pasn->group; + u8 bssid[ETH_ALEN]; + int network_id = + pasn->ssid ? pasn->ssid->id : 0; + + wpa_printf(MSG_DEBUG, "PASN: Immediate retry"); + os_memcpy(bssid, pasn->bssid, ETH_ALEN); + wpas_pasn_reset(wpa_s); + + return wpas_pasn_auth_start(wpa_s, bssid, akmp, + cipher, group, + network_id, + pasn_params.comeback, + pasn_params.comeback_len); + } + + pasn->comeback = wpabuf_alloc(pasn_params.comeback_len); + if (pasn->comeback) { + wpabuf_put_data(pasn->comeback, + pasn_params.comeback, + pasn_params.comeback_len); + pasn->comeback_after = pasn_params.after; + } + } + + pasn->status = status; goto fail; } @@ -1456,7 +1539,11 @@ fail: * the frame and terminate the authentication exchange. However, better * reply to the AP with an error status. */ - pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE; + if (status == WLAN_STATUS_SUCCESS) + pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE; + else + pasn->status = status; + wpas_pasn_auth_stop(wpa_s); return -1; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 7ed8c0ee4d..8813ddb710 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -554,6 +554,9 @@ struct wpas_pasn { struct wpa_ptk ptk; struct crypto_ecdh *ecdh; + struct wpabuf *comeback; + u16 comeback_after; + #ifdef CONFIG_SAE struct sae_data sae; #endif /* CONFIG_SAE */ @@ -1730,7 +1733,8 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid, int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, int akmp, int cipher, - u16 group, int network_id); + u16 group, int network_id, + const u8 *comeback, size_t comeback_len); void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s); int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data, size_t data_len, u8 acked); From patchwork Sun Mar 21 11:55:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peer, Ilan" X-Patchwork-Id: 1456282 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=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=cP9ASa2F; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F3GLS03llz9sSC for ; Sun, 21 Mar 2021 22:56:16 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:MIME-Version:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:References:In-Reply-To:Message-Id:Date:Subject:Cc:To :From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=50lNg0qXDqXj6xpPJSU5oijRYa8Li43AVhvQtgeurpw=; b=cP9ASa2FmTf4SUfZygAguCTGEZ B69meo1uO74CEBQMLbZg1b1PXnk/dLp5anz7sWvlKcf53ZgIL0IBHmnUtJtxFITvs7rGsEXY5Z/by kEHxHF9AT3aNTohE2H/Ne6ige8B5hPPMc1dbvridf3jvJa0W5aYTeSH+E7McI8axHejEKHRz9tQ/y jsZvs1eN+mHAU0h/R/xUA14Cvb7nCcbzNVb0SAtM+gA+3iRLQhfXF+Z50/b+4QRamYwKsDZpvrZ/j HnbCE7uqJb3XhXWvFXVCVtXbCu2NU6oNw1h3eRYqDh7buU5lYqKK1O0YSwiVbR+MJ31kvQ+Xks44A +b3FqBKw==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lNwgH-009tWq-ET; Sun, 21 Mar 2021 11:55:41 +0000 Received: from mga04.intel.com ([192.55.52.120]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lNwg0-009tTm-O8 for hostap@lists.infradead.org; Sun, 21 Mar 2021 11:55:27 +0000 IronPort-SDR: 5Mg307MR7k3GN/sYnmDhb+VArSF6aJwUkrFW+HfmQkvg0weLuY097lEiJbTTQOYxGJ9ZkQOWWs RbfLSdgpFPzQ== X-IronPort-AV: E=McAfee;i="6000,8403,9929"; a="187796388" X-IronPort-AV: E=Sophos;i="5.81,266,1610438400"; d="scan'208";a="187796388" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Mar 2021 04:55:23 -0700 IronPort-SDR: HUbKkF+QmPXXwt7PhImBVWQeq8vLGW/FZo7ICelFan9G6zrymsechfLL/YRMo0OPr7xA19vv0M sd3MUEluIhOg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,266,1610438400"; d="scan'208";a="603607611" Received: from jed01615.jer.intel.com ([10.12.217.51]) by fmsmga006.fm.intel.com with ESMTP; 21 Mar 2021 04:55:22 -0700 From: Ilan Peer To: hostap@lists.infradead.org Cc: Ilan Peer Subject: [PATCH v2 3/3] tests: Add PASN tests with comeback flow Date: Sun, 21 Mar 2021 13:55:10 +0200 Message-Id: <20210321115510.31582-3-ilan.peer@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210321115510.31582-1-ilan.peer@intel.com> References: <20210321115510.31582-1-ilan.peer@intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210321_115525_251088_B0B87190 X-CRM114-Status: UNSURE ( 8.32 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -2.3 (--) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Signed-off-by: Ilan Peer --- tests/hwsim/test_pasn.py | 120 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py index f2c7b3b221..578b445d98 100644 --- a/tests/hwsim/test_pasn.py +++ b/tests/hwsim/test_pasn.py @@ -13, 6 +13,7 @@ logger = logging.ge [...] Content analysis details: (-2.3 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [192.55.52.120 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.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Signed-off-by: Ilan Peer --- tests/hwsim/test_pasn.py | 120 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py index f2c7b3b221..578b445d98 100644 --- a/tests/hwsim/test_pasn.py +++ b/tests/hwsim/test_pasn.py @@ -13,6 +13,7 @@ logger = logging.getLogger() import socket import struct import subprocess +import re import hwsim_utils import hostapd @@ -681,3 +682,122 @@ def test_pasn_ap_mic_error(dev, apdev): check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP", status=1) check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP") + +@remote_compatible +def test_pasn_comeback(dev, apdev, params): + """ PASN authentication with comeback flow """ + check_pasn_capab(dev[0]) + + params = pasn_ap_params("PASN", "CCMP", "19") + params['sae_anti_clogging_threshold'] = '0' + hapd = hostapd.add_ap(apdev[0], params) + + dev[0].scan(type="ONLY", freq=2412) + cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19" % (hapd.own_addr()) + + resp = dev[0].request(cmd) + if "OK" not in resp: + raise Exception("Failed to start PASN authentication") + + ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3) + if not ev: + raise Exception("PASN: PASN-AUTH-STATUS not seen") + + if hapd.own_addr() + " akmp=PASN, status=30 comeback_after=" not in ev: + raise Exception("PASN: unexpected status") + + comeback = re.split("comeback=", ev)[1] + + cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19 comeback=%s" % \ + (hapd.own_addr(), comeback) + + resp = dev[0].request(cmd) + if "OK" not in resp: + raise Exception("Failed to start PASN authentication") + + ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3) + if not ev: + raise Exception("PASN: PASN-AUTH-STATUS not seen") + + if hapd.own_addr() + " akmp=PASN, status=0" not in ev: + raise Exception("PASN: unexpected status with comeback token") + + check_pasn_ptk(dev[0], hapd, "CCMP") + +@remote_compatible +def test_pasn_comeback_after_0(dev, apdev, params): + """ PASN authentication with comeback flow with comeback after set to 0""" + check_pasn_capab(dev[0]) + + params = pasn_ap_params("PASN", "CCMP", "19") + params['anti_clogging_threshold'] = '0' + params['pasn_comeback_after'] = '0' + hapd = start_pasn_ap(apdev[0], params) + + check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP") + +@remote_compatible +def test_pasn_comeback_after_0_sae(dev, apdev): + """ PASN authentication with SAE, with comeback flow where comeback after is set to 0 """ + check_pasn_capab(dev[0]) + check_sae_capab(dev[0]) + + params = hostapd.wpa2_params(ssid="test-pasn-sae", + passphrase="12345678") + params['wpa_key_mgmt'] = 'SAE PASN' + params['anti_clogging_threshold'] = '0' + params['pasn_comeback_after'] = '0' + hapd = start_pasn_ap(apdev[0], params) + + dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412", + only_add_network=True) + + # first test with a valid PSK + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0") + + # And now with PMKSA caching + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP") + + # And now with a wrong passphrase + if "FAIL" in dev[0].request("PMKSA_FLUSH"): + raise Exception("PMKSA_FLUSH failed") + + dev[0].set_network_quoted(0, "psk", "12345678787") + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0") + +@remote_compatible +def test_pasn_comeback_multi(dev, apdev): + """ PASN authentication with SAE, with multiple stations with comeback""" + check_pasn_capab(dev[0]) + check_sae_capab(dev[0]) + + params = hostapd.wpa2_params(ssid="test-pasn-sae", + passphrase="12345678") + params['wpa_key_mgmt'] = 'SAE PASN' + params['anti_clogging_threshold'] = '1' + params['pasn_comeback_after'] = '0' + hapd = start_pasn_ap(apdev[0], params) + + id = {} + for i in range(0, 2): + dev[i].flush_scan_cache() + dev[i].scan(type="ONLY", freq=2412) + id[i] = dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE", + scan_freq="2412", only_add_network=True) + + for i in range(0, 2): + cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19, nid=%s" % (hapd.own_addr(), id[i]) + resp = dev[i].request(cmd) + + if "OK" not in resp: + raise Exception("Failed to start pasn authentication") + + for i in range(0, 2): + ev = dev[i].wait_event(["PASN-AUTH-STATUS"], 3) + if not ev: + raise Exception("PASN: PASN-AUTH-STATUS not seen") + + if hapd.own_addr() + " akmp=PASN, status=0" not in ev: + raise Exception("PASN: unexpected status") + + check_pasn_ptk(dev[i], hapd, "CCMP")