network: Generate PSK lazily

In cases where networks are WPA3 only, there's no point to actually
generate the PSK.  Do so only if needed (network_get_psk gets called)
This commit is contained in:
Denis Kenzior 2021-07-06 14:32:05 -05:00
parent a8e2023a8e
commit 27583e6b35
1 changed files with 33 additions and 64 deletions

View File

@ -104,12 +104,13 @@ static void network_reset_psk(struct network *network)
static void network_reset_passphrase(struct network *network) static void network_reset_passphrase(struct network *network)
{ {
if (network->passphrase) if (network->passphrase) {
explicit_bzero(network->passphrase, explicit_bzero(network->passphrase,
strlen(network->passphrase)); strlen(network->passphrase));
l_free(network->passphrase);
network->passphrase = NULL;
}
l_free(network->passphrase);
network->passphrase = NULL;
} }
static void network_settings_close(struct network *network) static void network_settings_close(struct network *network)
@ -260,18 +261,22 @@ enum security network_get_security(const struct network *network)
const uint8_t *network_get_psk(struct network *network) const uint8_t *network_get_psk(struct network *network)
{ {
int r;
if (network->psk) if (network->psk)
return network->psk; return network->psk;
network->psk = l_malloc(32); network->psk = l_malloc(32);
if (crypto_psk_from_passphrase(network->passphrase, if ((r = crypto_psk_from_passphrase(network->passphrase,
(unsigned char *)network->ssid, (unsigned char *)network->ssid,
strlen(network->ssid), strlen(network->ssid),
network->psk) < 0) { network->psk)) < 0) {
l_free(network->psk); l_free(network->psk);
network->psk = NULL; network->psk = NULL;
} l_error("PSK generation failed: %s.", strerror(-r));
} else
network->sync_settings = true;
return network->psk; return network->psk;
} }
@ -281,21 +286,29 @@ const char *network_get_passphrase(const struct network *network)
return network->passphrase; return network->passphrase;
} }
static bool __network_set_passphrase(struct network *network,
const char *passphrase)
{
if (!passphrase || !crypto_passphrase_is_valid(passphrase))
return false;
network_reset_passphrase(network);
network->passphrase = l_strdup(passphrase);
network->sync_settings = true;
return true;
}
bool network_set_passphrase(struct network *network, const char *passphrase) bool network_set_passphrase(struct network *network, const char *passphrase)
{ {
if (network_get_security(network) != SECURITY_PSK) if (network_get_security(network) != SECURITY_PSK)
return false; return false;
if (!crypto_passphrase_is_valid(passphrase))
return false;
if (!network_settings_load(network)) if (!network_settings_load(network))
network->settings = l_settings_new(); network->settings = l_settings_new();
network_reset_passphrase(network); return __network_set_passphrase(network, passphrase);
network->passphrase = l_strdup(passphrase);
return true;
} }
struct l_queue *network_get_secrets(const struct network *network) struct l_queue *network_get_secrets(const struct network *network)
@ -380,14 +393,14 @@ static int network_load_psk(struct network *network, bool need_passphrase)
const char *ssid = network_get_ssid(network); const char *ssid = network_get_ssid(network);
enum security security = network_get_security(network); enum security security = network_get_security(network);
size_t psk_len; size_t psk_len;
uint8_t *psk = l_settings_get_bytes(network->settings, "Security", _auto_(l_free) uint8_t *psk =
l_settings_get_bytes(network->settings, "Security",
"PreSharedKey", &psk_len); "PreSharedKey", &psk_len);
_auto_(l_free) char *passphrase = _auto_(l_free) char *passphrase =
l_settings_get_string(network->settings, l_settings_get_string(network->settings,
"Security", "Passphrase"); "Security", "Passphrase");
_auto_(l_free) char *path = _auto_(l_free) char *path =
storage_get_network_file_path(security, ssid); storage_get_network_file_path(security, ssid);
int r;
if (psk && psk_len != 32) { if (psk && psk_len != 32) {
l_error("%s: invalid PreSharedKey format", path); l_error("%s: invalid PreSharedKey format", path);
@ -411,25 +424,9 @@ static int network_load_psk(struct network *network, bool need_passphrase)
network_reset_psk(network); network_reset_psk(network);
network->passphrase = l_steal_ptr(passphrase); network->passphrase = l_steal_ptr(passphrase);
if (psk) { network->psk = l_steal_ptr(psk);
network->psk = psk;
return 0;
}
network->psk = l_malloc(32); return 0;
r = crypto_psk_from_passphrase(network->passphrase, (uint8_t *) ssid,
strlen(ssid), network->psk);
if (!r) {
network->sync_settings = true;
return 0;
}
l_error("PSK generation failed: %s", strerror(-r));
network_reset_passphrase(network);
network_reset_psk(network);
return r;
} }
void network_sync_settings(struct network *network) void network_sync_settings(struct network *network)
@ -831,9 +828,7 @@ static void passphrase_callback(enum agent_result result,
{ {
struct network *network = user_data; struct network *network = user_data;
struct station *station = network->station; struct station *station = network->station;
const char *ssid = network_get_ssid(network);
struct scan_bss *bss; struct scan_bss *bss;
int r;
l_debug("result %d", result); l_debug("result %d", result);
@ -860,39 +855,13 @@ static void passphrase_callback(enum agent_result result,
} }
network_reset_psk(network); network_reset_psk(network);
network->psk = l_malloc(32);
r = crypto_psk_from_passphrase(passphrase,
(uint8_t *) ssid, strlen(ssid),
network->psk);
if (r) {
struct l_dbus_message *error;
l_free(network->psk); if (!__network_set_passphrase(network, passphrase)) {
network->psk = NULL; dbus_pending_reply(&message,
dbus_error_invalid_format(message));
if (r == -ERANGE || r == -EINVAL)
error = dbus_error_invalid_format(message);
else {
l_error("PSK generation failed: %s. "
"Ensure Crypto Engine is properly configured",
strerror(-r));
error = dbus_error_failed(message);
}
dbus_pending_reply(&message, error);
goto err; goto err;
} }
network_reset_passphrase(network);
network->passphrase = l_strdup(passphrase);
/*
* We need to store the PSK in our permanent store. However, before
* we do that, make sure the PSK works. We write to the store only
* when we are connected
*/
network->sync_settings = true;
station_connect_network(station, network, bss, message); station_connect_network(station, network, bss, message);
l_dbus_message_unref(message); l_dbus_message_unref(message);
return; return;