From: Jouni Malinen Date: Wed, 25 Mar 2020 22:10:16 +0000 (+0200) Subject: Process Transition Disable KDE in station mode X-Git-Tag: hostap_2_10~1561 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d1857cf35c8b52c21df672bd277058af542edce;p=thirdparty%2Fhostap.git Process Transition Disable KDE in station mode Check whether the Transition Disable KDE is received from an authenticated AP and if so, whether it contains valid indication for disabling a transition mode. If that is the case, update the local network profile by removing the less secure options. Signed-off-by: Jouni Malinen --- diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index aaeb13023..128474302 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -2784,6 +2784,16 @@ static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie) return 0; } + if (pos[1] >= RSN_SELECTOR_LEN + 1 && + RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) { + ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN; + ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, + "WPA: Transition Disable KDE in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + return 0; } diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index bcdf160b6..da58159e4 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -516,6 +516,8 @@ struct wpa_eapol_ie_parse { size_t ftie_len; const u8 *ip_addr_req; const u8 *ip_addr_alloc; + const u8 *transition_disable; + size_t transition_disable_len; const u8 *oci; size_t oci_len; const u8 *osen; diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 12906708a..7471f0d15 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -380,6 +380,9 @@ extern "C" { #define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED " #define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED " +/* Transition mode disabled indication - followed by bitmap */ +#define TRANSITION_DISABLE "TRANSITION-DISABLE " + #ifndef BIT #define BIT(x) (1U << (x)) #endif diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 14fe0846d..1c8966422 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -1771,6 +1771,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, sm->cur_pmksa = sa; } + if (ie.transition_disable) + wpa_sm_transition_disable(sm, ie.transition_disable[0]); sm->msg_3_of_4_ok = 1; return; @@ -4809,6 +4811,9 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len) sm->fils_completed = 1; forced_memzero(&gd, sizeof(gd)); + if (kde.transition_disable) + wpa_sm_transition_disable(sm, kde.transition_disable[0]); + return 0; fail: forced_memzero(&gd, sizeof(gd)); diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 02b5df883..1f22f2f26 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -85,6 +85,7 @@ struct wpa_sm_ctx { void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src, const u8 *pkt, size_t pkt_len); int (*channel_info)(void *ctx, struct wpa_channel_info *ci); + void (*transition_disable)(void *ctx, u8 bitmap); }; diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 5fd70a498..5178c28cb 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -426,6 +426,12 @@ static inline int wpa_sm_channel_info(struct wpa_sm *sm, return sm->ctx->channel_info(sm->ctx->ctx, ci); } +static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap) +{ + if (sm->ctx->transition_disable) + sm->ctx->transition_disable(sm->ctx->ctx, bitmap); +} + int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk, int ver, const u8 *dest, u16 proto, diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index a3049daf5..200a439cb 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -1238,6 +1238,73 @@ static int wpa_supplicant_channel_info(void *_wpa_s, return wpa_drv_channel_info(wpa_s, ci); } + +static void disable_wpa_wpa2(struct wpa_ssid *ssid) +{ + ssid->proto &= ~WPA_PROTO_WPA; + ssid->proto |= WPA_PROTO_RSN; + ssid->key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256); + ssid->group_cipher &= ~WPA_CIPHER_TKIP; + if (!(ssid->group_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | + WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256))) + ssid->group_cipher |= WPA_CIPHER_CCMP; + ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; +} + + +static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap) +{ + struct wpa_supplicant *wpa_s = _wpa_s; + struct wpa_ssid *ssid; + int changed = 0; + + wpa_msg(wpa_s, MSG_INFO, TRANSITION_DISABLE "%02x", bitmap); + + ssid = wpa_s->current_ssid; + if (!ssid) + return; + + if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) && + wpa_key_mgmt_sae(wpa_s->key_mgmt) && + (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) && + (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED || + (ssid->group_cipher & WPA_CIPHER_TKIP))) { + wpa_printf(MSG_DEBUG, + "WPA3-Personal transition mode disabled based on AP notification"); + disable_wpa_wpa2(ssid); + changed = 1; + } + + if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) && + wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) && + (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | + WPA_KEY_MGMT_FT_IEEE8021X | + WPA_KEY_MGMT_IEEE8021X_SHA256)) && + (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED || + (ssid->group_cipher & WPA_CIPHER_TKIP))) { + disable_wpa_wpa2(ssid); + changed = 1; + } + + if ((bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) && + wpa_s->key_mgmt == WPA_KEY_MGMT_OWE && + (ssid->key_mgmt & WPA_KEY_MGMT_OWE) && + !ssid->owe_only) { + ssid->owe_only = 1; + changed = 1; + } + + if (!changed) + return; + +#ifndef CONFIG_NO_CONFIG_WRITE + if (wpa_s->conf->update_config && + wpa_config_write(wpa_s->confname, wpa_s->conf)) + wpa_printf(MSG_DEBUG, "Failed to update configuration"); +#endif /* CONFIG_NO_CONFIG_WRITE */ +} + #endif /* CONFIG_NO_WPA */ @@ -1290,6 +1357,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk; ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx; ctx->channel_info = wpa_supplicant_channel_info; + ctx->transition_disable = wpa_supplicant_transition_disable; wpa_s->wpa = wpa_sm_init(ctx); if (wpa_s->wpa == NULL) {