"Failed to initialize WPA state machine");
return -1;
}
- wpa_auth_set_rsn_override(sta->wpa_sm,
- elems.rsne_override != NULL);
- wpa_auth_set_rsn_override_2(sta->wpa_sm,
- elems.rsne_override_2 != NULL);
+ wpa_auth_set_rsn_selection(sta->wpa_sm, elems.rsn_selection,
+ elems.rsn_selection_len);
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta)) {
wpa_printf(MSG_DEBUG,
goto fail;
}
+ wpa_auth_set_rsn_selection(sta->wpa_sm, elems.rsn_selection,
+ elems.rsn_selection_len);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
- wpa_auth_set_rsn_override(sta->wpa_sm, elems.rsne_override != NULL);
- wpa_auth_set_rsn_override_2(sta->wpa_sm, elems.rsne_override_2 != NULL);
-
if (!elems.fils_nonce) {
wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
#endif /* CONFIG_IEEE80211BE */
wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
- wpa_auth_set_rsn_override(sta->wpa_sm,
- elems->rsne_override != NULL);
- wpa_auth_set_rsn_override_2(sta->wpa_sm,
- elems->rsne_override_2 != NULL);
+ wpa_auth_set_rsn_selection(sta->wpa_sm, elems->rsn_selection,
+ elems->rsn_selection_len);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
os_free(sm->rsnxe);
+ os_free(sm->rsn_selection);
#ifdef CONFIG_IEEE80211BE
for_each_sm_auth(sm, link_id) {
wpa_group_put(sm->mld_links[link_id].wpa_auth,
goto out;
}
#endif /* CONFIG_IEEE80211R_AP */
+
+ /* Verify RSN Selection element for RSN overriding */
+ if ((sm->rsn_selection && !kde.rsn_selection) ||
+ (!sm->rsn_selection && kde.rsn_selection) ||
+ (sm->rsn_selection && kde.rsn_selection &&
+ (sm->rsn_selection_len != kde.rsn_selection_len ||
+ os_memcmp(sm->rsn_selection, kde.rsn_selection,
+ sm->rsn_selection_len) != 0))) {
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
+ "RSN Selection element from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
+ wpa_hexdump(MSG_DEBUG, "RSN Selection in AssocReq",
+ sm->rsn_selection, sm->rsn_selection_len);
+ wpa_hexdump(MSG_DEBUG, "RSN Selection in EAPOL-Key msg 2/4",
+ kde.rsn_selection, kde.rsn_selection_len);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ goto out;
+
+ }
+
#ifdef CONFIG_P2P
if (kde.ip_addr_req && kde.ip_addr_req[0] &&
wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
}
-void wpa_auth_set_rsn_override(struct wpa_state_machine *sm, bool val)
+void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
+ size_t len)
{
- if (sm)
- sm->rsn_override = val;
-}
-
-
-void wpa_auth_set_rsn_override_2(struct wpa_state_machine *sm, bool val)
-{
- if (sm)
- sm->rsn_override_2 = val;
+ if (!sm)
+ return;
+ os_free(sm->rsn_selection);
+ sm->rsn_selection = NULL;
+ sm->rsn_selection_len = 0;
+ sm->rsn_override = false;
+ sm->rsn_override_2 = false;
+ if (ie) {
+ if (len >= 1) {
+ if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE)
+ sm->rsn_override = true;
+ else if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE_2)
+ sm->rsn_override_2 = true;
+ }
+ sm->rsn_selection = os_memdup(ie, len);
+ if (sm->rsn_selection)
+ sm->rsn_selection_len = len;
+ }
}
bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
u8 *fd_rsn_info);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
-void wpa_auth_set_rsn_override(struct wpa_state_machine *sm, bool val);
-void wpa_auth_set_rsn_override_2(struct wpa_state_machine *sm, bool val);
+void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
+ size_t len);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val);
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
size_t wpa_ie_len;
u8 *rsnxe;
size_t rsnxe_len;
+ u8 *rsn_selection;
+ size_t rsn_selection_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
return WPA_INVALID_GROUP;
}
- key_mgmt = data.key_mgmt & (wpa_auth->conf.wpa_key_mgmt |
- wpa_auth->conf.rsn_override_key_mgmt |
- wpa_auth->conf.rsn_override_key_mgmt_2);
+ if (sm->rsn_override_2)
+ key_mgmt = data.key_mgmt &
+ wpa_auth->conf.rsn_override_key_mgmt_2;
+ else if (sm->rsn_override)
+ key_mgmt = data.key_mgmt & wpa_auth->conf.rsn_override_key_mgmt;
+ else
+ key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
if (!key_mgmt) {
wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
MACSTR, data.key_mgmt, MAC2STR(sm->addr));
else
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- if (version == WPA_PROTO_RSN)
+ if (version == WPA_PROTO_RSN && sm->rsn_override_2)
+ ciphers = data.pairwise_cipher &
+ wpa_auth->conf.rsn_override_pairwise_2;
+ else if (version == WPA_PROTO_RSN && sm->rsn_override)
ciphers = data.pairwise_cipher &
- (wpa_auth->conf.rsn_pairwise |
- wpa_auth->conf.rsn_override_pairwise |
- wpa_auth->conf.rsn_override_pairwise_2);
+ wpa_auth->conf.rsn_override_pairwise;
+ else if (version == WPA_PROTO_RSN)
+ ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
else
ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
if (!ciphers) {
elems->rsne_override_2 = pos;
elems->rsne_override_2_len = elen;
break;
+ case WFA_RSN_SELECTION_OUI_TYPE:
+ if (elen < 4 + 1) {
+ wpa_printf(MSG_DEBUG,
+ "Too short RSN Selection element ignored");
+ return -1;
+ }
+ elems->rsn_selection = pos + 4;
+ elems->rsn_selection_len = elen - 4;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
const u8 *mbssid;
const u8 *rsne_override;
const u8 *rsne_override_2;
+ const u8 *rsn_selection;
u8 ssid_len;
u8 supp_rates_len;
u8 mbssid_len;
size_t rsne_override_len;
size_t rsne_override_2_len;
+ size_t rsn_selection_len;
struct mb_ies_info mb_ies;
#define WFA_RSNE_OVERRIDE_OUI_TYPE 0x29
#define WFA_RSNE_OVERRIDE_2_OUI_TYPE 0x2a
#define WFA_RSNXE_OVERRIDE_OUI_TYPE 0x2b
+#define WFA_RSN_SELECTION_OUI_TYPE 0x2c
#define RSNE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a29
#define RSNE_OVERRIDE_2_IE_VENDOR_TYPE 0x506f9a2a
#define RSNXE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a2b
+#define RSN_SELECTION_IE_VENDOR_TYPE 0x506f9a2c
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_PROFILE_SUB_ELEM_TYPE 0x07
return 0;
}
+ if (selector == RSN_SELECTION_IE_VENDOR_TYPE) {
+ ie->rsn_selection = p;
+ ie->rsn_selection_len = left;
+ return 0;
+ }
+
return 2;
}
#define WPA_PASN_PUBKEY_COMPRESSED_1 0x03
#define WPA_PASN_PUBKEY_UNCOMPRESSED 0x04
+/* WPA3 specification - RSN Selection element */
+enum rsn_selection_variant {
+ RSN_SELECTION_RSNE = 0,
+ RSN_SELECTION_RSNE_OVERRIDE = 1,
+ RSN_SELECTION_RSNE_OVERRIDE_2 = 2,
+};
+
+
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int key_mgmt, bool reassoc_resp);
void wpa_ft_parse_ies_free(struct wpa_ft_ies *parse);
u16 aid;
const u8 *wmm;
size_t wmm_len;
+ const u8 *rsn_selection;
+ size_t rsn_selection_len;
u16 valid_mlo_gtks; /* bitmap of valid link GTK KDEs */
const u8 *mlo_gtk[MAX_NUM_MLD_LINKS];
size_t mlo_gtk_len[MAX_NUM_MLD_LINKS];
size_t mic_len, hdrlen, rlen, extra_len = 0;
struct wpa_eapol_key *reply;
u8 *rbuf, *key_mic;
- u8 *rsn_ie_buf = NULL;
+ u8 *rsn_ie_buf = NULL, *buf2 = NULL;
u16 key_info;
#ifdef CONFIG_TESTING_OPTIONS
size_t pad_len = 0;
}
#endif /* CONFIG_IEEE80211R */
+ if (sm->rsn_override != RSN_OVERRIDE_NOT_USED) {
+ u8 *pos;
+
+ buf2 = os_malloc(wpa_ie_len + 2 + 4 + 1);
+ if (!buf2) {
+ os_free(rsn_ie_buf);
+ return -1;
+ }
+ os_memcpy(buf2, wpa_ie, wpa_ie_len);
+ pos = buf2 + wpa_ie_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 1;
+ WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+ pos += 4;
+ if (sm->rsn_override == RSN_OVERRIDE_RSNE) {
+ *pos++ = RSN_SELECTION_RSNE;
+ } else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE) {
+ *pos++ = RSN_SELECTION_RSNE_OVERRIDE;
+ } else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE_2) {
+ *pos++ = RSN_SELECTION_RSNE_OVERRIDE_2;
+ } else {
+ os_free(rsn_ie_buf);
+ os_free(buf2);
+ return -1;
+ }
+
+ wpa_ie = buf2;
+ wpa_ie_len += 2 + 4 + 1;
+
+ }
+
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
#ifdef CONFIG_TESTING_OPTIONS
&rlen, (void *) &reply);
if (rbuf == NULL) {
os_free(rsn_ie_buf);
+ os_free(buf2);
return -1;
}
WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len + extra_len);
os_memcpy(key_mic + mic_len + 2, wpa_ie, wpa_ie_len); /* Key Data */
os_free(rsn_ie_buf);
+ os_free(buf2);
#ifdef CONFIG_TESTING_OPTIONS
if (sm->test_eapol_m2_elems) {
os_memcpy(key_mic + mic_len + 2 + wpa_ie_len,
case WPA_PARAM_SSID_PROTECTION:
sm->ssid_protection = value;
break;
+ case WPA_PARAM_RSN_OVERRIDE:
+ sm->rsn_override = value;
+ break;
default:
break;
}
WPA_PARAM_ENCRYPT_EAPOL_M4,
WPA_PARAM_FT_PREPEND_PMKID,
WPA_PARAM_SSID_PROTECTION,
+ WPA_PARAM_RSN_OVERRIDE,
+};
+
+enum wpa_rsn_override {
+ RSN_OVERRIDE_NOT_USED,
+ RSN_OVERRIDE_RSNE,
+ RSN_OVERRIDE_RSNE_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE_2,
};
struct rsn_supp_config {
bool wmm_enabled;
bool driver_bss_selection;
bool ft_prepend_pmkid;
+
+ enum wpa_rsn_override rsn_override;
};
union wpa_event_data *data)
{
int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
- const u8 *p;
+ const u8 *p, *ie;
u8 bssid[ETH_ALEN];
bool bssid_known;
+ enum wpa_rsn_override rsn_override;
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
wpa_s->ssid_verified = false;
if (!found_x && data->assoc_info.req_ies)
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ rsn_override = RSN_OVERRIDE_NOT_USED;
+ ie = get_vendor_ie(data->assoc_info.req_ies,
+ data->assoc_info.req_ies_len,
+ RSN_SELECTION_IE_VENDOR_TYPE);
+ if (ie && ie[1] >= 4 + 1) {
+ switch (ie[2 + 4]) {
+ case RSN_SELECTION_RSNE:
+ rsn_override = RSN_OVERRIDE_RSNE;
+ break;
+ case RSN_SELECTION_RSNE_OVERRIDE:
+ rsn_override = RSN_OVERRIDE_RSNE_OVERRIDE;
+ break;
+ case RSN_SELECTION_RSNE_OVERRIDE_2:
+ rsn_override = RSN_OVERRIDE_RSNE_OVERRIDE_2;
+ break;
+ }
+ }
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE, rsn_override);
+
#ifdef CONFIG_FILS
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
}
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_NOT_USED);
if (wpas_rsn_overriding(wpa_s) &&
wpas_ap_supports_rsn_overriding(wpa_s, wpa_s->current_bss) &&
wpa_s->sme.assoc_req_ie_len + 2 + 4 <=
sizeof(wpa_s->sme.assoc_req_ie)) {
u8 *pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
- u32 type = 0;
const u8 *ie;
+ enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE);
ie = wpa_bss_get_rsne(wpa_s, wpa_s->current_bss, ssid,
wpa_s->valid_links);
- if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4)
- type = WPA_GET_BE32(&ie[2]);
+ if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
+ u32 type;
- if (type) {
- /* Indicate support for RSN overriding */
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 4;
- WPA_PUT_BE32(pos, type);
- wpa_s->sme.assoc_req_ie_len += 2 + 4;
+ type = WPA_GET_BE32(&ie[2]);
+ if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
+ variant = RSN_SELECTION_RSNE_OVERRIDE;
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE);
+ } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
+ variant = RSN_SELECTION_RSNE_OVERRIDE_2;
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE_2);
+ }
}
+
+ /* Indicate which RSNE variant was used */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 1;
+ WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+ pos += 4;
+ *pos = variant;
+ wpa_s->sme.assoc_req_ie_len += 2 + 4 + 1;
}
params.bssid = bssid;
wpa_ie_len += multi_ap_ie_len;
}
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_NOT_USED);
if (!wpas_driver_bss_selection(wpa_s) &&
wpas_rsn_overriding(wpa_s) &&
wpas_ap_supports_rsn_overriding(wpa_s, bss) &&
- wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
- u8 *pos = wpa_ie + wpa_ie_len;
- u32 type = 0;
+ wpa_ie_len + 2 + 4 + 1 <= max_wpa_ie_len) {
+ u8 *pos = wpa_ie + wpa_ie_len, *start = pos;
const u8 *ie;
+ enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE);
ie = wpa_bss_get_rsne(wpa_s, bss, ssid, wpa_s->valid_links);
- if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4)
- type = WPA_GET_BE32(&ie[2]);
+ if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
+ u32 type;
- if (type) {
- /* Indicate support for RSN overriding */
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 4;
- WPA_PUT_BE32(pos, type);
- pos += 4;
- wpa_hexdump(MSG_MSGDUMP, "RSNE Override", wpa_ie,
- pos - wpa_ie);
- wpa_ie_len += 2 + 4;
+ type = WPA_GET_BE32(&ie[2]);
+ if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
+ variant = RSN_SELECTION_RSNE_OVERRIDE;
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE);
+ } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
+ variant = RSN_SELECTION_RSNE_OVERRIDE_2;
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE_2);
+ }
}
+
+ /* Indicate which RSNE variant was used */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 1;
+ WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+ pos += 4;
+ *pos++ = variant;
+ wpa_hexdump(MSG_MSGDUMP, "RSN Selection", start, pos - start);
+ wpa_ie_len += pos - start;
}
if (wpas_driver_bss_selection(wpa_s) &&
wpas_rsn_overriding(wpa_s)) {
+ /* TODO: Replace this indication of support for RSN overriding
+ * to the driver in driver-based BSS selection cases with
+ * something cleaner. */
if (wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
u8 *pos = wpa_ie + wpa_ie_len;