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);