diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index e86fd7f81..563d18fb8 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2570,6 +2570,7 @@ static const struct parse_data ssid_fields[] = { { STR_LEN(dpp_netaccesskey) }, { INT(dpp_netaccesskey_expiry) }, { STR_LEN(dpp_csign) }, + { INT_RANGE(dpp_pfs, 0, 2) }, #endif /* CONFIG_DPP */ { INT_RANGE(owe_group, 0, 65535) }, { INT_RANGE(owe_only, 0, 1) }, diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 74068d66c..074b3b31a 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -928,6 +928,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(dpp_netaccesskey); INT(dpp_netaccesskey_expiry); STR(dpp_csign); + INT(dpp_pfs); #endif /* CONFIG_DPP */ INT(owe_group); INT(owe_only); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 618145e8b..c214b6c3f 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -1002,6 +1002,22 @@ struct wpa_ssid { */ size_t dpp_csign_len; + /** + * dpp_pfs - DPP PFS + * 0: allow PFS to be used or not used + * 1: require PFS to be used (note: not compatible with DPP R1) + * 2: do not allow PFS to be used + */ + int dpp_pfs; + + /** + * dpp_pfs_fallback - DPP PFS fallback selection + * + * This is an internally used variable (i.e., not used in external + * configuration) to track state of the DPP PFS fallback mechanism. + */ + int dpp_pfs_fallback; + /** * owe_group - OWE DH Group * diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index a2b4ee765..7301d50fc 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -8106,6 +8106,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->dpp_resp_retry_time = 0; #ifdef CONFIG_DPP2 wpas_dpp_chirp_stop(wpa_s); + wpa_s->dpp_pfs_fallback = 0; #endif /* CONFIG_DPP2 */ #ifdef CONFIG_TESTING_OPTIONS os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 3758373d4..e8b8a9c98 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3196,6 +3196,10 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MBO wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid); #endif /* CONFIG_MBO */ + +#ifdef CONFIG_DPP2 + wpa_s->dpp_pfs_fallback = 0; +#endif /* CONFIG_DPP2 */ } @@ -4364,6 +4368,39 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_OWE */ +#ifdef CONFIG_DPP2 + /* Try to follow AP's PFS policy. WLAN_STATUS_ASSOC_DENIED_UNSPEC is + * the status code defined in the DPP R2 tech spec. + * WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an + * interoperability workaround with older hostapd implementation. */ + if (wpa_s->current_ssid && + wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP && + wpa_s->current_ssid->dpp_pfs == 0 && + (data->assoc_reject.status_code == + WLAN_STATUS_ASSOC_DENIED_UNSPEC || + data->assoc_reject.status_code == WLAN_STATUS_AKMP_NOT_VALID)) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + struct wpa_bss *bss = wpa_s->current_bss; + + wpa_s->current_ssid->dpp_pfs_fallback ^= 1; + if (!bss) + bss = wpa_supplicant_get_new_bss(wpa_s, bssid); + if (!bss || wpa_s->dpp_pfs_fallback) { + wpa_printf(MSG_DEBUG, + "DPP: Updated PFS policy for next try"); + wpas_connection_failed(wpa_s, bssid); + wpa_supplicant_mark_disassoc(wpa_s); + return; + } + wpa_printf(MSG_DEBUG, "DPP: Try again with updated PFS policy"); + wpa_s->dpp_pfs_fallback = 1; + wpas_connect_work_done(wpa_s); + wpa_supplicant_mark_disassoc(wpa_s); + wpa_supplicant_connect(wpa_s, bss, ssid); + return; + } +#endif /* CONFIG_DPP2 */ + #ifdef CONFIG_MBO if (data->assoc_reject.status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS && diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 71b67e4a7..a35310157 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1793,7 +1793,9 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, #ifdef CONFIG_DPP2 if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid && - wpa_s->current_ssid->dpp_netaccesskey) { + wpa_s->current_ssid->dpp_netaccesskey && + wpa_s->current_ssid->dpp_pfs != 2 && + !wpa_s->current_ssid->dpp_pfs_fallback) { struct wpa_ssid *ssid = wpa_s->current_ssid; dpp_pfs_free(wpa_s->dpp_pfs); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index a01a3e748..8016fd3ac 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -3071,7 +3071,8 @@ static u8 * wpas_populate_assoc_ies( #ifdef CONFIG_DPP2 if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP && - ssid->dpp_netaccesskey) { + ssid->dpp_netaccesskey && + ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) { dpp_pfs_free(wpa_s->dpp_pfs); wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len); diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 591e1343f..f242c3a9e 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -1461,6 +1461,12 @@ fast_reauth=1 # 1-65535 = DH Group to use for FILS PFS #fils_dh_group=0 +# DPP PFS +# 0: allow PFS to be used or not used (default) +# 1: require PFS to be used (note: not compatible with DPP R1) +# 2: do not allow PFS to be used +#dpp_pfs=0 + # MAC address policy # 0 = use permanent MAC address # 1 = use random MAC address for each ESS connection diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index b71e33583..b7cf7f4df 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1273,6 +1273,7 @@ struct wpa_supplicant { size_t dpp_last_ssid_len; #ifdef CONFIG_DPP2 struct dpp_pfs *dpp_pfs; + int dpp_pfs_fallback; struct wpabuf *dpp_presence_announcement; struct dpp_bootstrap_info *dpp_chirp_bi; int dpp_chirp_freq;