[RFC 37/56] NAN: Add support for NDP security Rx flow
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Sun Dec 7 03:18:46 PST 2025
From: Ilan Peer <ilan.peer at intel.com>
Add Rx flow processing and state for NDP security attributes.
Currently support only shared key flows.
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
src/nan/Makefile | 9 +-
src/nan/nan_i.h | 55 ++++
src/nan/nan_sec.c | 590 ++++++++++++++++++++++++++++++++++++++++
wpa_supplicant/Makefile | 1 +
4 files changed, 654 insertions(+), 1 deletion(-)
create mode 100644 src/nan/nan_sec.c
diff --git a/src/nan/Makefile b/src/nan/Makefile
index 7d79a2d77e..ae7879553a 100644
--- a/src/nan/Makefile
+++ b/src/nan/Makefile
@@ -1,2 +1,9 @@
-LIB_OBJS= nan.o nan_util.o nan_ndp.o nan_ndl.o nan_crypto.o
+LIB_OBJS= \
+ nan.o \
+ nan_util.o \
+ nan_ndp.o \
+ nan_ndl.o \
+ nan_crypto.o \
+ nan_sec.o
+
include ../lib.rules
diff --git a/src/nan/nan_i.h b/src/nan/nan_i.h
index 23a153dde9..c54ffe713c 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -43,6 +43,56 @@ struct nan_ptk {
size_t tk_len;
};
+/*
+ * struct nan_ndp_sec - NAN ndp security state
+ *
+ * @present: True iff NDP setup exchange includes security
+ * @valid: True iff the security configuration is valid
+ * @keys_installed: True iff the keys are installed
+ * @replaycnt_ok: True iff replay count ok
+ * @replaycnt: Current replay count
+ * @i_nonce: Initiator nonce
+ * @i_capab: Initiator capabilities
+ * @i_csid: Initiator cipher suite ID
+ * @i_instance_id: Initiator publish instance ID
+ * @i_pmkid: Initiator PMKID
+ * @r_nonce: Responder nonce
+ * @r_capab: Responder capabilities
+ * @r_csid: Responder cipher suite ID
+ * @r_instance_id: Responder instance ID
+ * @r_pmkid: Responder PMKID
+ * @auth_token: Authentication token
+ * @pmk: PMK used for the secure NDP establishment
+ * @ptk: Derived PTK
+ */
+struct nan_ndp_sec {
+ bool present;
+ bool valid;
+ bool keys_installed;
+
+ bool replaycnt_ok;
+ u8 replaycnt[8];
+
+ /* Initiator data */
+ u8 i_nonce[WPA_NONCE_LEN];
+ u8 i_capab;
+ u8 i_csid;
+ u8 i_instance_id;
+ u8 i_pmkid[PMKID_LEN];
+
+ /* Responder data */
+ u8 r_nonce[WPA_NONCE_LEN];
+ u8 r_capab;
+ u8 r_csid;
+ u8 r_instance_id;
+ u8 r_pmkid[PMKID_LEN];
+
+ u8 auth_token[NAN_AUTH_TOKEN_LEN];
+ u8 pmk[PMK_LEN];
+
+ struct nan_ptk ptk;
+};
+
/*
* enum nan_ndp_state - State of NDP establishment
* @NAN_NDP_STATE_NONE: No NDP establishment in progress.
@@ -112,6 +162,7 @@ struct nan_ndp {
* @ssi: Service specific information
* @ssi_len: Service specific information length
* @service_id: Service ID of the service used for NDP setup
+ * @sec: NDP security data
*/
struct nan_ndp_setup {
struct nan_ndp *ndp;
@@ -125,6 +176,7 @@ struct nan_ndp_setup {
u16 ssi_len;
u8 service_id[NAN_SERVICE_ID_LEN];
+ struct nan_ndp_sec sec;
};
/*
@@ -504,4 +556,7 @@ int nan_crypto_calc_auth_token(enum nan_cipher_suite_id cipher,
const u8 *buf, size_t len, u8 *token);
int nan_crypto_key_mic(const u8 *buf, size_t len, const u8 *kck,
size_t kck_len, u8 cipher, u8 *mic);
+void nan_sec_reset(struct nan_data *nan, struct nan_ndp_sec *ndp_sec);
+int nan_sec_rx(struct nan_data *nan, struct nan_peer *peer,
+ struct nan_msg *msg);
#endif
diff --git a/src/nan/nan_sec.c b/src/nan/nan_sec.c
new file mode 100644
index 0000000000..7f84b42a64
--- /dev/null
+++ b/src/nan/nan_sec.c
@@ -0,0 +1,590 @@
+/*
+ * Wi-Fi Aware - NAN Data link security
+ * Copyright (C) 2025 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "common/ieee802_11_common.h"
+#include "nan_i.h"
+
+/*
+ * nan_sec_reset - Reset security state
+ *
+ * @nan: NAN module context from nan_init()
+ * @ndp_sec: NDP security context to reset
+ */
+void nan_sec_reset(struct nan_data *nan, struct nan_ndp_sec *ndp_sec)
+{
+ os_memset(ndp_sec, 0, sizeof(*ndp_sec));
+}
+
+
+static void nan_sec_dump(struct nan_data *nan, struct nan_peer *peer)
+{
+ struct nan_ndp_sec *s = &peer->ndp_setup.sec;
+
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: present=%u, valid=%u, keys_installed=%u",
+ s->present, s->valid, s->keys_installed);
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: i_csid=%u, i_instance_id=%u",
+ s->i_csid, s->i_instance_id);
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: r_csid=%u, r_instance_id=%u",
+ s->r_csid, s->r_instance_id);
+}
+
+
+static int nan_sec_rx_m1_verify(struct nan_data *nan,
+ const struct nan_attrs *attrs)
+{
+ struct nan_sec_ctxt *sc;
+ u16 expected_len;
+
+ expected_len = sizeof(struct nan_cipher_suite_info) +
+ sizeof(struct nan_cipher_suite);
+
+ if (!attrs->cipher_suite_info ||
+ attrs->cipher_suite_info_len < expected_len) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Missing valid cipher suite attribute");
+ return -1;
+ }
+
+ /* Need at least one PMKID */
+ expected_len = sizeof(struct nan_sec_ctxt) + PMKID_LEN;
+
+ if (!attrs->sec_ctxt_info || attrs->sec_ctxt_info_len < expected_len) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Missing valid security context attribute");
+ return -1;
+ }
+
+ sc = (struct nan_sec_ctxt *)attrs->sec_ctxt_info;
+ if (sc->scid != NAN_SEC_CTX_TYPE_PMKID ||
+ le_to_host16(sc->len) != PMKID_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Got unknown security context");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int nan_sec_rx_m1(struct nan_data *nan, struct nan_peer *peer,
+ const struct nan_msg *msg,
+ const struct wpa_eapol_key *key)
+{
+ struct nan_ndp_sec *ndp_sec = &peer->ndp_setup.sec;
+ struct nan_cipher_suite_info *cs_info;
+ struct nan_cipher_suite *cs;
+ struct nan_sec_ctxt *sc;
+ u8 instance_id;
+ int ret;
+
+ if (peer->ndp_setup.state != NAN_NDP_STATE_REQ_RECV) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: Not expecting m1");
+ return -1;
+ }
+
+ ret = nan_sec_rx_m1_verify(nan, &msg->attrs);
+ if (ret)
+ return ret;
+
+ cs_info = (struct nan_cipher_suite_info *)msg->attrs.cipher_suite_info;
+ cs = (struct nan_cipher_suite *)cs_info->cs;
+ sc = (struct nan_sec_ctxt *)msg->attrs.sec_ctxt_info;
+
+ /* Get the cipher suites data */
+ ndp_sec->i_capab = cs_info->capab;
+ ndp_sec->i_csid = cs->csid;
+ ndp_sec->i_instance_id = cs->instance_id;
+
+ instance_id = sc->instance_id;
+
+ if (ndp_sec->i_instance_id && instance_id &&
+ ndp_sec->i_instance_id != instance_id) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: Mismatched instance ID");
+ return -1;
+ }
+
+ os_memcpy(ndp_sec->i_pmkid, sc->ctxt, PMKID_LEN);
+
+ /* Save initiator's nonce */
+ os_memcpy(ndp_sec->i_nonce, key->key_nonce, WPA_NONCE_LEN);
+
+ /* Save the replay counter */
+ os_memcpy(ndp_sec->replaycnt, key->replay_counter,
+ sizeof(key->replay_counter));
+
+ /* Store the authentication token, that is required for m3 MIC */
+ ret = nan_crypto_calc_auth_token(ndp_sec->i_csid, (u8 *)&msg->mgmt->u,
+ msg->len - 24, ndp_sec->auth_token);
+ if (ret)
+ return ret;
+
+ /* The flow will continue, once higher layer ACK the NDP setup */
+ ndp_sec->valid = 1;
+ return 0;
+}
+
+
+static int nan_sec_key_mic_ver(struct nan_data *nan, u8 *buf, size_t len,
+ const struct wpa_eapol_key *key,
+ u8 *kck, size_t kck_len, u8 csid)
+{
+ u8 mic[NAN_KEY_MIC_24_LEN];
+ u8 *pos = (u8 *)(key + 1);
+ u8 mic_len;
+ int ret;
+
+ os_memset(mic, 0, sizeof(mic));
+
+ if (csid == NAN_CS_SK_CCM_128)
+ mic_len = NAN_KEY_MIC_LEN;
+ else if (csid == NAN_CS_SK_GCM_256)
+ mic_len = NAN_KEY_MIC_24_LEN;
+ else
+ return -1;
+
+ os_memcpy(mic, pos, mic_len);
+ os_memset(pos, 0, mic_len);
+
+ ret = nan_crypto_key_mic(buf, len, kck, kck_len, csid, pos);
+ if (ret)
+ return ret;
+
+ if (os_memcmp_const(mic, pos, mic_len) != 0) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: MIC verification failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int nan_sec_rx_m2(struct nan_data *nan, struct nan_peer *peer,
+ const struct nan_msg *msg,
+ const struct wpa_eapol_key *key)
+{
+ struct nan_ndp_sec *ndp_sec = &peer->ndp_setup.sec;
+ struct nan_ndp *ndp = peer->ndp_setup.ndp;
+ struct nan_cipher_suite_info *cs_info;
+ struct nan_cipher_suite *cs;
+ struct nan_ptk tptk;
+ u16 cs_info_len;
+ u8 *pos;
+ int ret;
+
+ if (peer->ndp_setup.state != NAN_NDP_STATE_RES_RECV) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: Not expecting m2");
+ return -1;
+ }
+
+ cs_info = (struct nan_cipher_suite_info *)msg->attrs.cipher_suite_info;
+
+ cs_info_len = sizeof(struct nan_cipher_suite_info) +
+ sizeof(struct nan_cipher_suite);
+
+ if (!cs_info || msg->attrs.cipher_suite_info_len < cs_info_len) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Invalid cipher suite attribute");
+ return -1;
+ }
+
+ cs = (struct nan_cipher_suite *)cs_info->cs;
+
+ /* Get the cipher suites data */
+ ndp_sec->r_capab = cs_info->capab;
+ ndp_sec->r_csid = cs->csid;
+ ndp_sec->r_instance_id = cs->instance_id;
+
+ if (ndp_sec->i_csid != ndp_sec->r_csid) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: i_csid != r_csid (%u, %u)",
+ ndp_sec->i_csid, ndp_sec->r_csid);
+ return -1;
+ }
+
+ /* Save responder's nonce */
+ os_memcpy(ndp_sec->r_nonce, key->key_nonce, WPA_NONCE_LEN);
+
+ /* Note: replay counter should have been verified by caller */
+
+ /* PTK should be derived using NDI addresses */
+ ret = nan_crypto_pmk_to_ptk(ndp_sec->pmk,
+ ndp->init_ndi, ndp->resp_ndi,
+ ndp_sec->i_nonce, ndp_sec->r_nonce,
+ &tptk, ndp_sec->i_csid);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: m2 failed to derive PTK");
+ return ret;
+ }
+
+ /*
+ * Due to the different MIC size, need to handle the fields starting
+ * with the mic differently
+ */
+ pos = (u8 *)(key + 1);
+ if (ndp_sec->i_csid == NAN_CS_SK_CCM_128)
+ pos += NAN_KEY_MIC_LEN;
+ else
+ pos += NAN_KEY_MIC_24_LEN;
+
+ if (WPA_GET_BE16(pos))
+ wpa_printf(MSG_DEBUG, "NAN: SEC: TODO: m2 key data");
+
+ /* Verify MIC */
+ ret = nan_sec_key_mic_ver(nan, (u8 *)&msg->mgmt->u,
+ msg->len - 24, key,
+ tptk.kck, tptk.kck_len,
+ ndp_sec->i_csid);
+ if (ret)
+ return ret;
+
+ /* MIC is verified; save PTK */
+ os_memcpy(&ndp_sec->ptk, &tptk, sizeof(tptk));
+ forced_memzero(&tptk, sizeof(tptk));
+
+ /* Increment the replay counter here to prevent replays */
+ WPA_PUT_BE64(ndp_sec->replaycnt,
+ (WPA_GET_BE64(ndp_sec->replaycnt) + 1));
+ return 0;
+}
+
+
+static int nan_sec_rx_m3(struct nan_data *nan, struct nan_peer *peer,
+ const struct nan_msg *msg,
+ const struct wpa_eapol_key *key)
+{
+ struct nan_ndp_sec *ndp_sec = &peer->ndp_setup.sec;
+ u8 mic[NAN_KEY_MIC_24_LEN];
+ u8 *buf;
+ u8 mic_len;
+ u8 *pos;
+ int ret;
+
+ if (peer->ndp_setup.state != NAN_NDP_STATE_CON_RECV) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: Not expecting m3");
+ return -1;
+ }
+
+ /* Note: replay counter should have been verified by caller */
+
+ /* Verify the i_nonce did not change */
+ if (os_memcmp(key->key_nonce, ndp_sec->i_nonce, WPA_NONCE_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: m3 key nonce mismatch");
+ return -1;
+ }
+
+ /*
+ * In case of m3, the MIC is calculated over the frame body
+ * concatenated with the authentication token
+ */
+ buf = os_malloc(msg->len - 24 + NAN_AUTH_TOKEN_LEN);
+ if (!buf)
+ return -ENOBUFS;
+
+ /*
+ * Due to the different MIC size, need to handle the fields starting
+ * with the mic differently
+ */
+ pos = (u8 *)(key + 1);
+ if (ndp_sec->i_csid == NAN_CS_SK_CCM_128)
+ mic_len = NAN_KEY_MIC_LEN;
+ else
+ mic_len = NAN_KEY_MIC_24_LEN;
+
+ if (WPA_GET_BE16(pos + mic_len))
+ wpa_printf(MSG_DEBUG, "NAN: SEC: TODO: m3 key data");
+
+ /* Copy MIC and os_memset it */
+ os_memcpy(mic, pos, mic_len);
+ os_memset(pos, 0, mic_len);
+ os_memcpy(buf, ndp_sec->auth_token, NAN_AUTH_TOKEN_LEN);
+ os_memcpy(buf + NAN_AUTH_TOKEN_LEN, (u8 *)&msg->mgmt->u, msg->len - 24);
+
+ ret = nan_crypto_key_mic(buf, msg->len - 24 + NAN_AUTH_TOKEN_LEN,
+ ndp_sec->ptk.kck,
+ ndp_sec->ptk.kck_len,
+ ndp_sec->i_csid,
+ pos);
+ os_free(buf);
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: m3 MIC calculation failed");
+ return ret;
+ }
+
+ if (os_memcmp_const(mic, pos, mic_len) != 0) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: m3 MIC verification failed");
+ return -1;
+ }
+
+ forced_memzero(mic, sizeof(mic));
+
+ /* Save replay counter */
+ os_memcpy(ndp_sec->replaycnt, key->replay_counter,
+ sizeof(key->replay_counter));
+ return 0;
+}
+
+
+static int nan_sec_rx_m4(struct nan_data *nan, struct nan_peer *peer,
+ const struct nan_msg *msg,
+ const struct wpa_eapol_key *key)
+{
+ struct nan_ndp_sec *ndp_sec = &peer->ndp_setup.sec;
+ u8 *pos = (u8 *)(key + 1);
+ int ret;
+
+ if (peer->ndp_setup.state != NAN_NDP_STATE_DONE) {
+ wpa_printf(MSG_DEBUG, "NAN: SEC: Not expecting m4");
+ return -1;
+ }
+
+ /* Note: replay counter should have been verified by caller */
+
+ /*
+ * Due to the different MIC size, need to handle the fields starting
+ * with the mic differently
+ */
+ if (ndp_sec->i_csid == NAN_CS_SK_CCM_128)
+ pos += NAN_KEY_MIC_LEN;
+ else
+ pos += NAN_KEY_MIC_24_LEN;
+
+ if (WPA_GET_BE16(pos))
+ wpa_printf(MSG_DEBUG, "NAN: SEC: TODO: m4 key data");
+
+ /* Verify MIC */
+ ret = nan_sec_key_mic_ver(nan, (u8 *)&msg->mgmt->u,
+ msg->len - 24, key,
+ ndp_sec->ptk.kck,
+ ndp_sec->ptk.kck_len,
+ ndp_sec->i_csid);
+ if (ret)
+ return ret;
+
+ /* Increment the replay counter here to prevent replays */
+ WPA_PUT_BE64(ndp_sec->replaycnt,
+ (WPA_GET_BE64(ndp_sec->replaycnt) + 1));
+
+ /* Security negotiation done */
+ return 0;
+}
+
+
+/*
+ * nan_sec_rx - Handle security context for Rx frames
+ *
+ * @nan: NAN module context from nan_init()
+ * @peer: Peer from which the original message was received
+ * @msg: Parsed nan action frame
+ * Returns: 0 on success, negative on failure
+ */
+int nan_sec_rx(struct nan_data *nan, struct nan_peer *peer,
+ struct nan_msg *msg)
+{
+ struct nan_ndp_setup *ndp_setup = &peer->ndp_setup;
+ struct nan_ndp_sec *ndp_sec = &ndp_setup->sec;
+ struct wpa_eapol_key *key;
+ struct nan_shared_key *shared_key_desc;
+ u16 info, total_len, desc, shared_key_desc_len;
+ u8 instance_id, cipher;
+ u8 *pos;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "NAN: SEC: NDP security Rx");
+ nan_sec_dump(nan, peer);
+
+ if (!ndp_sec->present) {
+ if (!ndp_sec->valid)
+ return 0;
+
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: NDP with security but present=0");
+ return -1;
+ }
+
+ shared_key_desc = (struct nan_shared_key *)msg->attrs.shared_key_desc;
+ shared_key_desc_len = msg->attrs.shared_key_desc_len;
+
+ /* Shared key descriptor mandatory in all messages */
+ if (!shared_key_desc || !shared_key_desc_len) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: No shared key descriptor attribute");
+ return -1;
+ }
+
+ /*
+ * As the shared key type depends on the cipher suite negotiated, need
+ * to get the cipher suite to validate the proper length of the
+ * descriptor.
+ */
+ if (ndp_sec->valid) {
+ cipher = ndp_sec->i_csid;
+ } else {
+ struct nan_cipher_suite_info *cs_info;
+ struct nan_cipher_suite *cs;
+
+ /* Exactly one cipher suite should be negotiated */
+ if (!msg->attrs.cipher_suite_info ||
+ msg->attrs.cipher_suite_info_len !=
+ (sizeof(struct nan_cipher_suite_info) +
+ sizeof(struct nan_cipher_suite))) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Missing/bad cipher suite attribute");
+ return -1;
+ }
+
+ cs_info = (struct nan_cipher_suite_info *)
+ msg->attrs.cipher_suite_info;
+ cs = (struct nan_cipher_suite *)cs_info->cs;
+
+ cipher = cs->csid;
+ if (cipher != NAN_CS_SK_CCM_128 &&
+ cipher != NAN_CS_SK_GCM_256) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Unsupported cipher suite=%u",
+ cipher);
+ return -1;
+ }
+ }
+
+ key = (struct wpa_eapol_key *)shared_key_desc->key;
+ pos = (u8 *)(key + 1);
+
+ total_len = sizeof(*key) + 2;
+
+ if (cipher == NAN_CS_SK_CCM_128) {
+ if (shared_key_desc_len <
+ (sizeof(struct nan_shared_key) + sizeof(*key) +
+ NAN_KEY_MIC_LEN + 2)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Shared key descriptor too small");
+ return -1;
+ }
+
+ total_len += NAN_KEY_MIC_LEN +
+ WPA_GET_BE16(pos + NAN_KEY_MIC_LEN);
+
+ if (total_len >
+ (shared_key_desc_len - sizeof(struct nan_shared_key))) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Invalid shared key: payload len");
+ return -1;
+ }
+ } else {
+ if (shared_key_desc_len <
+ (sizeof(struct nan_shared_key) + sizeof(*key) +
+ NAN_KEY_MIC_24_LEN + 2)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Shared key (24) descriptor too small");
+ return -1;
+ }
+
+ total_len += NAN_KEY_MIC_24_LEN +
+ WPA_GET_BE16(pos + NAN_KEY_MIC_24_LEN);
+
+ if (total_len >
+ (shared_key_desc_len - sizeof(struct nan_shared_key))) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Invalid shared key (24): payload len");
+ return -1;
+ }
+ }
+
+ /*
+ * Note: only the fields before the mic are accessed in the function, so
+ * it is safe to continue with the key pointer.
+ */
+
+ /* Note: according to the NAN specification the following fields should
+ * be ignored:
+ * key->len: as the key length is derived from the cipher suite.
+ * key->iv: not needed for AES Key WRAP
+ * key->rsc: to avoid implicit assumption of a single GTK.
+ */
+ if (key->type != NAN_KEY_DESC) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Invalid shared key: key descriptor=0x%x",
+ key->type);
+ return -1;
+ }
+
+ info = WPA_GET_BE16(key->key_info);
+
+ /* Discard EAPOL-Key frames with an unknown descriptor version */
+ desc = info & WPA_KEY_INFO_TYPE_MASK;
+ if (desc != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Invalid shared key: invalid key version=0x%x",
+ desc);
+ return -1;
+ }
+
+ if (ndp_sec->replaycnt_ok &&
+ WPA_GET_BE64(key->replay_counter) <
+ WPA_GET_BE64(ndp_sec->replaycnt)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Replay counter did not increase");
+ return -1;
+ }
+
+ if (info & WPA_KEY_INFO_REQUEST) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Invalid shared key: key request not supported");
+ return -1;
+ } else if (!(info & WPA_KEY_INFO_KEY_TYPE)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Invalid shared key: group handshake not supported");
+ return -1;
+ }
+
+ switch (msg->oui_subtype) {
+ case NAN_SUBTYPE_DATA_PATH_REQUEST:
+ if (!(info & WPA_KEY_INFO_ACK))
+ return -1;
+ ret = nan_sec_rx_m1(nan, peer, msg, key);
+ break;
+ case NAN_SUBTYPE_DATA_PATH_RESPONSE:
+ if (!(info & WPA_KEY_INFO_MIC))
+ return -1;
+ ret = nan_sec_rx_m2(nan, peer, msg, key);
+ break;
+ case NAN_SUBTYPE_DATA_PATH_CONFIRM:
+ if (!(info & WPA_KEY_INFO_MIC) ||
+ !(info & WPA_KEY_INFO_ACK) ||
+ !(info & WPA_KEY_INFO_SECURE))
+ return -1;
+ ret = nan_sec_rx_m3(nan, peer, msg, key);
+ break;
+ case NAN_SUBTYPE_DATA_PATH_KEY_INSTALL:
+ if (!(info & WPA_KEY_INFO_MIC) ||
+ !(info & WPA_KEY_INFO_SECURE))
+ return -1;
+ ret = nan_sec_rx_m4(nan, peer, msg, key);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "NAN: SEC: Invalid frame OUI subtype");
+ return -1;
+ }
+
+ if (ret)
+ return ret;
+
+ instance_id = shared_key_desc->publish_id;
+ if (ndp_sec->i_instance_id && instance_id &&
+ ndp_sec->i_instance_id != instance_id) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: SEC: Mismatch instance ID in shared key descriptor");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index f57bcaf1eb..89d8bf8f78 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -342,6 +342,7 @@ OBJS += ../src/nan/nan_util.o
OBJS += ../src/nan/nan_ndp.o
OBJS += ../src/nan/nan_ndl.o
OBJS += ../src/nan/nan_crypto.o
+OBJS += ../src/nan/nan_sec.o
endif
ifdef CONFIG_OWE
--
2.49.0
More information about the Hostap
mailing list