[PATCH 70/92] NAN: Derive and report ND-PMK after successful pairing

Andrei Otcheretianski andrei.otcheretianski at intel.com
Wed Apr 22 05:24:01 PDT 2026


From: Avraham Stern <avraham.stern at intel.com>

After a successful pairing, derive the ND-PMK and report it in the
NAN-PAIRING_STATUS message.

Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
 src/common/wpa_ctrl.h           |  2 +-
 src/nan/nan.h                   |  4 +-
 src/nan/nan_pairing.c           | 66 ++++++++++++++++++++++++++++++---
 wpa_supplicant/nan_supplicant.c | 15 ++++++--
 4 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 31ca1529cc..afb207b509 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -257,7 +257,7 @@ extern "C" {
 #define NAN_NIK_RECEIVED "NAN-NIK-RECEIVED "
 
 /* NAN Pairing status
- * <peer address> akmp=<SAE|PASN> cipher=<CCMP|GCMP-256> status=<success|failure>
+ * addr=<peer address> akmp=<SAE|PASN> cipher=<CCMP|GCMP-256> status=<success|failure> [nd_pmk=<hex>]
  */
 #define NAN_PAIRING_STATUS "NAN-PAIRING-STATUS "
 
diff --git a/src/nan/nan.h b/src/nan/nan.h
index ab50545732..c1fe905b03 100644
--- a/src/nan/nan.h
+++ b/src/nan/nan.h
@@ -616,12 +616,14 @@ struct nan_config {
 	 * @cipher: Cipher used in the pairing
 	 * @status: Status of the pairing (WLAN_STATUS_* )
 	 * @ptk: Derived PTK for the pairing (valid only if status is success)
+	 * @nd_pmk: ND-PMK from the pairing (valid only if status is success)
 	 * Returns: 0 if status is WLAN_STATUS_SUCCESS and the key was
 	 *	installed successfully or status is
 	 *	WLAN_STATUS_UNSPECIFIED_FAILURE, -1 otherwise
 	 */
 	int (*pairing_result_cb)(void *ctx, const u8 *peer_addr, int akmp,
-				 int cipher, u8 status, struct wpa_ptk *ptk);
+				 int cipher, u8 status, struct wpa_ptk *ptk,
+				 const u8 *nd_pmk);
 
 	/**
 	 * update_pairing_credentials - Report received NIK and NPK for a peer
diff --git a/src/nan/nan_pairing.c b/src/nan/nan_pairing.c
index 0e2e87d039..8cdef0d727 100644
--- a/src/nan/nan_pairing.c
+++ b/src/nan/nan_pairing.c
@@ -786,6 +786,39 @@ static int nan_send_nik(struct nan_data *nan_data, struct nan_peer *peer)
 	return ret;
 }
 
+static int nan_pairing_derive_nd_pmk(struct nan_data *nan_data,
+				     struct nan_peer *peer, u8 *nd_pmk)
+{
+	struct pasn_data *pasn = peer->pairing.pasn;
+	int cipher = pasn_get_cipher(pasn);
+	enum nan_cipher_suite_id csid;
+	u8 *initiator_nmi, *responder_nmi;
+	int ret;
+
+	wpa_printf(MSG_DEBUG,
+		   "NAN: Pairing: Derive ND-PMK after PASN pairing");
+
+	if (peer->pairing.self_pairing_role == NAN_PAIRING_ROLE_INITIATOR) {
+		initiator_nmi = nan_data->cfg->nmi_addr;
+		responder_nmi = peer->nmi_addr;
+	} else {
+		initiator_nmi = peer->nmi_addr;
+		responder_nmi = nan_data->cfg->nmi_addr;
+	}
+
+	csid = cipher == WPA_CIPHER_GCMP_256 ? NAN_CS_PK_PASN_256 :
+					       NAN_CS_PK_PASN_128;
+
+	ret = nan_crypto_derive_nd_pmk_from_kdk(pasn->ptk.kdk,
+						pasn->ptk.kdk_len, csid,
+						initiator_nmi, responder_nmi,
+						nd_pmk);
+	if (ret)
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Pairing: Failed to derive ND PMK");
+	return ret;
+}
+
 
 /*
  * nan_pairing_pasn_auth_tx_status - Handle PASN authentication frame TX status
@@ -825,10 +858,22 @@ int nan_pairing_pasn_auth_tx_status(struct nan_data *nan, const u8 *data,
 
 	ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked);
 	if (ret == 1) {
+		u8 nd_pmk[PMK_LEN];
+
+		if (pasn->status == WLAN_STATUS_SUCCESS &&
+		    nan_pairing_derive_nd_pmk(nan, peer, nd_pmk)) {
+			pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Pairing: Failed to derive ND PMK");
+		}
+
 		ret = nan->cfg->pairing_result_cb(nan->cfg->cb_ctx,
-						  peer->nmi_addr,
-						  pasn->akmp, pasn->cipher,
-						  pasn->status, &pasn->ptk);
+						  peer->nmi_addr, pasn->akmp,
+						  pasn->cipher, pasn->status,
+						  &pasn->ptk,
+						  pasn->status ==
+						  WLAN_STATUS_SUCCESS ? nd_pmk :
+						  NULL);
 		if (pasn->status != WLAN_STATUS_SUCCESS || ret < 0) {
 			nan_pairing_deinit_peer(peer);
 			return -1;
@@ -1038,7 +1083,7 @@ static int nan_pairing_handle_auth_2(struct nan_data *nan_data,
 						 peer->nmi_addr, pasn->akmp,
 						 pasn->cipher,
 						 WLAN_STATUS_UNSPECIFIED_FAILURE,
-						 NULL);
+						 NULL, NULL);
 		nan_pairing_deinit_peer(peer);
 		return -1;
 	}
@@ -1055,18 +1100,27 @@ static int nan_pairing_handle_auth_3(struct nan_data *nan_data,
 	struct pasn_data *pasn = peer->pairing.pasn;
 	int ret;
 	u8 status = WLAN_STATUS_SUCCESS;
+	u8 nd_pmk[PMK_LEN];
 
 	ret = handle_auth_pasn_3(pasn, nan_data->cfg->nmi_addr, peer->nmi_addr,
 				 mgmt, len);
 	if (ret < 0) {
 		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		wpa_printf(MSG_DEBUG, "NAN: Pairing: Handle Auth3 failed");
+	} else {
+		if (nan_pairing_derive_nd_pmk(nan_data, peer, nd_pmk)) {
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Pairing: Failed to derive ND PMK");
+		}
 	}
 
 	ret = nan_data->cfg->pairing_result_cb(nan_data->cfg->cb_ctx,
 					       peer->nmi_addr, pasn->akmp,
 					       pasn->cipher, status,
-					       &pasn->ptk);
+					       &pasn->ptk,
+					       status == WLAN_STATUS_SUCCESS ?
+					       nd_pmk : NULL);
 	if (ret < 0 || status != WLAN_STATUS_SUCCESS)
 		nan_pairing_deinit_peer(peer);
 	else if (status == WLAN_STATUS_SUCCESS)
@@ -1161,7 +1215,7 @@ int nan_pairing_auth_rx(struct nan_data *nan_data,
 		nan_data->cfg->pairing_result_cb(nan_data->cfg->cb_ctx,
 						 peer->nmi_addr, pasn->akmp,
 						 pasn->cipher, status_code,
-						 NULL);
+						 NULL, NULL);
 		nan_pairing_deinit_peer(peer);
 		wpa_printf(MSG_DEBUG,
 			   "NAN: Pairing: Authentication rejected - status=%u",
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index d7e71c1457..072ce8229f 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -857,18 +857,27 @@ static int wpas_nan_pasn_send_cb(void *ctx, const u8 *data, size_t data_len)
 
 static int wpas_nan_pasn_auth_status_cb(void *ctx, const u8 *peer_addr,
 					int akmp, int cipher, u8 status,
-					struct wpa_ptk *ptk)
+					struct wpa_ptk *ptk, const u8 *nd_pmk)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	enum wpa_alg alg;
 	u8 seq[6];
+	char nd_pmk_hex[2 * PMK_LEN + 1];
+
+	if (nd_pmk)
+		wpa_snprintf_hex(nd_pmk_hex, sizeof(nd_pmk_hex), nd_pmk,
+				 PMK_LEN);
+	else
+		nd_pmk_hex[0] = '\0';
 
 	wpa_msg_global(wpa_s, MSG_INFO,
-		       NAN_PAIRING_STATUS MACSTR " akmp=%s cipher=%s status=%s",
+		       NAN_PAIRING_STATUS "addr=" MACSTR " akmp=%s cipher=%s status=%s%s%s",
 		       MAC2STR(peer_addr),
 		       wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
 		       wpa_cipher_txt(cipher),
-		       status == WLAN_STATUS_SUCCESS ? "success" : "failure");
+		       status == WLAN_STATUS_SUCCESS ? "success" : "failure",
+		       nd_pmk ? " nd_pmk=" : "",
+		       nd_pmk ? nd_pmk_hex : "");
 
 	if (status != WLAN_STATUS_SUCCESS)
 		return 0;
-- 
2.53.0




More information about the Hostap mailing list