#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(sm->test_assoc_ie);
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_FILS
+ crypto_ecdh_deinit(sm->fils_ecdh);
+#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
crypto_ecdh_deinit(sm->owe_ecdh);
#endif /* CONFIG_OWE */
#ifdef CONFIG_FILS
-struct wpabuf * fils_build_auth(struct wpa_sm *sm)
+struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group)
{
struct wpabuf *buf = NULL;
struct wpabuf *erp_msg;
+ struct wpabuf *pub = NULL;
erp_msg = eapol_sm_build_erp_reauth_start(sm->eapol);
if (!erp_msg && !sm->cur_pmksa) {
wpa_hexdump(MSG_DEBUG, "FILS: Generated FILS Session",
sm->fils_session, FILS_SESSION_LEN);
- buf = wpabuf_alloc(1000 + sm->assoc_wpa_ie_len);
+#ifdef CONFIG_FILS_SK_PFS
+ sm->fils_dh_group = dh_group;
+ if (dh_group) {
+ crypto_ecdh_deinit(sm->fils_ecdh);
+ sm->fils_ecdh = crypto_ecdh_init(dh_group);
+ if (!sm->fils_ecdh) {
+ wpa_printf(MSG_INFO,
+ "FILS: Could not initialize ECDH with group %d",
+ dh_group);
+ goto fail;
+ }
+ pub = crypto_ecdh_get_pubkey(sm->fils_ecdh, 1);
+ if (!pub)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "FILS: Element (DH public key)",
+ pub);
+ sm->fils_dh_elem_len = wpabuf_len(pub);
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ buf = wpabuf_alloc(1000 + sm->assoc_wpa_ie_len +
+ (pub ? wpabuf_len(pub) : 0));
if (!buf)
goto fail;
/* Status Code */
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
- /* TODO: Finite Cyclic Group when using PK or PFS */
- /* TODO: Element when using PK or PFS */
+ /* TODO: FILS PK */
+#ifdef CONFIG_FILS_SK_PFS
+ if (dh_group) {
+ /* Finite Cyclic Group */
+ wpabuf_put_le16(buf, dh_group);
+ /* Element */
+ wpabuf_put_buf(buf, pub);
+ }
+#endif /* CONFIG_FILS_SK_PFS */
/* RSNE */
wpa_hexdump(MSG_DEBUG, "FILS: RSNE in FILS Authentication frame",
fail:
wpabuf_free(erp_msg);
+ wpabuf_free(pub);
return buf;
}
u8 ick[FILS_ICK_MAX_LEN];
size_t ick_len;
int res;
+ struct wpabuf *dh_ss = NULL;
os_memcpy(sm->bssid, bssid, ETH_ALEN);
pos = data;
end = data + len;
- /* TODO: Finite Cyclic Group when using PK or PFS */
- /* TODO: Element when using PK or PFS */
+ /* TODO: FILS PK */
+#ifdef CONFIG_FILS_SK_PFS
+ if (sm->fils_dh_group) {
+ u16 group;
+
+ /* Using FILS PFS */
+
+ /* Finite Cyclic Group */
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No room for Finite Cyclic Group");
+ goto fail;
+ }
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ if (group != sm->fils_dh_group) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unexpected change in Finite Cyclic Group: %u (expected %u)",
+ group, sm->fils_dh_group);
+ goto fail;
+ }
+
+ /* Element */
+ if ((size_t) (end - pos) < sm->fils_dh_elem_len) {
+ wpa_printf(MSG_DEBUG, "FILS: No room for Element");
+ goto fail;
+ }
+
+ if (!sm->fils_ecdh) {
+ wpa_printf(MSG_DEBUG, "FILS: No ECDH state available");
+ goto fail;
+ }
+ dh_ss = crypto_ecdh_set_peerkey(sm->fils_ecdh, 1, pos,
+ sm->fils_dh_elem_len);
+ if (!dh_ss) {
+ wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
+ goto fail;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", dh_ss);
+ pos += sm->fils_dh_elem_len;
+ }
+#endif /* CONFIG_FILS_SK_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;
+ goto fail;
}
/* RSNE */
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;
+ goto fail;
}
if (!elems.fils_nonce) {
wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
- return -1;
+ goto fail;
}
os_memcpy(sm->fils_anonce, elems.fils_nonce, FILS_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FILS: ANonce", sm->fils_anonce, FILS_NONCE_LEN);
if (rsn.num_pmkid != 1) {
wpa_printf(MSG_DEBUG, "FILS: Invalid PMKID selection");
- return -1;
+ goto fail;
}
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;
+ goto fail;
}
wpa_printf(MSG_DEBUG,
"FILS: Matching PMKID - continue using PMKSA caching");
/* FILS Session */
if (!elems.fils_session) {
wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
- return -1;
+ goto fail;
}
wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
FILS_SESSION_LEN);
wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
sm->fils_session, FILS_SESSION_LEN);
- return -1;
+ goto fail;
}
/* FILS Wrapped Data */
eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data,
elems.fils_wrapped_data_len);
if (eapol_sm_failed(sm->eapol))
- return -1;
+ goto fail;
rmsk_len = ERP_MAX_KEY_LEN;
res = eapol_sm_get_key(sm->eapol, rmsk, rmsk_len);
res = eapol_sm_get_key(sm->eapol, rmsk, rmsk_len);
}
if (res)
- return -1;
+ goto fail;
res = fils_rmsk_to_pmk(sm->key_mgmt, rmsk, rmsk_len,
- sm->fils_nonce, sm->fils_anonce, NULL, 0,
+ sm->fils_nonce, sm->fils_anonce,
+ dh_ss ? wpabuf_head(dh_ss) : NULL,
+ dh_ss ? wpabuf_len(dh_ss) : 0,
sm->pmk, &sm->pmk_len);
os_memset(rmsk, 0, sizeof(rmsk));
+ wpabuf_clear_free(dh_ss);
+ dh_ss = NULL;
if (res)
- return -1;
+ goto fail;
if (!sm->fils_erp_pmkid_set) {
wpa_printf(MSG_DEBUG, "FILS: PMKID not available");
- return -1;
+ goto fail;
}
wpa_hexdump(MSG_DEBUG, "FILS: PMKID", sm->fils_erp_pmkid,
PMKID_LEN);
if (!sm->cur_pmksa) {
wpa_printf(MSG_DEBUG,
"FILS: No remaining options to continue FILS authentication");
- return -1;
+ goto fail;
}
if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, sm->bssid,
ick, &ick_len, sm->key_mgmt, sm->pairwise_cipher) <
0) {
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PTK");
- return -1;
+ goto fail;
}
sm->ptk_set = 1;
sm->tptk_set = 0;
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 */
+ NULL, 0, NULL, 0, /* TODO: PK */
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;
+fail:
+ wpabuf_clear_free(dh_ss);
+ return -1;
}
0)
wpa_printf(MSG_DEBUG,
"SME: Try to use FILS with PMKSA caching");
- resp = fils_build_auth(wpa_s->wpa);
+ resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group);
if (resp) {
- params.auth_alg = WPA_AUTH_ALG_FILS;
+ int auth_alg;
+
+ if (ssid->fils_dh_group)
+ wpa_printf(MSG_DEBUG,
+ "SME: Try to use FILS SK authentication with PFS (DH Group %u)",
+ ssid->fils_dh_group);
+ else
+ wpa_printf(MSG_DEBUG,
+ "SME: Try to use FILS SK authentication without PFS");
+ auth_alg = ssid->fils_dh_group ?
+ WPA_AUTH_ALG_FILS_SK_PFS : WPA_AUTH_ALG_FILS;
+ params.auth_alg = auth_alg;
params.auth_data = wpabuf_head(resp);
params.auth_data_len = wpabuf_len(resp);
- wpa_s->sme.auth_alg = WPA_AUTH_ALG_FILS;
+ wpa_s->sme.auth_alg = auth_alg;
}
}
#endif /* CONFIG_FILS */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_FILS
- if (data->auth.auth_type == WLAN_AUTH_FILS_SK) {
+ if (data->auth.auth_type == WLAN_AUTH_FILS_SK ||
+ data->auth.auth_type == WLAN_AUTH_FILS_SK_PFS) {
+ u16 expect_auth_type;
+
+ expect_auth_type = wpa_s->sme.auth_alg ==
+ WPA_AUTH_ALG_FILS_SK_PFS ? WLAN_AUTH_FILS_SK_PFS :
+ WLAN_AUTH_FILS_SK;
+ if (data->auth.auth_type != expect_auth_type) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: FILS Authentication response used different auth alg (%u; expected %u)",
+ data->auth.auth_type, expect_auth_type);
+ 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;
+ }
+
if (fils_process_auth(wpa_s->wpa, wpa_s->pending_bssid,
data->auth.ies, data->auth.ies_len) < 0) {
wpa_dbg(wpa_s, MSG_DEBUG,
os_memset(¶ms, 0, sizeof(params));
#ifdef CONFIG_FILS
- if (auth_type == WLAN_AUTH_FILS_SK) {
+ if (auth_type == WLAN_AUTH_FILS_SK ||
+ auth_type == WLAN_AUTH_FILS_SK_PFS) {
struct wpabuf *buf;
const u8 *snonce, *anonce;
const unsigned int max_hlp = 20;