[PATCHv7 7/8] FT: add support for wildcard R0KH / R1KH
Michael Braun
michael-dev at fami-braun.de
Sat Apr 22 01:46:42 PDT 2017
Enable using FT RRB without configuring each other AP locally. Instead,
broadcast messages are exchanged.
When an R0KH or R1KH is discovered, it is cached for 1d.
When a station uses an invalid or offline r0kh_id, requests are always
broadcasted. In order to avoid this, if r0kh does not reply, a temporary
blacklist entry is added to r0kh_list.
In order 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.
In order to free newly created stations later, the r*kh_list start pointer
in conf needs to be updateable from wpa_auto_ft.c, where only wconf is
accessed.
Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
--
v7:
- remove dynamic entries from r0kh/r1kh list when ft is deconfigured
---
hostapd/config_file.c | 8 +
hostapd/hostapd.conf | 23 ++
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 | 571 +++++++++++++++++++++++++++++++++++++++++++------
src/ap/wpa_auth_glue.c | 8 +-
src/ap/wpa_auth_i.h | 1 +
9 files changed, 565 insertions(+), 69 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 3aef8e4..0bb578c 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2637,6 +2637,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 c5ba0e9..b9ce734 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1459,6 +1459,10 @@ 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 broadcasted.
+# 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: <MAC address> <R1KH-ID> <256-bit key as hex string>
@@ -1468,6 +1472,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 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 = 1d)
+
+# Timeout (milli seconds) for requesting PMK-R1 from R0KH using PULL request
+# and number of retries.
+#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
# 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 6b3d4e8..09cbec3 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 989b071..0d5274a 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 052d809..cfc3ae5 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -704,6 +704,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 6827523..1d726d2 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -99,7 +99,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:
@@ -181,9 +182,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;
@@ -366,6 +371,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 9f9a5f8..fab7fb6 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 {
@@ -991,21 +993,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)
@@ -1032,21 +1040,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)
@@ -1077,6 +1092,164 @@ 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;
+
+ r0kh = *wpa_auth->conf.r0kh_list;
+ while (r0kh) {
+ if (r0kh != timeout_ctx) {
+ r0kh = r0kh->next;
+ continue;
+ }
+ 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);
+ break;
+ }
+}
+
+
+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 == NULL)
+ return NULL;
+
+ 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;
+
+ r1kh = *wpa_auth->conf.r1kh_list;
+ while (r1kh) {
+ if (r1kh != timeout_ctx) {
+ r1kh = r1kh->next;
+ continue;
+ }
+ 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);
+ break;
+ }
+}
+
+
+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 == NULL)
+ 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);
+}
+
+
void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
{
struct ft_remote_r0kh *r0kh;
@@ -1084,7 +1257,10 @@ void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
eloop_cancel_timeout(wpa_ft_rrb_seq_timeout, wpa_auth, ELOOP_ALL_CTX);
- r0kh = wpa_auth->conf.r0kh_list;
+ if (wpa_auth->conf.r0kh_list)
+ r0kh = *wpa_auth->conf.r0kh_list;
+ else
+ r0kh = NULL;
for (; r0kh; r0kh = r0kh->next) {
if (!r0kh->seq)
continue;
@@ -1093,7 +1269,10 @@ void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
r0kh->seq = NULL;
}
- r1kh = wpa_auth->conf.r1kh_list;
+ if (wpa_auth->conf.r1kh_list)
+ r1kh = *wpa_auth->conf.r1kh_list;
+ else
+ r1kh = NULL;
for (; r1kh; r1kh = r1kh->next) {
if (!r1kh->seq)
continue;
@@ -1104,9 +1283,99 @@ void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
}
+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;
+ const u8 *zaddr = (u8 *) "\x00\x00\x00\x00\x00\x00";
+
+ 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_memcpy(r0kh->addr, zaddr, ETH_ALEN);
+ } else
+ wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, zaddr, 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);
}
@@ -1114,11 +1383,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 },
@@ -1138,13 +1410,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 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);
@@ -1160,7 +1457,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;
@@ -1176,13 +1474,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);
@@ -1802,7 +2105,8 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
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");
+ "PMK-R1 and either unknown or blocked "
+ "R0KH-ID or NAK from R0KH");
return WLAN_STATUS_INVALID_PMKID;
}
@@ -1893,6 +2197,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) {
@@ -2174,6 +2479,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) {
@@ -2261,6 +2567,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;
@@ -2288,7 +2598,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
const u16 type = FT_PACKET_R0KH_R1KH_PULL;
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;
@@ -2315,17 +2625,30 @@ 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, noDefer);
+ 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, noDefer);
+ if (!noDefer && 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;
@@ -2333,6 +2656,13 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
src_addr, type, &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,
@@ -2343,6 +2673,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,
@@ -2379,10 +2711,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,
@@ -2404,6 +2734,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, const u8 type,
@@ -2418,7 +2749,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;
@@ -2440,14 +2771,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;
@@ -2455,6 +2803,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,
@@ -2464,6 +2819,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));
@@ -2471,9 +2828,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);
@@ -2506,13 +2865,20 @@ static void ft_finish_pull(struct wpa_state_machine *sm)
size_t resp_ies_len;
u16 status;
+ if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
+ 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);
@@ -2556,7 +2922,7 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
{
const char *msgtype = "pull response";
const u16 type = FT_PACKET_R0KH_R1KH_RESP;
- int ret = -1;
+ int nak, ret = -1;
struct ft_get_sta_ctx ctx;
u8 s1kh_id[ETH_ALEN];
const u8 *f_nonce;
@@ -2578,6 +2944,11 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
ret = wpa_ft_rrb_rx_r1(wpa_auth, src_addr, type, enc, enc_len, auth,
auth_len, msgtype, s1kh_id,
noDefer ? NULL : &wpa_ft_rrb_rx_resp);
+ if (ret == -2) {
+ ret = 0;
+ nak = 1;
+ } else
+ nak = 0;
if (ret < 0)
return -1;
@@ -2586,6 +2957,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);
}
@@ -2618,7 +2992,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;
@@ -2627,6 +3005,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);
@@ -2646,31 +3026,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 == NULL ||
- 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 == NULL ||
- 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,
@@ -2679,6 +3066,39 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth,
os_free(plain); plain = NULL;
+ 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;
@@ -2695,7 +3115,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;
@@ -2703,7 +3123,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);
@@ -2753,6 +3173,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;
@@ -2766,7 +3188,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);
@@ -2789,6 +3212,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) {
@@ -2952,6 +3389,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 noDefer = 0;
wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
MACSTR, MAC2STR(src_addr));
@@ -2969,7 +3407,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;
+ noDefer = 1;
}
if (data_len < sizeof(u16)) {
@@ -2990,23 +3428,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);
+ noDefer);
break;
case FT_PACKET_R0KH_R1KH_RESP:
wpa_ft_rrb_rx_resp(wpa_auth, src_addr, enc, elen, auth, alen,
- 0);
+ noDefer);
break;
case FT_PACKET_R0KH_R1KH_PUSH:
wpa_ft_rrb_rx_push(wpa_auth, src_addr, enc, elen, auth, alen,
- 0);
+ noDefer);
break;
case FT_PACKET_R0KH_R1KH_SEQ_REQ:
wpa_ft_rrb_rx_seq_req(wpa_auth, src_addr, enc, elen, auth, alen,
- 0);
+ noDefer);
break;
case FT_PACKET_R0KH_R1KH_SEQ_RESP:
wpa_ft_rrb_rx_seq_resp(wpa_auth, src_addr, enc, elen, auth,
- alen, 0);
+ alen, noDefer);
break;
}
}
@@ -3064,6 +3502,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) {
@@ -3079,7 +3519,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 b10d8bc..24a4b17 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 4a9c629..3e6c6a1 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -124,6 +124,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;
--
2.1.4
More information about the Hostap
mailing list