mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(nan): Add support for NAN Pairing Verification
- Add nira attr and verification for pasn auth frames - Refine key clearing and pairing complete logic for pasn verify - Add NIRA own-service resolution, cached NIK checks, and dynamic pairing IE construction for bootstrap vs verify paths. - Replace NAN bootstrap events by private callbacks
This commit is contained in:
@@ -61,7 +61,10 @@ enum nan_role {
|
||||
* Pairing Initiator NMI || Pairing Responder NMI)).
|
||||
*
|
||||
* @param peer_nmi Peer NMI (6 bytes).
|
||||
* @param role enum nan_role value for the local device.
|
||||
* @param role @c NAN_ROLE_PAIRING_INITIATOR or @c NAN_ROLE_PAIRING_RESPONDER.
|
||||
* @param pairing_verification 1 when PASN ran as re-pair verification (NIRA verified on
|
||||
* Auth1 for responder, or @c cfg->pairing_verification on
|
||||
* initiator); 0 for bootstrap auth pairing.
|
||||
* @param ndp_csid NCS-SK CSID for paired-peer NDP (WIFI_NAN_CSID_NCS_SK_128
|
||||
* or _SK_256), 0 if no usable cipher mapping was available.
|
||||
* @param nd_pmk ND-PMK bytes (32) or NULL if KDK was absent.
|
||||
@@ -73,6 +76,7 @@ enum nan_role {
|
||||
*/
|
||||
typedef void (*esp_nan_pairing_key_installed_cb_t)(const uint8_t *peer_nmi,
|
||||
uint8_t role,
|
||||
uint8_t pairing_verification,
|
||||
uint8_t ndp_csid,
|
||||
const uint8_t *nd_pmk,
|
||||
size_t nd_pmk_len,
|
||||
@@ -133,6 +137,23 @@ int esp_nan_supp_pasn_initiator_auth(const uint8_t *peer_nmi, uint32_t pincode,
|
||||
uint32_t nik_lifetime_sec,
|
||||
esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb);
|
||||
|
||||
/**
|
||||
* @brief Schedule NAN PASN initiator verification (re-pair with cached NIK/PMK).
|
||||
*
|
||||
* Same role as @ref esp_nan_supp_pasn_initiator_auth but uses PASN verify instead of auth.
|
||||
*
|
||||
* @param peer_nmi Peer NMI (6 bytes).
|
||||
* @param pairing_key_installed_cb Callback invoked after pairwise key installation with peer NMI.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int esp_nan_supp_pasn_initiator_verify(const uint8_t *peer_nmi,
|
||||
esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb);
|
||||
|
||||
/**
|
||||
* @brief Default pairing key-installed callback (NAN app layer).
|
||||
*/
|
||||
esp_nan_pairing_key_installed_cb_t esp_nan_pairing_get_key_installed_cb(void);
|
||||
|
||||
/**
|
||||
* Schedule @ref handle_auth_pasn from NAN app callback table.
|
||||
*/
|
||||
@@ -141,6 +162,26 @@ void handle_auth_pasn(uint8_t *buf, size_t len, uint16_t trans_seq, uint16_t sta
|
||||
const struct nan_pasn_key_material *nan_pasn_get_saved_keys(void);
|
||||
void nan_pasn_clear_saved_keys(void);
|
||||
|
||||
/**
|
||||
* Clear stale pairwise keys, saved PASN material, and active NDPs before
|
||||
* responder-side PASN verification (proactive pairing_start or passive Auth1).
|
||||
*/
|
||||
void nan_pasn_responder_verify_prepare(const uint8_t *peer_nmi);
|
||||
|
||||
/** Look up cached NPK for pairing verification (§7.6.5). Returns 0 on success.
|
||||
* Lookup matches peer_cred.service_hash against active own-service hashes,
|
||||
* or uses a single cached slot when only one NPK is present. */
|
||||
int nan_global_peer_npk_lookup(uint8_t *npk, size_t *npk_len, int *akmp);
|
||||
|
||||
/**
|
||||
* Mark/clear that the current PASN session for @a peer_nmi is pairing
|
||||
* verification (re-pair) and must not trigger NIK follow-up exchange. The
|
||||
* marker is anchored to own service @a own_inst_id (as resolved from the
|
||||
* verifying NIK), so it survives even when no peer_svc_info exists yet.
|
||||
*/
|
||||
void esp_nan_pairing_mark_verify_session(uint8_t own_inst_id, const uint8_t *peer_nmi);
|
||||
void esp_nan_pairing_clear_verify_session(const uint8_t *peer_nmi);
|
||||
|
||||
/**
|
||||
* Decrypt a NAN Shared Key Descriptor attribute received in a follow-up frame.
|
||||
*
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#if CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "esp_private/esp_supp_nan.h"
|
||||
@@ -17,6 +18,8 @@ struct wpabuf;
|
||||
struct pasn_data;
|
||||
struct rsn_pmksa_cache;
|
||||
|
||||
#define NAN_PASN_PMKID_LEN 16
|
||||
|
||||
typedef esp_nan_pairing_key_installed_cb_t nan_pasn_pairing_key_installed_cb_t;
|
||||
|
||||
struct nan_config {
|
||||
@@ -43,20 +46,20 @@ struct nan_pasn_data {
|
||||
size_t pasn_ptk_len;
|
||||
struct pasn_data *pasn;
|
||||
nan_pasn_pairing_key_installed_cb_t pairing_key_installed_cb;
|
||||
uint8_t pairing_verification;
|
||||
uint32_t nik_lifetime_sec;
|
||||
bool pasn_auth2_done; /**< Initiator: Auth2 already processed (dedup) */
|
||||
uint8_t peer_npkid[NAN_PASN_PMKID_LEN]; /**< Nonce||Tag from peer NIRA; for PMKID cross-check */
|
||||
bool peer_npkid_valid;
|
||||
};
|
||||
|
||||
int nan_initiate_pasn_verify(struct nan_pasn_data *pd, const uint8_t *peer_addr,
|
||||
int freq, int role, const uint8_t *bssid,
|
||||
int role, const uint8_t *bssid,
|
||||
const uint8_t *ssid, size_t ssid_len);
|
||||
int nan_initiate_pasn_auth(struct nan_pasn_data *pd, const uint8_t *addr, int freq);
|
||||
int nan_initiate_pasn_auth(struct nan_pasn_data *pd, const uint8_t *addr);
|
||||
struct nan_pasn_data *nan_pasn_data_init(void);
|
||||
void nan_pasn_data_deinit(struct nan_pasn_data *pd);
|
||||
int nan_pasn_auth_initiate(struct nan_pasn_data *pd, const uint8_t *peer_addr, int freq);
|
||||
int nan_pasn_auth(struct nan_pasn_data **pd_out, const uint8_t *peer_addr, int freq);
|
||||
int nan_pasn_verify_eloop(unsigned int secs, unsigned int usecs,
|
||||
const uint8_t *peer_addr, int freq, int role,
|
||||
const uint8_t *bssid,
|
||||
const uint8_t *ssid, size_t ssid_len);
|
||||
int nan_pasn_auth_initiate(struct nan_pasn_data *pd, const uint8_t *peer_addr);
|
||||
int nan_pasn_auth(struct nan_pasn_data **pd_out, const uint8_t *peer_addr);
|
||||
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "common/nan.h"
|
||||
#include "esp_wifi_driver.h"
|
||||
#include "crypto/crypto.h"
|
||||
@@ -49,12 +50,74 @@
|
||||
|
||||
static struct nan_pasn_key_material g_nan_pasn_saved_keys;
|
||||
|
||||
/* Key index for esp_wifi_set_nan_key_internal (NAN PASN pairwise TK). */
|
||||
int temp = 1;
|
||||
#define NAN_NIRA_NONCE_LEN 8
|
||||
#define NAN_NIRA_TAG_LEN 8
|
||||
#define NAN_NIRA_ATTR_LEN 20
|
||||
#define NAN_PASN_CSIA_ATTR_MAX_LEN (3 + 1 + 2 * 8)
|
||||
#define NAN_PASN_PAIRING_BOOTSTRAP_METHODS WIFI_NAN_BOOTSTRAP_PIN_CODE_DISPLAY
|
||||
#define NAN_PASN_PAIRING_CSIA_PUB_ID 5
|
||||
|
||||
static int nan_pasn_npkid_from_nira_attr(const u8 *nira, u16 nira_len, u8 *npkid)
|
||||
{
|
||||
if (!nira || !npkid ||
|
||||
nira_len < 4 + NAN_NIRA_NONCE_LEN + NAN_NIRA_TAG_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* NPKID = Nonce || Tag (wire order matches NIRA body after Cipher Version;
|
||||
* PMKID is carried little-endian in the RSNE). */
|
||||
os_memcpy(npkid, nira + 4, NAN_NIRA_NONCE_LEN);
|
||||
os_memcpy(npkid + NAN_NIRA_NONCE_LEN,
|
||||
nira + 4 + NAN_NIRA_NONCE_LEN, NAN_NIRA_TAG_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nan_pasn_build_local_npkid(u8 *npkid)
|
||||
{
|
||||
uint8_t nira_frm[NAN_NIRA_ATTR_LEN];
|
||||
|
||||
if (!npkid ||
|
||||
esp_nan_construct_nira(nira_frm) <
|
||||
(int)(4 + NAN_NIRA_NONCE_LEN + NAN_NIRA_TAG_LEN)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nan_pasn_npkid_from_nira_attr(nira_frm, NAN_NIRA_ATTR_LEN, npkid);
|
||||
}
|
||||
|
||||
static int nan_validate_custom_pmkid(void *ctx, const u8 *addr, const u8 *pmkid)
|
||||
{
|
||||
struct nan_pasn_data *nan = ctx;
|
||||
|
||||
if (!pmkid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pairing verification: NIK is already checked via NIRA and NPK via
|
||||
* PMKSA lookup, but §7.6.5 also binds RSNE PMKID to the same-frame NIRA
|
||||
* (NPKID = Nonce||Tag). Cross-check when we cached NPKID from that NIRA.
|
||||
*/
|
||||
if (!nan || !nan->peer_npkid_valid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (os_memcmp(pmkid, nan->peer_npkid, PMKID_LEN) != 0) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"NAN PASN verify: PMKID/NPKID mismatch for " MACSTR,
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NAN_PASN_AES_WRAP_OVERHEAD 8
|
||||
#define NAN_PASN_AES_WRAP_MIN_CIPHERTEXT (NAN_PASN_AES_WRAP_OVERHEAD + 8)
|
||||
|
||||
static int pasn_responder_init(const uint8_t *peer_addr, uint32_t pincode,
|
||||
esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb);
|
||||
|
||||
/**
|
||||
* Map PASN pairwise cipher to the NCS-SK CSID used for paired-peer NDPs
|
||||
* (Wi-Fi Aware v4.0 §7.6.4.2: paired NDP runs NCS-SK style M1-M4, key length
|
||||
@@ -239,7 +302,6 @@ static int nan_pasn_install_nan_pairwise_tk(struct nan_pasn_data *nan, struct pa
|
||||
struct wpa_ptk *ptk;
|
||||
uint8_t key_rsc[8] = {0};
|
||||
int kret;
|
||||
(void)nan;
|
||||
|
||||
if (!pasn) {
|
||||
return -1;
|
||||
@@ -258,7 +320,7 @@ static int nan_pasn_install_nan_pairwise_tk(struct nan_pasn_data *nan, struct pa
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "NAN PASN: NM-TK", ptk->tk, ptk->tk_len);
|
||||
kret = esp_wifi_set_nan_key_internal(
|
||||
NAN_PASN_WIFI_ALG_CCMP, pasn->peer_addr, temp, 1, key_rsc, sizeof(key_rsc),
|
||||
NAN_PASN_WIFI_ALG_CCMP, pasn->peer_addr, 1, 1, key_rsc, sizeof(key_rsc),
|
||||
ptk->tk, ptk->tk_len,
|
||||
NAN_KEY_NM_TK);
|
||||
if (kret != 0) {
|
||||
@@ -428,6 +490,21 @@ void nan_pasn_clear_saved_keys(void)
|
||||
forced_memzero(&g_nan_pasn_saved_keys, sizeof(g_nan_pasn_saved_keys));
|
||||
}
|
||||
|
||||
static void nan_pasn_clear_peer_tks_for_verify_start(const u8 *peer_nmi)
|
||||
{
|
||||
if (!peer_nmi) {
|
||||
return;
|
||||
}
|
||||
esp_nan_app_clear_peer_tks(peer_nmi, 0);
|
||||
nan_pasn_clear_saved_keys();
|
||||
}
|
||||
|
||||
void nan_pasn_responder_verify_prepare(const u8 *peer_nmi)
|
||||
{
|
||||
esp_nan_app_end_peer_datapaths(peer_nmi);
|
||||
nan_pasn_clear_peer_tks_for_verify_start(peer_nmi);
|
||||
}
|
||||
|
||||
/* NAN KDE OUI Type values from Wi-Fi Aware spec v4.0, Table 126. */
|
||||
#define NAN_PASN_KDE_OUI_TYPE_NIK 36
|
||||
#define NAN_PASN_KDE_OUI_TYPE_LIFETIME 37
|
||||
@@ -749,28 +826,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nan_chan_to_freq_mhz(uint8_t chan)
|
||||
{
|
||||
if (chan >= 1 && chan <= 13) {
|
||||
return 2407 + (int)chan * 5;
|
||||
}
|
||||
if (chan == 14) {
|
||||
return 2484;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nan_pasn_get_current_freq_mhz(void)
|
||||
{
|
||||
uint8_t primary = 0;
|
||||
wifi_second_chan_t second = WIFI_SECOND_CHAN_NONE;
|
||||
|
||||
if (esp_wifi_get_channel(&primary, &second) != ESP_OK || primary == 0) {
|
||||
return 0;
|
||||
}
|
||||
return nan_chan_to_freq_mhz(primary);
|
||||
}
|
||||
|
||||
static void nan_pasn_auth_timeout_cancel(struct nan_pasn_data *nan);
|
||||
|
||||
static void nan_pasn_auth_timeout_cb(void *eloop_ctx, void *user_data)
|
||||
@@ -846,48 +901,97 @@ static int nan_set_dev_sae_pin(struct nan_pasn_data *nan, const char *digits)
|
||||
}
|
||||
|
||||
/*
|
||||
* Build Wi-Fi Alliance NAN vendor IE (EID 221) with DCEA / BPBA / CSIA for PASN
|
||||
* and pass to @a pasn via pasn_set_extra_ies() so wpa_pasn_add_extra_ies() appends
|
||||
* Build Wi-Fi Alliance NAN vendor IE (EID 221) for PASN.
|
||||
* Bootstrap auth: DCEA + NPBA + CSIA.
|
||||
* Pairing verification: CSIA + NIRA only (no DCEA/NPBA).
|
||||
* Passed to @a pasn via pasn_set_extra_ies() so wpa_pasn_add_extra_ies() appends
|
||||
* it after PASN Parameters on Auth 1/3 (and after prepare_data_element on Auth 2).
|
||||
*/
|
||||
static int nan_prepare_pasn_extra_ie(struct nan_pasn_data *nan, struct pasn_data *pasn,
|
||||
const struct wpabuf *frame, bool add_dira)
|
||||
const struct wpabuf *frame, bool include_nira)
|
||||
{
|
||||
static const u8 nan_pasn_attr_payload[] = {
|
||||
NAN_ATTR_DCEA, 0x02, 0x00, 0x00, 0x03,
|
||||
NAN_ATTR_BPBA, 0x05, 0x00, 0x90, 0x02, 0x00, 0x02, 0x00,
|
||||
NAN_ATTR_CSIA, 0x03, 0x00, 0x00, 0x07, 0x05,
|
||||
};
|
||||
u8 fixed[2 + 3 + 1 + sizeof(nan_pasn_attr_payload)];
|
||||
u8 csia_attr[NAN_PASN_CSIA_ATTR_MAX_LEN];
|
||||
u8 nira_attr[NAN_NIRA_ATTR_LEN];
|
||||
uint8_t *pairing_attrs = NULL;
|
||||
u8 *buf = NULL;
|
||||
u8 *pos;
|
||||
size_t fr_len = 0;
|
||||
size_t csia_len;
|
||||
size_t nira_len = 0;
|
||||
size_t attr_payload_len;
|
||||
size_t vendor_ie_len;
|
||||
size_t total_len;
|
||||
uint32_t npba_len = 0;
|
||||
uint32_t dcea_len = 0;
|
||||
uint32_t pairing_attrs_len = 0;
|
||||
int ret;
|
||||
|
||||
(void)nan;
|
||||
(void)add_dira;
|
||||
|
||||
fixed[0] = WLAN_EID_VENDOR_SPECIFIC;
|
||||
fixed[1] = 3 + 1 + sizeof(nan_pasn_attr_payload);
|
||||
WPA_PUT_BE24(&fixed[2], OUI_WFA);
|
||||
fixed[5] = NAN_OUI_TYPE;
|
||||
os_memcpy(&fixed[6], nan_pasn_attr_payload, sizeof(nan_pasn_attr_payload));
|
||||
ret = esp_nan_construct_csia(csia_attr, NAN_PASN_PAIRING_CSIA_PUB_ID,
|
||||
WIFI_NAN_CSID_BIT_NCS_PK_PASN_128, 0);
|
||||
if (ret <= 0 || ret > (int)sizeof(csia_attr)) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN: CSIA build failed");
|
||||
return -1;
|
||||
}
|
||||
csia_len = (size_t) ret;
|
||||
attr_payload_len = csia_len;
|
||||
|
||||
if (include_nira) {
|
||||
ret = esp_nan_construct_nira(nira_attr);
|
||||
if (ret < (int)NAN_NIRA_ATTR_LEN) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN: NIRA build failed");
|
||||
return -1;
|
||||
}
|
||||
nira_len = (size_t) ret;
|
||||
attr_payload_len += nira_len;
|
||||
} else {
|
||||
pairing_attrs = esp_wifi_nan_get_pairing_attrs(NAN_PASN_PAIRING_BOOTSTRAP_METHODS,
|
||||
true, true, &npba_len,
|
||||
&dcea_len, &pairing_attrs_len);
|
||||
if (!pairing_attrs || !pairing_attrs_len) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN: pairing attrs build failed");
|
||||
return -1;
|
||||
}
|
||||
attr_payload_len += pairing_attrs_len;
|
||||
}
|
||||
|
||||
if (frame) {
|
||||
fr_len = wpabuf_len(frame);
|
||||
}
|
||||
|
||||
if (!fr_len) {
|
||||
return pasn_set_extra_ies(pasn, fixed, sizeof(fixed));
|
||||
vendor_ie_len = 3 + 1 + attr_payload_len;
|
||||
if (vendor_ie_len > UINT8_MAX) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN: extra IE too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
total_len = sizeof(fixed) + fr_len;
|
||||
total_len = 2 + vendor_ie_len + fr_len;
|
||||
buf = os_malloc(total_len);
|
||||
if (!buf) {
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(buf, fixed, sizeof(fixed));
|
||||
os_memcpy(buf + sizeof(fixed), wpabuf_head_u8(frame), fr_len);
|
||||
|
||||
pos = buf;
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = (u8) vendor_ie_len;
|
||||
WPA_PUT_BE24(pos, OUI_WFA);
|
||||
pos += 3;
|
||||
*pos++ = NAN_OUI_TYPE;
|
||||
if (pairing_attrs_len) {
|
||||
os_memcpy(pos, pairing_attrs, pairing_attrs_len);
|
||||
pos += pairing_attrs_len;
|
||||
}
|
||||
os_memcpy(pos, csia_attr, csia_len);
|
||||
pos += csia_len;
|
||||
if (nira_len) {
|
||||
os_memcpy(pos, nira_attr, nira_len);
|
||||
pos += nira_len;
|
||||
}
|
||||
if (fr_len) {
|
||||
os_memcpy(pos, wpabuf_head_u8(frame), fr_len);
|
||||
}
|
||||
|
||||
ret = pasn_set_extra_ies(pasn, buf, total_len);
|
||||
os_free(buf);
|
||||
return ret;
|
||||
@@ -962,7 +1066,7 @@ static void nan_pairing_apply_sae_pin(struct pasn_data *pasn, u8 pasn_type,
|
||||
pasn->password = nan->dev_sae_pin;
|
||||
}
|
||||
|
||||
void nan_pasn_initialize(struct nan_pasn_data *nan, const u8 *addr, int freq, bool verify, bool derive_kek)
|
||||
void nan_pasn_initialize(struct nan_pasn_data *nan, const u8 *addr)
|
||||
{
|
||||
struct pasn_data *pasn;
|
||||
struct wpabuf *rsnxe;
|
||||
@@ -971,6 +1075,8 @@ void nan_pasn_initialize(struct nan_pasn_data *nan, const u8 *addr, int freq, bo
|
||||
return;
|
||||
}
|
||||
|
||||
nan->peer_npkid_valid = false;
|
||||
|
||||
if (nan->pasn) {
|
||||
wpa_pasn_reset(nan->pasn);
|
||||
} else {
|
||||
@@ -1021,15 +1127,13 @@ void nan_pasn_initialize(struct nan_pasn_data *nan, const u8 *addr, int freq, bo
|
||||
* ND-PMK is filled by pasn_nd_pmk_derive_from_kdk_store (hostap
|
||||
* nan_crypto_derive_nd_pmk_from_kdk). Matches hostap nan_pairing.c.
|
||||
*/
|
||||
(void)derive_kek;
|
||||
pasn->derive_kek = false;
|
||||
pasn->kek_len = 0;
|
||||
|
||||
/* Wi-Fi Aware pairing: PASN Auth frames always use SAE as the base AKM. */
|
||||
pasn->akmp = WPA_KEY_MGMT_SAE;
|
||||
if (nan->dev_sae_pin_len > 0) {
|
||||
pasn->akmp = WPA_KEY_MGMT_SAE;
|
||||
nan_pairing_apply_sae_pin(pasn, nan->cfg->pasn_type, nan);
|
||||
} else if (!verify) {
|
||||
pasn->akmp = WPA_KEY_MGMT_PASN;
|
||||
}
|
||||
|
||||
pasn->rsn_pairwise = pasn->cipher;
|
||||
@@ -1059,16 +1163,19 @@ void nan_pasn_initialize(struct nan_pasn_data *nan, const u8 *addr, int freq, bo
|
||||
pasn->parse_data_element = nan->cfg->parse_data_element;
|
||||
pasn->validate_custom_pmkid = nan->cfg->pasn_validate_pmkid;
|
||||
|
||||
pasn->freq = freq;
|
||||
|
||||
}
|
||||
|
||||
int nan_initiate_pasn_verify(struct nan_pasn_data *pd, const u8 *peer_addr,
|
||||
int freq, int role,
|
||||
int role,
|
||||
const u8 *bssid, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct nan_pasn_data *nan;
|
||||
struct pasn_data *pasn;
|
||||
uint8_t npk[NAN_PASN_KEY_PMK_MAX];
|
||||
uint8_t own_addr[ETH_ALEN];
|
||||
u8 npkid[PMKID_LEN];
|
||||
size_t npk_len = 0;
|
||||
int akmp = WPA_KEY_MGMT_SAE;
|
||||
int ret = 0;
|
||||
|
||||
(void)role;
|
||||
@@ -1087,29 +1194,55 @@ int nan_initiate_pasn_verify(struct nan_pasn_data *pd, const u8 *peer_addr,
|
||||
}
|
||||
|
||||
nan->dev_role = NAN_ROLE_PAIRING_INITIATOR;
|
||||
nan_pasn_initialize(nan, peer_addr, freq, true, true);
|
||||
nan->pasn_auth2_done = false;
|
||||
nan->pairing_verification = 1;
|
||||
nan_pasn_clear_peer_tks_for_verify_start(peer_addr);
|
||||
nan_pasn_initialize(nan, peer_addr);
|
||||
pasn = nan->pasn;
|
||||
|
||||
if (nan_prepare_pasn_extra_ie(nan, pasn, NULL, false) != 0) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN: extra IE failed");
|
||||
if (!pasn) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
nan->cfg->pasn_validate_pmkid = nan_validate_custom_pmkid;
|
||||
pasn->validate_custom_pmkid = nan_validate_custom_pmkid;
|
||||
|
||||
/* §7.6.5: seed PMKSA with cached NPK and local NPKID (Nonce||Tag). */
|
||||
if (nan_global_peer_npk_lookup(npk, &npk_len, &akmp) != 0 ||
|
||||
esp_wifi_get_mac(WIFI_IF_NAN, own_addr) != ESP_OK ||
|
||||
nan_pasn_build_local_npkid(npkid) != 0) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pasn_initiator_pmksa_cache_add(nan->initiator_pmksa, own_addr,
|
||||
(u8 *) peer_addr, npk, npk_len, npkid) != 0) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pasn_set_akmp(pasn, akmp);
|
||||
pasn->wpa_key_mgmt = akmp;
|
||||
pasn_set_custom_pmkid(pasn, npkid);
|
||||
|
||||
if (nan_prepare_pasn_extra_ie(nan, pasn, NULL, true) != 0) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wpa_pasn_verify(pasn, pasn->own_addr, pasn->peer_addr, pasn->bssid,
|
||||
pasn->akmp, pasn->cipher, pasn->group, pasn->freq,
|
||||
pasn->akmp, pasn->cipher, pasn->group, 0,
|
||||
NULL, 0, NULL, 0, NULL)) {
|
||||
wpa_printf(MSG_INFO, "PASN verify failed");
|
||||
ret = -1;
|
||||
}
|
||||
if (pasn->extra_ies) {
|
||||
os_free((u8 *) pasn->extra_ies);
|
||||
pasn->extra_ies = NULL;
|
||||
pasn->extra_ies_len = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
forced_memzero(npk, sizeof(npk));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nan_initiate_pasn_auth(struct nan_pasn_data *pd, const u8 *addr, int freq)
|
||||
int nan_initiate_pasn_auth(struct nan_pasn_data *pd, const u8 *addr)
|
||||
{
|
||||
struct nan_pasn_data *nan;
|
||||
struct pasn_data *pasn;
|
||||
@@ -1126,10 +1259,16 @@ int nan_initiate_pasn_auth(struct nan_pasn_data *pd, const u8 *addr, int freq)
|
||||
}
|
||||
|
||||
nan->dev_role = NAN_ROLE_PAIRING_INITIATOR;
|
||||
nan->pasn_auth2_done = false;
|
||||
nan->pairing_verification = 0;
|
||||
|
||||
nan_pasn_initialize(nan, addr, freq, false, true);
|
||||
nan_pasn_initialize(nan, addr);
|
||||
pasn = nan->pasn;
|
||||
|
||||
if (!pasn) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pasn_initiator_pmksa_cache_remove(pasn->pmksa, (u8 *)addr);
|
||||
|
||||
if (nan_prepare_pasn_extra_ie(nan, pasn, NULL, false) != 0) {
|
||||
@@ -1138,7 +1277,7 @@ int nan_initiate_pasn_auth(struct nan_pasn_data *pd, const u8 *addr, int freq)
|
||||
}
|
||||
|
||||
if (wpas_pasn_start(pasn, pasn->own_addr, pasn->peer_addr, pasn->bssid,
|
||||
pasn->akmp, pasn->cipher, pasn->group, pasn->freq,
|
||||
pasn->akmp, pasn->cipher, pasn->group, 0,
|
||||
NULL, 0, NULL, 0, NULL)) {
|
||||
wpa_printf(MSG_INFO, "Failed to start PASN");
|
||||
ret = -1;
|
||||
@@ -1167,15 +1306,13 @@ int * int_array_dup(const int *a)
|
||||
}
|
||||
|
||||
static int nan_handle_pasn_auth(struct nan_pasn_data *nan,
|
||||
const struct ieee80211_auth *mgmt, size_t len,
|
||||
int freq)
|
||||
const struct ieee80211_auth *mgmt, size_t len)
|
||||
{
|
||||
struct pasn_data *pasn;
|
||||
u8 pasn_type;
|
||||
int pasn_groups[4] = { 0 };
|
||||
u16 auth_alg, auth_transaction, status_code;
|
||||
|
||||
(void)freq;
|
||||
if (!nan || !nan->pasn) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1246,6 +1383,7 @@ static int nan_handle_pasn_auth(struct nan_pasn_data *nan,
|
||||
nan_pasn_store_ptk(nan, &pasn->ptk);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
nan_pasn_copy_keys_from_pasn(nan, pasn);
|
||||
/* Install NM-TK only after Auth3 is successfully validated. */
|
||||
if (nan_pasn_install_nan_pairwise_tk(nan, pasn) == 0 &&
|
||||
nan->pairing_key_installed_cb) {
|
||||
const uint8_t *nd_pmk = pasn_nd_pmk_global.valid ?
|
||||
@@ -1253,6 +1391,7 @@ static int nan_handle_pasn_auth(struct nan_pasn_data *nan,
|
||||
size_t nd_pmk_len = pasn_nd_pmk_global.valid ? PMK_LEN : 0;
|
||||
nan->pairing_key_installed_cb(pasn->peer_addr,
|
||||
(uint8_t)nan->dev_role,
|
||||
nan->pairing_verification,
|
||||
nan_pasn_pasn_cipher_to_ndp_csid(pasn->cipher),
|
||||
nd_pmk, nd_pmk_len,
|
||||
nan->nik_lifetime_sec);
|
||||
@@ -1263,8 +1402,108 @@ static int nan_handle_pasn_auth(struct nan_pasn_data *nan,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a NIRA attribute inside a WFA NAN vendor-specific IE (OUI + type 0x13).
|
||||
* Returns a pointer to the attribute (ID + length + body) or NULL.
|
||||
*/
|
||||
static const u8 *nan_pasn_find_nira_attr(const u8 *ies, size_t ies_len, u16 *attr_len)
|
||||
{
|
||||
const u8 *ie = ies;
|
||||
const u8 *end = ies + ies_len;
|
||||
|
||||
while (ie + 2 <= end) {
|
||||
u8 id = ie[0];
|
||||
u8 elen = ie[1];
|
||||
|
||||
if (ie + 2 + elen > end) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (id == WLAN_EID_VENDOR_SPECIFIC && elen >= 4 &&
|
||||
WPA_GET_BE24(ie + 2) == OUI_WFA && ie[5] == NAN_OUI_TYPE) {
|
||||
const u8 *pos = ie + 6;
|
||||
const u8 *attrs_end = ie + 2 + elen;
|
||||
|
||||
while (attrs_end - pos >= NAN_ATTR_HDR_LEN) {
|
||||
u8 attr_id = pos[0];
|
||||
u16 attr_body_len = WPA_GET_LE16(pos + 1);
|
||||
u16 total_attr_len;
|
||||
|
||||
if (attr_body_len > (size_t)(attrs_end - pos - NAN_ATTR_HDR_LEN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
total_attr_len = NAN_ATTR_HDR_LEN + attr_body_len;
|
||||
if (attr_id == NAN_ATTR_NIRA) {
|
||||
if (attr_len) {
|
||||
*attr_len = total_attr_len;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
pos += total_attr_len;
|
||||
}
|
||||
}
|
||||
ie += 2 + elen;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find NIRA in @a mgmt once, verify identity, and stash NPKID for PMKID
|
||||
* cross-check. When @a own_inst_id is non-NULL the matched own service id is
|
||||
* also returned (0 if none). */
|
||||
static bool nan_pasn_auth_process_nira(struct nan_pasn_data *nan,
|
||||
const u8 *peer_addr,
|
||||
const struct ieee80211_auth *mgmt,
|
||||
size_t len, u16 auth_trans,
|
||||
uint8_t *own_inst_id)
|
||||
{
|
||||
const u8 *var;
|
||||
size_t var_len;
|
||||
const u8 *nira;
|
||||
u16 nira_len = 0;
|
||||
|
||||
if (own_inst_id) {
|
||||
*own_inst_id = 0;
|
||||
}
|
||||
|
||||
if (!nan || !peer_addr || !mgmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nan->peer_npkid_valid = false;
|
||||
|
||||
if (len < offsetof(struct ieee80211_auth, auth.variable)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var = mgmt->auth.variable;
|
||||
var_len = len - offsetof(struct ieee80211_auth, auth.variable);
|
||||
nira = nan_pasn_find_nira_attr(var, var_len, &nira_len);
|
||||
if (!nira) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN verify: NIRA missing in Auth%u from "
|
||||
MACSTR, auth_trans, MAC2STR(peer_addr));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!esp_nan_verify_nira_get_own_svc((u8 *) peer_addr, (u8 *) nira, nira_len,
|
||||
own_inst_id)) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN verify: NIRA verification failed in "
|
||||
"Auth%u for " MACSTR, auth_trans, MAC2STR(peer_addr));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nan_pasn_npkid_from_nira_attr(nira, nira_len, nan->peer_npkid) == 0) {
|
||||
nan->peer_npkid_valid = true;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "NAN PASN verify: NIRA OK in Auth%u for " MACSTR,
|
||||
auth_trans, MAC2STR(peer_addr));
|
||||
return true;
|
||||
}
|
||||
|
||||
int nan_pasn_auth_rx(struct nan_pasn_data *nan, const struct ieee80211_auth *mgmt,
|
||||
size_t len, int freq)
|
||||
size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 auth_transaction;
|
||||
@@ -1293,6 +1532,23 @@ int nan_pasn_auth_rx(struct nan_pasn_data *nan, const struct ieee80211_auth *mgm
|
||||
|
||||
if (nan->dev_role == NAN_ROLE_PAIRING_INITIATOR &&
|
||||
auth_transaction == WLAN_AUTH_TR_SEQ_PASN_AUTH2) {
|
||||
/*
|
||||
* Duplicate Auth2: responder may retransmit if it didn't get Auth3
|
||||
* ACK. wpa_pasn_auth_rx() would reject with trans_seq mismatch and
|
||||
* we would also lose NM-TK that was already installed; silently
|
||||
* accept the retransmit instead.
|
||||
*/
|
||||
if (nan->pasn_auth2_done) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pasn->custom_pmkid_valid &&
|
||||
!nan_pasn_auth_process_nira(nan, mgmt->sa, mgmt, len, 2, NULL)) {
|
||||
wpa_printf(MSG_INFO, "PASN: Auth2 NIRA verify failed");
|
||||
nan->dev_role = NAN_ROLE_IDLE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data);
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_INFO, "PASN: wpa_pasn_auth_rx() failed");
|
||||
@@ -1304,13 +1560,15 @@ int nan_pasn_auth_rx(struct nan_pasn_data *nan, const struct ieee80211_auth *mgm
|
||||
* successfully built/transmitted by wpa_pasn_auth_rx().
|
||||
*/
|
||||
nan_pasn_copy_keys_from_pasn(nan, pasn);
|
||||
if (nan_pasn_install_nan_pairwise_tk(nan, pasn) == 0 &&
|
||||
nan->pairing_key_installed_cb) {
|
||||
nan->pasn_auth2_done = true;
|
||||
int tk_ret = nan_pasn_install_nan_pairwise_tk(nan, pasn);
|
||||
if (tk_ret == 0 && nan->pairing_key_installed_cb) {
|
||||
const uint8_t *nd_pmk = pasn_nd_pmk_global.valid ?
|
||||
pasn_nd_pmk_global.nd_pmk : NULL;
|
||||
size_t nd_pmk_len = pasn_nd_pmk_global.valid ? PMK_LEN : 0;
|
||||
nan->pairing_key_installed_cb(pasn->peer_addr,
|
||||
(uint8_t)nan->dev_role,
|
||||
nan->pairing_verification,
|
||||
nan_pasn_pasn_cipher_to_ndp_csid(pasn->cipher),
|
||||
nd_pmk, nd_pmk_len,
|
||||
nan->nik_lifetime_sec);
|
||||
@@ -1321,7 +1579,7 @@ int nan_pasn_auth_rx(struct nan_pasn_data *nan, const struct ieee80211_auth *mgm
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
|
||||
} else {
|
||||
ret = nan_handle_pasn_auth(nan, mgmt, len, freq);
|
||||
ret = nan_handle_pasn_auth(nan, mgmt, len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -1330,7 +1588,8 @@ void handle_auth_pasn(uint8_t *buf, size_t len, uint16_t trans_seq, uint16_t sta
|
||||
{
|
||||
const struct ieee80211_auth *mgmt;
|
||||
struct nan_pasn_data *nan;
|
||||
int rx_freq;
|
||||
bool auth1_verify = false;
|
||||
u8 auth1_pmkid[PMKID_LEN];
|
||||
|
||||
(void)trans_seq;
|
||||
(void)status;
|
||||
@@ -1340,15 +1599,114 @@ void handle_auth_pasn(uint8_t *buf, size_t len, uint16_t trans_seq, uint16_t sta
|
||||
}
|
||||
mgmt = (const struct ieee80211_auth *)buf;
|
||||
nan = esp_nan_app_get_pasn_data();
|
||||
rx_freq = nan_pasn_get_current_freq_mhz();
|
||||
if (rx_freq <= 0) {
|
||||
rx_freq = 2412;
|
||||
if (!nan) {
|
||||
/*
|
||||
* Only lazy-init on Auth1: a stray Auth2/Auth3 (e.g. retransmit after
|
||||
* we already completed PASN and tore down the session) must be
|
||||
* dropped, otherwise we would init a fresh context and try to process
|
||||
* a mid-handshake frame against it, which fails noisily.
|
||||
*/
|
||||
if (le_to_host16(mgmt->auth.auth_transaction) !=
|
||||
WLAN_AUTH_TR_SEQ_PASN_AUTH1) {
|
||||
return;
|
||||
}
|
||||
if (pasn_responder_init(mgmt->sa, UINT32_MAX,
|
||||
esp_nan_pairing_get_key_installed_cb()) != 0) {
|
||||
return;
|
||||
}
|
||||
nan = esp_nan_app_get_pasn_data();
|
||||
}
|
||||
if (!nan) {
|
||||
wpa_printf(MSG_DEBUG, "NAN PASN: receive_pasn: no context");
|
||||
return;
|
||||
}
|
||||
nan_pasn_auth_rx(nan, mgmt, len, rx_freq);
|
||||
|
||||
if (le_to_host16(mgmt->auth.auth_transaction) == 1) {
|
||||
struct ieee802_11_elems elems;
|
||||
struct wpa_ie_data rsn_data;
|
||||
struct wpa_pasn_params_data pasn_params;
|
||||
|
||||
if (ieee802_11_parse_elems(mgmt->auth.variable,
|
||||
len - offsetof(struct ieee80211_auth, auth.variable),
|
||||
&elems, 0) != ParseFailed &&
|
||||
elems.rsn_ie && elems.pasn_params &&
|
||||
wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
|
||||
&rsn_data) == 0 &&
|
||||
rsn_data.num_pmkid &&
|
||||
wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
|
||||
elems.pasn_params_len + 3,
|
||||
false, &pasn_params) == 0 &&
|
||||
pasn_params.wrapped_data_format == WPA_PASN_WRAPPED_DATA_NO) {
|
||||
auth1_verify = true;
|
||||
os_memcpy(auth1_pmkid, rsn_data.pmkid, PMKID_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (auth1_verify) {
|
||||
uint8_t npk[NAN_PASN_KEY_PMK_MAX];
|
||||
uint8_t own_addr[ETH_ALEN];
|
||||
size_t npk_len = 0;
|
||||
int akmp = WPA_KEY_MGMT_SAE;
|
||||
struct pasn_data *pasn = nan->pasn;
|
||||
bool auth1_ok = false;
|
||||
uint8_t verify_own_inst_id = 0;
|
||||
|
||||
if (!nan_pasn_auth_process_nira(nan, mgmt->sa, mgmt, len, 1,
|
||||
&verify_own_inst_id)) {
|
||||
goto auth1_verify_done;
|
||||
}
|
||||
nan_pasn_responder_verify_prepare(mgmt->sa);
|
||||
|
||||
if (!pasn) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN verify: no PASN context for "
|
||||
MACSTR, MAC2STR(mgmt->sa));
|
||||
goto auth1_verify_done;
|
||||
}
|
||||
if (nan_global_peer_npk_lookup(npk, &npk_len, &akmp) != 0) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN verify: no cached NPK for "
|
||||
MACSTR, MAC2STR(mgmt->sa));
|
||||
goto auth1_verify_done;
|
||||
}
|
||||
if (esp_wifi_get_mac(WIFI_IF_NAN, own_addr) != ESP_OK) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN verify: failed to read NAN NMI");
|
||||
goto auth1_verify_done;
|
||||
}
|
||||
if (pasn_responder_pmksa_cache_add(nan->responder_pmksa, own_addr,
|
||||
(u8 *) mgmt->sa, npk, npk_len,
|
||||
auth1_pmkid) != 0) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN verify: PMKSA cache add failed for "
|
||||
MACSTR, MAC2STR(mgmt->sa));
|
||||
goto auth1_verify_done;
|
||||
}
|
||||
|
||||
{
|
||||
u8 npkid[PMKID_LEN];
|
||||
|
||||
nan->cfg->pasn_validate_pmkid = nan_validate_custom_pmkid;
|
||||
pasn->validate_custom_pmkid = nan_validate_custom_pmkid;
|
||||
pasn_set_akmp(pasn, akmp);
|
||||
pasn->wpa_key_mgmt = akmp;
|
||||
if (nan_pasn_build_local_npkid(npkid) == 0) {
|
||||
pasn_set_custom_pmkid(pasn, npkid);
|
||||
}
|
||||
if (nan_prepare_pasn_extra_ie(nan, pasn, NULL, true) != 0) {
|
||||
wpa_printf(MSG_INFO, "NAN PASN verify: extra IE (NIRA) build "
|
||||
"failed for " MACSTR, MAC2STR(mgmt->sa));
|
||||
goto auth1_verify_done;
|
||||
}
|
||||
auth1_ok = true;
|
||||
nan->pairing_verification = 1;
|
||||
}
|
||||
|
||||
auth1_verify_done:
|
||||
forced_memzero(npk, sizeof(npk));
|
||||
if (!auth1_ok) {
|
||||
return;
|
||||
}
|
||||
esp_nan_pairing_mark_verify_session(verify_own_inst_id, mgmt->sa);
|
||||
}
|
||||
|
||||
nan_pasn_auth_rx(nan, mgmt, len);
|
||||
}
|
||||
|
||||
void nan_pasn_pmksa_set_pmk(struct nan_pasn_data *nan, const u8 *src, const u8 *dst,
|
||||
@@ -1539,16 +1897,14 @@ void nan_pasn_data_deinit(struct nan_pasn_data *pd)
|
||||
os_free(pd);
|
||||
}
|
||||
|
||||
int nan_pasn_auth_initiate(struct nan_pasn_data *pd, const uint8_t *peer_addr, int freq)
|
||||
int nan_pasn_auth_initiate(struct nan_pasn_data *pd, const uint8_t *peer_addr)
|
||||
{
|
||||
if (!pd || !peer_addr) {
|
||||
return -1;
|
||||
}
|
||||
return nan_initiate_pasn_auth(pd, peer_addr, freq);
|
||||
return nan_initiate_pasn_auth(pd, peer_addr);
|
||||
}
|
||||
|
||||
#define NAN_PASN_VERIFY_ELOOP_SSID_MAX 32
|
||||
|
||||
struct nan_pasn_eloop_ctx {
|
||||
uint8_t peer_addr[ETH_ALEN];
|
||||
uint32_t pincode;
|
||||
@@ -1556,10 +1912,37 @@ struct nan_pasn_eloop_ctx {
|
||||
esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb;
|
||||
};
|
||||
|
||||
static struct nan_pasn_data *nan_pasn_eloop_prepare(struct nan_pasn_eloop_ctx *ctx,
|
||||
const char *pin_to_apply)
|
||||
{
|
||||
struct nan_pasn_data *old;
|
||||
struct nan_pasn_data *pd;
|
||||
|
||||
old = esp_nan_app_get_pasn_data();
|
||||
if (old) {
|
||||
nan_pasn_data_deinit(old);
|
||||
}
|
||||
|
||||
pd = nan_pasn_data_init();
|
||||
if (!pd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_nan_app_set_pasn_data(pd);
|
||||
pd->pairing_key_installed_cb = ctx->pairing_key_installed_cb;
|
||||
pd->nik_lifetime_sec = ctx->nik_lifetime_sec;
|
||||
|
||||
if (pin_to_apply && nan_set_dev_sae_pin(pd, pin_to_apply) != 0) {
|
||||
nan_pasn_data_deinit(pd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pd;
|
||||
}
|
||||
|
||||
static void nan_pasn_auth_eloop_cb(void *eloop_ctx, void *user_data)
|
||||
{
|
||||
struct nan_pasn_eloop_ctx *ctx = user_data;
|
||||
struct nan_pasn_data *old;
|
||||
struct nan_pasn_data *pd;
|
||||
char pin_digits[16];
|
||||
int n;
|
||||
@@ -1570,46 +1953,23 @@ static void nan_pasn_auth_eloop_cb(void *eloop_ctx, void *user_data)
|
||||
return;
|
||||
}
|
||||
|
||||
old = esp_nan_app_get_pasn_data();
|
||||
if (old) {
|
||||
nan_pasn_data_deinit(old);
|
||||
}
|
||||
|
||||
pd = nan_pasn_data_init();
|
||||
if (!pd) {
|
||||
os_free(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_nan_app_set_pasn_data(pd);
|
||||
pd->pairing_key_installed_cb = ctx->pairing_key_installed_cb;
|
||||
pd->nik_lifetime_sec = ctx->nik_lifetime_sec;
|
||||
|
||||
if (ctx->pincode != UINT32_MAX) {
|
||||
n = os_snprintf(pin_digits, sizeof(pin_digits), "%06u",
|
||||
(unsigned)ctx->pincode);
|
||||
if (os_snprintf_error(sizeof(pin_digits), n)) {
|
||||
nan_pasn_data_deinit(pd);
|
||||
os_free(ctx);
|
||||
return;
|
||||
}
|
||||
pin_to_apply = pin_digits;
|
||||
}
|
||||
|
||||
if (pin_to_apply && nan_set_dev_sae_pin(pd, pin_to_apply) != 0) {
|
||||
nan_pasn_data_deinit(pd);
|
||||
pd = nan_pasn_eloop_prepare(ctx, pin_to_apply);
|
||||
if (!pd) {
|
||||
os_free(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
int freq = nan_pasn_get_current_freq_mhz();
|
||||
|
||||
if (freq <= 0) {
|
||||
freq = 2412;
|
||||
}
|
||||
nan_pasn_auth_initiate(pd, ctx->peer_addr, freq);
|
||||
}
|
||||
nan_pasn_auth_initiate(pd, ctx->peer_addr);
|
||||
os_free(ctx);
|
||||
}
|
||||
|
||||
@@ -1619,8 +1979,12 @@ int esp_nan_supp_pasn_initiator_auth(const uint8_t *peer_nmi, uint32_t pincode,
|
||||
{
|
||||
struct nan_pasn_eloop_ctx *ctx;
|
||||
|
||||
if (!peer_nmi) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx = os_zalloc(sizeof(*ctx));
|
||||
if (!ctx || !peer_nmi) {
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1637,49 +2001,32 @@ int esp_nan_supp_pasn_initiator_auth(const uint8_t *peer_nmi, uint32_t pincode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nan_pasn_verify_eloop_ctx {
|
||||
uint8_t peer_addr[ETH_ALEN];
|
||||
int freq;
|
||||
int role;
|
||||
uint8_t bssid[ETH_ALEN];
|
||||
uint8_t ssid[NAN_PASN_VERIFY_ELOOP_SSID_MAX];
|
||||
size_t ssid_len;
|
||||
};
|
||||
|
||||
static void nan_pasn_verify_eloop_cb(void *eloop_ctx, void *user_data)
|
||||
static void nan_pasn_verify_init_eloop_cb(void *eloop_ctx, void *user_data)
|
||||
{
|
||||
struct nan_pasn_verify_eloop_ctx *ctx = user_data;
|
||||
struct nan_pasn_eloop_ctx *ctx = user_data;
|
||||
struct nan_pasn_data *pd;
|
||||
const uint8_t *ssid_arg;
|
||||
|
||||
(void)eloop_ctx;
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
pd = esp_nan_app_get_pasn_data();
|
||||
pd = nan_pasn_eloop_prepare(ctx, NULL);
|
||||
if (!pd) {
|
||||
os_free(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ssid_arg = ctx->ssid_len ? ctx->ssid : NULL;
|
||||
nan_initiate_pasn_verify(pd, ctx->peer_addr, ctx->freq, ctx->role,
|
||||
ctx->bssid, ssid_arg, ctx->ssid_len);
|
||||
nan_initiate_pasn_verify(pd, ctx->peer_addr, 0, NULL, NULL, 0);
|
||||
os_free(ctx);
|
||||
}
|
||||
|
||||
int nan_pasn_verify_eloop(unsigned int secs, unsigned int usecs,
|
||||
const uint8_t *peer_addr, int freq, int role,
|
||||
const uint8_t *bssid,
|
||||
const uint8_t *ssid, size_t ssid_len)
|
||||
int esp_nan_supp_pasn_initiator_verify(const uint8_t *peer_nmi,
|
||||
esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb)
|
||||
{
|
||||
struct nan_pasn_verify_eloop_ctx *ctx;
|
||||
struct nan_pasn_eloop_ctx *ctx;
|
||||
|
||||
if (!peer_addr) {
|
||||
return -1;
|
||||
}
|
||||
if (ssid_len > NAN_PASN_VERIFY_ELOOP_SSID_MAX) {
|
||||
if (!peer_nmi) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1688,20 +2035,10 @@ int nan_pasn_verify_eloop(unsigned int secs, unsigned int usecs,
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(ctx->peer_addr, peer_addr, ETH_ALEN);
|
||||
ctx->freq = freq;
|
||||
ctx->role = role;
|
||||
if (bssid) {
|
||||
os_memcpy(ctx->bssid, bssid, ETH_ALEN);
|
||||
} else {
|
||||
os_memcpy(ctx->bssid, peer_addr, ETH_ALEN);
|
||||
}
|
||||
if (ssid && ssid_len) {
|
||||
os_memcpy(ctx->ssid, ssid, ssid_len);
|
||||
ctx->ssid_len = ssid_len;
|
||||
}
|
||||
os_memcpy(ctx->peer_addr, peer_nmi, ETH_ALEN);
|
||||
ctx->pairing_key_installed_cb = pairing_key_installed_cb;
|
||||
|
||||
if (eloop_register_timeout(secs, usecs, nan_pasn_verify_eloop_cb, NULL, ctx) != 0) {
|
||||
if (eloop_register_timeout(0, 0, nan_pasn_verify_init_eloop_cb, NULL, ctx) != 0) {
|
||||
os_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
@@ -1717,9 +2054,11 @@ int nan_pasn_verify_eloop(unsigned int secs, unsigned int usecs,
|
||||
*
|
||||
* @param peer_addr Peer NAN address, or NULL to use a broadcast placeholder until Auth1.
|
||||
* @param pincode 6-digit value 0..999999, or @c UINT32_MAX to keep default PIN from @ref nan_pasn_data_init.
|
||||
* @param pairing_key_installed_cb Callback stored on the responder PASN context.
|
||||
* Returns 0 on success, -1 on failure.
|
||||
*/
|
||||
int pasn_responder_init(const uint8_t *peer_addr, uint32_t pincode)
|
||||
int pasn_responder_init(const uint8_t *peer_addr, uint32_t pincode,
|
||||
esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb)
|
||||
{
|
||||
struct nan_pasn_data *pd;
|
||||
struct nan_pasn_data *old;
|
||||
@@ -1728,11 +2067,20 @@ int pasn_responder_init(const uint8_t *peer_addr, uint32_t pincode)
|
||||
const u8 *peer = peer_addr ? peer_addr : bcast;
|
||||
const char *pin_to_apply = NULL;
|
||||
int n;
|
||||
int freq;
|
||||
|
||||
os_memset(pin_digits, 0, sizeof(pin_digits));
|
||||
|
||||
old = esp_nan_app_get_pasn_data();
|
||||
/* Lazy Auth1 init and scheduled bootstrap init can both call this; do not
|
||||
* tear down an in-progress responder session for the same peer. */
|
||||
if (old && old->dev_role == NAN_ROLE_PAIRING_RESPONDER && old->pasn &&
|
||||
!is_broadcast_ether_addr(peer) &&
|
||||
os_memcmp(old->pasn->peer_addr, peer, ETH_ALEN) == 0) {
|
||||
if (pairing_key_installed_cb) {
|
||||
old->pairing_key_installed_cb = pairing_key_installed_cb;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (old) {
|
||||
nan_pasn_data_deinit(old);
|
||||
}
|
||||
@@ -1743,6 +2091,7 @@ int pasn_responder_init(const uint8_t *peer_addr, uint32_t pincode)
|
||||
}
|
||||
|
||||
esp_nan_app_set_pasn_data(pd);
|
||||
pd->pairing_key_installed_cb = pairing_key_installed_cb;
|
||||
|
||||
if (pincode != UINT32_MAX) {
|
||||
n = os_snprintf(pin_digits, sizeof(pin_digits), "%06u",
|
||||
@@ -1757,13 +2106,8 @@ int pasn_responder_init(const uint8_t *peer_addr, uint32_t pincode)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
freq = nan_pasn_get_current_freq_mhz();
|
||||
if (freq <= 0) {
|
||||
freq = 2412;
|
||||
}
|
||||
|
||||
pd->dev_role = NAN_ROLE_PAIRING_RESPONDER;
|
||||
nan_pasn_initialize(pd, peer, freq, false, true);
|
||||
nan_pasn_initialize(pd, peer);
|
||||
|
||||
if (!pd->pasn || nan_prepare_pasn_extra_ie(pd, pd->pasn, NULL, false) != 0) {
|
||||
goto fail;
|
||||
@@ -1786,16 +2130,15 @@ struct pasn_responder_eloop_ctx {
|
||||
static void pasn_responder_init_eloop_cb(void *eloop_ctx, void *user_data)
|
||||
{
|
||||
struct pasn_responder_eloop_ctx *ctx = user_data;
|
||||
struct nan_pasn_data *pd;
|
||||
|
||||
(void)eloop_ctx;
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
if (pasn_responder_init(ctx->peer_addr, ctx->pincode) == 0) {
|
||||
pd = esp_nan_app_get_pasn_data();
|
||||
if (pasn_responder_init(ctx->peer_addr, ctx->pincode,
|
||||
ctx->pairing_key_installed_cb) == 0) {
|
||||
struct nan_pasn_data *pd = esp_nan_app_get_pasn_data();
|
||||
if (pd) {
|
||||
pd->pairing_key_installed_cb = ctx->pairing_key_installed_cb;
|
||||
pd->nik_lifetime_sec = ctx->nik_lifetime_sec;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,6 +342,9 @@ uint8_t esp_wifi_op_class_supported_internal(uint8_t op_class, uint8_t min_chan,
|
||||
bool esp_wifi_is_wpa3_compatible_mode_enabled(uint8_t if_index);
|
||||
uint8_t esp_wifi_ap_get_owe_config_internal(void);
|
||||
esp_err_t esp_nan_complete_pairing(uint8_t svc_id, uint8_t peer_svc_id);
|
||||
uint8_t *esp_wifi_nan_get_pairing_attrs(uint16_t bootstrap_methods, bool pairing_enabled,
|
||||
bool nik_cache_enabled, uint32_t *npba_len,
|
||||
uint32_t *dcea_len, uint32_t *total_len);
|
||||
esp_err_t esp_wifi_nan_load_saved_creds(uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN], bool *own_nik_valid,
|
||||
wifi_nan_peer_creds_t peer_creds[ESP_WIFI_NAN_MAX_PEER_CREDS], uint8_t *num_peer_creds);
|
||||
esp_err_t esp_wifi_nan_save_own_nik(const uint8_t own_nik[ESP_WIFI_NAN_NIK_LEN]);
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
#define IEEE802_11_H
|
||||
|
||||
enum wpa_validate_result;
|
||||
int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr);
|
||||
#ifdef CONFIG_SAE
|
||||
int auth_sae_queue(struct hostapd_data *hapd, u8 *buf, size_t len, u8 *bssid, u16 status, u32 auth_transaction);
|
||||
int handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *buf, size_t len, u8 *bssid,
|
||||
u16 auth_transaction, u16 status);
|
||||
#endif /* CONFIG_SAE */
|
||||
u16 wpa_res_to_status_code(enum wpa_validate_result res);
|
||||
#ifdef CONFIG_OWE_SOFTAP
|
||||
uint16_t owe_process_assoc_req(struct hostapd_data *hapd, struct sta_info *sta, const u8 *owe_dh,
|
||||
|
||||
@@ -52,7 +52,8 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
|
||||
unsigned int hash;
|
||||
|
||||
pmksa->pmksa_count--;
|
||||
pmksa->free_cb(entry, pmksa->ctx);
|
||||
if (pmksa->free_cb)
|
||||
pmksa->free_cb(entry, pmksa->ctx);
|
||||
|
||||
/* unlink from hash list */
|
||||
hash = PMKID_HASH(entry->pmkid);
|
||||
|
||||
@@ -48,7 +48,7 @@ enum nan_attr_id {
|
||||
NAN_ATTR_NDP_EXT = 0x29,
|
||||
NAN_ATTR_DCEA = 0x2A, /* Device Capability Extension attribute */
|
||||
NAN_ATTR_NIRA = 0x2B, /* NAN Identity Resolution attribute */
|
||||
NAN_ATTR_BPBA = 0x2C, /* NAN Pairing Bootstrapping attribute */
|
||||
NAN_ATTR_NPBA = 0x2C, /* NAN Pairing Bootstrapping attribute */
|
||||
NAN_ATTR_S3 = 0x2D,
|
||||
NAN_ATTR_TPEA = 0x2E, /* Transmit Power Envelope attribute */
|
||||
NAN_ATTR_VENDOR_SPECIFIC = 0xDD,
|
||||
|
||||
@@ -624,6 +624,9 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn,
|
||||
#else /* CONFIG_IEEE80211R */
|
||||
goto fail;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
} else if (verify && pasn->custom_pmkid_valid) {
|
||||
/* Wi-Fi Aware pairing verification: NPKID in RSNE, no wrapped data */
|
||||
pmkid = pasn->custom_pmkid;
|
||||
} else if (wrapped_data != WPA_PASN_WRAPPED_DATA_NO) {
|
||||
struct rsn_pmksa_cache_entry *pmksa;
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
|
||||
enum pmksa_free_reason reason)
|
||||
{
|
||||
pmksa->pmksa_count--;
|
||||
pmksa->free_cb(entry, pmksa->ctx, reason);
|
||||
if (pmksa->free_cb)
|
||||
pmksa->free_cb(entry, pmksa->ctx, reason);
|
||||
_pmksa_cache_free_entry(entry);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user