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:
Jouni Malinen 2020-01-20 20:27:06 +02:00 committed by Jouni Malinen
parent e36a5894d0
commit 5e32fb0170
4 changed files with 98 additions and 54 deletions

View file

@ -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

View file

@ -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.