From patchwork Sun Aug 25 16:35:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Wetzel X-Patchwork-Id: 1152825 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=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="A/fA3EtU"; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=wetzel-home.de header.i=@wetzel-home.de header.b="FULXV+eK"; 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 46Ggn62yWqz9s7T for ; Mon, 26 Aug 2019 02:38:34 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type: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=9sKlSPl471IErL4uNCUT9HiYKAfxnzjRcO322V3G7bE=; b=A/fA3EtUH7sObD UGiRgf35ccyLn4ejqMxWu1CvkquE4CXYmTj8VQ5CI0+Enkb4Ug/e2tDzr+PsAJBV7ITqgpWZXO55H WCMlzoaMDY9O06kPE6nr4DNoHdiTk66oP8QvGmywDYyXMbqhRY5HTBQi1CQuYVbL3MKpCqHUBTT+Z lZyhShBZGWWrHFemHTEysHRxv+Cm44/LvyQBmR296P51xMj5f+7BvDPANkMy1jiUjMtSwXqbFmP+O VTSmW7De7uaBKTtcLAThGJIQBtarZUlmZoy8IX1vK7GgItQtDgOy7H5odVPceFXlvNxQX3abt2VWS WyJIcoA5y4P/5OyAVr7A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92 #3 (Red Hat Linux)) id 1i1vXA-0005lf-Es; Sun, 25 Aug 2019 16:38:28 +0000 Received: from 14.mo1.mail-out.ovh.net ([178.32.97.215]) by bombadil.infradead.org with esmtps (Exim 4.92 #3 (Red Hat Linux)) id 1i1vUl-0003fq-96 for hostap@lists.infradead.org; Sun, 25 Aug 2019 16:36:05 +0000 Received: from player159.ha.ovh.net (unknown [10.109.143.189]) by mo1.mail-out.ovh.net (Postfix) with ESMTP id 671B418BEF7 for ; Sun, 25 Aug 2019 18:35:49 +0200 (CEST) Received: from awhome.eu (p57B7E04C.dip0.t-ipconnect.de [87.183.224.76]) (Authenticated sender: postmaster@awhome.eu) by player159.ha.ovh.net (Postfix) with ESMTPSA id B8B8090127D9; Sun, 25 Aug 2019 16:35:45 +0000 (UTC) From: Alexander Wetzel DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wetzel-home.de; s=wetzel-home; t=1566750940; bh=PVLuHCVmr2MPmNk/9kuwhGiVSp8/DLrwDOtuFlHj8ko=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=FULXV+eKW/ws8o4yI3YnDdZJSxRpR9NHIexakU83/gzBmbJwovnNS0W1ks0hswSX+ DeuOaVkFuO3tuvyXkPheoam4tL8ZGo1bB8pMrsQNDo0Gm9bjHIVRRmMgyXMuGQtIDz nO0J7kPWXwQLHvX3x41SUdxHJ8nnfWoSfEXiBErg= To: j@w1.fi Subject: [PATCH v5 09/16] hostapd: Add support for Extended Key ID Date: Sun, 25 Aug 2019 18:35:14 +0200 Message-Id: <20190825163521.22625-10-alexander@wetzel-home.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190825163521.22625-1-alexander@wetzel-home.de> References: <20190825163521.22625-1-alexander@wetzel-home.de> MIME-Version: 1.0 X-Ovh-Tracer-Id: 13323055074621529340 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 0 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgeduvddrudehvddguddthecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecu X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190825_093559_607404_74CACB16 X-CRM114-Status: GOOD ( 24.59 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [178.32.97.215 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_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -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: 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 Add support for Extended Key ID in hostapd based on IEEE 802.11 - 2016. Extended Key ID allows to rekey PTK keys without the otherwise unavoidable MPDU losses on a busy link. The standard is fully backward compatible, allowing an AP to server STA's with and without support for it. Signed-off-by: Alexander Wetzel --- This is now finally starting the real work on the Extended Key ID support. Most is directly based on IEEE 802.11 - 2016 or an obvious consequence. But the sanity checks for Extended Key ID and how we handle FT with it are not. A Extended Key ID capable AP will have two different keys using keyid 1: The "usual" broadcast key and a second unicast key. (We already had a quick mail exchange about that, see https://marc.info/?l=linux-wireless&m=154427921122092&w=2) It's fully backward compatible and can serve client supporting Extended Key ID and not at the same time. I can't find any reference how we should handle FT combined with Extended Key ID. While our beacons announce Extended Key ID support a "normal" FT handshake never has a 4-way EAPOL handshake and thus there is no documented way to hand over the KeyID. We could of course then just agree to use the keyid 0 and to really start to use Extended Key ID with the first rekey. But I prefer to just also hand over the KeyID in addition to the GTK Key ID: This allows us to also use the keyid 1 with the initial key and open the door to verify if a remote STA is indeed able to use Extended Key ID and either fail at the initial connect or even fall back when not. (More about that in the last patch of the series.) hostapd/config_file.c | 2 ++ hostapd/hostapd.conf | 10 ++++++ src/ap/ap_config.c | 1 + src/ap/ap_config.h | 1 + src/ap/hs20.c | 2 ++ src/ap/wpa_auth.c | 71 ++++++++++++++++++++++++++++++++++++----- src/ap/wpa_auth.h | 1 + src/ap/wpa_auth_ft.c | 6 +++- src/ap/wpa_auth_glue.c | 32 ++++++++++++++++++- src/ap/wpa_auth_i.h | 3 ++ src/ap/wpa_auth_ie.c | 42 +++++++++++++++++++++++- src/common/wpa_common.c | 1 + src/common/wpa_common.h | 1 + 13 files changed, 162 insertions(+), 11 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 1ef7d57cc..451b11d2c 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2872,6 +2872,8 @@ 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); } 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 f36e1fa3a..47ad9d12c 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1471,6 +1471,16 @@ 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 the PTK key without impact for ongoing +# transmissions +# When enabled and supported by the driver the AP will offer and support it for +# stations. (The setting is only relevant with wpa=2) +# 0 = force off +# 1 = enable Extended Key ID support when driver supports it (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 90348e1dd..b6d6b3f8e 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -61,6 +61,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_group_update_count = 4; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index daf787e16..f22783d42 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -346,6 +346,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; #ifdef CONFIG_IEEE80211W enum mfp_options ieee80211w; diff --git a/src/ap/hs20.c b/src/ap/hs20.c index 532580e7c..791847cbc 100644 --- a/src/ap/hs20.c +++ b/src/ap/hs20.c @@ -80,6 +80,8 @@ u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid) /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } + if (hapd->conf->wpa_extended_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; #ifdef CONFIG_IEEE80211W if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index ba415bd66..0213e97c2 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -755,6 +755,9 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm) if (sm == NULL) return; + if (sm->use_extended_key_id) + sm->keyidx_active ^= 1; /* flip keyID */ + sm->PTKRequest = TRUE; sm->PTK_valid = 0; } @@ -1459,6 +1462,12 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, else version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; + /* Extended Key ID must not be used for TKIP */ + if (version == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { + sm->use_extended_key_id = FALSE; + sm->keyidx_active = 0; + } + pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d " @@ -1717,6 +1726,11 @@ void wpa_remove_ptk(struct wpa_state_machine *sm) 0, KEY_TYPE_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_TYPE_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); } @@ -1775,6 +1789,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) sm->Init = FALSE; sm->AuthenticationRequest = TRUE; break; + } else if (sm->use_extended_key_id) { + sm->keyidx_active ^= 1; /* flip keyID */ } if (sm->GUpdateStationKeys) { /* @@ -3142,7 +3158,7 @@ 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, *pos, dummy_gtk[32]; + u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32], hdr[2]; size_t gtk_len, kde_len; struct wpa_group *gsm = sm->group; u8 *wpa_ie; @@ -3183,6 +3199,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_TYPE_NO_AUTO_TX)) { + 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]; @@ -3223,6 +3251,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 @@ -3259,10 +3291,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); } @@ -3345,8 +3382,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_TYPE_PAIRWISE)) { + if (sm->use_extended_key_id) { + if (wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr, + sm->keyidx_active, NULL, 0, + KEY_TYPE_SET_TX)) { + 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_TYPE_PAIRWISE)) { wpa_sta_disconnect(sm->wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); return; @@ -4980,7 +5026,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]; #ifdef CONFIG_IEEE80211W u8 *opos; #endif /* CONFIG_IEEE80211W */ @@ -5040,6 +5086,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 @@ -5072,10 +5122,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 & 0x03; + 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 cc8ea5aa7..f756d492b 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_ft.c b/src/ap/wpa_auth_ft.c index 0f1a51832..a870ea799 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -2652,7 +2652,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_TYPE_PAIRWISE)) return; @@ -2891,6 +2891,10 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } + + if (handle_extended_key_id(sm, parse.capabilities)) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + use_sha384 = wpa_key_mgmt_sha384(parse.key_mgmt); pmk_r1_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index df900dba7..0cc824863 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; @@ -369,7 +370,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_type == KEY_TYPE_SET_TX) { + /* KEY_TYPE_NO_AUTO_TX installed the key and updated the + * variables. Since KEY_TYPE_SET_TX would overwrite the + * desired information with zeros do nothing. + */ + } else if (addr && !is_broadcast_ether_addr(addr)) { struct sta_info *sta; sta = ap_get_sta(hapd, addr); @@ -1305,6 +1311,30 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) _conf.tx_status = 1; if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) _conf.ap_mlme = 1; + + if (_conf.wpa_extended_key_id) { + if (_conf.wpa & WPA_PROTO_RSN && + _conf.rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | + WPA_CIPHER_GCMP_256 | + WPA_CIPHER_CCMP_256) && + hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) { + wpa_msg(hapd->msg_ctx, MSG_INFO, + "Enable Extended Key ID support"); + } else { + if (!(hapd->iface->drv_flags & + WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) + wpa_msg(hapd->msg_ctx, MSG_INFO, + "Extended Key ID not supported by driver"); + else + wpa_msg(hapd->msg_ctx, MSG_INFO, + "Extended Key ID requires wpa2 and CCMP/GCMP"); + _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 4babd0cbb..21c9b082f 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; @@ -284,6 +286,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 2e5c9160d..725c76056 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -286,6 +286,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; #ifdef CONFIG_IEEE80211W if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; @@ -411,6 +413,8 @@ static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid) /* 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; #ifdef CONFIG_IEEE80211W if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; @@ -435,8 +439,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, @@ -449,6 +454,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 */ @@ -528,6 +541,31 @@ 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 && + capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) { + if (!sm->use_extended_key_id && sm->pairwise_set) { + wpa_printf(MSG_DEBUG, + "Can only enable Extended Key ID on initial connect"); + return -1; + } else if (!sm->use_extended_key_id) { + sm->use_extended_key_id = TRUE; + } + } else { + if (sm->use_extended_key_id && sm->pairwise_set) { + wpa_printf(MSG_DEBUG, + "Already using Extended Key ID, can't stop"); + return -1; + } else if (sm->use_extended_key_id) { + 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, @@ -809,6 +847,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } #endif /* CONFIG_IEEE80211W */ + if (handle_extended_key_id(sm, data.capabilities)) + return WPA_INVALID_IE; #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index a7569580f..dc5ae4891 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -963,6 +963,7 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, parse->rsn_pmkid = data.pmkid; parse->key_mgmt = data.key_mgmt; parse->pairwise_cipher = data.pairwise_cipher; + parse->capabilities = data.capabilities; if (update_use_sha384) { use_sha384 = wpa_key_mgmt_sha384(parse->key_mgmt); diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 415104de9..ca0acbad4 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -475,6 +475,7 @@ struct wpa_ft_ies { size_t ric_len; int key_mgmt; int pairwise_cipher; + int capabilities; }; int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,