#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;
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;
}
+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;
}
+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)
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,
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 */