]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FILS: Use FILS Cache Identifier to extend PMKSA applicability
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 21 Feb 2017 10:22:19 +0000 (12:22 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 26 Feb 2017 10:05:40 +0000 (12:05 +0200)
This allows PMKSA cache entries for FILS-enabled BSSs to be shared
within an ESS when the BSSs advertise the same FILS Cache Identifier
value.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
13 files changed:
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/preauth.c
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/events.c
wpa_supplicant/preauth_test.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpas_glue.c

index f723bb0a3a58b731db633137299df6aff8068175..d7d5bf7dc69c0af22a948dc032c12b751186751d 100644 (file)
@@ -117,6 +117,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
  * @spa: Supplicant address
  * @network_ctx: Network configuration context for this PMK
  * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * @cache_id: Pointer to FILS Cache Identifier or %NULL if not advertised
  * Returns: Pointer to the added PMKSA cache entry or %NULL on error
  *
  * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
@@ -127,7 +128,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                const u8 *pmkid, const u8 *kck, size_t kck_len,
-               const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+               const u8 *aa, const u8 *spa, void *network_ctx, int akmp,
+               const u8 *cache_id)
 {
        struct rsn_pmksa_cache_entry *entry;
        struct os_reltime now;
@@ -157,6 +159,10 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
        entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
                pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
        entry->akmp = akmp;
+       if (cache_id) {
+               entry->fils_cache_id_set = 1;
+               os_memcpy(entry->fils_cache_id, cache_id, FILS_CACHE_ID_LEN);
+       }
        os_memcpy(entry->aa, aa, ETH_ALEN);
        entry->network_ctx = network_ctx;
 
@@ -362,7 +368,9 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
        new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
                                    NULL, NULL, 0,
                                    aa, pmksa->sm->own_addr,
-                                   old_entry->network_ctx, old_entry->akmp);
+                                   old_entry->network_ctx, old_entry->akmp,
+                                   old_entry->fils_cache_id_set ?
+                                   old_entry->fils_cache_id : NULL);
        if (new_entry == NULL)
                return NULL;
 
@@ -410,6 +418,24 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
 }
 
 
+static struct rsn_pmksa_cache_entry *
+pmksa_cache_get_fils_cache_id(struct rsn_pmksa_cache *pmksa,
+                             const void *network_ctx, const u8 *cache_id)
+{
+       struct rsn_pmksa_cache_entry *entry;
+
+       for (entry = pmksa->pmksa; entry; entry = entry->next) {
+               if (network_ctx == entry->network_ctx &&
+                   entry->fils_cache_id_set &&
+                   os_memcmp(cache_id, entry->fils_cache_id,
+                             FILS_CACHE_ID_LEN) == 0)
+                       return entry;
+       }
+
+       return NULL;
+}
+
+
 /**
  * pmksa_cache_get_current - Get the current used PMKSA entry
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -442,11 +468,12 @@ void pmksa_cache_clear_current(struct wpa_sm *sm)
  * @bssid: BSSID for PMKSA or %NULL if not used
  * @network_ctx: Network configuration context
  * @try_opportunistic: Whether to allow opportunistic PMKSA caching
+ * @fils_cache_id: Pointer to FILS Cache Identifier or %NULL if not used
  * Returns: 0 if PMKSA was found or -1 if no matching entry was found
  */
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
                            const u8 *bssid, void *network_ctx,
-                           int try_opportunistic)
+                           int try_opportunistic, const u8 *fils_cache_id)
 {
        struct rsn_pmksa_cache *pmksa = sm->pmksa;
        wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
@@ -457,6 +484,10 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
        if (bssid)
                wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR,
                           MAC2STR(bssid));
+       if (fils_cache_id)
+               wpa_printf(MSG_DEBUG,
+                          "RSN: Search for FILS Cache Identifier %02x%02x",
+                          fils_cache_id[0], fils_cache_id[1]);
 
        sm->cur_pmksa = NULL;
        if (pmkid)
@@ -469,6 +500,10 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
                sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
                                                              network_ctx,
                                                              bssid);
+       if (sm->cur_pmksa == NULL && fils_cache_id)
+               sm->cur_pmksa = pmksa_cache_get_fils_cache_id(pmksa,
+                                                             network_ctx,
+                                                             fils_cache_id);
        if (sm->cur_pmksa) {
                wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
                            sm->cur_pmksa->pmkid, PMKID_LEN);
@@ -495,11 +530,20 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
        char *pos = buf;
        struct rsn_pmksa_cache_entry *entry;
        struct os_reltime now;
+       int cache_id_used = 0;
+
+       for (entry = pmksa->pmksa; entry; entry = entry->next) {
+               if (entry->fils_cache_id_set) {
+                       cache_id_used = 1;
+                       break;
+               }
+       }
 
        os_get_reltime(&now);
        ret = os_snprintf(pos, buf + len - pos,
                          "Index / AA / PMKID / expiration (in seconds) / "
-                         "opportunistic\n");
+                         "opportunistic%s\n",
+                         cache_id_used ? " / FILS Cache Identifier" : "");
        if (os_snprintf_error(buf + len - pos, ret))
                return pos - buf;
        pos += ret;
@@ -514,12 +558,24 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
                pos += ret;
                pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
                                        PMKID_LEN);
-               ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+               ret = os_snprintf(pos, buf + len - pos, " %d %d",
                                  (int) (entry->expiration - now.sec),
                                  entry->opportunistic);
                if (os_snprintf_error(buf + len - pos, ret))
                        return pos - buf;
                pos += ret;
+               if (entry->fils_cache_id_set) {
+                       ret = os_snprintf(pos, buf + len - pos, " %02x%02x",
+                                         entry->fils_cache_id[0],
+                                         entry->fils_cache_id[1]);
+                       if (os_snprintf_error(buf + len - pos, ret))
+                               return pos - buf;
+                       pos += ret;
+               }
+               ret = os_snprintf(pos, buf + len - pos, "\n");
+               if (os_snprintf_error(buf + len - pos, ret))
+                       return pos - buf;
+               pos += ret;
                entry = entry->next;
        }
        return pos - buf;
index adc251a08d4910f6707becf67b427a38b76f4b58..f9a72a6f63beae09fa616df8ee515e2f9c340d92 100644 (file)
@@ -21,6 +21,14 @@ struct rsn_pmksa_cache_entry {
        int akmp; /* WPA_KEY_MGMT_* */
        u8 aa[ETH_ALEN];
 
+       /*
+        * If FILS Cache Identifier is included (fils_cache_id_set), this PMKSA
+        * cache entry is applicable to all BSSs (any BSSID/aa[]) that
+        * advertise the same FILS Cache Identifier within the same ESS.
+        */
+       u8 fils_cache_id[2];
+       unsigned int fils_cache_id_set:1;
+
        os_time_t reauth_time;
 
        /**
@@ -59,7 +67,8 @@ struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                const u8 *pmkid, const u8 *kck, size_t kck_len,
-               const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
+               const u8 *aa, const u8 *spa, void *network_ctx, int akmp,
+               const u8 *cache_id);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
                      struct rsn_pmksa_cache_entry *entry);
@@ -67,7 +76,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
                            const u8 *bssid, void *network_ctx,
-                           int try_opportunistic);
+                           int try_opportunistic, const u8 *fils_cache_id);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
                              void *network_ctx, const u8 *aa);
@@ -123,7 +132,8 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
 static inline struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                const u8 *pmkid, const u8 *kck, size_t kck_len,
-               const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+               const u8 *aa, const u8 *spa, void *network_ctx, int akmp,
+               const u8 *cache_id)
 {
        return NULL;
 }
@@ -135,7 +145,8 @@ static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
 static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
                                          const u8 *bssid,
                                          void *network_ctx,
-                                         int try_opportunistic)
+                                         int try_opportunistic,
+                                         const u8 *fils_cache_id)
 {
        return -1;
 }
index e83d0735711b0618878422f9690e66103227f429..5f11a5309b51b1bde6d411a9df06c32ee4917f36 100644 (file)
@@ -97,7 +97,7 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol,
                                        NULL, 0,
                                        sm->preauth_bssid, sm->own_addr,
                                        sm->network_ctx,
-                                       WPA_KEY_MGMT_IEEE8021X);
+                                       WPA_KEY_MGMT_IEEE8021X, NULL);
                } else {
                        wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                                "RSN: failed to get master session key from "
index 4210ea7eba033cb69b32c492c2daf5618377a643..00b7ae2075da1e139fa660a5e36afc41461eeea4 100644 (file)
@@ -315,6 +315,13 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                }
                if (res == 0) {
                        struct rsn_pmksa_cache_entry *sa = NULL;
+                       const u8 *fils_cache_id = NULL;
+
+#ifdef CONFIG_FILS
+                       if (sm->fils_cache_id_set)
+                               fils_cache_id = sm->fils_cache_id;
+#endif /* CONFIG_FILS */
+
                        wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
                                        "machines", sm->pmk, pmk_len);
                        sm->pmk_len = pmk_len;
@@ -327,7 +334,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                                                     NULL, 0,
                                                     src_addr, sm->own_addr,
                                                     sm->network_ctx,
-                                                    sm->key_mgmt);
+                                                    sm->key_mgmt,
+                                                    fils_cache_id);
                        }
                        if (!sm->cur_pmksa && pmkid &&
                            pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
@@ -1371,7 +1379,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
                sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL,
                                     sm->ptk.kck, sm->ptk.kck_len,
                                     sm->bssid, sm->own_addr,
-                                    sm->network_ctx, sm->key_mgmt);
+                                    sm->network_ctx, sm->key_mgmt, NULL);
                if (!sm->cur_pmksa)
                        sm->cur_pmksa = sa;
        }
@@ -2573,7 +2581,7 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
        if (bssid) {
                pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0,
                                bssid, sm->own_addr,
-                               sm->network_ctx, sm->key_mgmt);
+                               sm->network_ctx, sm->key_mgmt, NULL);
        }
 }
 
@@ -2656,6 +2664,15 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
                sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
                sm->p2p = config->p2p;
                sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
+#ifdef CONFIG_FILS
+               if (config->fils_cache_id) {
+                       sm->fils_cache_id_set = 1;
+                       os_memcpy(sm->fils_cache_id, config->fils_cache_id,
+                                 FILS_CACHE_ID_LEN);
+               } else {
+                       sm->fils_cache_id_set = 0;
+               }
+#endif /* CONFIG_FILS */
        } else {
                sm->network_ctx = NULL;
                sm->peerkey_enabled = 0;
@@ -3456,7 +3473,8 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
                sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
                                                sm->fils_erp_pmkid, NULL, 0,
                                                sm->bssid, sm->own_addr,
-                                               sm->network_ctx, sm->key_mgmt);
+                                               sm->network_ctx, sm->key_mgmt,
+                                               NULL);
        }
 
        if (!sm->cur_pmksa) {
index 98162c1bfdbcfbea09a31b85557d0214b2d82594..fe0f84a10aff3e4d09a7b8cfa7859f01f6527e56 100644 (file)
@@ -109,6 +109,7 @@ struct rsn_supp_config {
        int wpa_ptk_rekey;
        int p2p;
        int wpa_rsc_relaxation;
+       const u8 *fils_cache_id;
 };
 
 #ifndef CONFIG_NO_WPA
index ab54a18f5d557183e54151c8d7be86e89208f866..7073bfeda45d7ce13a3d43cc9ddcf56693415e92 100644 (file)
@@ -148,7 +148,9 @@ struct wpa_sm {
        size_t fils_key_auth_len;
        unsigned int fils_completed:1;
        unsigned int fils_erp_pmkid_set:1;
+       unsigned int fils_cache_id_set:1;
        u8 fils_erp_pmkid[PMKID_LEN];
+       u8 fils_cache_id[FILS_CACHE_ID_LEN];
 #endif /* CONFIG_FILS */
 };
 
index 914bd5d9bc58fbb36cfa0d07ca50a6afb83aa74f..708b58abf42a90baeb9348625fc45e72e01bf9f4 100644 (file)
@@ -1317,3 +1317,19 @@ int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
        *rates = r;
        return len;
 }
+
+
+#ifdef CONFIG_FILS
+const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss)
+{
+       const u8 *ie;
+
+       if (bss) {
+               ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+               if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7))
+                       return ie + 4;
+       }
+
+       return NULL;
+}
+#endif /* CONFIG_FILS */
index 84505fa7caa9bfc5d1d899703ac2616f31d94023..37d9fb650fd2e5b3a0b52ca341b6abcf19ecdcc2 100644 (file)
@@ -145,6 +145,7 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss);
 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
 struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
 int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
+const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss);
 
 static inline int bss_is_dmg(const struct wpa_bss *bss)
 {
index 448615e401980343322ba272a70b3cde2ecf67c3..500c28506c56e8c5153dae92cdefe603d3302919 100644 (file)
@@ -327,7 +327,7 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
        for (i = 0; i < ie.num_pmkid; i++) {
                pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
                                                    ie.pmkid + i * PMKID_LEN,
-                                                   NULL, NULL, 0);
+                                                   NULL, NULL, 0, NULL);
                if (pmksa_set == 0) {
                        eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
                        break;
index 6ae239f79332294849896eee9d9efd2a86e8d070..9cb2d92e8f8d94967c6544525efe980c7c16e08a 100644 (file)
@@ -344,8 +344,8 @@ int main(int argc, char *argv[])
        if (preauth_test.auth_timed_out)
                ret = -2;
        else {
-               ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0)
-                       ? 0 : -3;
+               ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0,
+                                             NULL) ? 0 : -3;
        }
 
        test_eapol_clean(&wpa_s);
index b57f167b1264fab67f40e46407074cda2808b0bd..c2fc5f9ec935c77a2f6f1486c30200b1be37a593 100644 (file)
@@ -301,13 +301,19 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
             wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
+               const u8 *cache_id = NULL;
+
                try_opportunistic = (ssid->proactive_key_caching < 0 ?
                                     wpa_s->conf->okc :
                                     ssid->proactive_key_caching) &&
                        (ssid->proto & WPA_PROTO_RSN);
+#ifdef CONFIG_FILS
+               if (wpa_key_mgmt_fils(ssid->key_mgmt))
+                       cache_id = wpa_bss_get_fils_cache_id(bss);
+#endif /* CONFIG_FILS */
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
                                            wpa_s->current_ssid,
-                                           try_opportunistic) == 0)
+                                           try_opportunistic, cache_id) == 0)
                        eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
                wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -516,8 +522,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_SAE
        if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
-           pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0)
-       {
+           pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0,
+                                   NULL) == 0) {
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
                params.auth_alg = WPA_AUTH_ALG_OPEN;
@@ -552,7 +558,9 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
        if (params.auth_alg == WPA_AUTH_ALG_OPEN &&
            wpa_key_mgmt_fils(ssid->key_mgmt)) {
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
-                                           ssid, 0) == 0)
+                                           ssid, 0,
+                                           wpa_bss_get_fils_cache_id(bss)) ==
+                   0)
                        wpa_printf(MSG_DEBUG,
                                   "SME: Try to use FILS with PMKSA caching");
                resp = fils_build_auth(wpa_s->wpa);
index 10c17929ef2a9acedf08c15671d1c68bebb49c0c..7757a03f5a9481d4a10d6d85f38072815da51211 100644 (file)
@@ -2290,7 +2290,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                                     ssid->proactive_key_caching) &&
                        (ssid->proto & WPA_PROTO_RSN);
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
-                                           ssid, try_opportunistic) == 0)
+                                           ssid, try_opportunistic, NULL) == 0)
                        eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
                wpa_ie_len = sizeof(wpa_ie);
                if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
index 0d753a9c0f4763ad080c0dbdc2eafe41e2374fa0..768911fee79bce5ebe850d93e1855aed8a31e14f 100644 (file)
@@ -1232,6 +1232,11 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
                }
 #endif /* CONFIG_P2P */
                conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation;
+#ifdef CONFIG_FILS
+               if (wpa_key_mgmt_fils(wpa_s->key_mgmt))
+                       conf.fils_cache_id =
+                               wpa_bss_get_fils_cache_id(wpa_s->current_bss);
+#endif /* CONFIG_FILS */
        }
        wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
 }