From patchwork Mon Aug 6 19:46:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathy Vanhoef X-Patchwork-Id: 954205 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cs.kuleuven.be Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Jr7AnvkS"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=infradead.org header.i=@infradead.org header.b="TG7lGNgD"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41kpG62WHlz9ryt for ; Tue, 7 Aug 2018 05:52:30 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=bPvcjEnIo3VLajfxq6iZUp3r3XI1mdmtnINdhgcc6hc=; b=Jr7AnvkSncVAPkT+2f0vw5XWgU OwZDVAMFh+VSUhdqDKtoUMT3yJNzqjvS8CPLiMTd23FXgZbZP0YSTyDQhe4m+K598zQsq5d0jJX/B S9xCWT1EUM3jt0yhgw7hKBeC0e8lXyPPXO8mZsMJpcBD2XS4+xCK/UWRcJmzQ2psNA5CxlmS4a368 U5zjQEzFGygtuE96nbJbWy/6CMyoq4hOwgx+iH5sFqTwqHFOjwWHL7+cCxHQDagsQ4lDQQ3a6F+Hu buW075C4BoDIS2hftcn+ARndFQK5EAxd5/syQTPgicbTV9PleNtkRynVvPdKgLOQi/mUU5qAvcmTb pVzZEDaA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmlYG-0003dG-Uq; Mon, 06 Aug 2018 19:52:25 +0000 Received: from merlin.infradead.org ([2001:8b0:10b:1231::1]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmlXw-0002z5-NU for hostap@bombadil.infradead.org; Mon, 06 Aug 2018 19:52:05 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=merlin.20170209; h=References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Sender:Reply-To:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=ug4zzk03jH0d9UrJ9Ri/S8AQSi66C7zJVtLPuQFSKwY=; b=TG7lGNgDEaRWVhG4tHeSqqkhQ 5R/a/i5J8GLm98hXv+3c3nRofi6nSrZ/bLMfvEWA/uUVn/6+StNJ0zjHHcq2eyEQPg37MYI0I1q9l F03OiGqv/KEbj8mksAXVYkwjHYnTX14JgvIS//xO7AP+5k0Px84MeZ/gTGF1TlWlV1xxBik7V8myK Np1SKF4rB/OC6kWylYoDv6aNXIzm5ADnlQ6TAw1d/LCYKbaZh2jagn5qDlTyinFYvhs+gp22nzRQl aOImGlXoNhuQYOPbWvX9Bx2fwq7UmLaW6ON074dwM+72whoRwLHgDODl1RJaDWsiDAJO20iOmu9vK nLyCPmGbA==; Received: from vmailrelay1.cs.kuleuven.be ([2a02:2c40:0:a000::118] helo=hermes4.cs.kuleuven.be) by merlin.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmlXt-0003YK-Ew for hostap@lists.infradead.org; Mon, 06 Aug 2018 19:52:02 +0000 Received: from dr-zook.cs.kuleuven.be. (vdr-zook1.cs.kuleuven.be [IPv6:2a02:2c40:500:a005::12c]) by hermes4.cs.kuleuven.be. with ESMTP id w76JiQ9F018409 for ; Mon, 6 Aug 2018 21:44:26 +0200 Received: from localhost (localhost [127.0.0.1]) by dr-zook.cs.kuleuven.be. (8.14.4/8.14.4/Debian-4.1ubuntu1) with ESMTP id w76JiPsr020752 for ; Mon, 6 Aug 2018 21:44:25 +0200 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dr-zook.cs.kuleuven.be. X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.0 X-Virus-Scanned: Debian amavisd-new at dr-zook.cs.kuleuven.be Received: from dr-zook.cs.kuleuven.be. ([127.0.0.1]) by localhost (dr-zook.cs.kuleuven.be [127.0.0.1]) (amavisd-new, port 10023) with LMTP id d2UX16ewW8eP for ; Mon, 6 Aug 2018 21:44:18 +0200 (CEST) Received: from oryx.cs.kuleuven.be. (oryx.cs.kuleuven.be [IPv6:2a02:2c40:0:a000::122]) by dr-zook.cs.kuleuven.be. (8.14.4/8.14.4/Debian-4.1ubuntu1) with ESMTP id w76JiGo0020733 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 6 Aug 2018 21:44:16 +0200 Received: from localhost.localdomain (ip-83-134-207-58.dsl.scarlet.be [83.134.207.58]) (authenticated bits=0) by oryx.cs.kuleuven.be. (A_Good_MTA/8.14.4/Debian-4.1ubuntu1) with ESMTP id w76Jhl8o019837 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Mon, 6 Aug 2018 21:44:16 +0200 From: Maty Vanhoef To: hostap@lists.infradead.org Subject: [PATCH 07/25] OCV: Add configs for channel validation support Date: Mon, 6 Aug 2018 15:46:25 -0400 Message-Id: <20180806194643.1328-8-Mathy.Vanhoef@cs.kuleuven.be> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180806194643.1328-1-Mathy.Vanhoef@cs.kuleuven.be> References: <20180806194643.1328-1-Mathy.Vanhoef@cs.kuleuven.be> X-Scanned-By: MIMEDefang 2.73 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180806_155201_729410_C2C86CEB X-CRM114-Status: GOOD ( 23.28 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.1 on merlin.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Maty Vanhoef MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org This commit adds compilation flags and configuration variables to disable or enable Operating Channel Verification (OCV) support. Signed-off-by: Mathy Vanhoef --- 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)