[PATCH 4/6] FT: Re-calculate PMK-R0 for pull requests if value is not cached.

Benjamin Berg benjamin at sipsolutions.net
Mon Sep 19 08:47:42 PDT 2016


From: Benjamin Berg <benjamin.berg at open-mesh.com>

The PMK-R0 is usually cached, but it may happen that an item was removed
from the cache already for a client that is still associated.

When this happens, simply recalculate the PMK-R0 for immediate use in the
pull request without caching the result.

Signed-off-by: Benjamin Berg <benjamin.berg at open-mesh.com>
---
 src/ap/wpa_auth.h      |  1 +
 src/ap/wpa_auth_ft.c   | 42 +++++++++++++++++++++++++++++++++++++++---
 src/ap/wpa_auth_glue.c | 15 +++++++++++++++
 3 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index cd70912..7ea2ae5 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -224,6 +224,7 @@ struct wpa_auth_callbacks {
 			  size_t data_len);
 #ifdef CONFIG_IEEE80211R
 	struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+	struct wpa_state_machine * (*get_sta)(void *ctx, const u8 *sta_addr);
 	int (*send_ft_action)(void *ctx, const u8 *dst,
 			      const u8 *data, size_t data_len);
 	int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index a6e277d..c45ff89 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -60,6 +60,15 @@ wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
 }
 
 
+static struct wpa_state_machine *
+wpa_ft_get_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+{
+	if (wpa_auth->cb.get_sta == NULL)
+		return NULL;
+	return wpa_auth->cb.get_sta(wpa_auth->cb.ctx, sta_addr);
+}
+
+
 static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
 			    const u8 *sta_addr,
 			    u8 *tspec_ie, size_t tspec_ielen)
@@ -1405,6 +1414,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
 			      const u8 *src_addr,
 			      const u8 *data, size_t data_len)
 {
+	struct wpa_state_machine *sm;
 	struct ft_r0kh_r1kh_pull_frame f;
 	const u8 *crypt;
 	u8 *plain;
@@ -1412,6 +1422,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
 	u8 r1kh_key[16];
 	struct ft_r0kh_r1kh_resp_frame resp, r;
 	u8 pmk_r0[PMK_LEN];
+	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
 	int pairwise;
 
 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
@@ -1470,9 +1481,34 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
 	os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
 	if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
 				&pairwise) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
-			   "PMK-R1 pull");
-		return -1;
+
+		wpa_printf(MSG_DEBUG, "FT: PMK-R0 not in cache, "
+			   "re-calculating on the fly.");
+
+		/* No cache entry exists, derive the PMK-R0 again. */
+		sm = wpa_ft_get_sta(wpa_auth, f.s1kh_id);
+		if (sm == NULL) {
+			wpa_printf(MSG_DEBUG, "FT: Could not find station to "
+				   "calculate PMK-R0 for.");
+			return -1;
+		}
+
+		wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len,
+				  sm->wpa_auth->conf.ssid,
+				  sm->wpa_auth->conf.ssid_len,
+				  sm->wpa_auth->conf.mobility_domain,
+				  sm->wpa_auth->conf.r0_key_holder,
+				  sm->wpa_auth->conf.r0_key_holder_len,
+				  sm->addr,
+				  pmk_r0, pmk_r0_name);
+
+		if (os_memcmp_const(f.pmk_r0_name, pmk_r0_name,
+				    WPA_PMK_NAME_LEN)) {
+			wpa_printf(MSG_DEBUG, "FT: Newly generated PMKR0Name "
+				   "does not match the PMK-R1 pull request.");
+			return -1;
+		}
+		pairwise = sm->pairwise;
 	}
 
 	wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 90e39a4..4981c49 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -565,6 +565,20 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
 }
 
 
+static struct wpa_state_machine *
+hostapd_wpa_auth_get_sta(void *ctx, const u8 *addr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta != NULL)
+		return sta->wpa_sm;
+	else
+		return NULL;
+}
+
+
 static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
 				size_t len)
 {
@@ -624,6 +638,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 #ifdef CONFIG_IEEE80211R
 	cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
 	cb.add_sta = hostapd_wpa_auth_add_sta;
+	cb.get_sta = hostapd_wpa_auth_get_sta;
 	cb.add_tspec = hostapd_wpa_auth_add_tspec;
 #endif /* CONFIG_IEEE80211R */
 	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
-- 
2.9.3




More information about the Hostap mailing list