SAE: Allow enabled groups to be configured

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>
This commit is contained in:
Jouni Malinen 2013-01-01 16:23:47 +02:00
parent e056f93e60
commit 625f202a74
13 changed files with 145 additions and 11 deletions

View file

@ -1,6 +1,6 @@
/* /*
* hostapd / Configuration file parser * 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. * This software may be distributed under the terms of the BSD license.
* See README for more details. * See README for more details.
@ -2937,6 +2937,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->vendor_elements = elems; bss->vendor_elements = elems;
} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) { } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
bss->sae_anti_clogging_threshold = atoi(pos); 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 { } else {
wpa_printf(MSG_ERROR, "Line %d: unknown configuration " wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
"item '%s'", line, buf); "item '%s'", line, buf);

View file

@ -1042,6 +1042,15 @@ own_ip_addr=127.0.0.1
# same time before the anti-clogging mechanism is taken into use. # same time before the anti-clogging mechanism is taken into use.
#sae_anti_clogging_threshold=5 #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 ############################################## ##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID) # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)

View file

@ -521,6 +521,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#endif /* CONFIG_HS20 */ #endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements); wpabuf_free(conf->vendor_elements);
os_free(conf->sae_groups);
} }

View file

@ -457,6 +457,7 @@ struct hostapd_bss_config {
struct wpabuf *vendor_elements; struct wpabuf *vendor_elements;
unsigned int sae_anti_clogging_threshold; unsigned int sae_anti_clogging_threshold;
int *sae_groups;
}; };

View 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, resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len - ((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token, mgmt->u.auth.variable, &token,
&token_len); &token_len, hapd->conf->sae_groups);
if (token && check_sae_token(hapd, sta->addr, token, token_len) if (token && check_sae_token(hapd, sta->addr, token, token_len)
< 0) { < 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "

View 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, 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; const u8 *pos = data, *end = data + len;
u16 group; u16 group;
@ -485,6 +485,19 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
if (pos + 2 > end) if (pos + 2 > end)
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
group = WPA_GET_LE16(pos); 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) { if (sae->state == SAE_COMMITTED && group != sae->group) {
wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed"); wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;

View file

@ -43,7 +43,7 @@ int sae_process_commit(struct sae_data *sae);
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
const struct wpabuf *token); const struct wpabuf *token);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, 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); 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); int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);

View file

@ -916,9 +916,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */ #endif /* NO_CONFIG_WRITE */
static int * wpa_config_parse_freqs(const struct parse_data *data, static int * wpa_config_parse_int_array(const char *value)
struct wpa_ssid *ssid, int line,
const char *value)
{ {
int *freqs; int *freqs;
size_t used, len; size_t used, len;
@ -965,7 +963,7 @@ static int wpa_config_parse_scan_freq(const struct parse_data *data,
{ {
int *freqs; int *freqs;
freqs = wpa_config_parse_freqs(data, ssid, line, value); freqs = wpa_config_parse_int_array(value);
if (freqs == NULL) if (freqs == NULL)
return -1; return -1;
os_free(ssid->scan_freq); os_free(ssid->scan_freq);
@ -981,7 +979,7 @@ static int wpa_config_parse_freq_list(const struct parse_data *data,
{ {
int *freqs; int *freqs;
freqs = wpa_config_parse_freqs(data, ssid, line, value); freqs = wpa_config_parse_int_array(value);
if (freqs == NULL) if (freqs == NULL)
return -1; return -1;
os_free(ssid->freq_list); 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_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw); wpabuf_free(config->wps_nfc_dev_pw);
os_free(config->ext_password_backend); os_free(config->ext_password_backend);
os_free(config->sae_groups);
os_free(config); 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 #ifdef OFFSET
#undef OFFSET #undef OFFSET
#endif /* OFFSET */ #endif /* OFFSET */
@ -3070,6 +3087,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(auto_interworking, 0, 1), 0 }, { INT_RANGE(auto_interworking, 0, 1), 0 },
{ INT(okc), 0 }, { INT(okc), 0 },
{ INT(pmf), 0 }, { INT(pmf), 0 },
{ FUNC(sae_groups), 0 },
}; };
#undef FUNC #undef FUNC

View file

@ -797,6 +797,16 @@ struct wpa_config {
* this default behavior. * this default behavior.
*/ */
enum mfp_options pmf; 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;
}; };

View file

@ -970,6 +970,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "okc=%d\n", config->okc); fprintf(f, "okc=%d\n", config->okc);
if (config->pmf) if (config->pmf)
fprintf(f, "pmf=%d\n", 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 */ #endif /* CONFIG_NO_CONFIG_WRITE */

View file

@ -42,6 +42,45 @@ static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
#ifdef CONFIG_SAE #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, static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, struct wpa_ssid *ssid,
const u8 *bssid) const u8 *bssid)
@ -54,8 +93,10 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
return NULL; 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; return NULL;
}
if (sae_prepare_commit(wpa_s->own_addr, bssid, if (sae_prepare_commit(wpa_s->own_addr, bssid,
(u8 *) ssid->passphrase, (u8 *) ssid->passphrase,
@ -424,6 +465,20 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return 0; 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) if (status_code != WLAN_STATUS_SUCCESS)
return -1; return -1;
@ -434,7 +489,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1; return -1;
if (wpa_s->sme.sae.state != SAE_COMMITTED) if (wpa_s->sme.sae.state != SAE_COMMITTED)
return -1; 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) WLAN_STATUS_SUCCESS)
return -1; return -1;

View file

@ -281,6 +281,14 @@ fast_reauth=1
# ieee80211w parameter. # ieee80211w parameter.
#pmf=0 #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) # Interworking (IEEE 802.11u)
# Enable Interworking # Enable Interworking

View file

@ -517,6 +517,7 @@ struct wpa_supplicant {
#ifdef CONFIG_SAE #ifdef CONFIG_SAE
struct sae_data sae; struct sae_data sae;
struct wpabuf *sae_token; struct wpabuf *sae_token;
int sae_group_index;
#endif /* CONFIG_SAE */ #endif /* CONFIG_SAE */
} sme; } sme;
#endif /* CONFIG_SME */ #endif /* CONFIG_SME */