]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SAE: Enforce single use for anti-clogging tokens
authorJouni Malinen <jouni@codeaurora.org>
Fri, 1 Mar 2019 20:05:52 +0000 (22:05 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 6 Mar 2019 11:07:03 +0000 (13:07 +0200)
Add a 16-bit token index into the anti-clogging token. This can be used
to enforce only a single use of each issued anti-clogging token request.
The token value is now token-index |
last-30-octets-of(HMAC-SHA256(sae_token_key, STA-MAC-address |
token-index)), i.e., the first two octets of the SHA256 hash value are
replaced with the token-index and token-index itself is protected as
part of the HMAC context data.

Track the used 16-bit token index values and accept received tokens only
if they use an index value that has been requested, but has not yet been
used. This makes it a bit more difficult for an attacker to perform DoS
attacks against the heavy CPU operations needed for processing SAE
commit since the attacker cannot simply replay the same frame multiple
times and instead, needs to request each token separately.

While this does not add significant extra processing/CPU need for the
attacker, this can be helpful in combination with the queued processing
of SAE commit messages in enforcing more delay during flooding of SAE
commit messages since the new anti-clogging token values are not
returned before the new message goes through the processing queue.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
src/ap/hostapd.h
src/ap/ieee802_11.c

index 733f3f22a59e42be560fa3ac9b25cd951d1c5124..b8637c46a2d92a5c5f7558ceead9a036c4890f8f 100644 (file)
@@ -314,6 +314,8 @@ struct hostapd_data {
        /** Key used for generating SAE anti-clogging tokens */
        u8 sae_token_key[8];
        struct os_reltime last_sae_token_key_update;
+       u16 sae_token_idx;
+       u16 sae_pending_token_idx[256];
        int dot11RSNASAERetransPeriod; /* msec */
        struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
 #endif /* CONFIG_SAE */
index 0da1d42fc0f770bd1ea7f76b65bb2a93c5eeaf6c..afa17db249ecadaff961bf3012816566888d0e63 100644 (file)
@@ -532,18 +532,47 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
 }
 
 
+static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+{
+       u8 hash[SHA256_MAC_LEN];
+
+       hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+                   addr, ETH_ALEN, hash);
+       return hash[0];
+}
+
+
 static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
                           const u8 *token, size_t token_len)
 {
        u8 mac[SHA256_MAC_LEN];
+       const u8 *addrs[2];
+       size_t len[2];
+       u16 token_idx;
+       u8 idx;
 
        if (token_len != SHA256_MAC_LEN)
                return -1;
-       if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
-                       addr, ETH_ALEN, mac) < 0 ||
-           os_memcmp_const(token, mac, SHA256_MAC_LEN) != 0)
+       idx = sae_token_hash(hapd, addr);
+       token_idx = hapd->sae_pending_token_idx[idx];
+       if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
+               wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
+                          MACSTR " - token_idx 0x%04x, expected 0x%04x",
+                          MAC2STR(addr), WPA_GET_BE16(token), token_idx);
+               return -1;
+       }
+
+       addrs[0] = addr;
+       len[0] = ETH_ALEN;
+       addrs[1] = token;
+       len[1] = 2;
+       if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+                              2, addrs, len, mac) < 0 ||
+           os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
                return -1;
 
+       hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
+
        return 0;
 }
 
@@ -554,16 +583,25 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
        struct wpabuf *buf;
        u8 *token;
        struct os_reltime now;
+       u8 idx[2];
+       const u8 *addrs[2];
+       size_t len[2];
+       u8 p_idx;
+       u16 token_idx;
 
        os_get_reltime(&now);
        if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
-           os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
+           os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) ||
+           hapd->sae_token_idx == 0xffff) {
                if (random_get_bytes(hapd->sae_token_key,
                                     sizeof(hapd->sae_token_key)) < 0)
                        return NULL;
                wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
                            hapd->sae_token_key, sizeof(hapd->sae_token_key));
                hapd->last_sae_token_key_update = now;
+               hapd->sae_token_idx = 0;
+               os_memset(hapd->sae_pending_token_idx, 0,
+                         sizeof(hapd->sae_pending_token_idx));
        }
 
        buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
@@ -572,9 +610,25 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
 
        wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
 
+       p_idx = sae_token_hash(hapd, addr);
+       token_idx = hapd->sae_pending_token_idx[p_idx];
+       if (!token_idx) {
+               hapd->sae_token_idx++;
+               token_idx = hapd->sae_token_idx;
+               hapd->sae_pending_token_idx[p_idx] = token_idx;
+       }
+       WPA_PUT_BE16(idx, token_idx);
        token = wpabuf_put(buf, SHA256_MAC_LEN);
-       hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
-                   addr, ETH_ALEN, token);
+       addrs[0] = addr;
+       len[0] = ETH_ALEN;
+       addrs[1] = idx;
+       len[1] = sizeof(idx);
+       if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+                              2, addrs, len, token) < 0) {
+               wpabuf_free(buf);
+               return NULL;
+       }
+       WPA_PUT_BE16(token, token_idx);
 
        return buf;
 }