From cd1e0193abcf26f523bd52d83af5aab086ceaa92 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 1 Apr 2022 15:32:34 +0200 Subject: [PATCH 1/2] supplicant: add BIP interface capability Introduce a new capability indicating whether the interface supports any of the BIP ciphers that can be used for 802.11w (PMF). --- src/core/supplicant/nm-supplicant-interface.c | 28 +++++++++++++++++-- src/core/supplicant/nm-supplicant-types.h | 2 ++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index d827614483..e502ae8556 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -1225,8 +1225,10 @@ parse_capabilities(NMSupplicantInterface *self, GVariant *capabilities) const guint32 old_max_scan_ssids = priv->max_scan_ssids; gboolean have_ft = FALSE; gboolean have_sae = FALSE; + gboolean have_bip = FALSE; gint32 max_scan_ssids; const char **array; + guint i; nm_assert(capabilities && g_variant_is_of_type(capabilities, G_VARIANT_TYPE_VARDICT)); @@ -1236,12 +1238,28 @@ parse_capabilities(NMSupplicantInterface *self, GVariant *capabilities) g_free(array); } + if (g_variant_lookup(capabilities, "GroupMgmt", "^a&s", &array)) { + for (i = 0; array[i]; i++) { + if (NM_IN_STRSET(array[i], + "aes-128-cmac", + "bip-gmac-128", + "bip-gmac-256", + "bip-cmac-256")) { + have_bip = TRUE; + break; + } + } + } + priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_FT, have_ft ? NM_TERNARY_TRUE : NM_TERNARY_FALSE); priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_SAE, have_sae ? NM_TERNARY_TRUE : NM_TERNARY_FALSE); + priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, + NM_SUPPL_CAP_TYPE_BIP, + have_bip ? NM_TERNARY_TRUE : NM_TERNARY_FALSE); if (g_variant_lookup(capabilities, "Modes", "^a&s", &array)) { /* Setting p2p_capable might toggle _prop_p2p_available_get(). However, @@ -1317,10 +1335,12 @@ _starting_check_ready(NMSupplicantInterface *self) " AP%c" " FT%c" " SAE%c" + " BIP%c" "", NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_AP), NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_FT), - NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_SAE)); + NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_SAE), + NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_BIP)); /* Other global properties are set in constructed() because they don't * depend on interface capabilities. */ @@ -1362,6 +1382,7 @@ _get_capability(NMSupplicantInterfacePrivate *priv, NMSupplCapType type) } break; case NM_SUPPL_CAP_TYPE_SAE: + case NM_SUPPL_CAP_TYPE_BIP: nm_assert(NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type) == NM_TERNARY_DEFAULT); value = NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type); break; @@ -1395,10 +1416,13 @@ nm_supplicant_interface_get_capabilities(NMSupplicantInterface *self) caps = NM_SUPPL_CAP_MASK_SET(caps, NM_SUPPL_CAP_TYPE_SAE, _get_capability(priv, NM_SUPPL_CAP_TYPE_SAE)); + caps = NM_SUPPL_CAP_MASK_SET(caps, + NM_SUPPL_CAP_TYPE_BIP, + _get_capability(priv, NM_SUPPL_CAP_TYPE_BIP)); nm_assert(!NM_FLAGS_ANY(priv->iface_capabilities, ~(NM_SUPPL_CAP_MASK_T_AP_MASK | NM_SUPPL_CAP_MASK_T_FT_MASK - | NM_SUPPL_CAP_MASK_T_SAE_MASK))); + | NM_SUPPL_CAP_MASK_T_SAE_MASK | NM_SUPPL_CAP_MASK_T_BIP_MASK))); #if NM_MORE_ASSERTS > 10 { diff --git a/src/core/supplicant/nm-supplicant-types.h b/src/core/supplicant/nm-supplicant-types.h index 5c047ad683..1ae67e1382 100644 --- a/src/core/supplicant/nm-supplicant-types.h +++ b/src/core/supplicant/nm-supplicant-types.h @@ -49,6 +49,7 @@ typedef enum { NM_SUPPL_CAP_TYPE_WFD, NM_SUPPL_CAP_TYPE_SUITEB192, NM_SUPPL_CAP_TYPE_WEP, + NM_SUPPL_CAP_TYPE_BIP, /* Note: if you're adding a capability here, log its presence at the * bottom of _dbus_get_capabilities_cb(). */ _NM_SUPPL_CAP_TYPE_NUM, @@ -79,6 +80,7 @@ typedef enum { _NM_SUPPL_CAP_MASK_DEFINE(SAE), _NM_SUPPL_CAP_MASK_DEFINE(SHA384), _NM_SUPPL_CAP_MASK_DEFINE(WEP), + _NM_SUPPL_CAP_MASK_DEFINE(BIP), #undef _NM_SUPPL_CAP_MASK_DEFINE } NMSupplCapMask; From 1a7db1d7f712d7696f64b089011bc45fc86e7924 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 1 Apr 2022 15:49:13 +0200 Subject: [PATCH 2/2] supplicant: enable WPA3 transition mode only when interface supports PMF We have some reports of APs that advertise WPA2/WPA3 with MFP-required=0/MFP-capable=0, and reject the association when the client doesn't support 802.11w. According to WPA3_Specification_v3.0 section 2.3, when operating in WPA3-Personal transition mode a STA: - should allow AKM suite selector: 00-0F-AC:6 (WPA-PSK-SHA256) to be selected for an association; - shall negotiate PMF when associating to an AP using SAE. The first is guaranteed by capability PMF; the second by checking that the interface supports BIP ciphers suitable for PMF. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/964 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1003907 --- src/core/supplicant/nm-supplicant-config.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/core/supplicant/nm-supplicant-config.c b/src/core/supplicant/nm-supplicant-config.c index 96c23579d0..8626042bb7 100644 --- a/src/core/supplicant/nm-supplicant-config.c +++ b/src/core/supplicant/nm-supplicant-config.c @@ -854,7 +854,24 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig g_string_append(key_mgmt_conf, " WPA-PSK-SHA256"); if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) g_string_append(key_mgmt_conf, " FT-PSK"); - if (_get_capability(priv, NM_SUPPL_CAP_TYPE_SAE)) { + + /* For NM "key-mgmt=wpa-psk" doesn't strictly mean WPA1/wPA2 only, + * but also allows WPA3 (SAE), so that existing connections can + * benefit from the improved security when the AP gets upgraded. + * + * According to WPA3_Specification_v3.0 section 2.3, when operating + * in WPA3-Personal transition mode a STA: + * + * - should allow AKM suite selector: 00-0F-AC:6 (WPA-PSK-SHA256) to + * be selected for an association; + * - shall negotiate PMF when associating to an AP using SAE. + * + * Those conditions are met when the interface has capabilities + * SAE, PMF, BIP. + */ + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_SAE) + && _get_capability(priv, NM_SUPPL_CAP_TYPE_PMF) + && _get_capability(priv, NM_SUPPL_CAP_TYPE_BIP)) { g_string_append(key_mgmt_conf, " SAE"); if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) g_string_append(key_mgmt_conf, " FT-SAE");