]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add initial parts for SAE
authorJouni Malinen <j@w1.fi>
Sun, 30 Sep 2012 16:51:07 +0000 (19:51 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 30 Sep 2012 16:51:07 +0000 (19:51 +0300)
This introduces new AKM for SAE and FT-SAE and adds the initial parts
for going through the SAE Authentication frame exchange. The actual SAE
algorithm and new fields in Authentication frames are not yet included
in this commit and will be added separately. This version is able to
complete a dummy authentication with the correct authentication
algorithm and transaction values to allow cfg80211/mac80211 drivers to
be tested (all the missing parts can be handled with
hostapd/wpa_supplicant changes).

Signed-hostap: Jouni Malinen <j@w1.fi>

19 files changed:
hostapd/Android.mk
hostapd/Makefile
hostapd/config_file.c
src/ap/ieee802_11.c
src/ap/sta_info.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_ie.c
src/common/defs.h
src/common/ieee802_11_defs.h
src/common/wpa_common.c
src/common/wpa_common.h
src/drivers/driver.h
src/rsn_supp/wpa_ie.c
wpa_supplicant/Android.mk
wpa_supplicant/Makefile
wpa_supplicant/config.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c

index 3dc3d808a6146542c6bfe7c125d50fec0e53885d..475bdd8f1a148df2664a54a99c3453987c9eb488 100644 (file)
@@ -199,6 +199,10 @@ NEED_AES_OMAC1=y
 NEED_AES_UNWRAP=y
 endif
 
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211N
 L_CFLAGS += -DCONFIG_IEEE80211N
 endif
index f5dfce0b2683d547ed9edb7b7eda0fd7ce8dd4d4..277e1d4625b27e6dc2a41da648e7f5d8f17a6a71 100644 (file)
@@ -171,6 +171,10 @@ NEED_AES_OMAC1=y
 NEED_AES_UNWRAP=y
 endif
 
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211V
 CFLAGS += -DCONFIG_IEEE80211V
 OBJS += ../src/ap/wnm_ap.o
index 0a24ec379027e4747a500a9060a8f65efd06fd31..f9b398431130600d74c6a2c6a018264997ae1136 100644 (file)
@@ -624,6 +624,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
                else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
                        val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+               else if (os_strcmp(start, "SAE") == 0)
+                       val |= WPA_KEY_MGMT_SAE;
+               else if (os_strcmp(start, "FT-SAE") == 0)
+                       val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
                else {
                        wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
                                   line, start);
index ce20e5f8dabb35a0fff5349a54b92c40980775ab..a3ecce0719974c399bc8c8b492d75a93c600c8ad 100644 (file)
@@ -296,6 +296,51 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
 #endif /* CONFIG_IEEE80211R */
 
 
+#ifdef CONFIG_SAE
+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;
+
+       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;
+       } else if (auth_transaction == 2) {
+               if (sta->sae_state != SAE_COMMIT) {
+                       hostapd_logger(hapd, sta->addr,
+                                      HOSTAPD_MODULE_IEEE80211,
+                                      HOSTAPD_LEVEL_DEBUG,
+                                      "SAE confirm before commit");
+                       resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+               }
+               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);
+       } else {
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "unexpected SAE authentication transaction %u",
+                              auth_transaction);
+               resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+       }
+
+       sta->auth_alg = WLAN_AUTH_SAE;
+
+       send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+                       auth_transaction, resp, data, data_len);
+}
+#endif /* CONFIG_SAE */
+
+
 static void handle_auth(struct hostapd_data *hapd,
                        const struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -348,6 +393,10 @@ static void handle_auth(struct hostapd_data *hapd,
              (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
               auth_alg == WLAN_AUTH_FT) ||
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+             (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+              auth_alg == WLAN_AUTH_SAE) ||
+#endif /* CONFIG_SAE */
              ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
               auth_alg == WLAN_AUTH_SHARED_KEY))) {
                printf("Unsupported authentication algorithm (%d)\n",
@@ -356,7 +405,7 @@ static void handle_auth(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (!(auth_transaction == 1 ||
+       if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
              (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
                printf("Unknown authentication transaction number (%d)\n",
                       auth_transaction);
@@ -486,6 +535,11 @@ static void handle_auth(struct hostapd_data *hapd,
                /* handle_auth_ft_finish() callback will complete auth. */
                return;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+       case WLAN_AUTH_SAE:
+               handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+               return;
+#endif /* CONFIG_SAE */
        }
 
  fail:
@@ -779,6 +833,16 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                }
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_SAE
+               if (wpa_auth_uses_sae(sta->wpa_sm) &&
+                   sta->auth_alg != WLAN_AUTH_SAE) {
+                       wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
+                                  "SAE AKM after non-SAE auth_alg %u",
+                                  MAC2STR(sta->addr), sta->auth_alg);
+                       return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+               }
+#endif /* CONFIG_SAE */
+
 #ifdef CONFIG_IEEE80211N
                if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
                    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
index 91d6b34ce5a3874c3329b138b51a1b6f2700f380..bcebc91b2b8f3f6c72b66a2a7692c80a7a605162 100644 (file)
@@ -123,6 +123,10 @@ struct sta_info {
        struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
 
        struct os_time connected_time;
+
+#ifdef CONFIG_SAE
+       enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
+#endif /* CONFIG_SAE */
 };
 
 
index 49d817578a99d09fed684d1335e991d1d591fb50..1ba83a5eb9558e981d32ec672d69daf58fb53b83 100644 (file)
@@ -3056,3 +3056,11 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
                                       wpa_send_eapol_timeout, wpa_auth, sm);
        }
 }
+
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm)
+{
+       if (sm == NULL)
+               return 0;
+       return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
+}
index 91ba49919912c4ec36afef7692257cf66f2cc96b..6bcd99ce5a29cd0e55b63e4300c4bbf08a16342a 100644 (file)
@@ -291,4 +291,6 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
 #endif /* CONFIG_IEEE80211W */
 #endif /* CONFIG_IEEE80211V */
 
+int wpa_auth_uses_sae(struct wpa_state_machine *sm);
+
 #endif /* WPA_AUTH_H */
index 17862305f1079da36e73b240e71d8542ba001bfd..4fd0135fe6ea0a760683d0e0d2514a288e2ab68e 100644 (file)
@@ -188,6 +188,18 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                num_suites++;
        }
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_SAE */
 
 #ifdef CONFIG_RSN_TESTING
        if (rsn_testing) {
@@ -407,6 +419,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
                        selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+               else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
+                       selector = RSN_AUTH_KEY_MGMT_SAE;
+               else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
+                       selector = RSN_AUTH_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
                else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                        selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
                else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
@@ -479,6 +497,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       else if (key_mgmt & WPA_KEY_MGMT_SAE)
+               sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+       else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
+               sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
        else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
        else
index db29b5df0402f131b8302a9be3f2dfe51821da6f..f50a13302a44e3e68f764292ab054d4499031b7b 100644 (file)
@@ -38,6 +38,8 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
 #define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
 #define WPA_KEY_MGMT_WPS BIT(9)
+#define WPA_KEY_MGMT_SAE BIT(10)
+#define WPA_KEY_MGMT_FT_SAE BIT(11)
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
@@ -50,13 +52,21 @@ static inline int wpa_key_mgmt_wpa_psk(int akm)
 {
        return !!(akm & (WPA_KEY_MGMT_PSK |
                         WPA_KEY_MGMT_FT_PSK |
-                        WPA_KEY_MGMT_PSK_SHA256));
+                        WPA_KEY_MGMT_PSK_SHA256 |
+                        WPA_KEY_MGMT_SAE));
 }
 
 static inline int wpa_key_mgmt_ft(int akm)
 {
        return !!(akm & (WPA_KEY_MGMT_FT_PSK |
-                        WPA_KEY_MGMT_FT_IEEE8021X));
+                        WPA_KEY_MGMT_FT_IEEE8021X |
+                        WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sae(int akm)
+{
+       return !!(akm & (WPA_KEY_MGMT_SAE |
+                        WPA_KEY_MGMT_FT_SAE));
 }
 
 static inline int wpa_key_mgmt_sha256(int akm)
@@ -84,6 +94,7 @@ static inline int wpa_key_mgmt_wpa_any(int akm)
 #define WPA_AUTH_ALG_SHARED BIT(1)
 #define WPA_AUTH_ALG_LEAP BIT(2)
 #define WPA_AUTH_ALG_FT BIT(3)
+#define WPA_AUTH_ALG_SAE BIT(4)
 
 
 enum wpa_alg {
@@ -121,7 +132,9 @@ enum wpa_key_mgmt {
        KEY_MGMT_FT_PSK,
        KEY_MGMT_802_1X_SHA256,
        KEY_MGMT_PSK_SHA256,
-       KEY_MGMT_WPS
+       KEY_MGMT_WPS,
+       KEY_MGMT_SAE,
+       KEY_MGMT_FT_SAE
 };
 
 /**
index 2ab7fbf498204f5e23f24fbbe65e9e3f0e26949a..8b21c5321eb559501974d4c114d54da623ef92d4 100644 (file)
@@ -76,6 +76,7 @@
 #define WLAN_AUTH_OPEN                 0
 #define WLAN_AUTH_SHARED_KEY           1
 #define WLAN_AUTH_FT                   2
+#define WLAN_AUTH_SAE                  3
 #define WLAN_AUTH_LEAP                 128
 
 #define WLAN_AUTH_CHALLENGE_LEN 128
 #define WLAN_STATUS_REQ_REFUSED_SSPN 67
 #define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
 #define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
+#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
 #define WLAN_STATUS_TRANSMISSION_FAILURE 79
 
 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
index 36c308a9f7495130667df49e36eebce1efbc18b3..8d7a11cfc74b4e70cf3fb48a74b31e8727a0c4cb 100644 (file)
@@ -376,6 +376,12 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
        if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
                return WPA_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
+               return WPA_KEY_MGMT_SAE;
+       if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
+               return WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
        return 0;
 }
 #endif /* CONFIG_NO_WPA2 */
index 603166b710a50d13aa340395922c47bc3162d012..d9b32d09a3fe1a079897a0829c1a020fabbb4cea 100644 (file)
@@ -51,6 +51,8 @@
 #define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
 #define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
 #define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
 
 #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
 #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
index a9ca633707534fa1faa6c629d7c4475fe9402187..38d0180d30aa123e281aefe884004019aaa5c74f 100644 (file)
@@ -314,6 +314,9 @@ struct wpa_driver_auth_params {
         */
        int p2p;
 
+       const u8 *sae_data;
+       size_t sae_data_len;
+
 };
 
 enum wps_mode {
@@ -834,6 +837,8 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_INACTIVITY_TIMER              0x00800000
 /* Driver expects user space implementation of MLME in AP mode */
 #define WPA_DRIVER_FLAGS_AP_MLME                       0x01000000
+/* Driver supports SAE with user space SME */
+#define WPA_DRIVER_FLAGS_SAE                           0x02000000
        unsigned int flags;
 
        int max_scan_ssids;
index 6a8f9f12b7583ef0f23214058e445588c707266f..429f1e5cda382694a919d547ff0a3d7e0ae9c061 100644 (file)
@@ -164,6 +164,12 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+       } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
        } else {
                wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
                           key_mgmt);
index 90dd84e06a0eb5d8584518f2d170e6369dc91dde..cc334c8c205a76cfbb69a683516e33941ed833b1 100644 (file)
@@ -179,6 +179,10 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_TDLS
 L_CFLAGS += -DCONFIG_TDLS
 OBJS += src/rsn_supp/tdls.c
index 227fb4fd9b3282535892e72aabf9f96244cfe0a8..9684cfad9e2f36b0649d40e962d0b9b446035540 100644 (file)
@@ -172,6 +172,10 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211V
 CFLAGS += -DCONFIG_IEEE80211V
 OBJS += wnm_sta.o
index be2102971aad6a64bcc085c217769271801c2f2c..674766ece764802b03bdf58a55eeffef21b0ac4a 100644 (file)
@@ -504,6 +504,12 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                else if (os_strcmp(start, "WPS") == 0)
                        val |= WPA_KEY_MGMT_WPS;
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+               else if (os_strcmp(start, "SAE") == 0)
+                       val |= WPA_KEY_MGMT_SAE;
+               else if (os_strcmp(start, "FT-SAE") == 0)
+                       val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
                else {
                        wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
                                   line, start);
index b09e5f180209577e2f8d96e86128c69332dcdcad..02c44d436ca2ae5e01215a51838d6dcc0c3a34c9 100644 (file)
@@ -39,8 +39,47 @@ static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
 #endif /* CONFIG_IEEE80211W */
 
 
-void sme_authenticate(struct wpa_supplicant *wpa_s,
-                     struct wpa_bss *bss, struct wpa_ssid *ssid)
+#ifdef CONFIG_SAE
+
+static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(4 + 4);
+       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 */
+
+       return buf;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(4 + 4);
+       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 */
+
+       return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+void sme_send_authentication(struct wpa_supplicant *wpa_s,
+                            struct wpa_bss *bss, struct wpa_ssid *ssid,
+                            int start)
 {
        struct wpa_driver_auth_params params;
        struct wpa_ssid *old_ssid;
@@ -51,6 +90,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        const u8 *md = NULL;
 #endif /* CONFIG_IEEE80211R */
        int i, bssid_changed;
+       struct wpabuf *resp = NULL;
 
        if (bss == NULL) {
                wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -95,6 +135,21 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
                        "0x%x", params.auth_alg);
        }
+#ifdef CONFIG_SAE
+       if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
+               const u8 *rsn;
+               struct wpa_ie_data ied;
+
+               rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+               if (rsn &&
+                   wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0) {
+                       if (wpa_key_mgmt_sae(ied.key_mgmt)) {
+                               wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
+                               params.auth_alg = WPA_AUTH_ALG_SAE;
+                       }
+               }
+       }
+#endif /* CONFIG_SAE */
 
        for (i = 0; i < NUM_WEP_KEYS; i++) {
                if (ssid->wep_key_len[i])
@@ -265,6 +320,19 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_SAE
+       if (params.auth_alg == WPA_AUTH_ALG_SAE) {
+               if (start)
+                       resp = sme_auth_build_sae_commit(wpa_s);
+               else
+                       resp = sme_auth_build_sae_confirm(wpa_s);
+               if (resp == NULL)
+                       return;
+               params.sae_data = wpabuf_head(resp);
+               params.sae_data_len = wpabuf_len(resp);
+       }
+#endif /* CONFIG_SAE */
+
        wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
 
@@ -287,6 +355,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                        "driver failed");
                wpas_connection_failed(wpa_s, bss->bssid);
                wpa_supplicant_mark_disassoc(wpa_s);
+               wpabuf_free(resp);
                return;
        }
 
@@ -297,7 +366,45 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
         * Association will be started based on the authentication event from
         * the driver.
         */
+
+       wpabuf_free(resp);
+}
+
+
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+                     struct wpa_bss *bss, struct wpa_ssid *ssid)
+{
+       sme_send_authentication(wpa_s, bss, ssid, 1);
+}
+
+
+#ifdef CONFIG_SAE
+static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
+                       u16 status_code, const u8 *data, size_t len)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
+               "status code %u", auth_transaction, status_code);
+       wpa_hexdump(MSG_DEBUG, "SME: SAE fields", data, len);
+
+       if (status_code != WLAN_STATUS_SUCCESS)
+               return -1;
+
+       if (auth_transaction == 1) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
+               if (wpa_s->current_bss == NULL ||
+                   wpa_s->current_ssid == NULL)
+                       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");
+               return 1;
+       }
+
+       return -1;
 }
+#endif /* CONFIG_SAE */
 
 
 void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
@@ -324,14 +431,23 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
        }
 
        wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
-               " auth_type=%d status_code=%d",
+               " auth_type=%d auth_transaction=%d status_code=%d",
                MAC2STR(data->auth.peer), data->auth.auth_type,
-               data->auth.status_code);
+               data->auth.auth_transaction, data->auth.status_code);
        wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
                    data->auth.ies, data->auth.ies_len);
 
        eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
 
+#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)
+                       return;
+       }
+#endif /* CONFIG_SAE */
+
        if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
                wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status "
                        "code %d)", data->auth.status_code);
index fe2894935df15e58ecd65786f670af92a73700b8..f1efe6ba8e886ff887c6e17fc5d201a41618ef92 100644 (file)
@@ -1073,6 +1073,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 
        sel = ie.key_mgmt & ssid->key_mgmt;
+#ifdef CONFIG_SAE
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+               sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
        if (0) {
 #ifdef CONFIG_IEEE80211R
        } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
@@ -1082,6 +1086,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+       } else if (sel & WPA_KEY_MGMT_SAE) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+       } else if (sel & WPA_KEY_MGMT_FT_SAE) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+#endif /* CONFIG_SAE */
 #ifdef CONFIG_IEEE80211W
        } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;