From 3a46cf93d0bc56de8735df15e32f9512391bc066 Mon Sep 17 00:00:00 2001 From: Michael Braun Date: Sun, 2 Apr 2017 14:52:52 +0200 Subject: [PATCH] FT: Add support for wildcard R0KH/R1KH Enable use of FT RRB without configuring each other AP locally. Instead, broadcast messages are exchanged to discover APs within the local network. When an R0KH or R1KH is discovered, it is cached for one day. When a station uses an invalid or offline r0kh_id, requests are always broadcast. In order to avoid this, if r0kh does not reply, a temporary blacklist entry is added to r0kh_list. To avoid blocking a valid r0kh when a non-existing pmk_r0_name is requested, r0kh is required to always reply using a NAK. Resend requests a few times to ensure blacklisting does not happen due to small packet loss. To free newly created stations later, the r*kh_list start pointer in conf needs to be updateable from wpa_auth_ft.c, where only wconf is accessed. Signed-off-by: Michael Braun --- hostapd/config_file.c | 8 + hostapd/hostapd.conf | 24 ++ src/ap/ap_config.c | 4 + src/ap/ap_config.h | 4 + src/ap/wpa_auth.c | 3 + src/ap/wpa_auth.h | 12 +- src/ap/wpa_auth_ft.c | 574 ++++++++++++++++++++++++++++++++++++----- src/ap/wpa_auth_glue.c | 8 +- src/ap/wpa_auth_i.h | 1 + 9 files changed, 570 insertions(+), 68 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 2eb72055f..900d81131 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2641,6 +2641,14 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->r0_key_lifetime = atoi(pos); } else if (os_strcmp(buf, "reassociation_deadline") == 0) { 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) { + bss->rkh_pull_retries = atoi(pos); } else if (os_strcmp(buf, "r0kh") == 0) { if (add_r0kh(bss, pos) < 0) { wpa_printf(MSG_DEBUG, "Line %d: Invalid r0kh '%s'", diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index c5ba0e9cd..135715eb4 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1459,6 +1459,11 @@ own_ip_addr=127.0.0.1 #r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f #r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff # And so on.. One line per R0KH. +# Wildcard entry: +# Upon receiving a response from R0KH, it will be added to this list, so +# subsequent requests won't be broadcast. 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 # format: <256-bit key as hex string> @@ -1468,6 +1473,25 @@ own_ip_addr=127.0.0.1 #r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f #r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff # And so on.. One line per R1KH. +# Wildcard entry: +# Upon receiving a request from an R1KH not yet known, it will be added to this +# list and thus will receive push notifications. +#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff + +# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above) +# Special values: 0 -> do not expire +# Warning: do not cache implies no sequence number validation with wildcards +#rkh_pos_timeout=86400 (default = 1 day) + +# Timeout (milliseconds) for requesting PMK-R1 from R0KH using PULL request +# and number of retries. +#rkh_pull_timeout=1000 (default = 1 second) +#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=60 # Note: The R0KH/R1KH keys used to be 128-bit in length before the message # format was changed. That shorter key length is still supported for backwards diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 6b3d4e862..09cbec3b3 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -93,6 +93,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_IEEE80211R_AP bss->ft_over_ds = 1; + bss->rkh_pos_timeout = 86400; + bss->rkh_neg_timeout = 60; + bss->rkh_pull_timeout = 1000; + bss->rkh_pull_retries = 4; #endif /* CONFIG_IEEE80211R_AP */ bss->radius_das_time_window = 300; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 498891c54..849c69d92 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -342,6 +342,10 @@ struct hostapd_bss_config { u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; 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; struct ft_remote_r0kh *r0kh_list; struct ft_remote_r1kh *r1kh_list; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 9fceca65d..1f5885eea 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -706,6 +706,9 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); +#ifdef CONFIG_IEEE80211R_AP + wpa_ft_sta_deinit(sm); +#endif /* CONFIG_IEEE80211R_AP */ if (sm->in_step_loop) { /* Must not free state machine while wpa_sm_step() is running. * Freeing will be completed in the end of wpa_sm_step(). */ diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index bab56191b..5f8bb8726 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -103,7 +103,8 @@ struct ft_rrb_seq { * auth: * required: SEQ, NONCE, R0KH_ID, R1KH_ID * encrypted: - * required: S1KH_ID, session TLVs + * required: S1KH_ID + * optional: session TLVs * * push frame TLVs: * auth: @@ -185,9 +186,13 @@ struct wpa_auth_config { size_t r0_key_holder_len; 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; - struct ft_remote_r0kh *r0kh_list; - struct ft_remote_r1kh *r1kh_list; + struct ft_remote_r0kh **r0kh_list; + struct ft_remote_r1kh **r1kh_list; int pmk_r1_push; int ft_over_ds; int ft_psk_generate_local; @@ -370,6 +375,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, size_t data_len); void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr); void wpa_ft_deinit(struct wpa_authenticator *wpa_auth); +void wpa_ft_sta_deinit(struct wpa_state_machine *sm); #endif /* CONFIG_IEEE80211R_AP */ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 9db9b26c6..b73ea9944 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -34,6 +34,8 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm, const u8 *current_ap, const u8 *sta_addr, u16 status, const u8 *resp_ies, size_t resp_ies_len); +static void ft_finish_pull(struct wpa_state_machine *sm); +static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx); static void wpa_ft_rrb_seq_timeout(void *eloop_ctx, void *timeout_ctx); struct tlv_list { @@ -1008,21 +1010,27 @@ static int wpa_ft_rrb_init_r0kh_seq(struct ft_remote_r0kh *r0kh) static void wpa_ft_rrb_lookup_r0kh(struct wpa_authenticator *wpa_auth, const u8 *f_r0kh_id, size_t f_r0kh_id_len, - struct ft_remote_r0kh **r0kh_out) + struct ft_remote_r0kh **r0kh_out, + struct ft_remote_r0kh **r0kh_wildcard) { struct ft_remote_r0kh *r0kh; + *r0kh_wildcard = NULL; *r0kh_out = NULL; - for (r0kh = wpa_auth->conf.r0kh_list; r0kh; r0kh = r0kh->next) { + if (wpa_auth->conf.r0kh_list) + r0kh = *wpa_auth->conf.r0kh_list; + else + r0kh = NULL; + for (; r0kh; r0kh = r0kh->next) { + if (r0kh->id_len == 1 && r0kh->id[0] == '*') + *r0kh_wildcard = r0kh; if (f_r0kh_id && r0kh->id_len == f_r0kh_id_len && - os_memcmp_const(f_r0kh_id, r0kh->id, f_r0kh_id_len) == 0) { + os_memcmp_const(f_r0kh_id, r0kh->id, f_r0kh_id_len) == 0) *r0kh_out = r0kh; - break; - } } - if (!*r0kh_out) + if (!*r0kh_out && !*r0kh_wildcard) wpa_printf(MSG_DEBUG, "FT: No matching R0KH found"); if (*r0kh_out && wpa_ft_rrb_init_r0kh_seq(*r0kh_out) < 0) @@ -1049,21 +1057,28 @@ static int wpa_ft_rrb_init_r1kh_seq(struct ft_remote_r1kh *r1kh) static void wpa_ft_rrb_lookup_r1kh(struct wpa_authenticator *wpa_auth, const u8 *f_r1kh_id, - struct ft_remote_r1kh **r1kh_out) + struct ft_remote_r1kh **r1kh_out, + struct ft_remote_r1kh **r1kh_wildcard) { struct ft_remote_r1kh *r1kh; + *r1kh_wildcard = NULL; *r1kh_out = NULL; - for (r1kh = wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + if (wpa_auth->conf.r1kh_list) + r1kh = *wpa_auth->conf.r1kh_list; + else + r1kh = NULL; + for (; r1kh; r1kh = r1kh->next) { + if (is_zero_ether_addr(r1kh->addr) && + is_zero_ether_addr(r1kh->id)) + *r1kh_wildcard = r1kh; if (f_r1kh_id && - os_memcmp_const(r1kh->id, f_r1kh_id, FT_R1KH_ID_LEN) == 0) { + os_memcmp_const(r1kh->id, f_r1kh_id, FT_R1KH_ID_LEN) == 0) *r1kh_out = r1kh; - break; - } } - if (!*r1kh_out) + if (!*r1kh_out && !*r1kh_wildcard) wpa_printf(MSG_DEBUG, "FT: No matching R1KH found"); if (*r1kh_out && wpa_ft_rrb_init_r1kh_seq(*r1kh_out) < 0) @@ -1094,6 +1109,163 @@ static int wpa_ft_rrb_check_r1kh(struct wpa_authenticator *wpa_auth, } +static void wpa_ft_rrb_del_r0kh(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_authenticator *wpa_auth = eloop_ctx; + struct ft_remote_r0kh *r0kh, *prev = NULL; + + if (!wpa_auth->conf.r0kh_list) + return; + + for (r0kh = *wpa_auth->conf.r0kh_list; r0kh; r0kh = r0kh->next) { + if (r0kh == timeout_ctx) + break; + prev = r0kh; + } + if (!r0kh) + return; + if (prev) + prev->next = r0kh->next; + else + *wpa_auth->conf.r0kh_list = r0kh->next; + if (r0kh->seq) + wpa_ft_rrb_seq_flush(wpa_auth, r0kh->seq, 0); + os_free(r0kh->seq); + os_free(r0kh); +} + + +static void wpa_ft_rrb_r0kh_replenish(struct wpa_authenticator *wpa_auth, + struct ft_remote_r0kh *r0kh, int timeout) +{ + if (timeout > 0) + eloop_replenish_timeout(timeout, 0, wpa_ft_rrb_del_r0kh, + wpa_auth, r0kh); +} + + +static void wpa_ft_rrb_r0kh_timeout(struct wpa_authenticator *wpa_auth, + struct ft_remote_r0kh *r0kh, int timeout) +{ + eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth, r0kh); + + if (timeout > 0) + eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh, + wpa_auth, r0kh); +} + + +static struct ft_remote_r0kh * +wpa_ft_rrb_add_r0kh(struct wpa_authenticator *wpa_auth, + struct ft_remote_r0kh *r0kh_wildcard, + const u8 *src_addr, const u8 *r0kh_id, size_t id_len, + int timeout) +{ + struct ft_remote_r0kh *r0kh; + + if (!wpa_auth->conf.r0kh_list) + return NULL; + + r0kh = os_zalloc(sizeof(*r0kh)); + if (!r0kh) + return NULL; + + if (src_addr) + os_memcpy(r0kh->addr, src_addr, sizeof(r0kh->addr)); + + if (id_len > FT_R0KH_ID_MAX_LEN) + id_len = FT_R0KH_ID_MAX_LEN; + os_memcpy(r0kh->id, r0kh_id, id_len); + r0kh->id_len = id_len; + + os_memcpy(r0kh->key, r0kh_wildcard->key, sizeof(r0kh->key)); + + r0kh->next = *wpa_auth->conf.r0kh_list; + *wpa_auth->conf.r0kh_list = r0kh; + + if (timeout > 0) + eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh, + wpa_auth, r0kh); + + if (wpa_ft_rrb_init_r0kh_seq(r0kh) < 0) + return NULL; + + return r0kh; +} + + +static void wpa_ft_rrb_del_r1kh(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_authenticator *wpa_auth = eloop_ctx; + struct ft_remote_r1kh *r1kh, *prev = NULL; + + if (!wpa_auth->conf.r1kh_list) + return; + + for (r1kh = *wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + if (r1kh == timeout_ctx) + break; + prev = r1kh; + } + if (!r1kh) + return; + if (prev) + prev->next = r1kh->next; + else + *wpa_auth->conf.r1kh_list = r1kh->next; + if (r1kh->seq) + wpa_ft_rrb_seq_flush(wpa_auth, r1kh->seq, 0); + os_free(r1kh->seq); + os_free(r1kh); +} + + +static void wpa_ft_rrb_r1kh_replenish(struct wpa_authenticator *wpa_auth, + struct ft_remote_r1kh *r1kh, int timeout) +{ + if (timeout > 0) + eloop_replenish_timeout(timeout, 0, wpa_ft_rrb_del_r1kh, + wpa_auth, r1kh); +} + + +static struct ft_remote_r1kh * +wpa_ft_rrb_add_r1kh(struct wpa_authenticator *wpa_auth, + struct ft_remote_r1kh *r1kh_wildcard, + const u8 *src_addr, const u8 *r1kh_id, int timeout) +{ + struct ft_remote_r1kh *r1kh; + + if (!wpa_auth->conf.r1kh_list) + return NULL; + + r1kh = os_zalloc(sizeof(*r1kh)); + if (!r1kh) + return NULL; + + os_memcpy(r1kh->addr, src_addr, sizeof(r1kh->addr)); + os_memcpy(r1kh->id, r1kh_id, sizeof(r1kh->id)); + os_memcpy(r1kh->key, r1kh_wildcard->key, sizeof(r1kh->key)); + r1kh->next = *wpa_auth->conf.r1kh_list; + *wpa_auth->conf.r1kh_list = r1kh; + + if (timeout > 0) + eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r1kh, + wpa_auth, r1kh); + + if (wpa_ft_rrb_init_r1kh_seq(r1kh) < 0) + return NULL; + + return r1kh; +} + + +void wpa_ft_sta_deinit(struct wpa_state_machine *sm) +{ + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); +} + + static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth) { struct ft_remote_r0kh *r0kh; @@ -1101,7 +1273,11 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth) eloop_cancel_timeout(wpa_ft_rrb_seq_timeout, wpa_auth, ELOOP_ALL_CTX); - for (r0kh = wpa_auth->conf.r0kh_list; r0kh; r0kh = r0kh->next) { + if (wpa_auth->conf.r0kh_list) + r0kh = *wpa_auth->conf.r0kh_list; + else + r0kh = NULL; + for (; r0kh; r0kh = r0kh->next) { if (!r0kh->seq) continue; wpa_ft_rrb_seq_flush(wpa_auth, r0kh->seq, 0); @@ -1109,7 +1285,11 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth) r0kh->seq = NULL; } - for (r1kh = wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + if (wpa_auth->conf.r1kh_list) + r1kh = *wpa_auth->conf.r1kh_list; + else + r1kh = NULL; + for (; r1kh; r1kh = r1kh->next) { if (!r1kh->seq) continue; wpa_ft_rrb_seq_flush(wpa_auth, r1kh->seq, 0); @@ -1119,9 +1299,100 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth) } +static void wpa_ft_deinit_rkh_tmp(struct wpa_authenticator *wpa_auth) +{ + struct ft_remote_r0kh *r0kh, *r0kh_next, *r0kh_prev = NULL; + struct ft_remote_r1kh *r1kh, *r1kh_next, *r1kh_prev = NULL; + + if (wpa_auth->conf.r0kh_list) + r0kh = *wpa_auth->conf.r0kh_list; + else + r0kh = NULL; + while (r0kh) { + r0kh_next = r0kh->next; + if (eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth, + r0kh) > 0) { + if (r0kh_prev) + r0kh_prev->next = r0kh_next; + else + *wpa_auth->conf.r0kh_list = r0kh_next; + os_free(r0kh); + } else { + r0kh_prev = r0kh; + } + r0kh = r0kh_next; + } + + if (wpa_auth->conf.r1kh_list) + r1kh = *wpa_auth->conf.r1kh_list; + else + r1kh = NULL; + while (r1kh) { + r1kh_next = r1kh->next; + if (eloop_cancel_timeout(wpa_ft_rrb_del_r1kh, wpa_auth, + r1kh) > 0) { + if (r1kh_prev) + r1kh_prev->next = r1kh_next; + else + *wpa_auth->conf.r1kh_list = r1kh_next; + os_free(r1kh); + } else { + r1kh_prev = r1kh; + } + r1kh = r1kh_next; + } +} + + void wpa_ft_deinit(struct wpa_authenticator *wpa_auth) { wpa_ft_deinit_seq(wpa_auth); + wpa_ft_deinit_rkh_tmp(wpa_auth); +} + + +static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth, + const u8 *f_r0kh_id, size_t f_r0kh_id_len) +{ + struct ft_remote_r0kh *r0kh, *r0kh_wildcard; + + if (!wpa_auth->conf.rkh_neg_timeout) + return; + + wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, + &r0kh, &r0kh_wildcard); + + if (!r0kh_wildcard) { + /* r0kh removed after neg_timeout and might need re-adding */ + return; + } + + wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID", + f_r0kh_id, f_r0kh_id_len); + + if (r0kh) { + wpa_ft_rrb_r0kh_timeout(wpa_auth, r0kh, + wpa_auth->conf.rkh_neg_timeout); + os_memset(r0kh->addr, 0, ETH_ALEN); + } else + wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, NULL, f_r0kh_id, + f_r0kh_id_len, + wpa_auth->conf.rkh_neg_timeout); +} + + +static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_state_machine *sm = eloop_ctx; + + wpa_printf(MSG_DEBUG, "FT: Timeout pending pull request for " MACSTR, + MAC2STR(sm->addr)); + if (sm->ft_pending_pull_left_retries <= 0) + wpa_ft_block_r0kh(sm->wpa_auth, sm->r0kh_id, sm->r0kh_id_len); + + /* cancel multiple timeouts */ + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); + ft_finish_pull(sm); } @@ -1129,11 +1400,14 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, const u8 *ies, size_t ies_len, const u8 *pmk_r0_name) { - struct ft_remote_r0kh *r0kh; + struct ft_remote_r0kh *r0kh, *r0kh_wildcard; u8 *packet = NULL; const u8 *key, *f_r1kh_id = sm->wpa_auth->conf.r1_key_holder; size_t packet_len, key_len; struct ft_rrb_seq f_seq; + int tsecs, tusecs, first; + struct wpabuf *ft_pending_req_ies; + int r0kh_timeout; struct tlv_list req_enc[] = { { .type = FT_RRB_PMK_R0_NAME, .len = WPA_PMK_NAME_LEN, .data = pmk_r0_name }, @@ -1153,13 +1427,38 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL }, }; + if (sm->ft_pending_pull_left_retries <= 0) + return -1; + first = sm->ft_pending_pull_left_retries == + sm->wpa_auth->conf.rkh_pull_retries; + sm->ft_pending_pull_left_retries--; + wpa_ft_rrb_lookup_r0kh(sm->wpa_auth, sm->r0kh_id, sm->r0kh_id_len, - &r0kh); + &r0kh, &r0kh_wildcard); + + /* Keep r0kh sufficiently long in the list for seq num check */ + r0kh_timeout = sm->wpa_auth->conf.rkh_pull_timeout / 1000 + + 1 + ftRRBseqTimeout; + if (r0kh) { + wpa_ft_rrb_r0kh_replenish(sm->wpa_auth, r0kh, r0kh_timeout); + } else if (r0kh_wildcard) { + wpa_printf(MSG_DEBUG, "FT: Using wildcard R0KH-ID"); + /* r0kh->addr: updated by SEQ_RESP and wpa_ft_expire_pull */ + r0kh = wpa_ft_rrb_add_r0kh(sm->wpa_auth, r0kh_wildcard, + r0kh_wildcard->addr, + sm->r0kh_id, sm->r0kh_id_len, + r0kh_timeout); + } if (r0kh == NULL) { wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID", 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; + } key = r0kh->key; key_len = sizeof(r0kh->key); @@ -1175,7 +1474,8 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, key_len, NULL, 0, NULL, 0, NULL); } - if (random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) { + if (first && + random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " "nonce"); return -1; @@ -1191,13 +1491,18 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, &packet, &packet_len) < 0) return -1; + ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len); wpabuf_free(sm->ft_pending_req_ies); - sm->ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len); + sm->ft_pending_req_ies = ft_pending_req_ies; if (!sm->ft_pending_req_ies) { os_free(packet); return -1; } + tsecs = sm->wpa_auth->conf.rkh_pull_timeout / 1000; + tusecs = (sm->wpa_auth->conf.rkh_pull_timeout % 1000) * 1000; + eloop_register_timeout(tsecs, tusecs, wpa_ft_expire_pull, sm, NULL); + wpa_ft_rrb_oui_send(sm->wpa_auth, r0kh->addr, FT_PACKET_R0KH_R1KH_PULL, packet, packet_len); @@ -1816,8 +2121,8 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, } else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1, &pairwise) < 0) { if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) { - wpa_printf(MSG_DEBUG, "FT: Did not have matching " - "PMK-R1 and unknown R0KH-ID"); + wpa_printf(MSG_DEBUG, + "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH"); return WLAN_STATUS_INVALID_PMKID; } @@ -1908,6 +2213,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, sm->ft_pending_cb = cb; sm->ft_pending_cb_ctx = ctx; sm->ft_pending_auth_transaction = auth_transaction; + sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries; res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies, &resp_ies_len); if (res < 0) { @@ -2189,6 +2495,7 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth, sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb; sm->ft_pending_cb_ctx = sm; os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN); + sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries; res = wpa_ft_process_auth_req(sm, body, len, &resp_ies, &resp_ies_len); if (res < 0) { @@ -2276,6 +2583,10 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len, { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL }, }; + if (!pmk_r0) + return wpa_ft_rrb_build(key, key_len, tlvs, NULL, tlv_auth, + src_addr, type, packet, packet_len); + if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh_id, s1kh_id, pmk_r1, pmk_r1_name) < 0) return -1; @@ -2301,7 +2612,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, const char *msgtype = "pull request"; u8 *plain = NULL, *packet = NULL; size_t plain_len = 0, packet_len = 0; - struct ft_remote_r1kh *r1kh; + struct ft_remote_r1kh *r1kh, *r1kh_wildcard; const u8 *key; size_t key_len; int seq_ret; @@ -2327,17 +2638,31 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, msgtype, FT_R1KH_ID_LEN); wpa_printf(MSG_DEBUG, "FT: R1KH-ID=" MACSTR, MAC2STR(f_r1kh_id)); - wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh); - if (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0) + wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh, &r1kh_wildcard); + if (r1kh) { + key = r1kh->key; + key_len = sizeof(r1kh->key); + } else if (r1kh_wildcard) { + wpa_printf(MSG_DEBUG, "FT: Using wildcard R1KH-ID"); + key = r1kh_wildcard->key; + key_len = sizeof(r1kh_wildcard->key); + } else { goto out; - key = r1kh->key; - key_len = sizeof(r1kh->key); + } RRB_GET_AUTH(FT_RRB_NONCE, nonce, "pull request", FT_RRB_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: nonce", f_nonce, f_nonce_len); - seq_ret = wpa_ft_rrb_seq_chk(r1kh->seq, src_addr, enc, enc_len, auth, - auth_len, msgtype, no_defer); + seq_ret = FT_RRB_SEQ_DROP; + if (r1kh) + seq_ret = wpa_ft_rrb_seq_chk(r1kh->seq, src_addr, enc, enc_len, + auth, auth_len, msgtype, no_defer); + if (!no_defer && r1kh_wildcard && + (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) { + /* wildcard: r1kh-id unknown or changed addr -> do a seq req */ + seq_ret = FT_RRB_SEQ_DEFER; + } + if (seq_ret == FT_RRB_SEQ_DROP) goto out; @@ -2346,6 +2671,13 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, &plain, &plain_len) < 0) goto out; + if (!r1kh) + r1kh = wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard, src_addr, + f_r1kh_id, + wpa_auth->conf.rkh_pos_timeout); + if (!r1kh) + goto out; + if (seq_ret == FT_RRB_SEQ_DEFER) { wpa_ft_rrb_seq_req(wpa_auth, r1kh->seq, src_addr, f_r0kh_id, f_r0kh_id_len, f_r1kh_id, key, key_len, @@ -2356,6 +2688,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, wpa_ft_rrb_seq_accept(wpa_auth, r1kh->seq, src_addr, auth, auth_len, msgtype); + wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh, + wpa_auth->conf.rkh_pos_timeout); RRB_GET(FT_RRB_PMK_R0_NAME, pmk_r0_name, msgtype, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", f_pmk_r0_name, @@ -2392,10 +2726,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, resp_auth[4].len = 0; resp_auth[4].data = NULL; - if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) { + if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) wpa_printf(MSG_DEBUG, "FT: No matching PMK-R0-Name found"); - goto out; - } ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id, f_s1kh_id, resp_auth, wpa_auth->addr, @@ -2417,6 +2749,7 @@ out: /* @returns 0 on success * -1 on error + * -2 if FR_RRB_PAIRWISE is missing */ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, const u8 *src_addr, u8 type, @@ -2431,7 +2764,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, { u8 *plain = NULL; size_t plain_len = 0; - struct ft_remote_r0kh *r0kh; + struct ft_remote_r0kh *r0kh, *r0kh_wildcard; const u8 *key; size_t key_len; int seq_ret; @@ -2453,14 +2786,31 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, goto out; } - wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, &r0kh); - if (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0) + wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, &r0kh, + &r0kh_wildcard); + if (r0kh) { + key = r0kh->key; + key_len = sizeof(r0kh->key); + } else if (r0kh_wildcard) { + wpa_printf(MSG_DEBUG, "FT: Using wildcard R0KH-ID"); + key = r0kh_wildcard->key; + key_len = sizeof(r0kh_wildcard->key); + } else { goto out; - key = r0kh->key; - key_len = sizeof(r0kh->key); + } + + seq_ret = FT_RRB_SEQ_DROP; + if (r0kh) { + seq_ret = wpa_ft_rrb_seq_chk(r0kh->seq, src_addr, enc, enc_len, + auth, auth_len, msgtype, + cb ? 0 : 1); + } + if (cb && r0kh_wildcard && + (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) { + /* wildcard: r0kh-id unknown or changed addr -> do a seq req */ + seq_ret = FT_RRB_SEQ_DEFER; + } - seq_ret = wpa_ft_rrb_seq_chk(r0kh->seq, src_addr, enc, enc_len, auth, - auth_len, msgtype, cb ? 0 : 1); if (seq_ret == FT_RRB_SEQ_DROP) goto out; @@ -2468,6 +2818,13 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, src_addr, type, &plain, &plain_len) < 0) goto out; + if (!r0kh) + r0kh = wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, src_addr, + f_r0kh_id, f_r0kh_id_len, + wpa_auth->conf.rkh_pos_timeout); + if (!r0kh) + goto out; + if (seq_ret == FT_RRB_SEQ_DEFER) { wpa_ft_rrb_seq_req(wpa_auth, r0kh->seq, src_addr, f_r0kh_id, f_r0kh_id_len, f_r1kh_id, key, key_len, @@ -2477,6 +2834,8 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, wpa_ft_rrb_seq_accept(wpa_auth, r0kh->seq, src_addr, auth, auth_len, msgtype); + wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh, + wpa_auth->conf.rkh_pos_timeout); RRB_GET(FT_RRB_S1KH_ID, s1kh_id, msgtype, ETH_ALEN); wpa_printf(MSG_DEBUG, "FT: S1KH-ID=" MACSTR, MAC2STR(f_s1kh_id)); @@ -2484,9 +2843,11 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, if (s1kh_id_out) os_memcpy(s1kh_id_out, f_s1kh_id, ETH_ALEN); + ret = -2; RRB_GET(FT_RRB_PAIRWISE, pairwise, msgtype, sizeof(le16)); wpa_hexdump(MSG_DEBUG, "FT: pairwise", f_pairwise, f_pairwise_len); + ret = -1; RRB_GET(FT_RRB_PMK_R1_NAME, pmk_r1_name, msgtype, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f_pmk_r1_name, WPA_PMK_NAME_LEN); @@ -2519,13 +2880,20 @@ static void ft_finish_pull(struct wpa_state_machine *sm) size_t resp_ies_len; u16 status; + if (!sm->ft_pending_cb || !sm->ft_pending_req_ies) + return; + res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies), wpabuf_len(sm->ft_pending_req_ies), &resp_ies, &resp_ies_len); + if (res < 0) { + /* this loop is broken by ft_pending_pull_left_retries */ + wpa_printf(MSG_DEBUG, + "FT: Callback postponed until response is available"); + return; + } wpabuf_free(sm->ft_pending_req_ies); sm->ft_pending_req_ies = NULL; - if (res < 0) - res = WLAN_STATUS_UNSPECIFIED_FAILURE; status = res; wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR " - status %u", MAC2STR(sm->addr), status); @@ -2568,7 +2936,7 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, int no_defer) { const char *msgtype = "pull response"; - int ret = -1; + int nak, ret = -1; struct ft_get_sta_ctx ctx; u8 s1kh_id[ETH_ALEN]; const u8 *f_nonce; @@ -2590,6 +2958,12 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, ret = wpa_ft_rrb_rx_r1(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_RESP, enc, enc_len, auth, auth_len, msgtype, s1kh_id, no_defer ? NULL : &wpa_ft_rrb_rx_resp); + if (ret == -2) { + ret = 0; + nak = 1; + } else { + nak = 0; + } if (ret < 0) return -1; @@ -2598,6 +2972,9 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for " MACSTR, MAC2STR(ctx.sm->addr)); + eloop_cancel_timeout(wpa_ft_expire_pull, ctx.sm, NULL); + if (nak) + ctx.sm->ft_pending_pull_left_retries = 0; ft_finish_pull(ctx.sm); } @@ -2629,7 +3006,11 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, const u8 *enc, size_t enc_len, const u8 *auth, size_t auth_len, struct ft_remote_seq **rkh_seq, - u8 **key, size_t *key_len) + u8 **key, size_t *key_len, + struct ft_remote_r0kh **r0kh_out, + struct ft_remote_r1kh **r1kh_out, + struct ft_remote_r0kh **r0kh_wildcard_out, + struct ft_remote_r1kh **r1kh_wildcard_out) { struct ft_remote_r0kh *r0kh = NULL; struct ft_remote_r1kh *r1kh = NULL; @@ -2638,6 +3019,8 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, int to_r0kh, to_r1kh; u8 *plain = NULL; size_t plain_len = 0; + struct ft_remote_r0kh *r0kh_wildcard; + struct ft_remote_r1kh *r1kh_wildcard; RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, "seq", -1); RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, "seq", FT_R1KH_ID_LEN); @@ -2657,29 +3040,38 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, if (!to_r0kh) { wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, - &r0kh); - if (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0) { + &r0kh, &r0kh_wildcard); + if (!r0kh_wildcard && + (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) { wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID", f_r0kh_id, f_r0kh_id_len); goto out; } - - *key = r0kh->key; - *key_len = sizeof(r0kh->key); - *rkh_seq = r0kh->seq; + if (r0kh) { + *key = r0kh->key; + *key_len = sizeof(r0kh->key); + } else { + *key = r0kh_wildcard->key; + *key_len = sizeof(r0kh_wildcard->key); + } } if (!to_r1kh) { - wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh); - if (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0) { + wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh, + &r1kh_wildcard); + if (!r1kh_wildcard && + (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) { wpa_hexdump(MSG_DEBUG, "FT: Did not find R1KH-ID", f_r1kh_id, FT_R1KH_ID_LEN); goto out; } - - *key = r1kh->key; - *key_len = sizeof(r1kh->key); - *rkh_seq = r1kh->seq; + if (r1kh) { + *key = r1kh->key; + *key_len = sizeof(r1kh->key); + } else { + *key = r1kh_wildcard->key; + *key_len = sizeof(r1kh_wildcard->key); + } } if (wpa_ft_rrb_decrypt(*key, *key_len, enc, enc_len, auth, auth_len, @@ -2688,6 +3080,39 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, os_free(plain); + if (!to_r0kh) { + if (!r0kh) + r0kh = wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, + src_addr, f_r0kh_id, + f_r0kh_id_len, + ftRRBseqTimeout); + if (!r0kh) + goto out; + + wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh, ftRRBseqTimeout); + *rkh_seq = r0kh->seq; + if (r0kh_out) + *r0kh_out = r0kh; + if (r0kh_wildcard_out) + *r0kh_wildcard_out = r0kh_wildcard; + } + + if (!to_r1kh) { + if (!r1kh) + r1kh = wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard, + src_addr, f_r1kh_id, + ftRRBseqTimeout); + if (!r1kh) + goto out; + + wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh, ftRRBseqTimeout); + *rkh_seq = r1kh->seq; + if (r1kh_out) + *r1kh_out = r1kh; + if (r1kh_wildcard_out) + *r1kh_wildcard_out = r1kh_wildcard; + } + return 0; out: return -1; @@ -2704,7 +3129,7 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth, struct ft_rrb_seq f_seq; const u8 *f_nonce, *f_r0kh_id, *f_r1kh_id; size_t f_nonce_len, f_r0kh_id_len, f_r1kh_id_len; - struct ft_remote_seq *rkh_seq; + struct ft_remote_seq *rkh_seq = NULL; u8 *packet = NULL, *key = NULL; size_t packet_len = 0, key_len = 0; struct tlv_list seq_resp_auth[5]; @@ -2713,7 +3138,7 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth, if (wpa_ft_rrb_rx_seq(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_REQ, enc, enc_len, auth, auth_len, &rkh_seq, &key, - &key_len) < 0) + &key_len, NULL, NULL, NULL, NULL) < 0) goto out; RRB_GET_AUTH(FT_RRB_NONCE, nonce, "seq request", FT_RRB_NONCE_LEN); @@ -2767,6 +3192,8 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth, { u8 *key = NULL; size_t key_len = 0; + struct ft_remote_r0kh *r0kh = NULL, *r0kh_wildcard = NULL; + struct ft_remote_r1kh *r1kh = NULL, *r1kh_wildcard = NULL; const u8 *f_nonce, *f_seq; size_t f_nonce_len, f_seq_len; struct ft_remote_seq *rkh_seq = NULL; @@ -2780,7 +3207,8 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth, if (wpa_ft_rrb_rx_seq(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_RESP, enc, enc_len, auth, auth_len, &rkh_seq, &key, - &key_len) < 0) + &key_len, &r0kh, &r1kh, &r0kh_wildcard, + &r1kh_wildcard) < 0) goto out; RRB_GET_AUTH(FT_RRB_NONCE, nonce, "seq response", FT_RRB_NONCE_LEN); @@ -2804,6 +3232,20 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth, goto out; } + if (r0kh) { + wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh, + wpa_auth->conf.rkh_pos_timeout); + if (r0kh_wildcard) + os_memcpy(r0kh->addr, src_addr, ETH_ALEN); + } + + if (r1kh) { + wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh, + wpa_auth->conf.rkh_pos_timeout); + if (r1kh_wildcard) + os_memcpy(r1kh->addr, src_addr, ETH_ALEN); + } + seq_ret = wpa_ft_rrb_seq_chk(rkh_seq, src_addr, enc, enc_len, auth, auth_len, "seq response", 1); if (seq_ret == FT_RRB_SEQ_OK) { @@ -2967,6 +3409,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, { const u8 *auth, *enc; size_t alen, elen; + int no_defer = 0; wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP " MACSTR, MAC2STR(src_addr)); @@ -2984,7 +3427,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, "FT: RRB-OUI received frame from remote AP " MACSTR " to multicast address " MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr)); - return; + no_defer = 1; } if (data_len < sizeof(u16)) { @@ -3005,23 +3448,23 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, switch (oui_suffix) { case FT_PACKET_R0KH_R1KH_PULL: wpa_ft_rrb_rx_pull(wpa_auth, src_addr, enc, elen, auth, alen, - 0); + no_defer); break; case FT_PACKET_R0KH_R1KH_RESP: wpa_ft_rrb_rx_resp(wpa_auth, src_addr, enc, elen, auth, alen, - 0); + no_defer); break; case FT_PACKET_R0KH_R1KH_PUSH: wpa_ft_rrb_rx_push(wpa_auth, src_addr, enc, elen, auth, alen, - 0); + no_defer); break; case FT_PACKET_R0KH_R1KH_SEQ_REQ: wpa_ft_rrb_rx_seq_req(wpa_auth, src_addr, enc, elen, auth, alen, - 0); + no_defer); break; case FT_PACKET_R0KH_R1KH_SEQ_RESP: wpa_ft_rrb_rx_seq_resp(wpa_auth, src_addr, enc, elen, auth, - alen, 0); + alen, no_defer); break; } } @@ -3079,6 +3522,8 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr) if (!wpa_auth->conf.pmk_r1_push) return; + if (!wpa_auth->conf.r1kh_list) + return; r0 = wpa_auth->ft_pmk_cache->pmk_r0; while (r0) { @@ -3094,7 +3539,10 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr) wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs " "for STA " MACSTR, MAC2STR(addr)); - for (r1kh = wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + for (r1kh = *wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + if (is_zero_ether_addr(r1kh->addr) || + is_zero_ether_addr(r1kh->id)) + continue; if (wpa_ft_rrb_init_r1kh_seq(r1kh) < 0) continue; wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index b364fcee6..316f5d50b 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -74,8 +74,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN); wconf->r0_key_lifetime = conf->r0_key_lifetime; wconf->reassociation_deadline = conf->reassociation_deadline; - wconf->r0kh_list = conf->r0kh_list; - wconf->r1kh_list = conf->r1kh_list; + 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; + wconf->r1kh_list = &conf->r1kh_list; wconf->pmk_r1_push = conf->pmk_r1_push; wconf->ft_over_ds = conf->ft_over_ds; wconf->ft_psk_generate_local = conf->ft_psk_generate_local; diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index aebf75c1f..7ef817f54 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -126,6 +126,7 @@ struct wpa_state_machine { u8 ft_pending_pull_nonce[FT_RRB_NONCE_LEN]; u8 ft_pending_auth_transaction; u8 ft_pending_current_ap[ETH_ALEN]; + int ft_pending_pull_left_retries; #endif /* CONFIG_IEEE80211R_AP */ int pending_1_of_4_timeout;