SAE: Add Finite Cyclic Group negotiation and Send-Confirm
authorJouni Malinen <j@w1.fi>
Sat, 6 Oct 2012 16:30:54 +0000 (19:30 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 6 Oct 2012 16:30:54 +0000 (19:30 +0300)
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 <j@w1.fi>

src/ap/ieee802_11.c
src/ap/sta_info.h
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant_i.h

index a3ecce0..8d5268e 100644 (file)
@@ -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 */
 
index bcebc91..abf19cb 100644 (file)
@@ -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 */
 };
 
index 02c44d4..7d863fd 100644 (file)
@@ -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 */
index d23022b..43e9883 100644 (file)
@@ -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 */