From f00b9b8864e477cdd0747c4f8dbf328a7ac6d99a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 4 Sep 2015 15:32:07 +0300 Subject: [PATCH] FILS: Try to use FILS authentication if PMKSA or ERP entry is available If a PMKSA cache entry for the target AP is available, try to use FILS with PMKSA caching. If an ERP key for the target AP is available, try to use FILS with EAP-Initiate/Re-auth added as Wrapper Data element. Signed-off-by: Jouni Malinen --- src/rsn_supp/wpa.c | 88 ++++++++++++++++++++++++++++++++++++++++++++ src/rsn_supp/wpa.h | 2 + src/rsn_supp/wpa_i.h | 5 +++ wpa_supplicant/sme.c | 29 +++++++++++++-- 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index c2fc94fee..a0e37485b 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -3199,3 +3199,91 @@ void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf) sm->test_assoc_ie = buf; } #endif /* CONFIG_TESTING_OPTIONS */ + + +#ifdef CONFIG_FILS + +struct wpabuf * fils_build_auth(struct wpa_sm *sm) +{ + struct wpabuf *buf = NULL; + struct wpabuf *erp_msg; + + erp_msg = eapol_sm_build_erp_reauth_start(sm->eapol); + if (!erp_msg && !sm->cur_pmksa) { + wpa_printf(MSG_DEBUG, + "FILS: Neither ERP EAP-Initiate/Re-auth nor PMKSA cache entry is available - skip FILS"); + goto fail; + } + + wpa_printf(MSG_DEBUG, "FILS: Try to use FILS (erp=%d pmksa_cache=%d)", + erp_msg != NULL, sm->cur_pmksa != NULL); + + if (!sm->assoc_wpa_ie) { + wpa_printf(MSG_INFO, "FILS: No own RSN IE set for FILS"); + goto fail; + } + + if (random_get_bytes(sm->fils_nonce, FILS_NONCE_LEN) < 0 || + random_get_bytes(sm->fils_session, FILS_SESSION_LEN) < 0) + goto fail; + + wpa_hexdump(MSG_DEBUG, "FILS: Generated FILS Nonce", + sm->fils_nonce, FILS_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FILS: Generated FILS Session", + sm->fils_session, FILS_SESSION_LEN); + + buf = wpabuf_alloc(1000 + sm->assoc_wpa_ie_len); + if (!buf) + goto fail; + + /* Fields following the Authentication algorithm number field */ + + /* Authentication Transaction seq# */ + wpabuf_put_le16(buf, 1); + + /* Status Code */ + wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + + /* TODO: Finite Cyclic Group when using PK or PFS */ + /* TODO: Element when using PK or PFS */ + + /* RSNE */ + wpa_hexdump(MSG_DEBUG, "FILS: RSNE in FILS Authentication frame", + sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); + wpabuf_put_data(buf, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); + + /* TODO: MDE when using FILS for FT initial association */ + /* TODO: FTE when using FILS for FT initial association */ + + /* FILS Nonce */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */ + wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN); /* Length */ + /* Element ID Extension */ + wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE); + wpabuf_put_data(buf, sm->fils_nonce, FILS_NONCE_LEN); + + /* FILS Session */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */ + wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN); /* Length */ + /* Element ID Extension */ + wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION); + wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN); + + /* FILS Wrapped Data */ + if (erp_msg) { + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */ + wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */ + /* Element ID Extension */ + wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA); + wpabuf_put_buf(buf, erp_msg); + } + + wpa_hexdump_buf(MSG_DEBUG, "RSN: FILS fields for Authentication frame", + buf); + +fail: + wpabuf_free(erp_msg); + return buf; +} + +#endif /* CONFIG_FILS */ diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 0b7477f31..4b4b97378 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -426,4 +426,6 @@ extern unsigned int tdls_testing; int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf); void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf); +struct wpabuf * fils_build_auth(struct wpa_sm *sm); + #endif /* WPA_H */ diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 6f8bc3feb..5a3effc0c 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -138,6 +138,11 @@ struct wpa_sm { #ifdef CONFIG_TESTING_OPTIONS struct wpabuf *test_assoc_ie; #endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_FILS + u8 fils_nonce[FILS_NONCE_LEN]; + u8 fils_session[FILS_SESSION_LEN]; +#endif /* CONFIG_FILS */ }; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 477b4cc10..bcb6a46f4 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -549,6 +549,31 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_SAE */ + old_ssid = wpa_s->current_ssid; + wpa_s->current_ssid = ssid; + wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); + wpa_supplicant_initiate_eapol(wpa_s); + +#ifdef CONFIG_FILS + /* TODO: FILS operations can in some cases be done between different + * network_ctx (i.e., same credentials can be used with multiple + * networks). */ + if (params.auth_alg == WPA_AUTH_ALG_OPEN && + wpa_key_mgmt_fils(ssid->key_mgmt)) { + if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, + ssid, 0) == 0) + wpa_printf(MSG_DEBUG, + "SME: Try to use FILS with PMKSA caching"); + resp = fils_build_auth(wpa_s->wpa); + if (resp) { + params.auth_alg = WPA_AUTH_ALG_FILS; + params.auth_data = wpabuf_head(resp); + params.auth_data_len = wpabuf_len(resp); + wpa_s->sme.auth_alg = WPA_AUTH_ALG_FILS; + } + } +#endif /* CONFIG_FILS */ + wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_cancel_scan(wpa_s); @@ -558,10 +583,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_clear_keys(wpa_s, bss->bssid); wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING); - old_ssid = wpa_s->current_ssid; - wpa_s->current_ssid = ssid; - wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); - wpa_supplicant_initiate_eapol(wpa_s); if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s);