From c10347f246d2fa0b84fbcf7b59ea634542837071 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 30 Sep 2012 19:51:07 +0300 Subject: [PATCH] Add initial parts for SAE 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 --- hostapd/Android.mk | 4 ++ hostapd/Makefile | 4 ++ hostapd/config_file.c | 6 ++ src/ap/ieee802_11.c | 66 ++++++++++++++++- src/ap/sta_info.h | 4 ++ src/ap/wpa_auth.c | 8 +++ src/ap/wpa_auth.h | 2 + src/ap/wpa_auth_ie.c | 24 +++++++ src/common/defs.h | 19 ++++- src/common/ieee802_11_defs.h | 3 + src/common/wpa_common.c | 6 ++ src/common/wpa_common.h | 2 + src/drivers/driver.h | 5 ++ src/rsn_supp/wpa_ie.c | 6 ++ wpa_supplicant/Android.mk | 4 ++ wpa_supplicant/Makefile | 4 ++ wpa_supplicant/config.c | 6 ++ wpa_supplicant/sme.c | 124 ++++++++++++++++++++++++++++++-- wpa_supplicant/wpa_supplicant.c | 12 ++++ 19 files changed, 301 insertions(+), 8 deletions(-) diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 3dc3d808a..475bdd8f1 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -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 diff --git a/hostapd/Makefile b/hostapd/Makefile index f5dfce0b2..277e1d462 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -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 diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 0a24ec379..f9b398431 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -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); diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index ce20e5f8d..a3ecce071 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -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) { diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 91d6b34ce..bcebc91b2 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -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 */ }; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 49d817578..1ba83a5eb 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -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); +} diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 91ba49919..6bcd99ce5 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -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 */ diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 17862305f..4fd0135fe 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -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 diff --git a/src/common/defs.h b/src/common/defs.h index db29b5df0..f50a13302 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -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 }; /** diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 2ab7fbf49..8b21c5321 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -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 @@ -157,6 +158,8 @@ #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) */ diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 36c308a9f..8d7a11cfc 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -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 */ diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 603166b71..d9b32d09a 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -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) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index a9ca63370..38d0180d3 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -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; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 6a8f9f12b..429f1e5cd 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -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); diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 90dd84e06..cc334c8c2 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -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 diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 227fb4fd9..9684cfad9 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -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 diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index be2102971..674766ece 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -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); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index b09e5f180..02c44d436 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -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,9 +366,47 @@ 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) { struct wpa_ssid *ssid = wpa_s->current_ssid; @@ -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); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index fe2894935..f1efe6ba8 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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;