diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index a3ecce071..8d5268ed8 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -297,19 +297,92 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, #ifdef CONFIG_SAE + +static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(2); + if (buf == NULL) + return NULL; + + wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */ + /* TODO: Anti-Clogging Token (if requested) */ + /* TODO: Scalar */ + /* TODO: Element */ + + return buf; +} + + +static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(2); + if (buf == NULL) + return NULL; + + wpabuf_put_le16(buf, sta->sae_send_confirm); + sta->sae_send_confirm++; + /* TODO: Confirm */ + + return buf; +} + + +static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, size_t len) +{ + wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len); + + /* Check Finite Cyclic Group */ + if (len < 2) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + if (WPA_GET_LE16(data) != 19) { + wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u", + WPA_GET_LE16(data)); + return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + } + + return WLAN_STATUS_SUCCESS; +} + + +static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, size_t len) +{ + u16 rc; + + wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, len); + + if (len < 2) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + rc = WPA_GET_LE16(data); + wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc); + + 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) { u16 resp = WLAN_STATUS_SUCCESS; - u8 *data = (u8 *) "TEST"; /* TODO */ - size_t data_len = 4; + struct wpabuf *data; if (auth_transaction == 1) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "start SAE authentication (RX commit)"); - sta->sae_state = SAE_COMMIT; + resp = handle_sae_commit(hapd, sta, mgmt->u.auth.variable, + ((u8 *) mgmt) + len - + mgmt->u.auth.variable); + if (resp == WLAN_STATUS_SUCCESS) + sta->sae_state = SAE_COMMIT; } else if (auth_transaction == 2) { if (sta->sae_state != SAE_COMMIT) { hostapd_logger(hapd, sta->addr, @@ -321,10 +394,15 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "SAE authentication (RX confirm)"); - 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); + resp = handle_sae_confirm(hapd, sta, mgmt->u.auth.variable, + ((u8 *) mgmt) + len - + mgmt->u.auth.variable); + if (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); + } } else { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, @@ -335,8 +413,21 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, sta->auth_alg = WLAN_AUTH_SAE; + if (resp == WLAN_STATUS_SUCCESS) { + if (auth_transaction == 1) + data = auth_build_sae_commit(hapd, sta); + else + data = auth_build_sae_confirm(hapd, sta); + if (data == NULL) + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + } else + data = NULL; + send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, - auth_transaction, resp, data, data_len); + auth_transaction, resp, + data ? wpabuf_head(data) : (u8 *) "", + data ? wpabuf_len(data) : 0); + wpabuf_free(data); } #endif /* CONFIG_SAE */ diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index bcebc91b2..abf19cb41 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -126,6 +126,7 @@ struct sta_info { #ifdef CONFIG_SAE enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state; + u16 sae_send_confirm; #endif /* CONFIG_SAE */ }; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 02c44d436..7d863fd36 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -45,14 +45,16 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s) { struct wpabuf *buf; - buf = wpabuf_alloc(4 + 4); + buf = wpabuf_alloc(4 + 2); if (buf == NULL) return NULL; wpabuf_put_le16(buf, 1); /* Transaction seq# */ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); - wpabuf_put_str(buf, "TEST"); - /* TODO: full SAE commit */ + wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */ + /* TODO: Anti-Clogging Token (if requested) */ + /* TODO: Scalar */ + /* TODO: Element */ return buf; } @@ -62,14 +64,15 @@ static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s) { struct wpabuf *buf; - buf = wpabuf_alloc(4 + 4); + buf = wpabuf_alloc(4 + 2); if (buf == NULL) return NULL; wpabuf_put_le16(buf, 2); /* Transaction seq# */ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); - wpabuf_put_str(buf, "TEST"); - /* TODO: full SAE confirm */ + wpabuf_put_le16(buf, wpa_s->sme.sae_send_confirm); + wpa_s->sme.sae_send_confirm++; + /* TODO: Confirm */ return buf; } @@ -330,6 +333,7 @@ void sme_send_authentication(struct wpa_supplicant *wpa_s, return; params.sae_data = wpabuf_head(resp); params.sae_data_len = wpabuf_len(resp); + wpa_s->sme.sae_state = start ? SME_SAE_COMMIT : SME_SAE_CONFIRM; } #endif /* CONFIG_SAE */ @@ -374,11 +378,47 @@ void sme_send_authentication(struct wpa_supplicant *wpa_s, void sme_authenticate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { + wpa_s->sme.sae_state = SME_SAE_INIT; + wpa_s->sme.sae_send_confirm = 0; sme_send_authentication(wpa_s, bss, ssid, 1); } #ifdef CONFIG_SAE + +static int sme_sae_process_commit(struct wpa_supplicant *wpa_s, const u8 *data, + size_t len) +{ + /* Check Finite Cyclic Group */ + if (len < 2) + return -1; + if (WPA_GET_LE16(data) != 19) { + wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u", + WPA_GET_LE16(data)); + return -1; + } + + /* TODO */ + + return 0; +} + + +static int sme_sae_process_confirm(struct wpa_supplicant *wpa_s, const u8 *data, + size_t len) +{ + u16 rc; + + if (len < 2) + return -1; + rc = WPA_GET_LE16(data); + wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc); + + /* TODO */ + return 0; +} + + static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, u16 status_code, const u8 *data, size_t len) { @@ -394,11 +434,19 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if (wpa_s->current_bss == NULL || wpa_s->current_ssid == NULL) return -1; + if (wpa_s->sme.sae_state != SME_SAE_COMMIT) + return -1; + if (sme_sae_process_commit(wpa_s, data, len) < 0) + return -1; sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 0); return 0; } else if (auth_transaction == 2) { wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm"); + if (wpa_s->sme.sae_state != SME_SAE_CONFIRM) + return -1; + if (sme_sae_process_confirm(wpa_s, data, len) < 0) + return -1; return 1; } @@ -441,9 +489,16 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) #ifdef CONFIG_SAE if (data->auth.auth_type == WLAN_AUTH_SAE) { - if (sme_sae_auth(wpa_s, data->auth.auth_transaction, - data->auth.status_code, data->auth.ies, - data->auth.ies_len) != 1) + int res; + res = sme_sae_auth(wpa_s, data->auth.auth_transaction, + data->auth.status_code, data->auth.ies, + data->auth.ies_len); + if (res < 0) { + wpas_connection_failed(wpa_s, wpa_s->pending_bssid); + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + + } + if (res != 1) return; } #endif /* CONFIG_SAE */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index d23022b13..43e98830d 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -467,6 +467,12 @@ struct wpa_supplicant { u8 sched_obss_scan; u16 obss_scan_int; u16 bss_max_idle_period; + enum { + SME_SAE_INIT, + SME_SAE_COMMIT, + SME_SAE_CONFIRM + } sae_state; + u16 sae_send_confirm; } sme; #endif /* CONFIG_SME */