From: Peddolla Harshavardhan Reddy Date: Mon, 28 Apr 2025 09:50:50 +0000 (+0530) Subject: PR: PASN authentication initialization for Proximity Ranging X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b1c478f03a5f40c620493537917cc9c5e25d0c36;p=thirdparty%2Fhostap.git PR: PASN authentication initialization for Proximity Ranging Proximity Ranging negotiation is performed by wrapping PR element(s) onto PASN Authentication frames. Add functionality to initiate PASN and enable this negotiation process. The negotiation determines the roles, the type of ranging, and the channel on which the ranging should be conducted. Signed-off-by: Peddolla Harshavardhan Reddy --- diff --git a/src/common/proximity_ranging.c b/src/common/proximity_ranging.c index 28475e624..fea0c3dda 100644 --- a/src/common/proximity_ranging.c +++ b/src/common/proximity_ranging.c @@ -12,6 +12,7 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "crypto/sha256.h" +#include "pasn/pasn_common.h" #include "proximity_ranging.h" @@ -23,6 +24,12 @@ static bool valid_country_ch(char c) static void pr_device_free(struct pr_data *pr, struct pr_device *dev) { +#ifdef CONFIG_PASN + if (dev->pasn) { + wpa_pasn_reset(dev->pasn); + pasn_data_deinit(dev->pasn); + } +#endif /* CONFIG_PASN */ os_free(dev); } @@ -1029,3 +1036,129 @@ void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len, pr_parse_free(&msg); } + + +#ifdef CONFIG_PASN + +static int pr_pasn_initialize(struct pr_data *pr, struct pr_device *dev, + const u8 *addr, u8 auth_mode, int freq, + u8 ranging_type) +{ + struct pasn_data *pasn; + + if (dev->pasn) { + wpa_pasn_reset(dev->pasn); + } else { + dev->pasn = pasn_data_init(); + if (!dev->pasn) + return -1; + } + + pasn = dev->pasn; + os_memcpy(pasn->own_addr, pr->cfg->dev_addr, ETH_ALEN); + os_memcpy(pasn->peer_addr, addr, ETH_ALEN); + + if (dev->pasn_role == PR_ROLE_PASN_INITIATOR) + os_memcpy(pasn->bssid, pasn->peer_addr, ETH_ALEN); + else + os_memcpy(pasn->bssid, pasn->own_addr, ETH_ALEN); + + pasn->noauth = 1; + + /* As specified in Proximity Ranging Implementation Considerations for + * P2P Operation D1.8, unauthenticated mode PASN with DH group 19 + * should be supported by all P2P proximity ranging devices. */ + if (!(pr->cfg->pasn_type & BIT(0)) || + !(dev->pr_caps.pasn_type & BIT(0))) { + wpa_printf(MSG_DEBUG, + "PR PASN: Unauthenticated DH group 19 NOT supported, PASN type of self 0x%x, peer 0x%x", + pr->cfg->pasn_type, dev->pr_caps.pasn_type); + return -1; + } + + /* As specified in Proximity Ranging Implementation Considerations for + * P2P Operation D1.8, EDCA based ranging is only supported with + * unauthenticated mode PASN with DH group 19. */ + if (((pr->cfg->pasn_type & 0xc) && (dev->pr_caps.pasn_type & 0xc)) && + ranging_type != PR_EDCA_BASED_RANGING) { + pasn->group = 20; + pasn->cipher = WPA_CIPHER_GCMP_256; + } else { + pasn->group = 19; + pasn->cipher = WPA_CIPHER_CCMP; + } + + if (pr->cfg->secure_he_ltf && + ranging_type == PR_NTB_SECURE_LTF_BASED_RANGING) { + pasn->secure_ltf = true; + pasn_enable_kdk_derivation(pasn); + } else { + pasn_disable_kdk_derivation(pasn); + } + wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len); + + if (auth_mode == PR_PASN_AUTH_MODE_SAE) + pasn->akmp = WPA_KEY_MGMT_SAE; + else if (auth_mode == PR_PASN_AUTH_MODE_PMK) + pasn->akmp = WPA_KEY_MGMT_SAE; + else + pasn->akmp = WPA_KEY_MGMT_PASN; + + pasn->rsn_pairwise = pasn->cipher; + pasn->wpa_key_mgmt = pasn->akmp; + + pasn->cb_ctx = pr->cfg->cb_ctx; + pasn->send_mgmt = pr->cfg->pasn_send_mgmt; + pasn->freq = freq; + return 0; +} + + +int pr_initiate_pasn_auth(struct pr_data *pr, const u8 *addr, int freq, + u8 auth_mode, u8 ranging_role, u8 ranging_type, + int forced_pr_freq) +{ + int ret = 0; + struct pasn_data *pasn; + struct pr_device *dev; + + if (!addr) { + wpa_printf(MSG_DEBUG, "PR PASN: Peer address NULL"); + return -1; + } + + dev = pr_get_device(pr, addr); + if (!dev) { + wpa_printf(MSG_DEBUG, "PR PASN: Peer not known"); + return -1; + } + + if (freq == 0) + freq = dev->listen_freq; + + dev->pasn_role = PR_ROLE_PASN_INITIATOR; + + if (pr_pasn_initialize(pr, dev, addr, auth_mode, freq, ranging_type)) { + wpa_printf(MSG_INFO, "PR PASN: Initialization failed"); + return -1; + } + pasn = dev->pasn; + + if (auth_mode == PR_PASN_AUTH_MODE_PMK) { + ret = wpa_pasn_verify(pasn, pasn->own_addr, pasn->peer_addr, + pasn->bssid, pasn->akmp, pasn->cipher, + pasn->group, pasn->freq, NULL, 0, NULL, 0, + NULL); + } else { + ret = wpas_pasn_start(pasn, pasn->own_addr, pasn->peer_addr, + pasn->bssid, pasn->akmp, pasn->cipher, + pasn->group, pasn->freq, NULL, 0, NULL, 0, + NULL); + } + if (ret) + wpa_printf(MSG_INFO, "PR PASN: Failed to start PASN"); + + return ret; +} + +#endif /* CONFIG_PASN */ diff --git a/src/common/proximity_ranging.h b/src/common/proximity_ranging.h index 5eedcd674..28f667422 100644 --- a/src/common/proximity_ranging.h +++ b/src/common/proximity_ranging.h @@ -37,6 +37,12 @@ */ #define PR_MAX_PEER 100 +enum pr_pasn_role { + PR_ROLE_IDLE = 0, + PR_ROLE_PASN_INITIATOR, + PR_ROLE_PASN_RESPONDER, +}; + /** * struct pr_channels - List of supported channels */ @@ -226,6 +232,21 @@ enum pr_attr_id { #define PR_ISTA_SUPPORT BIT(0) #define PR_RSTA_SUPPORT BIT(1) +/* + * PASN capabilities in PASN Type field + * Proximity Ranging Implementation Considerations for P2P Operation D1.8, + * Table 7 (Proximity Ranging Capability Attribute). + */ +#define PR_PASN_DH19_UNAUTH BIT(0) +#define PR_PASN_DH19_AUTH BIT(1) +#define PR_PASN_DH20_UNAUTH BIT(2) +#define PR_PASN_DH20_AUTH BIT(3) + +/* Authentication Mode */ +#define PR_PASN_AUTH_MODE_PASN 0 +#define PR_PASN_AUTH_MODE_SAE 1 +#define PR_PASN_AUTH_MODE_PMK 2 + struct pr_dev_ik { struct dl_list list; u8 dik[DEVICE_IDENTITY_KEY_LEN]; @@ -263,6 +284,12 @@ struct pr_device { */ u8 pmk[PMK_LEN_MAX]; bool pmk_valid; + +#ifdef CONFIG_PASN + /* PASN data structure */ + struct pasn_data *pasn; + enum pr_pasn_role pasn_role; +#endif /* CONFIG_PASN */ }; @@ -369,6 +396,20 @@ struct pr_config { * cb_ctx - Context to use with callback functions */ void *cb_ctx; + + /** + * pasn_send_mgmt - Function handler to transmit a Management frame + * @ctx: Callback context from cb_ctx + * @data: Frame to transmit + * @data_len: Length of frame to transmit + * @noack: No ack flag + * @freq: Frequency in MHz for the channel on which to transmit + * @wait: How many milliseconds to wait for a response frame + * Returns: 0 on success, -1 on failure + */ + int (*pasn_send_mgmt)(void *ctx, const u8 *data, size_t data_len, + int noack, unsigned int freq, unsigned int wait); + }; struct pr_data { @@ -407,5 +448,8 @@ void pr_add_dev_ik(struct pr_data *pr, const u8 *dik, const char *password, struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr); void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len, const u8 *peer_addr, unsigned int freq); +int pr_initiate_pasn_auth(struct pr_data *pr, const u8 *addr, int freq, + u8 auth_mode, u8 ranging_role, u8 ranging_type, + int forced_pr_freq); #endif /* PROXIMITY_RANGING_H */ diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h index fd2b71ace..182b76558 100644 --- a/src/pasn/pasn_common.h +++ b/src/pasn/pasn_common.h @@ -12,6 +12,12 @@ #ifndef PASN_COMMON_H #define PASN_COMMON_H +#include "common/wpa_common.h" +#ifdef CONFIG_SAE +#include "common/sae.h" +#endif /* CONFIG_SAE */ +#include "crypto/sha384.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/wpa_supplicant/pr_supplicant.c b/wpa_supplicant/pr_supplicant.c index bf6905e50..7f7fdf143 100644 --- a/wpa_supplicant/pr_supplicant.c +++ b/wpa_supplicant/pr_supplicant.c @@ -9,12 +9,18 @@ #include "includes.h" #include "utils/common.h" +#include "utils/eloop.h" #include "common/proximity_ranging.h" #include "p2p/p2p.h" #include "wpa_supplicant_i.h" #include "config.h" +#include "driver_i.h" #include "pr_supplicant.h" +#ifdef CONFIG_PASN +static void wpas_pr_pasn_timeout(void *eloop_ctx, void *timeout_ctx); +#endif /* CONFIG_PASN */ + static int wpas_pr_edca_get_bw(enum edca_format_and_bw_value format_and_bw) { @@ -239,6 +245,16 @@ wpas_pr_setup_ntb_channels(struct wpa_supplicant *wpa_s, } +static int wpas_pr_pasn_send_mgmt(void *ctx, const u8 *data, size_t data_len, + int noack, unsigned int freq, + unsigned int wait) +{ + struct wpa_supplicant *wpa_s = ctx; + + return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait); +} + + struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s) { return pr_prepare_usd_elems(wpa_s->global->pr); @@ -300,6 +316,8 @@ int wpas_pr_init(struct wpa_global *global, struct wpa_supplicant *wpa_s, pr.support_6ghz = wpas_is_6ghz_supported(wpa_s, true); + pr.pasn_send_mgmt = wpas_pr_pasn_send_mgmt; + pr.secure_he_ltf = wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA; wpas_pr_setup_ntb_channels(wpa_s, &pr.ntb_channels, @@ -360,6 +378,10 @@ void wpas_pr_deinit(struct wpa_supplicant *wpa_s) wpa_s->global->pr = NULL; wpa_s->global->pr_init_wpa_s = NULL; } + +#ifdef CONFIG_PASN + eloop_cancel_timeout(wpas_pr_pasn_timeout, wpa_s, NULL); +#endif /* CONFIG_PASN */ } @@ -384,3 +406,124 @@ void wpas_pr_set_dev_ik(struct wpa_supplicant *wpa_s, const u8 *dik, pr_add_dev_ik(pr, dik, password, pmk, own); } + + +#ifdef CONFIG_PASN + +struct wpa_pr_pasn_auth_work { + u8 peer_addr[ETH_ALEN]; + u8 auth_mode; + int freq; + enum pr_pasn_role role; + u8 ranging_role; + u8 ranging_type; + u8 *ssid; + size_t ssid_len; + u8 bssid[ETH_ALEN]; + int forced_pr_freq; +}; + + +static void wpas_pr_pasn_free_auth_work(struct wpa_pr_pasn_auth_work *awork) +{ + if (!awork) + return; + os_free(awork->ssid); + os_free(awork); +} + + +static void wpas_pr_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "PR PASN: Cancel pr-pasn-start-auth work"); + + /* Remove pending/started work */ + radio_remove_works(wpa_s, "pr-pasn-start-auth", 0); +} + + +static void wpas_pr_pasn_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (wpa_s->pr_pasn_auth_work) { + wpas_pr_pasn_cancel_auth_work(wpa_s); + wpa_s->pr_pasn_auth_work = NULL; + } + wpa_printf(MSG_DEBUG, "PR: PASN timed out"); +} + + +static void wpas_pr_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) +{ + int ret; + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpa_pr_pasn_auth_work *awork = work->ctx; + struct pr_data *pr = wpa_s->global->pr; + const u8 *peer_addr = NULL; + + if (deinit) { + if (!work->started) + eloop_cancel_timeout(wpas_pr_pasn_timeout, wpa_s, NULL); + + wpas_pr_pasn_free_auth_work(awork); + return; + } + + if (!is_zero_ether_addr(awork->peer_addr)) + peer_addr = awork->peer_addr; + + ret = pr_initiate_pasn_auth(pr, peer_addr, awork->freq, + awork->auth_mode, awork->ranging_role, + awork->ranging_type, awork->forced_pr_freq); + if (ret) { + wpa_printf(MSG_DEBUG, + "PR PASN: Failed to start PASN authentication"); + goto fail; + } + + eloop_cancel_timeout(wpas_pr_pasn_timeout, wpa_s, NULL); + eloop_register_timeout(2, 0, wpas_pr_pasn_timeout, wpa_s, NULL); + wpa_s->pr_pasn_auth_work = work; + return; + +fail: + wpas_pr_pasn_free_auth_work(awork); + work->ctx = NULL; + radio_work_done(work); +} + + +int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int freq, u8 auth_mode, + u8 ranging_role, u8 ranging_type, + int forced_pr_freq) +{ + struct wpa_pr_pasn_auth_work *awork; + + wpas_pr_pasn_cancel_auth_work(wpa_s); + wpa_s->pr_pasn_auth_work = NULL; + + awork = os_zalloc(sizeof(*awork)); + if (!awork) + return -1; + + awork->freq = freq; + os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN); + awork->ranging_role = ranging_role; + awork->ranging_type = ranging_type; + awork->auth_mode = auth_mode; + awork->forced_pr_freq = forced_pr_freq; + + if (radio_add_work(wpa_s, freq, "pr-pasn-start-auth", 1, + wpas_pr_pasn_auth_start_cb, awork) < 0) { + wpas_pr_pasn_free_auth_work(awork); + return -1; + } + + wpa_printf(MSG_DEBUG, + "PR PASN: Authentication work successfully added"); + return 0; +} + +#endif /* CONFIG_PASN */ diff --git a/wpa_supplicant/pr_supplicant.h b/wpa_supplicant/pr_supplicant.h index 931d30780..920a859ec 100644 --- a/wpa_supplicant/pr_supplicant.h +++ b/wpa_supplicant/pr_supplicant.h @@ -21,6 +21,10 @@ struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s); void wpas_pr_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf, u16 buf_len, const u8 *peer_addr, unsigned int freq); +int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int freq, u8 auth_mode, + u8 ranging_role, u8 ranging_type, + int forced_pr_freq); #else /* CONFIG_PR */ @@ -50,6 +54,15 @@ static inline struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s) return NULL; } +static inline int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int freq, + u8 auth_mode, u8 ranging_role, + u8 ranging_type, + int forced_pr_freq) +{ + return 0; +} + #endif /* CONFIG_PR */ #endif /* PR_SUPPLICANT_H */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 676c01702..9780822df 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1608,6 +1608,7 @@ struct wpa_supplicant { #ifdef CONFIG_P2P struct wpa_radio_work *p2p_pasn_auth_work; #endif /* CONFIG_P2P */ + struct wpa_radio_work *pr_pasn_auth_work; #endif /* CONFIG_PASN */ bool is_6ghz_enabled;