SAE: Add RSNXE in Association Request and EAPOL-Key msg 2/4
Add the new RSNXE into (Re)Association Request frames and EAPOL-Key msg 2/4 when using SAE with hash-to-element mechanism enabled. This allows the AP to verify that there was no downgrade attack when both PWE derivation mechanisms are enabled. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
8401cdc8d4
commit
6d6c887751
9 changed files with 187 additions and 33 deletions
|
@ -655,51 +655,51 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
|
|||
|
||||
kde = sm->assoc_wpa_ie;
|
||||
kde_len = sm->assoc_wpa_ie_len;
|
||||
kde_buf = os_malloc(kde_len +
|
||||
2 + RSN_SELECTOR_LEN + 3 +
|
||||
sm->assoc_rsnxe_len +
|
||||
2 + RSN_SELECTOR_LEN + 1);
|
||||
if (!kde_buf)
|
||||
goto failed;
|
||||
os_memcpy(kde_buf, kde, kde_len);
|
||||
kde = kde_buf;
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_sm_ocv_enabled(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
u8 *pos;
|
||||
|
||||
pos = kde + kde_len;
|
||||
if (wpa_sm_channel_info(sm, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
|
||||
if (!kde_buf) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
os_memcpy(kde_buf, kde, kde_len);
|
||||
kde = kde_buf;
|
||||
pos = kde + kde_len;
|
||||
if (ocv_insert_oci_kde(&ci, &pos) < 0)
|
||||
goto failed;
|
||||
kde_len = pos - kde;
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
if (sm->assoc_rsnxe && sm->assoc_rsnxe_len) {
|
||||
os_memcpy(kde + kde_len, sm->assoc_rsnxe, sm->assoc_rsnxe_len);
|
||||
kde_len += sm->assoc_rsnxe_len;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (sm->p2p) {
|
||||
kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
|
||||
if (kde_buf) {
|
||||
u8 *pos;
|
||||
wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
|
||||
"into EAPOL-Key 2/4");
|
||||
os_memcpy(kde_buf, kde, kde_len);
|
||||
kde = kde_buf;
|
||||
pos = kde + kde_len;
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = RSN_SELECTOR_LEN + 1;
|
||||
RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
*pos++ = 0x01;
|
||||
kde_len = pos - kde;
|
||||
}
|
||||
u8 *pos;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"P2P: Add IP Address Request KDE into EAPOL-Key 2/4");
|
||||
pos = kde + kde_len;
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = RSN_SELECTOR_LEN + 1;
|
||||
RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
*pos++ = 0x01;
|
||||
kde_len = pos - kde;
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
|
@ -2672,6 +2672,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
|
|||
eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
|
||||
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
|
||||
os_free(sm->assoc_wpa_ie);
|
||||
os_free(sm->assoc_rsnxe);
|
||||
os_free(sm->ap_wpa_ie);
|
||||
os_free(sm->ap_rsn_ie);
|
||||
os_free(sm->ap_rsnxe);
|
||||
|
@ -3049,6 +3050,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
|
|||
case WPA_PARAM_OCV:
|
||||
sm->ocv = value;
|
||||
break;
|
||||
case WPA_PARAM_SAE_PWE:
|
||||
sm->sae_pwe = value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3226,6 +3230,83 @@ int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_sm_set_assoc_rsnxe_default - Generate own RSNXE from configuration
|
||||
* @sm: Pointer to WPA state machine data from wpa_sm_init()
|
||||
* @rsnxe: Pointer to buffer for RSNXE
|
||||
* @rsnxe_len: Pointer to the length of the rsne buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
|
||||
size_t *rsnxe_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!sm)
|
||||
return -1;
|
||||
|
||||
res = wpa_gen_rsnxe(sm, rsnxe, *rsnxe_len);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
*rsnxe_len = res;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "RSN: Set own RSNXE default", rsnxe, *rsnxe_len);
|
||||
|
||||
if (sm->assoc_rsnxe) {
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"RSN: Leave previously set RSNXE default",
|
||||
sm->assoc_rsnxe, sm->assoc_rsnxe_len);
|
||||
} else if (*rsnxe_len > 0) {
|
||||
/*
|
||||
* Make a copy of the RSNXE so that 4-Way Handshake gets the
|
||||
* correct version of the IE even if it gets changed.
|
||||
*/
|
||||
sm->assoc_rsnxe = os_memdup(rsnxe, *rsnxe_len);
|
||||
if (!sm->assoc_rsnxe)
|
||||
return -1;
|
||||
|
||||
sm->assoc_rsnxe_len = *rsnxe_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_sm_set_assoc_rsnxe - Set own RSNXE from (Re)AssocReq
|
||||
* @sm: Pointer to WPA state machine data from wpa_sm_init()
|
||||
* @ie: Pointer to IE data (starting from id)
|
||||
* @len: IE length
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Inform WPA state machine about the RSNXE used in (Re)Association Request
|
||||
* frame. The IE will be used to override the default value generated
|
||||
* with wpa_sm_set_assoc_rsnxe_default().
|
||||
*/
|
||||
int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
|
||||
{
|
||||
if (!sm)
|
||||
return -1;
|
||||
|
||||
os_free(sm->assoc_rsnxe);
|
||||
if (!ie || len == 0) {
|
||||
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
|
||||
"RSN: clearing own RSNXE");
|
||||
sm->assoc_rsnxe = NULL;
|
||||
sm->assoc_rsnxe_len = 0;
|
||||
} else {
|
||||
wpa_hexdump(MSG_DEBUG, "RSN: set own RSNXE", ie, len);
|
||||
sm->assoc_rsnxe = os_memdup(ie, len);
|
||||
if (!sm->assoc_rsnxe)
|
||||
return -1;
|
||||
|
||||
sm->assoc_rsnxe_len = len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
|
||||
* @sm: Pointer to WPA state machine data from wpa_sm_init()
|
||||
|
|
|
@ -98,7 +98,8 @@ enum wpa_sm_conf_params {
|
|||
WPA_PARAM_MGMT_GROUP,
|
||||
WPA_PARAM_RSN_ENABLED,
|
||||
WPA_PARAM_MFP,
|
||||
WPA_PARAM_OCV
|
||||
WPA_PARAM_OCV,
|
||||
WPA_PARAM_SAE_PWE,
|
||||
};
|
||||
|
||||
struct rsn_supp_config {
|
||||
|
@ -134,6 +135,9 @@ void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol);
|
|||
int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
|
||||
int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
|
||||
size_t *wpa_ie_len);
|
||||
int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
|
||||
size_t *rsnxe_len);
|
||||
int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
|
||||
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
|
||||
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
|
||||
int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
|
||||
|
|
|
@ -85,9 +85,12 @@ struct wpa_sm {
|
|||
int rsn_enabled; /* Whether RSN is enabled in configuration */
|
||||
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
|
||||
int ocv; /* Operating Channel Validation */
|
||||
int sae_pwe; /* SAE PWE generation options */
|
||||
|
||||
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
|
||||
size_t assoc_wpa_ie_len;
|
||||
u8 *assoc_rsnxe; /* Own RSNXE from (Re)AssocReq */
|
||||
size_t assoc_rsnxe_len;
|
||||
u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
|
||||
size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
|
||||
|
||||
|
|
|
@ -342,6 +342,28 @@ 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)
|
||||
{
|
||||
u8 *pos = rsnxe;
|
||||
|
||||
if (!wpa_key_mgmt_sae(sm->key_mgmt))
|
||||
return 0; /* SAE not in use */
|
||||
if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
|
||||
return 0; /* no supported extended RSN capabilities */
|
||||
|
||||
if (rsnxe_len < 3)
|
||||
return -1;
|
||||
|
||||
*pos++ = WLAN_EID_RSNX;
|
||||
*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);
|
||||
|
||||
return pos - rsnxe;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_parse_vendor_specific - Parse Vendor Specific IEs
|
||||
* @pos: Pointer to the IE header
|
||||
|
|
|
@ -62,5 +62,6 @@ struct wpa_eapol_ie_parse {
|
|||
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
|
||||
struct wpa_eapol_ie_parse *ie);
|
||||
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);
|
||||
|
||||
#endif /* WPA_IE_H */
|
||||
|
|
|
@ -2411,7 +2411,7 @@ static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
|
|||
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
int l, len, found = 0, wpa_found, rsn_found;
|
||||
int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
|
||||
const u8 *p;
|
||||
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
@ -2483,22 +2483,29 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
|
|||
p, l);
|
||||
break;
|
||||
}
|
||||
if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
|
||||
(os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
|
||||
(p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
|
||||
(os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
|
||||
(p[0] == WLAN_EID_RSN && p[1] >= 2)) {
|
||||
if (!found &&
|
||||
((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
|
||||
(os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
|
||||
(p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
|
||||
(os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
|
||||
(p[0] == WLAN_EID_RSN && p[1] >= 2))) {
|
||||
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
|
||||
break;
|
||||
found = 1;
|
||||
wpa_find_assoc_pmkid(wpa_s);
|
||||
break;
|
||||
}
|
||||
if (!found_x && p[0] == WLAN_EID_RSNX) {
|
||||
if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len))
|
||||
break;
|
||||
found_x = 1;
|
||||
}
|
||||
l -= len;
|
||||
p += len;
|
||||
}
|
||||
if (!found && data->assoc_info.req_ies)
|
||||
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
|
||||
if (!found_x && data->assoc_info.req_ies)
|
||||
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
#ifdef CONFIG_SME
|
||||
|
|
|
@ -591,6 +591,14 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
|||
os_memcpy(pos, ext_capab, ext_capab_len);
|
||||
}
|
||||
|
||||
if (wpa_s->rsnxe_len > 0 &&
|
||||
wpa_s->rsnxe_len <=
|
||||
sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
|
||||
os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
|
||||
wpa_s->rsnxe, wpa_s->rsnxe_len);
|
||||
wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
if (is_hs20_network(wpa_s, ssid, bss)) {
|
||||
struct wpabuf *hs20;
|
||||
|
@ -884,6 +892,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
|
|||
/* Starting new connection, so clear the possibly used WPA IE from the
|
||||
* previous association. */
|
||||
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
|
||||
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
|
||||
wpa_s->rsnxe_len = 0;
|
||||
|
||||
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
|
||||
}
|
||||
|
@ -1899,6 +1909,11 @@ pfs_fail:
|
|||
elems.osen_len + 2);
|
||||
} else
|
||||
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
|
||||
if (elems.rsnxe)
|
||||
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2,
|
||||
elems.rsnxe_len + 2);
|
||||
else
|
||||
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
|
||||
if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
|
||||
params.p2p = 1;
|
||||
|
||||
|
|
|
@ -404,6 +404,8 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
|
|||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
|
||||
wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
|
||||
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
|
||||
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
|
||||
wpa_s->rsnxe_len = 0;
|
||||
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
|
||||
wpa_s->group_cipher = WPA_CIPHER_NONE;
|
||||
wpa_s->mgmt_group_cipher = 0;
|
||||
|
@ -1578,12 +1580,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
|
|||
#ifdef CONFIG_OCV
|
||||
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
|
||||
#endif /* CONFIG_OCV */
|
||||
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, wpa_s->conf->sae_pwe);
|
||||
|
||||
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
|
||||
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
|
||||
if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
|
||||
&wpa_s->rsnxe_len)) {
|
||||
wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
#ifdef CONFIG_DPP
|
||||
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
|
||||
|
@ -2995,6 +3005,12 @@ pfs_fail:
|
|||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
if (wpa_s->rsnxe_len > 0 &&
|
||||
wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
|
||||
os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
|
||||
wpa_ie_len += wpa_s->rsnxe_len;
|
||||
}
|
||||
|
||||
if (ssid->multi_ap_backhaul_sta) {
|
||||
size_t multi_ap_ie_len;
|
||||
|
||||
|
@ -3305,6 +3321,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
|
|||
/* Starting new association, so clear the possibly used WPA IE from the
|
||||
* previous association. */
|
||||
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
|
||||
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
|
||||
wpa_s->rsnxe_len = 0;
|
||||
|
||||
wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, ¶ms, NULL);
|
||||
if (!wpa_ie) {
|
||||
|
|
|
@ -614,6 +614,9 @@ struct wpa_supplicant {
|
|||
int eapol_received; /* number of EAPOL packets received after the
|
||||
* previous association event */
|
||||
|
||||
u8 rsnxe[20];
|
||||
size_t rsnxe_len;
|
||||
|
||||
struct scard_data *scard;
|
||||
char imsi[20];
|
||||
int mnc_len;
|
||||
|
|
Loading…
Reference in a new issue