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;
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) {
}
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,
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));
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);
+ }
}
}
+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) {
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;
}
+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)
{
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;
}
/* 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.
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);
(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");
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);