From: Michael Braun <michael-dev@xxxxxxxxxxxxx> When a station uses an invalid or offline r0kh_id, requests are always broadcasted. To avoid this, r0kh is required to always reply using a NACK and target ap uses a timer to detect non replying r0kh. If r0kh does not reply, a temporary blacklist entry is added to r0kh_list. Signed-off-by: Michael Braun <michael-dev@xxxxxxxxxxxxx> --- hostapd/config_file.c | 2 ++ hostapd/hostapd.conf | 6 ++++ src/ap/ap_config.c | 1 + src/ap/ap_config.h | 1 + src/ap/wpa_auth.h | 3 +- src/ap/wpa_auth_ft.c | 89 ++++++++++++++++++++++++++++++++++---------------- src/ap/wpa_auth_glue.c | 1 + 7 files changed, 73 insertions(+), 30 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 8998b0f..2631e8d 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2545,6 +2545,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->reassociation_deadline = atoi(pos); } else if (os_strcmp(buf, "rkh_pos_timeout") == 0) { bss->rkh_pos_timeout = atoi(pos); + } else if (os_strcmp(buf, "rkh_neg_timeout") == 0) { + bss->rkh_neg_timeout = atoi(pos); } else if (os_strcmp(buf, "rkh_pull_timeout") == 0) { bss->rkh_pull_timeout = atoi(pos); } else if (os_strcmp(buf, "rkh_pull_retries") == 0) { diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 1274566..728712e 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1305,6 +1305,7 @@ own_ip_addr=127.0.0.1 # Wildcard entry: Upon receiving a request from an R1KH not yet known, # it will be added to this list and thus receive push # notifications. +# If R0KH does not reply, it will be blacklisted. #r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff # List of R1KHs in the same Mobility Domain @@ -1328,6 +1329,11 @@ own_ip_addr=127.0.0.1 #rkh_pull_timeout = 1000 (default = 1s) #rkh_pull_retries = 4 (default) +# Timeout (seconds) for non replying R0KH (see wildcard entries above) +# Special values: 0 -> do not cache +# default: 60 seconds +#rkh_neg_timeout = 86400 + # Whether PMK-R1 push is enabled at R0KH # 0 = do not push PMK-R1 to all configured R1KHs (default) # 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index cffcc30..c2361e0 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -94,6 +94,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->ft_over_ds = 1; bss->r0_key_lifetime = 60; /* same as eap_reauth_period */ bss->rkh_pos_timeout = 86400; + bss->rkh_neg_timeout = 60; bss->rkh_pull_timeout = 1000; bss->rkh_pull_retries = 4; #endif /* CONFIG_IEEE80211R */ diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 57d0b15..4d1aee5 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -326,6 +326,7 @@ struct hostapd_bss_config { u8 r1_key_holder[FT_R1KH_ID_LEN]; u32 r0_key_lifetime; int rkh_pos_timeout; + int rkh_neg_timeout; int rkh_pull_timeout; /* ms */ int rkh_pull_retries; u32 reassociation_deadline; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 317a9be..b73c046 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -91,7 +91,7 @@ struct ft_r0kh_r1kh_resp_frame { u8 pmk_r1[PMK_LEN]; u8 pmk_r1_name[WPA_PMK_NAME_LEN]; le16 pairwise; - le16 expiresIn; + le16 expiresIn; /* 0xffff for no-entry */ struct ft_vlan vlan; u8 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */ u8 key_wrap_extra[8]; @@ -183,6 +183,7 @@ struct wpa_auth_config { u8 r1_key_holder[FT_R1KH_ID_LEN]; u32 r0_key_lifetime; int rkh_pos_timeout; + int rkh_neg_timeout; int rkh_pull_timeout; /* ms */ int rkh_pull_retries; u32 reassociation_deadline; diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 918ceaf..6158212 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -550,9 +550,21 @@ void wpa_ft_deinit(struct wpa_authenticator *wpa_auth) static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx) { + struct wpa_state_machine *sm = eloop_ctx; + + if (sm->ft_pending_pull_left_retries <= 0 && + sm->wpa_auth->conf.rkh_neg_timeout) { + /* final timeout, block this r0kh_id */ + wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID", + sm->r0kh_id, sm->r0kh_id_len); + wpa_ft_rrb_add_r0kh(sm->wpa_auth, NULL, + (u8 *) "\x00\x00\x00\x00\x00\x00", + sm->r0kh_id, sm->r0kh_id_len, + sm->wpa_auth->conf.rkh_neg_timeout); + } /* cancel multiple timeouts */ - eloop_cancel_timeout(wpa_ft_expire_pull, eloop_ctx, NULL); - eloop_cancel_timeout(ft_pull_resp_cb_finish, eloop_ctx, NULL); + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); + eloop_cancel_timeout(ft_pull_resp_cb_finish, sm, NULL); ft_pull_resp_cb_finish(eloop_ctx, timeout_ctx); } @@ -593,6 +605,11 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, sm->r0kh_id, sm->r0kh_id_len); return -1; } + if (is_zero_ether_addr(r0kh->addr)) { + wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted", + sm->r0kh_id, sm->r0kh_id_len); + return -1; + } wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH " "address " MACSTR, MAC2STR(r0kh->addr)); @@ -1840,17 +1857,17 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, &pairwise, &vlan, &expiresIn) < 0) { wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for " "PMK-R1 pull"); - return -1; + r.expiresIn = 0xffff; + } else { + wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id, + r.pmk_r1, r.pmk_r1_name); + wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name, + WPA_PMK_NAME_LEN); + r.pairwise = host_to_le16(pairwise); + os_memcpy(&r.vlan, &vlan, FT_VLAN_DATA_LEN); + r.expiresIn = host_to_le16(expiresIn); } - - wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id, - r.pmk_r1, r.pmk_r1_name); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name, - WPA_PMK_NAME_LEN); - r.pairwise = host_to_le16(pairwise); - os_memcpy(&r.vlan, &vlan, FT_VLAN_DATA_LEN); - r.expiresIn = host_to_le16(expiresIn); os_memset(r.pad, 0, sizeof(r.pad)); if (aes_wrap(r1kh->key, sizeof(r1kh->key), @@ -1923,6 +1940,8 @@ static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx) wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for " MACSTR " - process from timeout", MAC2STR(sm->addr)); + if (frame->expiresIn == 0xffff) + sm->ft_pending_pull_left_retries = 0; eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); eloop_cancel_timeout(ft_pull_resp_cb_finish, sm, NULL); @@ -1998,24 +2017,36 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, } pairwise = le_to_host16(f.pairwise); - expiresIn = le_to_host16(f.expiresIn); - wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce", - f.nonce, sizeof(f.nonce)); - wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID=" - MACSTR " pairwise=0x%x expiresIn=%d", - MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise, expiresIn); - wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1", - f.pmk_r1, PMK_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name", - f.pmk_r1_name, WPA_PMK_NAME_LEN); - wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - vlan %d%s", - le_to_host16(f.vlan.untagged), - f.vlan.tagged[0] ? "+" : ""); + if (f.expiresIn == 0xffff) { + res = 0; + wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce", + f.nonce, sizeof(f.nonce)); + wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR + " S1KH-ID=" MACSTR " NACK", + MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id)); + } else { + expiresIn = le_to_host16(f.expiresIn); + wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce", + f.nonce, sizeof(f.nonce)); + wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR + " S1KH-ID=" MACSTR " pairwise=0x%x expiresIn=%d", + MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise, + expiresIn); + wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1", + f.pmk_r1, PMK_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name", + f.pmk_r1_name, WPA_PMK_NAME_LEN); + wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - vlan %d%s", + le_to_host16(f.vlan.untagged), + f.vlan.tagged[0] ? "+" : ""); + + if (expiresIn <= 0 || expiresIn > maxExpiresIn) + expiresIn = maxExpiresIn; + res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, + f.pmk_r1_name, pairwise, f.vlan, + expiresIn); + } - if (expiresIn <= 0 || expiresIn > maxExpiresIn) - expiresIn = maxExpiresIn; - res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, - pairwise, f.vlan, expiresIn); wpa_printf(MSG_DEBUG, "FT: Look for pending pull request"); ctx.frame = &f; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 2cd1260..e7fc46a 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -78,6 +78,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->r0_key_lifetime = conf->r0_key_lifetime; wconf->reassociation_deadline = conf->reassociation_deadline; wconf->rkh_pos_timeout = conf->rkh_pos_timeout; + wconf->rkh_neg_timeout = conf->rkh_neg_timeout; wconf->rkh_pull_timeout = conf->rkh_pull_timeout; wconf->rkh_pull_retries = conf->rkh_pull_retries; wconf->r0kh_list = &conf->r0kh_list; -- 1.9.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap