From patchwork Tue Oct 11 21:49:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeffery Miller X-Patchwork-Id: 1688948 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=So+tom7s; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20210112 header.b=GNSL3fmE; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Mn8br40vpz23k1 for ; Wed, 12 Oct 2022 08:50:48 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:Message-ID: Mime-Version:Date: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=l+KQSYxWnOT3NRHp6vkjcaPxbyPsAaU7fIfPfXZNxMo=; b=So+ tom7sRxg3SjL1xLWk5lyQmIZ9Dmc/4Bnc7VcYMtG5oscICiGvpwsAm6uCkK5g/K+sGJ0AmTjkGvnx 0VM7Vxxlu+u01WD2ZBYeC7R2nEO8RzcZ4ol/e35oHv3k0Ub8lNbN0fcGTwNC94nvZyeXFDSK1cPXJ hkL/SAEi5RCYIl6OAY/xQjTsQTdH+ore7LmfPBkdMri+brDLAJgnjLFHN96p9vZcwXzCccox2MKu7 eGYq7hjSBYd/Sy+Ce01NNFttB3auitjLA6jo3TsMk22rNAqcIv1l+D1BkuNcLzmv/Pj/46bKDlDeC Ic60c82RQCavQhecv7y94vqGdDJ6hTg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oiN7x-005xX5-NC; Tue, 11 Oct 2022 21:49:29 +0000 Received: from mail-yw1-x114a.google.com ([2607:f8b0:4864:20::114a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1oiN7t-005xWk-1O for hostap@lists.infradead.org; Tue, 11 Oct 2022 21:49:27 +0000 Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-349423f04dbso144918057b3.13 for ; Tue, 11 Oct 2022 14:49:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:mime-version:date:from:to:cc:subject :date:message-id:reply-to; bh=6DtKTyuDYLeS4KIQn4M+2WK97SOMKrF33LKhBsjwqPM=; b=GNSL3fmEH79ZWXyh/VaJEks/0mwU8gHXrcEc2uUlu+b3MLCAqPD3oVC3DtSL/qMGGv /B/toLVFO3ZjT+eMBEUlzIkCosVh8qq9MN1mCCTlV80FeT5YfW7nRblAEEEhdneWpfzw g5FJnXM6jaJQ6IJQrMB3u55lAqvKMZn2ywLax0lI/ukEgUGfs/qtQan6pa9TSSrWPyxD Pdt/UzaBFjBK0e3XfyMn3URIw7iAUIV0Za5TztX8P8RoPNkmf1AW46s4/5j3p53IJn4T V9n/LVewRb94NBONF14n6cYVEwc36vPfRJJqFIeDOHOQX+seN+z0BnL7myQYcaFLoSqS Y1fw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:mime-version:date:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=6DtKTyuDYLeS4KIQn4M+2WK97SOMKrF33LKhBsjwqPM=; b=58DlaJ/VRPiVIoLgnlixEpEP6tykO4yLeKkOWNFWAVpIMVI18rW9a8Qg5Fy9HHdJJ8 gS/7gf+XiexTVh4pn7rW9r45gDnbsmd2jN5sf1URpRhN6lSWpK1iZFj0sf7a3c7MCjHG KD+PQSeBCuyL8CIXYZl5sC66rxM0rHsA2U/gJM0YH6lW3pIUxl64Zp8KS7Z/rwP7B62v FVNs1A+LJoxy+72Txfzn8joxUfC/6lyJ8/0Ji8EPVtObNOf8ftRqHcee1eMHlMD8D4ie itR+AvTGTXNFUpDa1vuStQ6jyEt+8kbflsmTKom60YNQa/tJYB/jyRoDOdcEMAZo3V55 zd3w== X-Gm-Message-State: ACrzQf1Fucv7z+wyXLrEmfr1X9KHc7o75Y9irIOfLm1QSGOImgYvZ9Zp FLY9A2nQBEpA4zpyRaoCeoxobFYBTJ127IwaVSAKgjxzREiili2MzXm7eHxt9ruk/NN8z/TX9ZH 4XmJOdwYbWhuKtWP0fA+Bxj4DxVCisbfXlFY9NWLiBzAVTYp5UciQd9wgxwAM4nXW17MdlMlJqG eYz9LnPjaOVg== X-Google-Smtp-Source: AMsMyM5b5/pBOnOtrx2qn9OodjHX9knqiBuWaqsntH0owRF0AM2FaLPfLhH8gjslbfbPkwOUe1oE4Ar6b0C6pDADUCz0 X-Received: from horchata.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:5b3]) (user=jefferymiller job=sendgmr) by 2002:a0d:cc01:0:b0:360:1793:2154 with SMTP id o1-20020a0dcc01000000b0036017932154mr22323651ywd.222.1665524961294; Tue, 11 Oct 2022 14:49:21 -0700 (PDT) Date: Tue, 11 Oct 2022 21:49:18 +0000 Mime-Version: 1.0 X-Mailer: git-send-email 2.38.0.rc1.362.ged0d419d3c-goog Message-ID: <20221011214918.3054595-1-jefferymiller@google.com> Subject: [PATCH] Do not use SAE key_mgmt without PMF From: Jeffery Miller To: hostap@lists.infradead.org Cc: Jeffery Miller X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20221011_144925_109513_170D0552 X-CRM114-Status: GOOD ( 24.94 ) X-Spam-Score: -7.7 (-------) X-Spam-Report: Spam detection software, running on the system "bombadil.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: Add `sae_check_mfp` network option to limit SAE when PMF will not be selected for the connection. Avoids SAE when the hardware is not capable of PMF. Avoids SAE on capable hardware when the AP does no [...] Content analysis details: (-7.7 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:114a listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -7.5 USER_IN_DEF_DKIM_WL From: address is in the default DKIM white-list -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.0 DKIMWL_WL_MED DKIMwl.org - Medium trust sender 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: , Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Add `sae_check_mfp` network option to limit SAE when PMF will not be selected for the connection. Avoids SAE when the hardware is not capable of PMF. Avoids SAE on capable hardware when the AP does not enable PMF. Allows falling back to PSK on drivers with the WPA_DRIVER_FLAGS_SAE capability but do not support the BIP cipher necessary for PMF. This enables configurations that can fall back to WPA-PSK and avoid associating problems to APs configured with `sae_require_mfp=1`. Useful with networks configured with ieee80211w unspecified (default), sae_check_mfp=1, key_mgmt="WPA-PSK SAE" and the wpa supplicant global `pmf=1`. In this configuration if the device is unable to use PMF due to lacking BIP group ciphers it will disable SAE and fallback to WPA-PSK. Signed-off-by: Jeffery Miller --- tests/hwsim/test_sae.py | 52 ++++++++++++++++++++++++++++++ tests/hwsim/wpasupplicant.py | 1 + wpa_supplicant/config.c | 2 ++ wpa_supplicant/config_file.c | 1 + wpa_supplicant/config_ssid.h | 18 +++++++++++ wpa_supplicant/sme.c | 9 ++++-- wpa_supplicant/wpa_cli.c | 1 + wpa_supplicant/wpa_supplicant.c | 14 +++++++- wpa_supplicant/wpa_supplicant.conf | 17 ++++++++++ wpa_supplicant/wpa_supplicant_i.h | 6 ++++ 10 files changed, 118 insertions(+), 3 deletions(-) diff --git a/tests/hwsim/test_sae.py b/tests/hwsim/test_sae.py index 4e5687def..550466d6f 100644 --- a/tests/hwsim/test_sae.py +++ b/tests/hwsim/test_sae.py @@ -424,6 +424,58 @@ def test_sae_mixed_mfp(dev, apdev): dev[2].connect("test-sae", psk="12345678", ieee80211w="0", scan_freq="2412") dev[2].dump_monitor() +def test_sae_mixed_check_mfp(dev, apdev): + """Mixed SAE and non-SAE network and MFP required with SAE on sta""" + check_sae_capab(dev[0]) + check_sae_capab(dev[1]) + params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678") + params['wpa_key_mgmt'] = 'SAE WPA-PSK' + params["ieee80211w"] = "1" + hostapd.add_ap(apdev[0], params) + + params = hostapd.wpa2_params(ssid="test-sae-no-mfp", passphrase="12345678") + params['wpa_key_mgmt'] = 'SAE WPA-PSK' + params["ieee80211w"] = "0" + hostapd.add_ap(apdev[1], params) + + dev[0].request("SET sae_groups ") + dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE WPA-PSK", + ieee80211w="0", + sae_check_mfp="0", + scan_freq="2412") + dev[0].dump_monitor() + status = dev[0].get_status() + if status['key_mgmt'] != "SAE": + raise Exception("SAE without sae_check_mfp was not allowed") + + dev[1].request("SET sae_groups ") + dev[1].connect("test-sae", psk="12345678", key_mgmt="SAE WPA-PSK", + ieee80211w="0", sae_check_mfp="1", scan_freq="2412") + dev[1].dump_monitor() + status = dev[1].get_status() + if status['key_mgmt'] != "WPA2-PSK": + raise Exception("SAE without MFP was allowed"); + + # Do not use SAE to an AP without mfp enabled. + dev[2].request("SET sae_groups ") + dev[2].connect("test-sae-no-mfp", psk="12345678", key_mgmt="SAE WPA-PSK", + ieee80211w="1", sae_check_mfp="1", scan_freq="2412") + status = dev[2].get_status() + if status['key_mgmt'] != "WPA2-PSK": + raise Exception("SAE to MFP disabled AP was allowed") + dev[2].request("DISCONNECT") + dev[2].wait_disconnected() + dev[2].dump_monitor() + + # Confirm SAE is used when sae_check_mfp is not set. + dev[2].request("SET sae_groups ") + dev[2].connect("test-sae-no-mfp", psk="12345678", key_mgmt="SAE WPA-PSK", + ieee80211w="1", sae_check_mfp="0", scan_freq="2412") + status = dev[2].get_status() + if status['key_mgmt'] != "SAE": + raise Exception("SAE without sae_check_mfp was not allowed") + dev[2].dump_monitor() + def test_sae_and_psk_transition_disable(dev, apdev): """SAE and PSK transition disable indication""" check_sae_capab(dev[0]) diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py index fe1892785..2ab478a83 100644 --- a/tests/hwsim/wpasupplicant.py +++ b/tests/hwsim/wpasupplicant.py @@ -1090,6 +1090,7 @@ class WpaSupplicant: self.set_network_quoted(id, field, kwargs[field]) not_quoted = ["proto", "key_mgmt", "ieee80211w", "pairwise", + "sae_check_mfp", "group", "wep_key0", "wep_key1", "wep_key2", "wep_key3", "wep_tx_keyidx", "scan_freq", "freq_list", "eap", "eapol_flags", "fragment_size", "scan_ssid", "auth_alg", diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a91c689d0..2931b8740 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2559,6 +2559,7 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(disabled, 0, 2) }, { STR(id_str) }, { INT_RANGE(ieee80211w, 0, 2) }, + { INT_RANGE(sae_check_mfp, 0, 1) }, #ifdef CONFIG_OCV { FUNC(ocv) }, #endif /* CONFIG_OCV */ @@ -3177,6 +3178,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) ssid->proactive_key_caching = -1; ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT; ssid->sae_pwe = DEFAULT_SAE_PWE; + ssid->sae_check_mfp = 0; #ifdef CONFIG_MACSEC ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER; #endif /* CONFIG_MACSEC */ diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index b637dbfbc..a6e639414 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -789,6 +789,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT(fils_dh_group); write_int(f, "ieee80211w", ssid->ieee80211w, MGMT_FRAME_PROTECTION_DEFAULT); + INT(sae_check_mfp), STR(id_str); #ifdef CONFIG_P2P write_go_p2p_dev_addr(f, ssid); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index f625a0cc3..33460c211 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -478,6 +478,24 @@ struct wpa_ssid { */ enum mfp_options ieee80211w; + /** + * sae_check_mfp - Whether to limit SAE based on mfp capabilities + * + * With this check SAE key_mgmt will not be selected if PMF is + * not enabled. + * Scenarios where this check will limit SAE: + * 1) ieee8011w=0 is set for the network. + * 2) The AP does not have PMF enabled. + * 3) ieee8011w is default, pmf=1 set globally, and the + * device does not support the BIP cipher. + * + * Useful to allow the BIP cipher check of ieee80211w=3 and pmf=2 + * to avoid using SAE key_mgmt. + * Useful when hardware does not support BIP but to still to allow + * connecting to sae_require_mfp=1 wpa2+wpa3 transition access points. + */ + int sae_check_mfp; + #ifdef CONFIG_OCV /** * ocv - Enable/disable operating channel validation diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 41b67f8eb..72d035d71 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -413,8 +413,13 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #endif /* CONFIG_DPP */ } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 && wpa_key_mgmt_sae(ied.key_mgmt)) { - wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg"); - params.auth_alg = WPA_AUTH_ALG_SAE; + if (wpas_is_sae_avoided(wpa_s, ssid, &ied)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SAE enabled, but disallowing SAE auth_alg without PMF"); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg"); + params.auth_alg = WPA_AUTH_ALG_SAE; + } } else { wpa_dbg(wpa_s, MSG_DEBUG, "SAE enabled, but target BSS does not advertise SAE AKM for RSN"); diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 197efe0b7..5cb3593a4 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1450,6 +1450,7 @@ static const char *network_fields[] = { "mode", "proactive_key_caching", "disabled", "id_str", "ieee80211w", + "sae_check_mfp", "mixed_cell", "frequency", "fixed_freq", #ifdef CONFIG_MESH "no_auto_peer", "mesh_rssi_threshold", diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 761017248..f40268d1e 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1651,9 +1651,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, sel = ie.key_mgmt & ssid->key_mgmt; #ifdef CONFIG_SAE - if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) || + wpas_is_sae_avoided(wpa_s, ssid, &ie)) { sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY); + } #endif /* CONFIG_SAE */ #ifdef CONFIG_IEEE80211R if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME | @@ -8195,6 +8197,16 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) return ssid->ieee80211w; } +#ifdef CONFIG_SAE +int wpas_is_sae_avoided(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + const struct wpa_ie_data *ie) { + return (ssid->sae_check_mfp && + (!(ie->capabilities & + (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) || + wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)); +} +#endif /* CONFIG_SAE */ int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) { diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 90061ba67..6d591df57 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -990,6 +990,23 @@ fast_reauth=1 # (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used) # WPA3-Personal-only mode: ieee80211w=2 and key_mgmt=SAE # +# sae_check_mfp: require mfp support to select SAE key_mgmt +# 0 = do not check PMF for SAE (default) +# 1 = limit SAE when PMF is not enabled +# +# SAE will not be selected if PMF will not be used for the connection. +# This can occur if the AP has not enabled PMF or the network +# configuration does not enable PMF. +# An example configuration of sae_check_mfp=1, ieee80211w=0 and +# key_mgmt=SAE WPA-PSK will not use PMF and will select WPA-PSK +# when connecting to a PMF optional AP. +# Configurations with a ieee80211w unset (the default), sae_check_mfp=1, +# key_mgmt=SAE WPA-PSK and global pmf=1 will select WPA-PSK when +# the device does not support the BIP cipher as it will not use PMF. +# Limiting SAE with this check can avoid failing to associate to an AP +# that is configured with sae_requires_mfp=1 when the device does +# not support PMF due to lack of BIP. +# # ocv: whether operating channel validation is enabled # This is a countermeasure against multi-channel on-path attacks. # Enabling this automatically also enables ieee80211w, if not yet enabled. diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 813e5ac1b..89c0a75aa 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1844,6 +1844,12 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr); void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid); +#ifdef CONFIG_SAE +int wpas_is_sae_avoided(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + const struct wpa_ie_data *ie); +#endif /* CONFIG_SAE */ + int wpas_init_ext_pw(struct wpa_supplicant *wpa_s); void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,