mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
feat(wifi): NAN multi-credential discovery security
Replace scalar passphrase/PMK in wifi_nan_discovery_security_params_t with wifi_nan_credential_t[N] array (cap 4) per Wi-Fi Aware v4.0 §9.5.21.4. Drop public PMKID array and service-level csid_bitmap. Rename wifi_nan_datapath_security_params_t -> wifi_nan_security_params_t; add wifi_nan_peer_sdf_security_t for multi-PMKID peer-RX. The derive_security_params callback takes (svc_name, sec_cfg, out_derived[]) and runs once per credential on the WiFi task. Split nan_record_own_svc into claim/finalize so the WiFi-task callback finds the pending slot by name and mirrors derived material — no main-task PBKDF2.
This commit is contained in:
@@ -48,19 +48,43 @@ typedef enum {
|
||||
} wifi_nan_security_type_t;
|
||||
|
||||
/**
|
||||
* @brief NAN Datapath security parameters (Spec 6.1.1 - Data Path Request/Response)
|
||||
* @brief NAN single-PMKID security parameters
|
||||
*
|
||||
* @note Shared between WiFi libraries and NAN app layer.
|
||||
* @note Holds one derived ND-PMK + ND-PMKID per spec §7.1.3.5. Used both for
|
||||
* the blob's per-service derived cache (own-side Publish SDF SCIA TX)
|
||||
* and for the host's per-NDL handshake state (M1-M4). Single PMKID is
|
||||
* sufficient because every spec key derivation step yields exactly one
|
||||
* PMKID for a given (PMK, peer NMIs, Service ID) tuple.
|
||||
* Shared between WiFi libraries and NAN app layer.
|
||||
*/
|
||||
typedef struct {
|
||||
wifi_nan_security_type_t type; /**< Security Type (Open/Encrypted) */
|
||||
uint16_t csid_bitmap; /**< Bitmap of Cipher Suite IDs (WIFI_NAN_CSID_BIT_*) */
|
||||
uint8_t nd_pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< ND-PMK (Required for Datapath) */
|
||||
uint16_t csid_bitmap; /**< Selected Cipher Suite ID bit (WIFI_NAN_CSID_BIT_*) */
|
||||
uint8_t nd_pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< ND-PMK */
|
||||
uint8_t nd_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN]; /**< ND-PMKID */
|
||||
uint8_t group_data_prot: 1; /**< Group addressed data frame protection. Reserved: not supported right now. */
|
||||
uint8_t group_mgmt_prot: 1; /**< Group addressed management frame protection. Reserved: not supported right now. */
|
||||
uint8_t reserved: 6; /**< Reserved */
|
||||
} wifi_nan_datapath_security_params_t;
|
||||
} wifi_nan_security_params_t;
|
||||
|
||||
/**
|
||||
* @brief NAN peer security material parsed from Publish/Subscribe SDF SCIA
|
||||
*
|
||||
* @note Per Wi-Fi Aware v4.0 §7.1.3.5, a publisher SDF SCIA may advertise
|
||||
* multiple ND-PMKIDs (one per cached PMK). The receiver stores them
|
||||
* and matches against locally-derived PMKID at NDP-initiation time.
|
||||
* Internal only — not part of the public API. Shared between WiFi
|
||||
* libraries and NAN app layer.
|
||||
*/
|
||||
#define NAN_PEER_MAX_PMKIDS 2 /**< Internal cap; can grow without API impact */
|
||||
typedef struct {
|
||||
uint16_t csid_bitmap; /**< Peer's advertised Cipher Suite ID bitmap */
|
||||
uint8_t num_pmkids; /**< Number of parsed PMKIDs */
|
||||
uint8_t pmkids[NAN_PEER_MAX_PMKIDS][ESP_WIFI_NAN_NDP_PMKID_LEN]; /**< Parsed ND-PMKIDs */
|
||||
uint8_t group_data_prot: 1; /**< Peer advertises group data frame protection */
|
||||
uint8_t group_mgmt_prot: 1; /**< Peer advertises group mgmt frame protection */
|
||||
uint8_t reserved: 6; /**< Reserved */
|
||||
} wifi_nan_peer_sdf_security_t;
|
||||
|
||||
/* NAN Peer info parsed from SDF */
|
||||
struct nan_cb_peer_info {
|
||||
@@ -71,7 +95,7 @@ struct nan_cb_peer_info {
|
||||
uint8_t ssi_ver; /**< SSI version (service_match) */
|
||||
uint8_t *ssi; /**< Service-specific information */
|
||||
uint16_t ssi_len; /**< SSI length in bytes */
|
||||
wifi_nan_discovery_security_params_t *peer_security_params; /**< Peer's discovery security params (cipher / PMKIDs) */
|
||||
wifi_nan_peer_sdf_security_t *peer_security_params; /**< Peer's discovery security params parsed from SDF */
|
||||
nan_vendor_ie_t *vendor_ie; /**< Vendor-specific IE, if any */
|
||||
};
|
||||
|
||||
@@ -167,18 +191,23 @@ struct nan_secure_dp_funcs {
|
||||
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||
|
||||
/* RX-path attribute parsers (CSIA / SCIA / key-desc). */
|
||||
void (*parse_ndp_csia)(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param);
|
||||
void (*parse_ndp_scia)(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param);
|
||||
void (*parse_ndp_csia)(void *frm, size_t buf_len, wifi_nan_security_params_t *param);
|
||||
void (*parse_ndp_scia)(void *frm, size_t buf_len, wifi_nan_security_params_t *param);
|
||||
void (*parse_ndp_key_desc)(void *frm, size_t buf_len, uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||
|
||||
/* Publish-side security parser (called when blob processes inbound publish SDF) */
|
||||
esp_err_t (*parse_publish_security)(const uint8_t *attrs, size_t attrs_len,
|
||||
wifi_nan_discovery_security_params_t *security);
|
||||
wifi_nan_peer_sdf_security_t *security);
|
||||
|
||||
/* Publish-init helper -- derives ND-PMK / ND-PMKID from the publish cfg
|
||||
* passphrase and stores them on the host service record. Result is
|
||||
* unused when CONFIG_ESP_WIFI_NAN_SECURITY=n. */
|
||||
esp_err_t (*derive_security_params)(wifi_nan_publish_cfg_t *cfg);
|
||||
/* Derives ND-PMK + ND-PMKID for each credential in sec_cfg->creds[] and
|
||||
* writes one entry per credential into out_derived[0..num_credentials).
|
||||
* Caller passes service_name + the original publish/subscribe security
|
||||
* cfg. out_derived must point at an array of at least
|
||||
* ESP_WIFI_NAN_MAX_CREDS_PER_SVC entries. All inputs are treated as
|
||||
* read-only. Returns ESP_FAIL or NULL when CONFIG_ESP_WIFI_NAN_SECURITY=n. */
|
||||
esp_err_t (*derive_security_params)(const char *service_name,
|
||||
const wifi_nan_discovery_security_params_t *sec_cfg,
|
||||
wifi_nan_security_params_t *out_derived);
|
||||
|
||||
/* NDP security gate: cipher-suite bitmap for (ndp_id, peer_nmi), or 0 for open. */
|
||||
uint16_t (*get_ndp_security_csid)(uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||
|
||||
@@ -868,7 +868,7 @@ typedef struct {
|
||||
|
||||
#define ESP_WIFI_NAN_NDP_PMK_LEN 32 /**< Length of NAN Datapath PMK */
|
||||
#define ESP_WIFI_NAN_NDP_PMKID_LEN 16 /**< Length of NAN Datapath PMKID */
|
||||
#define ESP_WIFI_NAN_MAX_PMKIDS 2 /**< Maximum number of PMKIDs supported */
|
||||
#define ESP_WIFI_NAN_MAX_CREDS_PER_SVC 4 /**< Maximum number of NAN security credentials per service (passphrase/PMK entries) */
|
||||
|
||||
#define ESP_WIFI_MAX_SVC_NAME_LEN 256 /**< Maximum length of NAN service name */
|
||||
#define ESP_WIFI_MAX_FILTER_LEN 256 /**< Maximum length of NAN service filter */
|
||||
@@ -912,7 +912,7 @@ typedef enum {
|
||||
} wifi_nan_service_type_t;
|
||||
|
||||
/**
|
||||
* @brief NAN Cipher Suite IDs (Spec 4.1.1 & 6.1.1)
|
||||
* @brief NAN Cipher Suite IDs (Wi-Fi Aware v4.0 §4.1.1 & §6.1.1)
|
||||
*
|
||||
* @note Only WIFI_NAN_CSID_NCS_SK_128 is currently supported by the firmware.
|
||||
* The other values are reserved for future support; selecting any of
|
||||
@@ -936,19 +936,37 @@ typedef enum {
|
||||
#define WIFI_NAN_CSID_BIT_NCS_PK_PASN_256 (1 << WIFI_NAN_CSID_NCS_PK_PASN_256)
|
||||
|
||||
/**
|
||||
* @brief NAN Discovery security parameters (Spec 4.1.1 - Publish/Subscribe)
|
||||
* @brief NAN security credential — one passphrase or raw PMK + the cipher it's bound to.
|
||||
*
|
||||
* Per Wi-Fi Aware v4.0 §7.1.3.5 the PMKID derivation formula is cipher-specific
|
||||
* (NCS-SK-128 uses HMAC-SHA-256; NCS-SK-256 uses HMAC-SHA-384), so each
|
||||
* credential must carry the cipher it was provisioned for.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t csid_bitmap; /**< Bitmap of Supported Cipher Suite IDs (WIFI_NAN_CSID_BIT_*) */
|
||||
uint8_t num_pmkids; /**< Number of PMKIDs */
|
||||
uint8_t pmkids[ESP_WIFI_NAN_MAX_PMKIDS][ESP_WIFI_NAN_NDP_PMKID_LEN]; /**< ND-PMKIDs */
|
||||
uint8_t group_data_prot: 1; /**< Group addressed data frame protection. Reserved: not supported right now. */
|
||||
uint8_t group_mgmt_prot: 1; /**< Group addressed management frame protection. Reserved: not supported right now. */
|
||||
uint8_t use_pmk: 1; /**< 0 - Use passphrase, 1 - Use PMK directly */
|
||||
uint8_t reserved: 5; /**< Reserved */
|
||||
char passphrase[MAX_PASSPHRASE_LEN]; /**< NCS-SK passphrase (use_pmk=0). NUL-terminated. */
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< NCS-SK PMK (use_pmk=1). Raw bytes, not NUL-terminated. */
|
||||
uint8_t csid; /**< Cipher Suite ID this credential is for (wifi_nan_cipher_suite_id_t value) */
|
||||
uint8_t use_pmk: 1; /**< 0 - Use passphrase, 1 - Use PMK directly */
|
||||
uint8_t reserved: 7; /**< Reserved */
|
||||
char passphrase[MAX_PASSPHRASE_LEN]; /**< NCS-SK passphrase (use_pmk=0). NUL-terminated. */
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< NCS-SK PMK (use_pmk=1). Raw bytes, not NUL-terminated. */
|
||||
} wifi_nan_credential_t;
|
||||
|
||||
/**
|
||||
* @brief NAN Discovery security parameters (Wi-Fi Aware v4.0 §4.1.1 - Publish/Subscribe)
|
||||
*
|
||||
* Per Wi-Fi Aware v4.0 §9.5.21.4 (SCIA) and §7.1.3.5 the Publish/Subscribe SDF
|
||||
* may advertise multiple ND-PMKIDs (one per provisioned ND-PMK). Applications
|
||||
* provide one or more credentials in @c creds; the stack derives PMK + PMKID
|
||||
* per credential and emits the multi-SCID list. Subscriber-side, the library
|
||||
* walks an incoming publisher's SCID list and matches against any of the
|
||||
* locally-provisioned credentials. The CSIA cipher bitmap advertised on air
|
||||
* is computed by the stack as the union of each credential's @c csid.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t group_data_prot: 1; /**< Group addressed data frame protection. Reserved: not supported right now. */
|
||||
uint8_t group_mgmt_prot: 1; /**< Group addressed management frame protection. Reserved: not supported right now. */
|
||||
uint8_t reserved: 6; /**< Reserved */
|
||||
uint8_t num_credentials; /**< Number of valid entries in @c creds (0..ESP_WIFI_NAN_MAX_CREDS_PER_SVC). 0 = open service. */
|
||||
wifi_nan_credential_t creds[ESP_WIFI_NAN_MAX_CREDS_PER_SVC]; /**< Credentials list. */
|
||||
} wifi_nan_discovery_security_params_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,8 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define WIFI_AP_DEFAULT_MAX_IDLE_PERIOD 292 /**< Default timeout for SoftAP BSS Max Idle. Unit: 1000TUs >**/
|
||||
#define MAX_SSID_LEN 32 /**< Maximum length of SSID */
|
||||
#define MAX_PASSPHRASE_LEN 64 /**< Maximum length of passphrase */
|
||||
|
||||
/**
|
||||
* @brief Wi-Fi mode type
|
||||
@@ -866,7 +868,7 @@ typedef struct {
|
||||
|
||||
#define ESP_WIFI_NAN_NDP_PMK_LEN 32 /**< Length of NAN Datapath PMK */
|
||||
#define ESP_WIFI_NAN_NDP_PMKID_LEN 16 /**< Length of NAN Datapath PMKID */
|
||||
#define ESP_WIFI_NAN_MAX_PMKIDS 2 /**< Maximum number of PMKIDs supported */
|
||||
#define ESP_WIFI_NAN_MAX_CREDS_PER_SVC 4 /**< Maximum number of NAN security credentials per service (passphrase/PMK entries) */
|
||||
|
||||
#define ESP_WIFI_MAX_SVC_NAME_LEN 256 /**< Maximum length of NAN service name */
|
||||
#define ESP_WIFI_MAX_FILTER_LEN 256 /**< Maximum length of NAN service filter */
|
||||
@@ -910,7 +912,7 @@ typedef enum {
|
||||
} wifi_nan_service_type_t;
|
||||
|
||||
/**
|
||||
* @brief NAN Cipher Suite IDs (Spec 4.1.1 & 6.1.1)
|
||||
* @brief NAN Cipher Suite IDs (Wi-Fi Aware v4.0 §4.1.1 & §6.1.1)
|
||||
*
|
||||
* @note Only WIFI_NAN_CSID_NCS_SK_128 is currently supported by the firmware.
|
||||
* The other values are reserved for future support; selecting any of
|
||||
@@ -934,19 +936,37 @@ typedef enum {
|
||||
#define WIFI_NAN_CSID_BIT_NCS_PK_PASN_256 (1 << WIFI_NAN_CSID_NCS_PK_PASN_256)
|
||||
|
||||
/**
|
||||
* @brief NAN Discovery security parameters (Spec 4.1.1 - Publish/Subscribe)
|
||||
* @brief NAN security credential - one passphrase or raw PMK + the cipher it's bound to.
|
||||
*
|
||||
* Per Wi-Fi Aware v4.0 §7.1.3.5 the PMKID derivation formula is cipher-specific
|
||||
* (NCS-SK-128 uses HMAC-SHA-256; NCS-SK-256 uses HMAC-SHA-384), so each
|
||||
* credential must carry the cipher it was provisioned for.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t csid_bitmap; /**< Bitmap of Supported Cipher Suite IDs (WIFI_NAN_CSID_BIT_*) */
|
||||
uint8_t num_pmkids; /**< Number of PMKIDs */
|
||||
uint8_t pmkids[ESP_WIFI_NAN_MAX_PMKIDS][ESP_WIFI_NAN_NDP_PMKID_LEN]; /**< ND-PMKIDs */
|
||||
uint8_t group_data_prot: 1; /**< Group addressed data frame protection. Reserved: not supported right now. */
|
||||
uint8_t group_mgmt_prot: 1; /**< Group addressed management frame protection. Reserved: not supported right now. */
|
||||
uint8_t use_pmk: 1; /**< 0 - Use passphrase, 1 - Use PMK directly */
|
||||
uint8_t reserved: 5; /**< Reserved */
|
||||
char passphrase[MAX_PASSPHRASE_LEN]; /**< NCS-SK passphrase (use_pmk=0). NUL-terminated. */
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< NCS-SK PMK (use_pmk=1). Raw bytes, not NUL-terminated. */
|
||||
uint8_t csid; /**< Cipher Suite ID this credential is for (wifi_nan_cipher_suite_id_t value) */
|
||||
uint8_t use_pmk: 1; /**< 0 - Use passphrase, 1 - Use PMK directly */
|
||||
uint8_t reserved: 7; /**< Reserved */
|
||||
char passphrase[MAX_PASSPHRASE_LEN]; /**< NCS-SK passphrase (use_pmk=0). NUL-terminated. */
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< NCS-SK PMK (use_pmk=1). Raw bytes, not NUL-terminated. */
|
||||
} wifi_nan_credential_t;
|
||||
|
||||
/**
|
||||
* @brief NAN Discovery security parameters (Wi-Fi Aware v4.0 §4.1.1 - Publish/Subscribe)
|
||||
*
|
||||
* Per Wi-Fi Aware v4.0 §9.5.21.4 (SCIA) and §7.1.3.5 the Publish/Subscribe SDF
|
||||
* may advertise multiple ND-PMKIDs (one per provisioned ND-PMK). Applications
|
||||
* provide one or more credentials in @c creds; the stack derives PMK + PMKID
|
||||
* per credential and emits the multi-SCID list. Subscriber-side, the library
|
||||
* walks an incoming publisher's SCID list and matches against any of the
|
||||
* locally-provisioned credentials. The CSIA cipher bitmap advertised on air
|
||||
* is computed by the stack as the union of each credential's @c csid.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t group_data_prot: 1; /**< Group addressed data frame protection. Reserved: not supported right now. */
|
||||
uint8_t group_mgmt_prot: 1; /**< Group addressed management frame protection. Reserved: not supported right now. */
|
||||
uint8_t reserved: 6; /**< Reserved */
|
||||
uint8_t num_credentials; /**< Number of valid entries in @c creds (0..ESP_WIFI_NAN_MAX_CREDS_PER_SVC). 0 = open service. */
|
||||
wifi_nan_credential_t creds[ESP_WIFI_NAN_MAX_CREDS_PER_SVC]; /**< Credentials list. */
|
||||
} wifi_nan_discovery_security_params_t;
|
||||
|
||||
/**
|
||||
@@ -1290,8 +1310,6 @@ typedef enum {
|
||||
WPS_FAIL_REASON_MAX /**< Max WPS fail reason */
|
||||
} wifi_event_sta_wps_fail_reason_t;
|
||||
|
||||
#define MAX_SSID_LEN 32 /**< Maximum length of SSID */
|
||||
#define MAX_PASSPHRASE_LEN 64 /**< Maximum length of passphrase */
|
||||
#define MAX_WPS_AP_CRED 3 /**< Maximum number of AP credentials received from WPS handshake */
|
||||
|
||||
/**
|
||||
|
||||
@@ -111,7 +111,7 @@ struct own_svc_info *nan_find_own_svc(uint8_t svc_id)
|
||||
return p_svc;
|
||||
}
|
||||
|
||||
static struct own_svc_info *nan_find_own_svc_by_name(const char *svc_name)
|
||||
struct own_svc_info *nan_find_own_svc_by_name(const char *svc_name)
|
||||
{
|
||||
struct own_svc_info *p_svc = NULL;
|
||||
|
||||
@@ -271,46 +271,68 @@ static bool nan_services_limit_reached(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void nan_record_own_svc(uint8_t id, uint8_t type, const char svc_name[],
|
||||
bool ndp_resp_needed,
|
||||
const wifi_nan_discovery_security_params_t *security_cfg)
|
||||
/* Pre-claim a slot for an upcoming publish/subscribe service. The slot is
|
||||
* marked with a pending sentinel svc_id (0xFF) so nan_find_own_svc_by_name()
|
||||
* can find it from the derive callback running on the WiFi task — that's how
|
||||
* the host's per-credential derived_security[] mirror gets populated without
|
||||
* a duplicate PBKDF2 pass on the app/main task (which would block IDLE0 and
|
||||
* trip the watchdog). Real svc_id is stamped later by nan_finalize_own_svc(). */
|
||||
#define NAN_SVC_ID_PENDING 0xFF
|
||||
|
||||
static struct own_svc_info *nan_claim_own_svc_slot(uint8_t type, const char svc_name[],
|
||||
const wifi_nan_discovery_security_params_t *security_cfg)
|
||||
{
|
||||
struct own_svc_info *p_svc = NULL;
|
||||
|
||||
for (int i = 0; i < ESP_WIFI_NAN_MAX_SVC_SUPPORTED; i++) {
|
||||
if (s_nan_ctx.own_svc[i].svc_id == 0) {
|
||||
p_svc = &s_nan_ctx.own_svc[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!p_svc) {
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p_svc->svc_id = id;
|
||||
p_svc->svc_id = NAN_SVC_ID_PENDING;
|
||||
p_svc->type = type;
|
||||
strlcpy(p_svc->svc_name, svc_name, ESP_WIFI_MAX_SVC_NAME_LEN);
|
||||
SLIST_INIT(&(p_svc->peer_list));
|
||||
if (type == ESP_NAN_PUBLISH) {
|
||||
p_svc->ndp_resp_needed = ndp_resp_needed;
|
||||
}
|
||||
SLIST_INIT(&p_svc->peer_list);
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
/* Wipe to drop stale PMK material if this slot was previously used. */
|
||||
forced_memzero(&p_svc->security_cfg, sizeof(p_svc->security_cfg));
|
||||
forced_memzero(p_svc->pmk_cache, sizeof(p_svc->pmk_cache));
|
||||
|
||||
forced_memzero(&p_svc->user_cfg, sizeof(p_svc->user_cfg));
|
||||
forced_memzero(&p_svc->derived_security, sizeof(p_svc->derived_security));
|
||||
if (security_cfg) {
|
||||
memcpy(&p_svc->security_cfg, security_cfg, sizeof(wifi_nan_discovery_security_params_t));
|
||||
if (security_cfg->num_pmkids > 0) {
|
||||
memcpy(p_svc->pmk_cache[0], security_cfg->pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
/* Public struct has one pmk[32]; cap num_pmkids to the count we cached. */
|
||||
p_svc->security_cfg.num_pmkids = 1;
|
||||
}
|
||||
memcpy(&p_svc->user_cfg, security_cfg, sizeof(*security_cfg));
|
||||
}
|
||||
#else
|
||||
(void)security_cfg;
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||
#endif
|
||||
return p_svc;
|
||||
}
|
||||
|
||||
/* Stamp the real svc_id and per-publish flags after the blob accepts the
|
||||
* service. Looked up by name since the WiFi-task derive callback may have
|
||||
* already populated derived_security[] before this runs. */
|
||||
static void nan_finalize_own_svc(const char *svc_name, uint8_t id, bool ndp_resp_needed)
|
||||
{
|
||||
struct own_svc_info *p_svc = nan_find_own_svc_by_name(svc_name);
|
||||
if (!p_svc) {
|
||||
return;
|
||||
}
|
||||
p_svc->svc_id = id;
|
||||
if (p_svc->type == ESP_NAN_PUBLISH) {
|
||||
p_svc->ndp_resp_needed = ndp_resp_needed;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release a pending slot when the blob's publish/subscribe call fails. */
|
||||
static void nan_abort_own_svc(const char *svc_name)
|
||||
{
|
||||
struct own_svc_info *p_svc = nan_find_own_svc_by_name(svc_name);
|
||||
if (!p_svc) {
|
||||
return;
|
||||
}
|
||||
forced_memzero(p_svc, sizeof(*p_svc));
|
||||
/* svc_id back to 0 -> slot free */
|
||||
}
|
||||
|
||||
/* A slot is in use once nan_record_new_ndl/preclaim has stamped peer_nmi,
|
||||
@@ -566,9 +588,21 @@ void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info
|
||||
ESP_LOGI(TAG, "Service matched with capabilities: 0x%04x", capab);
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
if (peer_info->peer_security_params) {
|
||||
/* Service-match security gate:
|
||||
* 1. Subscriber configured no credentials (open subscribe) -> accept
|
||||
* regardless of what the peer advertised. NDP will be open.
|
||||
* 2. Subscriber configured credentials (secure subscribe) -> peer
|
||||
* must have advertised PMKIDs AND at least one of them must match
|
||||
* one of the local creds, else drop. */
|
||||
if (nan_security_subscriber_has_creds()) {
|
||||
if (!peer_info->peer_security_params ||
|
||||
peer_info->peer_security_params->num_pmkids == 0) {
|
||||
ESP_LOGW(TAG, "Secure subscribe: peer "MACSTR" advertises no PMKIDs",
|
||||
MAC2STR(pub_mac));
|
||||
return;
|
||||
}
|
||||
if (!nan_security_service_match(pub_mac, peer_info->peer_security_params)) {
|
||||
ESP_LOGD(TAG, "PMKID mismatch with "MACSTR, MAC2STR(pub_mac));
|
||||
ESP_LOGW(TAG, "PMKID mismatch with "MACSTR, MAC2STR(pub_mac));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1382,10 +1416,20 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg)
|
||||
ESP_LOGE(TAG, "Encrypted datapath not enabled (CONFIG_ESP_WIFI_NAN_SECURITY)");
|
||||
goto fail;
|
||||
#else
|
||||
if (!(publish_cfg->security_cfg.csid_bitmap & WIFI_NAN_CSID_BIT_NCS_SK_128)) {
|
||||
ESP_LOGE(TAG, "Unsupported cipher suite in csid_bitmap (only NCS-SK-128 is supported)");
|
||||
if (publish_cfg->security_cfg.num_credentials == 0 ||
|
||||
publish_cfg->security_cfg.num_credentials > ESP_WIFI_NAN_MAX_CREDS_PER_SVC) {
|
||||
ESP_LOGE(TAG, "security_cfg.num_credentials=%u must be 1..%u",
|
||||
publish_cfg->security_cfg.num_credentials,
|
||||
ESP_WIFI_NAN_MAX_CREDS_PER_SVC);
|
||||
goto fail;
|
||||
}
|
||||
for (uint8_t i = 0; i < publish_cfg->security_cfg.num_credentials; i++) {
|
||||
uint8_t csid = publish_cfg->security_cfg.creds[i].csid;
|
||||
if (csid != WIFI_NAN_CSID_NCS_SK_128) {
|
||||
ESP_LOGE(TAG, "creds[%u].csid=%u unsupported (only NCS-SK-128)", i, csid);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1397,24 +1441,31 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg)
|
||||
}
|
||||
memcpy(cfg, publish_cfg, sizeof(*cfg));
|
||||
|
||||
/* Security derivation (PMK, PMKID) now runs in WiFi task context —
|
||||
* the WiFi library calls nan_derive_security_params(cfg) during publish processing.
|
||||
* After esp_nan_internal_publish_service returns, cfg->security_cfg has
|
||||
* the derived PMK and PMKID populated by the WiFi task. */
|
||||
/* Pre-claim host slot BEFORE calling into the blob. Reason: the blob
|
||||
* invokes our derive_security_params callback on the WiFi task and looks
|
||||
* up the host's slot by service name to mirror derived ND-PMK/ND-PMKID
|
||||
* into p_svc->derived_security[]. Doing the derive on WiFi task (not the
|
||||
* app/main task) keeps PBKDF2's hardware-SHA polling off IDLE0 and avoids
|
||||
* tripping the task watchdog when num_credentials > 1. */
|
||||
if (!nan_claim_own_svc_slot(ESP_NAN_PUBLISH, publish_cfg->service_name,
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
&cfg->security_cfg
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
)) {
|
||||
ESP_LOGE(TAG, "No free service slot");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (esp_nan_internal_publish_service(cfg, (uint8_t *) &pub_id, false) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to publish service '%s'", publish_cfg->service_name);
|
||||
nan_abort_own_svc(publish_cfg->service_name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Started Publishing %s [Service ID - %u]", publish_cfg->service_name, pub_id);
|
||||
nan_record_own_svc(pub_id, ESP_NAN_PUBLISH, publish_cfg->service_name, publish_cfg->ndp_resp_needed,
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
&cfg->security_cfg
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
nan_finalize_own_svc(publish_cfg->service_name, pub_id, publish_cfg->ndp_resp_needed);
|
||||
os_free(cfg);
|
||||
NAN_DATA_UNLOCK();
|
||||
|
||||
@@ -1481,10 +1532,20 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe
|
||||
ESP_LOGE(TAG, "Encrypted datapath not enabled (CONFIG_ESP_WIFI_NAN_SECURITY)");
|
||||
return 0;
|
||||
#else
|
||||
if (!(subscribe_cfg->security_cfg.csid_bitmap & WIFI_NAN_CSID_BIT_NCS_SK_128)) {
|
||||
ESP_LOGE(TAG, "Unsupported cipher suite in csid_bitmap (only NCS-SK-128 is supported)");
|
||||
if (subscribe_cfg->security_cfg.num_credentials == 0 ||
|
||||
subscribe_cfg->security_cfg.num_credentials > ESP_WIFI_NAN_MAX_CREDS_PER_SVC) {
|
||||
ESP_LOGE(TAG, "security_cfg.num_credentials=%u must be 1..%u",
|
||||
subscribe_cfg->security_cfg.num_credentials,
|
||||
ESP_WIFI_NAN_MAX_CREDS_PER_SVC);
|
||||
return 0;
|
||||
}
|
||||
for (uint8_t i = 0; i < subscribe_cfg->security_cfg.num_credentials; i++) {
|
||||
uint8_t csid = subscribe_cfg->security_cfg.creds[i].csid;
|
||||
if (csid != WIFI_NAN_CSID_NCS_SK_128) {
|
||||
ESP_LOGE(TAG, "creds[%u].csid=%u unsupported (only NCS-SK-128)", i, csid);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
NAN_DATA_LOCK();
|
||||
@@ -1502,14 +1563,22 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Pre-claim host slot BEFORE the blob's subscribe call; see comment on
|
||||
* the publish path for the watchdog rationale. */
|
||||
if (!nan_claim_own_svc_slot(ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name,
|
||||
&subscribe_cfg->security_cfg)) {
|
||||
ESP_LOGE(TAG, "No free service slot");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (esp_nan_internal_subscribe_service(subscribe_cfg, (uint8_t*) &sub_id, false) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to subscribe to service '%s'", subscribe_cfg->service_name);
|
||||
nan_abort_own_svc(subscribe_cfg->service_name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %u]", subscribe_cfg->service_name, sub_id);
|
||||
nan_record_own_svc((uint8_t) sub_id, ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name, false, &subscribe_cfg->security_cfg);
|
||||
nan_finalize_own_svc(subscribe_cfg->service_name, (uint8_t) sub_id, false);
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
nan_security_cache_subscriber_params(subscribe_cfg->service_name, &subscribe_cfg->security_cfg);
|
||||
#endif
|
||||
|
||||
@@ -162,8 +162,12 @@ struct own_svc_info {
|
||||
|
||||
bool ndp_resp_needed;
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
wifi_nan_discovery_security_params_t security_cfg;
|
||||
uint8_t pmk_cache[ESP_WIFI_NAN_MAX_PMKIDS][ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||
/* App-provided input (creds[] / csid_bitmap / group prot flags). */
|
||||
wifi_nan_discovery_security_params_t user_cfg;
|
||||
/* Derived material — one ND-PMK + ND-PMKID per credential. Mirrors the
|
||||
* per-service array the blob caches in svc_entry->self_security_params[].
|
||||
* Valid entries: [0, user_cfg.num_credentials). */
|
||||
wifi_nan_security_params_t derived_security[ESP_WIFI_NAN_MAX_CREDS_PER_SVC];
|
||||
#endif
|
||||
uint8_t num_peer_records;
|
||||
SLIST_HEAD(peer_list_t, peer_svc_info) peer_list;
|
||||
@@ -178,7 +182,7 @@ struct ndl_info {
|
||||
uint8_t own_role;
|
||||
uint32_t device_caps;
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
wifi_nan_datapath_security_params_t security_ctx;
|
||||
wifi_nan_security_params_t security_ctx;
|
||||
|
||||
uint8_t anonce[NAN_NONCE_LEN];
|
||||
uint8_t snonce[NAN_NONCE_LEN];
|
||||
@@ -233,6 +237,7 @@ extern nan_ctx_t s_nan_ctx;
|
||||
|
||||
/* Helpers defined in nan_app.c, used by nan_security.c */
|
||||
struct own_svc_info *nan_find_own_svc(uint8_t svc_id);
|
||||
struct own_svc_info *nan_find_own_svc_by_name(const char *svc_name);
|
||||
struct ndl_info *nan_find_ndl(uint8_t ndp_id, uint8_t peer_nmi[]);
|
||||
struct ndl_info *nan_find_ndl_by_pub_id_and_peer(uint8_t pub_id, const uint8_t *peer_nmi);
|
||||
|
||||
@@ -291,12 +296,12 @@ int esp_nan_verify_ndp_security_install_mic(uint8_t *m4_body, size_t body_len,
|
||||
uint8_t *key_desc_attr,
|
||||
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||
|
||||
void esp_nan_parse_ndp_csia(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param);
|
||||
void esp_nan_parse_ndp_scia(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param);
|
||||
void esp_nan_parse_ndp_csia(void *frm, size_t buf_len, wifi_nan_security_params_t *param);
|
||||
void esp_nan_parse_ndp_scia(void *frm, size_t buf_len, wifi_nan_security_params_t *param);
|
||||
void esp_nan_parse_ndp_key_desc(void *frm, size_t buf_len, uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||
|
||||
esp_err_t esp_nan_parse_publish_security(const uint8_t *attrs, size_t attrs_len,
|
||||
wifi_nan_discovery_security_params_t *security);
|
||||
wifi_nan_peer_sdf_security_t *security);
|
||||
|
||||
/* Helpers defined in nan_security.c, used by nan_app.c */
|
||||
|
||||
@@ -311,8 +316,12 @@ void nan_security_apply_pending(struct ndl_info *ndl,
|
||||
const uint8_t *peer_nmi,
|
||||
const uint8_t *peer_ndi);
|
||||
|
||||
/* PMK / PMKID derivation entry point used by the publish path. */
|
||||
esp_err_t nan_derive_security_params(wifi_nan_publish_cfg_t *cfg);
|
||||
/* PMK / PMKID derivation entry point used by the publish path. Derives from
|
||||
* (service_name, sec_cfg) (passphrase or PMK) and writes the result into
|
||||
* out_derived. */
|
||||
esp_err_t nan_derive_security_params(const char *service_name,
|
||||
const wifi_nan_discovery_security_params_t *sec_cfg,
|
||||
wifi_nan_security_params_t *out_derived);
|
||||
|
||||
/* Blob-side gate query: returns ndl->security_ctx.csid_bitmap for the NDP
|
||||
* keyed on (ndp_id, peer_nmi), or 0 if no NDL match. ndp_id=0 is valid for
|
||||
@@ -336,13 +345,23 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||
* from the service-match callback.
|
||||
*/
|
||||
bool nan_security_service_match(const uint8_t *publisher_nmi,
|
||||
const wifi_nan_discovery_security_params_t *peer_sec);
|
||||
const wifi_nan_peer_sdf_security_t *peer_sec);
|
||||
|
||||
/* Returns true if the local subscriber configured at least one credential
|
||||
* via the most recent esp_wifi_nan_subscribe_service(). Used by the
|
||||
* service-match gate to decide whether to PMKID-validate an incoming peer. */
|
||||
bool nan_security_subscriber_has_creds(void);
|
||||
#else
|
||||
static inline esp_err_t nan_derive_security_params(wifi_nan_publish_cfg_t *cfg)
|
||||
static inline esp_err_t nan_derive_security_params(const char *service_name,
|
||||
const wifi_nan_discovery_security_params_t *sec_cfg,
|
||||
wifi_nan_security_params_t *out_derived)
|
||||
{
|
||||
(void)cfg;
|
||||
(void)service_name;
|
||||
(void)sec_cfg;
|
||||
(void)out_derived;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
static inline bool nan_security_subscriber_has_creds(void) { return false; }
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -70,6 +70,71 @@ static struct {
|
||||
wifi_nan_discovery_security_params_t security_cfg;
|
||||
} s_nan_subscriber_sec_cache;
|
||||
|
||||
/* Per-peer subscriber match memory: at service-match time
|
||||
* nan_security_service_match identifies which local credential matched the
|
||||
* publisher; we remember (publisher NMI -> matched cred index) so that the
|
||||
* later NDP-init path (nan_security_populate_initiator_ndl) derives M1's pair
|
||||
* PMKID from the *correct* credential instead of always cred[0]. Sized at
|
||||
* NAN_MAX_PEERS_RECORD to cover the realistic peer count; round-robin
|
||||
* eviction on overflow. */
|
||||
#define NAN_SUB_MATCH_CACHE_SIZE NAN_MAX_PEERS_RECORD
|
||||
static struct {
|
||||
bool used;
|
||||
uint8_t peer_nmi[ETH_ALEN];
|
||||
uint8_t matched_cred_idx;
|
||||
} s_nan_subscriber_match_cache[NAN_SUB_MATCH_CACHE_SIZE];
|
||||
static uint8_t s_nan_subscriber_match_cursor;
|
||||
|
||||
static void nan_subscriber_match_remember(const uint8_t *peer_nmi, uint8_t cred_idx)
|
||||
{
|
||||
if (!peer_nmi) {
|
||||
return;
|
||||
}
|
||||
/* Update existing entry for this peer if present. */
|
||||
for (uint8_t i = 0; i < NAN_SUB_MATCH_CACHE_SIZE; i++) {
|
||||
if (s_nan_subscriber_match_cache[i].used &&
|
||||
memcmp(s_nan_subscriber_match_cache[i].peer_nmi, peer_nmi, ETH_ALEN) == 0) {
|
||||
s_nan_subscriber_match_cache[i].matched_cred_idx = cred_idx;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* First free slot. */
|
||||
for (uint8_t i = 0; i < NAN_SUB_MATCH_CACHE_SIZE; i++) {
|
||||
if (!s_nan_subscriber_match_cache[i].used) {
|
||||
s_nan_subscriber_match_cache[i].used = true;
|
||||
memcpy(s_nan_subscriber_match_cache[i].peer_nmi, peer_nmi, ETH_ALEN);
|
||||
s_nan_subscriber_match_cache[i].matched_cred_idx = cred_idx;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Full: round-robin evict. */
|
||||
uint8_t idx = s_nan_subscriber_match_cursor;
|
||||
s_nan_subscriber_match_cursor = (uint8_t)((s_nan_subscriber_match_cursor + 1) % NAN_SUB_MATCH_CACHE_SIZE);
|
||||
s_nan_subscriber_match_cache[idx].used = true;
|
||||
memcpy(s_nan_subscriber_match_cache[idx].peer_nmi, peer_nmi, ETH_ALEN);
|
||||
s_nan_subscriber_match_cache[idx].matched_cred_idx = cred_idx;
|
||||
}
|
||||
|
||||
static int nan_subscriber_match_recall(const uint8_t *peer_nmi)
|
||||
{
|
||||
if (!peer_nmi) {
|
||||
return -1;
|
||||
}
|
||||
for (uint8_t i = 0; i < NAN_SUB_MATCH_CACHE_SIZE; i++) {
|
||||
if (s_nan_subscriber_match_cache[i].used &&
|
||||
memcmp(s_nan_subscriber_match_cache[i].peer_nmi, peer_nmi, ETH_ALEN) == 0) {
|
||||
return (int)s_nan_subscriber_match_cache[i].matched_cred_idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void nan_subscriber_match_clear(void)
|
||||
{
|
||||
memset(s_nan_subscriber_match_cache, 0, sizeof(s_nan_subscriber_match_cache));
|
||||
s_nan_subscriber_match_cursor = 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Static helpers
|
||||
*-----------------------------------------------------------------------*/
|
||||
@@ -98,22 +163,6 @@ static const uint8_t *nan_find_attr(const uint8_t *attrs, size_t attrs_len,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pick the highest-priority cipher suite the local device implements from
|
||||
* the negotiated CSIA bitmap. Only NCS-SK-128 is wired through the rest of
|
||||
* the M1–M4 path today (PTK length, MIC length, KCK/KEK lengths in
|
||||
* nan_i.h are 128-bit-specific); 256-bit and PK suites are intentionally
|
||||
* not selected here — return 0 to signal "no supported suite" so callers
|
||||
* fail negotiation rather than dispatching to a half-implemented path.
|
||||
*/
|
||||
static uint8_t nan_get_first_csid(uint16_t csid_bitmap)
|
||||
{
|
||||
if (csid_bitmap & WIFI_NAN_CSID_BIT_NCS_SK_128) {
|
||||
return WIFI_NAN_CSID_NCS_SK_128;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Service ID = first 6 bytes of SHA256(lowercase(service_name))
|
||||
* per Wi-Fi Aware v4.0 §5.1.5 (Service Name and Service ID).
|
||||
@@ -211,25 +260,22 @@ static bool nan_derive_ndp_request_pmkid(const uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_
|
||||
}
|
||||
|
||||
/*
|
||||
* Match peer's ND-PMKID (from NDP Request/SCIA) against our PMK cache.
|
||||
* Match peer's ND-PMKID (from NDP Request/SCIA) against our per-credential
|
||||
* PMK cache. Returns the index in p_svc->derived_security[] that matched, or
|
||||
* -1 if no credential matches.
|
||||
*
|
||||
* Rule: Do NOT compare NDP Request PMKID to Publish-PMKID — they differ by design.
|
||||
* - Publish SCIA PMKID uses IAddr = FF:FF:FF:FF:FF:FF (initiator-independent).
|
||||
* - NDP Request SCIA PMKID uses Initiator NMI and Responder NMI (pair-specific).
|
||||
*/
|
||||
static bool nan_match_pmkid(struct own_svc_info *p_svc,
|
||||
const uint8_t peer_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN],
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN],
|
||||
const uint8_t *peer_nmi,
|
||||
const uint8_t *peer_ndi)
|
||||
static int nan_match_pmkid(struct own_svc_info *p_svc,
|
||||
const uint8_t peer_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN],
|
||||
const uint8_t *peer_nmi,
|
||||
const uint8_t *peer_ndi)
|
||||
{
|
||||
(void)peer_ndi;
|
||||
|
||||
if (!p_svc || !peer_pmkid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!peer_nmi || !p_svc->svc_name[0]) {
|
||||
if (!p_svc || !peer_pmkid || !peer_nmi || !p_svc->svc_name[0]) {
|
||||
goto no_match;
|
||||
}
|
||||
|
||||
@@ -248,40 +294,30 @@ static bool nan_match_pmkid(struct own_svc_info *p_svc,
|
||||
ESP_LOGD(TAG, " Initiator NMI (peer): "MACSTR, MAC2STR(peer_nmi));
|
||||
ESP_LOGD(TAG, " Responder NMI (us): "MACSTR, MAC2STR(our_nmi));
|
||||
|
||||
/* Cap loop at array bound; guards against unsanitized num_pmkids. */
|
||||
uint8_t cached = p_svc->security_cfg.num_pmkids;
|
||||
if (cached > ESP_WIFI_NAN_MAX_PMKIDS) {
|
||||
cached = ESP_WIFI_NAN_MAX_PMKIDS;
|
||||
}
|
||||
for (int i = 0; i < cached; i++) {
|
||||
for (uint8_t i = 0; i < p_svc->user_cfg.num_credentials; i++) {
|
||||
uint8_t expected_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN];
|
||||
const uint8_t *own_pmk = p_svc->derived_security[i].nd_pmk;
|
||||
|
||||
/* Spec order: Initiator NMI, Responder NMI */
|
||||
if (nan_derive_ndp_request_pmkid(p_svc->pmk_cache[i], peer_nmi, our_nmi,
|
||||
service_id, expected_pmkid)) {
|
||||
if (memcmp(expected_pmkid, peer_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN) == 0) {
|
||||
if (pmk) {
|
||||
memcpy(pmk, p_svc->pmk_cache[i], ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (nan_derive_ndp_request_pmkid(own_pmk, peer_nmi, our_nmi,
|
||||
service_id, expected_pmkid) &&
|
||||
memcmp(expected_pmkid, peer_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN) == 0) {
|
||||
ESP_LOGD(TAG, "PMKID matched at credential slot %u", i);
|
||||
return (int)i;
|
||||
}
|
||||
|
||||
/* Fallback: try reversed order in case peer implementation differs */
|
||||
if (nan_derive_ndp_request_pmkid(p_svc->pmk_cache[i], our_nmi, peer_nmi,
|
||||
service_id, expected_pmkid)) {
|
||||
if (memcmp(expected_pmkid, peer_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN) == 0) {
|
||||
if (pmk) {
|
||||
memcpy(pmk, p_svc->pmk_cache[i], ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (nan_derive_ndp_request_pmkid(own_pmk, our_nmi, peer_nmi,
|
||||
service_id, expected_pmkid) &&
|
||||
memcmp(expected_pmkid, peer_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN) == 0) {
|
||||
ESP_LOGD(TAG, "PMKID matched at credential slot %u (reversed)", i);
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
no_match:
|
||||
ESP_LOGW(TAG, "PMKID not found in our cache (no match)");
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -693,69 +729,101 @@ static uint8_t nan_keyinfo_to_msg_type(uint16_t key_info)
|
||||
* Public API: PMK/PMKID derivation for publish
|
||||
*-----------------------------------------------------------------------*/
|
||||
|
||||
esp_err_t nan_derive_security_params(wifi_nan_publish_cfg_t *cfg)
|
||||
esp_err_t nan_derive_security_params(const char *service_name,
|
||||
const wifi_nan_discovery_security_params_t *sec_cfg,
|
||||
wifi_nan_security_params_t *out_derived)
|
||||
{
|
||||
uint8_t pmk[32];
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||
uint8_t service_id[6];
|
||||
uint8_t pmkid[16];
|
||||
uint8_t hash[32];
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
|
||||
/* 1. Service ID = SHA256(lowercase service name)[:6] */
|
||||
if (!nan_compute_service_id(cfg->service_name, service_id)) {
|
||||
ESP_LOGE(TAG, "Service ID derivation failed");
|
||||
goto cleanup;
|
||||
if (!service_name || !sec_cfg || !out_derived) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (sec_cfg->num_credentials == 0 ||
|
||||
sec_cfg->num_credentials > ESP_WIFI_NAN_MAX_CREDS_PER_SVC) {
|
||||
ESP_LOGE(TAG, "Invalid num_credentials=%u (cap %u)",
|
||||
sec_cfg->num_credentials, ESP_WIFI_NAN_MAX_CREDS_PER_SVC);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Security derivation: svc='%s'", cfg->service_name);
|
||||
memset(out_derived, 0,
|
||||
sizeof(*out_derived) * ESP_WIFI_NAN_MAX_CREDS_PER_SVC);
|
||||
|
||||
if (!nan_compute_service_id(service_name, service_id)) {
|
||||
ESP_LOGE(TAG, "Service ID derivation failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) {
|
||||
ESP_LOGE(TAG, "hmac_sha256_vector not registered");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Security derivation: svc='%s' num_creds=%u",
|
||||
service_name, sec_cfg->num_credentials);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, service_id, 6, ESP_LOG_DEBUG);
|
||||
|
||||
/* 2. PMK from passphrase (or directly provided) */
|
||||
if (cfg->security_cfg.use_pmk) {
|
||||
memcpy(pmk, cfg->security_cfg.pmk, 32);
|
||||
} else {
|
||||
uint8_t publisher_nmi[ETH_ALEN];
|
||||
uint8_t csid = nan_get_first_csid(cfg->security_cfg.csid_bitmap);
|
||||
|
||||
if (csid == 0) {
|
||||
ESP_LOGE(TAG, "No cipher suite in bitmap");
|
||||
goto cleanup;
|
||||
}
|
||||
esp_wifi_get_mac(WIFI_IF_NAN, publisher_nmi);
|
||||
if (nan_derive_nd_pmk_from_passphrase(cfg->security_cfg.passphrase, csid,
|
||||
service_id, publisher_nmi, pmk) != 0) {
|
||||
ESP_LOGE(TAG, "PBKDF2 ND-PMK derivation failed");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* 3. Publish PMKID uses IAddr = ff:ff:ff:ff:ff:ff (initiator-independent).
|
||||
* Pair-specific PMKID for NDP Request is derived separately. */
|
||||
/* Publish-side PMKID uses IAddr=ff:ff:ff:ff:ff:ff (initiator-independent);
|
||||
* pair-specific PMKID for NDP Request derived separately. */
|
||||
uint8_t i_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
uint8_t r_addr[6];
|
||||
esp_wifi_get_mac(WIFI_IF_NAN, r_addr);
|
||||
|
||||
if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) {
|
||||
ESP_LOGE(TAG, "hmac_sha256_vector not registered");
|
||||
goto cleanup;
|
||||
for (uint8_t i = 0; i < sec_cfg->num_credentials; i++) {
|
||||
const wifi_nan_credential_t *cred = &sec_cfg->creds[i];
|
||||
|
||||
if (cred->csid == 0) {
|
||||
ESP_LOGE(TAG, "Cred[%u] missing csid", i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (cred->use_pmk) {
|
||||
memcpy(pmk, cred->pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
} else {
|
||||
if (nan_derive_nd_pmk_from_passphrase(cred->passphrase, cred->csid,
|
||||
service_id, r_addr, pmk) != 0) {
|
||||
ESP_LOGE(TAG, "Cred[%u]: PBKDF2 ND-PMK derivation failed", i);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned char *addr_pmkid[4] = {(const unsigned char *)NAN_PMK_NAME_LABEL,
|
||||
i_addr, r_addr, service_id
|
||||
};
|
||||
int len_pmkid[4] = {NAN_PMK_NAME_LABEL_LEN, 6, 6, 6};
|
||||
|
||||
g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(pmk, ESP_WIFI_NAN_NDP_PMK_LEN,
|
||||
4, addr_pmkid, len_pmkid, hash);
|
||||
|
||||
out_derived[i].type = WIFI_NAN_SECURITY_ENCRYPTED;
|
||||
out_derived[i].csid_bitmap = (uint16_t)(1u << cred->csid);
|
||||
out_derived[i].group_data_prot = sec_cfg->group_data_prot;
|
||||
out_derived[i].group_mgmt_prot = sec_cfg->group_mgmt_prot;
|
||||
memcpy(out_derived[i].nd_pmk, pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
memcpy(out_derived[i].nd_pmkid, hash, ESP_WIFI_NAN_NDP_PMKID_LEN);
|
||||
|
||||
forced_memzero(pmk, sizeof(pmk));
|
||||
}
|
||||
|
||||
const unsigned char *addr_pmkid[4] = {(const unsigned char *)NAN_PMK_NAME_LABEL,
|
||||
i_addr, r_addr, service_id
|
||||
};
|
||||
int len_pmkid[4] = {NAN_PMK_NAME_LABEL_LEN, 6, 6, 6};
|
||||
/* Mirror the derived material into the host's own_svc_info slot for this
|
||||
* service (claimed before the blob's publish/subscribe call). This lets
|
||||
* host paths — nan_match_pmkid (responder M1) and the NDL seeding at
|
||||
* nan_app.c — read derived ND-PMK + PMKID without a second PBKDF2 pass
|
||||
* on the app/main task. Single derive, two destinations. */
|
||||
{
|
||||
struct own_svc_info *p_svc = nan_find_own_svc_by_name(service_name);
|
||||
if (p_svc) {
|
||||
memcpy(p_svc->derived_security, out_derived,
|
||||
sizeof(*out_derived) * sec_cfg->num_credentials);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
|
||||
g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(pmk, 32, 4, addr_pmkid, len_pmkid, hash);
|
||||
memcpy(pmkid, hash, 16);
|
||||
|
||||
memcpy(cfg->security_cfg.pmkids[0], pmkid, 16);
|
||||
cfg->security_cfg.num_pmkids = 1;
|
||||
memcpy(cfg->security_cfg.pmk, pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
ret = ESP_OK;
|
||||
|
||||
cleanup:
|
||||
fail:
|
||||
forced_memzero(pmk, sizeof(pmk));
|
||||
return ret;
|
||||
memset(out_derived, 0,
|
||||
sizeof(*out_derived) * ESP_WIFI_NAN_MAX_CREDS_PER_SVC);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -781,6 +849,10 @@ uint16_t nan_get_ndp_security_csid(uint8_t ndp_id, const uint8_t *peer_nmi)
|
||||
void nan_security_cache_subscriber_params(const char *service_name,
|
||||
const wifi_nan_discovery_security_params_t *security_cfg)
|
||||
{
|
||||
/* New (or cleared) subscribe session: wipe any stale per-peer match
|
||||
* memory from a previous subscriber. */
|
||||
nan_subscriber_match_clear();
|
||||
|
||||
if (!service_name || !security_cfg) {
|
||||
s_nan_subscriber_sec_cache.valid = false;
|
||||
return;
|
||||
@@ -792,43 +864,38 @@ void nan_security_cache_subscriber_params(const char *service_name,
|
||||
s_nan_subscriber_sec_cache.valid = true;
|
||||
}
|
||||
|
||||
bool nan_security_service_match(const uint8_t *publisher_nmi,
|
||||
const wifi_nan_discovery_security_params_t *peer_sec)
|
||||
bool nan_security_subscriber_has_creds(void)
|
||||
{
|
||||
uint8_t pmk[32];
|
||||
return s_nan_subscriber_sec_cache.valid &&
|
||||
s_nan_subscriber_sec_cache.security_cfg.num_credentials > 0;
|
||||
}
|
||||
|
||||
bool nan_security_service_match(const uint8_t *publisher_nmi,
|
||||
const wifi_nan_peer_sdf_security_t *peer_sec)
|
||||
{
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||
uint8_t service_id[6];
|
||||
uint8_t pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN];
|
||||
uint8_t hash[32];
|
||||
bool matched = false;
|
||||
|
||||
if (!s_nan_subscriber_sec_cache.valid || !publisher_nmi || !peer_sec) {
|
||||
goto cleanup;
|
||||
return false;
|
||||
}
|
||||
if (peer_sec->num_pmkids == 0) {
|
||||
goto cleanup;
|
||||
return false;
|
||||
}
|
||||
if (!nan_compute_service_id(s_nan_subscriber_sec_cache.service_name, service_id)) {
|
||||
goto cleanup;
|
||||
return false;
|
||||
}
|
||||
if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const wifi_nan_discovery_security_params_t *cfg = &s_nan_subscriber_sec_cache.security_cfg;
|
||||
|
||||
if (cfg->use_pmk) {
|
||||
memcpy(pmk, cfg->pmk, sizeof(pmk));
|
||||
} else {
|
||||
uint8_t csid = nan_get_first_csid(cfg->csid_bitmap);
|
||||
|
||||
if (csid == 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (nan_derive_nd_pmk_from_passphrase(cfg->passphrase, csid, service_id,
|
||||
publisher_nmi, pmk) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector) {
|
||||
goto cleanup;
|
||||
if (cfg->num_credentials == 0 ||
|
||||
cfg->num_credentials > ESP_WIFI_NAN_MAX_CREDS_PER_SVC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t i_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
@@ -837,19 +904,45 @@ bool nan_security_service_match(const uint8_t *publisher_nmi,
|
||||
};
|
||||
int len_pmkid[4] = {NAN_PMK_NAME_LABEL_LEN, 6, 6, 6};
|
||||
|
||||
g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(pmk, 32, 4, addr_pmkid, len_pmkid, hash);
|
||||
memcpy(pmkid, hash, ESP_WIFI_NAN_NDP_PMKID_LEN);
|
||||
/* Cross-product: each local credential vs each peer-advertised PMKID. First
|
||||
* match wins. Both sides honor the spec PMKID formula with IAddr broadcast,
|
||||
* RAddr = publisher_nmi, so a (local cred, peer SCID) match indicates a
|
||||
* shared ND-PMK for this service. */
|
||||
for (uint8_t c = 0; c < cfg->num_credentials; c++) {
|
||||
const wifi_nan_credential_t *cred = &cfg->creds[c];
|
||||
if (cred->csid == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < peer_sec->num_pmkids && i < ESP_WIFI_NAN_MAX_PMKIDS; i++) {
|
||||
if (memcmp(pmkid, peer_sec->pmkids[i], ESP_WIFI_NAN_NDP_PMKID_LEN) == 0) {
|
||||
ESP_LOGD(TAG, "ND-PMKID match with publisher " MACSTR, MAC2STR(publisher_nmi));
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN, ESP_LOG_INFO);
|
||||
matched = true;
|
||||
break;
|
||||
if (cred->use_pmk) {
|
||||
memcpy(pmk, cred->pmk, sizeof(pmk));
|
||||
} else {
|
||||
if (nan_derive_nd_pmk_from_passphrase(cred->passphrase, cred->csid,
|
||||
service_id, publisher_nmi, pmk) != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
g_wifi_default_wpa_crypto_funcs.hmac_sha256_vector(pmk, ESP_WIFI_NAN_NDP_PMK_LEN,
|
||||
4, addr_pmkid, len_pmkid, hash);
|
||||
memcpy(pmkid, hash, ESP_WIFI_NAN_NDP_PMKID_LEN);
|
||||
|
||||
for (uint8_t i = 0; i < peer_sec->num_pmkids && i < NAN_PEER_MAX_PMKIDS; i++) {
|
||||
if (memcmp(pmkid, peer_sec->pmkids[i], ESP_WIFI_NAN_NDP_PMKID_LEN) == 0) {
|
||||
ESP_LOGD(TAG, "ND-PMKID match: cred[%u] vs peer SCID[%u], publisher "MACSTR,
|
||||
c, i, MAC2STR(publisher_nmi));
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN, ESP_LOG_INFO);
|
||||
/* Remember which local cred matched this publisher so the
|
||||
* later NDP-init path (nan_security_populate_initiator_ndl)
|
||||
* uses the right cred for M1's pair-PMKID derivation. */
|
||||
nan_subscriber_match_remember(publisher_nmi, c);
|
||||
matched = true;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
done:
|
||||
forced_memzero(pmk, sizeof(pmk));
|
||||
return matched;
|
||||
}
|
||||
@@ -875,10 +968,24 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||
return ESP_OK; /* subscriber didn't cache security; open NDP */
|
||||
}
|
||||
const wifi_nan_discovery_security_params_t *cfg = &s_nan_subscriber_sec_cache.security_cfg;
|
||||
if (cfg->csid_bitmap == 0) {
|
||||
if (cfg->num_credentials == 0) {
|
||||
return ESP_OK; /* subscriber didn't request encrypted datapath */
|
||||
}
|
||||
|
||||
/* Use the credential that matched this publisher at discovery time
|
||||
* (remembered by nan_security_service_match -> nan_subscriber_match_remember).
|
||||
* Falls back to creds[0] only when no match memory exists for this peer
|
||||
* (e.g., subscriber initiated NDP without a prior service match — atypical). */
|
||||
int matched_idx = nan_subscriber_match_recall(peer_nmi);
|
||||
uint8_t cred_idx = (matched_idx >= 0) ? (uint8_t)matched_idx : 0;
|
||||
if (cred_idx >= cfg->num_credentials) {
|
||||
cred_idx = 0;
|
||||
}
|
||||
const wifi_nan_credential_t *cred = &cfg->creds[cred_idx];
|
||||
ESP_LOGD(TAG, "NDP req security: using cred[%u] for peer "MACSTR
|
||||
" (matched_idx=%d, num_creds=%u)",
|
||||
cred_idx, MAC2STR(peer_nmi), matched_idx, cfg->num_credentials);
|
||||
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||
uint8_t service_id[6];
|
||||
uint8_t our_nmi[6];
|
||||
@@ -893,14 +1000,13 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cfg->use_pmk) {
|
||||
memcpy(pmk, cfg->pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
if (cred->use_pmk) {
|
||||
memcpy(pmk, cred->pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
} else {
|
||||
uint8_t csid = nan_get_first_csid(cfg->csid_bitmap);
|
||||
if (csid == 0) {
|
||||
if (cred->csid == 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (nan_derive_nd_pmk_from_passphrase(cfg->passphrase, csid, service_id,
|
||||
if (nan_derive_nd_pmk_from_passphrase(cred->passphrase, cred->csid, service_id,
|
||||
peer_nmi, pmk) != 0) {
|
||||
ESP_LOGE(TAG, "NDP req security: passphrase->PMK failed");
|
||||
goto cleanup;
|
||||
@@ -914,7 +1020,7 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||
}
|
||||
|
||||
ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED;
|
||||
ndl->security_ctx.csid_bitmap = cfg->csid_bitmap;
|
||||
ndl->security_ctx.csid_bitmap = (uint16_t)(1u << cred->csid);
|
||||
memcpy(ndl->security_ctx.nd_pmk, pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
memcpy(ndl->security_ctx.nd_pmkid, pair_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN);
|
||||
|
||||
@@ -1093,23 +1199,22 @@ int esp_nan_get_ndp_resp_shared_key_desc(uint8_t *buf, size_t buf_len, uint8_t n
|
||||
|
||||
if (need_pmk && have_peer_pmkid) {
|
||||
struct own_svc_info *p_svc = nan_find_own_svc(ndl->publisher_id);
|
||||
uint8_t matched_pmk[ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||
if (p_svc && nan_match_pmkid(p_svc, ndl->security_ctx.nd_pmkid, matched_pmk,
|
||||
ndl->peer_nmi, ndl->peer_ndi)) {
|
||||
int matched_idx = p_svc ? nan_match_pmkid(p_svc, ndl->security_ctx.nd_pmkid,
|
||||
ndl->peer_nmi, ndl->peer_ndi) : -1;
|
||||
if (matched_idx >= 0) {
|
||||
ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED;
|
||||
ndl->security_ctx.csid_bitmap = p_svc->security_cfg.csid_bitmap;
|
||||
memcpy(ndl->security_ctx.nd_pmk, matched_pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
ESP_LOGD(TAG, "NDP Resp Key Desc: resolved PMK from publish (PMKID match)");
|
||||
forced_memzero(matched_pmk, sizeof(matched_pmk));
|
||||
ndl->security_ctx.csid_bitmap = p_svc->derived_security[matched_idx].csid_bitmap;
|
||||
memcpy(ndl->security_ctx.nd_pmk,
|
||||
p_svc->derived_security[matched_idx].nd_pmk,
|
||||
ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
ESP_LOGD(TAG, "NDP Resp Key Desc: resolved PMK from cred slot %d", matched_idx);
|
||||
} else if (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) {
|
||||
forced_memzero(matched_pmk, sizeof(matched_pmk));
|
||||
NAN_DATA_UNLOCK();
|
||||
ESP_LOGW(TAG, "NDP Resp Key Desc: NDL not encrypted; send NDP Response without Shared Key Descriptor");
|
||||
return 0;
|
||||
} else {
|
||||
forced_memzero(matched_pmk, sizeof(matched_pmk));
|
||||
NAN_DATA_UNLOCK();
|
||||
ESP_LOGW(TAG, "NDP Resp Key Desc: no PMK for peer PMKID; ensure same passphrase on both devices");
|
||||
ESP_LOGW(TAG, "NDP Resp Key Desc: no PMK for peer PMKID; ensure matching credential on both devices");
|
||||
return 0;
|
||||
}
|
||||
} else if (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) {
|
||||
@@ -1264,7 +1369,7 @@ int esp_nan_update_ndp_security_install_mic(uint8_t *m4_body, size_t body_len, u
|
||||
* Public API: parsers (CSIA / SCIA / Shared Key Descriptor / Publish SDF)
|
||||
*-----------------------------------------------------------------------*/
|
||||
|
||||
void esp_nan_parse_ndp_csia(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param)
|
||||
void esp_nan_parse_ndp_csia(void *frm, size_t buf_len, wifi_nan_security_params_t *param)
|
||||
{
|
||||
if (!frm || !param || buf_len < 3) {
|
||||
return;
|
||||
@@ -1304,7 +1409,7 @@ void esp_nan_parse_ndp_csia(void *frm, size_t buf_len, wifi_nan_datapath_securit
|
||||
}
|
||||
}
|
||||
|
||||
void esp_nan_parse_ndp_scia(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param)
|
||||
void esp_nan_parse_ndp_scia(void *frm, size_t buf_len, wifi_nan_security_params_t *param)
|
||||
{
|
||||
if (!frm || !param || buf_len < 3) {
|
||||
return;
|
||||
@@ -1522,7 +1627,7 @@ void esp_nan_parse_ndp_key_desc(void *frm, size_t buf_len, uint8_t ndp_id, const
|
||||
}
|
||||
|
||||
esp_err_t esp_nan_parse_publish_security(const uint8_t *attrs, size_t attrs_len,
|
||||
wifi_nan_discovery_security_params_t *security)
|
||||
wifi_nan_peer_sdf_security_t *security)
|
||||
{
|
||||
uint16_t csia_len = 0;
|
||||
const uint8_t *csia = NULL;
|
||||
@@ -1562,7 +1667,7 @@ esp_err_t esp_nan_parse_publish_security(const uint8_t *attrs, size_t attrs_len,
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, scia, scia_len, ESP_LOG_DEBUG);
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset + 4 <= scia_len && security->num_pmkids < ESP_WIFI_NAN_MAX_PMKIDS) {
|
||||
while (offset + 4 <= scia_len && security->num_pmkids < NAN_PEER_MAX_PMKIDS) {
|
||||
uint16_t val_len = scia[offset] | (scia[offset + 1] << 8);
|
||||
uint8_t type = scia[offset + 2];
|
||||
|
||||
@@ -1611,15 +1716,17 @@ void nan_security_apply_pending(struct ndl_info *ndl,
|
||||
|
||||
if (s_pending_scia.has_pmkid) {
|
||||
memcpy(ndl->security_ctx.nd_pmkid, s_pending_scia.pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN);
|
||||
uint8_t matched_pmk[ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||
if (nan_match_pmkid(p_own_svc, s_pending_scia.pmkid, matched_pmk, peer_nmi, peer_ndi)) {
|
||||
int matched_idx = nan_match_pmkid(p_own_svc, s_pending_scia.pmkid, peer_nmi, peer_ndi);
|
||||
if (matched_idx >= 0) {
|
||||
ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED;
|
||||
memcpy(ndl->security_ctx.nd_pmk, matched_pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
ESP_LOGD(TAG, "NDP Indication: PMKID validated, security=ENCRYPTED");
|
||||
ndl->security_ctx.csid_bitmap = p_own_svc->derived_security[matched_idx].csid_bitmap;
|
||||
memcpy(ndl->security_ctx.nd_pmk,
|
||||
p_own_svc->derived_security[matched_idx].nd_pmk,
|
||||
ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
ESP_LOGD(TAG, "NDP Indication: PMKID validated via cred slot %d", matched_idx);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "NDP Indication: PMKID validation failed");
|
||||
}
|
||||
forced_memzero(matched_pmk, sizeof(matched_pmk));
|
||||
}
|
||||
|
||||
memset(&s_pending_scia, 0, sizeof(s_pending_scia));
|
||||
|
||||
@@ -130,19 +130,24 @@ void wifi_nan_publish(void)
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SECURITY_ENABLED
|
||||
.security_reqd = 1,
|
||||
.security_cfg = {
|
||||
.csid_bitmap = WIFI_NAN_CSID_BIT_NCS_SK_128,
|
||||
.num_credentials = 1,
|
||||
.creds = {
|
||||
{
|
||||
.csid = WIFI_NAN_CSID_NCS_SK_128,
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
.use_pmk = true,
|
||||
.use_pmk = true,
|
||||
#else
|
||||
.use_pmk = false,
|
||||
.passphrase = CONFIG_EXAMPLE_NAN_PASSPHRASE,
|
||||
.use_pmk = false,
|
||||
.passphrase = CONFIG_EXAMPLE_NAN_PASSPHRASE,
|
||||
#endif
|
||||
},
|
||||
},
|
||||
},
|
||||
#endif
|
||||
};
|
||||
#if defined(CONFIG_EXAMPLE_NAN_SECURITY_ENABLED) && defined(CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK)
|
||||
if (!decode_hex_string(CONFIG_EXAMPLE_NAN_PMK, publish_cfg.security_cfg.pmk,
|
||||
sizeof(publish_cfg.security_cfg.pmk))) {
|
||||
if (!decode_hex_string(CONFIG_EXAMPLE_NAN_PMK, publish_cfg.security_cfg.creds[0].pmk,
|
||||
sizeof(publish_cfg.security_cfg.creds[0].pmk))) {
|
||||
ESP_LOGE(TAG, "Failed to decode CONFIG_EXAMPLE_NAN_PMK");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -224,19 +224,24 @@ void wifi_nan_subscribe(void)
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SECURITY_ENABLED
|
||||
.security_reqd = 1,
|
||||
.security_cfg = {
|
||||
.csid_bitmap = WIFI_NAN_CSID_BIT_NCS_SK_128,
|
||||
.num_credentials = 1,
|
||||
.creds = {
|
||||
{
|
||||
.csid = WIFI_NAN_CSID_NCS_SK_128,
|
||||
#ifdef CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK
|
||||
.use_pmk = true,
|
||||
.use_pmk = true,
|
||||
#else
|
||||
.use_pmk = false,
|
||||
.passphrase = CONFIG_EXAMPLE_NAN_PASSPHRASE,
|
||||
.use_pmk = false,
|
||||
.passphrase = CONFIG_EXAMPLE_NAN_PASSPHRASE,
|
||||
#endif
|
||||
},
|
||||
},
|
||||
},
|
||||
#endif
|
||||
};
|
||||
#if defined(CONFIG_EXAMPLE_NAN_SECURITY_ENABLED) && defined(CONFIG_EXAMPLE_NAN_SEC_METHOD_PMK)
|
||||
if (!decode_hex_string(CONFIG_EXAMPLE_NAN_PMK, subscribe_cfg.security_cfg.pmk,
|
||||
sizeof(subscribe_cfg.security_cfg.pmk))) {
|
||||
if (!decode_hex_string(CONFIG_EXAMPLE_NAN_PMK, subscribe_cfg.security_cfg.creds[0].pmk,
|
||||
sizeof(subscribe_cfg.security_cfg.creds[0].pmk))) {
|
||||
ESP_LOGE(TAG, "Failed to decode CONFIG_EXAMPLE_NAN_PMK");
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user