* [PATCH v2 1/4] eapol: implement rekey support for authenticator
@ 2023-01-12 19:32 James Prestwood
2023-01-12 19:32 ` [PATCH v2 2/4] eapol: detect message 2/4 retransmits James Prestwood
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: James Prestwood @ 2023-01-12 19:32 UTC (permalink / raw)
To: iwd; +Cc: James Prestwood
The only changes required was to set the secure bit for message 1,
reset the frame retry counter, and change the 2/4 verifier to use
the rekey flag rather than ptk_complete. This is because we must
set ptk_complete false in order to detect retransmissions of the
4/4 frame.
Initiating a rekey can now be done by simply calling eapol_start().
---
src/eapol.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/eapol.c b/src/eapol.c
index 22b2d5d1..2048a87d 100644
--- a/src/eapol.c
+++ b/src/eapol.c
@@ -1086,8 +1086,6 @@ static void eapol_send_ptk_1_of_4(struct eapol_sm *sm)
handshake_state_new_anonce(sm->handshake);
- sm->handshake->ptk_complete = false;
-
sm->replay_counter++;
memset(ek, 0, EAPOL_FRAME_LEN(sm->mic_len));
@@ -1111,6 +1109,12 @@ static void eapol_send_ptk_1_of_4(struct eapol_sm *sm)
eapol_key_data_append(ek, sm->mic_len, HANDSHAKE_KDE_PMKID, pmkid, 16);
+ if (sm->handshake->ptk_complete) {
+ ek->secure = true;
+ sm->rekey = true;
+ sm->handshake->ptk_complete = false;
+ }
+
ek->header.packet_len = L_CPU_TO_BE16(EAPOL_FRAME_LEN(sm->mic_len) +
EAPOL_KEY_DATA_LEN(ek, sm->mic_len) - 4);
@@ -1589,7 +1593,7 @@ static void eapol_handle_ptk_2_of_4(struct eapol_sm *sm,
l_debug("ifindex=%u", sm->handshake->ifindex);
- if (!eapol_verify_ptk_2_of_4(ek, sm->handshake->ptk_complete))
+ if (!eapol_verify_ptk_2_of_4(ek, sm->rekey))
return;
if (L_BE64_TO_CPU(ek->key_replay_counter) != sm->replay_counter)
@@ -2482,6 +2486,8 @@ static void eapol_eap_complete_cb(enum eap_result result, void *user_data)
/* sm->mic_len will have been set in eapol_eap_results_cb */
+ sm->frame_retry = 0;
+
/* Kick off 4-Way Handshake */
eapol_ptk_1_of_4_retry(NULL, sm);
}
@@ -2873,6 +2879,8 @@ bool eapol_start(struct eapol_sm *sm)
if (L_WARN_ON(!sm->handshake->have_pmk))
return false;
+ sm->frame_retry = 0;
+
/* Kick off handshake */
eapol_ptk_1_of_4_retry(NULL, sm);
}
--
2.34.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/4] eapol: detect message 2/4 retransmits
2023-01-12 19:32 [PATCH v2 1/4] eapol: implement rekey support for authenticator James Prestwood
@ 2023-01-12 19:32 ` James Prestwood
2023-01-13 15:16 ` Denis Kenzior
2023-01-12 19:32 ` [PATCH v2 3/4] ap: support PTK rekeys James Prestwood
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: James Prestwood @ 2023-01-12 19:32 UTC (permalink / raw)
To: iwd; +Cc: James Prestwood
If the authenticator has already set an snonce then the packet must
be a retransmit. Handle this by sending 3/4 again but making sure
to not reset the frame counter.
---
src/eapol.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/eapol.c b/src/eapol.c
index 2048a87d..c1ef8f90 100644
--- a/src/eapol.c
+++ b/src/eapol.c
@@ -1645,12 +1645,18 @@ static void eapol_handle_ptk_2_of_4(struct eapol_sm *sm,
sm->handshake->support_ip_allocation = ip_req_kde != NULL;
}
+ /*
+ * If the snonce is already set don't reset the retry counter as this
+ * is a rekey. To be safe take the most recent snonce (in this frame)
+ * in case the station created a new one.
+ */
+ if (!sm->handshake->have_snonce)
+ sm->frame_retry = 0;
+
memcpy(sm->handshake->snonce, ek->key_nonce,
sizeof(sm->handshake->snonce));
sm->handshake->have_snonce = true;
- sm->frame_retry = 0;
-
eapol_ptk_3_of_4_retry(NULL, sm);
}
--
2.34.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 3/4] ap: support PTK rekeys
2023-01-12 19:32 [PATCH v2 1/4] eapol: implement rekey support for authenticator James Prestwood
2023-01-12 19:32 ` [PATCH v2 2/4] eapol: detect message 2/4 retransmits James Prestwood
@ 2023-01-12 19:32 ` James Prestwood
2023-01-13 15:35 ` Denis Kenzior
2023-01-12 19:32 ` [PATCH v2 4/4] doc: Document RekeyTimeout for AP profiles James Prestwood
2023-01-13 15:13 ` [PATCH v2 1/4] eapol: implement rekey support for authenticator Denis Kenzior
3 siblings, 1 reply; 8+ messages in thread
From: James Prestwood @ 2023-01-12 19:32 UTC (permalink / raw)
To: iwd; +Cc: James Prestwood
This adds support for rekeys to AP mode. A single timer is used and
reset to the next station needing a rekey. A default rekey timer of
600 seconds is used unless the profile sets a timeout.
---
src/ap.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)
diff --git a/src/ap.c b/src/ap.c
index 1d937103..ef819724 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -60,6 +60,8 @@
#include "src/band.h"
#include "src/common.h"
+#define AP_DEFAULT_REKEY_SECONDS 600
+
struct ap_state {
struct netdev *netdev;
struct l_genl_family *nl80211;
@@ -106,6 +108,9 @@ struct ap_state {
struct l_dbus_message *scan_pending;
struct l_queue *networks;
+ struct l_timeout *rekey_timeout;
+ unsigned int rekey_time;
+
bool started : 1;
bool gtk_set : 1;
bool netconfig_set_addr4 : 1;
@@ -137,6 +142,7 @@ struct sta_state {
bool wsc_v2;
struct l_dhcp_lease *ip_alloc_lease;
bool ip_alloc_sent;
+ uint64_t rekey_time;
bool ht_support : 1;
bool ht_greenfield : 1;
@@ -345,6 +351,11 @@ static void ap_reset(struct ap_state *ap)
l_queue_destroy(ap->networks, l_free);
ap->networks = NULL;
}
+
+ if (ap->rekey_timeout) {
+ l_timeout_remove(ap->rekey_timeout);
+ ap->rekey_timeout = NULL;
+ }
}
static bool ap_event_done(struct ap_state *ap, bool prev_in_event)
@@ -377,6 +388,8 @@ static bool ap_event(struct ap_state *ap, enum ap_event_type event,
return ap_event_done(ap, prev);
}
+static void ap_reset_rekey_timeout(struct ap_state *ap);
+
static void ap_del_station(struct sta_state *sta, uint16_t reason,
bool disassociate)
{
@@ -439,6 +452,89 @@ static void ap_del_station(struct sta_state *sta, uint16_t reason,
ap_event_done(ap, prev);
}
+
+ ap_reset_rekey_timeout(ap);
+}
+
+static void ap_start_rekey(struct ap_state *ap, struct sta_state *sta)
+{
+ l_debug("Rekey STA "MAC, MAC_STR(sta->addr));
+
+ eapol_start(sta->sm);
+}
+
+static void ap_rekey_timeout(struct l_timeout *timeout, void *user_data)
+{
+ struct ap_state *ap = user_data;
+
+ l_timeout_remove(timeout);
+
+ ap_reset_rekey_timeout(ap);
+}
+
+/*
+ * Used to initiate any rekeys which are due and reset the rekey timer to the
+ * next soonest station needing a rekey.
+ *
+ * TODO: Could adapt this to also take into account the next GTK rekey and
+ * service that as well. But GTK rekeys are not yet supported in AP mode.
+ */
+static void ap_reset_rekey_timeout(struct ap_state *ap)
+{
+ const struct l_queue_entry *e;
+ uint64_t now = l_time_now();
+ uint64_t next = 0;
+
+ if (!ap->rekey_time)
+ return;
+
+ /* Find the station(s) that need a rekey and start it */
+ for (e = l_queue_get_entries(ap->sta_states); e; e = e->next) {
+ struct sta_state *sta = e->data;
+
+ if (!sta->associated || !sta->rsna)
+ continue;
+
+ if (l_time_before(now, sta->rekey_time)) {
+ uint64_t diff = l_time_diff(now, sta->rekey_time);
+
+ /* Finding the next rekey time */
+ if (next < diff)
+ next = diff;
+
+ continue;
+ }
+
+ ap_start_rekey(ap, sta);
+ }
+
+ /*
+ * Set the next rekey to the station needing it the soonest, or NULL
+ * if a single station and wait until the rekey is complete to reset
+ * the timer.
+ */
+ if (next)
+ ap->rekey_timeout = l_timeout_create(l_time_to_secs(next),
+ ap_rekey_timeout, ap, NULL);
+ else
+ ap->rekey_timeout = NULL;
+}
+
+static void ap_set_sta_rekey_timer(struct ap_state *ap, struct sta_state *sta)
+{
+ if (!ap->rekey_time)
+ return;
+
+ sta->rekey_time = l_time_now() + ap->rekey_time - 1;
+
+ /*
+ * First/only station authenticated, set rekey timer. Any more stations
+ * will just set their rekey time and be serviced by the single callback
+ */
+ if (!ap->rekey_timeout)
+ ap->rekey_timeout = l_timeout_create(
+ l_time_to_secs(ap->rekey_time),
+ ap_rekey_timeout, ap, NULL);
}
static bool ap_sta_match_addr(const void *a, const void *b)
@@ -479,6 +575,8 @@ static void ap_new_rsna(struct sta_state *sta)
sta->rsna = true;
+ ap_set_sta_rekey_timer(ap, sta);
+
event_data.mac = sta->addr;
event_data.assoc_ies = sta->assoc_ies;
event_data.assoc_ies_len = sta->assoc_ies_len;
@@ -1372,6 +1470,9 @@ static void ap_handshake_event(struct handshake_state *hs,
sta->hs->go_ip_addr = IP4_FROM_STR(own_addr_str);
break;
}
+ case HANDSHAKE_EVENT_REKEY_COMPLETE:
+ ap_set_sta_rekey_timer(ap, sta);
+ return;
default:
break;
}
@@ -3628,6 +3729,19 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
l_strfreev(strvval);
}
+ if (l_settings_has_key(config, "General", "RekeyTimeout")) {
+ unsigned int uintval;
+
+ if (!l_settings_get_uint(config, "General",
+ "RekeyTimeout", &uintval)) {
+ l_error("AP [General].RekeyTimeout is not valid");
+ return -EINVAL;
+ }
+
+ ap->rekey_time = uintval * L_USEC_PER_SEC;
+ } else
+ ap->rekey_time = AP_DEFAULT_REKEY_SECONDS * L_USEC_PER_SEC;
+
/*
* Since 5GHz won't ever support only CCK rates we can ignore this
* setting on that band.
--
2.34.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 4/4] doc: Document RekeyTimeout for AP profiles
2023-01-12 19:32 [PATCH v2 1/4] eapol: implement rekey support for authenticator James Prestwood
2023-01-12 19:32 ` [PATCH v2 2/4] eapol: detect message 2/4 retransmits James Prestwood
2023-01-12 19:32 ` [PATCH v2 3/4] ap: support PTK rekeys James Prestwood
@ 2023-01-12 19:32 ` James Prestwood
2023-01-13 15:19 ` Denis Kenzior
2023-01-13 15:13 ` [PATCH v2 1/4] eapol: implement rekey support for authenticator Denis Kenzior
3 siblings, 1 reply; 8+ messages in thread
From: James Prestwood @ 2023-01-12 19:32 UTC (permalink / raw)
To: iwd; +Cc: James Prestwood
---
src/iwd.ap.rst | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/iwd.ap.rst b/src/iwd.ap.rst
index 823aba99..ce402f91 100644
--- a/src/iwd.ap.rst
+++ b/src/iwd.ap.rst
@@ -67,6 +67,13 @@ The group ``[General]`` contains general AP configuration.
ensure the country is set, and that the desired frequency/channel is
unrestricted.
+ * - RekeyTimeout
+ - Timeout for PTK rekeys (seconds)
+
+ The time interval at which the AP starts a rekey for a given station. If
+ not provided a default value of 600 seconds is used. A value of 0 will
+ disable PTK rekeys completely.
+
Network Authentication Settings
-------------------------------
--
2.34.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/4] eapol: implement rekey support for authenticator
2023-01-12 19:32 [PATCH v2 1/4] eapol: implement rekey support for authenticator James Prestwood
` (2 preceding siblings ...)
2023-01-12 19:32 ` [PATCH v2 4/4] doc: Document RekeyTimeout for AP profiles James Prestwood
@ 2023-01-13 15:13 ` Denis Kenzior
3 siblings, 0 replies; 8+ messages in thread
From: Denis Kenzior @ 2023-01-13 15:13 UTC (permalink / raw)
To: James Prestwood, iwd
Hi James,
On 1/12/23 13:32, James Prestwood wrote:
> The only changes required was to set the secure bit for message 1,
> reset the frame retry counter, and change the 2/4 verifier to use
> the rekey flag rather than ptk_complete. This is because we must
> set ptk_complete false in order to detect retransmissions of the
> 4/4 frame.
>
> Initiating a rekey can now be done by simply calling eapol_start().
> ---
> src/eapol.c | 14 +++++++++++---
> 1 file changed, 11 insertions(+), 3 deletions(-)
>
<snip>
> @@ -1111,6 +1109,12 @@ static void eapol_send_ptk_1_of_4(struct eapol_sm *sm)
>
> eapol_key_data_append(ek, sm->mic_len, HANDSHAKE_KDE_PMKID, pmkid, 16);
>
> + if (sm->handshake->ptk_complete) {
> + ek->secure = true;
> + sm->rekey = true;
> + sm->handshake->ptk_complete = false;
> + }
> +
Hmm, shouldn't ek->secure always be set to sm->rekey? I'm thinking of
retransmissions. Lets say we start a rekey with eapol_start(). ptk_complete is
true, so the first transmit of the 1/4 packet will set ek->secure to true. But
on subsequent retransmissions, this if() statement won't be hit due to
ptk_complete being false. So ek->secure won't be set properly, no?
> ek->header.packet_len = L_CPU_TO_BE16(EAPOL_FRAME_LEN(sm->mic_len) +
> EAPOL_KEY_DATA_LEN(ek, sm->mic_len) - 4);
>
Regards,
-Denis
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/4] eapol: detect message 2/4 retransmits
2023-01-12 19:32 ` [PATCH v2 2/4] eapol: detect message 2/4 retransmits James Prestwood
@ 2023-01-13 15:16 ` Denis Kenzior
0 siblings, 0 replies; 8+ messages in thread
From: Denis Kenzior @ 2023-01-13 15:16 UTC (permalink / raw)
To: James Prestwood, iwd
Hi James,
On 1/12/23 13:32, James Prestwood wrote:
> If the authenticator has already set an snonce then the packet must
> be a retransmit. Handle this by sending 3/4 again but making sure
> to not reset the frame counter.
> ---
> src/eapol.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
Applied, thanks.
Regards,
-Denis
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 4/4] doc: Document RekeyTimeout for AP profiles
2023-01-12 19:32 ` [PATCH v2 4/4] doc: Document RekeyTimeout for AP profiles James Prestwood
@ 2023-01-13 15:19 ` Denis Kenzior
0 siblings, 0 replies; 8+ messages in thread
From: Denis Kenzior @ 2023-01-13 15:19 UTC (permalink / raw)
To: James Prestwood, iwd
Hi James,
On 1/12/23 13:32, James Prestwood wrote:
> ---
> src/iwd.ap.rst | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/src/iwd.ap.rst b/src/iwd.ap.rst
> index 823aba99..ce402f91 100644
> --- a/src/iwd.ap.rst
> +++ b/src/iwd.ap.rst
> @@ -67,6 +67,13 @@ The group ``[General]`` contains general AP configuration.
> ensure the country is set, and that the desired frequency/channel is
> unrestricted.
>
> + * - RekeyTimeout
> + - Timeout for PTK rekeys (seconds)
> +
> + The time interval at which the AP starts a rekey for a given station. If
> + not provided a default value of 600 seconds is used. A value of 0 will
> + disable PTK rekeys completely.
So the default should be 0 (disabled). Many older Linux kernels can't support
pairwise rekeys without (the potential) for leaking cleartext packets during the
process. iwd checks for the presence of NL80211_EXT_FEATURE_CAN_REPLACE_PTK0.
If the driver isn't capable of this, we actually disconnect when the
Authenticator requests a rekey.
> +
> Network Authentication Settings
> -------------------------------
>
Regards,
-Denis
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 3/4] ap: support PTK rekeys
2023-01-12 19:32 ` [PATCH v2 3/4] ap: support PTK rekeys James Prestwood
@ 2023-01-13 15:35 ` Denis Kenzior
0 siblings, 0 replies; 8+ messages in thread
From: Denis Kenzior @ 2023-01-13 15:35 UTC (permalink / raw)
To: James Prestwood, iwd
Hi James,
On 1/12/23 13:32, James Prestwood wrote:
> This adds support for rekeys to AP mode. A single timer is used and
> reset to the next station needing a rekey. A default rekey timer of
> 600 seconds is used unless the profile sets a timeout.
> ---
> src/ap.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 114 insertions(+)
>
<snip>
> @@ -439,6 +452,89 @@ static void ap_del_station(struct sta_state *sta, uint16_t reason,
>
> ap_event_done(ap, prev);
> }
> +
> + ap_reset_rekey_timeout(ap);
Shouldn't you be cleaning up the timeout here?
> +}
> +
> +static void ap_start_rekey(struct ap_state *ap, struct sta_state *sta)
> +{
> + l_debug("Rekey STA "MAC, MAC_STR(sta->addr));
> +
> + eapol_start(sta->sm);
> +}
> +
> +static void ap_rekey_timeout(struct l_timeout *timeout, void *user_data)
> +{
> + struct ap_state *ap = user_data;
> +
> + l_timeout_remove(timeout);
> +
> + ap_reset_rekey_timeout(ap);
> +}
> +
> +/*
> + * Used to initiate any rekeys which are due and reset the rekey timer to the
> + * next soonest station needing a rekey.
> + *
> + * TODO: Could adapt this to also take into account the next GTK rekey and
> + * service that as well. But GTK rekeys are not yet supported in AP mode.
> + */
> +static void ap_reset_rekey_timeout(struct ap_state *ap)
> +{
> + const struct l_queue_entry *e;
> + uint64_t now = l_time_now();
> + uint64_t next = 0;
> +
> + if (!ap->rekey_time)
> + return;
> +
> + /* Find the station(s) that need a rekey and start it */
> + for (e = l_queue_get_entries(ap->sta_states); e; e = e->next) {
> + struct sta_state *sta = e->data;
> +
> + if (!sta->associated || !sta->rsna)
> + continue;
Would checking sta->rekey_time == 0 also be worthwhile? For stas that haven't
authenticated yet?
> +
> + if (l_time_before(now, sta->rekey_time)) {
> + uint64_t diff = l_time_diff(now, sta->rekey_time);
> +
> + /* Finding the next rekey time */
> + if (next < diff)
> + next = diff;
> +
> + continue;
Ok, so you try to find the next soonest (absolute) rekey_time to schedule the
next timeout. Might be easier to just set next to ~0 and loop over the stations
using l_time_before(sta->rekey_time, next), setting next as needed.
> + }
> +
> + ap_start_rekey(ap, sta);
And looks like this starts a rekey for any stations that we somehow missed? How
does this happen?
> + }
> +
> + /*
> + * Set the next rekey to the station needing it the soonest, or NULL
> + * if a single station and wait until the rekey is complete to reset
> + * the timer.
> + */
> + if (next)
> + ap->rekey_timeout = l_timeout_create(l_time_to_secs(next),
> + ap_rekey_timeout, ap, NULL);
> + else
> + ap->rekey_timeout = NULL;
Are you sure the rekey_timeout is destroyed here?
Might be easier to use l_timeout_modify instead of creating/destroying it all
the time?
> +}
> +
Regards,
-Denis
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-01-13 15:55 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-01-12 19:32 [PATCH v2 1/4] eapol: implement rekey support for authenticator James Prestwood
2023-01-12 19:32 ` [PATCH v2 2/4] eapol: detect message 2/4 retransmits James Prestwood
2023-01-13 15:16 ` Denis Kenzior
2023-01-12 19:32 ` [PATCH v2 3/4] ap: support PTK rekeys James Prestwood
2023-01-13 15:35 ` Denis Kenzior
2023-01-12 19:32 ` [PATCH v2 4/4] doc: Document RekeyTimeout for AP profiles James Prestwood
2023-01-13 15:19 ` Denis Kenzior
2023-01-13 15:13 ` [PATCH v2 1/4] eapol: implement rekey support for authenticator Denis Kenzior
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.