[PATCH 34/97] NAN: Implement spec-compliant security strength comparison

Andrei Otcheretianski andrei.otcheretianski at intel.com
Tue Apr 28 13:05:35 PDT 2026


Per Wi-Fi Aware Specification v4.0 section 7.4, implement proper security
strength ordering for NDP security upgrade scenarios. The spec defines
the following strength ordering (highest to lowest):

- NCS-PK-PASN-256 using a password (SAE)
- NCS-PK-PASN-128 using a password (SAE)
- NCS-SK-256 using a PSK/Passphrase
- NCS-SK-128 using a PSK/Passphrase
- NCS-PK-PASN-256 using opportunistic bootstrapping (PASN)
- NCS-PK-PASN-128 using opportunistic bootstrapping (PASN)
- No security

To distinguish between password and opportunistic pairing, store the
AKMP which was used for pairing.

Add nan_sec_get_strength() to compute numeric strength levels considering
both the cipher suite ID and the authentication method (SAE vs PASN).
Update nan_sec_ndp_store_keys() to use this strength comparison when
deciding whether to update security keys.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/nan/nan_i.h       |  5 +++
 src/nan/nan_pairing.c |  1 +
 src/nan/nan_sec.c     | 72 ++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 70 insertions(+), 8 deletions(-)

diff --git a/src/nan/nan_i.h b/src/nan/nan_i.h
index 748120aa25..1d6956986b 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -302,6 +302,8 @@ struct nan_elem_container_entry {
  * @pmk: PMK shared with the peer
  * @pmkid: PMKID shared with the peer
  * @ptk: PTK shared with the peer
+ * @pairing_akmp: AKMP used for the pairing (see See WPA_KEY_MGMT_*) or
+ * 	zero if PASN pairing was not used for NDP establishment.
  */
 struct nan_peer_sec_info_entry {
 	struct dl_list list;
@@ -313,6 +315,7 @@ struct nan_peer_sec_info_entry {
 	u8 pmk[PMK_LEN];
 	u8 pmkid[PMKID_LEN];
 	struct nan_ptk ptk;
+	int pairing_akmp;
 };
 
 /**
@@ -503,6 +506,7 @@ enum nan_pairing_role {
  * @flags: Bitmap of pairing flags. See NAN_PAIRING_FLAG_*
  * @pending_auth1: Pending PASN Authentication frame 1 to be processed
  * @pairing_csid: Cipher suite ID used for the pairing
+ * @pairing_akmp: AKMP used for the pairing. See WPA_KEY_MGMT_*.
  */
 struct nan_pairing_peer_data {
 	struct nan_pairing_cfg pairing_cfg;
@@ -516,6 +520,7 @@ struct nan_pairing_peer_data {
 	u32 flags;
 	struct wpabuf *pending_auth1;
 	enum nan_cipher_suite_id pairing_csid;
+	int pairing_akmp;
 };
 
 /**
diff --git a/src/nan/nan_pairing.c b/src/nan/nan_pairing.c
index 938925eacf..00df9d5b96 100644
--- a/src/nan/nan_pairing.c
+++ b/src/nan/nan_pairing.c
@@ -602,6 +602,7 @@ static void nan_pairing_done(struct nan_data *nan_data, struct nan_peer *peer)
 
 	peer->pairing.pairing_csid = cipher == WPA_CIPHER_GCMP_256 ?
 		NAN_CS_PK_PASN_256 : NAN_CS_PK_PASN_128;
+	peer->pairing.pairing_akmp = pasn_get_akmp(pasn);
 
 	if (!nan_data->cfg->pairing_cfg.npk_caching ||
 	    !peer->pairing.pairing_cfg.npk_caching ||
diff --git a/src/nan/nan_sec.c b/src/nan/nan_sec.c
index 768a8268b0..7c509b672c 100644
--- a/src/nan/nan_sec.c
+++ b/src/nan/nan_sec.c
@@ -1416,6 +1416,44 @@ int nan_sec_pre_tx(struct nan_data *nan, struct nan_peer *peer,
 }
 
 
+/*
+ * nan_sec_get_strength - Get security strength level for a cipher suite
+ *
+ * Per Wi-Fi Aware Specification v4.0 section 7.4, security strength ordering
+ * (from highest to lowest):
+ * - CSID 8 (NCS-PK-PASN-256) using a password (SAE)
+ * - CSID 7 (NCS-PK-PASN-128) using a password (SAE)
+ * - CSID 2 (NCS-SK-256) using a PSK/Passphrase
+ * - CSID 1 (NCS-SK-128) using a PSK/Passphrase
+ * - CSID 8 (NCS-PK-PASN-256) using opportunistic bootstrapping (PASN)
+ * - CSID 7 (NCS-PK-PASN-128) using opportunistic bootstrapping (PASN)
+ * - No security
+ *
+ * @csid: Cipher suite ID
+ * @pairing_akmp: AKMP used for pairing (to distinguish SAE vs opportunistic)
+ *
+ * Returns: Security strength level (higher = stronger), 0 for no security
+ */
+static int nan_sec_get_strength(enum nan_cipher_suite_id csid, int pairing_akmp)
+{
+	bool is_opportunistic = pairing_akmp == WPA_KEY_MGMT_PASN;
+
+	switch (csid) {
+	case NAN_CS_PK_PASN_256:
+		return is_opportunistic ? 2 : 6;
+	case NAN_CS_PK_PASN_128:
+		return is_opportunistic ? 1 : 5;
+	case NAN_CS_SK_GCM_256:
+		return 4;
+	case NAN_CS_SK_CCM_128:
+		return 3;
+	case NAN_CS_NONE:
+	default:
+		return 0;
+	}
+}
+
+
 /*
  * nan_sec_ndp_store_keys - Store the NDP keys after successful NDP
  * establishment
@@ -1433,6 +1471,8 @@ bool nan_sec_ndp_store_keys(struct nan_data *nan, struct nan_peer *peer,
 	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;
+	int new_strength, cur_strength;
+	int new_akmp = 0;
 
 	if (!ndp || !ndp_sec->valid || !ndp_sec->i_csid ||
 	    peer->ndp_setup.state != NAN_NDP_STATE_DONE)
@@ -1441,6 +1481,12 @@ bool nan_sec_ndp_store_keys(struct nan_data *nan, struct nan_peer *peer,
 	if (!NAN_CS_IS_VALID_NDP(ndp_sec->i_csid))
 		return false;
 
+	/* Get AKMP for the new security association */
+	if (peer->pairing.flags & NAN_PAIRING_FLAG_PAIRED)
+		new_akmp = peer->pairing.pairing_akmp;
+
+	new_strength = nan_sec_get_strength(ndp_sec->i_csid, new_akmp);
+
 	dl_list_for_each_safe(cur, next, &peer->info.sec,
 			      struct nan_peer_sec_info_entry, list) {
 		if (!ether_addr_equal(peer_ndi, cur->peer_ndi) ||
@@ -1448,16 +1494,24 @@ bool nan_sec_ndp_store_keys(struct nan_data *nan, struct nan_peer *peer,
 			continue;
 
 		/*
-		 * The security configuration should be updated if it is
-		 * stronger than the existing one or equal in strength. Since
-		 * GCM-256 is considered stronger than CCM-128, always update if
-		 * it is the current one. Otherwise, update only if the previous
-		 * one was CCMP-128.
+		 * Per Wi-Fi Aware Specification v4.0 section 7.4:
+		 * The security configuration should be updated if the new
+		 * security strength is same or greater than the existing SA.
+		 * Otherwise, the existing higher-strength SA continues to be
+		 * used and any key material derived shall be discarded.
 		 */
-		if (ndp_sec->i_csid == NAN_CS_SK_GCM_256 ||
-		    cur->csid == NAN_CS_SK_CCM_128)
+		cur_strength = nan_sec_get_strength(cur->csid, cur->pairing_akmp);
+
+		wpa_printf(MSG_DEBUG,
+			   "NAN: SEC: Comparing strength: new=%d (csid=%u, akmp=0x%x) vs cur=%d (csid=%u, akmp=0x%x)",
+			   new_strength, ndp_sec->i_csid, new_akmp,
+			   cur_strength, cur->csid, cur->pairing_akmp);
+
+		if (new_strength >= cur_strength)
 			goto store;
 
+		wpa_printf(MSG_DEBUG,
+			   "NAN: SEC: New security weaker than existing, discarding keys");
 		return false;
 	}
 
@@ -1476,10 +1530,12 @@ store:
 	wpa_printf(MSG_DEBUG, "NAN: SEC: Store security information");
 
 	cur->csid = ndp_sec->i_csid;
+	if (peer->pairing.flags & NAN_PAIRING_FLAG_PAIRED)
+		cur->pairing_akmp = peer->pairing.pairing_akmp;
+
 	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));
-
 	return true;
 }
 
-- 
2.53.0




More information about the Hostap mailing list