[RFC 40/56] NAN: Support security processing on NDP done

Andrei Otcheretianski andrei.otcheretianski at intel.com
Sun Dec 7 03:18:49 PST 2025


From: Ilan Peer <ilan.peer at intel.com>

When a Secure Association (SA) NDP is done, keys should only
be installed if the cipher suite used is stronger and newer
than any of the cipher suites used for already established
NDPs.

As the NAN specification only allows a single key for a given
pair of initiator/responder NDIs, add logic to determine if the
newly established keys should be installed.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/nan/nan.c     | 18 ++++++++++++-
 src/nan/nan_i.h   | 30 ++++++++++++++++++++++
 src/nan/nan_sec.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/src/nan/nan.c b/src/nan/nan.c
index b99d3ca8ac..1ed75c20e5 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -88,6 +88,18 @@ static void nan_ndp_setup_stop(struct nan_data *nan, struct nan_peer *peer)
 }
 
 
+static void nan_peer_flush_sec(struct nan_peer_info *info)
+{
+	struct nan_peer_sec_info_entry *cur, *next;
+
+	dl_list_for_each_safe(cur, next, &info->sec,
+			      struct nan_peer_sec_info_entry, list) {
+		dl_list_del(&cur->list);
+		os_free(cur);
+	}
+}
+
+
 static void nan_del_peer(struct nan_data *nan, struct nan_peer *peer)
 {
 	if (!peer)
@@ -121,8 +133,8 @@ static void nan_del_peer(struct nan_data *nan, struct nan_peer *peer)
 	nan_peer_flush_avail(&peer->info);
 	nan_peer_flush_dev_capa(&peer->info);
 	nan_peer_flush_elem_container(&peer->info);
-
 	nan_ndl_reset(nan, peer);
+	nan_peer_flush_sec(&peer->info);
 	os_free(peer);
 }
 
@@ -983,6 +995,7 @@ static struct nan_peer *nan_alloc_peer(struct nan_data *nan)
 	dl_list_init(&peer->info.avail_entries);
 	dl_list_init(&peer->info.dev_capa);
 	dl_list_init(&peer->info.element_container);
+	dl_list_init(&peer->info.sec);
 
 	dl_list_add(&nan->peer_list, &peer->list);
 	dl_list_init(&peer->ndps);
@@ -1195,6 +1208,9 @@ static void nan_ndp_connected(struct nan_data *nan, struct nan_peer *peer)
 		params.peer_ndi = peer->ndp_setup.ndp->init_ndi;
 	}
 
+	nan_sec_ndp_store_keys(nan, peer, params.peer_ndi,
+			       params.local_ndi);
+
 	nan->cfg->ndp_connected(nan->cfg->cb_ctx, &params);
 
 	/* Move the NDP to the list of tracked NDPs */
diff --git a/src/nan/nan_i.h b/src/nan/nan_i.h
index a30311b6e7..2ed7a92e2f 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -271,6 +271,31 @@ struct nan_elem_container_entry {
 	u8 data[];
 };
 
+/*
+ * struct nan_peer_sec_info_entry - NAN peer security information entry
+ *
+ * Maintains the latest security information for an NDI pair.
+ *
+ * @list: used for linking in the peer security info list.
+ * @peer_ndi: Peer NDI address.
+ * @local_ndi: Local NDI address.
+ * @csid: Cipher Suite ID used for the secure NAN communication
+ * @pmk: PMK shared with the peer
+ * @pmkid: PMKID shared with the peer
+ * @ptk: PTK shared with the peer
+ */
+struct nan_peer_sec_info_entry {
+	struct dl_list list;
+
+	u8 peer_ndi[ETH_ALEN];
+	u8 local_ndi[ETH_ALEN];
+
+	enum nan_cipher_suite_id csid;
+	u8 pmk[PMK_LEN];
+	u8 pmkid[PMKID_LEN];
+	struct nan_ptk ptk;
+};
+
 /*
  * struct nan_peer_info - NAN peer information
  *
@@ -279,6 +304,7 @@ struct nan_elem_container_entry {
  * @avail_entries: List of availability entries of the peer.
  * @dev_capa: List of device capabilities of the peer.
  * @element_container: List of element container entries of the peer.
+ * @sec: List of security information entries of the peer.
  */
 struct nan_peer_info {
 	struct os_reltime last_seen;
@@ -286,6 +312,7 @@ struct nan_peer_info {
 	struct dl_list avail_entries;
 	struct dl_list dev_capa;
 	struct dl_list element_container;
+	struct dl_list sec;
 };
 
 /**
@@ -564,4 +591,7 @@ int nan_sec_add_attrs(struct nan_data *nan, struct nan_peer *peer,
 int nan_sec_init_resp(struct nan_data *nan, struct nan_peer *peer);
 int nan_sec_pre_tx(struct nan_data *nan, struct nan_peer *peer,
 		   struct wpabuf *buf);
+void nan_sec_ndp_store_keys(struct nan_data *nan, struct nan_peer *peer,
+			    const u8 *peer_ndi, const u8 *local_ndi);
+
 #endif
diff --git a/src/nan/nan_sec.c b/src/nan/nan_sec.c
index b727b6baf9..cbd74cfe79 100644
--- a/src/nan/nan_sec.c
+++ b/src/nan/nan_sec.c
@@ -1115,3 +1115,68 @@ int nan_sec_pre_tx(struct nan_data *nan, struct nan_peer *peer,
 
 	return ret;
 }
+
+
+/*
+ * nan_sec_ndp_store_keys - Store the NDP keys after successful NDP
+ * establishment
+ *
+ * @nan: NAN module context from nan_init()
+ * @peer: NAN peer for which the NDP was established
+ * @peer_ndi: NDI address of the peer for the NDP that was just established
+ * @local_ndi: Local NDI address for the NDP that was just established
+ */
+void nan_sec_ndp_store_keys(struct nan_data *nan, struct nan_peer *peer,
+			    const u8 *peer_ndi, const u8 *local_ndi)
+{
+	struct nan_ndp *ndp = peer->ndp_setup.ndp;
+	struct nan_ndp_sec *ndp_sec = &peer->ndp_setup.sec;
+	struct nan_peer_sec_info_entry *cur, *next;
+
+	if (!ndp || !ndp_sec->valid || !ndp_sec->i_csid ||
+	    peer->ndp_setup.state != NAN_NDP_STATE_DONE)
+		return;
+
+	if (ndp_sec->i_csid != NAN_CS_SK_CCM_128 &&
+	    ndp_sec->i_csid != NAN_CS_SK_GCM_256)
+		return;
+
+	dl_list_for_each_safe(cur, next, &peer->info.sec,
+			      struct nan_peer_sec_info_entry, list) {
+		if (os_memcmp(peer_ndi, cur->peer_ndi, ETH_ALEN) != 0 ||
+		    os_memcmp(local_ndi, cur->local_ndi, ETH_ALEN) != 0)
+			continue;
+
+		/*
+		 * If NAN_CS_SK_GCM_256 is already used it is the strongest so
+		 * no need to install the new keys. If not, and the candidate is
+		 * also not NAN_CS_SK_GCM_256, then NAN_CS_SK_CCM_128 is already
+		 * used, so no need to installed the new keys
+		 */
+		if (cur->csid == NAN_CS_SK_GCM_256 ||
+		    ndp_sec->i_csid != NAN_CS_SK_GCM_256)
+			return;
+
+		/* Update the current entry with the new key */
+		goto store;
+	}
+
+	cur = os_zalloc(sizeof(*cur));
+	if (!cur) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: SEC: Failed memory allocation for security info");
+		return;
+	}
+
+	dl_list_add(&peer->info.sec, &cur->list);
+	os_memcpy(cur->peer_ndi, peer_ndi, ETH_ALEN);
+	os_memcpy(cur->local_ndi, local_ndi, ETH_ALEN);
+
+store:
+	wpa_printf(MSG_DEBUG, "NAN: SEC: Store security information");
+
+	cur->csid = ndp_sec->i_csid;
+	os_memcpy(cur->pmkid, ndp_sec->i_pmkid, PMKID_LEN);
+	os_memcpy(cur->pmk, ndp_sec->pmk, PMK_LEN);
+	os_memcpy(&cur->ptk, &ndp_sec->ptk, sizeof(cur->ptk));
+}
-- 
2.49.0




More information about the Hostap mailing list