This commit adds compilation flags and configuration variables to disable or enable Operating Channel Verification (OCV) support. Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@xxxxxxxxxxxxxx> --- hostapd/Android.mk | 5 +++ hostapd/Makefile | 5 +++ hostapd/android.config | 3 ++ hostapd/config_file.c | 6 ++++ hostapd/defconfig | 3 ++ hostapd/hostapd.conf | 7 ++++ src/ap/ap_config.c | 9 ++++++ src/ap/ap_config.h | 4 +++ src/ap/hs20.c | 4 +++ src/ap/wpa_auth.h | 5 +++ src/ap/wpa_auth_glue.c | 3 ++ src/ap/wpa_auth_i.h | 3 ++ src/ap/wpa_auth_ie.c | 34 +++++++++++++++++++- src/common/wpa_common.h | 3 +- src/rsn_supp/wpa.c | 4 +++ src/rsn_supp/wpa.h | 3 +- src/rsn_supp/wpa_ft.c | 2 ++ src/rsn_supp/wpa_i.h | 1 + src/rsn_supp/wpa_ie.c | 2 ++ tests/hwsim/example-hostapd.config | 2 ++ tests/hwsim/example-wpa_supplicant.config | 2 ++ wlantest/Makefile | 1 + wlantest/bss.c | 5 +-- wlantest/ctrl.c | 3 ++ wlantest/sta.c | 11 +++++-- wpa_supplicant/Android.mk | 5 +++ wpa_supplicant/Makefile | 5 +++ wpa_supplicant/android.config | 3 ++ wpa_supplicant/ap.c | 4 +++ wpa_supplicant/config.c | 39 +++++++++++++++++++++++ wpa_supplicant/config_file.c | 9 ++++++ wpa_supplicant/config_ssid.h | 11 +++++++ wpa_supplicant/defconfig | 5 ++- wpa_supplicant/mesh.c | 3 ++ wpa_supplicant/mesh_rsn.c | 8 +++-- wpa_supplicant/wpa_supplicant.c | 3 ++ wpa_supplicant/wpa_supplicant.conf | 7 ++++ 37 files changed, 221 insertions(+), 11 deletions(-) diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 322f6a632..82d43c754 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -235,6 +235,11 @@ L_CFLAGS += -DCONFIG_SUITEB192 NEED_SHA384=y endif +ifdef CONFIG_OCV +L_CFLAGS += -DCONFIG_OCV +CONFIG_IEEE80211W=y +endif + ifdef CONFIG_IEEE80211W L_CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y diff --git a/hostapd/Makefile b/hostapd/Makefile index 2ce8b7ded..d88964c32 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -278,6 +278,11 @@ CFLAGS += -DCONFIG_SUITEB192 NEED_SHA384=y endif +ifdef CONFIG_OCV +CFLAGS += -DCONFIG_OCV +CONFIG_IEEE80211W=y +endif + ifdef CONFIG_IEEE80211W CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y diff --git a/hostapd/android.config b/hostapd/android.config index 08d21f044..60734e166 100644 --- a/hostapd/android.config +++ b/hostapd/android.config @@ -50,6 +50,9 @@ CONFIG_DRIVER_NL80211_QCA=y # Driver support is also needed for IEEE 802.11w. CONFIG_IEEE80211W=y +# Support Operating Channel Validation +CONFIG_OCV=y + # Integrated EAP server #CONFIG_EAP=y diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 37308dbcc..03ba7a9bb 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -3296,6 +3296,12 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + } else if (os_strcmp(buf, "ocv") == 0) { + bss->ocv = atoi(pos); + if (bss->ocv && !bss->ieee80211w) + bss->ieee80211w = 1; +#endif /* CONFIG_OCV */ #ifdef CONFIG_IEEE80211N } else if (os_strcmp(buf, "ieee80211n") == 0) { conf->ieee80211n = atoi(pos); diff --git a/hostapd/defconfig b/hostapd/defconfig index c67c6622d..0a129aa34 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -53,6 +53,9 @@ CONFIG_RSN_PREAUTH=y # IEEE 802.11w (management frame protection) CONFIG_IEEE80211W=y +# Support Operating Channel Validation +CONFIG_OCV=y + # Integrated EAP server CONFIG_EAP=y diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 70f9713d3..e6e49f318 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1418,6 +1418,13 @@ own_ip_addr=127.0.0.1 # dot11AssociationSAQueryRetryTimeout, 1...4294967295 #assoc_sa_query_retry_timeout=201 +# ocv: Operating Channel Validation +# This is a countermeasure against multi-channel man-in-the-middle attacks. +# Enabling this automatically also enables ieee80211w, if not yet enabled. +# 0 = disabled (default) +# 1 = enabled +#ocv=1 + # disable_pmksa_caching: Disable PMKSA caching # This parameter can be used to disable caching of PMKSA created through EAP # authentication. RSN preauthentication may still end up using PMKSA caching if diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 820cba956..27f014580 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -1002,6 +1002,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, } #endif /* CONFIG_MBO */ +#ifdef CONFIG_OCV + if (full_config && bss->ieee80211w == NO_MGMT_FRAME_PROTECTION && + bss->ocv) { + wpa_printf(MSG_ERROR, + "OCV: PMF needs to be enabled whenever using OCV"); + return -1; + } +#endif /* CONFIG_OCV */ + return 0; } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 5b7112609..450295ada 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -42,6 +42,7 @@ struct mesh_conf { #define MESH_CONF_SEC_AMPE BIT(2) unsigned int security; enum mfp_options ieee80211w; + int ocv; unsigned int pairwise_cipher; unsigned int group_cipher; unsigned int mgmt_group_cipher; @@ -335,6 +336,9 @@ struct hostapd_bss_config { /* dot11AssociationSAQueryRetryTimeout (in TUs) */ int assoc_sa_query_retry_timeout; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + int ocv; /* Operating Channel Validation */ +#endif /* CONFIG_OCV */ enum { PSK_RADIUS_IGNORED = 0, PSK_RADIUS_ACCEPTED = 1, diff --git a/src/ap/hs20.c b/src/ap/hs20.c index 98d016d96..4df844b5d 100644 --- a/src/ap/hs20.c +++ b/src/ap/hs20.c @@ -84,6 +84,10 @@ u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid) capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + if (hapd->conf->ocv) + capab |= WPA_CAPABILITY_OCVC; +#endif /* CONFIG_OCV */ WPA_PUT_LE16(eid, capab); eid += 2; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 5837c3e9f..2762044ff 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -192,6 +192,9 @@ struct wpa_auth_config { int group_mgmt_cipher; int sae_require_mfp; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + int ocv; /* Operating Channel Validation */ +#endif /* CONFIG_OCV */ #ifdef CONFIG_IEEE80211R_AP u8 ssid[SSID_MAX_LEN]; size_t ssid_len; @@ -319,6 +322,8 @@ int wpa_validate_osen(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, const u8 *osen_ie, size_t osen_ie_len); int wpa_auth_uses_mfp(struct wpa_state_machine *sm); +void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv); +int wpa_auth_uses_ocv(struct wpa_state_machine *sm); struct wpa_state_machine * wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *p2p_dev_addr); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 754b04462..1fbdc41a0 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -55,6 +55,9 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->wmm_enabled = conf->wmm_enabled; wconf->wmm_uapsd = conf->wmm_uapsd; wconf->disable_pmksa_caching = conf->disable_pmksa_caching; +#ifdef CONFIG_OCV + wconf->ocv = conf->ocv; +#endif /* CONFIG_OCV */ wconf->okc = conf->okc; #ifdef CONFIG_IEEE80211W wconf->ieee80211w = conf->ieee80211w; diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index b1cea1b49..a349304d5 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -92,6 +92,9 @@ struct wpa_state_machine { #endif /* CONFIG_IEEE80211R_AP */ unsigned int is_wnmsleep:1; unsigned int pmkid_set:1; +#ifdef CONFIG_OCV + unsigned int ocv_enabled:1; +#endif /* CONFIG_OCV */ u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN]; int req_replay_counter_used; diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 421dd5a6f..371be7bab 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -293,9 +293,13 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + if (conf->ocv) + capab |= WPA_CAPABILITY_OCVC; +#endif /* CONFIG_OCV */ #ifdef CONFIG_RSN_TESTING if (rsn_testing) - capab |= BIT(8) | BIT(14) | BIT(15); + capab |= BIT(8) | BIT(15); #endif /* CONFIG_RSN_TESTING */ WPA_PUT_LE16(pos, capab); pos += 2; @@ -414,6 +418,10 @@ static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid) capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + if (conf->ocv) + capab |= WPA_CAPABILITY_OCVC; +#endif /* CONFIG_OCV */ WPA_PUT_LE16(eid, capab); eid += 2; @@ -759,6 +767,18 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } #endif /* CONFIG_SAE */ +#ifdef CONFIG_OCV + if ((data.capabilities & WPA_CAPABILITY_OCVC) && !(data.capabilities & WPA_CAPABILITY_MFPC)) { + wpa_printf(MSG_DEBUG, + "Management frame protection required with OCV, but client did not enable it"); + return WPA_MGMT_FRAME_PROTECTION_VIOLATION; + } + if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC)) + wpa_auth_set_ocv(sm, 1); + else + wpa_auth_set_ocv(sm, 0); +#endif /* CONFIG_OCV */ + if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || !(data.capabilities & WPA_CAPABILITY_MFPC)) sm->mgmt_frame_prot = 0; @@ -1060,6 +1080,18 @@ int wpa_auth_uses_mfp(struct wpa_state_machine *sm) return sm ? sm->mgmt_frame_prot : 0; } +void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv) +{ + if (sm == NULL) + return; + sm->ocv_enabled = ocv; +} + +int wpa_auth_uses_ocv(struct wpa_state_machine *sm) +{ + return sm ? sm->ocv_enabled : 0; +} + #ifdef CONFIG_OWE u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm, diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 626174440..7d12b5e52 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -148,7 +148,8 @@ WPA_CIPHER_BIP_CMAC_256) #define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11) #define WPA_CAPABILITY_PBAC BIT(12) #define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13) -/* B14-B15: Reserved */ +#define WPA_CAPABILITY_OCVC BIT(14) +/* B15: Reserved */ /* IEEE 802.11r */ diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 56f3af799..774ddd9e4 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2847,6 +2847,8 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, case WPA_PARAM_MFP: sm->mfp = value; break; + case WPA_PARAM_OCV: + sm->ocv = value; default: break; } @@ -3800,6 +3802,8 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf) if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) capab |= WPA_CAPABILITY_MFPC; #endif /* CONFIG_IEEE80211W */ + if (sm->ocv) + capab |= WPA_CAPABILITY_OCVC; wpabuf_put_le16(buf, capab); /* PMKID Count */ diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index d52b8e033..b832267a5 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -97,7 +97,8 @@ enum wpa_sm_conf_params { WPA_PARAM_KEY_MGMT, WPA_PARAM_MGMT_GROUP, WPA_PARAM_RSN_ENABLED, - WPA_PARAM_MFP + WPA_PARAM_MFP, + WPA_PARAM_OCV }; struct rsn_supp_config { diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index b8d60e320..9caff859d 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -242,6 +242,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, sm->mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256) capab |= WPA_CAPABILITY_MFPC; #endif /* CONFIG_IEEE80211W */ + if (sm->ocv) + capab |= WPA_CAPABILITY_OCVC; WPA_PUT_LE16(pos, capab); pos += 2; diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index d7ea29b81..8ef27bb31 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -86,6 +86,7 @@ struct wpa_sm { int rsn_enabled; /* Whether RSN is enabled in configuration */ int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */ + int ocv; /* Operating Channel Validation */ u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ size_t assoc_wpa_ie_len; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index a3410d154..ea2e92672 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -223,6 +223,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, if (sm->mfp == 2) capab |= WPA_CAPABILITY_MFPR; #endif /* CONFIG_IEEE80211W */ + if (sm->ocv) + capab |= WPA_CAPABILITY_OCVC; WPA_PUT_LE16(pos, capab); pos += 2; diff --git a/tests/hwsim/example-hostapd.config b/tests/hwsim/example-hostapd.config index 71a207091..032465a9c 100644 --- a/tests/hwsim/example-hostapd.config +++ b/tests/hwsim/example-hostapd.config @@ -52,6 +52,8 @@ CONFIG_IEEE80211R=y CONFIG_IEEE80211N=y CONFIG_IEEE80211AC=y +CONFIG_OCV=y + CONFIG_WPS=y CONFIG_WPS_UPNP=y CONFIG_WPS_NFC=y diff --git a/tests/hwsim/example-wpa_supplicant.config b/tests/hwsim/example-wpa_supplicant.config index bc5dc2bbc..b681e9f55 100644 --- a/tests/hwsim/example-wpa_supplicant.config +++ b/tests/hwsim/example-wpa_supplicant.config @@ -63,6 +63,8 @@ CONFIG_IEEE80211R=y CONFIG_IEEE80211N=y CONFIG_IEEE80211AC=y +CONFIG_OCV=y + CONFIG_DEBUG_FILE=y CONFIG_WPS=y diff --git a/wlantest/Makefile b/wlantest/Makefile index 7104f4f58..e6c3123ac 100644 --- a/wlantest/Makefile +++ b/wlantest/Makefile @@ -47,6 +47,7 @@ OBJS_lib += ../src/crypto/libcrypto.a CFLAGS += -DCONFIG_PEERKEY CFLAGS += -DCONFIG_IEEE80211W +CFLAGS += -DCONFIG_OCV CFLAGS += -DCONFIG_IEEE80211R CFLAGS += -DCONFIG_HS20 CFLAGS += -DCONFIG_DEBUG_FILE diff --git a/wlantest/bss.c b/wlantest/bss.c index 04afe2b29..298a902c7 100644 --- a/wlantest/bss.c +++ b/wlantest/bss.c @@ -283,7 +283,7 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss, "group=%s%s%s%s%s%s%s%s%s" "mgmt_group_cipher=%s%s%s%s%s" "key_mgmt=%s%s%s%s%s%s%s%s%s" - "rsn_capab=%s%s%s%s%s", + "rsn_capab=%s%s%s%s%s%s", MAC2STR(bss->bssid), bss->proto == 0 ? "OPEN " : "", bss->proto & WPA_PROTO_WPA ? "WPA " : "", @@ -333,7 +333,8 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss, bss->rsn_capab & WPA_CAPABILITY_MFPR ? "MFPR " : "", bss->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "", bss->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ? - "PEERKEY " : ""); + "PEERKEY " : "", + bss->rsn_capab & WPA_CAPABILITY_OCVC ? "OCVC " : ""); } diff --git a/wlantest/ctrl.c b/wlantest/ctrl.c index 7de0a8aff..587a0d3e1 100644 --- a/wlantest/ctrl.c +++ b/wlantest/ctrl.c @@ -982,6 +982,9 @@ static void info_print_rsn_capab(char *buf, size_t len, int capab) if (capab & WPA_CAPABILITY_PEERKEY_ENABLED) pos += os_snprintf(pos, end - pos, "%sPEERKEY", pos == buf ? "" : " "); + if (capab & WPA_CAPABILITY_OCVC) + pos += os_snprintf(pos, end - pos, "%sOCVC", + pos == buf ? "" : " "); } diff --git a/wlantest/sta.c b/wlantest/sta.c index 1e53532a0..3e5ff51b6 100644 --- a/wlantest/sta.c +++ b/wlantest/sta.c @@ -168,13 +168,19 @@ void sta_update_assoc(struct wlantest_sta *sta, struct ieee802_11_elems *elems) "without MFP to BSS " MACSTR " that advertises " "MFPR", MAC2STR(sta->addr), MAC2STR(bss->bssid)); } + if ((sta->rsn_capab & WPA_CAPABILITY_OCVC) && + !(sta->rsn_capab & WPA_CAPABILITY_MFPC)) { + wpa_printf(MSG_INFO, "STA " MACSTR " tries to associate " + "without MFP to BSS " MACSTR " while supporting " + "OCV", MAC2STR(sta->addr), MAC2STR(bss->bssid)); + } skip_rsn_wpa: wpa_printf(MSG_INFO, "STA " MACSTR " proto=%s%s%s%s" "pairwise=%s%s%s%s%s%s%s" "key_mgmt=%s%s%s%s%s%s%s%s%s%s%s" - "rsn_capab=%s%s%s%s%s", + "rsn_capab=%s%s%s%s%s%s", MAC2STR(sta->addr), sta->proto == 0 ? "OPEN " : "", sta->proto & WPA_PROTO_WPA ? "WPA " : "", @@ -210,5 +216,6 @@ skip_rsn_wpa: sta->rsn_capab & WPA_CAPABILITY_MFPR ? "MFPR " : "", sta->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "", sta->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ? - "PEERKEY " : ""); + "PEERKEY " : "", + sta->rsn_capab & WPA_CAPABILITY_OCVC ? "OCVC " : ""); } diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index a6809956d..f3b6d2cfa 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -207,6 +207,11 @@ L_CFLAGS += -DCONFIG_SUITEB192 NEED_SHA384=y endif +ifdef CONFIG_OCV +L_CFLAGS += -DCONFIG_OCV +CONFIG_IEEE80211W=y +endif + ifdef CONFIG_IEEE80211W L_CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index c2e93e20b..69132bb57 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -240,6 +240,11 @@ CFLAGS += -DCONFIG_SUITEB192 NEED_SHA384=y endif +ifdef CONFIG_OCV +CFLAGS += -DCONFIG_OCV +CONFIG_IEEE80211W=y +endif + ifdef CONFIG_IEEE80211W CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config index c97f59131..59a02ea3f 100644 --- a/wpa_supplicant/android.config +++ b/wpa_supplicant/android.config @@ -280,6 +280,9 @@ CONFIG_L2_PACKET=linux # Driver support is also needed for IEEE 802.11w. CONFIG_IEEE80211W=y +# Support Operating Channel Validation +CONFIG_OCV=y + # Select TLS implementation # openssl = OpenSSL (default) # gnutls = GnuTLS diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index ea846a0fa..7a25b3f6a 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -494,6 +494,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, bss->ieee80211w = ssid->ieee80211w; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + bss->ocv = ssid->ocv; +#endif /* CONFIG_OCV */ + #ifdef CONFIG_WPS /* * Enable WPS by default for open and WPA/WPA2-Personal network, but diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index dd7f6036c..655c0df0a 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2035,6 +2035,42 @@ static char * wpa_config_write_mka_ckn(const struct parse_data *data, #endif /* CONFIG_MACSEC */ +#ifdef CONFIG_OCV + +static int wpa_config_parse_ocv(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + char *end; + + ssid->ocv = strtol(value, &end, 0); + if (*end || ssid->ocv < 0 || ssid->ocv > 1) { + wpa_printf(MSG_ERROR, "Line %d: Invalid ocv value '%s'.", + line, value); + return -1; + } + if (ssid->ocv && !ssid->ieee80211w) + ssid->ieee80211w = 1; + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_ocv(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *value = os_malloc(20); + if (value == NULL) + return NULL; + os_snprintf(value, 20, "%d", ssid->ocv); + value[20 - 1] = '\0'; + return value; +} +#endif /* NO_CONFIG_WRITE */ + +#endif /* CONFIG_OCV */ + + static int wpa_config_parse_peerkey(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) @@ -2238,6 +2274,9 @@ static const struct parse_data ssid_fields[] = { #ifdef CONFIG_IEEE80211W { INT_RANGE(ieee80211w, 0, 2) }, #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + { FUNC(ocv) }, +#endif /* CONFIG_OCV */ { FUNC(peerkey) /* obsolete - removed */ }, { INT_RANGE(mixed_cell, 0, 1) }, { INT_RANGE(frequency, 0, 65000) }, diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index aa73f9df6..cedec695e 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -160,6 +160,15 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) errors++; } +#ifdef CONFIG_OCV + if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION) { + wpa_printf(MSG_ERROR, + "Line %d: PMF needs to be enabled whenever using OCV", + line); + errors++; + } +#endif /* CONFIG_OCV */ + return errors; } diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 3000c43b4..e071820e4 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -457,6 +457,17 @@ struct wpa_ssid { enum mfp_options ieee80211w; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + /** + * ocv - Enable/disable operating channel validation + * + * If this parameter is set to 1, stations will exchange OCI element + * to cryptographically verify the operating channel. Setting this + * parameter to 0 disables this option. Default value: 0. + */ + int ocv; +#endif /* CONFIG_OCV */ + /** * frequency - Channel frequency in megahertz (MHz) for IBSS * diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 08f585779..951e8b86c 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -299,7 +299,10 @@ CONFIG_BACKEND=file # IEEE 802.11w (management frame protection), also known as PMF # Driver support is also needed for IEEE 802.11w. -#CONFIG_IEEE80211W=y +CONFIG_IEEE80211W=y + +# Support Operating Channel Validation +CONFIG_OCV=y # Select TLS implementation # openssl = OpenSSL (default) diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c index 38b9fb320..3da8b1b24 100644 --- a/wpa_supplicant/mesh.c +++ b/wpa_supplicant/mesh.c @@ -93,6 +93,9 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s, conf->ieee80211w = NO_MGMT_FRAME_PROTECTION; } #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + conf->ocv = ssid->ocv; +#endif /* CONFIG_OCV */ cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0); if (cipher < 0 || cipher == WPA_CIPHER_TKIP) { diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index e74cb16b0..435c90b38 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -140,7 +140,7 @@ static int auth_start_ampe(void *ctx, const u8 *addr) static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, - enum mfp_options ieee80211w) + enum mfp_options ieee80211w, int ocv) { struct wpa_auth_config conf; static const struct wpa_auth_callbacks cb = { @@ -168,6 +168,9 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, if (ieee80211w != NO_MGMT_FRAME_PROTECTION) conf.group_mgmt_cipher = rsn->mgmt_group_cipher; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + conf.ocv = ocv; +#endif /* CONFIG_OCV */ rsn->auth = wpa_init(addr, &conf, &cb, rsn); if (rsn->auth == NULL) { @@ -219,7 +222,6 @@ static void mesh_rsn_deinit(struct mesh_rsn *rsn) wpa_deinit(rsn->auth); } - struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s, struct mesh_conf *conf) { @@ -240,7 +242,7 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s, mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher; if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr, - conf->ieee80211w) < 0) { + conf->ieee80211w, conf->ocv) < 0) { mesh_rsn_deinit(mesh_rsn); os_free(mesh_rsn); return NULL; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 185a8d50f..d761eadde 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1505,6 +1505,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, wpas_get_ssid_pmf(wpa_s, ssid)); #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv); +#endif /* CONFIG_OCV */ if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE"); diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 4f5916025..b93990004 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -907,6 +907,13 @@ fast_reauth=1 # PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256 # (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used) # +# ocv: whether operating channel validation is enabled +# This is a countermeasure against multi-channel man-in-the-middle attacks. +# Enabling this automatically also enables ieee80211w, if not yet enabled. +# 0 = disabled (default) +# 1 = enabled +#ocv=1 +# # auth_alg: list of allowed IEEE 802.11 authentication algorithms # OPEN = Open System authentication (required for WPA/WPA2) # SHARED = Shared Key authentication (requires static WEP keys) -- 2.18.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap