]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FILS: Authentication frame processing (STA)
authorJouni Malinen <jouni@qca.qualcomm.com>
Mon, 7 Sep 2015 21:14:13 +0000 (00:14 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 22 Oct 2016 20:28:36 +0000 (23:28 +0300)
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
wpa_supplicant/sme.c

index a0e37485b5ebac455cd2c8e7e77ee501e44476f0..9201a1035f5876a60a9c72146299ba3b2a5373e9 100644 (file)
@@ -16,6 +16,7 @@
 #include "crypto/random.h"
 #include "crypto/aes_siv.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "wpa.h"
 #include "eloop.h"
@@ -3286,4 +3287,139 @@ fail:
        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 */
index 4b4b97378e52b28dcf3e19169aae488c6d595234..2f99b6ee152298417123fea22d0027b7386605bb 100644 (file)
@@ -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);
 
 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 */
index 5a3effc0c4cef1df788122fb5e1335e9678cf73c..45000687a97a730920150c9fa9bdc83602b53248 100644 (file)
@@ -142,6 +142,10 @@ struct wpa_sm {
 #ifdef CONFIG_FILS
        u8 fils_nonce[FILS_NONCE_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 */
 };
 
index bcb6a46f46835aeee050e48c369f0769f93a99ec..4e004e979e25c073a099e19ee7a71bf77d10a565 100644 (file)
@@ -958,6 +958,24 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
        }
 #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,
                      data->auth.auth_type);
 }