[PATCH 35/92] NAN: Send NIK after successful pairing
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Wed Apr 22 05:23:26 PDT 2026
From: Avraham Stern <avraham.stern at intel.com>
When NPK caching is enabled, send a followup message with the NIK
from the pairing initiator to the pairing responder after pairing
is completed.
Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
src/nan/nan_pairing.c | 156 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 156 insertions(+)
diff --git a/src/nan/nan_pairing.c b/src/nan/nan_pairing.c
index 9a60743117..01d0720f21 100644
--- a/src/nan/nan_pairing.c
+++ b/src/nan/nan_pairing.c
@@ -506,6 +506,149 @@ static void nan_pairing_done(struct nan_data *nan_data, struct nan_peer *peer)
}
+static void nan_add_kde_hdr(struct wpabuf *buf, u32 kde, size_t data_len)
+{
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, RSN_SELECTOR_LEN + data_len);
+ RSN_SELECTOR_PUT(wpabuf_put(buf, RSN_SELECTOR_LEN), kde);
+}
+
+
+/*
+ * nan_nik_build_key_data - Build NAN Identity Key (NIK) key data buffer
+ *
+ * @nan_data: Pointer to NAN data structure containing configuration
+ *
+ * This function constructs a buffer containing NAN key data elements including:
+ * - NIK KDE (Key Data Encapsulation) with cipher version and NIK value
+ * - Key Lifetime KDE indicating the NIK key lifetime
+ *
+ * Returns: Pointer to allocated wpabuf containing the key data, or NULL
+ * on failure.
+ * Note: Caller is responsible for freeing the returned buffer
+ */
+static struct wpabuf *nan_nik_build_key_data(struct nan_data *nan_data)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(KDE_HDR_LEN + sizeof(struct nan_nik_kde) +
+ KDE_HDR_LEN + sizeof(struct nan_key_lifetime_kde));
+ if (!buf)
+ return NULL;
+
+ nan_add_kde_hdr(buf, NAN_KEY_DATA_NIK, sizeof(struct nan_nik_kde));
+ wpabuf_put_u8(buf, NAN_NIRA_CIPHER_VER_128);
+ wpabuf_put_data(buf, nan_data->cfg->nik, sizeof(nan_data->cfg->nik));
+
+ nan_add_kde_hdr(buf, NAN_KEY_DATA_LIFETIME,
+ sizeof(struct nan_key_lifetime_kde));
+ wpabuf_put_le16(buf, NAN_KEY_LIFETIME_NIK);
+ wpabuf_put_be32(buf, nan_data->cfg->nik_lifetime);
+
+ return buf;
+}
+
+
+/**
+ * nan_send_nik - Send NAN Identity Key (NIK) to a peer
+ *
+ * @nan_data: Pointer to NAN data structure containing configuration and state
+ * @peer: Pointer to the NAN peer structure to send the NIK to
+ *
+ * This function sends the NAN Identity Key (NIK) and the NIK lifetime to a peer
+ * device as part of the NAN pairing process. The NIK is encrypted using the KEK
+ * (Key Encryption Key) derived from PASN and sent in a Shared Key Descriptor
+ * Attribute (SKDA) within a follow-up message.
+ *
+ * Returns: 0 on success, -1 in case NPK caching is disabled or an error
+ */
+static int nan_send_nik(struct nan_data *nan_data, struct nan_peer *peer)
+{
+ struct wpabuf *skda, *key_data;
+ struct wpa_eapol_key *key_desc;
+ u16 info, key_len;
+ int ret;
+ struct wpabuf *encrypted_key_data = NULL;
+ size_t skda_len;
+
+ if (!nan_data->cfg->pairing_cfg.npk_caching) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Pairing: Local NPK caching not enabled, don't send NIK");
+ return 0;
+ }
+
+ if (!peer->pairing.pairing_cfg.npk_caching) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Pairing: Peer NPK caching not enabled, don't send NIK");
+ return 0;
+ }
+
+ if (!peer->pairing.pasn || !peer->pairing.pasn->ptk.kek_len) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Pairing: KEK not available for NIK encryption");
+ return -1;
+ }
+
+ key_data = nan_nik_build_key_data(nan_data);
+ if (!key_data) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Pairing: Failed to build NIK key data");
+ return -1;
+ }
+
+ /* Encrypt the key data using the KEK from the PASN data */
+ encrypted_key_data =
+ nan_crypto_encrypt_key_data(key_data, peer->pairing.pasn->ptk.kek,
+ peer->pairing.pasn->ptk.kek_len);
+ wpabuf_clear_free(key_data);
+ if (!encrypted_key_data) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Pairing: Failed to encrypt NIK key data");
+ return -1;
+ }
+
+ skda_len = sizeof(struct nan_shared_key) +
+ sizeof(struct wpa_eapol_key) + 2 +
+ wpabuf_len(encrypted_key_data);
+
+ skda = wpabuf_alloc(NAN_ATTR_HDR_LEN + skda_len);
+ if (!skda) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Pairing: Failed to allocate SKDA buffer");
+ wpabuf_free(encrypted_key_data);
+ return -1;
+ }
+
+ wpabuf_put_u8(skda, NAN_ATTR_SHARED_KEY_DESCR);
+ wpabuf_put_le16(skda, skda_len);
+ wpabuf_put_u8(skda, peer->pairing.handle);
+
+ key_desc = wpabuf_put(skda, sizeof(*key_desc));
+ os_memset(key_desc, 0, sizeof(*key_desc));
+
+ key_desc->type = NAN_KEY_DESC;
+ info = WPA_KEY_INFO_TYPE_AKM_DEFINED | WPA_KEY_INFO_KEY_TYPE |
+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_ENCR_KEY_DATA;
+ WPA_PUT_BE16(key_desc->key_info, info);
+
+ key_len = wpa_cipher_key_len(peer->pairing.pasn->cipher);
+ WPA_PUT_BE16(key_desc->key_length, key_len);
+
+ wpabuf_put_be16(skda, wpabuf_len(encrypted_key_data));
+ wpabuf_put_buf(skda, encrypted_key_data);
+
+ ret = nan_data->cfg->transmit_followup(nan_data->cfg->cb_ctx,
+ peer->nmi_addr, skda,
+ peer->pairing.handle,
+ peer->pairing.peer_instance_id);
+
+ wpabuf_free(encrypted_key_data);
+ wpabuf_free(skda);
+
+ return ret;
+}
+
+
/*
* nan_pairing_pasn_auth_tx_status - Handle PASN authentication frame TX status
*
@@ -554,6 +697,19 @@ int nan_pairing_pasn_auth_tx_status(struct nan_data *nan, const u8 *data,
}
nan_pairing_done(nan, peer);
+
+ /*
+ * Allow the peer to install the keys before transmitting the
+ * follow up
+ */
+ os_sleep(0, 30000);
+
+ if (nan_send_nik(nan, peer) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Pairing: Failed to send NIK");
+ nan_pairing_deinit_peer(peer);
+ return -1;
+ }
}
wpabuf_free(pasn->frame);
--
2.53.0
More information about the Hostap
mailing list