FILS: Authentication frame processing (STA)
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
c4fd6d8aa8
commit
a660993772
4 changed files with 159 additions and 0 deletions
|
@ -16,6 +16,7 @@
|
||||||
#include "crypto/random.h"
|
#include "crypto/random.h"
|
||||||
#include "crypto/aes_siv.h"
|
#include "crypto/aes_siv.h"
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
|
#include "common/ieee802_11_common.h"
|
||||||
#include "eapol_supp/eapol_supp_sm.h"
|
#include "eapol_supp/eapol_supp_sm.h"
|
||||||
#include "wpa.h"
|
#include "wpa.h"
|
||||||
#include "eloop.h"
|
#include "eloop.h"
|
||||||
|
@ -3286,4 +3287,139 @@ fail:
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len)
|
||||||
|
{
|
||||||
|
const u8 *pos, *end;
|
||||||
|
struct ieee802_11_elems elems;
|
||||||
|
struct wpa_ie_data rsn;
|
||||||
|
int pmkid_match = 0;
|
||||||
|
u8 ick[FILS_ICK_MAX_LEN];
|
||||||
|
size_t ick_len;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
|
||||||
|
data, len);
|
||||||
|
pos = data;
|
||||||
|
end = data + len;
|
||||||
|
|
||||||
|
/* TODO: Finite Cyclic Group when using PK or PFS */
|
||||||
|
/* TODO: Element when using PK or PFS */
|
||||||
|
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
|
||||||
|
if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSNE */
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: RSN element", elems.rsn_ie,
|
||||||
|
elems.rsn_ie_len);
|
||||||
|
if (!elems.rsn_ie ||
|
||||||
|
wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
|
||||||
|
&rsn) < 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: No RSN element");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elems.fils_nonce) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
os_memcpy(sm->fils_anonce, elems.fils_nonce, FILS_NONCE_LEN);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: ANonce", sm->fils_anonce, FILS_NONCE_LEN);
|
||||||
|
|
||||||
|
/* TODO: MDE when using FILS+FT */
|
||||||
|
/* TODO: FTE when using FILS+FT */
|
||||||
|
|
||||||
|
/* PMKID List */
|
||||||
|
if (rsn.pmkid && rsn.num_pmkid > 0) {
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
|
||||||
|
rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
|
||||||
|
|
||||||
|
if (rsn.num_pmkid != 1) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: Invalid PMKID selection");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: PMKID", rsn.pmkid, PMKID_LEN);
|
||||||
|
if (os_memcmp(sm->cur_pmksa->pmkid, rsn.pmkid, PMKID_LEN) != 0)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: PMKID mismatch");
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: Expected PMKID",
|
||||||
|
sm->cur_pmksa->pmkid, PMKID_LEN);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"FILS: Matching PMKID - continue using PMKSA caching");
|
||||||
|
pmkid_match = 1;
|
||||||
|
}
|
||||||
|
if (!pmkid_match && sm->cur_pmksa) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"FILS: No PMKID match - cannot use cached PMKSA entry");
|
||||||
|
sm->cur_pmksa = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FILS Session */
|
||||||
|
if (!elems.fils_session) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
|
||||||
|
FILS_SESSION_LEN);
|
||||||
|
if (os_memcmp(sm->fils_session, elems.fils_session, FILS_SESSION_LEN)
|
||||||
|
!= 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
|
||||||
|
sm->fils_session, FILS_SESSION_LEN);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FILS Wrapped Data */
|
||||||
|
if (!sm->cur_pmksa && elems.fils_wrapped_data) {
|
||||||
|
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);
|
||||||
|
if (eapol_sm_failed(sm->eapol))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
|
||||||
|
if (res)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: ERP processing succeeded - add PMKSA cache entry for the result");
|
||||||
|
sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, PMK_LEN,
|
||||||
|
NULL, NULL, 0, sm->bssid,
|
||||||
|
sm->own_addr,
|
||||||
|
sm->network_ctx, sm->key_mgmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sm->cur_pmksa) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"FILS: No remaining options to continue FILS authentication");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, sm->bssid,
|
||||||
|
sm->fils_nonce, sm->fils_anonce, &sm->ptk,
|
||||||
|
ick, &ick_len, sm->key_mgmt, sm->pairwise_cipher) <
|
||||||
|
0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PTK");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sm->ptk_set = 1;
|
||||||
|
sm->tptk_set = 0;
|
||||||
|
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
|
||||||
|
|
||||||
|
res = fils_key_auth_sk(ick, ick_len, sm->fils_nonce,
|
||||||
|
sm->fils_anonce, sm->own_addr, sm->bssid,
|
||||||
|
NULL, 0, NULL, 0, /* TODO: SK+PFS */
|
||||||
|
sm->key_mgmt, sm->fils_key_auth_sta,
|
||||||
|
sm->fils_key_auth_ap,
|
||||||
|
&sm->fils_key_auth_len);
|
||||||
|
os_memset(ick, 0, sizeof(ick));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_FILS */
|
#endif /* CONFIG_FILS */
|
||||||
|
|
|
@ -427,5 +427,6 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
|
||||||
void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf);
|
void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf);
|
||||||
|
|
||||||
struct wpabuf * fils_build_auth(struct wpa_sm *sm);
|
struct wpabuf * fils_build_auth(struct wpa_sm *sm);
|
||||||
|
int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len);
|
||||||
|
|
||||||
#endif /* WPA_H */
|
#endif /* WPA_H */
|
||||||
|
|
|
@ -142,6 +142,10 @@ struct wpa_sm {
|
||||||
#ifdef CONFIG_FILS
|
#ifdef CONFIG_FILS
|
||||||
u8 fils_nonce[FILS_NONCE_LEN];
|
u8 fils_nonce[FILS_NONCE_LEN];
|
||||||
u8 fils_session[FILS_SESSION_LEN];
|
u8 fils_session[FILS_SESSION_LEN];
|
||||||
|
u8 fils_anonce[FILS_NONCE_LEN];
|
||||||
|
u8 fils_key_auth_ap[FILS_MAX_KEY_AUTH_LEN];
|
||||||
|
u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
|
||||||
|
size_t fils_key_auth_len;
|
||||||
#endif /* CONFIG_FILS */
|
#endif /* CONFIG_FILS */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -958,6 +958,24 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
|
|
||||||
|
#ifdef CONFIG_FILS
|
||||||
|
if (data->auth.auth_type == WLAN_AUTH_FILS_SK) {
|
||||||
|
if (fils_process_auth(wpa_s->wpa, data->auth.ies,
|
||||||
|
data->auth.ies_len) < 0) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
|
"SME: FILS Authentication response processing failed");
|
||||||
|
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
|
||||||
|
MACSTR
|
||||||
|
" reason=%d locally_generated=1",
|
||||||
|
MAC2STR(wpa_s->pending_bssid),
|
||||||
|
WLAN_REASON_DEAUTH_LEAVING);
|
||||||
|
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
|
||||||
|
wpa_supplicant_mark_disassoc(wpa_s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_FILS */
|
||||||
|
|
||||||
sme_associate(wpa_s, ssid->mode, data->auth.peer,
|
sme_associate(wpa_s, ssid->mode, data->auth.peer,
|
||||||
data->auth.auth_type);
|
data->auth.auth_type);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue