[PATCH 31/92] NAN: Derive KEK and NPK after pairing

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


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

After a successful pairing, derive the KEK that will be used to
encrypt the Key Data field of the NAN Shared Key Descriptor attribute
in the upcoming followup messages for the NIK exchange.
In addition, if NPK caching is enabled and pairing was performed via
opportunistic bootstarpping, derive the NPK for NPK caching and store
it in the PASN data.

Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
 src/nan/nan_pairing.c | 71 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/src/nan/nan_pairing.c b/src/nan/nan_pairing.c
index e5115e13dc..9a60743117 100644
--- a/src/nan/nan_pairing.c
+++ b/src/nan/nan_pairing.c
@@ -439,6 +439,73 @@ int nan_pairing_initiate_pasn_auth(struct nan_data *nan_data, const u8 *addr,
 }
 
 
+/*
+ * nan_pairing_done - Derive NPK caching related keys after successful pairing
+ *
+ * @nan_data: NAN interface data
+ * @peer: NAN peer with which pairing is being completed
+ *
+ * This function completes the NAN pairing process by deriving the necessary
+ * cryptographic keys (KEK and NPK for opportunistic pairing) when NPK caching
+ * is enabled.
+ */
+static void nan_pairing_done(struct nan_data *nan_data, struct nan_peer *peer)
+{
+	u8 npk[NAN_NPK_LEN];
+	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;
+
+	if (!nan_data->cfg->pairing_cfg.npk_caching ||
+	    !peer->pairing.pairing_cfg.npk_caching)
+		return;
+
+	wpa_printf(MSG_DEBUG, "NAN: Pairing: Derive KEK 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_kek(pasn->ptk.kdk, pasn->ptk.kdk_len, csid,
+				    initiator_nmi, responder_nmi,
+				    &pasn->ptk);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "NAN: Pairing: Failed to derive KEK");
+		return;
+	}
+
+	/* For SAE AKMP, NPK was already derived inside the PASN module and
+	 * stored in pasn->pmk.
+	 * For PASN AKMP, derive NPK here and configure it to the PASN module.
+	 * The NPK will be stored alongside the peer's NIK when the NIK is
+	 * received from the peer.
+	 */
+	if (pasn_get_akmp(pasn) != WPA_KEY_MGMT_PASN)
+		return;
+
+	wpa_printf(MSG_DEBUG, "NAN: Pairing: Derive NPK after PASN pairing");
+
+	ret = nan_crypto_derive_npk(pasn->ptk.kdk, pasn->ptk.kdk_len, csid,
+				    initiator_nmi, responder_nmi, npk,
+				    sizeof(npk));
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "NAN: Pairing: Failed to derive NPK");
+	} else {
+		os_memcpy(pasn->pmk, npk, NAN_NPK_LEN);
+		pasn->pmk_len = NAN_NPK_LEN;
+	}
+}
+
+
 /*
  * nan_pairing_pasn_auth_tx_status - Handle PASN authentication frame TX status
  *
@@ -485,6 +552,8 @@ int nan_pairing_pasn_auth_tx_status(struct nan_data *nan, const u8 *data,
 			nan_pairing_deinit_peer(peer);
 			return -1;
 		}
+
+		nan_pairing_done(nan, peer);
 	}
 
 	wpabuf_free(pasn->frame);
@@ -706,6 +775,8 @@ static int nan_pairing_handle_auth_3(struct nan_data *nan_data,
 					       &pasn->ptk);
 	if (ret < 0 || status != WLAN_STATUS_SUCCESS)
 		nan_pairing_deinit_peer(peer);
+	else if (status == WLAN_STATUS_SUCCESS)
+		nan_pairing_done(nan_data, peer);
 
 	/* Don't clear PASN data if pairing is successful. If caching is
 	 * enabled, it will still be needed when the NIK is received from
-- 
2.53.0




More information about the Hostap mailing list