mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-21 20:12:37 +01:00
netdev: added sae functionality to netdev
In order to plug SAE into the existing connect mechanism the actual CMD_CONNECT message is never sent, rather sae_register takes care of sending out CMD_AUTHENTICATE. This required some shuffling of code in order to handle both eapol and sae. In the case of non-SAE authentication everything behaves as it did before. When using SAE an sae_sm is created when a connection is attempted but the eapol_sm is not. After SAE succeeds it will start association and then create the eapol_sm and start the 4-way handshake. This change also adds the handshake SAE events to device and initializes SAE in main.
This commit is contained in:
parent
220fb61128
commit
fd8671e9c5
13
src/device.c
13
src/device.c
@ -779,10 +779,15 @@ static struct handshake_state *device_handshake_setup(struct device *device,
|
||||
handshake_state_set_own_wpa(hs, rsne_buf);
|
||||
}
|
||||
|
||||
if (security == SECURITY_PSK)
|
||||
handshake_state_set_pmk(hs, network_get_psk(network),
|
||||
32);
|
||||
else
|
||||
if (security == SECURITY_PSK) {
|
||||
/* SAE will generate/set the PMK */
|
||||
if (info.akm_suites == IE_RSN_AKM_SUITE_SAE_SHA256)
|
||||
handshake_state_set_passphrase(hs,
|
||||
network_get_passphrase(network));
|
||||
else
|
||||
handshake_state_set_pmk(hs,
|
||||
network_get_psk(network), 32);
|
||||
} else
|
||||
handshake_state_set_8021x_config(hs,
|
||||
network_get_settings(network));
|
||||
|
||||
|
255
src/netdev.c
255
src/netdev.c
@ -54,6 +54,7 @@
|
||||
#include "src/ftutil.h"
|
||||
#include "src/util.h"
|
||||
#include "src/watchlist.h"
|
||||
#include "src/sae.h"
|
||||
|
||||
#ifndef ENOTSUPP
|
||||
#define ENOTSUPP 524
|
||||
@ -85,6 +86,7 @@ struct netdev {
|
||||
netdev_adhoc_cb_t adhoc_cb;
|
||||
void *user_data;
|
||||
struct eapol_sm *sm;
|
||||
struct sae_sm *sae_sm;
|
||||
struct handshake_state *handshake;
|
||||
uint32_t connect_cmd_id;
|
||||
uint32_t disconnect_cmd_id;
|
||||
@ -507,6 +509,11 @@ static void netdev_connect_free(struct netdev *netdev)
|
||||
netdev->sm = NULL;
|
||||
}
|
||||
|
||||
if (netdev->sae_sm) {
|
||||
sae_sm_free(netdev->sae_sm);
|
||||
netdev->sae_sm = NULL;
|
||||
}
|
||||
|
||||
eapol_preauth_cancel(netdev->index);
|
||||
|
||||
if (netdev->handshake) {
|
||||
@ -1962,68 +1969,19 @@ static void netdev_cmd_ft_reassociate_cb(struct l_genl_msg *msg,
|
||||
}
|
||||
}
|
||||
|
||||
static void netdev_authenticate_event(struct l_genl_msg *msg,
|
||||
struct netdev *netdev)
|
||||
static void netdev_ft_process(struct netdev *netdev, const uint8_t *frame,
|
||||
size_t frame_len)
|
||||
{
|
||||
struct l_genl_msg *cmd_associate, *cmd_deauth;
|
||||
struct l_genl_attr attr;
|
||||
uint16_t type, len;
|
||||
const void *data;
|
||||
uint16_t status_code;
|
||||
const uint8_t *ies = NULL;
|
||||
size_t ies_len;
|
||||
const uint8_t *frame = NULL;
|
||||
size_t frame_len = 0;
|
||||
struct ie_tlv_iter iter;
|
||||
const uint8_t *rsne = NULL;
|
||||
const uint8_t *mde = NULL;
|
||||
const uint8_t *fte = NULL;
|
||||
struct handshake_state *hs = netdev->handshake;
|
||||
bool is_rsn;
|
||||
|
||||
l_debug("");
|
||||
|
||||
if (!netdev->connected) {
|
||||
l_warn("Unexpected connection related event -- "
|
||||
"is another supplicant running?");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* During Fast Transition we use the authenticate event to start the
|
||||
* reassociation step because the FTE necessary before we can build
|
||||
* the FT Associate command is included in the attached frame and is
|
||||
* not available in the Authenticate command callback.
|
||||
*/
|
||||
if (!netdev->in_ft)
|
||||
return;
|
||||
|
||||
if (!l_genl_attr_init(&attr, msg)) {
|
||||
l_debug("attr init failed");
|
||||
|
||||
goto auth_error;
|
||||
}
|
||||
|
||||
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
||||
switch (type) {
|
||||
case NL80211_ATTR_TIMED_OUT:
|
||||
l_warn("authentication timed out");
|
||||
|
||||
goto auth_error;
|
||||
|
||||
case NL80211_ATTR_FRAME:
|
||||
if (frame)
|
||||
goto auth_error;
|
||||
|
||||
frame = data;
|
||||
frame_len = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frame)
|
||||
goto auth_error;
|
||||
|
||||
/*
|
||||
* Parse the Authentication Response and validate the contents
|
||||
* according to 12.5.2 / 12.5.4: RSN or non-RSN Over-the-air
|
||||
@ -2200,6 +2158,85 @@ ft_error:
|
||||
netdev, NULL);
|
||||
}
|
||||
|
||||
static void netdev_sae_process(struct netdev *netdev, const uint8_t *from,
|
||||
const uint8_t *frame, size_t frame_len)
|
||||
{
|
||||
sae_rx_packet(netdev->sae_sm, from, frame, frame_len);
|
||||
}
|
||||
|
||||
static void netdev_authenticate_event(struct l_genl_msg *msg,
|
||||
struct netdev *netdev)
|
||||
{
|
||||
struct l_genl_attr attr;
|
||||
uint16_t type, len;
|
||||
const void *data;
|
||||
const uint8_t *frame = NULL;
|
||||
size_t frame_len = 0;
|
||||
|
||||
l_debug("");
|
||||
|
||||
if (!netdev->connected) {
|
||||
l_warn("Unexpected connection related event -- "
|
||||
"is another supplicant running?");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* During Fast Transition we use the authenticate event to start the
|
||||
* reassociation step because the FTE necessary before we can build
|
||||
* the FT Associate command is included in the attached frame and is
|
||||
* not available in the Authenticate command callback.
|
||||
*/
|
||||
if (!netdev->in_ft && !netdev->sae_sm)
|
||||
return;
|
||||
|
||||
if (!l_genl_attr_init(&attr, msg)) {
|
||||
l_debug("attr init failed");
|
||||
|
||||
goto auth_error;
|
||||
}
|
||||
|
||||
while (l_genl_attr_next(&attr, &type, &len, &data)) {
|
||||
switch (type) {
|
||||
case NL80211_ATTR_TIMED_OUT:
|
||||
l_warn("authentication timed out");
|
||||
|
||||
if (netdev->sae_sm) {
|
||||
sae_timeout(netdev->sae_sm);
|
||||
return;
|
||||
}
|
||||
|
||||
goto auth_error;
|
||||
|
||||
case NL80211_ATTR_FRAME:
|
||||
if (frame)
|
||||
goto auth_error;
|
||||
|
||||
frame = data;
|
||||
frame_len = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frame)
|
||||
goto auth_error;
|
||||
|
||||
if (netdev->in_ft)
|
||||
netdev_ft_process(netdev, frame, frame_len);
|
||||
else if (netdev->sae_sm)
|
||||
netdev_sae_process(netdev,
|
||||
((struct mmpdu_header *)frame)->address_2,
|
||||
frame + 26, frame_len - 26);
|
||||
else
|
||||
goto auth_error;
|
||||
|
||||
return;
|
||||
|
||||
auth_error:
|
||||
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
|
||||
netdev_connect_failed(NULL, netdev);
|
||||
}
|
||||
|
||||
static void netdev_associate_event(struct l_genl_msg *msg,
|
||||
struct netdev *netdev)
|
||||
{
|
||||
@ -2219,6 +2256,12 @@ static void netdev_cmd_connect_cb(struct l_genl_msg *msg, void *user_data)
|
||||
NETDEV_EVENT_ASSOCIATING,
|
||||
netdev->user_data);
|
||||
|
||||
/* the SAE SM can be freed */
|
||||
if (netdev->sae_sm) {
|
||||
sae_sm_free(netdev->sae_sm);
|
||||
netdev->sae_sm = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We register the eapol state machine here, in case the PAE
|
||||
* socket receives EAPoL packets before the nl80211 socket
|
||||
@ -2236,6 +2279,81 @@ static void netdev_cmd_connect_cb(struct l_genl_msg *msg, void *user_data)
|
||||
netdev_connect_failed(NULL, netdev);
|
||||
}
|
||||
|
||||
static void netdev_sae_complete(uint16_t status, void *user_data)
|
||||
{
|
||||
struct netdev *netdev = user_data;
|
||||
struct l_genl_msg *msg;
|
||||
|
||||
if (status != 0) {
|
||||
l_error("SAE exchange failed on %u result %u",
|
||||
netdev->index, status);
|
||||
netdev->sae_sm = NULL;
|
||||
goto auth_failed;
|
||||
}
|
||||
|
||||
msg = netdev_build_cmd_associate_common(netdev);
|
||||
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IE,
|
||||
netdev->handshake->own_ie[1] + 2,
|
||||
netdev->handshake->own_ie);
|
||||
|
||||
/* netdev_cmd_connect_cb can be reused */
|
||||
netdev->connect_cmd_id = l_genl_family_send(nl80211, msg,
|
||||
netdev_cmd_connect_cb,
|
||||
netdev, NULL);
|
||||
|
||||
if (!netdev->connect_cmd_id)
|
||||
goto auth_failed;
|
||||
|
||||
/*
|
||||
* Kick off EAPoL sm early in case the first EAPoL packet comes prior
|
||||
* to the netdev_cmd_connect_cb
|
||||
*/
|
||||
netdev->sm = eapol_sm_new(netdev->handshake);
|
||||
return;
|
||||
|
||||
auth_failed:
|
||||
netdev->result = NETDEV_RESULT_AUTHENTICATION_FAILED;
|
||||
netdev_connect_failed(NULL, netdev);
|
||||
}
|
||||
|
||||
static void netdev_tx_sae_frame_cb(struct l_genl_msg *msg,
|
||||
void *user_data)
|
||||
{
|
||||
int err = l_genl_msg_get_error(msg);
|
||||
|
||||
if (err < 0)
|
||||
l_debug("SAE: CMD_AUTHENTICATE failed: %s", strerror(err));
|
||||
}
|
||||
|
||||
static int netdev_tx_sae_frame(const uint8_t *dest, const uint8_t *body,
|
||||
size_t body_len, void *user_data)
|
||||
{
|
||||
struct netdev *netdev = user_data;
|
||||
struct l_genl_msg *msg;
|
||||
uint32_t auth_type = NL80211_AUTHTYPE_SAE;
|
||||
|
||||
msg = l_genl_msg_new_sized(NL80211_CMD_AUTHENTICATE, 512);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ,
|
||||
4, &netdev->frequency);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, dest);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_SSID,
|
||||
strlen((char *) netdev->handshake->ssid),
|
||||
netdev->handshake->ssid);
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_AUTH_TYPE, 4, &auth_type);
|
||||
|
||||
l_genl_msg_append_attr(msg, NL80211_ATTR_AUTH_DATA, body_len, body);
|
||||
|
||||
if (!l_genl_family_send(nl80211, msg, netdev_tx_sae_frame_cb,
|
||||
netdev, NULL)) {
|
||||
l_genl_msg_unref(msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct l_genl_msg *netdev_build_cmd_connect(struct netdev *netdev,
|
||||
struct scan_bss *bss,
|
||||
struct handshake_state *hs,
|
||||
@ -2337,13 +2455,15 @@ static int netdev_connect_common(struct netdev *netdev,
|
||||
netdev_event_func_t event_filter,
|
||||
netdev_connect_cb_t cb, void *user_data)
|
||||
{
|
||||
netdev->connect_cmd_id = l_genl_family_send(nl80211, cmd_connect,
|
||||
netdev_cmd_connect_cb,
|
||||
netdev, NULL);
|
||||
if (cmd_connect) {
|
||||
netdev->connect_cmd_id = l_genl_family_send(nl80211,
|
||||
cmd_connect, netdev_cmd_connect_cb,
|
||||
netdev, NULL);
|
||||
|
||||
if (!netdev->connect_cmd_id) {
|
||||
l_genl_msg_unref(cmd_connect);
|
||||
return -EIO;
|
||||
if (!netdev->connect_cmd_id) {
|
||||
l_genl_msg_unref(cmd_connect);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
netdev->event_filter = event_filter;
|
||||
@ -2360,6 +2480,9 @@ static int netdev_connect_common(struct netdev *netdev,
|
||||
handshake_state_set_authenticator_address(hs, bss->addr);
|
||||
handshake_state_set_supplicant_address(hs, netdev->addr);
|
||||
|
||||
if (netdev->sae_sm)
|
||||
sae_start(netdev->sae_sm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2368,7 +2491,7 @@ int netdev_connect(struct netdev *netdev, struct scan_bss *bss,
|
||||
netdev_event_func_t event_filter,
|
||||
netdev_connect_cb_t cb, void *user_data)
|
||||
{
|
||||
struct l_genl_msg *cmd_connect;
|
||||
struct l_genl_msg *cmd_connect = NULL;
|
||||
struct eapol_sm *sm = NULL;
|
||||
bool is_rsn = hs->own_ie != NULL;
|
||||
|
||||
@ -2378,12 +2501,18 @@ int netdev_connect(struct netdev *netdev, struct scan_bss *bss,
|
||||
if (netdev->connected)
|
||||
return -EISCONN;
|
||||
|
||||
cmd_connect = netdev_build_cmd_connect(netdev, bss, hs, NULL);
|
||||
if (!cmd_connect)
|
||||
return -EINVAL;
|
||||
if (hs->akm_suite == IE_RSN_AKM_SUITE_SAE_SHA256) {
|
||||
netdev->sae_sm = sae_sm_new(hs, netdev_tx_sae_frame,
|
||||
netdev_sae_complete, netdev);
|
||||
} else {
|
||||
cmd_connect = netdev_build_cmd_connect(netdev, bss, hs, NULL);
|
||||
|
||||
if (is_rsn)
|
||||
sm = eapol_sm_new(hs);
|
||||
if (!cmd_connect)
|
||||
return -EINVAL;
|
||||
|
||||
if (is_rsn)
|
||||
sm = eapol_sm_new(hs);
|
||||
}
|
||||
|
||||
return netdev_connect_common(netdev, cmd_connect, bss, hs, sm,
|
||||
event_filter, cb, user_data);
|
||||
|
Loading…
Reference in New Issue
Block a user