]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add group_mgmt network parameter for PMF cipher selection
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 26 Sep 2017 14:36:33 +0000 (17:36 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 26 Sep 2017 14:40:02 +0000 (17:40 +0300)
The new wpa_supplicant network parameter group_mgmt can be used to
specify which group management ciphers (AES-128-CMAC, BIP-GMAC-128,
BIP-GMAC-256, BIP-CMAC-256) are allowed for the network. If not
specified, the current behavior is maintained (i.e., follow what the AP
advertises). The parameter can list multiple space separate ciphers.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/common/wpa_common.c
src/common/wpa_common.h
src/drivers/driver.h
tests/hwsim/wpasupplicant.py
wpa_supplicant/config.c
wpa_supplicant/config_file.c
wpa_supplicant/config_ssid.h
wpa_supplicant/events.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf

index 4efb04604ec467dbcc46874a6ffa0901cdccd33d..13323bf9f8862e8f533304a0d69c92929a62294c 100644 (file)
@@ -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);
index 2f11d2f345059f2a79b88f8cc93f1c1593060ca6..cc8edf82d29f2ace7370ebf80c7e0cdc0ddd056c 100644 (file)
@@ -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
index 6797a5a84f2e50187621fb92f9b6309f2748b124..f8631c7ba7ce14aa638ee8d89e84b92a748c46d2 100644 (file)
@@ -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
@@ -853,6 +853,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_*)
         *
index 6ca45abcf368183c8f90cfaad6ae42a4dfd2abce..7f182d12f3e7477254c2578289611de6d47d0619 100644 (file)
@@ -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])
index 7e6022d5719ebbf0785c7137f9ef59a573063790..0ea34e0ce99551b24cb2aaf67c4406f73c042700 100644 (file)
@@ -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) },
index 5ccd003878a62b97dfeca185a8db64585b46c5c0..ab11af9590b5ec2b4e6d41c66ac6e8343b26b893 100644 (file)
@@ -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);
index 81f64a5f4b53f26fa18499524d73175519c3943c..737ef42ff4458d0366d63ff6323045f285b65199 100644 (file)
@@ -209,6 +209,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
         *
index db7de89ed0f6a41d55a50673e326b3ee7b3cad66..500e66c78797c9aad3a95109a19573b1422db2a5 100644 (file)
@@ -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,
index a4d5f75b947175ff9b586f711094c380beb3f13e..a92fb4573c2e86ae466ee0eebcfcc3ac67519731 100644 (file)
@@ -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
index cdff003d8f74b870883b44feae37160d5c5ae9e7..eca9b255561965c042ee9d443f0961b5a2b6b74c 100644 (file)
@@ -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;
index 3430be0cf61a6e24503a91c39cc378b738c8f4c8..fbf3e72c9b3d8d75264096aa1d2e2584ac1af268 100644 (file)
@@ -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