SAE: Use Anti-Clogging Token Container element with H2E
IEEE P802.11-REVmd was modified to use a container IE for anti-clogging token whenver H2E is used so that parsing of the SAE Authentication frames can be simplified. See this document for more details of the approved changes: https://mentor.ieee.org/802.11/dcn/19/11-19-2154-02-000m-sae-anti-clogging-token.docx Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
e36a5894d0
commit
5e32fb0170
4 changed files with 98 additions and 54 deletions
|
@ -658,7 +658,7 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
|
|||
|
||||
|
||||
static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
|
||||
int group, const u8 *addr)
|
||||
int group, const u8 *addr, int h2e)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
u8 *token;
|
||||
|
@ -684,12 +684,19 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
|
|||
sizeof(hapd->sae_pending_token_idx));
|
||||
}
|
||||
|
||||
buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
|
||||
buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
|
||||
|
||||
if (h2e) {
|
||||
/* Encapsulate Anti-clogging Token field in a container IE */
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
|
||||
}
|
||||
|
||||
p_idx = sae_token_hash(hapd, addr);
|
||||
token_idx = hapd->sae_pending_token_idx[p_idx];
|
||||
if (!token_idx) {
|
||||
|
@ -1332,11 +1339,17 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
|||
}
|
||||
|
||||
if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
|
||||
int h2e = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE: Request anti-clogging token from "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
if (sta->sae->tmp)
|
||||
h2e = sta->sae->tmp->h2e;
|
||||
if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
|
||||
h2e = 1;
|
||||
data = auth_build_token_req(hapd, sta->sae->group,
|
||||
sta->addr);
|
||||
sta->addr, h2e);
|
||||
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
|
||||
if (hapd->conf->mesh & MESH_ENABLED)
|
||||
sae_set_state(sta, SAE_NOTHING,
|
||||
|
|
|
@ -476,6 +476,7 @@
|
|||
#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
|
||||
#define WLAN_EID_EXT_EDMG_OPERATION 62
|
||||
#define WLAN_EID_EXT_REJECTED_GROUPS 92
|
||||
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
|
||||
|
||||
/* Extended Capabilities field */
|
||||
#define WLAN_EXT_CAPAB_20_40_COEX 0
|
||||
|
|
|
@ -1631,7 +1631,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
|
|||
return;
|
||||
|
||||
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
|
||||
if (token) {
|
||||
if (!sae->tmp->h2e && token) {
|
||||
wpabuf_put_buf(buf, token);
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
|
||||
wpabuf_head(token), wpabuf_len(token));
|
||||
|
@ -1677,6 +1677,16 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
|
|||
wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
|
||||
wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
|
||||
}
|
||||
|
||||
if (sae->tmp->h2e && token) {
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(buf, 1 + wpabuf_len(token));
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
|
||||
wpabuf_put_buf(buf, token);
|
||||
wpa_hexdump_buf(MSG_DEBUG,
|
||||
"SAE: Anti-clogging token (in container)",
|
||||
token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1742,32 +1752,34 @@ static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end)
|
|||
}
|
||||
|
||||
|
||||
static int sae_is_token_container_elem(const u8 *pos, const u8 *end)
|
||||
{
|
||||
return end - pos >= 3 &&
|
||||
pos[0] == WLAN_EID_EXTENSION &&
|
||||
pos[1] >= 1 &&
|
||||
end - pos - 2 >= pos[1] &&
|
||||
pos[2] == WLAN_EID_EXT_ANTI_CLOGGING_TOKEN;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
size_t scalar_elem_len, tlen;
|
||||
const u8 *elem;
|
||||
|
||||
if (token)
|
||||
*token = NULL;
|
||||
if (token_len)
|
||||
*token_len = 0;
|
||||
|
||||
if (h2e)
|
||||
return; /* No Anti-Clogging Token field outside container IE */
|
||||
|
||||
scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
|
||||
if (scalar_elem_len >= (size_t) (end - *pos))
|
||||
return; /* No extra data beyond peer scalar and element */
|
||||
|
||||
/* It is a bit difficult to parse this now that there is an
|
||||
* optional variable length Anti-Clogging Token field and
|
||||
* optional variable length Password Identifier element in the
|
||||
* frame. We are sending out fixed length Anti-Clogging Token
|
||||
* fields, so use that length as a requirement for the received
|
||||
* token and check for the presence of possible Password
|
||||
* Identifier element based on the element header information.
|
||||
* When parsing H2E case, also consider the Rejected Groupd element
|
||||
* similarly.
|
||||
*/
|
||||
tlen = end - (*pos + scalar_elem_len);
|
||||
|
||||
if (tlen < SHA256_MAC_LEN) {
|
||||
|
@ -1777,36 +1789,6 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
|
|||
return;
|
||||
}
|
||||
|
||||
elem = *pos + scalar_elem_len;
|
||||
if (sae_is_password_id_elem(elem, end)) {
|
||||
/* Password Identifier element takes out all available
|
||||
* extra octets, so there can be no Anti-Clogging token in
|
||||
* this frame. */
|
||||
return;
|
||||
}
|
||||
if (h2e && sae_is_rejected_groups_elem(elem, end)) {
|
||||
/* Rejected Groups takes out all available extra octets, so
|
||||
* there can be no Anti-Clogging token in this frame. */
|
||||
return;
|
||||
}
|
||||
|
||||
elem += SHA256_MAC_LEN;
|
||||
if (sae_is_password_id_elem(elem, end)) {
|
||||
/* Password Identifier element is included in the end, so
|
||||
* remove its length from the Anti-Clogging token field. */
|
||||
tlen -= 2 + elem[1];
|
||||
elem += 2 + elem[1];
|
||||
if (h2e && sae_is_rejected_groups_elem(elem, end)) {
|
||||
/* Also remove Rejected Groups element from the
|
||||
* Anti-Clogging token field length */
|
||||
tlen -= 2 + elem[1];
|
||||
}
|
||||
} else if (h2e && sae_is_rejected_groups_elem(elem, end)) {
|
||||
/* Rejected Groups element is included in the end, so
|
||||
* remove its length from the Anti-Clogging token field. */
|
||||
tlen -= 2 + elem[1];
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
|
||||
if (token)
|
||||
*token = *pos;
|
||||
|
@ -1816,6 +1798,21 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
|
|||
}
|
||||
|
||||
|
||||
static void sae_parse_token_container(struct sae_data *sae,
|
||||
const u8 *pos, const u8 *end,
|
||||
const u8 **token, size_t *token_len)
|
||||
{
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
|
||||
pos, end - pos);
|
||||
if (!sae_is_token_container_elem(pos, end))
|
||||
return;
|
||||
*token = pos + 3;
|
||||
*token_len = pos[1] - 1;
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)",
|
||||
*token, *token_len);
|
||||
}
|
||||
|
||||
|
||||
static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
|
||||
const u8 *end)
|
||||
{
|
||||
|
@ -2010,19 +2007,21 @@ static int sae_parse_password_identifier(struct sae_data *sae,
|
|||
|
||||
|
||||
static int sae_parse_rejected_groups(struct sae_data *sae,
|
||||
const u8 *pos, const u8 *end)
|
||||
const u8 **pos, const u8 *end)
|
||||
{
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
|
||||
pos, end - pos);
|
||||
if (!sae_is_rejected_groups_elem(pos, end))
|
||||
*pos, end - *pos);
|
||||
if (!sae_is_rejected_groups_elem(*pos, end))
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
wpabuf_free(sae->tmp->peer_rejected_groups);
|
||||
sae->tmp->peer_rejected_groups = wpabuf_alloc(pos[1] - 1);
|
||||
sae->tmp->peer_rejected_groups = wpabuf_alloc((*pos)[1] - 1);
|
||||
if (!sae->tmp->peer_rejected_groups)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
wpabuf_put_data(sae->tmp->peer_rejected_groups, pos + 3, pos[1] - 1);
|
||||
wpabuf_put_data(sae->tmp->peer_rejected_groups, (*pos) + 3,
|
||||
(*pos)[1] - 1);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list",
|
||||
sae->tmp->peer_rejected_groups);
|
||||
*pos = *pos + 2 + (*pos)[1];
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -2062,11 +2061,15 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
|
|||
|
||||
/* Conditional Rejected Groups element */
|
||||
if (h2e) {
|
||||
res = sae_parse_rejected_groups(sae, pos, end);
|
||||
res = sae_parse_rejected_groups(sae, &pos, end);
|
||||
if (res != WLAN_STATUS_SUCCESS)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Optional Anti-Clogging Token Container element */
|
||||
if (h2e)
|
||||
sae_parse_token_container(sae, pos, end, token, token_len);
|
||||
|
||||
/*
|
||||
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
|
||||
* the values we sent which would be evidence of a reflection attack.
|
||||
|
|
|
@ -170,7 +170,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
|
|||
os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
|
||||
|
||||
reuse_data:
|
||||
len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
|
||||
len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0;
|
||||
if (ssid->sae_password_id)
|
||||
len += 4 + os_strlen(ssid->sae_password_id);
|
||||
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
|
||||
|
@ -1181,11 +1181,16 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
|
|||
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
|
||||
int default_groups[] = { 19, 20, 21, 0 };
|
||||
u16 group;
|
||||
const u8 *token_pos;
|
||||
size_t token_len;
|
||||
int h2e = 0;
|
||||
|
||||
groups = wpa_s->conf->sae_groups;
|
||||
if (!groups || groups[0] <= 0)
|
||||
groups = default_groups;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "SME: SAE anti-clogging token request",
|
||||
data, len);
|
||||
if (len < sizeof(le16)) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||
"SME: Too short SAE anti-clogging token request");
|
||||
|
@ -1203,8 +1208,30 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
|
|||
return -1;
|
||||
}
|
||||
wpabuf_free(wpa_s->sme.sae_token);
|
||||
wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
|
||||
len - sizeof(le16));
|
||||
token_pos = data + sizeof(le16);
|
||||
token_len = len - sizeof(le16);
|
||||
if (wpa_s->sme.sae.tmp)
|
||||
h2e = wpa_s->sme.sae.tmp->h2e;
|
||||
if (h2e) {
|
||||
if (token_len < 3) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||
"SME: Too short SAE anti-clogging token container");
|
||||
return -1;
|
||||
}
|
||||
if (token_pos[0] != WLAN_EID_EXTENSION ||
|
||||
token_pos[1] == 0 ||
|
||||
token_pos[1] > token_len - 2 ||
|
||||
token_pos[2] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||
"SME: Invalid SAE anti-clogging token container header");
|
||||
return -1;
|
||||
}
|
||||
token_len = token_pos[1] - 1;
|
||||
token_pos += 3;
|
||||
}
|
||||
wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
|
||||
wpa_s->sme.sae_token);
|
||||
if (!external)
|
||||
sme_send_authentication(wpa_s, wpa_s->current_bss,
|
||||
wpa_s->current_ssid, 2);
|
||||
|
|
Loading…
Reference in a new issue