[PATCH 12/44] FT: add expiration to PMK-R0 and PMK-R1 cache

michael-dev at fami-braun.de michael-dev at fami-braun.de
Wed Feb 24 03:53:18 PST 2016


From: Michael Braun <michael-dev at fami-braun.de>

IEEE 802.11-2012 says: MSK has a lifetime that limits PMK_R0 and PMK_R1
lifetime. This is currently stored in r0_key_lifetime, but cache entries
are not actually removed.

This patch assumes a default MSK lifetime to be 3600s when
wpa_auth_derive_ptk_ft is called. This matches the default eapol_reauth
timeout and should probably be passed in from eapol state machine with
some future changes. For PSK, things could be handled quite differently,
but currently are not, as PMK-R0/R1 caching can be avoided for FT_PSK with
some other patch in this queue.

The expiration timeout is then passed form R0KH to R1KH. The R1KH verifies
that the given timeout for sanity, it max not exceed the locally configured
r0_key_lifetime.

Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
---
 hostapd/hostapd.conf |   1 +
 src/ap/ap_config.c   |   1 +
 src/ap/wpa_auth.h    |   6 +-
 src/ap/wpa_auth_ft.c | 198 ++++++++++++++++++++++++++++++++++++++-------------
 4 files changed, 155 insertions(+), 51 deletions(-)

diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 2c18495..f7a3fe8 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1255,6 +1255,7 @@ own_ip_addr=127.0.0.1
 # This is configured with nas_identifier (see RADIUS client section above).
 
 # Default lifetime of the PMK-RO in minutes; range 1..65535
+# (default: 60 minutes; 0 = disable timeout)
 # (dot11FTR0KeyLifetime)
 #r0_key_lifetime=10000
 
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index ce96ed5..7890c07 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -92,6 +92,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 
 #ifdef CONFIG_IEEE80211R
 	bss->ft_over_ds = 1;
+	bss->r0_key_lifetime = 60; /* same as eap_reauth_period */
 #endif /* CONFIG_IEEE80211R */
 
 	bss->radius_das_time_window = 300;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 5ad837a..400828f 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -74,7 +74,7 @@ struct ft_r0kh_r1kh_pull_frame {
 
 #define FT_R0KH_R1KH_RESP_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
 				    FT_R1KH_ID_LEN + ETH_ALEN + PMK_LEN + \
-				    WPA_PMK_NAME_LEN + FT_VLAN_DATA_LEN + 2)
+				    WPA_PMK_NAME_LEN + FT_VLAN_DATA_LEN + 2 + 2)
 #define FT_R0KH_R1KH_RESP_PAD_LEN (8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8)
 struct ft_r0kh_r1kh_resp_frame {
 	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
@@ -88,6 +88,7 @@ struct ft_r0kh_r1kh_resp_frame {
 	u8 pmk_r1[PMK_LEN];
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
 	le16 pairwise;
+	le16 expiresIn;
 	struct ft_vlan vlan;
 	u8 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */
 	u8 key_wrap_extra[8];
@@ -95,7 +96,7 @@ struct ft_r0kh_r1kh_resp_frame {
 
 #define FT_R0KH_R1KH_PUSH_DATA_LEN (4 + FT_R1KH_ID_LEN + ETH_ALEN + \
 				    WPA_PMK_NAME_LEN + PMK_LEN + \
-				    WPA_PMK_NAME_LEN + FT_VLAN_DATA_LEN + 2)
+				    WPA_PMK_NAME_LEN + FT_VLAN_DATA_LEN + 2 + 2)
 #define FT_R0KH_R1KH_PUSH_PAD_LEN (8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8)
 struct ft_r0kh_r1kh_push_frame {
 	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
@@ -112,6 +113,7 @@ struct ft_r0kh_r1kh_push_frame {
 	u8 pmk_r1[PMK_LEN];
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
 	le16 pairwise;
+	le16 expiresIn;
 	struct ft_vlan vlan;
 	u8 pad[FT_R0KH_R1KH_PUSH_PAD_LEN]; /* 8-octet boundary for AES block */
 	u8 key_wrap_extra[8];
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index f600aa7..4007764 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -163,18 +163,19 @@ int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
 
 
 struct wpa_ft_pmk_r0_sa {
-	struct wpa_ft_pmk_r0_sa *next;
+	struct dl_list list;
 	u8 pmk_r0[PMK_LEN];
 	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
 	u8 spa[ETH_ALEN];
 	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
 	struct ft_vlan vlan;
-	/* TODO: expiration, identity, radius_class, EAP type */
+	os_time_t expiration; /* 0 for no expiration */
+	/* TODO: identity, radius_class, EAP type, expiration from EAPOL */
 	int pmk_r1_pushed;
 };
 
 struct wpa_ft_pmk_r1_sa {
-	struct wpa_ft_pmk_r1_sa *next;
+	struct dl_list list;
 	u8 pmk_r1[PMK_LEN];
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
 	u8 spa[ETH_ALEN];
@@ -184,15 +185,83 @@ struct wpa_ft_pmk_r1_sa {
 };
 
 struct wpa_ft_pmk_cache {
-	struct wpa_ft_pmk_r0_sa *pmk_r0;
-	struct wpa_ft_pmk_r1_sa *pmk_r1;
+	struct dl_list pmk_r0;
+	struct dl_list pmk_r1;
 };
 
+
+static void wpa_ft_free_pmk_r0(struct wpa_ft_pmk_r0_sa *r0);
+static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx);
+static void wpa_ft_free_pmk_r1(struct wpa_ft_pmk_r1_sa *r1);
+static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx);
+
+static void wpa_ft_free_pmk_r0(struct wpa_ft_pmk_r0_sa *r0)
+{
+	if (!r0)
+		return;
+
+	dl_list_del(&r0->list);
+	eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
+
+	os_memset(r0->pmk_r0, 0, PMK_LEN);
+	os_free(r0);
+}
+
+
+static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_ft_pmk_r0_sa *r0 = eloop_ctx;
+	struct os_reltime now;
+	int expiresIn;
+
+	os_get_reltime(&now);
+
+	if (!r0)
+		return;
+
+	expiresIn = r0->expiration - now.sec;
+	if (expiresIn > 0) {
+		wpa_printf(MSG_ERROR, "FT: wpa_ft_expire_pmk_r0 called for "
+				      "non-expired entry %p, delete in %ds",
+				      r0, expiresIn);
+		eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
+		eloop_register_timeout(expiresIn + 1, 0,
+				       wpa_ft_expire_pmk_r0, r0, NULL);
+		return;
+	}
+
+	wpa_ft_free_pmk_r0(r0);
+}
+
+
+static void wpa_ft_free_pmk_r1(struct wpa_ft_pmk_r1_sa *r1)
+{
+	if (!r1)
+		return;
+
+	dl_list_del(&r1->list);
+	eloop_cancel_timeout(wpa_ft_expire_pmk_r1, r1, NULL);
+
+	os_memset(r1->pmk_r1, 0, PMK_LEN);
+	os_free(r1);
+}
+
+
+static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_ft_pmk_r1_sa *r1 = eloop_ctx;
+
+	wpa_ft_free_pmk_r1(r1);
+}
+
+
 struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
 {
 	struct wpa_ft_pmk_cache *cache;
 
 	cache = os_zalloc(sizeof(*cache));
+	dl_list_init(&cache->pmk_r0);
+	dl_list_init(&cache->pmk_r1);
 
 	return cache;
 }
@@ -203,20 +272,14 @@ void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
 	struct wpa_ft_pmk_r0_sa *r0, *r0prev;
 	struct wpa_ft_pmk_r1_sa *r1, *r1prev;
 
-	r0 = cache->pmk_r0;
-	while (r0) {
-		r0prev = r0;
-		r0 = r0->next;
-		os_memset(r0prev->pmk_r0, 0, PMK_LEN);
-		os_free(r0prev);
+	dl_list_for_each_safe(r0, r0prev, &cache->pmk_r0,
+			      struct wpa_ft_pmk_r0_sa, list) {
+		wpa_ft_free_pmk_r0(r0);
 	}
 
-	r1 = cache->pmk_r1;
-	while (r1) {
-		r1prev = r1;
-		r1 = r1->next;
-		os_memset(r1prev->pmk_r1, 0, PMK_LEN);
-		os_free(r1prev);
+	dl_list_for_each_safe(r1, r1prev, &cache->pmk_r1,
+			      struct wpa_ft_pmk_r1_sa, list) {
+		wpa_ft_free_pmk_r1(r1);
 	}
 
 	os_free(cache);
@@ -226,12 +289,15 @@ void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
 static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
 			       const u8 *spa, const u8 *pmk_r0,
 			       const u8 *pmk_r0_name, int pairwise,
-			       const struct ft_vlan vlan)
+			       const struct ft_vlan vlan,
+			       const int expiresIn)
 {
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
 	struct wpa_ft_pmk_r0_sa *r0;
+	struct os_reltime now;
 
-	/* TODO: add expiration and limit on number of entries in cache */
+	/* TODO: add limit on number of entries in cache */
+	os_get_reltime(&now);
 
 	r0 = os_zalloc(sizeof(*r0));
 	if (r0 == NULL)
@@ -242,9 +308,14 @@ static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
 	os_memcpy(r0->spa, spa, ETH_ALEN);
 	r0->pairwise = pairwise;
 	os_memcpy(&r0->vlan, &vlan, FT_VLAN_DATA_LEN);
+	if (expiresIn > 0)
+		r0->expiration = now.sec + expiresIn;
+
+	dl_list_add(&cache->pmk_r0, &r0->list);
 
-	r0->next = cache->pmk_r0;
-	cache->pmk_r0 = r0;
+	if (expiresIn > 0)
+		eloop_register_timeout(expiresIn + 1, 0,
+				       wpa_ft_expire_pmk_r0, r0, NULL);
 
 	return 0;
 }
@@ -253,13 +324,14 @@ static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
 static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
 			       const u8 *spa, const u8 *pmk_r0_name,
 			       u8 *pmk_r0, int *pairwise,
-			       struct ft_vlan *vlan)
+			       struct ft_vlan *vlan, int *expiresIn)
 {
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
 	struct wpa_ft_pmk_r0_sa *r0;
+	struct os_reltime now;
 
-	r0 = cache->pmk_r0;
-	while (r0) {
+	os_get_reltime(&now);
+	dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
 		if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
 		    os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
 				    WPA_PMK_NAME_LEN) == 0) {
@@ -268,10 +340,15 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
 				*pairwise = r0->pairwise;
 			if (vlan)
 				os_memcpy(vlan, &r0->vlan, FT_VLAN_DATA_LEN);
+			if (expiresIn && r0->expiration > now.sec)
+				*expiresIn = r0->expiration - now.sec;
+			else if (expiresIn && r0->expiration)
+				*expiresIn = 1;
+			else
+				*expiresIn = 0;
+
 			return 0;
 		}
-
-		r0 = r0->next;
 	}
 
 	return -1;
@@ -281,7 +358,8 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
 static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
 			       const u8 *spa, const u8 *pmk_r1,
 			       const u8 *pmk_r1_name, int pairwise,
-			       const struct ft_vlan vlan)
+			       const struct ft_vlan vlan,
+			       int expiresIn)
 {
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
 	struct wpa_ft_pmk_r1_sa *r1;
@@ -298,8 +376,11 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
 	r1->pairwise = pairwise;
 	os_memcpy(&r1->vlan, &vlan, FT_VLAN_DATA_LEN);
 
-	r1->next = cache->pmk_r1;
-	cache->pmk_r1 = r1;
+	dl_list_add(&cache->pmk_r1, &r1->list);
+
+	if (expiresIn > 0)
+		eloop_register_timeout(expiresIn + 1, 0,
+				       wpa_ft_expire_pmk_r1, r1, NULL);
 
 	return 0;
 }
@@ -313,8 +394,7 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
 	struct wpa_ft_pmk_r1_sa *r1;
 
-	r1 = cache->pmk_r1;
-	while (r1) {
+	dl_list_for_each(r1, &cache->pmk_r1, struct wpa_ft_pmk_r1_sa, list) {
 		if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
 		    os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
 				    WPA_PMK_NAME_LEN) == 0) {
@@ -325,8 +405,6 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
 				os_memcpy(vlan, &r1->vlan, FT_VLAN_DATA_LEN);
 			return 0;
 		}
-
-		r1 = r1->next;
 	}
 
 	return -1;
@@ -405,6 +483,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
 	const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
 	const u8 *ssid = sm->wpa_auth->conf.ssid;
 	size_t ssid_len = sm->wpa_auth->conf.ssid_len;
+	int expiresIn = sm->wpa_auth->conf.r0_key_lifetime * 60;
 	struct ft_vlan vlan;
 
 	if (sm->xxkey_len == 0) {
@@ -424,7 +503,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
 	wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
-			    sm->pairwise, vlan);
+			    sm->pairwise, vlan, expiresIn);
 
 	wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
 			  pmk_r1, sm->pmk_r1_name);
@@ -432,7 +511,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
 		    WPA_PMK_NAME_LEN);
 	wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
-			    sm->pairwise, vlan);
+			    sm->pairwise, vlan, expiresIn);
 
 	return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
 				 sm->wpa_auth->addr, sm->pmk_r1_name,
@@ -1363,6 +1442,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
 	u8 pmk_r0[PMK_LEN];
 	int pairwise;
 	struct ft_vlan vlan;
+	int expiresIn;
 
 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
 
@@ -1414,7 +1494,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
 	os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
 	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, &vlan) < 0) {
+				&pairwise, &vlan, &expiresIn) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
 			   "PMK-R1 pull");
 		return -1;
@@ -1427,6 +1507,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
 		    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),
@@ -1498,6 +1579,8 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
 	u8 *plain;
 	struct ft_remote_r0kh *r0kh;
 	int pairwise, res;
+	int expiresIn;
+	int maxExpiresIn = wpa_auth->conf.r0_key_lifetime * 60;
 
 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
 
@@ -1538,11 +1621,12 @@ 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",
-		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
+		   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",
@@ -1551,8 +1635,10 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
 		   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);
+				  pairwise, f.vlan, expiresIn);
 	wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
 	wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f);
 	os_memset(f.pmk_r1, 0, PMK_LEN);
@@ -1572,6 +1658,8 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
 	struct os_time now;
 	os_time_t tsend;
 	int pairwise;
+	int expiresIn;
+	int maxExpiresIn = wpa_auth->conf.r0_key_lifetime * 60;
 
 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
 
@@ -1625,9 +1713,10 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
 	}
 
 	pairwise = le_to_host16(f.pairwise);
+	expiresIn = le_to_host16(f.expiresIn);
 	wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
-		   MACSTR " pairwise=0x%x",
-		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
+		   MACSTR " pairwise=0x%x expiresIn=%d",
+		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise, expiresIn);
 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
 			f.pmk_r1, PMK_LEN);
 	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
@@ -1636,8 +1725,10 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
 		   le_to_host16(f.vlan.untagged),
 		   f.vlan.tagged[0] ? "+" : "");
 
+	if (expiresIn <= 0 || expiresIn > maxExpiresIn)
+		expiresIn = maxExpiresIn;
 	wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
-			    pairwise, f.vlan);
+			    pairwise, f.vlan, expiresIn);
 	os_memset(f.pmk_r1, 0, PMK_LEN);
 
 	return 0;
@@ -1772,7 +1863,8 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
 static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
 				   struct wpa_ft_pmk_r0_sa *pmk_r0,
 				   struct ft_remote_r1kh *r1kh,
-				   const u8 *s1kh_id, int pairwise)
+				   const u8 *s1kh_id, int pairwise,
+				   int expiresIn)
 {
 	struct ft_r0kh_r1kh_push_frame frame, f;
 	struct os_time now;
@@ -1800,6 +1892,7 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
 	WPA_PUT_LE32(f.timestamp, now.sec);
 	f.pairwise = host_to_le16(pairwise);
 	f.vlan = pmk_r0->vlan;
+	f.expiresIn = host_to_le16(expiresIn);
 	os_memset(f.pad, 0, sizeof(f.pad));
 	plain = ((const u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
 					     timestamp);
@@ -1816,29 +1909,36 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
 
 void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
 {
-	struct wpa_ft_pmk_r0_sa *r0;
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r0_sa *r0, *r0found = NULL;
 	struct ft_remote_r1kh *r1kh;
+	struct os_reltime now;
+	int expiresIn;
 
 	if (!wpa_auth->conf.pmk_r1_push)
 		return;
 
-	r0 = wpa_auth->ft_pmk_cache->pmk_r0;
-	while (r0) {
-		if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
+	dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
+		if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0) {
+			r0found = r0;
 			break;
-		r0 = r0->next;
+		}
 	}
 
+	r0 = r0found;
 	if (r0 == NULL || r0->pmk_r1_pushed)
 		return;
 	r0->pmk_r1_pushed = 1;
+	os_get_reltime(&now);
+	expiresIn = r0->expiration - now.sec;
 
 	wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
 		   "for STA " MACSTR, MAC2STR(addr));
 
 	r1kh = wpa_auth->conf.r1kh_list;
 	while (r1kh) {
-		wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
+		wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise,
+				       expiresIn);
 		r1kh = r1kh->next;
 	}
 }
-- 
1.9.1




More information about the Hostap mailing list