From 47ba837e98c15b2408afd03a27665a6aefbc74f0 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Thu, 15 Jul 2021 17:06:34 -0500 Subject: [PATCH] network: Store Transition Disable info This indication can come in via EAPoL message 3 or during FILS Association. It carries information as to whether certain transition mode options should be disabled. See WPA3 Specification, version 3 for more details. --- src/handshake.h | 1 + src/knownnetworks.h | 4 ++ src/network.c | 97 ++++++++++++++++++++++++++++++++++++--------- src/network.h | 3 ++ src/station.c | 8 ++++ 5 files changed, 95 insertions(+), 18 deletions(-) diff --git a/src/handshake.h b/src/handshake.h index ca4b58c6..6ceaeccf 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -54,6 +54,7 @@ enum handshake_event { HANDSHAKE_EVENT_FAILED, HANDSHAKE_EVENT_REKEY_FAILED, HANDSHAKE_EVENT_EAP_NOTIFY, + HANDSHAKE_EVENT_TRANSITION_DISABLE, }; typedef void (*handshake_event_func_t)(struct handshake_state *hs, diff --git a/src/knownnetworks.h b/src/knownnetworks.h index 5d1698c2..0a5c9e25 100644 --- a/src/knownnetworks.h +++ b/src/knownnetworks.h @@ -25,6 +25,8 @@ #define NET_AUTOCONNECT SETTINGS, "AutoConnect" #define NET_ALWAYS_RANDOMIZE_ADDRESS SETTINGS, "AlwaysRandomizeAddress" #define NET_ADDRESS_OVERRIDE SETTINGS, "AddressOverride" +#define NET_TRANSITION_DISABLE SETTINGS, "TransitionDisable" +#define NET_TRANSITION_DISABLE_MODES SETTINGS, "DisabledTransitionModes" enum security; struct scan_freq_set; @@ -67,6 +69,8 @@ struct network_config { bool override_addr:1; bool always_random_addr:1; uint8_t sta_addr[6]; + bool have_transition_disable : 1; + uint8_t transition_disable; }; struct network_info { diff --git a/src/network.c b/src/network.c index 6323cb28..68e625b4 100644 --- a/src/network.c +++ b/src/network.c @@ -83,6 +83,8 @@ struct network { bool ask_passphrase:1; /* Whether we should force-ask agent */ bool is_hs20:1; bool anqp_pending:1; /* Set if there is a pending ANQP request */ + uint8_t transition_disable; /* Temporary cache until info is set */ + bool have_transition_disable:1; int rank; /* Holds DBus Connect() message if it comes in before ANQP finishes */ struct l_dbus_message *connect_after_anqp; @@ -353,6 +355,29 @@ bool network_set_psk(struct network *network, const uint8_t *psk) return true; } +int network_set_transition_disable(struct network *network, + const uint8_t *td, size_t len) +{ + struct network_info *info = network->info; + /* We only recognize bits 0, 2, 3 */ + uint8_t supported_bitmask = 0x0d; + + if (len < 1) + return -EBADMSG; + + network->have_transition_disable = true; + network->transition_disable = td[0] & supported_bitmask; + + if (info && info->config.have_transition_disable && + info->config.transition_disable == + network->transition_disable) + return 0; + + network->sync_settings = true; + + return 0; +} + int network_get_signal_strength(const struct network *network) { struct scan_bss *best_bss = l_queue_peek_head(network->bss_list); @@ -608,26 +633,35 @@ static void network_settings_save_sae_pt_ecc(struct l_settings *settings, l_settings_set_bytes(settings, "Security", key, buf, len); } -void network_sync_settings(struct network *network) +static void network_settings_save(struct network *network, + struct l_settings *settings) { - struct l_settings *settings = network->settings; - struct l_settings *fs_settings; - const char *ssid = network_get_ssid(network); + if (network->have_transition_disable) { + char *modes[4]; + unsigned int i = 0; - if (!network->sync_settings) + l_settings_set_bool(settings, NET_TRANSITION_DISABLE, true); + + if (test_bit(&network->transition_disable, 0)) + modes[i++] = "personal"; + + if (test_bit(&network->transition_disable, 2)) + modes[i++] = "enterprise"; + + if (test_bit(&network->transition_disable, 3)) + modes[i++] = "open"; + + modes[i] = NULL; + + l_settings_set_string_list(settings, + NET_TRANSITION_DISABLE_MODES, + modes, ' '); + } + + if (network->security != SECURITY_PSK) return; - network->sync_settings = false; - - /* - * Re-open the settings from Disk, in case they were updated - * since we last opened them. We only update the [Security] - * bits here - */ - fs_settings = storage_network_open(SECURITY_PSK, ssid); - if (fs_settings) - settings = fs_settings; - + /* We only update the [Security] bits here, wipe the group first */ l_settings_remove_group(settings, "Security"); if (network->psk) @@ -643,11 +677,38 @@ void network_sync_settings(struct network *network) if (network->sae_pt_20) network_settings_save_sae_pt_ecc(settings, network->sae_pt_20); +} - storage_network_sync(SECURITY_PSK, ssid, settings); +void network_sync_settings(struct network *network) +{ + struct network_info *info = network->info; - if (fs_settings) + if (!network->sync_settings) + return; + + l_debug(""); + + network->sync_settings = false; + + /* + * Re-open the settings from Disk, in case they were updated + * since we last opened them. + */ + if (network->info) { + struct l_settings *fs_settings = info->ops->open(info); + + if (L_WARN_ON(!fs_settings)) + return; + + network_settings_save(network, fs_settings); + info->ops->sync(info, fs_settings); l_settings_free(fs_settings); + return; + } + + network_settings_save(network, network->settings); + storage_network_sync(network->security, network->ssid, + network->settings); } const struct network_info *network_get_info(const struct network *network) diff --git a/src/network.h b/src/network.h index 0130592e..1dc24124 100644 --- a/src/network.h +++ b/src/network.h @@ -46,6 +46,9 @@ struct l_settings *network_get_settings(const struct network *network); bool network_set_psk(struct network *network, const uint8_t *psk); +int network_set_transition_disable(struct network *network, + const uint8_t *td, size_t len); + int network_handshake_setup(struct network *network, struct handshake_state *hs); diff --git a/src/station.c b/src/station.c index 3431a707..75998215 100644 --- a/src/station.c +++ b/src/station.c @@ -714,6 +714,14 @@ static void station_handshake_event(struct handshake_state *hs, l_warn("Unable to securely rekey on this hw/kernel..."); station_reconnect(station); break; + case HANDSHAKE_EVENT_TRANSITION_DISABLE: + { + const uint8_t *td = va_arg(args, const uint8_t *); + size_t len = va_arg(args, size_t); + + network_set_transition_disable(network, td, len); + break; + } case HANDSHAKE_EVENT_COMPLETE: case HANDSHAKE_EVENT_SETTING_KEYS_FAILED: case HANDSHAKE_EVENT_EAP_NOTIFY: