wifi: provide WPA3-personal support

This commit introduces preliminary support for joining networks secured
via WPA3-personal. So far it was only tested with the one OpenWRT AP
configured for WPA3 (see excerpt below) where it WPA3-only as well as
WPA2/WPA3 mixed worked fine.

Scan results excerpt:

00:11:22:33:44:55    5180    -45     [WPA2-SAE-CCMP][SAE-H2E][ESS][UTF-8]    PewPew
00:11:22:33:44:55    2412    -67     [WPA2-PSK+SAE+PSK-SHA256-CCMP][SAE-H2E][ESS][UTF-8]     PewPew2

Issue #4861.
This commit is contained in:
Josef Söntgen 2023-05-20 21:19:56 +00:00 committed by Christian Helmuth
parent cfd3be675f
commit 497c8b0922
4 changed files with 83 additions and 18 deletions

View File

@ -44,7 +44,8 @@ INC_DIR += $(WS_CONTRIB_DIR)/wpa_supplicant
CC_OPT += -DCONFIG_BACKEND_FILE -DCONFIG_NO_CONFIG_WRITE \
-DCONFIG_SME -DCONFIG_CTRL_IFACE \
-DCONFIG_BGSCAN -DCONFIG_BGSCAN_SIMPLE \
-DCONFIG_OPENSSL_CMAC -DCONFIG_SHA256
-DCONFIG_OPENSSL_CMAC -DCONFIG_SHA256 \
-DCONFIG_SAE -DCONFIG_ECC
CC_OPT += -DTLS_DEFAULT_CIPHERS=\"DEFAULT:!EXP:!LOW\"
@ -52,17 +53,19 @@ INC_DIR += $(WS_CONTRIB_DIR)/src/
# common
SRC_C_common = ieee802_11_common.c wpa_common.c hw_features_common.c \
ctrl_iface_common.c
ctrl_iface_common.c sae.c dragonfly.c
SRC_C += $(addprefix src/common/, $(SRC_C_common))
INC_DIR += $(WS_CONTRIB_DIR)/src/common
# crypto
SRC_C_crypto = crypto_openssl.c \
dh_groups.c \
ms_funcs.c \
random.c \
sha1-prf.c \
sha1-tlsprf.c \
sha256-prf.c \
sha256-kdf.c \
tls_openssl.c
SRC_C += $(addprefix src/crypto/, $(SRC_C_crypto))
INC_DIR += $(WS_CONTRIB_DIR)/src/crypto

View File

@ -89,8 +89,9 @@ connect to a network:
To temporarily prevent any radio activity, the 'rfkill' attribute
can be set to 'true'.
If the network is protected by, e.g., WPA/WPA2, the protection type, either
'WPA' or 'WPA2' as well as the the passphrase have to be specified.
If the network is protected by, e.g., WPA/WPA2/WPA3, the protection type,
either 'WPA', 'WPA2' or 'WPA3' as well as the the passphrase have to be
specified.
The 'bssid' attribute can be used to select a specifc accesspoint within a
network. Of all attributes only the 'ssid' attribute is mandatory, all others
are optional and should only be used when needed.
@ -150,9 +151,9 @@ the 'rfkill' attribute.
By subscribing to both reports and providing the required 'wifi_config' ROM
module, a component is able control the wireless driver.
Currently only WPA/WPA2 protection using a passphrase is supported and the the
SSID is copied verbatim. At the moment, there is no way to express or escape
non alphanumeric characters.
Currently only WPA/WPA2/WPA3 protection using a passphrase is supported and
the SSID is copied verbatim. At the moment, there is no way to express or
escape non alphanumeric characters.
The driver optionally reports the following information under the
label "devices" if requested in the config as depicted.

View File

@ -185,6 +185,7 @@ struct Accesspoint : Genode::Interface
bool valid() const { return ssid.length() > 1; }
bool bssid_valid() const { return bssid.length() > 1; }
bool wpa() const { return prot != "NONE"; }
bool wpa3() const { return prot == "WPA3"; }
bool stored() const { return id != -1; }
};
@ -233,11 +234,13 @@ static void for_each_result_line(char const *msg, FUNC const &func)
bool const is_wpa1 = Util::string_contains((char const*)s[3], "WPA");
bool const is_wpa2 = Util::string_contains((char const*)s[3], "WPA2");
bool const is_wpa3 = Util::string_contains((char const*)s[3], "SAE");
unsigned signal = Util::approximate_quality(s[2]);
char const *prot = is_wpa1 ? "WPA" : "NONE";
prot = is_wpa2 ? "WPA2" : prot;
prot = is_wpa3 ? "WPA3" : prot;
Accesspoint ap(s[0], s[1], prot, s[4], signal);
@ -556,14 +559,16 @@ struct Wifi::Frontend : Wifi::Rfkill_notification_handler
INITIATE_SCAN = 0x00|SCAN,
PENDING_RESULTS = 0x10|SCAN,
ADD_NETWORK = 0x00|NETWORK,
FILL_NETWORK_SSID = 0x10|NETWORK,
FILL_NETWORK_BSSID = 0x20|NETWORK,
FILL_NETWORK_PSK = 0x30|NETWORK,
REMOVE_NETWORK = 0x40|NETWORK,
ENABLE_NETWORK = 0x50|NETWORK,
DISABLE_NETWORK = 0x60|NETWORK,
LIST_NETWORKS = 0x80|NETWORK,
ADD_NETWORK = 0x00|NETWORK,
FILL_NETWORK_SSID = 0x10|NETWORK,
FILL_NETWORK_BSSID = 0x20|NETWORK,
FILL_NETWORK_KEY_MGMT = 0x30|NETWORK,
FILL_NETWORK_PSK = 0x40|NETWORK,
REMOVE_NETWORK = 0x50|NETWORK,
ENABLE_NETWORK = 0x60|NETWORK,
DISABLE_NETWORK = 0x70|NETWORK,
LIST_NETWORKS = 0x90|NETWORK,
SET_NETWORK_PMF = 0xA0|NETWORK,
CONNECTING = 0x00|CONNECT,
CONNECTED = 0x10|CONNECT,
@ -581,6 +586,7 @@ struct Wifi::Frontend : Wifi::Rfkill_notification_handler
case ADD_NETWORK: return "add network";
case FILL_NETWORK_SSID: return "fill network ssid";
case FILL_NETWORK_BSSID: return "fill network bssid";
case FILL_NETWORK_KEY_MGMT: return "fill network key_mgmt";
case FILL_NETWORK_PSK: return "fill network pass";
case REMOVE_NETWORK: return "remove network";
case ENABLE_NETWORK: return "enable network";
@ -591,6 +597,7 @@ struct Wifi::Frontend : Wifi::Rfkill_notification_handler
case STATUS: return "status";
case LIST_NETWORKS: return "list networks";
case INFO: return "info";
case SET_NETWORK_PMF: return "set network pmf";
default: return "unknown";
};
}
@ -922,6 +929,18 @@ struct Wifi::Frontend : Wifi::Rfkill_notification_handler
" bssid ", bssid));
}
void _network_set_key_mgmt_sae()
{
_submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id,
" key_mgmt SAE"));
}
void _network_set_pmf()
{
_submit_cmd(Cmd_str("SET_NETWORK ", _processed_ap->id,
" ieee80211w 2"));
}
void _network_set_psk()
{
if (_processed_ap->wpa()) {
@ -1018,6 +1037,41 @@ struct Wifi::Frontend : Wifi::Rfkill_notification_handler
_state_transition(_state, State::IDLE);
} else {
/*
* For the moment branch here to handle WPA3-personal-only
* explicitly.
*/
if (_processed_ap->wpa3()) {
_state_transition(_state, State::FILL_NETWORK_KEY_MGMT);
_network_set_key_mgmt_sae();
} else {
_state_transition(_state, State::FILL_NETWORK_PSK);
_network_set_psk();
}
successfully = true;
}
break;
case State::FILL_NETWORK_KEY_MGMT:
_state_transition(_state, State::IDLE);
if (!cmd_successful(msg)) {
Genode::error("could not set key_mgmt for network: ", msg);
_state_transition(_state, State::IDLE);
} else {
_state_transition(_state, State::SET_NETWORK_PMF);
_network_set_pmf();
successfully = true;
}
break;
case State::SET_NETWORK_PMF:
_state_transition(_state, State::IDLE);
if (!cmd_successful(msg)) {
Genode::error("could not set PMF for network: ", msg);
_state_transition(_state, State::IDLE);
} else {
_state_transition(_state, State::FILL_NETWORK_PSK);
_network_set_psk();

View File

@ -17,6 +17,13 @@ proc wifi_psk { } {
return $::env(GENODE_WIFI_PSK)
}
proc wifi_wpa { } {
if {![info exists ::env(GENODE_WIFI_WPA)]} {
return WPA2
}
return $::env(GENODE_WIFI_WPA)
}
#
# widi_drv config generator (supporting a network list)
#
@ -232,15 +239,15 @@ append config {
</inline>
<sleep milliseconds="15000"/>
<inline description="connect">
} [wifi_config 30 5 no [list "[wifi_ssid] WPA2 [wifi_psk] yes"]] {
} [wifi_config 30 5 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] {
</inline>
<sleep milliseconds="60000"/>
<inline description="rfkill block">
} [wifi_config 30 5 yes [list "[wifi_ssid] WPA2 [wifi_psk] yes"]] {
} [wifi_config 30 5 yes [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] {
</inline>
<sleep milliseconds="30000"/>
<inline description="rfkill unblock">
} [wifi_config 30 5 no [list "[wifi_ssid] WPA2 [wifi_psk] yes"]] {
} [wifi_config 30 5 no [list "[wifi_ssid] [wifi_wpa] [wifi_psk] yes"]] {
</inline>
<sleep milliseconds="30000"/>
</rom>