SAE: Allow enabled groups to be configured
authorJouni Malinen <j@w1.fi>
Tue, 1 Jan 2013 14:23:47 +0000 (16:23 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 12 Jan 2013 15:51:53 +0000 (17:51 +0200)
hostapd.conf sae_groups parameter can now be used to limit the set of
groups that the AP allows for SAE. Similarly, sae_groups parameter is
wpa_supplicant.conf can be used to set the preferred order of groups. By
default, all implemented groups are enabled.

Signed-hostap: Jouni Malinen <j@w1.fi>

13 files changed:
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/ieee802_11.c
src/common/sae.c
src/common/sae.h
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant_i.h

index 3032919..7b2c41c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration file parser
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -2937,6 +2937,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        bss->vendor_elements = elems;
                } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
                        bss->sae_anti_clogging_threshold = atoi(pos);
+               } else if (os_strcmp(buf, "sae_groups") == 0) {
+                       if (hostapd_parse_rates(&bss->sae_groups, pos)) {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
+                                          "sae_groups value '%s'", line, pos);
+                               return 1;
+                       }
                } else {
                        wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
                                   "item '%s'", line, buf);
index a25fe37..eca3996 100644 (file)
@@ -1042,6 +1042,15 @@ own_ip_addr=127.0.0.1
 # same time before the anti-clogging mechanism is taken into use.
 #sae_anti_clogging_threshold=5
 
+# Enabled SAE finite cyclic groups
+# SAE implementation are required to support group 19 (ECC group defined over a
+# 256-bit prime order field). All groups that are supported by the
+# implementation are enabled by default. This configuration parameter can be
+# used to specify a limited set of allowed groups. The group values are listed
+# in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=19 20 21 25 26
+
 ##### IEEE 802.11r configuration ##############################################
 
 # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
index c9bf02b..922f564 100644 (file)
@@ -521,6 +521,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 #endif /* CONFIG_HS20 */
 
        wpabuf_free(conf->vendor_elements);
+
+       os_free(conf->sae_groups);
 }
 
 
index b3efff7..4742107 100644 (file)
@@ -457,6 +457,7 @@ struct hostapd_bss_config {
        struct wpabuf *vendor_elements;
 
        unsigned int sae_anti_clogging_threshold;
+       int *sae_groups;
 };
 
 
index 4a04aa9..ea19cdd 100644 (file)
@@ -460,7 +460,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
                resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
                                        ((const u8 *) mgmt) + len -
                                        mgmt->u.auth.variable, &token,
-                                       &token_len);
+                                       &token_len, hapd->conf->sae_groups);
                if (token && check_sae_token(hapd, sta->addr, token, token_len)
                    < 0) {
                        wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
index d9d6467..a182cf5 100644 (file)
@@ -470,7 +470,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
 
 
 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
-                    const u8 **token, size_t *token_len)
+                    const u8 **token, size_t *token_len, int *allowed_groups)
 {
        const u8 *pos = data, *end = data + len;
        u16 group;
@@ -485,6 +485,19 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
        if (pos + 2 > end)
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
        group = WPA_GET_LE16(pos);
+       if (allowed_groups) {
+               int i;
+               for (i = 0; allowed_groups[i] >= 0; i++) {
+                       if (allowed_groups[i] == group)
+                               break;
+               }
+               if (allowed_groups[i] != group) {
+                       wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
+                                  "enabled in the current configuration",
+                                  group);
+                       return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+               }
+       }
        if (sae->state == SAE_COMMITTED && group != sae->group) {
                wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
                return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
index a30fb62..b2bb605 100644 (file)
@@ -43,7 +43,7 @@ int sae_process_commit(struct sae_data *sae);
 void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
                      const struct wpabuf *token);
 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
-                    const u8 **token, size_t *token_len);
+                    const u8 **token, size_t *token_len, int *allowed_groups);
 void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
 int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
 
index 0fab07a..136deea 100644 (file)
@@ -916,9 +916,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
 #endif /* NO_CONFIG_WRITE */
 
 
-static int * wpa_config_parse_freqs(const struct parse_data *data,
-                                   struct wpa_ssid *ssid, int line,
-                                   const char *value)
+static int * wpa_config_parse_int_array(const char *value)
 {
        int *freqs;
        size_t used, len;
@@ -965,7 +963,7 @@ static int wpa_config_parse_scan_freq(const struct parse_data *data,
 {
        int *freqs;
 
-       freqs = wpa_config_parse_freqs(data, ssid, line, value);
+       freqs = wpa_config_parse_int_array(value);
        if (freqs == NULL)
                return -1;
        os_free(ssid->scan_freq);
@@ -981,7 +979,7 @@ static int wpa_config_parse_freq_list(const struct parse_data *data,
 {
        int *freqs;
 
-       freqs = wpa_config_parse_freqs(data, ssid, line, value);
+       freqs = wpa_config_parse_int_array(value);
        if (freqs == NULL)
                return -1;
        os_free(ssid->freq_list);
@@ -1903,6 +1901,7 @@ void wpa_config_free(struct wpa_config *config)
        wpabuf_free(config->wps_nfc_dh_privkey);
        wpabuf_free(config->wps_nfc_dev_pw);
        os_free(config->ext_password_backend);
+       os_free(config->sae_groups);
        os_free(config);
 }
 
@@ -2978,6 +2977,24 @@ static int wpa_config_process_hessid(
 }
 
 
+static int wpa_config_process_sae_groups(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       int *groups = wpa_config_parse_int_array(pos);
+       if (groups == NULL) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'",
+                          line, pos);
+               return -1;
+       }
+
+       os_free(config->sae_groups);
+       config->sae_groups = groups;
+
+       return 0;
+}
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
@@ -3070,6 +3087,7 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(auto_interworking, 0, 1), 0 },
        { INT(okc), 0 },
        { INT(pmf), 0 },
+       { FUNC(sae_groups), 0 },
 };
 
 #undef FUNC
index bb70b9c..0c3cb9a 100644 (file)
@@ -797,6 +797,16 @@ struct wpa_config {
         * this default behavior.
         */
        enum mfp_options pmf;
+
+       /**
+        * sae_groups - Preference list of enabled groups for SAE
+        *
+        * By default (if this parameter is not set), the mandatory group 19
+        * (ECC group defined over a 256-bit prime order field) is preferred,
+        * but other groups are also enabled. If this parameter is set, the
+        * groups will be tried in the indicated order.
+        */
+       int *sae_groups;
 };
 
 
index 8f32cc8..50c3533 100644 (file)
@@ -970,6 +970,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                fprintf(f, "okc=%d\n", config->okc);
        if (config->pmf)
                fprintf(f, "pmf=%d\n", config->pmf);
+
+       if (config->sae_groups) {
+               int i;
+               fprintf(f, "sae_groups=");
+               for (i = 0; config->sae_groups[i] >= 0; i++) {
+                       fprintf(f, "%s%d", i > 0 ? " " : "",
+                               config->sae_groups[i]);
+               }
+               fprintf(f, "\n");
+       }
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
index 112c80f..6fbb9e1 100644 (file)
@@ -42,6 +42,45 @@ static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
 
 #ifdef CONFIG_SAE
 
+static int index_within_array(const int *array, int idx)
+{
+       int i;
+       for (i = 0; i < idx; i++) {
+               if (array[i] == -1)
+                       return 0;
+       }
+       return 1;
+}
+
+
+static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
+{
+       int *groups = wpa_s->conf->sae_groups;
+       int default_groups[] = { 19, 20, 21, 25, 26 };
+
+       if (!groups)
+               groups = default_groups;
+
+       /* Configuration may have changed, so validate current index */
+       if (!index_within_array(groups, wpa_s->sme.sae_group_index))
+               return -1;
+
+       for (;;) {
+               int group = groups[wpa_s->sme.sae_group_index];
+               if (group < 0)
+                       break;
+               if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
+                               wpa_s->sme.sae.group);
+                      return 0;
+               }
+               wpa_s->sme.sae_group_index++;
+       }
+
+       return -1;
+}
+
+
 static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
                                                 struct wpa_ssid *ssid,
                                                 const u8 *bssid)
@@ -54,8 +93,10 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
                return NULL;
        }
 
-       if (sae_set_group(&wpa_s->sme.sae, 19) < 0)
+       if (sme_set_sae_group(wpa_s) < 0) {
+               wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
                return NULL;
+       }
 
        if (sae_prepare_commit(wpa_s->own_addr, bssid,
                               (u8 *) ssid->passphrase,
@@ -424,6 +465,20 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
                return 0;
        }
 
+       if (auth_transaction == 1 &&
+           status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+           wpa_s->sme.sae.state == SAE_COMMITTED &&
+           wpa_s->current_bss && wpa_s->current_ssid) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+               wpa_s->sme.sae_group_index++;
+               if (sme_set_sae_group(wpa_s) < 0)
+                       return -1; /* no other groups enabled */
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
+               sme_send_authentication(wpa_s, wpa_s->current_bss,
+                                       wpa_s->current_ssid, 1);
+               return 0;
+       }
+
        if (status_code != WLAN_STATUS_SUCCESS)
                return -1;
 
@@ -434,7 +489,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
                        return -1;
                if (wpa_s->sme.sae.state != SAE_COMMITTED)
                        return -1;
-               if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL) !=
+               if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
+                                    wpa_s->conf->sae_groups) !=
                    WLAN_STATUS_SUCCESS)
                        return -1;
 
index 381ab47..18460b8 100644 (file)
@@ -281,6 +281,14 @@ fast_reauth=1
 # ieee80211w parameter.
 #pmf=0
 
+# Enabled SAE finite cyclic groups in preference order
+# By default (if this parameter is not set), the mandatory group 19 (ECC group
+# defined over a 256-bit prime order field) is preferred, but other groups are
+# also enabled. If this parameter is set, the groups will be tried in the
+# indicated order. The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=21 20 19 26 25
+
 # Interworking (IEEE 802.11u)
 
 # Enable Interworking
index 081928a..8408a4a 100644 (file)
@@ -517,6 +517,7 @@ struct wpa_supplicant {
 #ifdef CONFIG_SAE
                struct sae_data sae;
                struct wpabuf *sae_token;
+               int sae_group_index;
 #endif /* CONFIG_SAE */
        } sme;
 #endif /* CONFIG_SME */