aboutsummaryrefslogtreecommitdiffstats
path: root/src/rsn_supp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rsn_supp')
-rw-r--r--src/rsn_supp/Makefile15
-rw-r--r--src/rsn_supp/pmksa_cache.c43
-rw-r--r--src/rsn_supp/pmksa_cache.h1
-rw-r--r--src/rsn_supp/preauth.c24
-rw-r--r--src/rsn_supp/tdls.c12
-rw-r--r--src/rsn_supp/wpa.c437
-rw-r--r--src/rsn_supp/wpa.h33
-rw-r--r--src/rsn_supp/wpa_ft.c248
-rw-r--r--src/rsn_supp/wpa_i.h39
-rw-r--r--src/rsn_supp/wpa_ie.c36
-rw-r--r--src/rsn_supp/wpa_ie.h1
11 files changed, 739 insertions, 150 deletions
diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
index eea0efb..d14d736 100644
--- a/src/rsn_supp/Makefile
+++ b/src/rsn_supp/Makefile
@@ -1,13 +1,3 @@
-all: librsn_supp.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov librsn_supp.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_TDLS
CFLAGS += -DCONFIG_WNM
@@ -21,7 +11,4 @@ LIB_OBJS= \
wpa.o \
wpa_ie.o
-librsn_supp.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index d720f7b..e481dd5 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -267,7 +267,10 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
entry->network_ctx, entry->akmp);
wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid,
entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
- entry->pmk, entry->pmk_len);
+ entry->pmk, entry->pmk_len,
+ pmksa->sm->dot11RSNAConfigPMKLifetime,
+ pmksa->sm->dot11RSNAConfigPMKReauthThreshold,
+ entry->akmp);
return entry;
}
@@ -277,7 +280,7 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
* pmksa_cache_flush - Flush PMKSA cache entries for a specific network
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context or %NULL to flush all entries
- * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk: PMK to match for or %NULL to match all PMKs
* @pmk_len: PMK length
*/
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
@@ -371,9 +374,12 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
{
struct rsn_pmksa_cache_entry *new_entry;
os_time_t old_expiration = old_entry->expiration;
+ const u8 *pmkid = NULL;
+ if (wpa_key_mgmt_sae(old_entry->akmp))
+ pmkid = old_entry->pmkid;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
- NULL, NULL, 0,
+ pmkid, NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp,
old_entry->fils_cache_id_set ?
@@ -413,6 +419,20 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
while (entry) {
if (entry->network_ctx == network_ctx &&
(!akmp || entry->akmp == akmp)) {
+ struct os_reltime now;
+
+ if (wpa_key_mgmt_sae(entry->akmp) &&
+ os_get_reltime(&now) == 0 &&
+ entry->reauth_time < now.sec) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Do not clone PMKSA cache entry for "
+ MACSTR
+ " since its reauth threshold has passed",
+ MAC2STR(entry->aa));
+ entry = entry->next;
+ continue;
+ }
+
entry = pmksa_cache_clone_entry(pmksa, entry, aa);
if (entry) {
wpa_printf(MSG_DEBUG, "RSN: added "
@@ -466,6 +486,9 @@ void pmksa_cache_clear_current(struct wpa_sm *sm)
{
if (sm == NULL)
return;
+ if (sm->cur_pmksa)
+ wpa_printf(MSG_DEBUG,
+ "RSN: Clear current PMKSA entry selection");
sm->cur_pmksa = NULL;
}
@@ -516,6 +539,20 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
network_ctx,
fils_cache_id);
if (sm->cur_pmksa) {
+ struct os_reltime now;
+
+ if (wpa_key_mgmt_sae(sm->cur_pmksa->akmp) &&
+ os_get_reltime(&now) == 0 &&
+ sm->cur_pmksa->reauth_time < now.sec) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Do not allow PMKSA cache entry for "
+ MACSTR
+ " to be used for SAE since its reauth threshold has passed",
+ MAC2STR(sm->cur_pmksa->aa));
+ sm->cur_pmksa = NULL;
+ return -1;
+ }
+
wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
sm->cur_pmksa->pmkid, PMKID_LEN);
return 0;
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index 6c49fa9..83faa05 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -28,6 +28,7 @@ struct rsn_pmksa_cache_entry {
*/
u8 fils_cache_id[2];
unsigned int fils_cache_id_set:1;
+ unsigned int dpp_pfs:1;
os_time_t reauth_time;
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index d0c43f4..1a38bf6 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -49,6 +49,15 @@ void pmksa_candidate_free(struct wpa_sm *sm)
}
+static int rsn_preauth_key_mgmt(int akmp)
+{
+ return !!(akmp & (WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
+}
+
+
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -243,9 +252,9 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
- eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
+ eapol_sm_notify_portValid(sm->preauth_eapol, true);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
+ eapol_sm_notify_portEnabled(sm->preauth_eapol, true);
eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
rsn_preauth_timeout, sm, NULL);
@@ -311,10 +320,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
if (sm->preauth_eapol ||
sm->proto != WPA_PROTO_RSN ||
wpa_sm_get_state(sm) != WPA_COMPLETED ||
- (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
+ !rsn_preauth_key_mgmt(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
"state for new pre-authentication");
return; /* invalid state for new pre-auth */
@@ -343,7 +349,8 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
* PMKIDs again, so report the existing data now. */
if (p) {
wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid,
- NULL, p->pmk, p->pmk_len);
+ NULL, p->pmk, p->pmk_len, 0, 0,
+ p->akmp);
}
dl_list_del(&candidate->list);
@@ -488,6 +495,9 @@ void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
!(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
return;
+ if (!rsn_preauth_key_mgmt(ie.key_mgmt))
+ return;
+
/* Give less priority to candidates found from normal scan results. */
pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
ie.capabilities & WPA_CAPABILITY_PREAUTH);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 704c95e..eff8cd8 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -178,7 +178,7 @@ static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
- 0, 0, NULL, 0, NULL, 0) < 0) {
+ 0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
"the driver");
return -1;
@@ -227,8 +227,9 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
MAC2STR(peer->addr));
- if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
- rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+ if (wpa_sm_set_key(sm, alg, peer->addr, 0, 1, rsc, sizeof(rsc),
+ peer->tpk.tk, key_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
"driver");
return -1;
@@ -2806,6 +2807,11 @@ int wpa_tdls_init(struct wpa_sm *sm)
if (sm == NULL)
return -1;
+ if (sm->l2_tdls) {
+ l2_packet_deinit(sm->l2_tdls);
+ sm->l2_tdls = NULL;
+ }
+
sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname :
sm->ifname,
sm->own_addr,
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 504feaf..f3d324a 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -21,6 +21,8 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "drivers/driver.h"
@@ -183,6 +185,14 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
+ if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_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);
+ return;
+ }
+
if (wpa_use_akm_defined(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
@@ -488,6 +498,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
int res;
+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE before FT processing",
+ wpa_ie, wpa_ie_len);
/*
* Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and
* FTIE from (Re)Association Response.
@@ -503,8 +515,14 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
os_free(rsn_ie_buf);
return -1;
}
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: WPA IE after PMKID[PMKR1Name] addition into RSNE",
+ rsn_ie_buf, wpa_ie_len);
if (sm->assoc_resp_ies) {
+ wpa_hexdump(MSG_DEBUG, "WPA: Add assoc_resp_ies",
+ sm->assoc_resp_ies,
+ sm->assoc_resp_ies_len);
os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
sm->assoc_resp_ies_len);
wpa_ie_len += sm->assoc_resp_ies_len;
@@ -562,6 +580,7 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
{
const u8 *z = NULL;
size_t z_len = 0;
+ int akmp;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
@@ -575,13 +594,67 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->key_mgmt;
+#ifdef CONFIG_OWE
+ if (sm->owe_ptk_workaround && akmp == WPA_KEY_MGMT_OWE &&
+ sm->pmk_len > 32) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Force SHA256 for PTK derivation");
+ akmp |= WPA_KEY_MGMT_PSK_SHA256;
+ }
+#endif /* CONFIG_OWE */
return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
sm->own_addr, sm->bssid, sm->snonce,
- key->key_nonce, ptk, sm->key_mgmt,
+ key->key_nonce, ptk, akmp,
sm->pairwise_cipher, z, z_len);
}
+static int wpa_handle_ext_key_id(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *kde)
+{
+ if (sm->ext_key_id) {
+ u16 key_id;
+
+ if (!kde->key_id) {
+ wpa_msg(sm->ctx->msg_ctx,
+ sm->use_ext_key_id ? MSG_INFO : MSG_DEBUG,
+ "RSN: No Key ID in Extended Key ID handshake");
+ sm->keyidx_active = 0;
+ return sm->use_ext_key_id ? -1 : 0;
+ }
+
+ key_id = kde->key_id[0] & 0x03;
+ if (key_id > 1) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Invalid Extended Key ID: %d", key_id);
+ return -1;
+ }
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Using Extended Key ID %d", key_id);
+ sm->keyidx_active = key_id;
+ sm->use_ext_key_id = 1;
+ } else {
+ if (kde->key_id && (kde->key_id[0] & 0x03)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Non-zero Extended Key ID Key ID in PTK0 handshake");
+ return -1;
+ }
+
+ if (kde->key_id) {
+ /* This is not supposed to be included here, but ignore
+ * the case of matching Key ID 0 just in case. */
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Extended Key ID Key ID 0 in PTK0 handshake");
+ }
+ sm->keyidx_active = 0;
+ sm->use_ext_key_id = 0;
+ }
+
+ return 0;
+}
+
+
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
@@ -600,6 +673,14 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
return;
}
+ if (sm->wpa_deny_ptk0_rekey && !sm->use_ext_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);
+ return;
+ }
+
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way "
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
@@ -658,7 +739,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
kde_buf = os_malloc(kde_len +
2 + RSN_SELECTOR_LEN + 3 +
sm->assoc_rsnxe_len +
- 2 + RSN_SELECTOR_LEN + 1);
+ 2 + RSN_SELECTOR_LEN + 1 +
+ 2 + RSN_SELECTOR_LEN + 2);
if (!kde_buf)
goto failed;
os_memcpy(kde_buf, kde, kde_len);
@@ -675,6 +757,14 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
goto failed;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_eapol) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency, sm->oci_freq_override_eapol);
+ ci.frequency = sm->oci_freq_override_eapol;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (ocv_insert_oci_kde(&ci, &pos) < 0)
goto failed;
@@ -703,6 +793,27 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1 && sm->key_mgmt == WPA_KEY_MGMT_DPP) {
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "DPP: Add DPP KDE into EAPOL-Key 2/4");
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 2;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_DPP);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = DPP_VERSION; /* Protocol Version */
+ *pos = 0; /* Flags */
+ if (sm->dpp_pfs == 0)
+ *pos |= DPP_KDE_PFS_ALLOWED;
+ else if (sm->dpp_pfs == 1)
+ *pos |= DPP_KDE_PFS_ALLOWED | DPP_KDE_PFS_REQUIRED;
+ pos++;
+ kde_len = pos - kde;
+ }
+#endif /* CONFIG_DPP2 */
+
if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
kde, kde_len, ptk) < 0)
goto failed;
@@ -739,11 +850,11 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
wpa_sm_mlme_setprotection(
sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
- eapol_sm_notify_portValid(sm->eapol, TRUE);
+ eapol_sm_notify_portValid(sm->eapol, true);
if (wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
sm->key_mgmt == WPA_KEY_MGMT_DPP ||
sm->key_mgmt == WPA_KEY_MGMT_OWE)
- eapol_sm_notify_eap_success(sm->eapol, TRUE);
+ eapol_sm_notify_eap_success(sm->eapol, true);
/*
* Start preauthentication after a short wait to avoid a
* possible race condition between the data receive and key
@@ -781,7 +892,8 @@ static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
- const struct wpa_eapol_key *key)
+ const struct wpa_eapol_key *key,
+ enum key_flag key_flag)
{
int keylen, rsclen;
enum wpa_alg alg;
@@ -825,12 +937,14 @@ 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) < 0) {
+ 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 key_flag=0x%x)",
+ alg, keylen, MAC2STR(sm->bssid),
+ sm->keyidx_active, key_flag);
return -1;
}
@@ -844,7 +958,23 @@ 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_WARNING,
+ "WPA: Failed to activate PTK for TX (idx=%d bssid="
+ MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid));
+ return -1;
+ }
return 0;
}
@@ -919,7 +1049,8 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
if (wpa_sm_set_key(sm, gd->alg, NULL,
gd->keyidx, 1, key_rsc, gd->key_rsc_len,
- _gtk, gd->gtk_len) < 0) {
+ _gtk, gd->gtk_len,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to the driver "
"(Group only)");
@@ -928,7 +1059,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
}
} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
- _gtk, gd->gtk_len) < 0) {
+ _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to "
"the driver (alg=%d keylen=%d keyidx=%d)",
@@ -1082,7 +1213,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn),
- igtk->igtk, len) < 0) {
+ igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) {
if (keyidx == 0x0400 || keyidx == 0x0500) {
/* Assume the AP has broken PMF implementation since it
* seems to have swapped the KeyID bytes. The AP cannot
@@ -1119,14 +1250,66 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
}
+static int wpa_supplicant_install_bigtk(struct wpa_sm *sm,
+ const struct wpa_bigtk_kde *bigtk,
+ int wnm_sleep)
+{
+ size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ u16 keyidx = WPA_GET_LE16(bigtk->keyid);
+
+ /* Detect possible key reinstallation */
+ if ((sm->bigtk.bigtk_len == len &&
+ os_memcmp(sm->bigtk.bigtk, bigtk->bigtk,
+ sm->bigtk.bigtk_len) == 0) ||
+ (sm->bigtk_wnm_sleep.bigtk_len == len &&
+ os_memcmp(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len) == 0)) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)",
+ keyidx);
+ return 0;
+ }
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: BIGTK keyid %d pn " COMPACT_MACSTR,
+ keyidx, MAC2STR(bigtk->pn));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len);
+ if (keyidx < 6 || keyidx > 7) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid BIGTK KeyID %d", keyidx);
+ return -1;
+ }
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
+ keyidx, 0, bigtk->pn, sizeof(bigtk->pn),
+ bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure BIGTK to the driver");
+ return -1;
+ }
+
+ if (wnm_sleep) {
+ sm->bigtk_wnm_sleep.bigtk_len = len;
+ os_memcpy(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len);
+ } else {
+ sm->bigtk.bigtk_len = len;
+ os_memcpy(sm->bigtk.bigtk, bigtk->bigtk, sm->bigtk.bigtk_len);
+ }
+
+ return 0;
+}
+
+
static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
+ size_t len;
+
if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0;
if (ie->igtk) {
- size_t len;
const struct wpa_igtk_kde *igtk;
len = wpa_cipher_key_len(sm->mgmt_group_cipher);
@@ -1138,6 +1321,18 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
return -1;
}
+ if (ie->bigtk && sm->beacon_prot) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (ie->bigtk_len != WPA_BIGTK_KDE_PREFIX_LEN + len)
+ return -1;
+
+ bigtk = (const struct wpa_bigtk_kde *) ie->bigtk;
+ if (wpa_supplicant_install_bigtk(sm, bigtk, 0) < 0)
+ return -1;
+ }
+
return 0;
}
@@ -1324,11 +1519,10 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Could not find AP from "
"the scan results");
- } else {
- wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: Found the current AP from "
- "updated scan results");
+ return -1;
}
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Found the current AP from updated scan results");
}
if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
@@ -1372,6 +1566,11 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+ wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4",
+ ie->rsnxe, ie->rsnxe_len);
+ wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
return -1;
}
@@ -1478,6 +1677,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 (wpa_handle_ext_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 "
@@ -1515,14 +1717,33 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
- ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=eapol-key-m3 error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return;
}
}
#endif /* CONFIG_OCV */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1 && ie.dpp_kde) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: peer Protocol Version %u Flags 0x%x",
+ ie.dpp_kde[0], ie.dpp_kde[1]);
+ if (sm->key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_pfs != 2 &&
+ (ie.dpp_kde[1] & DPP_KDE_PFS_ALLOWED) && !sm->dpp_z) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association");
+ goto failed;
+ }
+ }
+#endif /* CONFIG_DPP2 */
+
+ if (sm->use_ext_key_id &&
+ 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) {
goto failed;
@@ -1534,7 +1755,14 @@ 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))
+ int res;
+
+ if (sm->use_ext_key_id)
+ res = wpa_supplicant_activate_ptk(sm);
+ else
+ res = wpa_supplicant_install_ptk(sm, key,
+ KEY_FLAG_RX_TX);
+ if (res)
goto failed;
}
@@ -1542,7 +1770,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_sm_mlme_setprotection(
sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
- eapol_sm_notify_portValid(sm->eapol, TRUE);
+ eapol_sm_notify_portValid(sm->eapol, true);
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
@@ -1590,6 +1818,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
sm->cur_pmksa = sa;
}
+ if (ie.transition_disable)
+ wpa_sm_transition_disable(sm, ie.transition_disable[0]);
sm->msg_3_of_4_ok = 1;
return;
@@ -1635,9 +1865,10 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
- ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=eapol-key-g1 error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return -1;
}
}
@@ -1808,6 +2039,15 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
os_free(rbuf);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_eapol_g2) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ sm->oci_freq_override_eapol_g2);
+ ci.frequency = sm->oci_freq_override_eapol_g2;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = key_mic + mic_len + 2; /* Key Data */
if (ocv_insert_oci_kde(&ci, &pos) < 0) {
@@ -2211,13 +2451,16 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
u8 *tmp = NULL;
int ret = -1;
u8 *mic, *key_data;
- size_t mic_len, keyhdrlen;
+ size_t mic_len, keyhdrlen, pmk_len;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ pmk_len = sm->pmk_len;
+ if (!pmk_len && sm->cur_pmksa)
+ pmk_len = sm->cur_pmksa->pmk_len;
+ mic_len = wpa_mic_len(sm->key_mgmt, pmk_len);
keyhdrlen = sizeof(*key) + mic_len + 2;
if (len < sizeof(*hdr) + keyhdrlen) {
@@ -2513,7 +2756,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
char pmkid_txt[PMKID_LEN * 2 + 1];
- int rsna, ret;
+ bool rsna;
+ int ret;
size_t len;
if (sm->cur_pmksa) {
@@ -2522,12 +2766,9 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
} else
pmkid_txt[0] = '\0';
- if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
- wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
- sm->proto == WPA_PROTO_RSN)
- rsna = 1;
- else
- rsna = 0;
+ rsna = (wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
+ wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
+ sm->proto == WPA_PROTO_RSN;
ret = os_snprintf(buf, buflen,
"dot11RSNAOptionImplemented=TRUE\n"
@@ -2730,7 +2971,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
* Clear portValid to kick EAPOL state machine to re-enter
* AUTHENTICATED state to get the EAPOL port Authorized.
*/
- eapol_sm_notify_portValid(sm->eapol, FALSE);
+ eapol_sm_notify_portValid(sm->eapol, false);
wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
/* Prepare for the next transition */
@@ -2776,6 +3017,8 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
#ifdef CONFIG_P2P
os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
#endif /* CONFIG_P2P */
+
+ sm->keyidx_active = 0;
}
@@ -2807,6 +3050,7 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
/* Keys are not needed in the WPA state machine anymore */
wpa_sm_drop_sa(sm);
+ sm->keyidx_active = 0;
sm->msg_3_of_4_ok = 0;
os_memset(sm->bssid, 0, ETH_ALEN);
@@ -2902,7 +3146,7 @@ void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
/**
- * wpa_sm_set_config - Notification of current configration change
+ * wpa_sm_set_config - Notification of current configuration change
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @config: Pointer to current network configuration
*
@@ -2929,6 +3173,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
sm->p2p = config->p2p;
sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
+ sm->owe_ptk_workaround = config->owe_ptk_workaround;
#ifdef CONFIG_FILS
if (config->fils_cache_id) {
sm->fils_cache_id_set = 1;
@@ -2938,6 +3183,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->fils_cache_id_set = 0;
}
#endif /* CONFIG_FILS */
+ sm->beacon_prot = config->beacon_prot;
} else {
sm->network_ctx = NULL;
sm->allowed_pairwise_cipher = 0;
@@ -2948,6 +3194,8 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->wpa_ptk_rekey = 0;
sm->p2p = 0;
sm->wpa_rsc_relaxation = 0;
+ sm->owe_ptk_workaround = 0;
+ sm->beacon_prot = 0;
}
}
@@ -3053,6 +3301,40 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_SAE_PWE:
sm->sae_pwe = value;
break;
+ case WPA_PARAM_SAE_PK:
+ sm->sae_pk = value;
+ break;
+ case WPA_PARAM_DENY_PTK0_REKEY:
+ sm->wpa_deny_ptk0_rekey = value;
+ break;
+ case WPA_PARAM_EXT_KEY_ID:
+ sm->ext_key_id = value;
+ break;
+ case WPA_PARAM_USE_EXT_KEY_ID:
+ sm->use_ext_key_id = value;
+ break;
+#ifdef CONFIG_TESTING_OPTIONS
+ case WPA_PARAM_FT_RSNXE_USED:
+ sm->ft_rsnxe_used = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_EAPOL:
+ sm->oci_freq_override_eapol = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_EAPOL_G2:
+ sm->oci_freq_override_eapol_g2 = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_FT_ASSOC:
+ sm->oci_freq_override_ft_assoc = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_FILS_ASSOC:
+ sm->oci_freq_override_fils_assoc = value;
+ break;
+#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP2
+ case WPA_PARAM_DPP_PFS:
+ sm->dpp_pfs = value;
+ break;
+#endif /* CONFIG_DPP2 */
default:
break;
}
@@ -3090,6 +3372,15 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
return pos - buf;
pos += ret;
+#ifdef CONFIG_DPP2
+ if (sm->key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+ ret = os_snprintf(pos, end - pos, "dpp_pfs=1\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_DPP2 */
+
if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
struct wpa_ie_data rsn;
if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
@@ -3127,6 +3418,18 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
}
+int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+ return sm ? sm->ext_key_id : 0;
+}
+
+
+int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+ return sm ? sm->use_ext_key_id : 0;
+}
+
+
int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
@@ -3502,6 +3805,14 @@ int wpa_sm_has_ptk(struct wpa_sm *sm)
}
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm)
+{
+ if (!sm)
+ return 0;
+ return sm->ptk.installed;
+}
+
+
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
{
os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
@@ -3562,6 +3873,13 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
igtk = (const struct wpa_igtk_kde *) (buf + 2);
if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
return -1;
+ } else if (subelem_id == WNM_SLEEP_SUBELEM_BIGTK) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ bigtk = (const struct wpa_bigtk_kde *) (buf + 2);
+ if (sm->beacon_prot &&
+ wpa_supplicant_install_bigtk(sm, bigtk, 1) < 0)
+ return -1;
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
return -1;
@@ -3745,13 +4063,13 @@ struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md)
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
+ /* Wrapped Data */
sm->fils_erp_pmkid_set = 0;
if (erp_msg) {
wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
/* Element ID Extension */
- wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
wpabuf_put_buf(buf, erp_msg);
/* Calculate pending PMKID here so that we do not need to
* maintain a copy of the EAP-Initiate/Reauth message. */
@@ -3956,16 +4274,16 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
goto fail;
}
- /* FILS Wrapped Data */
- if (!sm->cur_pmksa && elems.fils_wrapped_data) {
+ /* Wrapped Data */
+ if (!sm->cur_pmksa && elems.wrapped_data) {
u8 rmsk[ERP_MAX_KEY_LEN];
size_t rmsk_len;
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
- eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ elems.wrapped_data,
+ elems.wrapped_data_len);
+ eapol_sm_process_erp_finish(sm->eapol, elems.wrapped_data,
+ elems.wrapped_data_len);
if (eapol_sm_failed(sm->eapol))
goto fail;
@@ -4127,6 +4445,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->ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
wpabuf_put_le16(buf, capab);
/* PMKID Count */
@@ -4148,10 +4468,6 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
return -1;
}
sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
- sm->pmk_r0, sm->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
- sm->pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR,
MAC2STR(sm->r1kh_id));
pos = wpabuf_put(buf, WPA_PMK_NAME_LEN);
@@ -4160,8 +4476,6 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
@@ -4272,6 +4586,15 @@ struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
wpabuf_free(buf);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_fils_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ sm->oci_freq_override_fils_assoc);
+ ci.frequency = sm->oci_freq_override_fils_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
@@ -4476,8 +4799,10 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=fils-assoc error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
goto fail;
}
}
@@ -4554,11 +4879,12 @@ 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;
}
+
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) < 0) {
+ 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 ")",
@@ -4582,6 +4908,9 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
sm->fils_completed = 1;
forced_memzero(&gd, sizeof(gd));
+ if (kde.transition_disable)
+ wpa_sm_transition_disable(sm, kde.transition_disable[0]);
+
return 0;
fail:
forced_memzero(&gd, sizeof(gd));
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index f1fbb1b..2142772 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -27,10 +27,11 @@ struct wpa_sm_ctx {
void (*set_state)(void *ctx, enum wpa_states state);
enum wpa_states (*get_state)(void *ctx);
void (*deauthenticate)(void * ctx, u16 reason_code);
+ void (*reconnect)(void *ctx);
int (*set_key)(void *ctx, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len);
+ const u8 *key, size_t key_len, enum key_flag key_flag);
void * (*get_network_ctx)(void *ctx);
int (*get_bssid)(void *ctx, u8 *bssid);
int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
@@ -41,7 +42,8 @@ struct wpa_sm_ctx {
size_t *msg_len, void **data_pos);
int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len);
+ const u8 *pmk, size_t pmk_len, u32 pmk_lifetime,
+ u8 pmk_reauth_threshold, int akmp);
int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id);
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
@@ -84,6 +86,7 @@ struct wpa_sm_ctx {
void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
const u8 *pkt, size_t pkt_len);
int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
+ void (*transition_disable)(void *ctx, u8 bitmap);
};
@@ -100,6 +103,16 @@ enum wpa_sm_conf_params {
WPA_PARAM_MFP,
WPA_PARAM_OCV,
WPA_PARAM_SAE_PWE,
+ WPA_PARAM_SAE_PK,
+ WPA_PARAM_DENY_PTK0_REKEY,
+ WPA_PARAM_EXT_KEY_ID,
+ WPA_PARAM_USE_EXT_KEY_ID,
+ WPA_PARAM_FT_RSNXE_USED,
+ WPA_PARAM_DPP_PFS,
+ WPA_PARAM_OCI_FREQ_EAPOL,
+ WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ WPA_PARAM_OCI_FREQ_FILS_ASSOC,
};
struct rsn_supp_config {
@@ -111,9 +124,12 @@ struct rsn_supp_config {
const u8 *ssid;
size_t ssid_len;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey;
int p2p;
int wpa_rsc_relaxation;
+ int owe_ptk_workaround;
const u8 *fils_cache_id;
+ int beacon_prot;
};
#ifndef CONFIG_NO_WPA
@@ -149,6 +165,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_ext_key_id(struct wpa_sm *sm);
+int wpa_sm_ext_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);
@@ -172,6 +190,7 @@ int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm);
int wpa_sm_has_ptk(struct wpa_sm *sm);
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
@@ -294,6 +313,16 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
return 0;
}
+static inline int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+ return 0;
+}
+
+static inline int wpa_sm_ext_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 2b8b41f..bf73376 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
@@ -50,17 +51,11 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, sm->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
- sm->pmk_r0_name, WPA_PMK_NAME_LEN);
sm->pmk_r1_len = sm->pmk_r0_len;
if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
sm->r1kh_id, sm->own_addr, sm->pmk_r1,
sm->pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
ptk_name, sm->key_mgmt, sm->pairwise_cipher);
@@ -82,23 +77,30 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
if (sm == NULL)
return 0;
+ if (!get_ie(ies, ies_len, WLAN_EID_MOBILITY_DOMAIN)) {
+ os_free(sm->assoc_resp_ies);
+ sm->assoc_resp_ies = NULL;
+ sm->assoc_resp_ies_len = 0;
+ os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+ os_memset(sm->r0kh_id, 0, FT_R0KH_ID_MAX_LEN);
+ sm->r0kh_id_len = 0;
+ os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
+ return 0;
+ }
+
use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0)
return -1;
- if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
+ if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
return -1;
- if (ft.mdie) {
- wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
- ft.mdie, MOBILITY_DOMAIN_ID_LEN);
- os_memcpy(sm->mobility_domain, ft.mdie,
- MOBILITY_DOMAIN_ID_LEN);
- sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
- wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
- sm->mdie_ft_capab);
- } else
- os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
+ ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+ os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+ sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
+ wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
+ sm->mdie_ft_capab);
if (ft.r0kh_id) {
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
@@ -125,10 +127,10 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
if (sm->assoc_resp_ies) {
u8 *pos = sm->assoc_resp_ies;
- if (ft.mdie) {
- os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
- pos += ft.mdie_len + 2;
- }
+
+ os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
+ pos += ft.mdie_len + 2;
+
if (ft.ftie) {
os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
pos += ft.ftie_len + 2;
@@ -155,6 +157,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
* @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
* @ric_ies_len: Length of ric_ies buffer in octets
* @ap_mdie: Mobility Domain IE from the target AP
+ * @omit_rsnxe: Whether RSNXE is omitted from Reassociation Request frame
* Returns: Pointer to buffer with IEs or %NULL on failure
*
* Caller is responsible for freeing the returned buffer with os_free();
@@ -164,16 +167,16 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
const u8 *kck, size_t kck_len,
const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len,
- const u8 *ap_mdie)
+ const u8 *ap_mdie, int omit_rsnxe)
{
size_t buf_len;
u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count;
struct rsn_mdie *mdie;
struct rsn_ie_hdr *rsnie;
- u16 capab;
int mdie_len;
u8 rsnxe[10];
size_t rsnxe_len;
+ int rsnxe_used;
int res;
sm->ft_completed = 0;
@@ -249,14 +252,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- capab = 0;
- if (sm->mfp)
- capab |= WPA_CAPABILITY_MFPC;
- if (sm->mfp == 2)
- capab |= WPA_CAPABILITY_MFPR;
- if (sm->ocv)
- capab |= WPA_CAPABILITY_OCVC;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, rsn_supp_capab(sm));
pos += 2;
/* PMKID Count */
@@ -302,10 +298,20 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
ftie_pos = pos;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ftie_len = pos++;
+ rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && anonce &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (anonce && sm->ft_rsnxe_used) {
+ rsnxe_used = sm->ft_rsnxe_used == 1;
+ wpa_printf(MSG_DEBUG, "TESTING: FT: Force RSNXE Used %d",
+ rsnxe_used);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
struct rsn_ftie_sha384 *ftie;
ftie = (struct rsn_ftie_sha384 *) pos;
+ ftie->mic_control[0] = !!rsnxe_used;
fte_mic = ftie->mic;
elem_count = &ftie->mic_control[1];
pos += sizeof(*ftie);
@@ -316,6 +322,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
struct rsn_ftie *ftie;
ftie = (struct rsn_ftie *) pos;
+ ftie->mic_control[0] = !!rsnxe_used;
fte_mic = ftie->mic;
elem_count = &ftie->mic_control[1];
pos += sizeof(*ftie);
@@ -346,6 +353,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
os_free(buf);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_ft_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency, sm->oci_freq_override_ft_assoc);
+ ci.frequency = sm->oci_freq_override_ft_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
*pos++ = FTIE_SUBELEM_OCI;
*pos++ = OCV_OCI_LEN;
@@ -363,12 +378,16 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += ric_ies_len;
}
- res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
- if (res < 0) {
- os_free(buf);
- return NULL;
+ if (omit_rsnxe) {
+ rsnxe_len = 0;
+ } else {
+ res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
+ if (res < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ rsnxe_len = res;
}
- rsnxe_len = res;
if (kck) {
/*
@@ -422,8 +441,9 @@ 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) < 0) {
+ if (wpa_sm_set_key(sm, alg, bssid, 0, 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;
}
@@ -450,7 +470,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, 0, sm->bssid, NULL, 0, mdie);
+ NULL, 0, sm->bssid, NULL, 0, mdie, 0);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -624,9 +644,6 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name) < 0)
return -1;
sm->pmk_r1_len = sm->pmk_r0_len;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
- sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
@@ -646,7 +663,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name,
kck, kck_len, bssid,
ric_ies, ric_ies_len,
- parse.mdie ? parse.mdie - 2 : NULL);
+ parse.mdie ? parse.mdie - 2 : NULL,
+ !sm->ap_rsnxe);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -773,7 +791,8 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
os_memcpy(gtk + 24, tmp, 8);
}
if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
- gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
+ gtk_elem + 3, rsc_len, gtk, keylen,
+ KEY_FLAG_GROUP_RX) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
"driver.");
return -1;
@@ -840,7 +859,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
igtk_len);
if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr, keyidx, 0,
- igtk_elem + 2, 6, igtk, igtk_len) < 0) {
+ igtk_elem + 2, 6, igtk, igtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
"driver.");
forced_memzero(igtk, sizeof(igtk));
@@ -852,6 +872,74 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
}
+static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem,
+ size_t bigtk_elem_len)
+{
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+ size_t bigtk_len;
+ u16 keyidx;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (!sm->beacon_prot || !bigtk_elem ||
+ (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_128 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_CMAC_256))
+ return 0;
+
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: Received BIGTK in Reassoc Resp",
+ bigtk_elem, bigtk_elem_len);
+
+ bigtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (bigtk_elem_len != 2 + 6 + 1 + bigtk_len + 8) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem length %lu",
+ (unsigned long) bigtk_elem_len);
+ return -1;
+ }
+ if (bigtk_elem[8] != bigtk_len) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem Key Length %d",
+ bigtk_elem[8]);
+ return -1;
+ }
+
+ if (aes_unwrap(kek, kek_len, bigtk_len / 8, bigtk_elem + 9, bigtk)) {
+ wpa_printf(MSG_WARNING,
+ "FT: AES unwrap failed - could not decrypt BIGTK");
+ return -1;
+ }
+
+ /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
+
+ keyidx = WPA_GET_LE16(bigtk_elem);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: BIGTK from Reassoc Resp", bigtk,
+ bigtk_len);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr, keyidx, 0,
+ bigtk_elem + 2, 6, bigtk, bigtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
+ wpa_printf(MSG_WARNING,
+ "WPA: Failed to set BIGTK to the driver");
+ forced_memzero(bigtk, sizeof(bigtk));
+ return -1;
+ }
+ forced_memzero(bigtk, sizeof(bigtk));
+
+ return 0;
+}
+
+
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr)
{
@@ -864,6 +952,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
+ int own_rsnxe_used, rsnxe_used;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@@ -902,6 +991,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
@@ -915,6 +1005,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
}
@@ -1012,6 +1103,58 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
+ if (rsnxe_used && !sm->ap_rsnxe) {
+ wpa_printf(MSG_INFO,
+ "FT: FTE indicated that AP uses RSNXE, but RSNXE was not included in Beacon/Probe Response frames");
+ return -1;
+ }
+
+ if (!sm->ap_rsn_ie) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "FT: No RSNE for this AP known - trying to get from scan results");
+ if (wpa_sm_get_beacon_ie(sm) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "FT: Could not find AP from the scan results");
+ return -1;
+ }
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "FT: Found the current AP from updated scan results");
+ }
+
+ if (sm->ap_rsn_ie &&
+ wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+ parse.rsn - 2, parse.rsn_len + 2)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+ wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp",
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNE in FT protocol Reassociation Response frame",
+ parse.rsn ? parse.rsn - 2 : NULL,
+ parse.rsn ? parse.rsn_len + 2 : 0);
+ return -1;
+ }
+
+ own_rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2);
+ if ((sm->ap_rsnxe && !parse.rsnxe && own_rsnxe_used) ||
+ (!sm->ap_rsnxe && parse.rsnxe) ||
+ (sm->ap_rsnxe && parse.rsnxe &&
+ (sm->ap_rsnxe_len != 2 + parse.rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, parse.rsnxe - 2,
+ sm->ap_rsnxe_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FT: RSNXE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+ wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNXE in FT protocol Reassociation Response frame",
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0);
+ return -1;
+ }
+
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
@@ -1024,8 +1167,10 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=ft-assoc error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return -1;
}
}
@@ -1033,10 +1178,9 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
sm->ft_reassoc_completed = 1;
- if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
- return -1;
-
- if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
+ if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 ||
+ wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 ||
+ wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0)
return -1;
if (sm->set_ptk_after_assoc) {
@@ -1083,7 +1227,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, 0, target_ap, NULL, 0, mdie);
+ NULL, 0, target_ap, NULL, 0, mdie, 0);
if (ft_ies) {
sm->over_the_ds_in_progress = 1;
os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 2a43342..96b07fc 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -33,6 +33,8 @@ struct wpa_sm {
struct wpa_gtk gtk_wnm_sleep;
struct wpa_igtk igtk;
struct wpa_igtk igtk_wnm_sleep;
+ struct wpa_bigtk bigtk;
+ struct wpa_bigtk bigtk_wnm_sleep;
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
@@ -61,8 +63,15 @@ struct wpa_sm {
u8 ssid[32];
size_t ssid_len;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey:1;
int p2p;
int wpa_rsc_relaxation;
+ int owe_ptk_workaround;
+ int beacon_prot;
+ int ext_key_id; /* whether Extended Key ID is enabled */
+ int use_ext_key_id; /* whether Extended Key ID has been detected
+ * to be used */
+ int keyidx_active; /* Key ID for the active TK */
u8 own_addr[ETH_ALEN];
const char *ifname;
@@ -86,6 +95,7 @@ struct wpa_sm {
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
int ocv; /* Operating Channel Validation */
int sae_pwe; /* SAE PWE generation options */
+ int sae_pk; /* whether SAE-PK is used */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
@@ -144,6 +154,11 @@ struct wpa_sm {
#ifdef CONFIG_TESTING_OPTIONS
struct wpabuf *test_assoc_ie;
+ int ft_rsnxe_used;
+ unsigned int oci_freq_override_eapol;
+ unsigned int oci_freq_override_eapol_g2;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS
@@ -173,6 +188,7 @@ struct wpa_sm {
#ifdef CONFIG_DPP2
struct wpabuf *dpp_z;
+ int dpp_pfs;
#endif /* CONFIG_DPP2 */
};
@@ -198,11 +214,18 @@ static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, u16 reason_code)
static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
WPA_ASSERT(sm->ctx->set_key);
return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ seq, seq_len, key, key_len, key_flag);
+}
+
+static inline void wpa_sm_reconnect(struct wpa_sm *sm)
+{
+ WPA_ASSERT(sm->ctx->reconnect);
+ sm->ctx->reconnect(sm->ctx->ctx);
}
static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
@@ -248,11 +271,13 @@ static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *cache_id, const u8 *pmk,
- size_t pmk_len)
+ size_t pmk_len, u32 pmk_lifetime,
+ u8 pmk_reauth_threshold, int akmp)
{
WPA_ASSERT(sm->ctx->add_pmkid);
return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
- cache_id, pmk, pmk_len);
+ cache_id, pmk, pmk_len, pmk_lifetime,
+ pmk_reauth_threshold, akmp);
}
static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
@@ -410,6 +435,12 @@ static inline int wpa_sm_channel_info(struct wpa_sm *sm,
return sm->ctx->channel_info(sm->ctx->ctx, ci);
}
+static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap)
+{
+ if (sm->ctx->transition_disable)
+ sm->ctx->transition_disable(sm->ctx->ctx, bitmap);
+}
+
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 03c0d7e..20fdd69 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -105,6 +105,23 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
}
+u16 rsn_supp_capab(struct wpa_sm *sm)
+{
+ u16 capab = 0;
+
+ if (sm->mfp)
+ capab |= WPA_CAPABILITY_MFPC;
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+ if (sm->ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+ return capab;
+}
+
+
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
int pairwise_cipher, int group_cipher,
int key_mgmt, int mgmt_group_cipher,
@@ -112,7 +129,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
{
u8 *pos;
struct rsn_ie_hdr *hdr;
- u16 capab;
u32 suite;
if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
@@ -214,14 +230,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- capab = 0;
- if (sm->mfp)
- capab |= WPA_CAPABILITY_MFPC;
- if (sm->mfp == 2)
- capab |= WPA_CAPABILITY_MFPR;
- if (sm->ocv)
- capab |= WPA_CAPABILITY_OCVC;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, rsn_supp_capab(sm));
pos += 2;
if (sm->cur_pmksa) {
@@ -348,7 +357,7 @@ int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
if (!wpa_key_mgmt_sae(sm->key_mgmt))
return 0; /* SAE not in use */
- if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
+ if (sm->sae_pwe != 1 && sm->sae_pwe != 2 && !sm->sae_pk)
return 0; /* no supported extended RSN capabilities */
if (rsnxe_len < 3)
@@ -358,7 +367,12 @@ int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
*pos++ = 1;
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
* used for now */
- *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ *pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sm->sae_pk)
+ *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ pos++;
return pos - rsnxe;
}
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 6dc6cf5..83a6727 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -13,5 +13,6 @@ struct wpa_sm;
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len);
+u16 rsn_supp_capab(struct wpa_sm *sm);
#endif /* WPA_IE_H */