[PATCH 91/97] wpa_supplicant: NAN: Support password hex in NDP request/response

Andrei Otcheretianski andrei.otcheretianski at intel.com
Tue Apr 28 13:06:32 PDT 2026


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

Add support for specifying the password as hex for NAN NDP
request/response.

Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
 wpa_supplicant/nan_supplicant.c | 86 ++++++++++++++++++++++++++++-----
 1 file changed, 74 insertions(+), 12 deletions(-)

diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index 14064249bb..6f2292a1ba 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -2456,6 +2456,47 @@ static int wpas_nan_set_ndp_schedule(struct wpa_supplicant *wpa_s,
 }
 
 
+static char * wpas_nan_parse_password_hex(const char *hexstr)
+{
+	size_t len = os_strlen(hexstr);
+	size_t pwd_len;
+	char *pwd;
+	size_t i;
+
+	if (!len || len % 2 != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Invalid password hex length: %zu", len);
+		return NULL;
+	}
+
+	pwd_len = len / 2;
+	pwd = os_malloc(pwd_len + 1);
+	if (!pwd)
+		return NULL;
+
+	if (hexstr2bin(hexstr, (u8 *)pwd, pwd_len) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Invalid password hex data: %s", hexstr);
+		os_free(pwd);
+		return NULL;
+	}
+
+	/* Reject passwords containing NULL bytes (except the terminator) */
+	for (i = 0; i < pwd_len; i++) {
+		if (pwd[i] == '\0') {
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Decoded password contains embedded NUL byte at offset %zu",
+				   i);
+			os_free(pwd);
+			return NULL;
+		}
+	}
+
+	pwd[pwd_len] = '\0';
+	return pwd;
+}
+
+
 static int wpas_nan_fill_nd_pmk(struct wpa_supplicant *wpa_s,
 				struct nan_ndp_params *ndp,
 				int handle,
@@ -2582,7 +2623,7 @@ static int wpas_nan_set_gtk(struct wpa_supplicant *ndi_wpa_s,
 
 /* Command format NAN_NDP_REQUEST handle=<id> ndi=<ifname> peer_nmi=<nmi>
    peer_id=<peer_instance_id> ssi=<hexdata> qos=<slots:latency>
-   [csid = <cipher_suite> <password=<string>|pmk=<hex>>
+   [csid = <cipher_suite> <password=<string>|pwd_hex=<hex>|pmk=<hex>>
    [gtk_csid=<cipher_suite>]] [interface_id=<hex>] */
 int wpas_nan_ndp_request(struct wpa_supplicant *wpa_s, char *cmd)
 {
@@ -2590,7 +2631,8 @@ int wpas_nan_ndp_request(struct wpa_supplicant *wpa_s, char *cmd)
 	struct wpabuf *ssi_buf = NULL;
 	char *token, *context = NULL;
 	char *pos;
-	const char *pwd = NULL, *pmk = NULL;
+	const char *pwd = NULL, *pmk = NULL, *pwd_hex = NULL;
+	char *pwd_decoded = NULL;
 	int handle = -1;
 	int ret = -1;
 	struct wpa_supplicant *ndi_wpa_s = NULL;
@@ -2681,6 +2723,8 @@ int wpas_nan_ndp_request(struct wpa_supplicant *wpa_s, char *cmd)
 			ndp.sec.csid = atoi(pos);
 		} else if (os_strcmp(token, "password") == 0) {
 			pwd = pos;
+		} else if (os_strcmp(token, "pwd_hex") == 0) {
+			pwd_hex = pos;
 		} else if (os_strcmp(token, "pmk") == 0) {
 			pmk = pos;
 		} else if (os_strcmp(token, "interface_id") == 0) {
@@ -2734,14 +2778,20 @@ int wpas_nan_ndp_request(struct wpa_supplicant *wpa_s, char *cmd)
 		goto fail;
 	}
 
-	if (pmk && pwd) {
+	if ((pmk && pwd) || (pmk && pwd_hex) || (pwd && pwd_hex)) {
 		wpa_printf(MSG_INFO,
-			   "NAN: Specify only one of password or pmk");
+			   "NAN: Specify only one of password, pwd_hex or pmk");
 		goto fail;
 	}
 
-	if (wpas_nan_fill_nd_pmk(wpa_s, &ndp, handle,
-				 ndp.ndp_id.peer_nmi, pwd, pmk) < 0) {
+	if (pwd_hex) {
+		pwd_decoded = wpas_nan_parse_password_hex(pwd_hex);
+		if (!pwd_decoded)
+			goto fail;
+	}
+
+	if (wpas_nan_fill_nd_pmk(wpa_s, &ndp, handle, ndp.ndp_id.peer_nmi,
+				 pwd_decoded ? pwd_decoded : pwd, pmk) < 0) {
 		wpa_printf(MSG_INFO,
 			   "NAN: Failed to derive NDP PMK");
 		goto fail;
@@ -2773,6 +2823,7 @@ fail:
 	wpabuf_free(ndp.sched.elems);
 	wpabuf_free(ssi_buf);
 	os_free(ndp.interface_id);
+	os_free(pwd_decoded);
 
 	return ret;
 }
@@ -2805,14 +2856,16 @@ int wpas_nan_ndp_response_set_gtk(struct wpa_supplicant *wpa_s,
    [reason_code=<reject_reason>]
    [ndi=<ifname> handle=<service_handle> init_ndi=<ndi>
    ndp_id=<id> [ssi=<hexdata>] [qos=<slots:latency>]
-   [csid=<csid> <password=<string>|pmk=<hex>]] [interface_id=<hex>] */
+   [csid=<csid> <password=<string>|pwd_hex=<hex>|pmk=<hex>>]]
+   [interface_id=<hex>] */
 int wpas_nan_ndp_response(struct wpa_supplicant *wpa_s, char *cmd)
 {
 	struct nan_ndp_params ndp;
 	struct wpabuf *ssi_buf = NULL;
 	char *token, *context = NULL;
 	char *pos;
-	const char *pwd = NULL, *pmk = NULL;
+	const char *pwd = NULL, *pmk = NULL, *pwd_hex = NULL;
+	char *pwd_decoded = NULL;
 	int handle = -1;
 	int ret = -1;
 	struct wpa_supplicant *ndi_wpa_s = NULL;
@@ -2915,6 +2968,8 @@ int wpas_nan_ndp_response(struct wpa_supplicant *wpa_s, char *cmd)
 			ndp.sec.csid = atoi(pos);
 		} else if (os_strcmp(token, "password") == 0) {
 			pwd = pos;
+		} else if (os_strcmp(token, "pwd_hex") == 0) {
+			pwd_hex = pos;
 		} else if (os_strcmp(token, "pmk") == 0) {
 			pmk = pos;
 		} else if (os_strcmp(token, "interface_id") == 0) {
@@ -2960,14 +3015,20 @@ int wpas_nan_ndp_response(struct wpa_supplicant *wpa_s, char *cmd)
 			goto fail;
 		}
 
-		if (pmk && pwd) {
+		if ((pmk && pwd) || (pmk && pwd_hex) || (pwd && pwd_hex)) {
 			wpa_printf(MSG_INFO,
-				   "NAN: Specify only one of password or pmk");
+				   "NAN: Specify only one of password, pwd_hex or pmk");
 			goto fail;
 		}
 
-		if (wpas_nan_fill_nd_pmk(wpa_s, &ndp, handle,
-					 publisher_nmi, pwd, pmk) < 0) {
+		if (pwd_hex) {
+			pwd_decoded = wpas_nan_parse_password_hex(pwd_hex);
+			if (!pwd_decoded)
+				goto fail;
+		}
+
+		if (wpas_nan_fill_nd_pmk(wpa_s, &ndp, handle, publisher_nmi,
+					 pwd_decoded ? pwd_decoded : pwd, pmk) < 0) {
 			wpa_printf(MSG_INFO, "NAN: Failed to derive NDP PMK");
 			goto fail;
 		}
@@ -3019,6 +3080,7 @@ fail:
 	wpabuf_free(ndp.sched.elems);
 	wpabuf_free(ssi_buf);
 	os_free(ndp.interface_id);
+	os_free(pwd_decoded);
 
 	return ret;
 }
-- 
2.53.0




More information about the Hostap mailing list