From a9af1da0b544faecf8cc03ec2f418db1dc9ced43 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 1 Mar 2019 22:05:52 +0200 Subject: [PATCH] SAE: Enforce single use for anti-clogging tokens 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 --- src/ap/hostapd.h | 2 ++ src/ap/ieee802_11.c | 66 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 733f3f22a..b8637c46a 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -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 */ diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 0da1d42fc..afa17db24 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -532,17 +532,46 @@ 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; }