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);