aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/wpa_common.c36
-rw-r--r--src/common/wpa_common.h3
-rw-r--r--src/drivers/driver.h9
-rw-r--r--tests/hwsim/wpasupplicant.py3
-rw-r--r--wpa_supplicant/config.c35
-rw-r--r--wpa_supplicant/config_file.c17
-rw-r--r--wpa_supplicant/config_ssid.h9
-rw-r--r--wpa_supplicant/events.c8
-rw-r--r--wpa_supplicant/sme.c1
-rw-r--r--wpa_supplicant/wpa_supplicant.c27
-rw-r--r--wpa_supplicant/wpa_supplicant.conf8
11 files changed, 150 insertions, 6 deletions
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 4efb046..13323bf 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -2072,6 +2072,14 @@ int wpa_parse_cipher(const char *value)
val |= WPA_CIPHER_NONE;
else if (os_strcmp(start, "GTK_NOT_USED") == 0)
val |= WPA_CIPHER_GTK_NOT_USED;
+ else if (os_strcmp(start, "AES-128-CMAC") == 0)
+ val |= WPA_CIPHER_AES_128_CMAC;
+ else if (os_strcmp(start, "BIP-GMAC-128") == 0)
+ val |= WPA_CIPHER_BIP_GMAC_128;
+ else if (os_strcmp(start, "BIP-GMAC-256") == 0)
+ val |= WPA_CIPHER_BIP_GMAC_256;
+ else if (os_strcmp(start, "BIP-CMAC-256") == 0)
+ val |= WPA_CIPHER_BIP_CMAC_256;
else {
os_free(buf);
return -1;
@@ -2127,6 +2135,34 @@ int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
return -1;
pos += ret;
}
+ if (ciphers & WPA_CIPHER_AES_128_CMAC) {
+ ret = os_snprintf(pos, end - pos, "%sAES-128-CMAC",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_BIP_GMAC_128) {
+ ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-128",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_BIP_GMAC_256) {
+ ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-256",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (ciphers & WPA_CIPHER_BIP_CMAC_256) {
+ ret = os_snprintf(pos, end - pos, "%sBIP-CMAC-256",
+ pos == start ? "" : delim);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
if (ciphers & WPA_CIPHER_NONE) {
ret = os_snprintf(pos, end - pos, "%sNONE",
pos == start ? "" : delim);
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 2f11d2f..cc8edf8 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -29,6 +29,9 @@ WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
WPA_CIPHER_GTK_NOT_USED)
+#define WPA_ALLOWED_GROUP_MGMT_CIPHERS \
+(WPA_CIPHER_AES_128_CMAC | WPA_CIPHER_BIP_GMAC_128 | WPA_CIPHER_BIP_GMAC_256 | \
+WPA_CIPHER_BIP_CMAC_256)
#define WPA_SELECTOR_LEN 4
#define WPA_VERSION 1
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6797a5a..f8631c7 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -814,7 +814,7 @@ struct wpa_driver_associate_params {
* WPA information element to be included in (Re)Association
* Request (including information element id and length). Use
* of this WPA IE is optional. If the driver generates the WPA
- * IE, it can use pairwise_suite, group_suite, and
+ * IE, it can use pairwise_suite, group_suite, group_mgmt_suite, and
* key_mgmt_suite to select proper algorithms. In this case,
* the driver has to notify wpa_supplicant about the used WPA
* IE by generating an event that the interface code will
@@ -854,6 +854,13 @@ struct wpa_driver_associate_params {
unsigned int group_suite;
/**
+ * mgmt_group_suite - Selected group management cipher suite (WPA_CIPHER_*)
+ *
+ * This is usually ignored if @wpa_ie is used.
+ */
+ unsigned int mgmt_group_suite;
+
+ /**
* key_mgmt_suite - Selected key management suite (WPA_KEY_MGMT_*)
*
* This is usually ignored if @wpa_ie is used.
diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py
index 6ca45ab..7f182d1 100644
--- a/tests/hwsim/wpasupplicant.py
+++ b/tests/hwsim/wpasupplicant.py
@@ -1027,7 +1027,8 @@ class WpaSupplicant:
"bssid_whitelist", "mem_only_psk", "eap_workaround",
"engine", "fils_dh_group", "bssid_hint",
"dpp_csign", "dpp_csign_expiry",
- "dpp_netaccesskey", "dpp_netaccesskey_expiry" ]
+ "dpp_netaccesskey", "dpp_netaccesskey_expiry",
+ "group_mgmt" ]
for field in not_quoted:
if field in kwargs and kwargs[field]:
self.set_network(id, field, kwargs[field])
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 7e6022d..0ea34e0 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1148,6 +1148,40 @@ static char * wpa_config_write_group(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_group_mgmt(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ int val;
+
+ val = wpa_config_parse_cipher(line, value);
+ if (val == -1)
+ return -1;
+
+ if (val & ~WPA_ALLOWED_GROUP_MGMT_CIPHERS) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: not allowed group management cipher (0x%x).",
+ line, val);
+ return -1;
+ }
+
+ if (ssid->group_mgmt_cipher == val)
+ return 1;
+ wpa_printf(MSG_MSGDUMP, "group_mgmt: 0x%x", val);
+ ssid->group_mgmt_cipher = val;
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_group_mgmt(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_cipher(ssid->group_mgmt_cipher);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
static int wpa_config_parse_auth_alg(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -2086,6 +2120,7 @@ static const struct parse_data ssid_fields[] = {
{ INT(bg_scan_period) },
{ FUNC(pairwise) },
{ FUNC(group) },
+ { FUNC(group_mgmt) },
{ FUNC(auth_alg) },
{ FUNC(scan_freq) },
{ FUNC(freq_list) },
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 5ccd003..ab11af9 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -593,6 +593,22 @@ static void write_group(FILE *f, struct wpa_ssid *ssid)
}
+static void write_group_mgmt(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!ssid->group_mgmt_cipher)
+ return;
+
+ value = wpa_config_get(ssid, "group_mgmt");
+ if (!value)
+ return;
+ if (value[0])
+ fprintf(f, "\tgroup_mgmt=%s\n", value);
+ os_free(value);
+}
+
+
static void write_auth_alg(FILE *f, struct wpa_ssid *ssid)
{
char *value;
@@ -734,6 +750,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
write_pairwise(f, ssid);
write_group(f, ssid);
+ write_group_mgmt(f, ssid);
write_auth_alg(f, ssid);
STR(bgscan);
STR(autoscan);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 81f64a5..737ef42 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -210,6 +210,15 @@ struct wpa_ssid {
int group_cipher;
/**
+ * group_mgmt_cipher - Bitfield of allowed group management ciphers
+ *
+ * This is a bitfield of WPA_CIPHER_AES_128_CMAC and WPA_CIPHER_BIP_*
+ * values. If 0, no constraint is used for the cipher, i.e., whatever
+ * the AP uses is accepted.
+ */
+ int group_mgmt_cipher;
+
+ /**
* key_mgmt - Bitfield of allowed key management protocols
*
* WPA_KEY_MGMT_*
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index db7de89..500e66c 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -565,6 +565,14 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
break;
}
+ if (ssid->group_mgmt_cipher &&
+ !(ie.mgmt_group_cipher & ssid->group_mgmt_cipher)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - group mgmt cipher mismatch");
+ break;
+ }
+
if (!(ie.key_mgmt & ssid->key_mgmt)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index a4d5f75..a92fb45 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1227,6 +1227,7 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
params.pairwise_suite = wpa_s->pairwise_cipher;
params.group_suite = wpa_s->group_cipher;
+ params.mgmt_group_suite = wpa_s->mgmt_group_cipher;
params.key_mgmt_suite = wpa_s->key_mgmt;
params.wpa_proto = wpa_s->wpa_proto;
#ifdef CONFIG_HT_OVERRIDES
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index cdff003..eca9b25 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1232,9 +1232,24 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
ie.pairwise_cipher = ssid->pairwise_cipher;
ie.key_mgmt = ssid->key_mgmt;
#ifdef CONFIG_IEEE80211W
- ie.mgmt_group_cipher =
- ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
- WPA_CIPHER_AES_128_CMAC : 0;
+ ie.mgmt_group_cipher = 0;
+ if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (ssid->group_mgmt_cipher &
+ WPA_CIPHER_BIP_GMAC_256)
+ ie.mgmt_group_cipher =
+ WPA_CIPHER_BIP_GMAC_256;
+ else if (ssid->group_mgmt_cipher &
+ WPA_CIPHER_BIP_CMAC_256)
+ ie.mgmt_group_cipher =
+ WPA_CIPHER_BIP_CMAC_256;
+ else if (ssid->group_mgmt_cipher &
+ WPA_CIPHER_BIP_GMAC_128)
+ ie.mgmt_group_cipher =
+ WPA_CIPHER_BIP_GMAC_128;
+ else
+ ie.mgmt_group_cipher =
+ WPA_CIPHER_AES_128_CMAC;
+ }
#endif /* CONFIG_IEEE80211W */
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
"based on configuration");
@@ -1387,6 +1402,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211W
sel = ie.mgmt_group_cipher;
+ if (ssid->group_mgmt_cipher)
+ sel &= ssid->group_mgmt_cipher;
if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
!(ie.capabilities & WPA_CAPABILITY_MFPC))
sel = 0;
@@ -2301,7 +2318,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
size_t wpa_ie_len;
int use_crypt, ret, i, bssid_changed;
int algs = WPA_AUTH_ALG_OPEN;
- unsigned int cipher_pairwise, cipher_group;
+ unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
int wep_keys_set = 0;
int assoc_failed = 0;
@@ -2665,6 +2682,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
use_crypt = 1;
cipher_pairwise = wpa_s->pairwise_cipher;
cipher_group = wpa_s->group_cipher;
+ cipher_group_mgmt = wpa_s->mgmt_group_cipher;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
@@ -2748,6 +2766,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.wpa_ie_len = wpa_ie_len;
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
+ params.mgmt_group_suite = cipher_group_mgmt;
params.key_mgmt_suite = wpa_s->key_mgmt;
params.wpa_proto = wpa_s->wpa_proto;
params.auth_alg = algs;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 3430be0..fbf3e72 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -879,6 +879,14 @@ fast_reauth=1
# WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11]
# If not set, this defaults to: CCMP TKIP WEP104 WEP40
#
+# group_mgmt: list of accepted group management ciphers for RSN (PMF)
+# AES-128-CMAC = BIP-CMAC-128
+# BIP-GMAC-128
+# BIP-GMAC-256
+# BIP-CMAC-256
+# If not set, no constraint on the cipher, i.e., accept whichever cipher the AP
+# indicates.
+#
# psk: WPA preshared key; 256-bit pre-shared key
# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be