From patchwork Fri Jan 10 22:19:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 1221457 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) 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=fail (p=quarantine dis=none) header.from=wetzel-home.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20170209 header.b=cmsY1jED; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=wetzel-home.de header.i=@wetzel-home.de header.a=rsa-sha256 header.s=wetzel-home header.b=vCCpHHHu; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47vcqP1YfGz9sPW for ; Sat, 11 Jan 2020 09:20:01 +1100 (AEDT) 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:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version: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=1oa5W1wZE2ik3lnnR3/5wiMVDnJxd6kLkH7Yvquc980=; b=cmsY1jEDBttMhw 0Vz2CE6Zvs4rF3yz8bEItU4FrFL3cEjJjk9d7tT1rj+dtYzwKX3W8xeNrKsp1sG5sEvx6xYVAzZ9r NYxuz+9g/X/c/19XGGBfv17oQqWyKMTDHnDdb7JfLho1FGO4BksVqgh5flGiEeTy/OOpM7vzbUo8W kVFcrUL0OpCvyY1+oAbRFlZ/zIQMgtlxBxNkLh6F9viIQDrYlFA7n9a2IqrQy1AGN8XZtqUMDgj/4 BSY+J4aavtOaLp3dJnSEAbpJeFK8JNKTcZQ947BK/SHQA6EptY5xq2KVqbVn6FZhtwP/lv/hAe/QJ s3Dy/UpOoKGuY5wBSIaA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1iq2dG-0003aH-O3; Fri, 10 Jan 2020 22:19:54 +0000 Received: from 7.mo178.mail-out.ovh.net ([46.105.58.91]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1iq2d1-0003Ic-3X for hostap@lists.infradead.org; Fri, 10 Jan 2020 22:19:42 +0000 Received: from player770.ha.ovh.net (unknown [10.108.54.97]) by mo178.mail-out.ovh.net (Postfix) with ESMTP id B9446842CC for ; Fri, 10 Jan 2020 23:19:28 +0100 (CET) Received: from awhome.eu (p4FF91EE6.dip0.t-ipconnect.de [79.249.30.230]) (Authenticated sender: postmaster@awhome.eu) by player770.ha.ovh.net (Postfix) with ESMTPSA id 78F75E2E0E3C; Fri, 10 Jan 2020 22:19:25 +0000 (UTC) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1578694702; bh=Yt4C4SAWNi1k1TKeNXVGjaSQshZHnaQSuev91JjUB1A=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=vCCpHHHu16OmhmY5sGHv8AQh5aMZNWK7CDIEnSimt965TrJsYqJS/koOFmpgKxJfR Nry8YQ+H27chNvo72j/SrgTa4UD6pdJ4iaa2QWmSEYaDy/o6yItMud2+tPtOCBnkg3 6KHork9wPOQgmRO1PO1la3AJWXzgEaLyCRzmZliQ= To: j@w1.fi Subject: [PATCH 1/3] AP: Address PTK rekey issues Date: Fri, 10 Jan 2020 23:19:08 +0100 Message-Id: <20200110221910.312529-2-alexander@wetzel-home.de> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200110221910.312529-1-alexander@wetzel-home.de> References: <20200110221910.312529-1-alexander@wetzel-home.de> MIME-Version: 1.0 X-Ovh-Tracer-Id: 17901527046171335872 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedufedrvdeifedgudehgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecunecujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeetlhgvgigrnhguvghrucghvghtiigvlhcuoegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgeqnecukfhppedtrddtrddtrddtpdejledrvdegledrfedtrddvfedtnecurfgrrhgrmhepmhhouggvpehsmhhtphdqohhuthdphhgvlhhopehplhgrhigvrhejjedtrdhhrgdrohhvhhdrnhgvthdpihhnvghtpedtrddtrddtrddtpdhmrghilhhfrhhomheprghlvgigrghnuggvrhesfigvthiivghlqdhhohhmvgdruggvpdhrtghpthhtohephhhoshhtrghpsehlihhsthhsrdhinhhfrhgruggvrggurdhorhhgnecuvehluhhsthgvrhfuihiivgeptd X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200110_141939_452314_0550341D X-CRM114-Status: GOOD ( 20.46 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.105.58.91 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [46.105.58.91 listed in wl.mailspike.net] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: hostap@lists.infradead.org, Alexander Wetzel Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many broken implementations and should be avoided when using or interacting with one. The effects can be triggered by either end of the connection and range from hardly noticeable disconnects over long connection freezes up to leaking clear text MPDUs. To allow affected users to mitigate the issues the new option "wpa_deny_ptk0_rekey" has been added to replace all PTK0 rekeys with disconnects. Signed-off-by: Alexander Wetzel --- hostapd/config_file.c | 9 +++++++++ hostapd/hostapd.conf | 34 ++++++++++++++++++++++++++++++++++ src/ap/ap_config.c | 1 + src/ap/ap_config.h | 1 + src/ap/wpa_auth.c | 23 +++++++++++++++++++++-- src/ap/wpa_auth.h | 1 + src/ap/wpa_auth_glue.c | 14 ++++++++++++++ src/common/defs.h | 6 ++++++ 8 files changed, 87 insertions(+), 2 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 89e02a59a..e19653218 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2884,6 +2884,15 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->wpa_gmk_rekey = atoi(pos); } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { bss->wpa_ptk_rekey = atoi(pos); + } else if (os_strcmp(buf, "wpa_deny_ptk0_rekey") == 0) { + bss->wpa_deny_ptk0_rekey = atoi(pos); + if (bss->wpa_deny_ptk0_rekey < 0 || + bss->wpa_deny_ptk0_rekey > 2) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2", + line, bss->wpa_deny_ptk0_rekey); + return 1; + } } else if (os_strcmp(buf, "wpa_group_update_count") == 0) { char *endp; unsigned long val = strtoul(pos, &endp, 0); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 10a6291ff..bdfb62051 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -903,6 +903,8 @@ eapol_key_index_workaround=0 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable # reauthentication). +# Reauthentications may enforce a disconnect, check the related setting +# "wpa_deny_ptk0_rekey" for details. #eap_reauth_period=3600 # Use PAE group address (01:80:c2:00:00:03) instead of individual target @@ -1607,8 +1609,40 @@ own_ip_addr=127.0.0.1 # Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of # PTK to mitigate some attacks against TKIP deficiencies. +# Warning: PTK rekeying is buggy with many drivers/devices and the only secure +# method to rekey the PTK without Extended Key ID support requires a disconnect. +# Check the related setting "wpa_deny_ptk0_rekey" for details. #wpa_ptk_rekey=600 +# Workaround for PTK rekey issues +# +# Rekeying the PTK without using "Extended Key ID for Individually Addressed +# Frames" can - depending on the used cards/drivers - impact the security and +# stability of connections. Both ends can accidentally trick one end to drop +# all packets send by it till the connection is torn down or rekeyed again. +# Additionally some drivers may skip/break the encryption for the time window +# the key is updated (normally a few ms). +# +# To avoid the issues hostapd can now replace all PTK rekeys using only keyid 0 +# (PTK0 rekeys) with disconnects and forcing the remote stations to reconnect +# instead. +# +# Eap reauthentication depends on replacing the PTK and is therefore just +# another way to rekey the PTK and affected by the setting, too. +# +# "Extended Key ID for Individually Addressed Frames" is avoiding the issues +# and the setting will be ignored when using it. +# +# If you your cards/drivers - either local or remote - need the workaround for +# PTK0 rekeys you must set "wpa_deny_ptk0_rekey = 0" or - if you want to allow +# it when the local system is known to be ok - "wpa_deny_ptk0_rekey = 1". +# +# Available options: +# 0 = always rekey when configured/instructed (default) +# 1 = only rekey when the local driver is able to do it bug free +# 2 = never allow PTK0 rekeys +# wpa_deny_ptk0_rekey = 2 + # The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way # Handshake are retried per 4-Way Handshake attempt. # (dot11RSNAConfigPairwiseUpdateCount) diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index cc041441c..0142c87b0 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -64,6 +64,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->wpa_group_rekey = 600; bss->wpa_gmk_rekey = 86400; + bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS; bss->wpa_group_update_count = 4; bss->wpa_pairwise_update_count = 4; bss->wpa_disable_eapol_key_retries = diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 1efdc2b43..db8745be7 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -368,6 +368,7 @@ struct hostapd_bss_config { int wpa_strict_rekey; int wpa_gmk_rekey; int wpa_ptk_rekey; + int wpa_deny_ptk0_rekey; u32 wpa_group_update_count; u32 wpa_pairwise_update_count; int wpa_disable_eapol_key_retries; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 423528d12..f3d7b4a87 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -780,8 +780,17 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm) if (sm == NULL) return; - sm->PTKRequest = TRUE; - sm->PTK_valid = 0; + if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { + wpa_printf(MSG_WARNING, + "WPA: PTK0 rekey not allowed, disconnect " MACSTR, + MAC2STR(sm->addr)); + sm->Disconnect = TRUE; + /* Try to encourage the STA to reconnect */ + sm->disconnect_reason = WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; + } else { + sm->PTKRequest = TRUE; + sm->PTK_valid = 0; + } } @@ -1800,6 +1809,16 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) sm->Init = FALSE; sm->AuthenticationRequest = TRUE; break; + } else { + if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { + wpa_printf(MSG_WARNING, + "WPA: PTK0 rekey not allowed, disconnect " + MACSTR, MAC2STR(sm->addr)); + sm->Disconnect = TRUE; + /* Try to encourage the STA reconnect */ + sm->disconnect_reason = WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; + break; + } } if (sm->GUpdateStationKeys) { /* diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 0b4b7297c..5705694ae 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -176,6 +176,7 @@ struct wpa_auth_config { int wpa_strict_rekey; int wpa_gmk_rekey; int wpa_ptk_rekey; + int wpa_deny_ptk0_rekey; u32 wpa_group_update_count; u32 wpa_pairwise_update_count; int wpa_disable_eapol_key_retries; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index e64304636..156e71ae6 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -1370,6 +1370,20 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) _conf.tx_status = 1; if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) _conf.ap_mlme = 1; + + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) && + (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER || + (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK && + !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) { + wpa_msg(hapd->msg_ctx, MSG_INFO, + "Disable PTK0 rekey support - replaced with disconnect"); + _conf.wpa_deny_ptk0_rekey = 1; + } else { + wpa_msg(hapd->msg_ctx, MSG_WARNING, + "Support PTK0 rekey - may randomly break connections"); + _conf.wpa_deny_ptk0_rekey = 0; + } + hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd); if (hapd->wpa_auth == NULL) { wpa_printf(MSG_ERROR, "WPA initialization failed."); diff --git a/src/common/defs.h b/src/common/defs.h index 5e22278e6..1e21ec2de 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -445,4 +445,10 @@ enum key_flag { KEY_FLAG_MODIFY, }; +enum ptk0_rekey_handling { + PTK0_REKEY_ALLOW_ALWAYS, + PTK0_REKEY_ALLOW_LOCAL_OK, + PTK0_REKEY_ALLOW_NEVER +}; + #endif /* DEFS_H */ From patchwork Fri Jan 10 22:19:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 1221458 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) 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=fail (p=quarantine dis=none) header.from=wetzel-home.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20170209 header.b=LZ9E/2YD; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=wetzel-home.de header.i=@wetzel-home.de header.a=rsa-sha256 header.s=wetzel-home header.b=fY8RBzbp; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47vcqc5J2Dz9sPW for ; Sat, 11 Jan 2020 09:20:12 +1100 (AEDT) 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:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version: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=ZrZZvq6frWdtTzdcZvwafOu1Bv4sS/ACibX+Elv2/Js=; b=LZ9E/2YD81aG5p Jn8Q4J7XP3zd7B47TAtRUC0GSNIRr1wh8SiJo0ZRhw/LiFxh1oJSa3BJG4z19DH52uY+U235vZ6rm YinVRzYgF6rwsed34J1GdmI6c02LrycZOWzgkSWpqQXonHgq1P+rJ7TY1OzGL4Nixepd8MeXKHGMF HpJ0ftcxykp7W9F/dihjfXa/cKF6dlange0kKG9oWbYgcmgX/7teKdMPwt3JjYvowrROeBHH7EG4C eqOQ9wB7VbkCGZQR0rQUI70RFE+vSNirkts3VGB4QygwxWpw9MAT31SSi0wFwxRo81RM98ZavkrOX R7om0UQGnqiotGJlnAwQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1iq2dR-0003oN-Ti; Fri, 10 Jan 2020 22:20:05 +0000 Received: from 4.mo4.mail-out.ovh.net ([178.32.98.131]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1iq2d1-0003Ib-3o for hostap@lists.infradead.org; Fri, 10 Jan 2020 22:19:43 +0000 Received: from player696.ha.ovh.net (unknown [10.108.35.159]) by mo4.mail-out.ovh.net (Postfix) with ESMTP id C542C21EDFE for ; Fri, 10 Jan 2020 23:19:28 +0100 (CET) Received: from awhome.eu (p4FF91EE6.dip0.t-ipconnect.de [79.249.30.230]) (Authenticated sender: postmaster@awhome.eu) by player696.ha.ovh.net (Postfix) with ESMTPSA id 7949FE250538; Fri, 10 Jan 2020 22:19:25 +0000 (UTC) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1578694702; bh=5IWqIzEFGxVtNAMt/yI+ozNlgkTfjaG6DKeyarpBDlA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=fY8RBzbpAq2BMt51rNloHuDb6a7HgQP+7K72DZsBfHcm+F8aj0CmRjVZeMUlMrG8L t4QdjMaIVAWP2pK4apVAP0lButcTJYlYM0c+MmaRFf7YruoFb1b84D6oPTtraFvYq+ EJnboe/CE9Wxhwf96H2Dy6w4mvTxnJSBOlBu7R20= To: j@w1.fi Subject: [PATCH 2/3] wpa_supplicant: Address PTK rekey issues Date: Fri, 10 Jan 2020 23:19:09 +0100 Message-Id: <20200110221910.312529-3-alexander@wetzel-home.de> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200110221910.312529-1-alexander@wetzel-home.de> References: <20200110221910.312529-1-alexander@wetzel-home.de> MIME-Version: 1.0 X-Ovh-Tracer-Id: 17901527048036818112 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedufedrvdeifedgudehhecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecunecujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeetlhgvgigrnhguvghrucghvghtiigvlhcuoegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgeqnecukfhppedtrddtrddtrddtpdejledrvdegledrfedtrddvfedtnecurfgrrhgrmhepmhhouggvpehsmhhtphdqohhuthdphhgvlhhopehplhgrhigvrheileeirdhhrgdrohhvhhdrnhgvthdpihhnvghtpedtrddtrddtrddtpdhmrghilhhfrhhomheprghlvgigrghnuggvrhesfigvthiivghlqdhhohhmvgdruggvpdhrtghpthhtohephhhoshhtrghpsehlihhsthhsrdhinhhfrhgruggvrggurdhorhhgnecuvehluhhsthgvrhfuihiivgeptd X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200110_141939_478208_0E9A8292 X-CRM114-Status: GOOD ( 22.24 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [178.32.98.131 listed in list.dnswl.org] 0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [178.32.98.131 listed in wl.mailspike.net] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: hostap@lists.infradead.org, Alexander Wetzel Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many broken implementations and should be avoided when using or interacting with one of them. To allow affected users to mitigate the issues the new option "wpa_deny_ptk0_rekey" has been added to replace all PTK0 rekeys with fast reconnects. Signed-off-by: Alexander Wetzel --- src/eapol_supp/eapol_supp_sm.c | 15 +++++++++++++++ src/eapol_supp/eapol_supp_sm.h | 8 ++++++++ src/rsn_supp/wpa.c | 18 ++++++++++++++++++ src/rsn_supp/wpa.h | 3 +++ src/rsn_supp/wpa_i.h | 7 +++++++ wpa_supplicant/ap.c | 1 + wpa_supplicant/config.c | 2 ++ wpa_supplicant/config_file.c | 1 + wpa_supplicant/config_ssid.h | 12 ++++++++++++ wpa_supplicant/events.c | 16 ++++++++++------ wpa_supplicant/ibss_rsn.c | 9 ++++++++- wpa_supplicant/notify.c | 10 ++++++++++ wpa_supplicant/notify.h | 1 + wpa_supplicant/wpa_cli.c | 4 ++-- wpa_supplicant/wpa_supplicant.c | 28 +++++++++++++++++++++++++++- wpa_supplicant/wpa_supplicant.conf | 25 +++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant_i.h | 3 +++ wpa_supplicant/wpas_glue.c | 17 +++++++++++++++++ 18 files changed, 170 insertions(+), 10 deletions(-) diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index f1ca0a859..90a551200 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -200,6 +200,17 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx) } +static int eapol_sm_confirm_auth(struct eapol_sm *sm) +{ + if (!sm->ctx->confirm_auth_cb) + return 0; + + wpa_printf(MSG_DEBUG, + "EAPOL: Confirm planned PTK key install or trigger reconnect"); + return sm->ctx->confirm_auth_cb(sm->ctx->ctx); +} + + static void eapol_enable_timer_tick(struct eapol_sm *sm) { if (sm->timer_tick_enabled) @@ -316,6 +327,10 @@ SM_STATE(SUPP_PAE, AUTHENTICATED) SM_STATE(SUPP_PAE, RESTART) { + if (eapol_sm_confirm_auth(sm)) + /* Don't process restart, we are already reconnecting */ + return; + SM_ENTRY(SUPP_PAE, RESTART); sm->eapRestart = TRUE; if (sm->altAccept) { diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index c9d7522d5..0789118e3 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -298,6 +298,14 @@ struct eapol_ctx { * @len: Length of anonymous identity in octets */ void (*set_anon_id)(void *ctx, const u8 *id, size_t len); + + /** + * confirm_auth_cb - Callback confirming if we can install a new PTK + * Automatically triggers a reconnect when not. + * @ctx: Callback context (ctx) + * Returns: 0 when authentication can continue, -1 when reconnecting + */ + int (*confirm_auth_cb)(void *ctx); }; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 5f08d0e78..59b034d48 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -183,6 +183,14 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) int key_info, ver; u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic; + if (pairwise && sm->wpa_deny_ptk0_rekey && + wpa_sm_get_state(sm) == WPA_COMPLETED) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: PTK0 rekey not allowed, reconnecting"); + wpa_sm_reconnect(sm); + return; + } + if (wpa_use_akm_defined(sm->key_mgmt)) ver = WPA_KEY_INFO_TYPE_AKM_DEFINED; else if (wpa_key_mgmt_ft(sm->key_mgmt) || @@ -607,6 +615,13 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, "found (msg 1 of 4)"); return; } + if (sm->wpa_deny_ptk0_rekey && + wpa_sm_get_state(sm) == WPA_COMPLETED) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: PTK0 rekey not allowed, reconnecting"); + wpa_sm_reconnect(sm); + return; + } wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way " @@ -3043,6 +3058,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, case WPA_PARAM_PAIRWISE: sm->pairwise_cipher = value; break; + case WPA_PARAM_DENY_PTK0_REKEY: + sm->wpa_deny_ptk0_rekey = value; + break; case WPA_PARAM_GROUP: sm->group_cipher = value; break; diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 85fedeeae..c62428d4a 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -27,6 +27,7 @@ struct wpa_sm_ctx { void (*set_state)(void *ctx, enum wpa_states state); enum wpa_states (*get_state)(void *ctx); void (*deauthenticate)(void * ctx, u16 reason_code); + void (*reconnect)(void *ctx); int (*set_key)(void *ctx, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, @@ -100,6 +101,7 @@ enum wpa_sm_conf_params { WPA_PARAM_MFP, WPA_PARAM_OCV, WPA_PARAM_SAE_PWE, + WPA_PARAM_DENY_PTK0_REKEY, }; struct rsn_supp_config { @@ -111,6 +113,7 @@ struct rsn_supp_config { const u8 *ssid; size_t ssid_len; int wpa_ptk_rekey; + int wpa_deny_ptk0_rekey; int p2p; int wpa_rsc_relaxation; const u8 *fils_cache_id; diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 7d7c06ef2..dfd53d23a 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -61,6 +61,7 @@ struct wpa_sm { u8 ssid[32]; size_t ssid_len; int wpa_ptk_rekey; + int wpa_deny_ptk0_rekey:1; int p2p; int wpa_rsc_relaxation; @@ -206,6 +207,12 @@ static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg, seq, seq_len, key, key_len, key_flag); } +static inline void wpa_sm_reconnect(struct wpa_sm *sm) +{ + WPA_ASSERT(sm->ctx->reconnect); + sm->ctx->reconnect(sm->ctx->ctx); +} + static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm) { WPA_ASSERT(sm->ctx->get_network_ctx); diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index e552306d7..004d86bc3 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -349,6 +349,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, bss->isolate = !wpa_s->conf->p2p_intra_bss; bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk; + bss->wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey; if (ssid->p2p_group) { os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4); diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 3b37d152d..fbcdcf650 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2495,6 +2495,7 @@ static const struct parse_data ssid_fields[] = { { INT(dot11MeshHoldingTimeout) }, #endif /* CONFIG_MESH */ { INT(wpa_ptk_rekey) }, + { INT_RANGE(wpa_deny_ptk0_rekey, 0, 2) }, { INT(group_rekey) }, { STR(bgscan) }, { INT_RANGE(ignore_broadcast_ssid, 0, 2) }, @@ -3016,6 +3017,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) { ssid->proto = DEFAULT_PROTO; ssid->pairwise_cipher = DEFAULT_PAIRWISE; + ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS; ssid->group_cipher = DEFAULT_GROUP; ssid->key_mgmt = DEFAULT_KEY_MGMT; ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 2a0c7803e..16b5251d0 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -900,6 +900,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD); #endif /* CONFIG_MESH */ INT(wpa_ptk_rekey); + INT(wpa_deny_ptk0_rekey); INT(group_rekey); INT(ignore_broadcast_ssid); #ifdef CONFIG_DPP diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 98db1fe1a..8877ab5e1 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -553,6 +553,18 @@ struct wpa_ssid { */ int wpa_ptk_rekey; + /** wpa_deny_ptk0_rekey - Control PTK0 rekeying + * + * Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many + * broken implementations and should be avoided when using or + * interacting with one. + * + * 0 = always rekey when configured/instructed (default) + * 1 = only rekey when local driver is able to do it bug free + * 2 = never allow PTK0 rekeys + */ + int wpa_deny_ptk0_rekey; + /** * group_rekey - Group rekeying time in seconds * diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 90138c60d..28860bef0 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3246,8 +3246,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, if (wpa_s->wpa_state == WPA_COMPLETED && wpa_s->current_ssid && wpa_s->current_ssid->mode == WPAS_MODE_INFRA && - !locally_generated && - disconnect_reason_recoverable(reason_code)) { + (wpa_s->own_reconnect_req || + (!locally_generated && + disconnect_reason_recoverable(reason_code)))) { /* * It looks like the AP has dropped association with * us, but could allow us to get back in. Try to @@ -3256,11 +3257,12 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, */ fast_reconnect = wpa_s->current_bss; fast_reconnect_ssid = wpa_s->current_ssid; - } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) + } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) { wpa_supplicant_req_scan(wpa_s, 0, 100000); - else + } else { wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new " "immediate scan"); + } } else { wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not " "try to re-connect"); @@ -3302,15 +3304,16 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, fast_reconnect->ssid_len) && !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) && !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) { -#ifndef CONFIG_NO_SCAN_PROCESSING wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS"); if (wpa_supplicant_connect(wpa_s, fast_reconnect, fast_reconnect_ssid) < 0) { +#ifndef CONFIG_NO_SCAN_PROCESSING /* Recover through full scan */ wpa_supplicant_req_scan(wpa_s, 0, 100000); - } #endif /* CONFIG_NO_SCAN_PROCESSING */ + } } else if (fast_reconnect) { +#ifndef CONFIG_NO_SCAN_PROCESSING /* * Could not reconnect to the same BSS due to network being * disabled. Use a new scan to match the alternative behavior @@ -3318,6 +3321,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, * way that enforces disabled network rules. */ wpa_supplicant_req_scan(wpa_s, 0, 100000); +#endif /* CONFIG_NO_SCAN_PROCESSING */ } } diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 37368c4cb..ea909a91c 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -200,7 +200,13 @@ static void supp_cancel_auth_timeout(void *ctx) } -static void supp_deauthenticate(void * ctx, u16 reason_code) +static void supp_deauthenticate(void *ctx, u16 reason_code) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); +} + + +static void supp_reconnect(void *ctx) { wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); } @@ -225,6 +231,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, ctx->mlme_setprotection = supp_mlme_setprotection; ctx->cancel_auth_timeout = supp_cancel_auth_timeout; ctx->deauthenticate = supp_deauthenticate; + ctx->reconnect = supp_reconnect; peer->supp = wpa_sm_init(ctx); if (peer->supp == NULL) { wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 0ba1e144c..b2a6e458e 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -851,6 +851,16 @@ void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code) wpa_msg(wpa_s, MSG_ERROR, WPA_EVENT_EAP_ERROR_CODE "%d", error_code); } +int wpas_notify_eap_auth_start(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey) { + wpa_msg(wpa_s, MSG_INFO, + "WPA: PTK0 rekey not allowed, reconnecting"); + wpa_supplicant_reconnect(wpa_s); + return -1; + } + return 0; +} void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index e843aa124..bc9a022e5 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -140,6 +140,7 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s, void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code); +int wpas_notify_eap_auth_start(struct wpa_supplicant *wpa_s); void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 6d3f56a87..d3fa0349f 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1440,8 +1440,8 @@ static const char *network_fields[] = { "dot11MeshRetryTimeout", "dot11MeshConfirmTimeout", "dot11MeshHoldingTimeout", #endif /* CONFIG_MESH */ - "wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid", - "enable_edmg", "edmg_channel", + "wpa_ptk_rekey", "wpa_deny_ptk0_rekey", "bgscan", + "ignore_broadcast_ssid", "enable_edmg", "edmg_channel", #ifdef CONFIG_P2P "go_p2p_dev_addr", "p2p_client_list", "psk_list", #endif /* CONFIG_P2P */ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 9f3d6ef60..785daa749 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1275,6 +1275,24 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, int sel, proto; const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen; + if (ssid->mode == WPAS_MODE_IBSS) { + wpa_msg(wpa_s, MSG_INFO, + "PTK rekey not supported, ignoring PTK0 rekey setting"); + } else if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) && + (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER || + (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) { + wpa_msg(wpa_s, MSG_INFO, + "Disable PTK0 rekey support - replaced with reconnect"); + wpa_s->deny_ptk0_rekey = 1; + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1); + } else { + wpa_msg(wpa_s, MSG_WARNING, + "Support PTK0 rekey - may randomly break connections"); + wpa_s->deny_ptk0_rekey = 0; + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0); + } + if (bss) { bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); @@ -2048,6 +2066,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, int rand_style; wpa_s->own_disconnect_req = 0; + wpa_s->own_reconnect_req = 0; /* * If we are starting a new connection, any previously pending EAPOL @@ -3834,6 +3853,13 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, wpa_supplicant_clear_connection(wpa_s, addr); } +void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s) +{ + wpa_s->own_reconnect_req = 1; + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED); + +} + static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -7073,7 +7099,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) * There is no point in blacklisting the AP if this event is * generated based on local request to disconnect. */ - if (wpa_s->own_disconnect_req) { + if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) { wpa_s->own_disconnect_req = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure due to local request to disconnect"); diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 328f91a97..6b2d45145 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -1102,6 +1102,31 @@ fast_reauth=1 # wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies. # +# wpa_deny_ptk0_rekey: Control PTK0 rekeying. +# Rekeying the PTK without using "Extended Key ID for Individually Addressed +# Frames" can - depending on the used cards/drivers - impact the security and +# stability of connections. Both ends can accidentally trick one end to drop +# all packets send by it till the connection is torn down or rekeyed again. +# Additionally some drivers may skip/break the encryption for the time window +# the key is updated (normally a few ms). +# To avoid the issues wpa_supplicant can now replace all PTK rekeys using only +# keyid 0 (PTK0 rekeys) with fast reconnects. +# +# Eap reauthentication depends on replacing the PTK and is therefore just +# another way to rekey the PTK and affected by the setting, too. +# +# "Extended Key ID for Individually Addressed Frames" is avoiding the issues +# and the setting will be ignored when using it. +# +# If you your cards/drivers - either local or remote - need the workaround for +# PTK0 rekeys you must set "wpa_deny_ptk0_rekey = 0" or - if you want to allow +# it when the local system is known to be ok - "wpa_deny_ptk0_rekey = 1". +# +# Available options: +# 0 = always rekey when configured/instructed (default) +# 1 = only rekey when local driver is able to do it bug free +# 2 = never allow problematic PTK0 rekeys +# # group_rekey: Group rekeying time in seconds. This value, if non-zero, is used # as the dot11RSNAConfigGroupRekeyTime parameter when operating in # Authenticator role in IBSS, or in AP and mesh modes. diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 7ab6ca377..633ae163d 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -554,6 +554,7 @@ struct wpa_supplicant { /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ int pairwise_cipher; + int deny_ptk0_rekey; int group_cipher; int key_mgmt; int wpa_proto; @@ -1072,6 +1073,7 @@ struct wpa_supplicant { unsigned int wmm_ac_supported:1; unsigned int ext_work_in_progress:1; unsigned int own_disconnect_req:1; + unsigned int own_reconnect_req:1; unsigned int ignore_post_flush_scan_res:1; #define MAC_ADDR_RAND_SCAN BIT(0) @@ -1326,6 +1328,7 @@ const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s); void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s); void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason_code); +void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s); struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s); int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id); diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 9d5d35607..9c919fb00 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -486,6 +486,12 @@ static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code) } +static void _wpa_supplicant_reconnect(void *wpa_s) +{ + wpa_supplicant_reconnect(wpa_s); +} + + static void * wpa_supplicant_get_network_ctx(void *wpa_s) { return wpa_supplicant_get_ssid(wpa_s); @@ -1058,6 +1064,14 @@ static void wpa_supplicant_eap_error_cb(void *ctx, int error_code) } +static int wpa_supplicant_eap_auth_start_cb(void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + + return wpas_notify_eap_auth_start(wpa_s); +} + + static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len) { struct wpa_supplicant *wpa_s = ctx; @@ -1136,6 +1150,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) ctx->cert_in_cb = wpa_s->conf->cert_in_cb; ctx->status_cb = wpa_supplicant_status_cb; ctx->eap_error_cb = wpa_supplicant_eap_error_cb; + ctx->confirm_auth_cb = wpa_supplicant_eap_auth_start_cb; ctx->set_anon_id = wpa_supplicant_set_anon_id; ctx->cb_ctx = wpa_s; wpa_s->eapol = eapol_sm_init(ctx); @@ -1222,6 +1237,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) ctx->set_state = _wpa_supplicant_set_state; ctx->get_state = _wpa_supplicant_get_state; ctx->deauthenticate = _wpa_supplicant_deauthenticate; + ctx->reconnect = _wpa_supplicant_reconnect; ctx->set_key = wpa_supplicant_set_key; ctx->get_network_ctx = wpa_supplicant_get_network_ctx; ctx->get_bssid = wpa_supplicant_get_bssid; @@ -1286,6 +1302,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, conf.ssid = ssid->ssid; conf.ssid_len = ssid->ssid_len; conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey; + conf.wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey; #ifdef CONFIG_P2P if (ssid->p2p_group && wpa_s->current_bss && !wpa_s->p2p_disable_ip_addr_req) { From patchwork Fri Jan 10 22:19:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 1221455 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) 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=fail (p=quarantine dis=none) header.from=wetzel-home.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20170209 header.b=CqHyCgOe; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=wetzel-home.de header.i=@wetzel-home.de header.a=rsa-sha256 header.s=wetzel-home header.b=RcXrXw7O; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47vcqC281jz9sR8 for ; Sat, 11 Jan 2020 09:19:51 +1100 (AEDT) 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:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version: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=xgu+0J+1omFVWgm08m+A8jyb22o+yqvPTLEhAb3RQ/g=; b=CqHyCgOe3wq4MC X7S3V7kY9V9Q/Z+CrRB8cAIreiFSiDXdjrtp6E0hJz6LTFSvtxrfx9YvWp+riwEezFiLRkWPdUOze AMtdHym8i+LBuJD8QP38h66XMA0244hKBhmflRb14xB/nMB4326qQUHZ5qwOKLl3hePMyxU2SQmua +U/1Gr4TijX1i+NbZUHXmQAJ+RVCM8Fm21wuoluaSLoARt3We7Ga+bPYKBN8DJE8cxFHMXS3rThrB bZLfmDhKCzAYMYQKKWORchwPNCPOmeIL4PadpntKvor8jgWUDLzE4Kez1Mc773xlLVrUiIq2KzUez thoH9Txij2LVCrt827Lg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1iq2d8-0003Oe-CL; Fri, 10 Jan 2020 22:19:46 +0000 Received: from 4.mo173.mail-out.ovh.net ([46.105.34.219]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1iq2d1-0003IY-3p for hostap@lists.infradead.org; Fri, 10 Jan 2020 22:19:41 +0000 Received: from player771.ha.ovh.net (unknown [10.109.146.131]) by mo173.mail-out.ovh.net (Postfix) with ESMTP id 6586A12AB63 for ; Fri, 10 Jan 2020 23:19:27 +0100 (CET) Received: from awhome.eu (p4FF91EE6.dip0.t-ipconnect.de [79.249.30.230]) (Authenticated sender: postmaster@awhome.eu) by player771.ha.ovh.net (Postfix) with ESMTPSA id A4183E2CAE82; Fri, 10 Jan 2020 22:19:25 +0000 (UTC) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1578694703; bh=csvEPg7XY6+XNn4QF/3nLZX/G/+NouIPRan0L2KgS8c=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=RcXrXw7OuYCkoDUT9rlIwvRBfSgAmGrmSLrYcGoX5ZorDfAso0/R8wgGVt18IGm5d pljiSmtfZFl9kwU/FslI6DxQ7hhN58cskJzUbZdAXsbnOkjDj2oNDFZdc+Q4lW9YSW 3nQP4I16IqrooPqL1DE2V6kaUe2bg/go59M/urHQ= To: j@w1.fi Subject: [PATCH 3/3] tests: Allow PTK0 rekey for tests Date: Fri, 10 Jan 2020 23:19:10 +0100 Message-Id: <20200110221910.312529-4-alexander@wetzel-home.de> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200110221910.312529-1-alexander@wetzel-home.de> References: <20200110221910.312529-1-alexander@wetzel-home.de> MIME-Version: 1.0 X-Ovh-Tracer-Id: 17901527048025545920 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedufedrvdeifedgudehgecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecunecujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeetlhgvgigrnhguvghrucghvghtiigvlhcuoegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgeqnecukfhppedtrddtrddtrddtpdejledrvdegledrfedtrddvfedtnecurfgrrhgrmhepmhhouggvpehsmhhtphdqohhuthdphhgvlhhopehplhgrhigvrhejjedurdhhrgdrohhvhhdrnhgvthdpihhnvghtpedtrddtrddtrddtpdhmrghilhhfrhhomheprghlvgigrghnuggvrhesfigvthiivghlqdhhohhmvgdruggvpdhrtghpthhtohephhhoshhtrghpsehlihhsthhsrdhinhhfrhgruggvrggurdhorhhgnecuvehluhhsthgvrhfuihiivgeptd X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200110_141939_449078_5472160B X-CRM114-Status: GOOD ( 10.47 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [46.105.34.219 listed in list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: hostap@lists.infradead.org, Alexander Wetzel Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Verify PTK0 rekey blocking is working as intended. Signed-off-by: Alexander Wetzel --- tests/hwsim/hostapd.py | 2 +- tests/hwsim/test_ap_eap.py | 40 +++++++++++++++++++++++++++++++++++ tests/hwsim/test_ap_psk.py | 41 +++++++++++++++++++++++++++++++++++- tests/hwsim/wpasupplicant.py | 2 +- 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py index 67e8a7fb8..d97b5fab1 100644 --- a/tests/hwsim/hostapd.py +++ b/tests/hwsim/hostapd.py @@ -548,7 +548,7 @@ def add_ap(apdev, params, wait_enabled=True, no_enable=False, timeout=30, raise Exception("Could not ping hostapd") hapd.set_defaults() fields = ["ssid", "wpa_passphrase", "nas_identifier", "wpa_key_mgmt", - "wpa", + "wpa", "wpa_deny_ptk0_rekey", "wpa_pairwise", "rsn_pairwise", "auth_server_addr", "acct_server_addr", "osu_server_uri"] for field in fields: diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py index f502bf7a7..85bcef80a 100644 --- a/tests/hwsim/test_ap_eap.py +++ b/tests/hwsim/test_ap_eap.py @@ -5126,6 +5126,46 @@ def test_ap_wpa2_eap_reauth(dev, apdev): if state != "COMPLETED": raise Exception("Reauthentication did not complete") +def test_ap_wpa2_eap_reauth_ptk_rekey_blocked_ap(dev, apdev): + """WPA2-Enterprise and Authenticator forcing reauthentication with PTK rekey blocked on AP""" + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + params['eap_reauth_period'] = '2' + params['wpa_deny_ptk0_rekey'] = '2' + hapd = hostapd.add_ap(apdev[0], params) + eap_connect(dev[0], hapd, "PAX", "pax.user@example.com", + password_hex="0123456789abcdef0123456789abcdef") + logger.info("Wait for disconnect due to reauth") + ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED", + "CTRL-EVENT-DISCONNECTED"], timeout=10) + if ev is None: + raise Exception("Timeout on reauthentication") + elif "CTRL-EVENT-EAP-STARTED" in ev: + raise Exception("Reauthentication without disconnect") + + ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=1) + if ev is None: + raise Exception("Timeout on reconnect") + +def test_ap_wpa2_eap_reauth_ptk_rekey_blocked_sta(dev, apdev): + """WPA2-Enterprise and Authenticator forcing reauthentication with PTK rekey blocked on station""" + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + params['eap_reauth_period'] = '2' + hapd = hostapd.add_ap(apdev[0], params) + eap_connect(dev[0], hapd, "PAX", "pax.user@example.com", + password_hex="0123456789abcdef0123456789abcdef", + wpa_deny_ptk0_rekey="2") + logger.info("Wait for disconnect due to reauth") + ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED", + "CTRL-EVENT-DISCONNECTED"], timeout=10) + if ev is None: + raise Exception("Timeout on reauthentication") + elif "CTRL-EVENT-EAP-STARTED" in ev: + raise Exception("Reauthentication without disconnect") + + ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=1) + if ev is None: + raise Exception("Timeout on reconnect") + def test_ap_wpa2_eap_request_identity_message(dev, apdev): """Optional displayable message in EAP Request-Identity""" params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") diff --git a/tests/hwsim/test_ap_psk.py b/tests/hwsim/test_ap_psk.py index ac0fabc5d..2042cab59 100644 --- a/tests/hwsim/test_ap_psk.py +++ b/tests/hwsim/test_ap_psk.py @@ -211,11 +211,50 @@ def test_ap_wpa2_ptk_rekey(dev, apdev): params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) hapd = hostapd.add_ap(apdev[0], params) dev[0].connect(ssid, psk=passphrase, wpa_ptk_rekey="1", scan_freq="2412") - ev = dev[0].wait_event(["WPA: Key negotiation completed"]) + ev = dev[0].wait_event(["WPA: Key negotiation completed", + "CTRL-EVENT-DISCONNECTED"]) if ev is None: raise Exception("PTK rekey timed out") + elif "CTRL-EVENT-DISCONNECTED" in ev: + raise Exception("Disconnect instead of rekey") hwsim_utils.test_connectivity(dev[0], hapd) +def test_ap_wpa2_ptk_rekey_blocked_ap(dev, apdev): + """WPA2-PSK AP and PTK rekey enforced by station and AP blocking it""" + ssid = "test-wpa2-psk" + passphrase = 'qwertyuiop' + params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) + params['wpa_deny_ptk0_rekey'] = "2" + hapd = hostapd.add_ap(apdev[0], params) + dev[0].connect(ssid, psk=passphrase, wpa_ptk_rekey="1", scan_freq="2412") + ev = dev[0].wait_event(["WPA: Key negotiation completed", + "CTRL-EVENT-DISCONNECTED"]) + if ev is None: + raise Exception("PTK rekey timed out") + elif "WPA: Key negotiation completed" in ev: + raise Exception("No disconnect, PTK rekey succeeded") + ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=1) + if ev is None: + raise Exception("Reconnect too slow") + +def test_ap_wpa2_ptk_rekey_blocked_sta(dev, apdev): + """WPA2-PSK AP and PTK rekey enforced by station while also blocking it""" + ssid = "test-wpa2-psk" + passphrase = 'qwertyuiop' + params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) + hapd = hostapd.add_ap(apdev[0], params) + dev[0].connect(ssid, psk=passphrase, wpa_ptk_rekey="1", scan_freq="2412", + wpa_deny_ptk0_rekey="2") + ev = dev[0].wait_event(["WPA: Key negotiation completed", + "CTRL-EVENT-DISCONNECTED"]) + if ev is None: + raise Exception("PTK rekey timed out") + elif "WPA: Key negotiation completed" in ev: + raise Exception("No disconnect, PTK rekey succeeded") + ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=1) + if ev is None: + raise Exception("Reconnect too slow") + def test_ap_wpa2_ptk_rekey_anonce(dev, apdev): """WPA2-PSK AP and PTK rekey enforced by station and ANonce change""" ssid = "test-wpa2-psk" diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py index c9ebb250d..fe6cccacf 100644 --- a/tests/hwsim/wpasupplicant.py +++ b/tests/hwsim/wpasupplicant.py @@ -1092,7 +1092,7 @@ class WpaSupplicant: "group_mgmt", "owe_group", "roaming_consortium_selection", "ocv", "multi_ap_backhaul_sta", "rx_stbc", "tx_stbc", - "ft_eap_pmksa_caching"] + "ft_eap_pmksa_caching", "wpa_deny_ptk0_rekey"] for field in not_quoted: if field in kwargs and kwargs[field]: self.set_network(id, field, kwargs[field])