]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SAE: Use Anti-Clogging Token Container element with H2E
authorJouni Malinen <jouni@codeaurora.org>
Mon, 20 Jan 2020 18:27:06 +0000 (20:27 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 21 Jan 2020 11:13:56 +0000 (13:13 +0200)
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>
src/ap/ieee802_11.c
src/common/ieee802_11_defs.h
src/common/sae.c
wpa_supplicant/sme.c

index 5ff65b901138827104bf99ada04aaaedd3fedc32..ffa303d6927e2ca4d758cc5a2ef2177cbe08e9af 100644 (file)
@@ -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,
index d999a3665febf10e33211459f72c136214898821..ad4ef1a332f3d936b832cc98feca562279db82e1 100644 (file)
 #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
index 1682f81afe6844288a554d75c671c3ab6265d3ed..94ec1a39c1fa98483ead77c19e97bc1039172bb0 100644 (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.
index 51f8d6105b6593d4ff644b075ed387dda734fc14..ea4bad2b45a9e6ef97e633fa3b6fa83ca1bee8a6 100644 (file)
@@ -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);