/*
* 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.
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);
# 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)
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
+
+ os_free(conf->sae_groups);
}
struct wpabuf *vendor_elements;
unsigned int sae_anti_clogging_threshold;
+ int *sae_groups;
};
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 "
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;
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;
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);
#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;
{
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);
{
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);
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);
}
}
+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 */
{ INT_RANGE(auto_interworking, 0, 1), 0 },
{ INT(okc), 0 },
{ INT(pmf), 0 },
+ { FUNC(sae_groups), 0 },
};
#undef FUNC
* 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;
};
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 */
#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)
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,
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;
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;
# 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
#ifdef CONFIG_SAE
struct sae_data sae;
struct wpabuf *sae_token;
+ int sae_group_index;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */