From patchwork Fri Mar 20 19:04:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 1259196 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=Np8VFiJe; 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=rECP+GnA; 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 48kYDN2wSXz9sPF for ; Sat, 21 Mar 2020 06:07:00 +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: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:In-Reply-To:References: List-Owner; bh=ZQxDCjbQjXCvCNHk1u0FE/xzC0dmyAJTkMbvu5eTQS8=; b=Np8VFiJeHYvJey JZYGonE6C6ydDkYHTndacnXY6+2yQqrzHrTryg2wGfKKOFV9gX+JZXl0z5b4SqmQ/TTK1O9VsY1HK 47ZMdDMUhTEWibgHC6AGHDaidCz4BgkAOhKxRU51fo1i8eiFJ6gFOoixPFtd3CYYpkJHInuZcrjsr Ln1AJXaqhy+qRJnvctNxhgdT9Nfdgx6vP2g6GfflI1L+Nr65UeAUB/Y8r4FB1gXMgRfsOoPP0BWsU ZT28f55n4GoiUK/yavVHpXzpDeTfewcD/pafuL4x4CCRwE/cY/DaS5r+DqboeWFtJyCZVIUzORQIw OZWFm1FopKaI/SyzYa/g==; 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 1jFMyj-0006wd-Ay; Fri, 20 Mar 2020 19:06:45 +0000 Received: from 5.mo69.mail-out.ovh.net ([46.105.43.105]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jFMyN-0006XC-L3 for hostap@lists.infradead.org; Fri, 20 Mar 2020 19:06:29 +0000 Received: from player687.ha.ovh.net (unknown [10.108.42.184]) by mo69.mail-out.ovh.net (Postfix) with ESMTP id 39B27896D2 for ; Fri, 20 Mar 2020 20:06:13 +0100 (CET) Received: from awhome.eu (p4FF9153C.dip0.t-ipconnect.de [79.249.21.60]) (Authenticated sender: postmaster@awhome.eu) by player687.ha.ovh.net (Postfix) with ESMTPSA id 98F561099FC83; Fri, 20 Mar 2020 19:06:03 +0000 (UTC) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1584731162; bh=wBPR609lENsGpFJh7mLF0RA0wBaMm+yLEdCJldyPKdg=; h=From:To:Cc:Subject:Date; b=rECP+GnALkS0bcMDAcx4EZd0ejuFotJnPOswnm1vtbLqCQB5bb0hLMlcav9fVo9R1 njtZ0rZ/oVhCw/TLKNMbEsL7pvuSbRL/fW4Y48DIuZhVvli4TBvqft+yTx+KNPl0ch iaWC3WJI77hwQD+xLvm9t+WRotpsJBUbjOT7fcw4= To: j@w1.fi Subject: [PATCH v2 1/3] AP: Support Extended Key ID Date: Fri, 20 Mar 2020 20:04:31 +0100 Message-Id: <20200320190433.142039-1-alexander@wetzel-home.de> X-Mailer: git-send-email 2.25.2 MIME-Version: 1.0 X-Ovh-Tracer-Id: 1451003507909336256 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedugedrudeguddguddukecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecunecujfgurhephffvufffkffoggfgsedtkeertdertddtnecuhfhrohhmpeetlhgvgigrnhguvghrucghvghtiigvlhcuoegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgeqnecuffhomhgrihhnpehpthhkrdhtkhenucfkpheptddrtddrtddrtddpjeelrddvgeelrddvuddriedtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmohguvgepshhmthhpqdhouhhtpdhhvghlohepphhlrgihvghrieekjedrhhgrrdhovhhhrdhnvghtpdhinhgvtheptddrtddrtddrtddpmhgrihhlfhhrohhmpegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgdprhgtphhtthhopehhohhsthgrpheslhhishhtshdrihhnfhhrrgguvggrugdrohhrgh X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200320_120624_154818_8A9C0104 X-CRM114-Status: GOOD ( 28.43 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.3 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.43.105 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's 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_EF Message has a valid DKIM or DK signature from envelope-from 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 Support Extended Key ID in hostapd according to IEEE 802.11-2016. Extended Key ID allows to rekey pairwise keys without the otherwise unavoidable MPDU losses on a busy link. The standard is fully backward compatible, allowing an AP to serve STAs with and without Extended Key ID support in the same BSS. Signed-off-by: Alexander Wetzel Signed-off-by: Alexander Wetzel --- This should have all the changes you requested. We still verify that the Extended Key ID bit is used consequently and disconnect anyone who violates the rule. (I figure it makes no sense to add workarounds when there are no known broken implementations, yet.) The biggest challenge was getting all tests using Extended Key ID while having it off by default. The tests are updated assuming it's off but after tripping over sigma.dut I gave up and changed the default for test builds back to on. When you don't like that you can simply use the "production" defaults and some tests will start using PTK0 again. (Or you may know a better way to handle it...) The decision to use a global config variable in wpa_supplicant is also making deterministic tests a bit harder: I tried to make sure the test revert to the default setting but I know I failed for many tests. Especially when a test is executed with Extended Key ID disabled and triggers an Exception the next test can be run without Extended Key ID when it's not resetting the interface itself... That said tests are looking great for me now. We are using Extended Key ID now everywhere where I expect it. (Ignoring WEP we can't use it for TKIP, WPA1, OWE, IBSS or when not using nl80211.) I also should point out that merging the patches will break bissecting when you use tests. With nl80211 already supporting Extended Key ID the only "safe" merges would be all three patches as one or add two patches sabotaging/fixing nl80211 Extended key ID at the beginning/end. I also made some other improvements: - Don't disable Extended key ID when loading the config. - I reworked the code handling IE/RSN overloading. The code is now checking (hopefully all) overload strings if they allows Extended Key ID or not and force enable/disable it accordingly. And the handling has been moved to the config parse sections. - Some cosmetic fixes (But I'm sure there are I still got quite some wrong...) hostapd/config_file.c | 51 ++++++++++++++++++++++++++ hostapd/ctrl_iface.c | 8 +++++ hostapd/hostapd.conf | 12 +++++++ src/ap/ap_config.c | 6 ++++ src/ap/ap_config.h | 1 + src/ap/ieee802_11.c | 7 ++++ src/ap/wpa_auth.c | 81 ++++++++++++++++++++++++++++++++++-------- src/ap/wpa_auth.h | 3 ++ src/ap/wpa_auth_ft.c | 25 ++++++++++++- src/ap/wpa_auth_glue.c | 14 +++++++- src/ap/wpa_auth_i.h | 4 +++ src/ap/wpa_auth_ie.c | 59 ++++++++++++++++++++++++++++++ 12 files changed, 255 insertions(+), 16 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 1a5b742b2..63ca2cb9d 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2869,6 +2869,14 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "wpa") == 0) { bss->wpa = atoi(pos); + } else if (os_strcmp(buf, "extended_key_id") == 0) { + bss->extended_key_id = atoi(pos); + if (bss->extended_key_id < 0 || bss->extended_key_id > 2) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid wpa_extended_key_id=%d; allowed range 0..2", + line, bss->extended_key_id); + return 1; + } } else if (os_strcmp(buf, "wpa_group_rekey") == 0) { bss->wpa_group_rekey = atoi(pos); bss->wpa_group_rekey_set = 1; @@ -4154,6 +4162,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->radio_measurements[0] |= WLAN_RRM_CAPS_NEIGHBOR_REPORT; } else if (os_strcmp(buf, "own_ie_override") == 0) { + struct wpa_ie_data data; struct wpabuf *tmp; size_t len = os_strlen(pos) / 2; @@ -4171,20 +4180,62 @@ static int hostapd_config_fill(struct hostapd_config *conf, wpabuf_free(bss->own_ie_override); bss->own_ie_override = tmp; + if (!wpa_parse_wpa_ie_rsn(wpabuf_head(tmp), wpabuf_len(tmp), + &data) && + (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) + bss->extended_key_id = 1; + else + bss->extended_key_id = 0; + wpa_printf(MSG_DEBUG, + "WPA: Forced own IE %sables Extended Key ID", + bss->extended_key_id ? "en" : "dis"); } else if (os_strcmp(buf, "sae_reflection_attack") == 0) { bss->sae_reflection_attack = atoi(pos); } else if (os_strcmp(buf, "sae_commit_override") == 0) { wpabuf_free(bss->sae_commit_override); bss->sae_commit_override = wpabuf_parse_bin(pos); } else if (os_strcmp(buf, "rsne_override_eapol") == 0) { + struct wpa_ie_data data; + wpabuf_free(bss->rsne_override_eapol); bss->rsne_override_eapol = wpabuf_parse_bin(pos); + + if (!wpa_parse_wpa_ie_rsn(wpabuf_head( + bss->rsne_override_eapol), + wpabuf_len(bss->rsne_override_eapol), + &data) && + (data.capabilities & + WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) { + bss->extended_key_id = 1; + wpa_printf(MSG_DEBUG, + "WPA: rsne_override_eapol enables Extended Key ID"); + } else { + bss->extended_key_id = 0; + wpa_printf(MSG_DEBUG, + "WPA: rsne_override_eapol disables Extended Key ID"); + } } else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) { wpabuf_free(bss->rsnxe_override_eapol); bss->rsnxe_override_eapol = wpabuf_parse_bin(pos); } else if (os_strcmp(buf, "rsne_override_ft") == 0) { + struct wpa_ie_data data; + wpabuf_free(bss->rsne_override_ft); bss->rsne_override_ft = wpabuf_parse_bin(pos); + + if (!wpa_parse_wpa_ie_rsn(wpabuf_head(bss->rsne_override_ft), + wpabuf_len(bss->rsne_override_ft), + &data) && + (data.capabilities & + WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) { + bss->extended_key_id = 1; + wpa_printf(MSG_DEBUG, + "WPA: rsne_override_ft enables Extended Key ID"); + } else { + bss->extended_key_id = 0; + wpa_printf(MSG_DEBUG, + "WPA: rsne_override_ft disables Extended Key ID"); + } } else if (os_strcmp(buf, "rsnxe_override_ft") == 0) { wpabuf_free(bss->rsnxe_override_ft); bss->rsnxe_override_ft = wpabuf_parse_bin(pos); diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 6d2ecbc9c..1a369ed2a 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1295,6 +1295,14 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, pos += ret; } + if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) { + ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n", + hapd->conf->extended_key_id); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + return pos - buf; } diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index bc5d1a7f6..98e3cb510 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1510,6 +1510,18 @@ own_ip_addr=127.0.0.1 # wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK). #wpa=2 +# "Extended Key ID support for Individually Addressed Frames" according to +# IEEE 802.11-2016. +# +# Extended Key ID allows to rekey PTK keys without the impacts the "normal" +# PTK0 rekeying has. It can only be used when the driver supports it and +# requires wpa=2 with a CCMP/GCMP cipher. +# +# 0 = force off (default) +# 1 = enable and use Extended Key ID support when possible +# 2 = identical to 1 but start with Key ID 1 when possible +#wpa_extended_key_id=0 + # WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit # secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase # (8..63 characters) that will be converted to PSK. This conversion uses SSID diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 5bf4502b0..07ea4858b 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -68,6 +68,12 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->wpa_group_rekey = 600; bss->wpa_gmk_rekey = 86400; +#ifdef CONFIG_TESTING_OPTIONS + /* For now only testing is using Extended Key ID by default */ + bss->extended_key_id = 2; +#else /* CONFIG_TESTING_OPTIONS */ + bss->extended_key_id = 0; +#endif /* CONFIG_TESTING_OPTIONS */ bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS; bss->wpa_group_update_count = 4; bss->wpa_pairwise_update_count = 4; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 0cb10c118..4d14e15d3 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -354,6 +354,7 @@ struct hostapd_bss_config { * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ + int extended_key_id; int wpa_key_mgmt; enum mfp_options ieee80211w; int group_mgmt_cipher; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 46cc7fae7..78c5bfc2a 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -3490,6 +3490,13 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_MBO */ +#if defined(CONFIG_FILS) + if (sta->auth_alg == WLAN_AUTH_FILS_SK || + sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || + sta->auth_alg == WLAN_AUTH_FILS_PK) + fils_handle_extended_key_id(sta->wpa_sm, wpa_ie, wpa_ie_len); +#endif /* CONFIG_FILS */ + #if defined(CONFIG_FILS) && defined(CONFIG_OCV) if (wpa_auth_uses_ocv(sta->wpa_sm) && (sta->auth_alg == WLAN_AUTH_FILS_SK || diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index ab20705f0..0954018cf 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -781,7 +781,8 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm) if (sm == NULL) return; - if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { + if (!sm->use_extended_key_id && + sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { wpa_printf(MSG_INFO, "WPA: PTK0 rekey not allowed, disconnect " MACSTR, MAC2STR(sm->addr)); @@ -790,6 +791,8 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm) sm->disconnect_reason = WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; } else { + if (sm->use_extended_key_id) + sm->keyidx_active ^= 1; /* flip keyID */ sm->PTKRequest = TRUE; sm->PTK_valid = 0; } @@ -1754,6 +1757,11 @@ void wpa_remove_ptk(struct wpa_state_machine *sm) 0, KEY_FLAG_PAIRWISE)) wpa_printf(MSG_DEBUG, "RSN: PTK removal from the driver failed"); + if (sm->wpa_auth->conf.extended_key_id && + wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL, + 0, KEY_FLAG_PAIRWISE)) + wpa_printf(MSG_DEBUG, + "RSN: PTK ID1 removal from the driver failed"); sm->pairwise_set = FALSE; eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); } @@ -1812,16 +1820,20 @@ 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) { + } else if (!sm->use_extended_key_id && + sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { wpa_printf(MSG_INFO, "WPA: PTK0 rekey not allowed, disconnect " MACSTR, MAC2STR(sm->addr)); sm->Disconnect = TRUE; - /* Try to encourage the STA reconnect */ + /* Try to encourage the STA to reconnect */ sm->disconnect_reason = WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; break; + } else if (sm->use_extended_key_id) { + sm->keyidx_active ^= 1; /* flip keyID */ } + if (sm->GUpdateStationKeys) { /* * Reauthentication cancels the pending group key @@ -2796,7 +2808,7 @@ int fils_set_tk(struct wpa_state_machine *sm) klen = wpa_cipher_key_len(sm->pairwise); wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver"); - if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, + if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active, sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) { wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver"); return -1; @@ -3097,6 +3109,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) return; } + if (handle_extended_key_id(sm, &kde)) + return; + sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); @@ -3255,12 +3270,12 @@ static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid, SM_STATE(WPA_PTK, PTKINITNEGOTIATING) { - u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32]; + u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *pos, dummy_gtk[32], hdr[2]; size_t gtk_len, kde_len, wpa_ie_len; struct wpa_group *gsm = sm->group; u8 *wpa_ie; int secure, gtkidx, encr = 0; - u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL; + u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL, *kde = NULL; SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = FALSE; @@ -3317,6 +3332,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "sending 3/4 msg of 4-Way Handshake"); if (sm->wpa == WPA_VERSION_WPA2) { + if (sm->use_extended_key_id && sm->TimeoutCtr == 1 && + wpa_auth_set_key(sm->wpa_auth, 0, + wpa_cipher_to_alg(sm->pairwise), + sm->addr, + sm->keyidx_active, sm->PTK.tk, + wpa_cipher_key_len(sm->pairwise), + KEY_FLAG_PAIRWISE_RX)) { + wpa_sta_disconnect(sm->wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } + /* WPA2 send GTK in the 4-way handshake */ secure = 1; gtk = gsm->GTK[gsm->GN - 1]; @@ -3357,6 +3384,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); + + if (sm->use_extended_key_id) + kde_len += 2 + RSN_SELECTOR_LEN + 2; + if (gtk) kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; #ifdef CONFIG_IEEE80211R_AP @@ -3392,10 +3423,15 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) pos += elen; } #endif /* CONFIG_IEEE80211R_AP */ + hdr[1] = 0; + + if (sm->use_extended_key_id) { + hdr[0] = sm->keyidx_active & 0x01; + pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0); + } + if (gtk) { - u8 hdr[2]; hdr[0] = gtkidx & 0x03; - hdr[1] = 0; pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gtk_len); } @@ -3478,9 +3514,17 @@ SM_STATE(WPA_PTK, PTKINITDONE) if (sm->Pair) { enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise); int klen = wpa_cipher_key_len(sm->pairwise); - if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, - sm->PTK.tk, klen, - KEY_FLAG_PAIRWISE_RX_TX)) { + if (sm->use_extended_key_id) { + if (wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr, + sm->keyidx_active, NULL, 0, + KEY_FLAG_PAIRWISE_RX_TX_MODIFY)) { + wpa_sta_disconnect(sm->wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } + } else if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, + sm->PTK.tk, klen, + KEY_FLAG_PAIRWISE_RX_TX)) { wpa_sta_disconnect(sm->wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); return; @@ -5161,7 +5205,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, void (*cb)(void *ctx1, void *ctx2), void *ctx1, void *ctx2) { - u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos; + u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, hdr[2]; u8 *opos; size_t gtk_len, kde_len; struct wpa_group *gsm = sm->group; @@ -5219,6 +5263,10 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, } kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); + + if (sm->use_extended_key_id) + kde_len += 2 + RSN_SELECTOR_LEN + 2; + if (gtk) kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; #ifdef CONFIG_IEEE80211R_AP @@ -5251,10 +5299,15 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, pos += elen; } #endif /* CONFIG_IEEE80211R_AP */ + hdr[1] = 0; + + if (sm->use_extended_key_id) { + hdr[0] = sm->keyidx_active & 0x01; + pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0); + } + if (gtk) { - u8 hdr[2]; hdr[0] = gtkidx & 0x03; - hdr[1] = 0; pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gtk_len); } diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 4edeea151..107389f7b 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -169,6 +169,7 @@ struct ft_remote_r1kh { struct wpa_auth_config { int wpa; + int extended_key_id; int wpa_key_mgmt; int wpa_pairwise; int wpa_group; @@ -474,6 +475,8 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf, size_t current_len, size_t max_len, const struct wpabuf *hlp); int fils_set_tk(struct wpa_state_machine *sm); +void fils_handle_extended_key_id(struct wpa_state_machine *sm, + const u8 *rsn_ie, size_t rsn_ie_len); u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *eid, const u8 *fils_session, struct wpabuf *fils_hlp_resp); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 1795848e1..293275056 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -2738,6 +2738,28 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, } +static void ft_handle_extended_key_id(struct wpa_state_machine *sm, + struct wpa_ft_ies *parse) +{ + struct wpa_auth_config *conf = &sm->wpa_auth->conf; + + if (conf->extended_key_id && sm->pairwise != WPA_CIPHER_TKIP && + parse->rsn_capab & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) + sm->use_extended_key_id = 1; + else + sm->use_extended_key_id = 0; + + /* There is no standardized way to hand over the KeyID in FT. + * Since FT can only be used for the initial connect we can simply + * agree to always use 0. + */ + sm->keyidx_active = 0; + + wpa_printf(MSG_DEBUG, + "FT: STA " MACSTR " is %susing Extended Key ID", + MAC2STR(sm->addr), sm->use_extended_key_id ? "" : "not "); +} + void wpa_ft_install_ptk(struct wpa_state_machine *sm) { enum wpa_alg alg; @@ -2766,7 +2788,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) * again after association to get the PTK configured, but that could be * optimized by adding the STA entry earlier. */ - if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, + if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active, sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) return; @@ -3128,6 +3150,7 @@ pmk_r1_derived: pairwise) < 0) return WLAN_STATUS_UNSPECIFIED_FAILURE; + ft_handle_extended_key_id(sm, &parse); sm->pairwise = pairwise; sm->PTK_valid = TRUE; sm->tk_already_set = FALSE; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 926ff455f..01b3f494e 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -41,6 +41,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, os_memset(wconf, 0, sizeof(*wconf)); wconf->wpa = conf->wpa; + wconf->extended_key_id = conf->extended_key_id; wconf->wpa_key_mgmt = conf->wpa_key_mgmt; wconf->wpa_pairwise = conf->wpa_pairwise; wconf->wpa_group = conf->wpa_group; @@ -433,7 +434,12 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, } #ifdef CONFIG_TESTING_OPTIONS - if (addr && !is_broadcast_ether_addr(addr)) { + if (key_flag & KEY_FLAG_MODIFY) { + /* We are updating an already installed key. + * Don't overwrite the already stored key + * information with zeros. + */ + } else if (addr && !is_broadcast_ether_addr(addr)) { struct sta_info *sta; sta = ap_get_sta(hapd, addr); @@ -1419,6 +1425,12 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) _conf.wpa_deny_ptk0_rekey = 1; } + if (_conf.extended_key_id && + hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) + wpa_msg(hapd->msg_ctx, MSG_INFO, "Extended Key ID supported"); + else + _conf.extended_key_id = 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/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index c2b22eba1..be9cd70bb 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -61,6 +61,8 @@ struct wpa_state_machine { unsigned int pmk_len; u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */ struct wpa_ptk PTK; + u8 keyidx_active; + Boolean use_extended_key_id; Boolean PTK_valid; Boolean pairwise_set; Boolean tk_already_set; @@ -287,6 +289,8 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, int (*cb)(struct wpa_authenticator *a, void *ctx), void *cb_ctx); +int handle_extended_key_id(struct wpa_state_machine *sm, + struct wpa_eapol_ie_parse *kde); #ifdef CONFIG_IEEE80211R_AP int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 2e6d05910..d9fa88d37 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -297,6 +297,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, if (rsn_testing) capab |= BIT(8) | BIT(15); #endif /* CONFIG_RSN_TESTING */ + if (conf->extended_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; WPA_PUT_LE16(pos, capab); pos += 2; @@ -546,6 +548,63 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) } +int handle_extended_key_id(struct wpa_state_machine *sm, + struct wpa_eapol_ie_parse *kde) +{ + struct wpa_auth_config *conf = &sm->wpa_auth->conf; + struct wpa_ie_data rsn; + + if (conf->extended_key_id && sm->pairwise != WPA_CIPHER_TKIP && + !wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &rsn) && + rsn.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) { + if (!sm->use_extended_key_id && sm->pairwise_set) { + wpa_printf(MSG_ERROR, "STA " MACSTR + " tries to start using Extended Key ID on rekey", + MAC2STR(sm->addr)); + return -1; + } else if (!sm->use_extended_key_id) { + sm->use_extended_key_id = TRUE; + if (conf->extended_key_id == 2) + sm->keyidx_active = 1; + else + sm->keyidx_active = 0; + } + } else { + if (sm->use_extended_key_id && sm->pairwise_set) { + wpa_printf(MSG_ERROR, "STA " MACSTR + " is using Extended Key ID but tries to rekey without it", + MAC2STR(sm->addr)); + return -1; + } else if (!sm->pairwise_set) { + sm->use_extended_key_id = FALSE; + sm->keyidx_active = 0; + } + } + wpa_printf(MSG_DEBUG, "STA " MACSTR " is %susing Extended Key ID", + MAC2STR(sm->addr), sm->use_extended_key_id ? "" : "not "); + return 0; +} + + +void fils_handle_extended_key_id(struct wpa_state_machine *sm, + const u8 *rsn_ie, size_t rsn_ie_len) +{ + struct wpa_auth_config *conf = &sm->wpa_auth->conf; + struct wpa_ie_data rsn; + + sm->keyidx_active = 0; + if (conf->extended_key_id && sm->pairwise != WPA_CIPHER_TKIP && + !wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &rsn) && + rsn.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) + sm->use_extended_key_id = 1; + else + sm->use_extended_key_id = 0; + wpa_printf(MSG_DEBUG, + "FILS: STA " MACSTR " is %susing Extended Key ID", + MAC2STR(sm->addr), sm->use_extended_key_id ? "":"not "); +} + + int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int freq, const u8 *wpa_ie, size_t wpa_ie_len, From patchwork Fri Mar 20 19:04:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 1259194 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=OlV8Ofv0; 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=kXDStZLP; 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 48kYD80w4Cz9sR4 for ; Sat, 21 Mar 2020 06:06:48 +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=GQYUT4MqYOQ8Rq9KHk5GIowo95smq/NRKhjbnB5g02Q=; b=OlV8Ofv0o/MEZr cwuOK6tl0OSmV4P/x7PvHcRjVmkxFyruHbEjpw/EM8YGcT1C2OYcs6e5Gx2PlOH2/S4vJO1hm5SBk SqEaUnbaJZpRYmvS4PceBQoizN+9zHj+g+X6ZvsgdqoslYsOwOEaZQq7hh26ASJWguljOna0x5M7g P3OPmf8dQoCjdniG6waEYIVcI3S6wMLhtcsRj4hE8nOE4XZeR7IDdeUvzc3nMivZgdH8shlN2BIUA V0SPPWS22YKzWqWCm5aucdUyRzLBWLfXjYg7XD71qawiDo5NT85rco6PcTyxcYLDFAgDRXFQ6nj8v AQQzKkS6F7UZl7TS5ouw==; 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 1jFMyT-0006Yd-Mi; Fri, 20 Mar 2020 19:06:29 +0000 Received: from 10.mo173.mail-out.ovh.net ([46.105.74.148]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jFMyN-0006XG-LI for hostap@lists.infradead.org; Fri, 20 Mar 2020 19:06:27 +0000 Received: from player735.ha.ovh.net (unknown [10.110.208.245]) by mo173.mail-out.ovh.net (Postfix) with ESMTP id 617DA12C2A9 for ; Fri, 20 Mar 2020 20:06:14 +0100 (CET) Received: from awhome.eu (p4FF9153C.dip0.t-ipconnect.de [79.249.21.60]) (Authenticated sender: postmaster@awhome.eu) by player735.ha.ovh.net (Postfix) with ESMTPSA id 9EA0D106E9B48; Fri, 20 Mar 2020 19:06:11 +0000 (UTC) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1584731162; bh=ksAInI8290GD6cTtSpsaLtm4v8Wte2MRDQBpTRSHhYg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=kXDStZLPwLvp5tl50VRrfPobI5Q+jMxc8DfLTWKWMUk0GeZvM3nG1WO+Eeo9IOwcc kUnyL9C3o8Bram9oTqt50pc/6XoyV8m+7hdcc+exXo9AuDJrnWCTCenjNMUhx2nTQX fvnQidJdgQehcfUywTeVChGKIcmtkYxmG8SPSR0g= To: j@w1.fi Subject: [PATCH v2 2/3] STA: Support Extended Key ID Date: Fri, 20 Mar 2020 20:04:32 +0100 Message-Id: <20200320190433.142039-2-alexander@wetzel-home.de> X-Mailer: git-send-email 2.25.2 In-Reply-To: <20200320190433.142039-1-alexander@wetzel-home.de> References: <20200320190433.142039-1-alexander@wetzel-home.de> MIME-Version: 1.0 X-Ovh-Tracer-Id: 1451847933698383040 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedugedrudeguddguddukecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecunecujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeetlhgvgigrnhguvghrucghvghtiigvlhcuoegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgeqnecuffhomhgrihhnpehpthhkrdhtkhenucfkpheptddrtddrtddrtddpjeelrddvgeelrddvuddriedtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmohguvgepshhmthhpqdhouhhtpdhhvghlohepphhlrgihvghrjeefhedrhhgrrdhovhhhrdhnvghtpdhinhgvtheptddrtddrtddrtddpmhgrihhlfhhrohhmpegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgdprhgtphhtthhopehhohhsthgrpheslhhishhtshdrihhnfhhrrgguvggrugdrohhrgh X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200320_120624_137515_9A2F517E X-CRM114-Status: GOOD ( 20.32 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.3 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.74.148 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's 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_EF Message has a valid DKIM or DK signature from envelope-from 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 Support Extended Key ID in wpa_supplicant according to IEEE 802.11-2016 for infrastructure (AP) associations. Extended Key ID allows to rekey pairwise keys without the otherwise unavoidable MPDU losses on a busy link. The standard is fully backward compatible, allowing STAs to also connect to APs not supporting it. Signed-off-by: Alexander Wetzel Signed-off-by: Alexander Wetzel --- src/rsn_supp/wpa.c | 135 ++++++++++++++++++++++-- src/rsn_supp/wpa.h | 13 +++ src/rsn_supp/wpa_ft.c | 27 ++++- src/rsn_supp/wpa_i.h | 3 + src/rsn_supp/wpa_ie.c | 2 + wpa_supplicant/ap.c | 1 + wpa_supplicant/config.c | 2 + wpa_supplicant/config.h | 18 ++++ wpa_supplicant/config_file.c | 3 + wpa_supplicant/config_winreg.c | 10 ++ wpa_supplicant/ctrl_iface.c | 35 +++++- wpa_supplicant/dbus/dbus_new_handlers.c | 3 +- wpa_supplicant/driver_i.h | 9 +- wpa_supplicant/wpa_cli.c | 3 +- wpa_supplicant/wpa_supplicant.c | 24 ++++- wpa_supplicant/wpa_supplicant.conf | 7 ++ wpa_supplicant/wpas_glue.c | 6 +- 17 files changed, 278 insertions(+), 23 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 5bb47bcbe..75d564b9c 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -184,6 +184,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic; if (pairwise && sm->wpa_deny_ptk0_rekey && + !sm->use_extended_key_id && wpa_sm_get_state(sm) == WPA_COMPLETED) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: PTK0 rekey not allowed, reconnecting"); @@ -607,6 +608,58 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, sm->pairwise_cipher, z, z_len); } +#ifdef CONFIG_FILS +static int fils_handle_extended_key_id(struct wpa_sm *sm, + struct wpa_eapol_ie_parse *kde) +{ + struct wpa_ie_data rsn; + + sm->keyidx_active = 0; + if (sm->extended_key_id && sm->pairwise_cipher != WPA_CIPHER_TKIP && + !wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &rsn) && + rsn.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) + sm->use_extended_key_id = 1; + else + sm->use_extended_key_id = 0; + return 0; +} +#endif /* CONFIG_FILS */ + +static int handle_extended_key_id(struct wpa_sm *sm, + struct wpa_eapol_ie_parse *kde) +{ + struct wpa_ie_data rsn; + + if (sm->extended_key_id && sm->pairwise_cipher != WPA_CIPHER_TKIP && + !wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &rsn) && + rsn.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) { + if (!kde->key_id) { + wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, + "WPA: No KeyID in Extended Key ID handshake"); + return -1; + } else if (kde->key_id[0] & 0xfe) { + wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, + "WPA: Invalid KeyID: %d", kde->key_id[0]); + return -1; + } + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: Using Extended Key ID"); + sm->keyidx_active = kde->key_id[0]; + sm->use_extended_key_id = 1; + } else { + if (kde->key_id && kde->key_id[0]) { + wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, + "Non-zero Extended Key ID KeyID in PTK0 handshake"); + return -1; + } else if (kde->key_id) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "Extended Key ID KeyID in PTK0 handshake"); + } + sm->keyidx_active = 0; + sm->use_extended_key_id = 0; + } + return 0; +} static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, const unsigned char *src_addr, @@ -626,7 +679,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, return; } - if (sm->wpa_deny_ptk0_rekey && wpa_sm_get_state(sm) == WPA_COMPLETED) { + if (sm->wpa_deny_ptk0_rekey && !sm->use_extended_key_id && + 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); @@ -762,9 +816,10 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Key negotiation completed with " - MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr), + MACSTR " [PTK=%s GTK=%s%s]", MAC2STR(addr), wpa_cipher_txt(sm->pairwise_cipher), - wpa_cipher_txt(sm->group_cipher)); + wpa_cipher_txt(sm->group_cipher), + sm->use_extended_key_id ? " Extended_Key_ID" : ""); wpa_sm_cancel_auth_timeout(sm); wpa_sm_set_state(sm, WPA_COMPLETED); @@ -859,13 +914,15 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen); } - if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen, - sm->ptk.tk, keylen, + if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc, + rsclen, sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE | key_flag) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to set PTK to the " - "driver (alg=%d keylen=%d bssid=" MACSTR ")", - alg, keylen, MAC2STR(sm->bssid)); + "WPA: Failed to set PTK to the driver" + "(alg=%d keylen=%d bssid=" MACSTR + " idx=%d use_extended_key_id=%d key_flag=0x%x)", + alg, keylen, MAC2STR(sm->bssid), + sm->keyidx_active, sm->use_extended_key_id, key_flag); return -1; } @@ -879,7 +936,22 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, sm, NULL); } + return 0; +} +static int wpa_supplicant_activate_ptk(struct wpa_sm *sm) +{ + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: Activate PTK (idx=%d bssid=" MACSTR ")", + sm->keyidx_active, MAC2STR(sm->bssid)); + + if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active, + 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, + "WPA: Failed to activate PTK for Tx (idx=%d bssid=" + MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid)); + return -1; + } return 0; } @@ -1582,6 +1654,9 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) goto failed; + if (handle_extended_key_id(sm, &ie)) + goto failed; + if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: ANonce from message 1 of 4-Way Handshake " @@ -1626,6 +1701,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, } } #endif /* CONFIG_OCV */ + if (sm->use_extended_key_id) { + if (wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX)) + goto failed; + } if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, &sm->ptk) < 0) { @@ -1638,8 +1717,13 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, sm->renew_snonce = 1; if (key_info & WPA_KEY_INFO_INSTALL) { - if (wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX_TX)) + if (sm->use_extended_key_id) { + if (wpa_supplicant_activate_ptk(sm)) + goto failed; + } else if (wpa_supplicant_install_ptk(sm, key, + KEY_FLAG_RX_TX)) { goto failed; + } } if (key_info & WPA_KEY_INFO_SECURE) { @@ -2746,6 +2830,7 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) return NULL; dl_list_init(&sm->pmksa_candidates); sm->renew_snonce = 1; + sm->keyidx_active = 0; sm->ctx = ctx; sm->dot11RSNAConfigPMKLifetime = 43200; @@ -3164,6 +3249,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, case WPA_PARAM_DENY_PTK0_REKEY: sm->wpa_deny_ptk0_rekey = value; break; + case WPA_PARAM_EXTENDED_KEY_ID: + sm->extended_key_id = value; + break; default: break; } @@ -3238,6 +3326,18 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm) } +int wpa_sm_extended_key_id(struct wpa_sm *sm) +{ + return sm->extended_key_id; +} + + +int wpa_sm_extended_key_id_active(struct wpa_sm *sm) +{ + return sm->use_extended_key_id; +} + + int wpa_sm_ocv_enabled(struct wpa_sm *sm) { struct wpa_ie_data rsn; @@ -4253,6 +4353,8 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf) capab |= WPA_CAPABILITY_MFPR; if (sm->ocv) capab |= WPA_CAPABILITY_OCVC; + if (sm->extended_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; wpabuf_put_le16(buf, capab); /* PMKID Count */ @@ -4645,6 +4747,7 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len) wpa_printf(MSG_DEBUG, "FILS: No GTK KDE"); goto fail; } + maxkeylen = gd.gtk_len = kde.gtk_len - 2; if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, gd.gtk_len, maxkeylen, @@ -4680,11 +4783,21 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len) keylen, (long unsigned int) sm->ptk.tk_len); goto fail; } + + if (elems.rsn_ie) { + /* link in RSN for fils_handle_extended_key_id() */ + kde.rsn_ie = elems.rsn_ie - 2; + kde.rsn_ie_len = elems.rsn_ie_len + 2; + } + if (fils_handle_extended_key_id(sm, &kde)) + goto fail; + rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher); wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver", sm->ptk.tk, keylen); - if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen, - sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) { + if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, + null_rsc, rsclen, sm->ptk.tk, keylen, + KEY_FLAG_PAIRWISE_RX_TX) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid=" MACSTR ")", diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 0bd14495a..585bbcc95 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -102,6 +102,7 @@ enum wpa_sm_conf_params { WPA_PARAM_OCV, WPA_PARAM_SAE_PWE, WPA_PARAM_DENY_PTK0_REKEY, + WPA_PARAM_EXTENDED_KEY_ID, }; struct rsn_supp_config { @@ -154,6 +155,8 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, int verbose); int wpa_sm_pmf_enabled(struct wpa_sm *sm); +int wpa_sm_extended_key_id(struct wpa_sm *sm); +int wpa_sm_extended_key_id_active(struct wpa_sm *sm); int wpa_sm_ocv_enabled(struct wpa_sm *sm); void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise); @@ -300,6 +303,16 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm) return 0; } +static inline int wpa_sm_extended_key_id(struct wpa_sm *sm) +{ + return 0; +} + +static inline int wpa_sm_extended_key_id_active(struct wpa_sm *sm) +{ + return 0; +} + static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm) { return 0; diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index baa185ffe..9592d10d7 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -263,6 +263,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, capab |= WPA_CAPABILITY_MFPR; if (sm->ocv) capab |= WPA_CAPABILITY_OCVC; + if (sm->extended_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; WPA_PUT_LE16(pos, capab); pos += 2; @@ -429,8 +431,8 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) alg = wpa_cipher_to_alg(sm->pairwise_cipher); keylen = wpa_cipher_key_len(sm->pairwise_cipher); - if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc), - (u8 *) sm->ptk.tk, keylen, + if (wpa_sm_set_key(sm, alg, bssid, sm->keyidx_active, 1, null_rsc, + sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) { wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); return -1; @@ -440,6 +442,26 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) } +static void ft_handle_extended_key_id(struct wpa_sm *sm, + struct wpa_ft_ies *parse) +{ + if (sm->extended_key_id && parse->rsn && + sm->pairwise_cipher != WPA_CIPHER_TKIP && + parse->rsn_capab & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "FT: Using Extended Key ID"); + sm->use_extended_key_id = 1; + } else { + sm->use_extended_key_id = 0; + } + /* There is no standardized way to hand over the KeyID in FT. + * Since FT can only be used for the initial connect we assume + * it must be 0. + */ + sm->keyidx_active = 0; +} + + /** * wpa_ft_prepare_auth_request - Generate over-the-air auth request * @sm: Pointer to WPA state machine data from wpa_sm_init() @@ -661,6 +683,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, os_free(ft_ies); } + ft_handle_extended_key_id(sm, &parse); wpa_sm_mark_authenticated(sm, bssid); ret = wpa_ft_install_ptk(sm, bssid); if (ret) { diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 7af678dcd..27c31f8ca 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -26,6 +26,7 @@ struct wpa_sm { u8 snonce[WPA_NONCE_LEN]; u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */ int renew_snonce; + int keyidx_active; u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; int rx_replay_counter_set; u8 request_counter[WPA_REPLAY_COUNTER_LEN]; @@ -68,6 +69,8 @@ struct wpa_sm { int wpa_rsc_relaxation; int owe_ptk_workaround; int beacon_prot; + int extended_key_id; + int use_extended_key_id; u8 own_addr[ETH_ALEN]; const char *ifname; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 03c0d7e85..c9899595e 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -221,6 +221,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, capab |= WPA_CAPABILITY_MFPR; if (sm->ocv) capab |= WPA_CAPABILITY_OCVC; + if (sm->extended_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; WPA_PUT_LE16(pos, capab); pos += 2; diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 87573ef10..ee7c755b5 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -344,6 +344,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, #endif /* CONFIG_IEEE80211AX */ bss->isolate = !wpa_s->conf->p2p_intra_bss; + bss->extended_key_id = wpa_s->conf->extended_key_id; bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk; bss->wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey; diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 2b9c3f53e..2fef83a5a 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -4293,6 +4293,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD; config->cert_in_cb = DEFAULT_CERT_IN_CB; config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION; + config->extended_key_id = DEFAULT_EXTENDED_KEY_ID; #ifdef CONFIG_MBO config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA; @@ -5057,6 +5058,7 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(coloc_intf_reporting, 0, 1), 0 }, #ifdef CONFIG_WNM { INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM }, + { INT_RANGE(extended_key_id, 0, 1), 0 }, #endif /* CONFIG_WNM */ }; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index b3c779233..165be35f7 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -44,6 +44,12 @@ #define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED #define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75 #define DEFAULT_OCE_SUPPORT OCE_STA +#ifdef CONFIG_TESTING_OPTIONS +/* For now only testing is using Extended Key ID by default */ +#define DEFAULT_EXTENDED_KEY_ID 1 +#else /* CONFIG_TESTING_OPTIONS */ +#define DEFAULT_EXTENDED_KEY_ID 0 +#endif /* CONFIG_TESTING_OPTIONS */ #include "config_ssid.h" #include "wps/wps.h" @@ -1570,6 +1576,18 @@ struct wpa_config { * By default BSS transition management is enabled */ int disable_btm; + + /** extended_key_id - Extended Key ID support + * + * IEEE 802.11-2016 optionally allows to use keyid 0 and 1 for PTK keys + * with Extended Key ID. + * + * 0 = don't use Extended Key ID + * 1 = use Extended Key ID when possible + * + * By default Extended Key ID support is disabled + */ + int extended_key_id; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index b8e56f5b2..e77cbca4f 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1596,6 +1596,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) config->p2p_interface_random_mac_addr); if (config->disable_btm) fprintf(f, "disable_btm=1\n"); + if (config->extended_key_id != DEFAULT_EXTENDED_KEY_ID) + fprintf(f, "extended_key_id=%d\n", + config->extended_key_id); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c index 598bc7790..2ff5f27ec 100644 --- a/wpa_supplicant/config_winreg.c +++ b/wpa_supplicant/config_winreg.c @@ -277,6 +277,16 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk) wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc); wpa_config_read_reg_dword(hk, TEXT("pmf"), &val); config->pmf = val; + if (wpa_config_read_reg_dword(hk, TEXT("extended_key_id"), + &config->extended_key_id) == 0) { + if (config->extended_key_id < 0 || + config->extended_key_id > 1) { + wpa_printf(MSG_ERROR, + "Invalid Extended Key ID setting (%d)", + config->extended_key_id); + errors++; + } + } return errors ? -1 : 0; } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 2321fc358..20ea5a515 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -746,11 +746,28 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, pos++; } } else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) { + struct wpa_ie_data data; + wpabuf_free(wpa_s->rsne_override_eapol); - if (os_strcmp(value, "NULL") == 0) + if (os_strcmp(value, "NULL") == 0) { wpa_s->rsne_override_eapol = NULL; - else + } else { wpa_s->rsne_override_eapol = wpabuf_parse_bin(value); + if (!wpa_parse_wpa_ie_rsn( + wpabuf_head(wpa_s->rsne_override_eapol), + wpabuf_len(wpa_s->rsne_override_eapol), + &data) && + (data.capabilities & + WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) { + wpa_s->conf->extended_key_id = 1; + wpa_printf(MSG_DEBUG, + "TESTING: rsne_override_eapol enables Extended Key ID"); + } else { + wpa_s->conf->extended_key_id = 0; + wpa_printf(MSG_DEBUG, + "TESTING: rsne_override_eapol disables Extended Key ID"); + } + } } else if (os_strcasecmp(cmd, "rsnxe_override_assoc") == 0) { wpabuf_free(wpa_s->rsnxe_override_assoc); if (os_strcmp(value, "NULL") == 0) @@ -5372,6 +5389,9 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s) wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); + if (wpa_sm_extended_key_id(wpa_s->wpa)) + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0, + NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); /* MLME-SETPROTECTION.request(None) */ wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid, MLME_SETPROTECTION_PROTECT_TYPE_NONE, @@ -9338,6 +9358,7 @@ static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd) static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, const char *cmd) { + struct wpa_ie_data data; struct wpabuf *buf; size_t len; @@ -9360,6 +9381,16 @@ static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, } wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf); + if (!wpa_parse_wpa_ie_rsn(wpabuf_head(buf), wpabuf_len(buf), &data) && + (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) { + wpa_s->conf->extended_key_id = 1; + wpa_printf(MSG_DEBUG, + "WPA: Forced own IE enables Extended Key ID"); + } else { + wpa_s->conf->extended_key_id = 0; + wpa_printf(MSG_DEBUG, + "WPA: Forced own IE disables Extended Key ID"); + } return 0; } diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index c842c50e9..d99242473 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -991,7 +991,7 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { - const char *capabilities[11]; + const char *capabilities[12]; size_t num_items = 0; #ifdef CONFIG_FILS struct wpa_global *global = user_data; @@ -1037,6 +1037,7 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( #ifdef CONFIG_OWE capabilities[num_items++] = "owe"; #endif /* CONFIG_OWE */ + capabilities[num_items++] = "extended_key_id"; return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING, diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index d3fb58707..edde6fa99 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -165,7 +165,14 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, params.key_flag = key_flag; if (alg != WPA_ALG_NONE) { - if (key_idx >= 0 && key_idx <= 6) + /* keyidx = 1 can be either a broadcast or - with + * Extended Key ID - an unicast key. Use bit 15 for + * the pairwise keyidx 1 which is hopefully high enough + * to not clash with future extensions. + */ + if (key_idx == 1 && key_flag & KEY_FLAG_PAIRWISE) + wpa_s->keys_cleared &= ~BIT(15); + else if (key_idx >= 0 && key_idx <= 5) wpa_s->keys_cleared &= ~BIT(key_idx); else wpa_s->keys_cleared = 0; diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 22885e646..730d749fe 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -502,6 +502,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos) "ignore_auth_resp", #endif /* CONFIG_TESTING_OPTIONS */ "relative_rssi", "relative_band_adjust", + "extended_key_id", }; int i, num_fields = ARRAY_SIZE(fields); @@ -593,7 +594,7 @@ static char ** wpa_cli_complete_get(const char *str, int pos) "tdls_external_control", "osu_dir", "wowlan_triggers", "p2p_search_delay", "mac_addr", "rand_addr_lifetime", "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", - "reassoc_same_bss_optim" + "reassoc_same_bss_optim", "extended_key_id" }; int i, num_fields = ARRAY_SIZE(fields); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index c638fe535..d82e8828f 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -748,10 +748,15 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP); } - if (!(wpa_s->keys_cleared & BIT(0)) && addr && + /* Pairwise key idx 1 for Extended Key ID is tracked in bit 15 */ + if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr && !is_zero_ether_addr(addr)) { - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, - 0, KEY_FLAG_PAIRWISE); + if (!(wpa_s->keys_cleared & (BIT(0)))) + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, + 0, NULL, 0, KEY_FLAG_PAIRWISE); + if (!(wpa_s->keys_cleared & (BIT(15)))) + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL, + 0, NULL, 0, KEY_FLAG_PAIRWISE); /* MLME-SETPROTECTION.request(None) */ wpa_drv_mlme_setprotection( wpa_s, addr, @@ -1635,6 +1640,19 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, sae_pwe = 1; wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe); + /* Extended Key ID is only supported in INFRA mode so far */ + if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id && + ssid->proto & WPA_PROTO_RSN && + ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 | + WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) && + wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) { + wpa_msg(wpa_s, MSG_INFO, "Enable Extended Key ID support"); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXTENDED_KEY_ID, + wpa_s->conf->extended_key_id); + } else { + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXTENDED_KEY_ID, 0); + } + 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"); return -1; diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index f3a750e3c..c75cc9248 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -802,6 +802,13 @@ fast_reauth=1 # Set BIT(1) to Enable OCE in STA-CFON mode #oce=1 +# extended_key_id: +# "Extended Key ID support for Individually Addressed Frames" according to +# IEEE 802.11-2016. +# +# 0 = force off: Do not use Extended Key ID (default) +# 1 = auto: Activate Extended Key ID support + # network block # # Each network (usually AP's sharing the same SSID) is configured as a separate diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 39b05b2b9..7ca1a9f64 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -533,7 +533,8 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg, } #endif /* CONFIG_TESTING_GET_GTK */ #ifdef CONFIG_TESTING_OPTIONS - if (addr && !is_broadcast_ether_addr(addr)) { + if (addr && !is_broadcast_ether_addr(addr) && + !(key_flag & KEY_FLAG_MODIFY)) { wpa_s->last_tk_alg = alg; os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN); wpa_s->last_tk_key_idx = key_idx; @@ -1077,7 +1078,8 @@ static int wpa_supplicant_eap_auth_start_cb(void *ctx) { struct wpa_supplicant *wpa_s = ctx; - if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey) { + if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey && + !wpa_sm_extended_key_id_active(wpa_s->wpa)) { wpa_msg(wpa_s, MSG_INFO, "WPA: PTK0 rekey not allowed, reconnecting"); wpa_supplicant_reconnect(wpa_s);