From patchwork Sat Jan 4 22:10: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: 1217680 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.b="utwEJ3de"; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=wetzel-home.de header.i=@wetzel-home.de header.b="Yy1FPVkX"; 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 47qwyL32x5z9sP3 for ; Sun, 5 Jan 2020 09:13:14 +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=nPpGkngk5QvlvxskpCY1C28/rjOz6rNfKHF0k615lPU=; b=utwEJ3defpzeDB IVIGgX9j+APDPIv9D0Io06ZrLz814p/XnZBPww0KpenvwsC8oypXFXpJCGTwVfFYh2Bk8w9PCXTBm R6Ds65qp+pSS56DlEO+7xT4+s5zX2kHp1+sjLZA4Jjjk0x8nzWhpYN2fFQXZXlvL4yLZZlo3nFiT1 Ikd7ay2mop72PRwm3Hdc1Lzz6IrH1ZEs4W9E4K31qtuIauAXoSr21tcaf4pip4YS0i7Jubpk779pU /KIPOFsMSoXHFic6z2PwMzlgvUvvXX3UMhrN8Fcy+cL9lpSNPFzgEr4qRqq1IezrGgP490fp+hu8n r7i46BJ/WNsjFD69jvxg==; 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 1inrfM-0004f2-Qx; Sat, 04 Jan 2020 22:13:04 +0000 Received: from 8.mo179.mail-out.ovh.net ([46.105.75.26]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1inrdR-0002hL-Ir for hostap@lists.infradead.org; Sat, 04 Jan 2020 22:11:15 +0000 Received: from player157.ha.ovh.net (unknown [10.108.54.230]) by mo179.mail-out.ovh.net (Postfix) with ESMTP id 6A0B71542BB for ; Sat, 4 Jan 2020 23:11:02 +0100 (CET) Received: from awhome.eu (p4FF91EE6.dip0.t-ipconnect.de [79.249.30.230]) (Authenticated sender: postmaster@awhome.eu) by player157.ha.ovh.net (Postfix) with ESMTPSA id 4E5ACDDBBF15; Sat, 4 Jan 2020 22:10:58 +0000 (UTC) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1578175793; bh=nSpLFCR/7kyXtQoiY95b8gbD8isDMf+4pM3bItITY+k=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Yy1FPVkXjrklib9BWwn8PMC428o6LNaoy5Ynqb1k2bcVlG4BQrz87tKASMmInokxs t0WZA8AsZyuWObJ0glAuMjjMqx1KYC0blHsKW+ZqNGjTTm0VJ9PN04vlrN2BYnOqD4 WPO2BOcGqUznZy8zdQ4YRDxpueLlYNbqBe9vk5CM= To: j@w1.fi Subject: [Patch v9 10/16] AP: Support Extended Key ID Date: Sat, 4 Jan 2020 23:10:09 +0100 Message-Id: <20200104221015.90469-11-alexander@wetzel-home.de> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200104221015.90469-1-alexander@wetzel-home.de> References: <20200104221015.90469-1-alexander@wetzel-home.de> MIME-Version: 1.0 X-Ovh-Tracer-Id: 969962773997100284 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedufedrvdeghedgudeitdcutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecunecujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeetlhgvgigrnhguvghrucghvghtiigvlhcuoegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgeqnecuffhomhgrihhnpehpthhkrdhtkhenucfkpheptddrtddrtddrtddpjeelrddvgeelrdeftddrvdeftdenucfrrghrrghmpehmohguvgepshhmthhpqdhouhhtpdhhvghlohepphhlrgihvghrudehjedrhhgrrdhovhhhrdhnvghtpdhinhgvtheptddrtddrtddrtddpmhgrihhlfhhrohhmpegrlhgvgigrnhguvghrseifvghtiigvlhdqhhhomhgvrdguvgdprhgtphhtthhopehhohhsthgrpheslhhishhtshdrihhnfhhrrgguvggrugdrohhrghenucevlhhushhtvghrufhiiigvpedt X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200104_141105_959364_7DDDBA12 X-CRM114-Status: GOOD ( 21.96 ) 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.75.26 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_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 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: Alexander Wetzel , hostap@lists.infradead.org, luca@coelho.fi, johannes@sipsolutions.net 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 --- hostapd/config_file.c | 9 +++++ hostapd/hostapd.conf | 11 +++++++ src/ap/ap_config.c | 10 ++++++ src/ap/ap_config.h | 1 + src/ap/wpa_auth.c | 74 +++++++++++++++++++++++++++++++++++------- src/ap/wpa_auth.h | 1 + src/ap/wpa_auth_glue.c | 22 ++++++++++++- src/ap/wpa_auth_i.h | 3 ++ src/ap/wpa_auth_ie.c | 54 +++++++++++++++++++++++++++++- 9 files changed, 171 insertions(+), 14 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index b88071a58..417d4ee3c 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2875,6 +2875,15 @@ 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, "wpa_extended_key_id") == 0) { + bss->wpa_extended_key_id = atoi(pos); + if (bss->wpa_extended_key_id < 0 || + bss->wpa_extended_key_id > 1) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid wpa_extended_key_id=%d; allowed range 0..1", + line, bss->wpa_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; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index b61176717..9de9096fd 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1509,6 +1509,17 @@ 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 based on IEEE 802.11-2016 +# +# Extended Key ID allows to rekey PTK keys without the impacts the "normal" +# PTK0 rekeying has. (No data losses during the rekey and it requires less +# potentially missing special handling from the card/driver.) +# But it can only be used with wpa=2, CCMP/GCMP ciphers and when the +# card/driver has support for it. +# 0 = force off +# 1 = enable and use Extended Key ID support when possible (default) +#wpa_extended_key_id=1 + # 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 98a7f6e26..63174c133 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -62,6 +62,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->broadcast_key_idx_max = 2; bss->eap_reauth_period = 3600; + bss->wpa_extended_key_id = 1; bss->wpa_group_rekey = 600; bss->wpa_gmk_rekey = 86400; bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_NEVER; @@ -1143,6 +1144,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, } } + if (full_config && bss->wpa_extended_key_id && + !(bss->wpa & WPA_PROTO_RSN && + bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 | + WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256))) { + wpa_printf(MSG_ERROR, + "Extended Key ID support requires WPA2 and CCMP/GCMP, disabling it"); + bss->wpa_extended_key_id = 0; + } + #ifdef CONFIG_IEEE80211R_AP if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) && (bss->nas_identifier == NULL || diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 0b4483ea1..75f8dc432 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -345,6 +345,7 @@ struct hostapd_bss_config { * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ + int wpa_extended_key_id; int wpa_key_mgmt; enum mfp_options ieee80211w; int group_mgmt_cipher; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 7298e4928..c8ef366eb 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -756,7 +756,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_WARNING, "WPA: PTK0 rekey not allowed, disconnect " MACSTR, MAC2STR(sm->addr)); @@ -764,6 +765,8 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm) /* Try to encourage the STA reconnect */ 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; } @@ -1727,6 +1730,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.wpa_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); } @@ -1786,7 +1794,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) sm->AuthenticationRequest = TRUE; break; } else { - 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_WARNING, "WPA: PTK0 rekey not allowed, disconnect " MACSTR, MAC2STR(sm->addr)); @@ -1795,6 +1804,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) sm->disconnect_reason = WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; break; } + + if (sm->use_extended_key_id) + sm->keyidx_active ^= 1; /* flip keyID */ } if (sm->GUpdateStationKeys) { /* @@ -3160,12 +3172,12 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos) 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; struct wpa_group *gsm = sm->group; u8 *wpa_ie; int wpa_ie_len, secure, gtkidx, encr = 0; - u8 *wpa_ie_buf = NULL; + u8 *wpa_ie_buf = NULL, *kde = NULL; SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = FALSE; @@ -3231,6 +3243,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]; @@ -3271,6 +3295,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 @@ -3306,10 +3334,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); } @@ -3391,9 +3424,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; @@ -5016,7 +5057,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; @@ -5074,6 +5115,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 @@ -5106,10 +5151,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 64c261964..332dff30c 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 wpa_extended_key_id; int wpa_key_mgmt; int wpa_pairwise; int wpa_group; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 7abb93e73..a918daf00 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -39,6 +39,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, { os_memset(wconf, 0, sizeof(*wconf)); wconf->wpa = conf->wpa; + wconf->wpa_extended_key_id = conf->wpa_extended_key_id; wconf->wpa_key_mgmt = conf->wpa_key_mgmt; wconf->wpa_pairwise = conf->wpa_pairwise; wconf->wpa_group = conf->wpa_group; @@ -374,7 +375,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_PAIRWISE_RX_TX_MODIFY) { + /* KEY_FLAG_PAIRWISE_RX installed the key and updated the + * variables. Doing it again for KEY_FLAG_PAIRWISE_RX_TX_MODIFY + * would overwrite the desired information with zeros. + */ + } else if (addr && !is_broadcast_ether_addr(addr)) { struct sta_info *sta; sta = ap_get_sta(hapd, addr); @@ -1360,6 +1366,20 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) _conf.wpa_deny_ptk0_rekey = 0; } + if (_conf.wpa_extended_key_id) { + if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) { + wpa_msg(hapd->msg_ctx, MSG_INFO, + "Enable Extended Key ID support"); + } else { + wpa_msg(hapd->msg_ctx, MSG_INFO, + "Extended Key ID not supported by driver"); + _conf.wpa_extended_key_id = 0; + } + } else if (_conf.wpa & WPA_PROTO_RSN) { + wpa_msg(hapd->msg_ctx, MSG_INFO, + "Extended Key ID support disabled"); + } + 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 a993f5008..0b182391b 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; @@ -285,6 +287,7 @@ 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, int capabilities); #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..cb01e4d7f 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -284,6 +284,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } + if (conf->wpa_extended_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) @@ -447,8 +449,9 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) { u8 *pos, buf[128]; int res; - #ifdef CONFIG_TESTING_OPTIONS + struct wpa_ie_data data; + if (wpa_auth->conf.own_ie_override_len) { wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing", wpa_auth->conf.own_ie_override, @@ -461,6 +464,14 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override, wpa_auth->conf.own_ie_override_len); wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len; + if (wpa_parse_wpa_ie_rsn(wpa_auth->wpa_ie, + wpa_auth->wpa_ie_len, &data) || + !(data.capabilities & + WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) { + wpa_printf(MSG_DEBUG, + "WPA: Own IE forcing wpa_extended_key_id=0"); + wpa_auth->conf.wpa_extended_key_id = 0; + } return 0; } #endif /* CONFIG_TESTING_OPTIONS */ @@ -545,6 +556,44 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) return 0; } +int handle_extended_key_id(struct wpa_state_machine *sm, int capabilities) +{ + struct wpa_auth_config *conf = &sm->wpa_auth->conf; + + if (conf->wpa_extended_key_id && + sm->pairwise != WPA_CIPHER_TKIP && + 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) { + wpa_printf(MSG_DEBUG, "STA " MACSTR + " supports Extended Key ID", + MAC2STR(sm->addr)); + sm->use_extended_key_id = TRUE; + } else if (!sm->pairwise_set) { + wpa_printf(MSG_DEBUG, "STA " MACSTR + " is not supporting Extended Key ID", + MAC2STR(sm->addr)); + } + } else { + if (sm->use_extended_key_id && sm->pairwise_set) { + wpa_printf(MSG_ERROR, "STA " MACSTR + " is using Extended Key ID, can't rekey without it", + MAC2STR(sm->addr)); + return -1; + } else if (!sm->pairwise_set) { + wpa_printf(MSG_DEBUG, "STA " MACSTR + " can't use Extended Key ID", + MAC2STR(sm->addr)); + sm->use_extended_key_id = FALSE; + sm->keyidx_active = 0; + } + } + return 0; +} int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int freq, @@ -870,6 +919,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, else sm->wpa = WPA_VERSION_WPA; + if (handle_extended_key_id(sm, data.capabilities)) + return WPA_INVALID_IE; + #if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS) if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 || sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&