diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index d59a2b433..8ced9afbf 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -325,8 +325,8 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, #ifdef CONFIG_SAE -static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd, - struct sta_info *sta) +static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, + struct sta_info *sta) { struct wpabuf *buf; @@ -343,11 +343,6 @@ static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd, return NULL; } - if (sae_process_commit(sta->sae) < 0) { - wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit"); - return NULL; - } - buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); if (buf == NULL) return NULL; @@ -372,6 +367,46 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd, } +static int auth_sae_send_commit(struct hostapd_data *hapd, + struct sta_info *sta, + const u8 *bssid) +{ + struct wpabuf *data; + + data = auth_build_sae_commit(hapd, sta); + if (data == NULL) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + send_auth_reply(hapd, sta->addr, bssid, + WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS, + wpabuf_head(data), wpabuf_len(data)); + + wpabuf_free(data); + + return WLAN_STATUS_SUCCESS; +} + + +static int auth_sae_send_confirm(struct hostapd_data *hapd, + struct sta_info *sta, + const u8 *bssid) +{ + struct wpabuf *data; + + data = auth_build_sae_confirm(hapd, sta); + if (data == NULL) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + send_auth_reply(hapd, sta->addr, bssid, + WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS, + wpabuf_head(data), wpabuf_len(data)); + + wpabuf_free(data); + + return WLAN_STATUS_SUCCESS; +} + + static int use_sae_anti_clogging(struct hostapd_data *hapd) { struct sta_info *sta; @@ -441,6 +476,141 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, } +static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *bssid, u8 auth_transaction) +{ + int ret; + + if (auth_transaction != 1 && auth_transaction != 2) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + switch (sta->sae->state) { + case SAE_NOTHING: + if (auth_transaction == 1) { + ret = auth_sae_send_commit(hapd, sta, bssid); + if (ret) + return ret; + sta->sae->state = SAE_COMMITTED; + + if (sae_process_commit(sta->sae) < 0) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + /* + * In mesh case, both Commit and Confirm can be sent + * immediately. In infrastructure BSS, only a single + * Authentication frame (Commit) is expected from the AP + * here and the second one (Confirm) will be sent once + * the STA has sent its second Authentication frame + * (Confirm). + */ + if (hapd->conf->mesh & MESH_ENABLED) { + /* + * Send both Commit and Confirm immediately + * based on SAE finite state machine + * Nothing -> Confirm transition. + */ + ret = auth_sae_send_confirm(hapd, sta, bssid); + if (ret) + return ret; + sta->sae->state = SAE_CONFIRMED; + } else { + /* + * For infrastructure BSS, send only the Commit + * message now to get alternating sequence of + * Authentication frames between the AP and STA. + * Confirm will be sent in + * Commited -> Confirmed/Accepted transition + * when receiving Confirm from STA. + */ + } + } else { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "SAE confirm before commit"); + } + break; + case SAE_COMMITTED: + if (auth_transaction == 1) { + if (sae_process_commit(sta->sae) < 0) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + ret = auth_sae_send_confirm(hapd, sta, bssid); + if (ret) + return ret; + sta->sae->state = SAE_CONFIRMED; + } else if (hapd->conf->mesh & MESH_ENABLED) { + /* + * In mesh case, follow SAE finite state machine and + * send Commit now. + */ + ret = auth_sae_send_commit(hapd, sta, bssid); + if (ret) + return ret; + } else { + /* + * For instructure BSS, send the postponed Confirm from + * Nothing -> Confirmed transition that was reduced to + * Nothing -> Committed above. + */ + ret = auth_sae_send_confirm(hapd, sta, bssid); + if (ret) + return ret; + + sta->sae->state = SAE_CONFIRMED; + + /* + * Since this was triggered on Confirm RX, run another + * step to get to Accepted without waiting for + * additional events. + */ + return sae_sm_step(hapd, sta, bssid, auth_transaction); + } + break; + case SAE_CONFIRMED: + if (auth_transaction == 1) { + ret = auth_sae_send_commit(hapd, sta, bssid); + if (ret) + return ret; + + if (sae_process_commit(sta->sae) < 0) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + + ret = auth_sae_send_confirm(hapd, sta, bssid); + if (ret) + return ret; + } else { + sta->flags |= WLAN_STA_AUTH; + sta->auth_alg = WLAN_AUTH_SAE; + mlme_authenticate_indication(hapd, sta); + wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); + sta->sae->state = SAE_ACCEPTED; + wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr, + sta->sae->pmk); + } + break; + case SAE_ACCEPTED: + if (auth_transaction == 1) { + wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR + ") doing reauthentication", + MAC2STR(sta->addr)); + ap_free_sta(hapd, sta); + } else { + ret = auth_sae_send_confirm(hapd, sta, bssid); + sae_clear_temp_data(sta->sae); + if (ret) + return ret; + } + break; + default: + wpa_printf(MSG_ERROR, "SAE: invalid state %d", + sta->sae->state); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + return WLAN_STATUS_SUCCESS; +} + + static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, const struct ieee80211_mgmt *mgmt, size_t len, u8 auth_transaction) @@ -475,55 +645,34 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, return; } - if (resp == WLAN_STATUS_SUCCESS) { - if (!token && use_sae_anti_clogging(hapd)) { - wpa_printf(MSG_DEBUG, "SAE: Request anti-" - "clogging token from " MACSTR, - MAC2STR(sta->addr)); - data = auth_build_token_req(hapd, sta->addr); - resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ; - } else { - data = auth_process_sae_commit(hapd, sta); - if (data == NULL) - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - else - sta->sae->state = SAE_COMMITTED; - } + if (resp != WLAN_STATUS_SUCCESS) + goto reply; + + if (!token && use_sae_anti_clogging(hapd)) { + wpa_printf(MSG_DEBUG, + "SAE: Request anti-clogging token from " + MACSTR, MAC2STR(sta->addr)); + data = auth_build_token_req(hapd, sta->addr); + resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ; + goto reply; } + + resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction); } else if (auth_transaction == 2) { - if (sta->sae->state != SAE_COMMITTED) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "SAE confirm before commit"); - resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; - goto failed; - } hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "SAE authentication (RX confirm)"); - if (sae_check_confirm(sta->sae, mgmt->u.auth.variable, - ((u8 *) mgmt) + len - - mgmt->u.auth.variable) < 0) { - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - } else { - resp = WLAN_STATUS_SUCCESS; - sta->flags |= WLAN_STA_AUTH; - wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); - sta->auth_alg = WLAN_AUTH_SAE; - mlme_authenticate_indication(hapd, sta); - - data = auth_build_sae_confirm(hapd, sta); - if (data == NULL) + if (sta->sae->state >= SAE_CONFIRMED || + !(hapd->conf->mesh & MESH_ENABLED)) { + if (sae_check_confirm(sta->sae, mgmt->u.auth.variable, + ((u8 *) mgmt) + len - + mgmt->u.auth.variable) < 0) { resp = WLAN_STATUS_UNSPECIFIED_FAILURE; - else { - sta->sae->state = SAE_ACCEPTED; - wpa_auth_pmksa_add_sae(hapd->wpa_auth, - sta->addr, - sta->sae->pmk); - sae_clear_temp_data(sta->sae); + goto reply; } } + resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction); + } else { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, @@ -532,13 +681,13 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; } -failed: - sta->auth_alg = WLAN_AUTH_SAE; - - send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, - auth_transaction, resp, - data ? wpabuf_head(data) : (u8 *) "", - data ? wpabuf_len(data) : 0); +reply: + if (resp != WLAN_STATUS_SUCCESS) { + send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, + auth_transaction, resp, + data ? wpabuf_head(data) : (u8 *) "", + data ? wpabuf_len(data) : 0); + } wpabuf_free(data); } #endif /* CONFIG_SAE */