feat(esp_wifi): Add improvements for privacy extension

1) Add support for MAC randomization in Active scan and connect
  2) Add support for randomizaton of sequence numbers
  3) Add support for randomization of dialog token for GAS frames
This commit is contained in:
Aditi
2024-10-18 04:30:56 +05:30
committed by BOT
parent 3bf83125b4
commit 18cbdbf2b1
15 changed files with 130 additions and 15 deletions

View File

@@ -117,6 +117,8 @@ esp_err_t esp_efuse_mac_get_default(uint8_t *mac);
* Then calculates the MAC address of the specific interface requested,
* refer to ESP-IDF Programming Guide for the algorithm.
*
* @note This function reads MAC address directly from efuse(and might be different from MAC address read using esp_wifi_get_mac() API).
*
* The MAC address set by the esp_iface_mac_addr_set() function will not depend on the base MAC address.
*
* @param mac base MAC address, length: 6 bytes/8 bytes.

View File

@@ -925,6 +925,21 @@ menu "Wi-Fi"
Select this option to enable/disable support for station connections
to hidden APs using passive scan when the country policy is set to auto.
config ESP_WIFI_STA_RANDOM_MAC_ENABLED
bool "Station Mac-Randomization enabled"
default y
help
Select this option to enable Mac Randomization for Station
config ESP_WIFI_STA_RANDOM_MAC_AUTO_RESET_INTERVAL
int "Station Mac-Randomization Auto-Reset Interval time"
depends on ESP_WIFI_STA_RANDOM_MAC_ENABLED
range 1 24
default 12
help
Interval in hours to rotate the STA random MAC while not connected to an AP.
Values below 1 or above 24 are not allowed.
endif # wifi enabled
endmenu # Wi-Fi

View File

@@ -120,6 +120,8 @@ typedef struct {
int espnow_max_encrypt_num; /**< Maximum encrypt number of peers supported by espnow */
int tx_hetb_queue_num; /**< WiFi TX HE TB QUEUE number for STA HE TB PPDU transmission */
bool dump_hesigb_enable; /**< enable dump sigb field */
bool sta_random_mac; /**< STA MAC randomization. Supported on station interface only; softAP may be added in future */
uint8_t sta_rmac_auto_reset_int;/**< STA random MAC auto-reset interval in hours (1-24) while not connected */
int magic; /**< WiFi init magic number, it should be the last field */
} wifi_init_config_t;
@@ -347,6 +349,8 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs;
.espnow_max_encrypt_num = CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM, \
.tx_hetb_queue_num = WIFI_TX_HETB_QUEUE_NUM, \
.dump_hesigb_enable = WIFI_DUMP_HESIGB_ENABLED, \
.sta_random_mac = CONFIG_ESP_WIFI_STA_RANDOM_MAC_ENABLED, \
.sta_rmac_auto_reset_int = CONFIG_ESP_WIFI_STA_RANDOM_MAC_AUTO_RESET_INTERVAL, \
.magic = WIFI_INIT_CONFIG_MAGIC\
}

View File

@@ -904,6 +904,21 @@ config WIFI_RMT_PASSIVE_HIDDEN_AP_SUPPORT
Select this option to enable/disable support for station connections
to hidden APs using passive scan when the country policy is set to auto.
config WIFI_RMT_STA_RANDOM_MAC_ENABLED
bool "Station Mac-Randomization enabled"
default y
help
Select this option to enable Mac Randomization for Station
config WIFI_RMT_STA_RANDOM_MAC_AUTO_RESET_INTERVAL
int "Station Mac-Randomization Auto-Reset Interval time"
depends on WIFI_RMT_STA_RANDOM_MAC_ENABLED
range 1 24
default 12
help
Interval in hours to rotate the STA random MAC while not connected to an AP.
Values below 1 or above 24 are not allowed.
if !ESP_WIFI_ENABLED
rsource "Kconfig.wifi_is_remote.in"
endif # ESP_WIFI_ENABLED

View File

@@ -512,3 +512,14 @@ if WIFI_RMT_PASSIVE_HIDDEN_AP_SUPPORT
bool
default WIFI_RMT_PASSIVE_HIDDEN_AP_SUPPORT
endif
if WIFI_RMT_STA_RANDOM_MAC_ENABLED
config ESP_WIFI_STA_RANDOM_MAC_ENABLED # ignore: multiple-definition
bool
default WIFI_RMT_STA_RANDOM_MAC_ENABLED
endif
config ESP_WIFI_STA_RANDOM_MAC_AUTO_RESET_INTERVAL # ignore: multiple-definition
int
depends on WIFI_RMT_STA_RANDOM_MAC_ENABLED
default WIFI_RMT_STA_RANDOM_MAC_AUTO_RESET_INTERVAL

View File

@@ -120,6 +120,8 @@ typedef struct {
int espnow_max_encrypt_num; /**< Maximum encrypt number of peers supported by espnow */
int tx_hetb_queue_num; /**< WiFi TX HE TB QUEUE number for STA HE TB PPDU transmission */
bool dump_hesigb_enable; /**< enable dump sigb field */
bool sta_random_mac; /**< STA MAC randomization. Supported on station interface only; softAP may be added in future */
uint8_t sta_rmac_auto_reset_int;/**< STA random MAC auto-reset interval in hours (1-24) while not connected */
int magic; /**< WiFi init magic number, it should be the last field */
} wifi_init_config_t;
@@ -347,6 +349,8 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs;
.espnow_max_encrypt_num = CONFIG_WIFI_RMT_ESPNOW_MAX_ENCRYPT_NUM, \
.tx_hetb_queue_num = WIFI_TX_HETB_QUEUE_NUM, \
.dump_hesigb_enable = WIFI_DUMP_HESIGB_ENABLED, \
.sta_random_mac = CONFIG_WIFI_RMT_STA_RANDOM_MAC_ENABLED, \
.sta_rmac_auto_reset_int = CONFIG_WIFI_RMT_STA_RANDOM_MAC_AUTO_RESET_INTERVAL, \
.magic = WIFI_INIT_CONFIG_MAGIC\
}

View File

@@ -119,6 +119,13 @@ static void wifi_default_action_sta_connected(void *arg, esp_event_base_t base,
}
}
#if CONFIG_ESP_WIFI_STA_RANDOM_MAC_ENABLED
/* Sync netif MAC when STA random MAC was set internally by the Wi-Fi driver */
uint8_t mac[6];
esp_wifi_get_mac(WIFI_IF_STA, mac);
esp_netif_set_mac(esp_netif, mac);
#endif
esp_netif_action_connected(s_wifi_netifs[WIFI_IF_STA], base, event_id, data);
}
}

View File

@@ -620,6 +620,18 @@ static void esp_dpp_rx_action(void *data, void *user_ctx)
public_action->v.pa_gas_resp.length == 8 &&
public_action->v.pa_gas_resp.status_code == 0) {
if (!s_dpp_ctx.dpp_auth ||
public_action->v.pa_gas_resp.diag_token !=
s_dpp_ctx.dpp_auth->gas_dialog_token) {
wpa_printf(MSG_DEBUG,
"DPP: GAS dialog token mismatch (rx=%u exp=%u) - drop",
public_action->v.pa_gas_resp.diag_token,
s_dpp_ctx.dpp_auth ?
s_dpp_ctx.dpp_auth->gas_dialog_token : 0);
os_free(rx_param);
return;
}
rx_param->vendor_data_len = rx_param->frm_len -
(size_t)(public_action->v.pa_gas_resp.data +
public_action->v.pa_gas_resp.length -

View File

@@ -33,7 +33,6 @@ struct dpp_bootstrap_params_t {
struct esp_dpp_context_t {
struct dpp_bootstrap_params_t bootstrap_params;
struct dpp_authentication *dpp_auth;
int gas_dialog_token;
struct dpp_global *dpp_global;
wifi_config_t wifi_cfg;
int id;

View File

@@ -1368,6 +1368,7 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
const char *json)
{
struct wpabuf *buf, *conf_req;
u8 dialog_token;
conf_req = dpp_build_conf_req_attr(auth, json);
if (!conf_req) {
@@ -1376,7 +1377,12 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
return NULL;
}
buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
do {
dialog_token = os_random() & 0xff;
} while (!dialog_token);
auth->gas_dialog_token = dialog_token;
buf = gas_build_initial_req(dialog_token, 10 + 2 + wpabuf_len(conf_req));
if (!buf) {
wpabuf_free(conf_req);
return NULL;

View File

@@ -311,6 +311,7 @@ struct dpp_authentication {
int send_conn_status;
int conn_status_requested;
int akm_use_selector;
u8 gas_dialog_token; /* Dialog Token used in GAS Initial Request */
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;

View File

@@ -165,6 +165,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
entry->reauth_time = now.sec + dot11RSNAConfigPMKLifetime / 100 * dot11RSNAConfigPMKReauthThreshold;
entry->akmp = akmp;
os_memcpy(entry->aa, aa, ETH_ALEN);
os_memcpy(entry->spa, spa, ETH_ALEN);
entry->network_ctx = network_ctx;
return pmksa_cache_add_entry(pmksa, entry);
@@ -335,12 +336,13 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
* pmksa_cache_get - Fetch a PMKSA cache entry
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @aa: Authenticator address or %NULL to match any
* @spa: Supplicant address or %NULL to skip SPA matching (not recommended)
* @pmkid: PMKID or %NULL to match any
* @network_ctx: Network context or %NULL to match any
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
*/
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid,
const u8 *aa, const u8 *spa, const u8 *pmkid,
const void *network_ctx)
{
if(!pmksa)
@@ -348,6 +350,8 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
while (entry) {
if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
(spa == NULL ||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
(pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
(network_ctx == NULL || network_ctx == entry->network_ctx))
@@ -468,10 +472,10 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
sm->cur_pmksa = NULL;
if (pmkid)
sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, sm->own_addr, pmkid,
network_ctx);
if (sm->cur_pmksa == NULL && bssid)
sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, sm->own_addr, NULL,
network_ctx);
if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
@@ -504,7 +508,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
ret = os_snprintf(pos, buf + len - pos,
"Index / AA / PMKID / expiration (in seconds) / "
"Index / AA / SPA / PMKID / expiration (in seconds) / "
"opportunistic\n");
if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
@@ -514,8 +518,8 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
os_get_reltime(&now);
while (entry) {
i++;
ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
i, MAC2STR(entry->aa));
ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " " MACSTR " ",
i, MAC2STR(entry->aa), MAC2STR(entry->spa));
if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;

View File

@@ -20,6 +20,8 @@ struct rsn_pmksa_cache_entry {
os_time_t expiration;
int akmp; /* WPA_KEY_MGMT_* */
u8 aa[ETH_ALEN];
/** Supplicant MAC (SPA) this PMKSA was created for; used when matching cache */
u8 spa[ETH_ALEN];
os_time_t reauth_time;
@@ -52,7 +54,7 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx, struct wpa_sm *sm);
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid,
const u8 *aa, const u8 *spa, const u8 *pmkid,
const void *network_ctx);
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
struct rsn_pmksa_cache_entry *
@@ -90,8 +92,8 @@ static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
}
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
const void *network_ctx)
pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
const u8 *pmkid, const void *network_ctx)
{
return NULL;
}

View File

@@ -400,8 +400,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
* not have enough time to get the association information
* event before receiving this 1/4 message, so try to find a
* matching PMKSA cache entry here. */
sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
NULL);
sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr,
pmkid, NULL);
if (sm->cur_pmksa) {
wpa_printf(MSG_DEBUG,
"RSN: found matching PMKID from PMKSA cache");
@@ -470,7 +470,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
sm->network_ctx, sm->key_mgmt);
}
if (!sm->cur_pmksa && pmkid &&
pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr, pmkid, NULL))
{
wpa_printf( MSG_DEBUG,
"RSN: the new PMK matches with the "
@@ -2687,7 +2687,8 @@ int wpa_set_bss(uint8_t *macddr, uint8_t *bssid, uint8_t pairwise_cipher, uint8_
struct rsn_pmksa_cache_entry *pmksa = NULL;
if (use_pmk_cache) {
pmksa = pmksa_cache_get(sm->pmksa, (const u8 *)bssid, NULL, NULL);
pmksa = pmksa_cache_get(sm->pmksa, (const u8 *)bssid, sm->own_addr,
NULL, NULL);
if (pmksa && (pmksa->akmp != sm->key_mgmt)) {
use_pmk_cache = false;
}

View File

@@ -171,3 +171,35 @@ A configuration option :ref:`CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA` and configurat
For softap mode :
A configuration option :ref:`CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_SOFTAP` from menuconfig should be enabled and configuration parameter `authmode` from :cpp:type:`wifi_ap_config_t` should be set to ``WIFI_AUTH_OWE``. SoftAP does not support OWE Transition Mode; configure ``WIFI_AUTH_OWE`` only.
MAC Address Randomization
--------------------------
MAC addresses, used by devices to connect to Wi-Fi networks, can be captured and tracked because they are transmitted without encryption and due to their unique and static nature. {IDF_TARGET_NAME} supports the MAC randomization feature which enhances privacy by using a randomized MAC address, preventing devices from being consistently tracked when scanning or connecting to networks.
To use this feature, enable configuration option :ref:`CONFIG_ESP_WIFI_STA_RANDOM_MAC_ENABLED` from menuconfig.
{IDF_TARGET_NAME} also rotates the STA random MAC periodically while not connected, using menuconfig option :ref:`CONFIG_ESP_WIFI_STA_RANDOM_MAC_AUTO_RESET_INTERVAL` (valid range: 1 to 24 hours, default 12).
.. note::
The `CONFIG_ESP_WIFI_STA_RANDOM_MAC_AUTO_RESET_INTERVAL` will only generate and set new random mac address when station is not connected to any AP. If the station is connected to any AP, the connection will not be interrupted and same random mac will be used.
For every new connection request, new random mac will be generated and auto reset time interval will be reset if `CONFIG_ESP_WIFI_STA_RANDOM_MAC_ENABLED` is enabled.
PMK caching is not supported when MAC randomization is enabled, as the device's identity changes with each connection attempt.
{IDF_TARGET_NAME} supports MAC randomization while scanning when
- enable configuration option :ref:`CONFIG_ESP_WIFI_STA_RANDOM_MAC_ENABLED` from menuconfig
- scan_type is :cpp:enumerator:`WIFI_SCAN_TYPE_ACTIVE`
- station is not connected to any Access Point
{IDF_TARGET_NAME} supports MAC randomization while connecting when
- enable configuration option :ref:`CONFIG_ESP_WIFI_STA_RANDOM_MAC_ENABLED` from menuconfig
- new wifi configuration is set using esp_wifi_set_config()
To get the mac address, please use API :cpp:func:`esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);`