mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-26 02:19:26 +01:00
network: Don't require PSK if Passphrase present
Refactor the network->psk and network->passphrase loading and saving logic to not require the PreSharedKey entry in the psk config file and to generate network->psk lazily on request. Still cache the computed PSK in memory and in the .psk file to avoid recomputing it which uses many syscalls. While there update the ask_psk variable to ask_passphrase because we're specifically asking for the passphrase.
This commit is contained in:
parent
0b1e6cc3e5
commit
0b5dceab27
175
src/network.c
175
src/network.c
@ -59,7 +59,7 @@ struct network {
|
|||||||
struct l_settings *settings;
|
struct l_settings *settings;
|
||||||
struct l_queue *secrets;
|
struct l_queue *secrets;
|
||||||
bool update_psk:1; /* Whether PSK should be written to storage */
|
bool update_psk:1; /* Whether PSK should be written to storage */
|
||||||
bool ask_psk:1; /* Whether we should force-ask agent for PSK */
|
bool ask_passphrase:1; /* Whether we should force-ask agent */
|
||||||
int rank;
|
int rank;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -312,9 +312,30 @@ enum security network_get_security(const struct network *network)
|
|||||||
return network->info->type;
|
return network->info->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *network_get_psk(const struct network *network)
|
const uint8_t *network_get_psk(struct network *network)
|
||||||
{
|
{
|
||||||
return network->psk;
|
int r;
|
||||||
|
|
||||||
|
if (network->psk)
|
||||||
|
return network->psk;
|
||||||
|
|
||||||
|
if (!network->passphrase)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
network->psk = l_malloc(32);
|
||||||
|
r = crypto_psk_from_passphrase(network->passphrase,
|
||||||
|
(uint8_t *) network->info->ssid,
|
||||||
|
strlen(network->info->ssid),
|
||||||
|
network->psk);
|
||||||
|
if (!r)
|
||||||
|
return network->psk;
|
||||||
|
|
||||||
|
l_free(network->psk);
|
||||||
|
network->psk = NULL;
|
||||||
|
l_error("PMK generation failed: %s. "
|
||||||
|
"Ensure Crypto Engine is properly configured",
|
||||||
|
strerror(-r));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *network_get_passphrase(const struct network *network)
|
const char *network_get_passphrase(const struct network *network)
|
||||||
@ -399,36 +420,33 @@ static bool network_set_8021x_secrets(struct network *network)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int network_load_psk(struct network *network)
|
static int network_load_psk(struct network *network, bool need_passphrase)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *psk = l_settings_get_value(network->settings,
|
const char *psk = l_settings_get_value(network->settings,
|
||||||
"Security", "PreSharedKey");
|
"Security", "PreSharedKey");
|
||||||
|
char *passphrase = l_settings_get_string(network->settings,
|
||||||
if (!psk)
|
|
||||||
return -ENOKEY;
|
|
||||||
|
|
||||||
l_free(network->psk);
|
|
||||||
network->psk = l_util_from_hexstring(psk, &len);
|
|
||||||
if (!network->psk)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (len != 32) {
|
|
||||||
l_free(network->psk);
|
|
||||||
network->psk = NULL;
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
l_free(network->passphrase);
|
|
||||||
network->passphrase = l_settings_get_string(network->settings,
|
|
||||||
"Security", "Passphrase");
|
"Security", "Passphrase");
|
||||||
|
|
||||||
return 0;
|
if ((!psk || need_passphrase) && !passphrase)
|
||||||
|
return -ENOKEY;
|
||||||
|
|
||||||
|
l_free(network->passphrase);
|
||||||
|
network->passphrase = passphrase;
|
||||||
|
l_free(network->psk);
|
||||||
|
network->psk = l_util_from_hexstring(psk, &len);
|
||||||
|
if (network->psk && len == 32)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
l_free(network->passphrase);
|
||||||
|
network->passphrase = NULL;
|
||||||
|
l_free(network->psk);
|
||||||
|
network->psk = NULL;
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_sync_psk(struct network *network)
|
void network_sync_psk(struct network *network)
|
||||||
{
|
{
|
||||||
char *hex;
|
|
||||||
struct l_settings *fs_settings;
|
struct l_settings *fs_settings;
|
||||||
|
|
||||||
if (!network->update_psk)
|
if (!network->update_psk)
|
||||||
@ -436,32 +454,51 @@ void network_sync_psk(struct network *network)
|
|||||||
|
|
||||||
network->update_psk = false;
|
network->update_psk = false;
|
||||||
|
|
||||||
hex = l_util_hexstring(network->psk, 32);
|
fs_settings = storage_network_open(SECURITY_PSK, network->info->ssid);
|
||||||
l_settings_set_value(network->settings, "Security",
|
|
||||||
|
if (network->psk) {
|
||||||
|
char *hex = l_util_hexstring(network->psk, 32);
|
||||||
|
l_settings_set_value(network->settings, "Security",
|
||||||
"PreSharedKey", hex);
|
"PreSharedKey", hex);
|
||||||
|
|
||||||
if (network->passphrase)
|
if (fs_settings)
|
||||||
|
l_settings_set_value(fs_settings, "Security",
|
||||||
|
"PreSharedKey", hex);
|
||||||
|
|
||||||
|
l_free(hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (network->passphrase) {
|
||||||
l_settings_set_string(network->settings, "Security",
|
l_settings_set_string(network->settings, "Security",
|
||||||
"Passphrase",
|
"Passphrase",
|
||||||
network->passphrase);
|
network->passphrase);
|
||||||
|
|
||||||
fs_settings = storage_network_open(SECURITY_PSK, network->info->ssid);
|
if (fs_settings)
|
||||||
if (fs_settings) {
|
|
||||||
l_settings_set_value(fs_settings, "Security",
|
|
||||||
"PreSharedKey", hex);
|
|
||||||
if (network->passphrase)
|
|
||||||
l_settings_set_string(fs_settings, "Security",
|
l_settings_set_string(fs_settings, "Security",
|
||||||
"Passphrase",
|
"Passphrase",
|
||||||
network->passphrase);
|
network->passphrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs_settings) {
|
||||||
storage_network_sync(SECURITY_PSK, network->info->ssid,
|
storage_network_sync(SECURITY_PSK, network->info->ssid,
|
||||||
fs_settings);
|
fs_settings);
|
||||||
l_settings_free(fs_settings);
|
l_settings_free(fs_settings);
|
||||||
} else
|
} else
|
||||||
storage_network_sync(SECURITY_PSK, network->info->ssid,
|
storage_network_sync(SECURITY_PSK, network->info->ssid,
|
||||||
network->settings);
|
network->settings);
|
||||||
|
}
|
||||||
|
|
||||||
l_free(hex);
|
static bool bss_is_sae(struct scan_bss *bss)
|
||||||
|
{
|
||||||
|
struct ie_rsn_info rsn;
|
||||||
|
|
||||||
|
memset(&rsn, 0, sizeof(rsn));
|
||||||
|
scan_bss_get_rsn_info(bss, &rsn);
|
||||||
|
|
||||||
|
if (rsn.akm_suites & IE_RSN_AKM_SUITE_SAE_SHA256)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int network_autoconnect(struct network *network, struct scan_bss *bss)
|
int network_autoconnect(struct network *network, struct scan_bss *bss)
|
||||||
@ -477,7 +514,7 @@ int network_autoconnect(struct network *network, struct scan_bss *bss)
|
|||||||
is_rsn = false;
|
is_rsn = false;
|
||||||
break;
|
break;
|
||||||
case SECURITY_PSK:
|
case SECURITY_PSK:
|
||||||
if (network->ask_psk)
|
if (network->ask_passphrase)
|
||||||
return -ENOKEY;
|
return -ENOKEY;
|
||||||
|
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
@ -504,12 +541,9 @@ int network_autoconnect(struct network *network, struct scan_bss *bss)
|
|||||||
goto close_settings;
|
goto close_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsn.akm_suites & IE_RSN_AKM_SUITE_SAE_SHA256 &&
|
ret = network_load_psk(network, bss_is_sae(bss));
|
||||||
!l_settings_has_key(network->settings,
|
if (ret < 0)
|
||||||
"Security", "Passphrase")) {
|
|
||||||
ret = -ENOKEY;
|
|
||||||
goto close_settings;
|
goto close_settings;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no entry, default to Autoconnectable=True */
|
/* If no entry, default to Autoconnectable=True */
|
||||||
@ -521,11 +555,7 @@ int network_autoconnect(struct network *network, struct scan_bss *bss)
|
|||||||
if (!is_autoconnectable)
|
if (!is_autoconnectable)
|
||||||
goto close_settings;
|
goto close_settings;
|
||||||
|
|
||||||
if (network_get_security(network) == SECURITY_PSK) {
|
if (network_get_security(network) == SECURITY_8021X) {
|
||||||
ret = network_load_psk(network);
|
|
||||||
if (ret < 0)
|
|
||||||
goto close_settings;
|
|
||||||
} else if (network_get_security(network) == SECURITY_8021X) {
|
|
||||||
struct l_queue *missing_secrets = NULL;
|
struct l_queue *missing_secrets = NULL;
|
||||||
|
|
||||||
ret = eap_check_settings(network->settings, network->secrets,
|
ret = eap_check_settings(network->settings, network->secrets,
|
||||||
@ -558,7 +588,7 @@ void network_connect_failed(struct network *network)
|
|||||||
*/
|
*/
|
||||||
if (network_get_security(network) == SECURITY_PSK) {
|
if (network_get_security(network) == SECURITY_PSK) {
|
||||||
network->update_psk = false;
|
network->update_psk = false;
|
||||||
network->ask_psk = true;
|
network->ask_passphrase = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
l_queue_destroy(network->secrets, eap_secret_info_free);
|
l_queue_destroy(network->secrets, eap_secret_info_free);
|
||||||
@ -665,21 +695,10 @@ static void passphrase_callback(enum agent_result result,
|
|||||||
}
|
}
|
||||||
|
|
||||||
l_free(network->psk);
|
l_free(network->psk);
|
||||||
network->psk = l_malloc(32);
|
network->psk = NULL;
|
||||||
l_free(network->passphrase);
|
l_free(network->passphrase);
|
||||||
network->passphrase = l_strdup(passphrase);
|
network->passphrase = l_strdup(passphrase);
|
||||||
|
|
||||||
if (crypto_psk_from_passphrase(passphrase,
|
|
||||||
(uint8_t *) network->info->ssid,
|
|
||||||
strlen(network->info->ssid),
|
|
||||||
network->psk) < 0) {
|
|
||||||
l_error("PMK generation failed. "
|
|
||||||
"Ensure Crypto Engine is properly configured");
|
|
||||||
dbus_pending_reply(&message, dbus_error_failed(message));
|
|
||||||
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to store the PSK in our permanent store. However, before
|
* 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
|
* we do that, make sure the PSK works. We write to the store only
|
||||||
@ -695,43 +714,31 @@ err:
|
|||||||
network_settings_close(network);
|
network_settings_close(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bss_is_sae(struct scan_bss *bss)
|
|
||||||
{
|
|
||||||
struct ie_rsn_info rsn;
|
|
||||||
|
|
||||||
memset(&rsn, 0, sizeof(rsn));
|
|
||||||
scan_bss_get_rsn_info(bss, &rsn);
|
|
||||||
|
|
||||||
if (rsn.akm_suites & IE_RSN_AKM_SUITE_SAE_SHA256)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct l_dbus_message *network_connect_psk(struct network *network,
|
static struct l_dbus_message *network_connect_psk(struct network *network,
|
||||||
struct scan_bss *bss,
|
struct scan_bss *bss,
|
||||||
struct l_dbus_message *message)
|
struct l_dbus_message *message)
|
||||||
{
|
{
|
||||||
struct station *station = network->station;
|
struct station *station = network->station;
|
||||||
|
|
||||||
l_debug("");
|
|
||||||
|
|
||||||
if (network_settings_load(network))
|
|
||||||
network_load_psk(network);
|
|
||||||
else
|
|
||||||
network->settings = l_settings_new();
|
|
||||||
|
|
||||||
l_debug("ask_psk: %s", network->ask_psk ? "true" : "false");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A legacy psk file may only contain the PreSharedKey entry. For SAE
|
* A legacy psk file may only contain the PreSharedKey entry. For SAE
|
||||||
* networks the raw Passphrase is required. So in this case where
|
* networks the raw Passphrase is required. So in this case where
|
||||||
* the psk is found but no passphrase, we ask the agent. In this case
|
* the psk is found but no Passphrase, we ask the agent. The psk file
|
||||||
* the psk file will be re-written to contain the raw passphrase.
|
* will then be re-written to contain the raw passphrase.
|
||||||
*/
|
*/
|
||||||
if (network->ask_psk || !network->psk ||
|
bool need_passphrase = bss_is_sae(bss);
|
||||||
(!network->passphrase && bss_is_sae(bss))) {
|
|
||||||
network->ask_psk = false;
|
l_debug("ask_passphrase: %s",
|
||||||
|
network->ask_passphrase ? "true" : "false");
|
||||||
|
|
||||||
|
if (!network_settings_load(network)) {
|
||||||
|
network->settings = l_settings_new();
|
||||||
|
network->ask_passphrase = true;
|
||||||
|
} else if (!network->ask_passphrase)
|
||||||
|
network->ask_passphrase =
|
||||||
|
network_load_psk(network, need_passphrase) < 0;
|
||||||
|
|
||||||
|
if (network->ask_passphrase) {
|
||||||
|
network->ask_passphrase = false;
|
||||||
|
|
||||||
network->agent_request =
|
network->agent_request =
|
||||||
agent_request_passphrase(network->object_path,
|
agent_request_passphrase(network->object_path,
|
||||||
|
@ -39,7 +39,7 @@ struct network *network_create(struct station *station, const char *ssid,
|
|||||||
const char *network_get_ssid(const struct network *network);
|
const char *network_get_ssid(const struct network *network);
|
||||||
const char *network_get_path(const struct network *network);
|
const char *network_get_path(const struct network *network);
|
||||||
enum security network_get_security(const struct network *network);
|
enum security network_get_security(const struct network *network);
|
||||||
const uint8_t *network_get_psk(const struct network *network);
|
const uint8_t *network_get_psk(struct network *network);
|
||||||
const char *network_get_passphrase(const struct network *network);
|
const char *network_get_passphrase(const struct network *network);
|
||||||
struct l_queue *network_get_secrets(const struct network *network);
|
struct l_queue *network_get_secrets(const struct network *network);
|
||||||
int network_get_signal_strength(const struct network *network);
|
int network_get_signal_strength(const struct network *network);
|
||||||
|
Loading…
Reference in New Issue
Block a user