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:
parent
e056f93e60
commit
625f202a74
13 changed files with 145 additions and 11 deletions
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 "
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue