* [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
* 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
* [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
* 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
* [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 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 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
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 a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).