mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-01-20 09:34:06 +01:00
station: support PMKSA connections
The actual connection piece of this is very minimal, and only requires station to check if there is a PMKSA cached, and if so include the PMKID in the RSNE. Netdev then takes care of the rest. The remainder of this patch is the error handling if a PMKSA connection fails with INVALID_PMKID. In this case IWD should retry the same BSS without PMKSA. An option was also added to disable PMKSA if a user wants to do that. In theory PMKSA is actually less secure compared to SAE so it could be something a user wants to disable. Going forward though it will be enabled by default as its a requirement from the WiFi alliance for WPA3 certification.
This commit is contained in:
parent
9bc71b2853
commit
ab49b404fd
@ -63,6 +63,7 @@
|
|||||||
#include "src/eap.h"
|
#include "src/eap.h"
|
||||||
#include "src/eap-tls-common.h"
|
#include "src/eap-tls-common.h"
|
||||||
#include "src/storage.h"
|
#include "src/storage.h"
|
||||||
|
#include "src/pmksa.h"
|
||||||
|
|
||||||
#define STATION_RECENT_NETWORK_LIMIT 5
|
#define STATION_RECENT_NETWORK_LIMIT 5
|
||||||
#define STATION_RECENT_FREQS_LIMIT 5
|
#define STATION_RECENT_FREQS_LIMIT 5
|
||||||
@ -78,6 +79,7 @@ static bool supports_drop_gratuitous_arp;
|
|||||||
static bool supports_drop_unsolicited_na;
|
static bool supports_drop_unsolicited_na;
|
||||||
static bool supports_ipv4_drop_unicast_in_l2_multicast;
|
static bool supports_ipv4_drop_unicast_in_l2_multicast;
|
||||||
static bool supports_ipv6_drop_unicast_in_l2_multicast;
|
static bool supports_ipv6_drop_unicast_in_l2_multicast;
|
||||||
|
static bool pmksa_disabled;
|
||||||
static struct watchlist event_watches;
|
static struct watchlist event_watches;
|
||||||
static uint32_t known_networks_watch;
|
static uint32_t known_networks_watch;
|
||||||
static uint32_t allowed_bands;
|
static uint32_t allowed_bands;
|
||||||
@ -1157,6 +1159,7 @@ static int station_build_handshake_rsn(struct handshake_state *hs,
|
|||||||
struct network *network,
|
struct network *network,
|
||||||
struct scan_bss *bss)
|
struct scan_bss *bss)
|
||||||
{
|
{
|
||||||
|
struct netdev *netdev = netdev_find(hs->ifindex);
|
||||||
const struct l_settings *settings = iwd_get_config();
|
const struct l_settings *settings = iwd_get_config();
|
||||||
enum security security = network_get_security(network);
|
enum security security = network_get_security(network);
|
||||||
bool add_mde = false;
|
bool add_mde = false;
|
||||||
@ -1167,6 +1170,7 @@ static int station_build_handshake_rsn(struct handshake_state *hs,
|
|||||||
uint8_t *ap_ie;
|
uint8_t *ap_ie;
|
||||||
bool disable_ocv;
|
bool disable_ocv;
|
||||||
enum band_freq band;
|
enum band_freq band;
|
||||||
|
struct pmksa *pmksa;
|
||||||
|
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
||||||
@ -1300,6 +1304,17 @@ build_ie:
|
|||||||
IE_CIPHER_IS_GCMP_CCMP(info.pairwise_ciphers))
|
IE_CIPHER_IS_GCMP_CCMP(info.pairwise_ciphers))
|
||||||
info.extended_key_id = true;
|
info.extended_key_id = true;
|
||||||
|
|
||||||
|
if (IE_AKM_IS_SAE(info.akm_suites) && !pmksa_disabled) {
|
||||||
|
pmksa = pmksa_cache_get(netdev_get_address(netdev), bss->addr,
|
||||||
|
bss->ssid, bss->ssid_len,
|
||||||
|
info.akm_suites);
|
||||||
|
if (pmksa) {
|
||||||
|
handshake_state_set_pmksa(hs, pmksa);
|
||||||
|
info.num_pmkids = 1;
|
||||||
|
info.pmkids = hs->pmksa->pmkid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* RSN takes priority */
|
/* RSN takes priority */
|
||||||
if (bss->rsne) {
|
if (bss->rsne) {
|
||||||
ap_ie = bss->rsne;
|
ap_ie = bss->rsne;
|
||||||
@ -3391,6 +3406,39 @@ try_next:
|
|||||||
return station_try_next_bss(station);
|
return station_try_next_bss(station);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool station_pmksa_fallback(struct station *station, uint16_t status)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* IEEE 802.11-2020 12.6.10.3 Cached PMKSAs and RSNA key management
|
||||||
|
*
|
||||||
|
* "If the Authenticator does not have a PMKSA for the PMKIDs in the
|
||||||
|
* (re)association request or the AKM does not match, its behavior
|
||||||
|
* depends on how the PMKSA was established. If SAE authentication was
|
||||||
|
* used to establish the PMKSA, then the AP shall reject (re)association
|
||||||
|
* by sending a (Re)Association Response frame with status code
|
||||||
|
* STATUS_INVALID_PMKID. Note that this allows the non-AP STA to fall
|
||||||
|
* back to full SAE authentication to establish another PMKSA"
|
||||||
|
*/
|
||||||
|
if (status != MMPDU_STATUS_CODE_INVALID_PMKID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (L_WARN_ON(!station->hs))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!IE_AKM_IS_SAE(station->hs->akm_suite) || !station->hs->have_pmksa)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the PMKSA from the handshake and return true to re-try the
|
||||||
|
* same BSS without PMKSA.
|
||||||
|
*/
|
||||||
|
handshake_state_remove_pmksa(station->hs);
|
||||||
|
|
||||||
|
station_debug_event(station, "pmksa-invalid-pmkid");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* A bit more concise for trying to fit these into 80 characters */
|
/* A bit more concise for trying to fit these into 80 characters */
|
||||||
#define IS_TEMPORARY_STATUS(code) \
|
#define IS_TEMPORARY_STATUS(code) \
|
||||||
((code) == MMPDU_STATUS_CODE_DENIED_UNSUFFICIENT_BANDWIDTH || \
|
((code) == MMPDU_STATUS_CODE_DENIED_UNSUFFICIENT_BANDWIDTH || \
|
||||||
@ -3414,7 +3462,7 @@ static bool station_retry_with_status(struct station *station,
|
|||||||
if (IS_TEMPORARY_STATUS(status_code))
|
if (IS_TEMPORARY_STATUS(status_code))
|
||||||
network_blacklist_add(station->connected_network,
|
network_blacklist_add(station->connected_network,
|
||||||
station->connected_bss);
|
station->connected_bss);
|
||||||
else
|
else if (!station_pmksa_fallback(station, status_code))
|
||||||
blacklist_add_bss(station->connected_bss->addr);
|
blacklist_add_bss(station->connected_bss->addr);
|
||||||
|
|
||||||
iwd_notice(IWD_NOTICE_CONNECT_FAILED, "status: %u", status_code);
|
iwd_notice(IWD_NOTICE_CONNECT_FAILED, "status: %u", status_code);
|
||||||
@ -5830,6 +5878,10 @@ static int station_init(void)
|
|||||||
&anqp_disabled))
|
&anqp_disabled))
|
||||||
anqp_disabled = true;
|
anqp_disabled = true;
|
||||||
|
|
||||||
|
if (!l_settings_get_bool(iwd_get_config(), "General", "DisablePMKSA",
|
||||||
|
&pmksa_disabled))
|
||||||
|
pmksa_disabled = false;
|
||||||
|
|
||||||
if (!netconfig_enabled())
|
if (!netconfig_enabled())
|
||||||
l_info("station: Network configuration is disabled.");
|
l_info("station: Network configuration is disabled.");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user