diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 1bd57afe5..65e125e83 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -495,6 +495,7 @@ #define WLAN_EID_EXT_EHT_CAPABILITIES 108 #define WLAN_EID_EXT_TID_TO_LINK_MAPPING 109 #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110 +#define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114 /* Extended Capabilities field */ #define WLAN_EXT_CAPAB_20_40_COEX 0 diff --git a/src/common/sae.c b/src/common/sae.c index 48e4fb4af..637ca29b5 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -1727,6 +1727,17 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, token); } + if (wpa_key_mgmt_sae_ext_key(sae->akmp)) { + u32 suite = wpa_akm_to_suite(sae->akmp); + + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 1 + RSN_SELECTOR_LEN); + wpabuf_put_u8(buf, WLAN_EID_EXT_AKM_SUITE_SELECTOR); + RSN_SELECTOR_PUT(wpabuf_put(buf, RSN_SELECTOR_LEN), suite); + wpa_printf(MSG_DEBUG, "SAE: AKM Suite Selector: %08x", suite); + sae->own_akm_suite_selector = suite; + } + return 0; } @@ -1803,6 +1814,16 @@ static int sae_is_token_container_elem(const u8 *pos, const u8 *end) } +static int sae_is_akm_suite_selector_elem(const u8 *pos, const u8 *end) +{ + return end - pos >= 2 + 1 + RSN_SELECTOR_LEN && + pos[0] == WLAN_EID_EXTENSION && + pos[1] >= 1 + RSN_SELECTOR_LEN && + end - pos - 2 >= pos[1] && + pos[2] == WLAN_EID_EXT_AKM_SUITE_SELECTOR; +} + + static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos, const u8 *end, const u8 **token, size_t *token_len, int h2e) @@ -2090,6 +2111,35 @@ static int sae_parse_rejected_groups(struct sae_data *sae, } +static int sae_parse_akm_suite_selector(struct sae_data *sae, + const u8 **pos, const u8 *end) +{ + const u8 *epos; + u8 len; + + wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame", + *pos, end - *pos); + if (!sae_is_akm_suite_selector_elem(*pos, end)) + return WLAN_STATUS_SUCCESS; + + epos = *pos; + epos++; /* skip IE type */ + len = *epos++; /* IE length */ + if (len > end - epos || len < 1) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + epos++; /* skip ext ID */ + len--; + + if (len < RSN_SELECTOR_LEN) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + sae->peer_akm_suite_selector = RSN_SELECTOR_GET(epos); + wpa_printf(MSG_DEBUG, "SAE: Received AKM Suite Selector: %08x", + sae->peer_akm_suite_selector); + *pos = epos + len; + return WLAN_STATUS_SUCCESS; +} + + u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups, int h2e) @@ -2134,6 +2184,31 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, if (h2e) sae_parse_token_container(sae, pos, end, token, token_len); + /* Conditional AKM Suite Selector element */ + if (h2e) { + res = sae_parse_akm_suite_selector(sae, &pos, end); + if (res != WLAN_STATUS_SUCCESS) + return res; + } + + if (sae->own_akm_suite_selector && + sae->own_akm_suite_selector != sae->peer_akm_suite_selector) { + wpa_printf(MSG_DEBUG, + "SAE: AKM suite selector mismatch: own=%08x peer=%08x", + sae->own_akm_suite_selector, + sae->peer_akm_suite_selector); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + if (!sae->akmp) { + if (sae->peer_akm_suite_selector == + RSN_AUTH_KEY_MGMT_SAE_EXT_KEY) + sae->akmp = WPA_KEY_MGMT_SAE_EXT_KEY; + else if (sae->peer_akm_suite_selector == + RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY) + sae->akmp = WPA_KEY_MGMT_FT_SAE_EXT_KEY; + } + /* * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as * the values we sent which would be evidence of a reflection attack. diff --git a/src/common/sae.h b/src/common/sae.h index 6eb2b6f4f..459117a71 100644 --- a/src/common/sae.h +++ b/src/common/sae.h @@ -107,6 +107,8 @@ struct sae_data { u8 pmk[SAE_PMK_LEN]; size_t pmk_len; int akmp; /* WPA_KEY_MGMT_* used in key derivation */ + u32 own_akm_suite_selector; + u32 peer_akm_suite_selector; u8 pmkid[SAE_PMKID_LEN]; struct crypto_bignum *peer_commit_scalar; struct crypto_bignum *peer_commit_scalar_accepted;