From 21af6d15a8f0542a5677bd8b8b8f7298c65052c6 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 6 Oct 2012 19:30:54 +0300 Subject: [PATCH] SAE: Add Finite Cyclic Group negotiation and Send-Confirm This replaces the previously used bogus test data in SAE messages with the first real field. The actual SAE authentication mechanism is still missing and the Scaler, Element, and Confirm fields are not included. Signed-hostap: Jouni Malinen --- src/ap/ieee802_11.c | 107 +++++++++++++++++++++++++++--- src/ap/sta_info.h | 1 + wpa_supplicant/sme.c | 73 +++++++++++++++++--- wpa_supplicant/wpa_supplicant_i.h | 6 ++ 4 files changed, 170 insertions(+), 17 deletions(-) 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 */