blob: 9295dc6afa6b0774965bbcd4c9eefdf8993cc029 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002 * IEEE 802.11 RSN / WPA Authenticator
Sunil Ravia04bd252022-05-02 22:54:18 -07003 * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
10
11#include "utils/common.h"
12#include "utils/eloop.h"
13#include "utils/state_machine.h"
Dmitry Shmidtcf32e602014-01-28 10:57:39 -080014#include "utils/bitfield.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070015#include "common/ieee802_11_defs.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080016#include "common/ocv.h"
Hai Shalom4fbc08f2020-05-18 12:37:00 -070017#include "common/dpp.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070018#include "common/wpa_ctrl.h"
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080019#include "crypto/aes.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070020#include "crypto/aes_wrap.h"
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080021#include "crypto/aes_siv.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022#include "crypto/crypto.h"
23#include "crypto/sha1.h"
24#include "crypto/sha256.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070025#include "crypto/sha384.h"
Sunil Ravi38ad1ed2023-01-17 23:58:31 +000026#include "crypto/sha512.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070027#include "crypto/random.h"
28#include "eapol_auth/eapol_auth_sm.h"
Hai Shalom74f70d42019-02-11 14:42:39 -080029#include "drivers/driver.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include "ap_config.h"
31#include "ieee802_11.h"
Sunil Ravi2a14cf12023-11-21 00:54:38 +000032#include "sta_info.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070033#include "wpa_auth.h"
34#include "pmksa_cache_auth.h"
35#include "wpa_auth_i.h"
36#include "wpa_auth_ie.h"
37
38#define STATE_MACHINE_DATA struct wpa_state_machine
39#define STATE_MACHINE_DEBUG_PREFIX "WPA"
Sunil Raviaf8751c2023-03-29 11:35:17 -070040#define STATE_MACHINE_ADDR wpa_auth_get_spa(sm)
Sunil Ravi876a49b2025-02-03 19:18:32 +000041#define KDE_ALL_LINKS 0xffff
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070042
43
44static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
45static int wpa_sm_step(struct wpa_state_machine *sm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070046static int wpa_verify_key_mic(int akmp, size_t pmk_len, struct wpa_ptk *PTK,
47 u8 *data, size_t data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080048#ifdef CONFIG_FILS
49static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
50 u8 *buf, size_t buf_len, u16 *_key_data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070051static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
52 const struct wpabuf *hlp);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080053#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070054static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
55static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
56 struct wpa_group *group);
57static void wpa_request_new_ptk(struct wpa_state_machine *sm);
58static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
59 struct wpa_group *group);
60static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
61 struct wpa_group *group);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080062static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080063 const u8 *pmk, unsigned int pmk_len,
Sunil Raviaf8751c2023-03-29 11:35:17 -070064 struct wpa_ptk *ptk, int force_sha256,
65 u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
Sunil Ravi7f769292024-07-23 22:21:32 +000066 size_t *key_len, bool no_kdk);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070067static void wpa_group_free(struct wpa_authenticator *wpa_auth,
68 struct wpa_group *group);
69static void wpa_group_get(struct wpa_authenticator *wpa_auth,
70 struct wpa_group *group);
71static void wpa_group_put(struct wpa_authenticator *wpa_auth,
72 struct wpa_group *group);
Hai Shalomfdcde762020-04-02 11:19:20 -070073static int ieee80211w_kde_len(struct wpa_state_machine *sm);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080074static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
Sunil Ravi7f769292024-07-23 22:21:32 +000075static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
76 struct wpa_group *group);
77
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070078
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070079static const u32 eapol_key_timeout_first = 100; /* ms */
80static const u32 eapol_key_timeout_subseq = 1000; /* ms */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080081static const u32 eapol_key_timeout_first_group = 500; /* ms */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070082static const u32 eapol_key_timeout_no_retrans = 4000; /* ms */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070083
84/* TODO: make these configurable */
85static const int dot11RSNAConfigPMKLifetime = 43200;
86static const int dot11RSNAConfigPMKReauthThreshold = 70;
87static const int dot11RSNAConfigSATimeout = 60;
88
89
Sunil Raviaf8751c2023-03-29 11:35:17 -070090static const u8 * wpa_auth_get_aa(const struct wpa_state_machine *sm)
91{
Sunil Ravi2a14cf12023-11-21 00:54:38 +000092#ifdef CONFIG_IEEE80211BE
93 if (sm->mld_assoc_link_id >= 0)
Sunil Ravi7f769292024-07-23 22:21:32 +000094 return sm->wpa_auth->mld_addr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +000095#endif /* CONFIG_IEEE80211BE */
Sunil Raviaf8751c2023-03-29 11:35:17 -070096 return sm->wpa_auth->addr;
97}
98
99
100static const u8 * wpa_auth_get_spa(const struct wpa_state_machine *sm)
101{
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000102#ifdef CONFIG_IEEE80211BE
103 if (sm->mld_assoc_link_id >= 0)
104 return sm->peer_mld_addr;
105#endif /* CONFIG_IEEE80211BE */
Sunil Raviaf8751c2023-03-29 11:35:17 -0700106 return sm->addr;
107}
108
109
Sunil Ravi7f769292024-07-23 22:21:32 +0000110static void wpa_gkeydone_sta(struct wpa_state_machine *sm)
111{
112#ifdef CONFIG_IEEE80211BE
113 int link_id;
114#endif /* CONFIG_IEEE80211BE */
115
Sunil Ravic0f5d412024-09-11 22:12:49 +0000116 sm->group->GKeyDoneStations--;
Sunil Ravi7f769292024-07-23 22:21:32 +0000117 sm->GUpdateStationKeys = false;
118
119#ifdef CONFIG_IEEE80211BE
120 for_each_sm_auth(sm, link_id)
121 sm->mld_links[link_id].wpa_auth->group->GKeyDoneStations--;
122#endif /* CONFIG_IEEE80211BE */
123}
124
125
126#ifdef CONFIG_IEEE80211BE
127
128void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
129 int release_link_id)
130{
131 int link_id;
132
133 if (!sm || release_link_id >= MAX_NUM_MLD_LINKS)
134 return;
135
136 for_each_sm_auth(sm, link_id) {
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000137 if (link_id == release_link_id)
Sunil Ravi7f769292024-07-23 22:21:32 +0000138 sm->mld_links[link_id].wpa_auth = NULL;
Sunil Ravi7f769292024-07-23 22:21:32 +0000139 }
140}
141
142
143struct wpa_get_link_auth_ctx {
144 const u8 *addr;
145 const u8 *mld_addr;
146 int link_id;
147 struct wpa_authenticator *wpa_auth;
148};
149
150static int wpa_get_link_sta_auth(struct wpa_authenticator *wpa_auth, void *data)
151{
152 struct wpa_get_link_auth_ctx *ctx = data;
153
154 if (!wpa_auth->is_ml)
155 return 0;
156
157 if (ctx->mld_addr &&
158 !ether_addr_equal(wpa_auth->mld_addr, ctx->mld_addr))
159 return 0;
160
161 if ((ctx->addr && ether_addr_equal(wpa_auth->addr, ctx->addr)) ||
162 (ctx->link_id > -1 && wpa_auth->is_ml &&
163 wpa_auth->link_id == ctx->link_id)) {
164 ctx->wpa_auth = wpa_auth;
165 return 1;
166
167 }
168 return 0;
169}
170
171
172static struct wpa_authenticator *
173wpa_get_link_auth(struct wpa_authenticator *wpa_auth, int link_id)
174{
175 struct wpa_get_link_auth_ctx ctx;
176
177 ctx.addr = NULL;
178 ctx.mld_addr = wpa_auth->mld_addr;
179 ctx.link_id = link_id;
180 ctx.wpa_auth = NULL;
181 wpa_auth_for_each_auth(wpa_auth, wpa_get_link_sta_auth, &ctx);
182 return ctx.wpa_auth;
183}
184
185
186static int wpa_get_primary_auth_cb(struct wpa_authenticator *wpa_auth,
187 void *data)
188{
189 struct wpa_get_link_auth_ctx *ctx = data;
190
191 if (!wpa_auth->is_ml ||
192 !ether_addr_equal(wpa_auth->mld_addr, ctx->addr) ||
193 !wpa_auth->primary_auth)
194 return 0;
195
196 ctx->wpa_auth = wpa_auth;
197 return 1;
198}
199
200#endif /* CONFIG_IEEE80211BE */
201
202
203static struct wpa_authenticator *
204wpa_get_primary_auth(struct wpa_authenticator *wpa_auth)
205{
206#ifdef CONFIG_IEEE80211BE
207 struct wpa_get_link_auth_ctx ctx;
208
209 if (!wpa_auth || !wpa_auth->is_ml || wpa_auth->primary_auth)
210 return wpa_auth;
211
212 ctx.addr = wpa_auth->mld_addr;
213 ctx.wpa_auth = NULL;
214 wpa_auth_for_each_auth(wpa_auth, wpa_get_primary_auth_cb, &ctx);
215
216 return ctx.wpa_auth;
217#else /* CONFIG_IEEE80211BE */
218 return wpa_auth;
219#endif /* CONFIG_IEEE80211BE */
220}
221
222
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800223static inline int wpa_auth_mic_failure_report(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700224 struct wpa_authenticator *wpa_auth, const u8 *addr)
225{
Paul Stewart092955c2017-02-06 09:13:09 -0800226 if (wpa_auth->cb->mic_failure_report)
227 return wpa_auth->cb->mic_failure_report(wpa_auth->cb_ctx, addr);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800228 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700229}
230
231
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700232static inline void wpa_auth_psk_failure_report(
233 struct wpa_authenticator *wpa_auth, const u8 *addr)
234{
Paul Stewart092955c2017-02-06 09:13:09 -0800235 if (wpa_auth->cb->psk_failure_report)
236 wpa_auth->cb->psk_failure_report(wpa_auth->cb_ctx, addr);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700237}
238
239
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700240static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
241 const u8 *addr, wpa_eapol_variable var,
242 int value)
243{
Paul Stewart092955c2017-02-06 09:13:09 -0800244 if (wpa_auth->cb->set_eapol)
245 wpa_auth->cb->set_eapol(wpa_auth->cb_ctx, addr, var, value);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246}
247
248
249static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
250 const u8 *addr, wpa_eapol_variable var)
251{
Hai Shalomfdcde762020-04-02 11:19:20 -0700252 if (!wpa_auth->cb->get_eapol)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700253 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -0800254 return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700255}
256
257
258static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
Dmitry Shmidt391c59f2013-09-03 12:16:28 -0700259 const u8 *addr,
260 const u8 *p2p_dev_addr,
Hai Shalom021b0b52019-04-10 11:17:58 -0700261 const u8 *prev_psk, size_t *psk_len,
262 int *vlan_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700263{
Hai Shalomfdcde762020-04-02 11:19:20 -0700264 if (!wpa_auth->cb->get_psk)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700265 return NULL;
Paul Stewart092955c2017-02-06 09:13:09 -0800266 return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
Hai Shalom021b0b52019-04-10 11:17:58 -0700267 prev_psk, psk_len, vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700268}
269
270
271static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
272 const u8 *addr, u8 *msk, size_t *len)
273{
Hai Shalomfdcde762020-04-02 11:19:20 -0700274 if (!wpa_auth->cb->get_msk)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700275 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -0800276 return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700277}
278
279
280static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
281 int vlan_id,
282 enum wpa_alg alg, const u8 *addr, int idx,
Hai Shalomfdcde762020-04-02 11:19:20 -0700283 u8 *key, size_t key_len,
284 enum key_flag key_flag)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700285{
Hai Shalomfdcde762020-04-02 11:19:20 -0700286 if (!wpa_auth->cb->set_key)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700287 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -0800288 return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
Hai Shalomfdcde762020-04-02 11:19:20 -0700289 key, key_len, key_flag);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700290}
291
292
Sunil Ravi89eba102022-09-13 21:04:37 -0700293#ifdef CONFIG_PASN
294static inline int wpa_auth_set_ltf_keyseed(struct wpa_authenticator *wpa_auth,
295 const u8 *peer_addr,
296 const u8 *ltf_keyseed,
297 size_t ltf_keyseed_len)
298{
299 if (!wpa_auth->cb->set_ltf_keyseed)
300 return -1;
301 return wpa_auth->cb->set_ltf_keyseed(wpa_auth->cb_ctx, peer_addr,
302 ltf_keyseed, ltf_keyseed_len);
303}
304#endif /* CONFIG_PASN */
305
306
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700307static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
308 const u8 *addr, int idx, u8 *seq)
309{
Hai Shalomfdcde762020-04-02 11:19:20 -0700310 int res;
311
312 if (!wpa_auth->cb->get_seqnum)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700313 return -1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000314#ifdef CONFIG_TESTING_OPTIONS
315 os_memset(seq, 0, WPA_KEY_RSC_LEN);
316#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalomfdcde762020-04-02 11:19:20 -0700317 res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
318#ifdef CONFIG_TESTING_OPTIONS
319 if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) {
320 wpa_printf(MSG_DEBUG,
321 "TESTING: Override GTK RSC %016llx --> %016llx",
322 (long long unsigned) WPA_GET_LE64(seq),
323 (long long unsigned)
324 WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override));
325 os_memcpy(seq, wpa_auth->conf.gtk_rsc_override,
326 WPA_KEY_RSC_LEN);
327 }
328 if (!addr && idx >= 4 && idx <= 5 &&
329 wpa_auth->conf.igtk_rsc_override_set) {
330 wpa_printf(MSG_DEBUG,
331 "TESTING: Override IGTK RSC %016llx --> %016llx",
332 (long long unsigned) WPA_GET_LE64(seq),
333 (long long unsigned)
334 WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override));
335 os_memcpy(seq, wpa_auth->conf.igtk_rsc_override,
336 WPA_KEY_RSC_LEN);
337 }
338#endif /* CONFIG_TESTING_OPTIONS */
339 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700340}
341
342
343static inline int
344wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
345 const u8 *data, size_t data_len, int encrypt)
346{
Hai Shalomfdcde762020-04-02 11:19:20 -0700347 if (!wpa_auth->cb->send_eapol)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348 return -1;
Kai Shie75b0652020-11-24 20:31:29 -0800349#ifdef CONFIG_TESTING_OPTIONS
350 if (wpa_auth->conf.skip_send_eapol)
351 return 0;
352#endif
Paul Stewart092955c2017-02-06 09:13:09 -0800353 return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
354 encrypt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700355}
356
357
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800358#ifdef CONFIG_MESH
359static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
360 const u8 *addr)
361{
Hai Shalomfdcde762020-04-02 11:19:20 -0700362 if (!wpa_auth->cb->start_ampe)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800363 return -1;
Paul Stewart092955c2017-02-06 09:13:09 -0800364 return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800365}
366#endif /* CONFIG_MESH */
367
368
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000369static inline int wpa_auth_get_drv_flags(struct wpa_authenticator *wpa_auth,
370 u64 *drv_flags, u64 *drv_flags2)
371{
372 if (!wpa_auth->cb->get_drv_flags)
373 return -1;
374 return wpa_auth->cb->get_drv_flags(wpa_auth->cb_ctx, drv_flags,
375 drv_flags2);
376}
377
378
379static bool wpa_auth_4way_handshake_offload(struct wpa_authenticator *wpa_auth)
380{
381 u64 drv_flags = 0, drv_flags2 = 0;
382
383 return wpa_auth_get_drv_flags(wpa_auth, &drv_flags, &drv_flags2) == 0 &&
384 (drv_flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK);
385}
386
387
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700388int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
389 int (*cb)(struct wpa_state_machine *sm, void *ctx),
390 void *cb_ctx)
391{
Hai Shalomfdcde762020-04-02 11:19:20 -0700392 if (!wpa_auth->cb->for_each_sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700393 return 0;
Paul Stewart092955c2017-02-06 09:13:09 -0800394 return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700395}
396
397
398int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
399 int (*cb)(struct wpa_authenticator *a, void *ctx),
400 void *cb_ctx)
401{
Hai Shalomfdcde762020-04-02 11:19:20 -0700402 if (!wpa_auth->cb->for_each_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700403 return 0;
Paul Stewart092955c2017-02-06 09:13:09 -0800404 return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700405}
406
407
Hai Shalom60840252021-02-19 19:02:11 -0800408void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth,
409 const u8 *addr, int cipher,
410 u32 life_time, const struct wpa_ptk *ptk)
411{
412 if (wpa_auth->cb->store_ptksa)
413 wpa_auth->cb->store_ptksa(wpa_auth->cb_ctx, addr, cipher,
414 life_time, ptk);
415}
416
417
Sunil Raviaf8751c2023-03-29 11:35:17 -0700418static void wpa_auth_remove_ptksa(struct wpa_authenticator *wpa_auth,
419 const u8 *addr, int cipher)
Hai Shalom60840252021-02-19 19:02:11 -0800420{
421 if (wpa_auth->cb->clear_ptksa)
422 wpa_auth->cb->clear_ptksa(wpa_auth->cb_ctx, addr, cipher);
423}
424
Sunil Raviaf8751c2023-03-29 11:35:17 -0700425
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700426void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
427 logger_level level, const char *txt)
428{
Hai Shalomfdcde762020-04-02 11:19:20 -0700429 if (!wpa_auth->cb->logger)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700430 return;
Paul Stewart092955c2017-02-06 09:13:09 -0800431 wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700432}
433
434
435void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
436 logger_level level, const char *fmt, ...)
437{
438 char *format;
439 int maxlen;
440 va_list ap;
441
Hai Shalomfdcde762020-04-02 11:19:20 -0700442 if (!wpa_auth->cb->logger)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700443 return;
444
445 maxlen = os_strlen(fmt) + 100;
446 format = os_malloc(maxlen);
447 if (!format)
448 return;
449
450 va_start(ap, fmt);
451 vsnprintf(format, maxlen, fmt, ap);
452 va_end(ap);
453
454 wpa_auth_logger(wpa_auth, addr, level, format);
455
456 os_free(format);
457}
458
459
460static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700461 const u8 *addr, u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462{
Hai Shalomfdcde762020-04-02 11:19:20 -0700463 if (!wpa_auth->cb->disconnect)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700464 return;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700465 wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)",
466 MAC2STR(addr), reason);
467 wpa_auth->cb->disconnect(wpa_auth->cb_ctx, addr, reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700468}
469
470
Hai Shalom74f70d42019-02-11 14:42:39 -0800471#ifdef CONFIG_OCV
472static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
473 struct wpa_channel_info *ci)
474{
475 if (!wpa_auth->cb->channel_info)
476 return -1;
477 return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
478}
479#endif /* CONFIG_OCV */
480
481
Hai Shalom021b0b52019-04-10 11:17:58 -0700482static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth,
483 const u8 *addr, int vlan_id)
484{
485 if (!wpa_auth->cb->update_vlan)
486 return -1;
487 return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id);
488}
489
490
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700491static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
492{
493 struct wpa_authenticator *wpa_auth = eloop_ctx;
494
495 if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700496 wpa_printf(MSG_ERROR,
497 "Failed to get random data for WPA initialization.");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700498 } else {
499 wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
500 wpa_hexdump_key(MSG_DEBUG, "GMK",
501 wpa_auth->group->GMK, WPA_GMK_LEN);
502 }
503
504 if (wpa_auth->conf.wpa_gmk_rekey) {
505 eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
506 wpa_rekey_gmk, wpa_auth, NULL);
507 }
508}
509
510
Sunil Ravi7f769292024-07-23 22:21:32 +0000511static void wpa_rekey_all_groups(struct wpa_authenticator *wpa_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700512{
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700513 struct wpa_group *group, *next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700514
515 wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700516 group = wpa_auth->group;
517 while (group) {
Sunil Ravi7f769292024-07-23 22:21:32 +0000518 wpa_printf(MSG_DEBUG, "GTK rekey start for authenticator ("
519 MACSTR "), group vlan %d",
520 MAC2STR(wpa_auth->addr), group->vlan_id);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700521 wpa_group_get(wpa_auth, group);
522
Hai Shalome21d4e82020-04-29 16:34:06 -0700523 group->GTKReKey = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700524 do {
Hai Shalome21d4e82020-04-29 16:34:06 -0700525 group->changed = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700526 wpa_group_sm_step(wpa_auth, group);
527 } while (group->changed);
Dmitry Shmidt1d755d02015-04-28 10:34:29 -0700528
529 next = group->next;
530 wpa_group_put(wpa_auth, group);
531 group = next;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700532 }
Sunil Ravi7f769292024-07-23 22:21:32 +0000533}
534
535
536#ifdef CONFIG_IEEE80211BE
537
538static void wpa_update_all_gtks(struct wpa_authenticator *wpa_auth)
539{
540 struct wpa_group *group, *next;
541
542 group = wpa_auth->group;
543 while (group) {
544 wpa_group_get(wpa_auth, group);
545
546 wpa_group_update_gtk(wpa_auth, group);
547 next = group->next;
548 wpa_group_put(wpa_auth, group);
549 group = next;
550 }
551}
552
553
554static int wpa_update_all_gtks_cb(struct wpa_authenticator *wpa_auth, void *ctx)
555{
556 const u8 *mld_addr = ctx;
557
558 if (!ether_addr_equal(wpa_auth->mld_addr, mld_addr))
559 return 0;
560
561 wpa_update_all_gtks(wpa_auth);
562 return 0;
563}
564
565
566static int wpa_rekey_all_groups_cb(struct wpa_authenticator *wpa_auth,
567 void *ctx)
568{
569 const u8 *mld_addr = ctx;
570
571 if (!ether_addr_equal(wpa_auth->mld_addr, mld_addr))
572 return 0;
573
574 wpa_rekey_all_groups(wpa_auth);
575 return 0;
576}
577
578#endif /* CONFIG_IEEE80211BE */
579
580
581static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
582{
583 struct wpa_authenticator *wpa_auth = eloop_ctx;
584
585#ifdef CONFIG_IEEE80211BE
586 if (wpa_auth->is_ml) {
587 /* Non-primary ML authenticator eloop timer for group rekey is
588 * never started and shouldn't fire. Check and warn just in
589 * case. */
590 if (!wpa_auth->primary_auth) {
591 wpa_printf(MSG_DEBUG,
592 "RSN: Cannot start GTK rekey on non-primary ML authenticator");
593 return;
594 }
595
596 /* Generate all the new group keys */
597 wpa_auth_for_each_auth(wpa_auth, wpa_update_all_gtks_cb,
598 wpa_auth->mld_addr);
599
600 /* Send all the generated group keys to the respective stations
601 * with group key handshake. */
602 wpa_auth_for_each_auth(wpa_auth, wpa_rekey_all_groups_cb,
603 wpa_auth->mld_addr);
604 } else {
605 wpa_rekey_all_groups(wpa_auth);
606 }
607#else /* CONFIG_IEEE80211BE */
608 wpa_rekey_all_groups(wpa_auth);
609#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700610
611 if (wpa_auth->conf.wpa_group_rekey) {
612 eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
613 0, wpa_rekey_gtk, wpa_auth, NULL);
614 }
615}
616
617
618static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
619{
620 struct wpa_authenticator *wpa_auth = eloop_ctx;
621 struct wpa_state_machine *sm = timeout_ctx;
622
Sunil Raviaf8751c2023-03-29 11:35:17 -0700623 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
624 "rekeying PTK");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700625 wpa_request_new_ptk(sm);
626 wpa_sm_step(sm);
627}
628
629
Hai Shalom81f62d82019-07-22 12:10:00 -0700630void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm)
631{
632 if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) {
633 wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for "
Sunil Raviaf8751c2023-03-29 11:35:17 -0700634 MACSTR " (%d seconds)",
635 MAC2STR(wpa_auth_get_spa(sm)),
Hai Shalom81f62d82019-07-22 12:10:00 -0700636 sm->wpa_auth->conf.wpa_ptk_rekey);
637 eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
638 eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0,
639 wpa_rekey_ptk, sm->wpa_auth, sm);
640 }
641}
642
643
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700644static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
645{
646 if (sm->pmksa == ctx)
647 sm->pmksa = NULL;
648 return 0;
649}
650
651
652static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
653 void *ctx)
654{
655 struct wpa_authenticator *wpa_auth = ctx;
656 wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
657}
658
659
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700660static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
661 struct wpa_group *group)
662{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800663 u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700664 u8 rkey[32];
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800665 unsigned long ptr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700666
667 if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
668 return -1;
669 wpa_hexdump_key(MSG_DEBUG, "GMK", group->GMK, WPA_GMK_LEN);
670
671 /*
672 * Counter = PRF-256(Random number, "Init Counter",
673 * Local MAC Address || Time)
674 */
675 os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
676 wpa_get_ntp_timestamp(buf + ETH_ALEN);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800677 ptr = (unsigned long) group;
678 os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
Hai Shalom74f70d42019-02-11 14:42:39 -0800679#ifdef TEST_FUZZ
680 os_memset(buf + ETH_ALEN, 0xab, 8);
681 os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr));
682#endif /* TEST_FUZZ */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700683 if (random_get_bytes(rkey, sizeof(rkey)) < 0)
684 return -1;
685
686 if (sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
687 group->Counter, WPA_NONCE_LEN) < 0)
688 return -1;
689 wpa_hexdump_key(MSG_DEBUG, "Key Counter",
690 group->Counter, WPA_NONCE_LEN);
691
692 return 0;
693}
694
695
696static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800697 int vlan_id, int delay_init)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700698{
699 struct wpa_group *group;
700
701 group = os_zalloc(sizeof(struct wpa_group));
Hai Shalomfdcde762020-04-02 11:19:20 -0700702 if (!group)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700703 return NULL;
704
Hai Shalome21d4e82020-04-29 16:34:06 -0700705 group->GTKAuthenticator = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700706 group->vlan_id = vlan_id;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700707 group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700708
709 if (random_pool_ready() != 1) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700710 wpa_printf(MSG_INFO,
711 "WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700712 }
713
714 /*
715 * Set initial GMK/Counter value here. The actual values that will be
716 * used in negotiations will be set once the first station tries to
717 * connect. This allows more time for collecting additional randomness
718 * on embedded devices.
719 */
720 if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700721 wpa_printf(MSG_ERROR,
722 "Failed to get random data for WPA initialization.");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700723 os_free(group);
724 return NULL;
725 }
726
Hai Shalome21d4e82020-04-29 16:34:06 -0700727 group->GInit = true;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800728 if (delay_init) {
Hai Shalomfdcde762020-04-02 11:19:20 -0700729 wpa_printf(MSG_DEBUG,
730 "WPA: Delay group state machine start until Beacon frames have been configured");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800731 /* Initialization is completed in wpa_init_keys(). */
732 } else {
733 wpa_group_sm_step(wpa_auth, group);
Hai Shalome21d4e82020-04-29 16:34:06 -0700734 group->GInit = false;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800735 wpa_group_sm_step(wpa_auth, group);
736 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700737
738 return group;
739}
740
741
Sunil Ravi876a49b2025-02-03 19:18:32 +0000742static void wpa_deinit_groups(struct wpa_authenticator *wpa_auth)
743{
744 struct wpa_group *group, *prev;
745
746 group = wpa_auth->group;
747 while (group) {
748 prev = group;
749 group = group->next;
750 bin_clear_free(prev, sizeof(*prev));
751 }
752}
753
754
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700755/**
756 * wpa_init - Initialize WPA authenticator
757 * @addr: Authenticator address
758 * @conf: Configuration for WPA authenticator
759 * @cb: Callback functions for WPA authenticator
760 * Returns: Pointer to WPA authenticator data or %NULL on failure
761 */
762struct wpa_authenticator * wpa_init(const u8 *addr,
763 struct wpa_auth_config *conf,
Paul Stewart092955c2017-02-06 09:13:09 -0800764 const struct wpa_auth_callbacks *cb,
765 void *cb_ctx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700766{
767 struct wpa_authenticator *wpa_auth;
768
769 wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
Hai Shalomfdcde762020-04-02 11:19:20 -0700770 if (!wpa_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700771 return NULL;
Sunil Ravi7f769292024-07-23 22:21:32 +0000772
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700773 os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
774 os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
Sunil Ravi7f769292024-07-23 22:21:32 +0000775
776#ifdef CONFIG_IEEE80211BE
777 if (conf->mld_addr) {
778 wpa_auth->is_ml = true;
779 wpa_auth->link_id = conf->link_id;
780 wpa_auth->primary_auth = !conf->first_link_auth;
781 os_memcpy(wpa_auth->mld_addr, conf->mld_addr, ETH_ALEN);
782 }
783#endif /* CONFIG_IEEE80211BE */
784
Paul Stewart092955c2017-02-06 09:13:09 -0800785 wpa_auth->cb = cb;
786 wpa_auth->cb_ctx = cb_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700787
788 if (wpa_auth_gen_wpa_ie(wpa_auth)) {
789 wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
Sunil Ravi876a49b2025-02-03 19:18:32 +0000790 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700791 }
792
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800793 wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
Sunil Ravi876a49b2025-02-03 19:18:32 +0000794 if (!wpa_auth->group)
795 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700796
Sunil Ravi876a49b2025-02-03 19:18:32 +0000797 /* Per-link PMKSA cache */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700798 wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
799 wpa_auth);
Hai Shalomfdcde762020-04-02 11:19:20 -0700800 if (!wpa_auth->pmksa) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700801 wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
Sunil Ravi876a49b2025-02-03 19:18:32 +0000802 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700803 }
804
Sunil Ravi876a49b2025-02-03 19:18:32 +0000805#ifdef CONFIG_IEEE80211BE
806 /* MLD-level PMKSA cache */
807 if (wpa_auth->is_ml && wpa_auth->primary_auth) {
808 wpa_auth->ml_pmksa = pmksa_cache_auth_init(
809 wpa_auth_pmksa_free_cb, wpa_auth);
810 if (!wpa_auth->ml_pmksa) {
811 wpa_printf(MSG_ERROR,
812 "MLD-level PMKSA cache initialization failed.");
813 goto fail;
814 }
815 } else if (wpa_auth->is_ml) {
816 struct wpa_authenticator *pa = wpa_get_primary_auth(wpa_auth);
817
818 if (!pa) {
819 wpa_printf(MSG_ERROR,
820 "Could not find primary authenticator.");
821 goto fail;
822 }
823 wpa_auth->ml_pmksa = pa->ml_pmksa;
824 }
825#endif /* CONFIG_IEEE80211BE */
826
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800827#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700828 wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
Hai Shalomfdcde762020-04-02 11:19:20 -0700829 if (!wpa_auth->ft_pmk_cache) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700830 wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
Sunil Ravi876a49b2025-02-03 19:18:32 +0000831 goto fail;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700832 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800833#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700834
835 if (wpa_auth->conf.wpa_gmk_rekey) {
836 eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
837 wpa_rekey_gmk, wpa_auth, NULL);
838 }
839
Sunil Ravi7f769292024-07-23 22:21:32 +0000840#ifdef CONFIG_IEEE80211BE
841 /* For AP MLD, run group rekey timer only on one link (first) and
842 * whenever it fires do rekey on all associated ML links in one shot.
843 */
844 if ((!wpa_auth->is_ml || !conf->first_link_auth) &&
845 wpa_auth->conf.wpa_group_rekey) {
846#else /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700847 if (wpa_auth->conf.wpa_group_rekey) {
Sunil Ravi7f769292024-07-23 22:21:32 +0000848#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700849 eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
850 wpa_rekey_gtk, wpa_auth, NULL);
851 }
852
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800853#ifdef CONFIG_P2P
854 if (WPA_GET_BE32(conf->ip_addr_start)) {
855 int count = WPA_GET_BE32(conf->ip_addr_end) -
856 WPA_GET_BE32(conf->ip_addr_start) + 1;
857 if (count > 1000)
858 count = 1000;
859 if (count > 0)
860 wpa_auth->ip_pool = bitfield_alloc(count);
861 }
862#endif /* CONFIG_P2P */
863
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000864 if (conf->tx_bss_auth && conf->beacon_prot) {
865 conf->tx_bss_auth->non_tx_beacon_prot = true;
866 if (!conf->tx_bss_auth->conf.beacon_prot)
867 conf->tx_bss_auth->conf.beacon_prot = true;
868 if (!conf->tx_bss_auth->conf.group_mgmt_cipher)
869 conf->tx_bss_auth->conf.group_mgmt_cipher =
870 conf->group_mgmt_cipher;
871 }
872
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700873 return wpa_auth;
Sunil Ravi876a49b2025-02-03 19:18:32 +0000874
875fail:
876 wpa_deinit_groups(wpa_auth);
877 os_free(wpa_auth->wpa_ie);
878 pmksa_cache_auth_deinit(wpa_auth->pmksa);
879#ifdef CONFIG_IEEE80211BE
880 if (wpa_auth->primary_auth)
881 pmksa_cache_auth_deinit(wpa_auth->ml_pmksa);
882#endif /* CONFIG_IEEE80211BE */
883 os_free(wpa_auth);
884 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700885}
886
887
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800888int wpa_init_keys(struct wpa_authenticator *wpa_auth)
889{
890 struct wpa_group *group = wpa_auth->group;
891
Hai Shalomfdcde762020-04-02 11:19:20 -0700892 wpa_printf(MSG_DEBUG,
893 "WPA: Start group state machine to set initial keys");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800894 wpa_group_sm_step(wpa_auth, group);
Hai Shalome21d4e82020-04-29 16:34:06 -0700895 group->GInit = false;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800896 wpa_group_sm_step(wpa_auth, group);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800897 if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
898 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800899 return 0;
900}
901
902
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000903static void wpa_auth_free_conf(struct wpa_auth_config *conf)
904{
905#ifdef CONFIG_TESTING_OPTIONS
906 wpabuf_free(conf->eapol_m1_elements);
907 conf->eapol_m1_elements = NULL;
908 wpabuf_free(conf->eapol_m3_elements);
909 conf->eapol_m3_elements = NULL;
910#endif /* CONFIG_TESTING_OPTIONS */
911}
912
913
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700914/**
915 * wpa_deinit - Deinitialize WPA authenticator
916 * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
917 */
918void wpa_deinit(struct wpa_authenticator *wpa_auth)
919{
Sunil Ravi876a49b2025-02-03 19:18:32 +0000920#ifdef CONFIG_IEEE80211BE
921 struct wpa_authenticator *next_pa;
922#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700923
924 eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
925 eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
926
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700927 pmksa_cache_auth_deinit(wpa_auth->pmksa);
928
Sunil Ravi876a49b2025-02-03 19:18:32 +0000929#ifdef CONFIG_IEEE80211BE
930 if (wpa_auth->is_ml && wpa_auth->primary_auth) {
931 next_pa = wpa_auth->cb->next_primary_auth(wpa_auth->cb_ctx);
932
933 if (!next_pa) {
934 /* Deinit PMKSA entry list if last link */
935 pmksa_cache_auth_deinit(wpa_auth->ml_pmksa);
936 } else {
937 /* Assign ML primary authenticator to the next link
938 * authenticator and start rekey timer.
939 */
940 next_pa->primary_auth = true;
941 if (next_pa->conf.wpa_group_rekey)
942 eloop_register_timeout(
943 next_pa->conf.wpa_group_rekey,
944 0, wpa_rekey_gtk, next_pa, NULL);
945 }
946 }
947#endif /* CONFIG_IEEE80211BE */
948
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800949#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700950 wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
951 wpa_auth->ft_pmk_cache = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700952 wpa_ft_deinit(wpa_auth);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800953#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700954
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800955#ifdef CONFIG_P2P
956 bitfield_free(wpa_auth->ip_pool);
957#endif /* CONFIG_P2P */
958
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700959 os_free(wpa_auth->wpa_ie);
Sunil Ravi876a49b2025-02-03 19:18:32 +0000960 wpa_deinit_groups(wpa_auth);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000961 wpa_auth_free_conf(&wpa_auth->conf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700962 os_free(wpa_auth);
963}
964
965
966/**
967 * wpa_reconfig - Update WPA authenticator configuration
968 * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
969 * @conf: Configuration for WPA authenticator
970 */
971int wpa_reconfig(struct wpa_authenticator *wpa_auth,
972 struct wpa_auth_config *conf)
973{
974 struct wpa_group *group;
Hai Shalomfdcde762020-04-02 11:19:20 -0700975
976 if (!wpa_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700977 return 0;
978
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000979 wpa_auth_free_conf(&wpa_auth->conf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700980 os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
981 if (wpa_auth_gen_wpa_ie(wpa_auth)) {
982 wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
983 return -1;
984 }
985
986 /*
987 * Reinitialize GTK to make sure it is suitable for the new
988 * configuration.
989 */
990 group = wpa_auth->group;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700991 group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
Hai Shalome21d4e82020-04-29 16:34:06 -0700992 group->GInit = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700993 wpa_group_sm_step(wpa_auth, group);
Hai Shalome21d4e82020-04-29 16:34:06 -0700994 group->GInit = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995 wpa_group_sm_step(wpa_auth, group);
996
997 return 0;
998}
999
1000
1001struct wpa_state_machine *
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001002wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
1003 const u8 *p2p_dev_addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001004{
1005 struct wpa_state_machine *sm;
1006
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001007 if (wpa_auth->group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
1008 return NULL;
1009
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001010 sm = os_zalloc(sizeof(struct wpa_state_machine));
Hai Shalomfdcde762020-04-02 11:19:20 -07001011 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001012 return NULL;
1013 os_memcpy(sm->addr, addr, ETH_ALEN);
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001014 if (p2p_dev_addr)
1015 os_memcpy(sm->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001016
1017 sm->wpa_auth = wpa_auth;
1018 sm->group = wpa_auth->group;
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001019 wpa_group_get(sm->wpa_auth, sm->group);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001020#ifdef CONFIG_IEEE80211BE
1021 sm->mld_assoc_link_id = -1;
1022#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001023
1024 return sm;
1025}
1026
1027
1028int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
1029 struct wpa_state_machine *sm)
1030{
Hai Shalomfdcde762020-04-02 11:19:20 -07001031 if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001032 return -1;
1033
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001034#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001035 if (sm->ft_completed) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001036 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07001037 "FT authentication already completed - do not start 4-way handshake");
Dmitry Shmidt71757432014-06-02 13:50:35 -07001038 /* Go to PTKINITDONE state to allow GTK rekeying */
1039 sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
Hai Shalome21d4e82020-04-29 16:34:06 -07001040 sm->Pair = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001041 return 0;
1042 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001043#endif /* CONFIG_IEEE80211R_AP */
1044
1045#ifdef CONFIG_FILS
1046 if (sm->fils_completed) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001047 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001048 "FILS authentication already completed - do not start 4-way handshake");
1049 /* Go to PTKINITDONE state to allow GTK rekeying */
1050 sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
Hai Shalome21d4e82020-04-29 16:34:06 -07001051 sm->Pair = true;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001052 return 0;
1053 }
1054#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001055
1056 if (sm->started) {
1057 os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
Hai Shalome21d4e82020-04-29 16:34:06 -07001058 sm->ReAuthenticationRequest = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001059 return wpa_sm_step(sm);
1060 }
1061
Sunil Raviaf8751c2023-03-29 11:35:17 -07001062 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001063 "start authentication");
1064 sm->started = 1;
1065
Hai Shalome21d4e82020-04-29 16:34:06 -07001066 sm->Init = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001067 if (wpa_sm_step(sm) == 1)
1068 return 1; /* should not really happen */
Hai Shalome21d4e82020-04-29 16:34:06 -07001069 sm->Init = false;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001070
1071 if (wpa_auth_4way_handshake_offload(sm->wpa_auth))
1072 wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
1073 "Skip EAPOL for 4-way handshake offload case");
1074 else
1075 sm->AuthenticationRequest = true;
1076
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001077 return wpa_sm_step(sm);
1078}
1079
1080
1081void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
1082{
1083 /* WPA/RSN was not used - clear WPA state. This is needed if the STA
1084 * reassociates back to the same AP while the previous entry for the
1085 * STA has not yet been removed. */
Hai Shalomfdcde762020-04-02 11:19:20 -07001086 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001087 return;
1088
1089 sm->wpa_key_mgmt = 0;
1090}
1091
1092
1093static void wpa_free_sta_sm(struct wpa_state_machine *sm)
1094{
Sunil Ravi7f769292024-07-23 22:21:32 +00001095#ifdef CONFIG_IEEE80211BE
1096 int link_id;
1097#endif /* CONFIG_IEEE80211BE */
1098
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001099#ifdef CONFIG_P2P
1100 if (WPA_GET_BE32(sm->ip_addr)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001101 wpa_printf(MSG_DEBUG,
1102 "P2P: Free assigned IP address %u.%u.%u.%u from "
Sunil8cd6f4d2022-06-28 18:40:46 +00001103 MACSTR " (bit %u)",
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001104 sm->ip_addr[0], sm->ip_addr[1],
1105 sm->ip_addr[2], sm->ip_addr[3],
Sunil Raviaf8751c2023-03-29 11:35:17 -07001106 MAC2STR(wpa_auth_get_spa(sm)),
1107 sm->ip_addr_bit);
Sunil8cd6f4d2022-06-28 18:40:46 +00001108 bitfield_clear(sm->wpa_auth->ip_pool, sm->ip_addr_bit);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001109 }
1110#endif /* CONFIG_P2P */
Sunil Ravi7f769292024-07-23 22:21:32 +00001111 if (sm->GUpdateStationKeys)
1112 wpa_gkeydone_sta(sm);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001113#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001114 os_free(sm->assoc_resp_ftie);
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07001115 wpabuf_free(sm->ft_pending_req_ies);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001116#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001117 os_free(sm->last_rx_eapol_key);
1118 os_free(sm->wpa_ie);
Hai Shalomc3565922019-10-28 11:58:20 -07001119 os_free(sm->rsnxe);
Sunil Ravic0f5d412024-09-11 22:12:49 +00001120 os_free(sm->rsn_selection);
Sunil Ravi7f769292024-07-23 22:21:32 +00001121#ifdef CONFIG_IEEE80211BE
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00001122 for_each_sm_auth(sm, link_id)
Sunil Ravi7f769292024-07-23 22:21:32 +00001123 sm->mld_links[link_id].wpa_auth = NULL;
Sunil Ravi7f769292024-07-23 22:21:32 +00001124#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07001125 wpa_group_put(sm->wpa_auth, sm->group);
Hai Shalom021b0b52019-04-10 11:17:58 -07001126#ifdef CONFIG_DPP2
1127 wpabuf_clear_free(sm->dpp_z);
1128#endif /* CONFIG_DPP2 */
Hai Shalom1dc4d202019-04-29 16:22:27 -07001129 bin_clear_free(sm, sizeof(*sm));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001130}
1131
1132
1133void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
1134{
Hai Shalomfdcde762020-04-02 11:19:20 -07001135 struct wpa_authenticator *wpa_auth;
1136
1137 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001138 return;
1139
Hai Shalomfdcde762020-04-02 11:19:20 -07001140 wpa_auth = sm->wpa_auth;
1141 if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
Sunil Ravi7f769292024-07-23 22:21:32 +00001142 struct wpa_authenticator *primary_auth = wpa_auth;
1143
Sunil Raviaf8751c2023-03-29 11:35:17 -07001144 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07001145 "strict rekeying - force GTK rekey since STA is leaving");
Sunil Ravi7f769292024-07-23 22:21:32 +00001146
1147#ifdef CONFIG_IEEE80211BE
1148 if (wpa_auth->is_ml && !wpa_auth->primary_auth)
1149 primary_auth = wpa_get_primary_auth(wpa_auth);
1150#endif /* CONFIG_IEEE80211BE */
1151
Roshan Pius3a1667e2018-07-03 15:17:14 -07001152 if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
Sunil Ravi7f769292024-07-23 22:21:32 +00001153 primary_auth, NULL) == -1)
Hai Shalomfdcde762020-04-02 11:19:20 -07001154 eloop_register_timeout(0, 500000, wpa_rekey_gtk,
Sunil Ravi7f769292024-07-23 22:21:32 +00001155 primary_auth, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001156 }
1157
Hai Shalomfdcde762020-04-02 11:19:20 -07001158 eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001159 sm->pending_1_of_4_timeout = 0;
1160 eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07001161 eloop_cancel_timeout(wpa_rekey_ptk, wpa_auth, sm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001162#ifdef CONFIG_IEEE80211R_AP
1163 wpa_ft_sta_deinit(sm);
1164#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001165 if (sm->in_step_loop) {
1166 /* Must not free state machine while wpa_sm_step() is running.
1167 * Freeing will be completed in the end of wpa_sm_step(). */
Hai Shalomfdcde762020-04-02 11:19:20 -07001168 wpa_printf(MSG_DEBUG,
1169 "WPA: Registering pending STA state machine deinit for "
Sunil Raviaf8751c2023-03-29 11:35:17 -07001170 MACSTR, MAC2STR(wpa_auth_get_spa(sm)));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001171 sm->pending_deinit = 1;
1172 } else
1173 wpa_free_sta_sm(sm);
1174}
1175
1176
1177static void wpa_request_new_ptk(struct wpa_state_machine *sm)
1178{
Hai Shalomfdcde762020-04-02 11:19:20 -07001179 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001180 return;
1181
Hai Shalomfdcde762020-04-02 11:19:20 -07001182 if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
1183 wpa_printf(MSG_INFO,
1184 "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
Sunil Raviaf8751c2023-03-29 11:35:17 -07001185 MAC2STR(wpa_auth_get_spa(sm)));
Hai Shalome21d4e82020-04-29 16:34:06 -07001186 sm->Disconnect = true;
Hai Shalomfdcde762020-04-02 11:19:20 -07001187 /* Try to encourage the STA to reconnect */
1188 sm->disconnect_reason =
1189 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
1190 } else {
1191 if (sm->use_ext_key_id)
1192 sm->keyidx_active ^= 1; /* flip Key ID */
Hai Shalome21d4e82020-04-29 16:34:06 -07001193 sm->PTKRequest = true;
Hai Shalomfdcde762020-04-02 11:19:20 -07001194 sm->PTK_valid = 0;
1195 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001196}
1197
1198
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001199static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001200 const u8 *replay_counter)
1201{
1202 int i;
1203 for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001204 if (!ctr[i].valid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001205 break;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001206 if (os_memcmp(replay_counter, ctr[i].counter,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001207 WPA_REPLAY_COUNTER_LEN) == 0)
1208 return 1;
1209 }
1210 return 0;
1211}
1212
1213
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001214static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
1215 const u8 *replay_counter)
1216{
1217 int i;
1218 for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
1219 if (ctr[i].valid &&
Hai Shalomfdcde762020-04-02 11:19:20 -07001220 (!replay_counter ||
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001221 os_memcmp(replay_counter, ctr[i].counter,
1222 WPA_REPLAY_COUNTER_LEN) == 0))
Hai Shalome21d4e82020-04-29 16:34:06 -07001223 ctr[i].valid = false;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001224 }
1225}
1226
1227
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001228#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001229static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
1230 struct wpa_state_machine *sm,
1231 struct wpa_eapol_ie_parse *kde)
1232{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001233 struct wpa_ie_data ie, assoc_ie;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001234 struct rsn_mdie *mdie;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001235 unsigned int i, j;
1236 bool found = false;
1237
1238 /* Verify that PMKR1Name from EAPOL-Key message 2/4 matches the value
1239 * we derived. */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001240
1241 if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001242 ie.num_pmkid < 1 || !ie.pmkid) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001243 wpa_printf(MSG_DEBUG,
1244 "FT: No PMKR1Name in FT 4-way handshake message 2/4");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001245 return -1;
1246 }
1247
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001248 if (wpa_parse_wpa_ie_rsn(sm->wpa_ie, sm->wpa_ie_len, &assoc_ie) < 0) {
1249 wpa_printf(MSG_DEBUG,
1250 "FT: Could not parse (Re)Association Request frame RSNE");
1251 os_memset(&assoc_ie, 0, sizeof(assoc_ie));
1252 /* Continue to allow PMKR1Name matching to be done to cover the
1253 * case where it is the only listed PMKID. */
1254 }
1255
1256 for (i = 0; i < ie.num_pmkid; i++) {
1257 const u8 *pmkid = ie.pmkid + i * PMKID_LEN;
1258
1259 if (os_memcmp_const(pmkid, sm->pmk_r1_name,
1260 WPA_PMK_NAME_LEN) == 0) {
1261 wpa_printf(MSG_DEBUG,
1262 "FT: RSNE[PMKID[%u]] from supplicant matches PMKR1Name",
1263 i);
1264 found = true;
1265 } else {
1266 for (j = 0; j < assoc_ie.num_pmkid; j++) {
1267 if (os_memcmp(pmkid,
1268 assoc_ie.pmkid + j * PMKID_LEN,
1269 PMKID_LEN) == 0)
1270 break;
1271 }
1272
1273 if (j == assoc_ie.num_pmkid) {
1274 wpa_printf(MSG_DEBUG,
1275 "FT: RSNE[PMKID[%u]] from supplicant is neither PMKR1Name nor included in AssocReq",
1276 i);
1277 found = false;
1278 break;
1279 }
1280 wpa_printf(MSG_DEBUG,
1281 "FT: RSNE[PMKID[%u]] from supplicant is not PMKR1Name, but matches a PMKID in AssocReq",
1282 i);
1283 }
1284 }
1285
1286 if (!found) {
1287 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
1288 LOGGER_DEBUG,
1289 "PMKR1Name mismatch in FT 4-way handshake");
1290 wpa_hexdump(MSG_DEBUG,
1291 "FT: PMKIDs/PMKR1Name from Supplicant",
1292 ie.pmkid, ie.num_pmkid * PMKID_LEN);
1293 wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
1294 sm->pmk_r1_name, WPA_PMK_NAME_LEN);
1295 return -1;
1296 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001297
1298 if (!kde->mdie || !kde->ftie) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001299 wpa_printf(MSG_DEBUG,
1300 "FT: No %s in FT 4-way handshake message 2/4",
1301 kde->mdie ? "FTIE" : "MDIE");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001302 return -1;
1303 }
1304
1305 mdie = (struct rsn_mdie *) (kde->mdie + 2);
1306 if (kde->mdie[1] < sizeof(struct rsn_mdie) ||
1307 os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain,
1308 MOBILITY_DOMAIN_ID_LEN) != 0) {
1309 wpa_printf(MSG_DEBUG, "FT: MDIE mismatch");
1310 return -1;
1311 }
1312
1313 if (sm->assoc_resp_ftie &&
1314 (kde->ftie[1] != sm->assoc_resp_ftie[1] ||
1315 os_memcmp(kde->ftie, sm->assoc_resp_ftie,
1316 2 + sm->assoc_resp_ftie[1]) != 0)) {
1317 wpa_printf(MSG_DEBUG, "FT: FTIE mismatch");
1318 wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4",
1319 kde->ftie, kde->ftie_len);
1320 wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp",
1321 sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]);
1322 return -1;
1323 }
1324
1325 return 0;
1326}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001327#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001328
1329
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001330static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
1331 struct wpa_state_machine *sm, int group)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001332{
1333 /* Supplicant reported a Michael MIC error */
Sunil Raviaf8751c2023-03-29 11:35:17 -07001334 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001335 "received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))",
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001336 group);
1337
1338 if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001339 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001340 "ignore Michael MIC failure report since group cipher is not TKIP");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001341 } else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001342 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001343 "ignore Michael MIC failure report since pairwise cipher is not TKIP");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001344 } else {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001345 if (wpa_auth_mic_failure_report(wpa_auth,
1346 wpa_auth_get_spa(sm)) > 0)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001347 return 1; /* STA entry was removed */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001348 sm->dot11RSNAStatsTKIPRemoteMICFailures++;
1349 wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
1350 }
1351
1352 /*
1353 * Error report is not a request for a new key handshake, but since
1354 * Authenticator may do it, let's change the keys now anyway.
1355 */
1356 wpa_request_new_ptk(sm);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001357 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001358}
1359
1360
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001361static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
1362 size_t data_len)
1363{
1364 struct wpa_ptk PTK;
1365 int ok = 0;
1366 const u8 *pmk = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001367 size_t pmk_len;
Hai Shalom021b0b52019-04-10 11:17:58 -07001368 int vlan_id = 0;
Sunil Raviaf8751c2023-03-29 11:35:17 -07001369 u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
1370 u8 pmk_r1[PMK_LEN_MAX];
1371 size_t key_len;
1372 int ret = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001373
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001374 os_memset(&PTK, 0, sizeof(PTK));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001375 for (;;) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001376 if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
1377 !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001378 pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
Hai Shalom021b0b52019-04-10 11:17:58 -07001379 sm->p2p_dev_addr, pmk, &pmk_len,
1380 &vlan_id);
Hai Shalomfdcde762020-04-02 11:19:20 -07001381 if (!pmk)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001382 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001383#ifdef CONFIG_IEEE80211R_AP
1384 if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
1385 os_memcpy(sm->xxkey, pmk, pmk_len);
1386 sm->xxkey_len = pmk_len;
1387 }
1388#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001389 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001390 pmk = sm->PMK;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001391 pmk_len = sm->pmk_len;
1392 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001393
Sunil Raviaf8751c2023-03-29 11:35:17 -07001394 if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0,
Sunil Ravi7f769292024-07-23 22:21:32 +00001395 pmk_r0, pmk_r1, pmk_r0_name, &key_len,
1396 false) < 0)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001397 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001398
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001399 if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
1400 data, data_len) == 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001401 if (sm->PMK != pmk) {
1402 os_memcpy(sm->PMK, pmk, pmk_len);
1403 sm->pmk_len = pmk_len;
1404 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001405 ok = 1;
1406 break;
1407 }
1408
Roshan Pius3a1667e2018-07-03 15:17:14 -07001409 if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
1410 wpa_key_mgmt_sae(sm->wpa_key_mgmt))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001411 break;
1412 }
1413
1414 if (!ok) {
1415 wpa_printf(MSG_DEBUG,
1416 "WPA: Earlier SNonce did not result in matching MIC");
Sunil Raviaf8751c2023-03-29 11:35:17 -07001417 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001418 }
1419
1420 wpa_printf(MSG_DEBUG,
1421 "WPA: Earlier SNonce resulted in matching MIC");
1422 sm->alt_snonce_valid = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07001423
1424 if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
1425 wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
Sunil Raviaf8751c2023-03-29 11:35:17 -07001426 goto fail;
1427
1428#ifdef CONFIG_IEEE80211R_AP
1429 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) {
1430 wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1");
1431 wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name,
1432 key_len);
1433 }
1434#endif /* CONFIG_IEEE80211R_AP */
Hai Shalom021b0b52019-04-10 11:17:58 -07001435
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001436 os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
1437 os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
Hai Shalom81f62d82019-07-22 12:10:00 -07001438 forced_memzero(&PTK, sizeof(PTK));
Hai Shalome21d4e82020-04-29 16:34:06 -07001439 sm->PTK_valid = true;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001440
Sunil Raviaf8751c2023-03-29 11:35:17 -07001441 ret = 0;
1442fail:
1443 forced_memzero(pmk_r0, sizeof(pmk_r0));
1444 forced_memzero(pmk_r1, sizeof(pmk_r1));
1445 return ret;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001446}
1447
1448
Hai Shaloma20dcd72022-02-04 13:43:00 -08001449static bool wpa_auth_gtk_rekey_in_process(struct wpa_authenticator *wpa_auth)
1450{
1451 struct wpa_group *group;
1452
1453 for (group = wpa_auth->group; group; group = group->next) {
1454 if (group->GKeyDoneStations)
1455 return true;
1456 }
1457 return false;
1458}
1459
1460
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001461enum eapol_key_msg { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST };
1462
1463static bool wpa_auth_valid_key_desc_ver(struct wpa_authenticator *wpa_auth,
1464 struct wpa_state_machine *sm, u16 ver)
1465{
1466 if (ver > WPA_KEY_INFO_TYPE_AES_128_CMAC) {
1467 wpa_printf(MSG_INFO, "RSN: " MACSTR
1468 " used undefined Key Descriptor Version %d",
1469 MAC2STR(wpa_auth_get_spa(sm)), ver);
1470 return false;
1471 }
1472
1473 if (!wpa_use_akm_defined(sm->wpa_key_mgmt) &&
1474 wpa_use_cmac(sm->wpa_key_mgmt) &&
1475 ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
1476 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1477 LOGGER_WARNING,
1478 "advertised support for AES-128-CMAC, but did not use it");
1479 return false;
1480 }
1481
1482 if (sm->pairwise != WPA_CIPHER_TKIP &&
1483 !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
1484 !wpa_use_cmac(sm->wpa_key_mgmt) &&
1485 ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
1486 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1487 LOGGER_WARNING,
1488 "did not use HMAC-SHA1-AES with CCMP/GCMP");
1489 return false;
1490 }
1491
1492 if (wpa_use_akm_defined(sm->wpa_key_mgmt) &&
1493 ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
1494 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1495 LOGGER_WARNING,
1496 "did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
1497 return false;
1498 }
1499
1500 return true;
1501}
1502
1503
1504static bool wpa_auth_valid_request_counter(struct wpa_authenticator *wpa_auth,
1505 struct wpa_state_machine *sm,
1506 const u8 *replay_counter)
1507{
1508
1509 if (sm->req_replay_counter_used &&
1510 os_memcmp(replay_counter, sm->req_replay_counter,
1511 WPA_REPLAY_COUNTER_LEN) <= 0) {
1512 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1513 LOGGER_WARNING,
1514 "received EAPOL-Key request with replayed counter");
1515 return false;
1516 }
1517
1518 return true;
1519}
1520
1521
1522static bool wpa_auth_valid_counter(struct wpa_authenticator *wpa_auth,
1523 struct wpa_state_machine *sm,
1524 const struct wpa_eapol_key *key,
1525 enum eapol_key_msg msg,
1526 const char *msgtxt)
1527{
1528 int i;
1529
1530 if (msg == REQUEST)
1531 return wpa_auth_valid_request_counter(wpa_auth, sm,
1532 key->replay_counter);
1533
1534 if (wpa_replay_counter_valid(sm->key_replay, key->replay_counter))
1535 return true;
1536
1537 if (msg == PAIRWISE_2 &&
1538 wpa_replay_counter_valid(sm->prev_key_replay,
1539 key->replay_counter) &&
1540 sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
1541 os_memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
1542 /*
1543 * Some supplicant implementations (e.g., Windows XP
1544 * WZC) update SNonce for each EAPOL-Key 2/4. This
1545 * breaks the workaround on accepting any of the
1546 * pending requests, so allow the SNonce to be updated
1547 * even if we have already sent out EAPOL-Key 3/4.
1548 */
1549 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
1550 LOGGER_DEBUG,
1551 "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4");
1552 sm->update_snonce = 1;
1553 os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
1554 sm->alt_snonce_valid = true;
1555 os_memcpy(sm->alt_replay_counter,
1556 sm->key_replay[0].counter,
1557 WPA_REPLAY_COUNTER_LEN);
1558 return true;
1559 }
1560
1561 if (msg == PAIRWISE_4 && sm->alt_snonce_valid &&
1562 sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
1563 os_memcmp(key->replay_counter, sm->alt_replay_counter,
1564 WPA_REPLAY_COUNTER_LEN) == 0) {
1565 /*
1566 * Supplicant may still be using the old SNonce since
1567 * there was two EAPOL-Key 2/4 messages and they had
1568 * different SNonce values.
1569 */
1570 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
1571 LOGGER_DEBUG,
1572 "Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4");
1573 return true;
1574 }
1575
1576 if (msg == PAIRWISE_2 &&
1577 wpa_replay_counter_valid(sm->prev_key_replay,
1578 key->replay_counter) &&
1579 sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
1580 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
1581 LOGGER_DEBUG,
1582 "ignore retransmitted EAPOL-Key %s - SNonce did not change",
1583 msgtxt);
1584 } else {
1585 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
1586 LOGGER_DEBUG,
1587 "received EAPOL-Key %s with unexpected replay counter",
1588 msgtxt);
1589 }
1590 for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
1591 if (!sm->key_replay[i].valid)
1592 break;
1593 wpa_hexdump(MSG_DEBUG, "pending replay counter",
1594 sm->key_replay[i].counter,
1595 WPA_REPLAY_COUNTER_LEN);
1596 }
1597 wpa_hexdump(MSG_DEBUG, "received replay counter",
1598 key->replay_counter, WPA_REPLAY_COUNTER_LEN);
1599 return false;
1600}
1601
1602
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001603void wpa_receive(struct wpa_authenticator *wpa_auth,
1604 struct wpa_state_machine *sm,
1605 u8 *data, size_t data_len)
1606{
1607 struct ieee802_1x_hdr *hdr;
1608 struct wpa_eapol_key *key;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001609 u16 key_info, ver, key_data_length;
1610 enum eapol_key_msg msg;
1611 const char *msgtxt;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001612 const u8 *key_data;
1613 size_t keyhdrlen, mic_len;
1614 u8 *mic;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001615 u8 *key_data_buf = NULL;
1616 size_t key_data_buf_len = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001617
Hai Shalomfdcde762020-04-02 11:19:20 -07001618 if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001619 return;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001620
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001621 wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001622
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001623 mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001624 keyhdrlen = sizeof(*key) + mic_len + 2;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001625
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001626 if (data_len < sizeof(*hdr) + keyhdrlen) {
1627 wpa_printf(MSG_DEBUG, "WPA: Ignore too short EAPOL-Key frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001628 return;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001629 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001630
1631 hdr = (struct ieee802_1x_hdr *) data;
1632 key = (struct wpa_eapol_key *) (hdr + 1);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001633 mic = (u8 *) (key + 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001634 key_info = WPA_GET_BE16(key->key_info);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001635 key_data = mic + mic_len + 2;
1636 key_data_length = WPA_GET_BE16(mic + mic_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001637 wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
Hai Shalomfdcde762020-04-02 11:19:20 -07001638 " key_info=0x%x type=%u mic_len=%zu key_data_length=%u",
Sunil Raviaf8751c2023-03-29 11:35:17 -07001639 MAC2STR(wpa_auth_get_spa(sm)), key_info, key->type,
Hai Shalomfdcde762020-04-02 11:19:20 -07001640 mic_len, key_data_length);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001641 wpa_hexdump(MSG_MSGDUMP,
1642 "WPA: EAPOL-Key header (ending before Key MIC)",
1643 key, sizeof(*key));
1644 wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
1645 mic, mic_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001646 if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001647 wpa_printf(MSG_INFO,
1648 "WPA: Invalid EAPOL-Key frame - key_data overflow (%d > %zu)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001649 key_data_length,
Hai Shalomfdcde762020-04-02 11:19:20 -07001650 data_len - sizeof(*hdr) - keyhdrlen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001651 return;
1652 }
1653
1654 if (sm->wpa == WPA_VERSION_WPA2) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001655 if (key->type == EAPOL_KEY_TYPE_WPA) {
1656 /*
1657 * Some deployed station implementations seem to send
1658 * msg 4/4 with incorrect type value in WPA2 mode.
1659 */
Hai Shalomfdcde762020-04-02 11:19:20 -07001660 wpa_printf(MSG_DEBUG,
1661 "Workaround: Allow EAPOL-Key with unexpected WPA type in RSN mode");
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001662 } else if (key->type != EAPOL_KEY_TYPE_RSN) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001663 wpa_printf(MSG_DEBUG,
1664 "Ignore EAPOL-Key with unexpected type %d in RSN mode",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001665 key->type);
1666 return;
1667 }
1668 } else {
1669 if (key->type != EAPOL_KEY_TYPE_WPA) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001670 wpa_printf(MSG_DEBUG,
1671 "Ignore EAPOL-Key with unexpected type %d in WPA mode",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001672 key->type);
1673 return;
1674 }
1675 }
1676
1677 wpa_hexdump(MSG_DEBUG, "WPA: Received Key Nonce", key->key_nonce,
1678 WPA_NONCE_LEN);
1679 wpa_hexdump(MSG_DEBUG, "WPA: Received Replay Counter",
1680 key->replay_counter, WPA_REPLAY_COUNTER_LEN);
1681
1682 /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
1683 * are set */
1684
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001685 if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
1686 wpa_printf(MSG_DEBUG, "WPA: Ignore SMK message");
1687 return;
1688 }
1689
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001690 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
1691 if (!wpa_auth_valid_key_desc_ver(wpa_auth, sm, ver))
1692 goto out;
1693 if (mic_len > 0 && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
1694 sm->PTK_valid &&
1695 (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
1696 ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
1697 wpa_use_aes_key_wrap(sm->wpa_key_mgmt)) &&
1698 key_data_length >= 8 && key_data_length % 8 == 0) {
1699 key_data_length -= 8; /* AES-WRAP adds 8 bytes */
1700 key_data_buf = os_malloc(key_data_length);
1701 if (!key_data_buf)
1702 goto out;
1703 key_data_buf_len = key_data_length;
1704 if (aes_unwrap(sm->PTK.kek, sm->PTK.kek_len,
1705 key_data_length / 8, key_data, key_data_buf)) {
1706 wpa_printf(MSG_INFO,
1707 "RSN: AES unwrap failed - could not decrypt EAPOL-Key key data");
1708 goto out;
1709 }
1710 key_data = key_data_buf;
1711 wpa_hexdump_key(MSG_DEBUG, "RSN: Decrypted EAPOL-Key Key Data",
1712 key_data, key_data_length);
1713 }
1714
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001715 if (key_info & WPA_KEY_INFO_REQUEST) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001716 msg = REQUEST;
1717 msgtxt = "Request";
1718 } else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
1719 msg = GROUP_2;
1720 msgtxt = "2/2 Group";
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001721 } else if (key_data_length == 0 ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001722 (sm->wpa == WPA_VERSION_WPA2 &&
1723 (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA) ||
1724 key_data_buf) &&
1725 (key_info & WPA_KEY_INFO_SECURE) &&
1726 !get_ie(key_data, key_data_length, WLAN_EID_RSN)) ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001727 (mic_len == 0 && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001728 key_data_length == AES_BLOCK_SIZE)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001729 msg = PAIRWISE_4;
1730 msgtxt = "4/4 Pairwise";
1731 } else {
1732 msg = PAIRWISE_2;
1733 msgtxt = "2/4 Pairwise";
1734 }
1735
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001736 if (!wpa_auth_valid_counter(wpa_auth, sm, key, msg, msgtxt))
1737 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001738
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001739#ifdef CONFIG_FILS
1740 if (sm->wpa == WPA_VERSION_WPA2 && mic_len == 0 &&
1741 !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001742 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001743 "WPA: Encr Key Data bit not set even though AEAD cipher is supposed to be used - drop frame");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001744 goto out;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001745 }
1746#endif /* CONFIG_FILS */
1747
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001748 switch (msg) {
1749 case PAIRWISE_2:
1750 if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001751 sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING &&
1752 (!sm->update_snonce ||
1753 sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001754 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
1755 LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001756 "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001757 sm->wpa_ptk_state);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001758 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001759 }
1760 random_add_randomness(key->key_nonce, WPA_NONCE_LEN);
1761 if (sm->group->reject_4way_hs_for_entropy) {
1762 /*
1763 * The system did not have enough entropy to generate
1764 * strong random numbers. Reject the first 4-way
1765 * handshake(s) and collect some entropy based on the
1766 * information from it. Once enough entropy is
1767 * available, the next atempt will trigger GMK/Key
1768 * Counter update and the station will be allowed to
1769 * continue.
1770 */
Hai Shalomfdcde762020-04-02 11:19:20 -07001771 wpa_printf(MSG_DEBUG,
1772 "WPA: Reject 4-way handshake to collect more entropy for random number generation");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001773 random_mark_pool_ready();
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001774 wpa_sta_disconnect(wpa_auth, sm->addr,
1775 WLAN_REASON_PREV_AUTH_NOT_VALID);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001776 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001777 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001778 break;
1779 case PAIRWISE_4:
1780 if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
1781 !sm->PTK_valid) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001782 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
1783 LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001784 "received EAPOL-Key msg 4/4 in invalid state (%d) - dropped",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001785 sm->wpa_ptk_state);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001786 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001787 }
1788 break;
1789 case GROUP_2:
1790 if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
1791 || !sm->PTK_valid) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001792 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
1793 LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001794 "received EAPOL-Key msg 2/2 in invalid state (%d) - dropped",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001795 sm->wpa_ptk_group_state);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001796 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001797 }
1798 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001799 case REQUEST:
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001800 if (sm->wpa_ptk_state == WPA_PTK_PTKSTART ||
1801 sm->wpa_ptk_state == WPA_PTK_PTKCALCNEGOTIATING ||
1802 sm->wpa_ptk_state == WPA_PTK_PTKCALCNEGOTIATING2 ||
1803 sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
1804 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
1805 LOGGER_INFO,
1806 "received EAPOL-Key Request in invalid state (%d) - dropped",
1807 sm->wpa_ptk_state);
1808 goto out;
1809 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001810 break;
1811 }
1812
Sunil Raviaf8751c2023-03-29 11:35:17 -07001813 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001814 "received EAPOL-Key frame (%s)", msgtxt);
1815
1816 if (key_info & WPA_KEY_INFO_ACK) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001817 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001818 "received invalid EAPOL-Key: Key Ack set");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001819 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001820 }
1821
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001822 if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
1823 !(key_info & WPA_KEY_INFO_MIC)) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001824 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001825 "received invalid EAPOL-Key: Key MIC not set");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001826 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001827 }
1828
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001829#ifdef CONFIG_FILS
1830 if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
1831 (key_info & WPA_KEY_INFO_MIC)) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001832 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001833 "received invalid EAPOL-Key: Key MIC set");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001834 goto out;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001835 }
1836#endif /* CONFIG_FILS */
1837
Hai Shalome21d4e82020-04-29 16:34:06 -07001838 sm->MICVerified = false;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001839 if (sm->PTK_valid && !sm->update_snonce) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001840 if (mic_len &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001841 wpa_verify_key_mic(sm->wpa_key_mgmt, sm->pmk_len, &sm->PTK,
1842 data, data_len) &&
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001843 (msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
1844 wpa_try_alt_snonce(sm, data, data_len))) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001845 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1846 LOGGER_INFO,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001847 "received EAPOL-Key with invalid MIC");
Hai Shalom74f70d42019-02-11 14:42:39 -08001848#ifdef TEST_FUZZ
1849 wpa_printf(MSG_INFO,
1850 "TEST: Ignore Key MIC failure for fuzz testing");
1851 goto continue_fuzz;
1852#endif /* TEST_FUZZ */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001853 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001854 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001855#ifdef CONFIG_FILS
1856 if (!mic_len &&
1857 wpa_aead_decrypt(sm, &sm->PTK, data, data_len,
1858 &key_data_length) < 0) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001859 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1860 LOGGER_INFO,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001861 "received EAPOL-Key with invalid MIC");
Hai Shalom74f70d42019-02-11 14:42:39 -08001862#ifdef TEST_FUZZ
1863 wpa_printf(MSG_INFO,
1864 "TEST: Ignore Key MIC failure for fuzz testing");
1865 goto continue_fuzz;
1866#endif /* TEST_FUZZ */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001867 goto out;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001868 }
1869#endif /* CONFIG_FILS */
Hai Shalom74f70d42019-02-11 14:42:39 -08001870#ifdef TEST_FUZZ
1871 continue_fuzz:
1872#endif /* TEST_FUZZ */
Hai Shalome21d4e82020-04-29 16:34:06 -07001873 sm->MICVerified = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001874 eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
1875 sm->pending_1_of_4_timeout = 0;
1876 }
1877
1878 if (key_info & WPA_KEY_INFO_REQUEST) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001879 if (!(key_info & WPA_KEY_INFO_SECURE)) {
1880 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1881 LOGGER_INFO,
1882 "received EAPOL-Key request without Secure=1");
1883 goto out;
1884 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001885 if (sm->MICVerified) {
1886 sm->req_replay_counter_used = 1;
1887 os_memcpy(sm->req_replay_counter, key->replay_counter,
1888 WPA_REPLAY_COUNTER_LEN);
1889 } else {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001890 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1891 LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001892 "received EAPOL-Key request with invalid MIC");
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001893 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001894 }
1895
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001896 if (key_info & WPA_KEY_INFO_ERROR) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001897 if (wpa_receive_error_report(
1898 wpa_auth, sm,
1899 !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001900 goto out; /* STA entry was removed */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001901 } else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001902 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1903 LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001904 "received EAPOL-Key Request for new 4-Way Handshake");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001905 wpa_request_new_ptk(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001906 } else {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001907 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
1908 LOGGER_INFO,
Hai Shalomfdcde762020-04-02 11:19:20 -07001909 "received EAPOL-Key Request for GTK rekeying");
Sunil Ravi7f769292024-07-23 22:21:32 +00001910
1911 eloop_cancel_timeout(wpa_rekey_gtk,
1912 wpa_get_primary_auth(wpa_auth),
1913 NULL);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001914 if (wpa_auth_gtk_rekey_in_process(wpa_auth))
1915 wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG,
1916 "skip new GTK rekey - already in process");
1917 else
Sunil Ravi7f769292024-07-23 22:21:32 +00001918 wpa_rekey_gtk(wpa_get_primary_auth(wpa_auth),
1919 NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001920 }
1921 } else {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001922 /* Do not allow the same key replay counter to be reused. */
1923 wpa_replay_counter_mark_invalid(sm->key_replay,
1924 key->replay_counter);
1925
1926 if (msg == PAIRWISE_2) {
1927 /*
1928 * Maintain a copy of the pending EAPOL-Key frames in
1929 * case the EAPOL-Key frame was retransmitted. This is
1930 * needed to allow EAPOL-Key msg 2/4 reply to another
1931 * pending msg 1/4 to update the SNonce to work around
1932 * unexpected supplicant behavior.
1933 */
1934 os_memcpy(sm->prev_key_replay, sm->key_replay,
1935 sizeof(sm->key_replay));
1936 } else {
1937 os_memset(sm->prev_key_replay, 0,
1938 sizeof(sm->prev_key_replay));
1939 }
1940
1941 /*
1942 * Make sure old valid counters are not accepted anymore and
1943 * do not get copied again.
1944 */
1945 wpa_replay_counter_mark_invalid(sm->key_replay, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001946 }
1947
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001948 os_free(sm->last_rx_eapol_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001949 sm->last_rx_eapol_key = os_memdup(data, data_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07001950 if (!sm->last_rx_eapol_key)
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001951 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001952 sm->last_rx_eapol_key_len = data_len;
1953
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001954 sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
Hai Shalome21d4e82020-04-29 16:34:06 -07001955 sm->EAPOLKeyReceived = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001956 sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
1957 sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
Sunil Ravic0f5d412024-09-11 22:12:49 +00001958 if (msg == PAIRWISE_2)
1959 os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001960 wpa_sm_step(sm);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001961
1962out:
1963 bin_clear_free(key_data_buf, key_data_buf_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001964}
1965
1966
1967static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
1968 const u8 *gnonce, u8 *gtk, size_t gtk_len)
1969{
Roshan Pius3a1667e2018-07-03 15:17:14 -07001970 u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + WPA_GTK_MAX_LEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001971 u8 *pos;
1972 int ret = 0;
1973
1974 /* GTK = PRF-X(GMK, "Group key expansion",
1975 * AA || GNonce || Time || random data)
1976 * The example described in the IEEE 802.11 standard uses only AA and
1977 * GNonce as inputs here. Add some more entropy since this derivation
1978 * is done only at the Authenticator and as such, does not need to be
1979 * exactly same.
1980 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001981 os_memset(data, 0, sizeof(data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001982 os_memcpy(data, addr, ETH_ALEN);
1983 os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
1984 pos = data + ETH_ALEN + WPA_NONCE_LEN;
1985 wpa_get_ntp_timestamp(pos);
Hai Shalom74f70d42019-02-11 14:42:39 -08001986#ifdef TEST_FUZZ
1987 os_memset(pos, 0xef, 8);
1988#endif /* TEST_FUZZ */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001989 pos += 8;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001990 if (random_get_bytes(pos, gtk_len) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001991 ret = -1;
1992
Roshan Pius3a1667e2018-07-03 15:17:14 -07001993#ifdef CONFIG_SHA384
1994 if (sha384_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
1995 gtk, gtk_len) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001996 ret = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001997#else /* CONFIG_SHA384 */
1998#ifdef CONFIG_SHA256
1999 if (sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
2000 gtk, gtk_len) < 0)
2001 ret = -1;
2002#else /* CONFIG_SHA256 */
2003 if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
2004 gtk, gtk_len) < 0)
2005 ret = -1;
2006#endif /* CONFIG_SHA256 */
2007#endif /* CONFIG_SHA384 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002008
Hai Shalom81f62d82019-07-22 12:10:00 -07002009 forced_memzero(data, sizeof(data));
2010
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002011 return ret;
2012}
2013
2014
2015static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
2016{
2017 struct wpa_authenticator *wpa_auth = eloop_ctx;
2018 struct wpa_state_machine *sm = timeout_ctx;
2019
Sunil Ravia04bd252022-05-02 22:54:18 -07002020 if (sm->waiting_radius_psk) {
2021 wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
2022 "Ignore EAPOL-Key timeout while waiting for RADIUS PSK");
2023 return;
2024 }
2025
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002026 sm->pending_1_of_4_timeout = 0;
Sunil Raviaf8751c2023-03-29 11:35:17 -07002027 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
2028 "EAPOL-Key timeout");
Hai Shalome21d4e82020-04-29 16:34:06 -07002029 sm->TimeoutEvt = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002030 wpa_sm_step(sm);
2031}
2032
2033
2034void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
2035 struct wpa_state_machine *sm, int key_info,
2036 const u8 *key_rsc, const u8 *nonce,
2037 const u8 *kde, size_t kde_len,
2038 int keyidx, int encr, int force_version)
2039{
Hai Shalomfdcde762020-04-02 11:19:20 -07002040 struct wpa_auth_config *conf = &wpa_auth->conf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002041 struct ieee802_1x_hdr *hdr;
2042 struct wpa_eapol_key *key;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002043 size_t len, mic_len, keyhdrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002044 int alg;
2045 int key_data_len, pad_len = 0;
2046 u8 *buf, *pos;
2047 int version, pairwise;
2048 int i;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002049 u8 *key_mic, *key_data;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002050
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002051 mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002052 keyhdrlen = sizeof(*key) + mic_len + 2;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002053
2054 len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002055
2056 if (force_version)
2057 version = force_version;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002058 else if (wpa_use_akm_defined(sm->wpa_key_mgmt))
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002059 version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002060 else if (wpa_use_cmac(sm->wpa_key_mgmt))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002061 version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002062 else if (sm->pairwise != WPA_CIPHER_TKIP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002063 version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
2064 else
2065 version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
2066
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07002067 pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002068
Hai Shalomfdcde762020-04-02 11:19:20 -07002069 wpa_printf(MSG_DEBUG,
2070 "WPA: Send EAPOL(version=%d secure=%d mic=%d ack=%d install=%d pairwise=%d kde_len=%zu keyidx=%d encr=%d)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002071 version,
2072 (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
2073 (key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
2074 (key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
2075 (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07002076 pairwise, kde_len, keyidx, encr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002077
2078 key_data_len = kde_len;
2079
2080 if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07002081 wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002082 version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
2083 pad_len = key_data_len % 8;
2084 if (pad_len)
2085 pad_len = 8 - pad_len;
2086 key_data_len += pad_len + 8;
2087 }
2088
2089 len += key_data_len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002090 if (!mic_len && encr)
2091 len += AES_BLOCK_SIZE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002092
2093 hdr = os_zalloc(len);
Hai Shalomfdcde762020-04-02 11:19:20 -07002094 if (!hdr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002095 return;
Hai Shalomfdcde762020-04-02 11:19:20 -07002096 hdr->version = conf->eapol_version;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002097 hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
2098 hdr->length = host_to_be16(len - sizeof(*hdr));
2099 key = (struct wpa_eapol_key *) (hdr + 1);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002100 key_mic = (u8 *) (key + 1);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002101 key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002102
2103 key->type = sm->wpa == WPA_VERSION_WPA2 ?
2104 EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
2105 key_info |= version;
2106 if (encr && sm->wpa == WPA_VERSION_WPA2)
2107 key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
2108 if (sm->wpa != WPA_VERSION_WPA2)
2109 key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
2110 WPA_PUT_BE16(key->key_info, key_info);
2111
Hai Shalomfdcde762020-04-02 11:19:20 -07002112 alg = pairwise ? sm->pairwise : conf->wpa_group;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002113 if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002114 WPA_PUT_BE16(key->key_length, 0);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002115 else
2116 WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002117
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002118 for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
2119 sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
2120 os_memcpy(sm->key_replay[i].counter,
2121 sm->key_replay[i - 1].counter,
2122 WPA_REPLAY_COUNTER_LEN);
2123 }
2124 inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
2125 os_memcpy(key->replay_counter, sm->key_replay[0].counter,
2126 WPA_REPLAY_COUNTER_LEN);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002127 wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
2128 key->replay_counter, WPA_REPLAY_COUNTER_LEN);
Hai Shalome21d4e82020-04-29 16:34:06 -07002129 sm->key_replay[0].valid = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002130
2131 if (nonce)
2132 os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
2133
2134 if (key_rsc)
2135 os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
2136
Sunil Ravic0f5d412024-09-11 22:12:49 +00002137#ifdef CONFIG_TESTING_OPTIONS
Sunil Ravi876a49b2025-02-03 19:18:32 +00002138 if (conf->eapol_key_reserved_random &&
2139 random_get_bytes(key->key_id, sizeof(key->key_id)) < 0)
2140 os_memset(key->key_id, 0x11, sizeof(key->key_id));
Sunil Ravic0f5d412024-09-11 22:12:49 +00002141#endif /* CONFIG_TESTING_OPTIONS */
2142
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002143 if (kde && !encr) {
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002144 os_memcpy(key_data, kde, kde_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002145 WPA_PUT_BE16(key_mic + mic_len, kde_len);
2146#ifdef CONFIG_FILS
Roshan Pius3a1667e2018-07-03 15:17:14 -07002147 } else if (!mic_len && kde) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002148 const u8 *aad[1];
2149 size_t aad_len[1];
2150
2151 WPA_PUT_BE16(key_mic, AES_BLOCK_SIZE + kde_len);
2152 wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
2153 kde, kde_len);
2154
2155 wpa_hexdump_key(MSG_DEBUG, "WPA: KEK",
2156 sm->PTK.kek, sm->PTK.kek_len);
2157 /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
2158 * to Key Data (exclusive). */
2159 aad[0] = (u8 *) hdr;
2160 aad_len[0] = key_mic + 2 - (u8 *) hdr;
2161 if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len, kde, kde_len,
2162 1, aad, aad_len, key_mic + 2) < 0) {
2163 wpa_printf(MSG_DEBUG, "WPA: AES-SIV encryption failed");
2164 return;
2165 }
2166
2167 wpa_hexdump(MSG_DEBUG, "WPA: Encrypted Key Data from SIV",
2168 key_mic + 2, AES_BLOCK_SIZE + kde_len);
2169#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002170 } else if (encr && kde) {
2171 buf = os_zalloc(key_data_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07002172 if (!buf) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002173 os_free(hdr);
2174 return;
2175 }
2176 pos = buf;
2177 os_memcpy(pos, kde, kde_len);
2178 pos += kde_len;
2179
2180 if (pad_len)
2181 *pos++ = 0xdd;
2182
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002183 wpa_hexdump_key(MSG_DEBUG,
2184 "Plaintext EAPOL-Key Key Data (+ padding)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002185 buf, key_data_len);
2186 if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
Roshan Pius3a1667e2018-07-03 15:17:14 -07002187 wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002188 version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002189 wpa_hexdump_key(MSG_DEBUG, "RSN: AES-WRAP using KEK",
2190 sm->PTK.kek, sm->PTK.kek_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002191 if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
2192 (key_data_len - 8) / 8, buf, key_data)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002193 os_free(hdr);
Sunil Ravia04bd252022-05-02 22:54:18 -07002194 bin_clear_free(buf, key_data_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002195 return;
2196 }
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002197 wpa_hexdump(MSG_DEBUG,
2198 "RSN: Encrypted Key Data from AES-WRAP",
2199 key_data, key_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002200 WPA_PUT_BE16(key_mic + mic_len, key_data_len);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002201#if !defined(CONFIG_NO_RC4) && !defined(CONFIG_FIPS)
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002202 } else if (sm->PTK.kek_len == 16) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002203 u8 ek[32];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002204
2205 wpa_printf(MSG_DEBUG,
2206 "WPA: Encrypt Key Data using RC4");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002207 os_memcpy(key->key_iv,
2208 sm->group->Counter + WPA_NONCE_LEN - 16, 16);
2209 inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
2210 os_memcpy(ek, key->key_iv, 16);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002211 os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
2212 os_memcpy(key_data, buf, key_data_len);
2213 rc4_skip(ek, 32, 256, key_data, key_data_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002214 WPA_PUT_BE16(key_mic + mic_len, key_data_len);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002215#endif /* !(CONFIG_NO_RC4 || CONFIG_FIPS) */
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002216 } else {
2217 os_free(hdr);
Sunil Ravia04bd252022-05-02 22:54:18 -07002218 bin_clear_free(buf, key_data_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002219 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002220 }
Sunil Ravia04bd252022-05-02 22:54:18 -07002221 bin_clear_free(buf, key_data_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002222 }
2223
2224 if (key_info & WPA_KEY_INFO_MIC) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002225 if (!sm->PTK_valid || !mic_len) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07002226 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
2227 LOGGER_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07002228 "PTK not valid when sending EAPOL-Key frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002229 os_free(hdr);
2230 return;
2231 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002232
Roshan Pius3a1667e2018-07-03 15:17:14 -07002233 if (wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
2234 sm->wpa_key_mgmt, version,
2235 (u8 *) hdr, len, key_mic) < 0) {
2236 os_free(hdr);
2237 return;
2238 }
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07002239#ifdef CONFIG_TESTING_OPTIONS
2240 if (!pairwise &&
Hai Shalomfdcde762020-04-02 11:19:20 -07002241 conf->corrupt_gtk_rekey_mic_probability > 0.0 &&
2242 drand48() < conf->corrupt_gtk_rekey_mic_probability) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07002243 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
2244 LOGGER_INFO,
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07002245 "Corrupting group EAPOL-Key Key MIC");
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002246 key_mic[0]++;
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07002247 }
2248#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002249 }
2250
Hai Shalomfdcde762020-04-02 11:19:20 -07002251 wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002252 wpa_hexdump(MSG_DEBUG, "Send EAPOL-Key msg", hdr, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002253 wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
Kai Shie75b0652020-11-24 20:31:29 -08002254 sm->pairwise_set);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002255 os_free(hdr);
2256}
2257
2258
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002259static int wpa_auth_get_sta_count(struct wpa_authenticator *wpa_auth)
2260{
2261 if (!wpa_auth->cb->get_sta_count)
2262 return -1;
2263
2264 return wpa_auth->cb->get_sta_count(wpa_auth->cb_ctx);
2265}
2266
2267
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002268static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
2269 struct wpa_state_machine *sm, int key_info,
2270 const u8 *key_rsc, const u8 *nonce,
2271 const u8 *kde, size_t kde_len,
2272 int keyidx, int encr)
2273{
2274 int timeout_ms;
2275 int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002276 u32 ctr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002277
Hai Shalomfdcde762020-04-02 11:19:20 -07002278 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002279 return;
2280
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002281 ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
2282
2283#ifdef CONFIG_TESTING_OPTIONS
2284 /* When delay_eapol_tx is true, delay the EAPOL-Key transmission by
2285 * sending it only on the last attempt after all timeouts for the prior
2286 * skipped attemps. */
2287 if (wpa_auth->conf.delay_eapol_tx &&
2288 ctr != wpa_auth->conf.wpa_pairwise_update_count) {
2289 wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO,
2290 "DELAY-EAPOL-TX-%d", ctr);
2291 goto skip_tx;
2292 }
2293#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002294 __wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
2295 keyidx, encr, 0);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002296#ifdef CONFIG_TESTING_OPTIONS
2297skip_tx:
2298#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002299
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002300 if (ctr == 1 && wpa_auth->conf.tx_status) {
2301 if (pairwise)
2302 timeout_ms = eapol_key_timeout_first;
2303 else if (wpa_auth_get_sta_count(wpa_auth) > 100)
2304 timeout_ms = eapol_key_timeout_first_group * 2;
2305 else
2306 timeout_ms = eapol_key_timeout_first_group;
2307 } else {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002308 timeout_ms = eapol_key_timeout_subseq;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002309 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002310 if (wpa_auth->conf.wpa_disable_eapol_key_retries &&
2311 (!pairwise || (key_info & WPA_KEY_INFO_MIC)))
2312 timeout_ms = eapol_key_timeout_no_retrans;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002313 if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
2314 sm->pending_1_of_4_timeout = 1;
Hai Shalom74f70d42019-02-11 14:42:39 -08002315#ifdef TEST_FUZZ
2316 timeout_ms = 1;
2317#endif /* TEST_FUZZ */
Kai Shie75b0652020-11-24 20:31:29 -08002318#ifdef CONFIG_TESTING_OPTIONS
2319 if(wpa_auth->conf.enable_eapol_large_timeout) {
2320 timeout_ms = 50 * 1000;
2321 }
2322#endif
Hai Shalomfdcde762020-04-02 11:19:20 -07002323 wpa_printf(MSG_DEBUG,
2324 "WPA: Use EAPOL-Key timeout of %u ms (retry counter %u)",
2325 timeout_ms, ctr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002326 eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
2327 wpa_send_eapol_timeout, wpa_auth, sm);
2328}
2329
2330
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002331static int wpa_verify_key_mic(int akmp, size_t pmk_len, struct wpa_ptk *PTK,
2332 u8 *data, size_t data_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002333{
2334 struct ieee802_1x_hdr *hdr;
2335 struct wpa_eapol_key *key;
2336 u16 key_info;
2337 int ret = 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002338 u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN], *mic_pos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002339 size_t mic_len = wpa_mic_len(akmp, pmk_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002340
2341 if (data_len < sizeof(*hdr) + sizeof(*key))
2342 return -1;
2343
2344 hdr = (struct ieee802_1x_hdr *) data;
2345 key = (struct wpa_eapol_key *) (hdr + 1);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002346 mic_pos = (u8 *) (key + 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002347 key_info = WPA_GET_BE16(key->key_info);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002348 os_memcpy(mic, mic_pos, mic_len);
2349 os_memset(mic_pos, 0, mic_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002350 if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
2351 key_info & WPA_KEY_INFO_TYPE_MASK,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002352 data, data_len, mic_pos) ||
2353 os_memcmp_const(mic, mic_pos, mic_len) != 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002354 ret = -1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002355 os_memcpy(mic_pos, mic, mic_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002356 return ret;
2357}
2358
2359
2360void wpa_remove_ptk(struct wpa_state_machine *sm)
2361{
Hai Shalome21d4e82020-04-29 16:34:06 -07002362 sm->PTK_valid = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002363 os_memset(&sm->PTK, 0, sizeof(sm->PTK));
Hai Shalom60840252021-02-19 19:02:11 -08002364
2365 wpa_auth_remove_ptksa(sm->wpa_auth, sm->addr, sm->pairwise);
2366
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002367 if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
Hai Shalomfdcde762020-04-02 11:19:20 -07002368 0, KEY_FLAG_PAIRWISE))
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002369 wpa_printf(MSG_DEBUG,
2370 "RSN: PTK removal from the driver failed");
Hai Shalomfdcde762020-04-02 11:19:20 -07002371 if (sm->use_ext_key_id &&
2372 wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL,
2373 0, KEY_FLAG_PAIRWISE))
2374 wpa_printf(MSG_DEBUG,
2375 "RSN: PTK Key ID 1 removal from the driver failed");
Hai Shalome21d4e82020-04-29 16:34:06 -07002376 sm->pairwise_set = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002377 eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
2378}
2379
2380
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002381int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002382{
2383 int remove_ptk = 1;
2384
Hai Shalomfdcde762020-04-02 11:19:20 -07002385 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002386 return -1;
2387
Sunil Raviaf8751c2023-03-29 11:35:17 -07002388 wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002389 "event %d notification", event);
2390
2391 switch (event) {
2392 case WPA_AUTH:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002393#ifdef CONFIG_MESH
2394 /* PTKs are derived through AMPE */
2395 if (wpa_auth_start_ampe(sm->wpa_auth, sm->addr)) {
2396 /* not mesh */
2397 break;
2398 }
2399 return 0;
2400#endif /* CONFIG_MESH */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002401 case WPA_ASSOC:
2402 break;
2403 case WPA_DEAUTH:
2404 case WPA_DISASSOC:
Hai Shalome21d4e82020-04-29 16:34:06 -07002405 sm->DeauthenticationRequest = true;
Hai Shalom1dc4d202019-04-29 16:22:27 -07002406 os_memset(sm->PMK, 0, sizeof(sm->PMK));
2407 sm->pmk_len = 0;
Sunil Ravia04bd252022-05-02 22:54:18 -07002408#ifdef CONFIG_IEEE80211R_AP
Hai Shalom1dc4d202019-04-29 16:22:27 -07002409 os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
2410 sm->xxkey_len = 0;
Hai Shalom81f62d82019-07-22 12:10:00 -07002411 os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
2412 sm->pmk_r1_len = 0;
Hai Shalom1dc4d202019-04-29 16:22:27 -07002413#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002414 break;
2415 case WPA_REAUTH:
2416 case WPA_REAUTH_EAPOL:
2417 if (!sm->started) {
2418 /*
2419 * When using WPS, we may end up here if the STA
2420 * manages to re-associate without the previous STA
2421 * entry getting removed. Consequently, we need to make
2422 * sure that the WPA state machines gets initialized
2423 * properly at this point.
2424 */
Hai Shalomfdcde762020-04-02 11:19:20 -07002425 wpa_printf(MSG_DEBUG,
2426 "WPA state machine had not been started - initialize now");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002427 sm->started = 1;
Hai Shalome21d4e82020-04-29 16:34:06 -07002428 sm->Init = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002429 if (wpa_sm_step(sm) == 1)
2430 return 1; /* should not really happen */
Hai Shalome21d4e82020-04-29 16:34:06 -07002431 sm->Init = false;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002432
2433 if (wpa_auth_4way_handshake_offload(sm->wpa_auth))
2434 wpa_printf(MSG_DEBUG,
2435 "Skip EAPOL for 4-way handshake offload case");
2436 else
2437 sm->AuthenticationRequest = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002438 break;
2439 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002440
Sunil Ravia04bd252022-05-02 22:54:18 -07002441 if (sm->ptkstart_without_success > 3) {
2442 wpa_printf(MSG_INFO,
2443 "WPA: Multiple EAP reauth attempts without 4-way handshake completion, disconnect "
2444 MACSTR, MAC2STR(sm->addr));
2445 sm->Disconnect = true;
2446 break;
2447 }
2448
Hai Shalomfdcde762020-04-02 11:19:20 -07002449 if (!sm->use_ext_key_id &&
2450 sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
2451 wpa_printf(MSG_INFO,
2452 "WPA: PTK0 rekey not allowed, disconnect "
Sunil Raviaf8751c2023-03-29 11:35:17 -07002453 MACSTR, MAC2STR(wpa_auth_get_spa(sm)));
Hai Shalome21d4e82020-04-29 16:34:06 -07002454 sm->Disconnect = true;
Hai Shalomfdcde762020-04-02 11:19:20 -07002455 /* Try to encourage the STA to reconnect */
2456 sm->disconnect_reason =
2457 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
2458 break;
2459 }
2460
2461 if (sm->use_ext_key_id)
2462 sm->keyidx_active ^= 1; /* flip Key ID */
2463
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002464 if (sm->GUpdateStationKeys) {
2465 /*
2466 * Reauthentication cancels the pending group key
2467 * update for this STA.
2468 */
Sunil Ravi7f769292024-07-23 22:21:32 +00002469 wpa_gkeydone_sta(sm);
Hai Shalome21d4e82020-04-29 16:34:06 -07002470 sm->PtkGroupInit = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002471 }
Hai Shalome21d4e82020-04-29 16:34:06 -07002472 sm->ReAuthenticationRequest = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002473 break;
2474 case WPA_ASSOC_FT:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002475#ifdef CONFIG_IEEE80211R_AP
Hai Shalomfdcde762020-04-02 11:19:20 -07002476 wpa_printf(MSG_DEBUG,
2477 "FT: Retry PTK configuration after association");
Hai Shalomb755a2a2020-04-23 21:49:02 -07002478 wpa_ft_install_ptk(sm, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002479
2480 /* Using FT protocol, not WPA auth state machine */
2481 sm->ft_completed = 1;
Hai Shalom81f62d82019-07-22 12:10:00 -07002482 wpa_auth_set_ptk_rekey_timer(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002483 return 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002484#else /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002485 break;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002486#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002487 case WPA_ASSOC_FILS:
2488#ifdef CONFIG_FILS
2489 wpa_printf(MSG_DEBUG,
2490 "FILS: TK configuration after association");
2491 fils_set_tk(sm);
2492 sm->fils_completed = 1;
2493 return 0;
2494#else /* CONFIG_FILS */
2495 break;
2496#endif /* CONFIG_FILS */
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02002497 case WPA_DRV_STA_REMOVED:
Hai Shalome21d4e82020-04-29 16:34:06 -07002498 sm->tk_already_set = false;
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02002499 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002500 }
2501
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002502#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002503 sm->ft_completed = 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002504#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002505
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002506 if (sm->mgmt_frame_prot && event == WPA_AUTH)
2507 remove_ptk = 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002508#ifdef CONFIG_FILS
2509 if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
2510 (event == WPA_AUTH || event == WPA_ASSOC))
2511 remove_ptk = 0;
2512#endif /* CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002513
2514 if (remove_ptk) {
Hai Shalome21d4e82020-04-29 16:34:06 -07002515 sm->PTK_valid = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002516 os_memset(&sm->PTK, 0, sizeof(sm->PTK));
2517
2518 if (event != WPA_REAUTH_EAPOL)
2519 wpa_remove_ptk(sm);
2520 }
2521
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002522 if (sm->in_step_loop) {
2523 /*
2524 * wpa_sm_step() is already running - avoid recursive call to
2525 * it by making the existing loop process the new update.
2526 */
Hai Shalome21d4e82020-04-29 16:34:06 -07002527 sm->changed = true;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002528 return 0;
2529 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002530 return wpa_sm_step(sm);
2531}
2532
2533
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002534SM_STATE(WPA_PTK, INITIALIZE)
2535{
2536 SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
2537 if (sm->Init) {
2538 /* Init flag is not cleared here, so avoid busy
2539 * loop by claiming nothing changed. */
Hai Shalome21d4e82020-04-29 16:34:06 -07002540 sm->changed = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002541 }
2542
2543 sm->keycount = 0;
2544 if (sm->GUpdateStationKeys)
Sunil Ravi7f769292024-07-23 22:21:32 +00002545 wpa_gkeydone_sta(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002546 if (sm->wpa == WPA_VERSION_WPA)
Hai Shalome21d4e82020-04-29 16:34:06 -07002547 sm->PInitAKeys = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002548 if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
2549 * Local AA > Remote AA)) */) {
Hai Shalome21d4e82020-04-29 16:34:06 -07002550 sm->Pair = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002551 }
2552 wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
2553 wpa_remove_ptk(sm);
2554 wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
2555 sm->TimeoutCtr = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002556 if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
2557 sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
2558 sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002559 wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
2560 WPA_EAPOL_authorized, 0);
2561 }
2562}
2563
2564
2565SM_STATE(WPA_PTK, DISCONNECT)
2566{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002567 u16 reason = sm->disconnect_reason;
2568
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002569 SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
Hai Shalome21d4e82020-04-29 16:34:06 -07002570 sm->Disconnect = false;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002571 sm->disconnect_reason = 0;
2572 if (!reason)
2573 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
2574 wpa_sta_disconnect(sm->wpa_auth, sm->addr, reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002575}
2576
2577
2578SM_STATE(WPA_PTK, DISCONNECTED)
2579{
2580 SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
Hai Shalome21d4e82020-04-29 16:34:06 -07002581 sm->DeauthenticationRequest = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002582}
2583
2584
2585SM_STATE(WPA_PTK, AUTHENTICATION)
2586{
2587 SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
2588 os_memset(&sm->PTK, 0, sizeof(sm->PTK));
Hai Shalome21d4e82020-04-29 16:34:06 -07002589 sm->PTK_valid = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002590 wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
2591 1);
2592 wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
Hai Shalome21d4e82020-04-29 16:34:06 -07002593 sm->AuthenticationRequest = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002594}
2595
2596
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002597static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
2598 struct wpa_group *group)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002599{
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002600 if (group->first_sta_seen)
2601 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002602 /*
2603 * System has run bit further than at the time hostapd was started
2604 * potentially very early during boot up. This provides better chances
2605 * of collecting more randomness on embedded systems. Re-initialize the
2606 * GMK and Counter here to improve their strength if there was not
2607 * enough entropy available immediately after system startup.
2608 */
Hai Shalomfdcde762020-04-02 11:19:20 -07002609 wpa_printf(MSG_DEBUG,
2610 "WPA: Re-initialize GMK/Counter on first station");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002611 if (random_pool_ready() != 1) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002612 wpa_printf(MSG_INFO,
2613 "WPA: Not enough entropy in random pool to proceed - reject first 4-way handshake");
Hai Shalome21d4e82020-04-29 16:34:06 -07002614 group->reject_4way_hs_for_entropy = true;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002615 } else {
Hai Shalome21d4e82020-04-29 16:34:06 -07002616 group->first_sta_seen = true;
2617 group->reject_4way_hs_for_entropy = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002618 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002619
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002620 if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 ||
2621 wpa_gtk_update(wpa_auth, group) < 0 ||
2622 wpa_group_config_group_keys(wpa_auth, group) < 0) {
2623 wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed");
Hai Shalome21d4e82020-04-29 16:34:06 -07002624 group->first_sta_seen = false;
2625 group->reject_4way_hs_for_entropy = true;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002626 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002627}
2628
2629
2630SM_STATE(WPA_PTK, AUTHENTICATION2)
2631{
2632 SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
2633
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002634 wpa_group_ensure_init(sm->wpa_auth, sm->group);
Hai Shalome21d4e82020-04-29 16:34:06 -07002635 sm->ReAuthenticationRequest = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002636
Dmitry Shmidt04949592012-07-19 12:16:46 -07002637 /*
2638 * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
2639 * ambiguous. The Authenticator state machine uses a counter that is
2640 * incremented by one for each 4-way handshake. However, the security
2641 * analysis of 4-way handshake points out that unpredictable nonces
2642 * help in preventing precomputation attacks. Instead of the state
2643 * machine definition, use an unpredictable nonce value here to provide
2644 * stronger protection against potential precomputation attacks.
2645 */
2646 if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002647 wpa_printf(MSG_ERROR,
2648 "WPA: Failed to get random data for ANonce.");
Hai Shalome21d4e82020-04-29 16:34:06 -07002649 sm->Disconnect = true;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002650 return;
2651 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002652 wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
2653 WPA_NONCE_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002654 /* IEEE 802.11i does not clear TimeoutCtr here, but this is more
2655 * logical place than INITIALIZE since AUTHENTICATION2 can be
2656 * re-entered on ReAuthenticationRequest without going through
2657 * INITIALIZE. */
2658 sm->TimeoutCtr = 0;
2659}
2660
2661
Jouni Malinen1420a892017-10-01 12:32:57 +03002662static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
2663{
2664 if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
2665 wpa_printf(MSG_ERROR,
2666 "WPA: Failed to get random data for ANonce");
Hai Shalome21d4e82020-04-29 16:34:06 -07002667 sm->Disconnect = true;
Jouni Malinen1420a892017-10-01 12:32:57 +03002668 return -1;
2669 }
2670 wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
2671 WPA_NONCE_LEN);
2672 sm->TimeoutCtr = 0;
2673 return 0;
2674}
2675
2676
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002677SM_STATE(WPA_PTK, INITPMK)
2678{
2679 u8 msk[2 * PMK_LEN];
2680 size_t len = 2 * PMK_LEN;
2681
2682 SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002683#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002684 sm->xxkey_len = 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002685#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002686 if (sm->pmksa) {
2687 wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002688 os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
2689 sm->pmk_len = sm->pmksa->pmk_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002690#ifdef CONFIG_DPP
2691 } else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
2692 wpa_printf(MSG_DEBUG,
2693 "DPP: No PMKSA cache entry for STA - reject connection");
Hai Shalome21d4e82020-04-29 16:34:06 -07002694 sm->Disconnect = true;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002695 sm->disconnect_reason = WLAN_REASON_INVALID_PMKID;
2696 return;
2697#endif /* CONFIG_DPP */
Sunil Raviaf8751c2023-03-29 11:35:17 -07002698 } else if (wpa_auth_get_msk(sm->wpa_auth, wpa_auth_get_spa(sm),
2699 msk, &len) == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002700 unsigned int pmk_len;
2701
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002702 if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt))
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002703 pmk_len = PMK_LEN_SUITE_B_192;
2704 else
2705 pmk_len = PMK_LEN;
Hai Shalomfdcde762020-04-02 11:19:20 -07002706 wpa_printf(MSG_DEBUG,
2707 "WPA: PMK from EAPOL state machine (MSK len=%zu PMK len=%u)",
2708 len, pmk_len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002709 if (len < pmk_len) {
2710 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07002711 "WPA: MSK not long enough (%zu) to create PMK (%u)",
2712 len, pmk_len);
Hai Shalome21d4e82020-04-29 16:34:06 -07002713 sm->Disconnect = true;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002714 return;
2715 }
2716 os_memcpy(sm->PMK, msk, pmk_len);
2717 sm->pmk_len = pmk_len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002718#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002719 if (len >= 2 * PMK_LEN) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002720 if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
2721 os_memcpy(sm->xxkey, msk, SHA384_MAC_LEN);
2722 sm->xxkey_len = SHA384_MAC_LEN;
2723 } else {
2724 os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
2725 sm->xxkey_len = PMK_LEN;
2726 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002727 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002728#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002729 } else {
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002730 wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
Paul Stewart092955c2017-02-06 09:13:09 -08002731 sm->wpa_auth->cb->get_msk);
Hai Shalome21d4e82020-04-29 16:34:06 -07002732 sm->Disconnect = true;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002733 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002734 }
Hai Shalom81f62d82019-07-22 12:10:00 -07002735 forced_memzero(msk, sizeof(msk));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002736
2737 sm->req_replay_counter_used = 0;
Hai Shalome21d4e82020-04-29 16:34:06 -07002738 /* IEEE 802.11i does not set keyRun to false, but not doing this
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002739 * will break reauthentication since EAPOL state machines may not be
2740 * get into AUTHENTICATING state that clears keyRun before WPA state
2741 * machine enters AUTHENTICATION2 state and goes immediately to INITPMK
2742 * state and takes PMK from the previously used AAA Key. This will
2743 * eventually fail in 4-Way Handshake because Supplicant uses PMK
Hai Shalome21d4e82020-04-29 16:34:06 -07002744 * derived from the new AAA Key. Setting keyRun = false here seems to
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002745 * be good workaround for this issue. */
Hai Shalome21d4e82020-04-29 16:34:06 -07002746 wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002747}
2748
2749
2750SM_STATE(WPA_PTK, INITPSK)
2751{
2752 const u8 *psk;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002753 size_t psk_len;
2754
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002755 SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002756 psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
Hai Shalom021b0b52019-04-10 11:17:58 -07002757 &psk_len, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002758 if (psk) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002759 os_memcpy(sm->PMK, psk, psk_len);
2760 sm->pmk_len = psk_len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002761#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002762 sm->xxkey_len = PMK_LEN;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002763#ifdef CONFIG_SAE
2764 if (sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
2765 (psk_len == SHA512_MAC_LEN || psk_len == SHA384_MAC_LEN ||
2766 psk_len == SHA256_MAC_LEN))
2767 sm->xxkey_len = psk_len;
2768#endif /* CONFIG_SAE */
2769 os_memcpy(sm->xxkey, psk, sm->xxkey_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002770#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002771 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002772#ifdef CONFIG_SAE
2773 if (wpa_auth_uses_sae(sm) && sm->pmksa) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002774 wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache (len=%zu)",
2775 sm->pmksa->pmk_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002776 os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
2777 sm->pmk_len = sm->pmksa->pmk_len;
Hai Shalom021b0b52019-04-10 11:17:58 -07002778#ifdef CONFIG_IEEE80211R_AP
2779 os_memcpy(sm->xxkey, sm->pmksa->pmk, sm->pmksa->pmk_len);
2780 sm->xxkey_len = sm->pmksa->pmk_len;
2781#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002782 }
2783#endif /* CONFIG_SAE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002784 sm->req_replay_counter_used = 0;
2785}
2786
2787
2788SM_STATE(WPA_PTK, PTKSTART)
2789{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002790 u8 *buf;
2791 size_t buf_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002792 u8 *pmkid = NULL;
2793 size_t kde_len = 0;
Sunil8cd6f4d2022-06-28 18:40:46 +00002794 u16 key_info;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002795#ifdef CONFIG_TESTING_OPTIONS
2796 struct wpa_auth_config *conf = &sm->wpa_auth->conf;
2797#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002798
2799 SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
Hai Shalome21d4e82020-04-29 16:34:06 -07002800 sm->PTKRequest = false;
2801 sm->TimeoutEvt = false;
2802 sm->alt_snonce_valid = false;
Sunil Ravia04bd252022-05-02 22:54:18 -07002803 sm->ptkstart_without_success++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002804
2805 sm->TimeoutCtr++;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002806 if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002807 /* No point in sending the EAPOL-Key - we will disconnect
2808 * immediately following this. */
2809 return;
2810 }
2811
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002812#ifdef CONFIG_IEEE80211BE
2813 if (sm->mld_assoc_link_id >= 0)
2814 buf_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
2815#endif /* CONFIG_IEEE80211BE */
2816#ifdef CONFIG_TESTING_OPTIONS
2817 if (conf->eapol_m1_elements)
2818 buf_len += wpabuf_len(conf->eapol_m1_elements);
2819#endif /* CONFIG_TESTING_OPTIONS */
2820
2821 buf = os_zalloc(buf_len);
2822 if (!buf)
2823 return;
2824
Sunil Raviaf8751c2023-03-29 11:35:17 -07002825 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002826 "sending 1/4 msg of 4-Way Handshake");
2827 /*
Hai Shalomce48b4a2018-09-05 11:41:35 -07002828 * For infrastructure BSS cases, it is better for the AP not to include
2829 * the PMKID KDE in EAPOL-Key msg 1/4 since it could be used to initiate
2830 * offline search for the passphrase/PSK without having to be able to
2831 * capture a 4-way handshake from a STA that has access to the network.
2832 *
2833 * For IBSS cases, addition of PMKID KDE could be considered even with
2834 * WPA2-PSK cases that use multiple PSKs, but only if there is a single
2835 * possible PSK for this STA. However, this should not be done unless
2836 * there is support for using that information on the supplicant side.
2837 * The concern about exposing PMKID unnecessarily in infrastructure BSS
2838 * cases would also apply here, but at least in the IBSS case, this
2839 * would cover a potential real use case.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002840 */
2841 if (sm->wpa == WPA_VERSION_WPA2 &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002842 (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) ||
2843 (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && sm->pmksa) ||
Sunil Ravi876a49b2025-02-03 19:18:32 +00002844 wpa_key_mgmt_sae(sm->wpa_key_mgmt))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002845 pmkid = buf;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002846 kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002847 pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
2848 pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
2849 RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002850 if (sm->pmksa) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002851 wpa_hexdump(MSG_DEBUG,
2852 "RSN: Message 1/4 PMKID from PMKSA entry",
2853 sm->pmksa->pmkid, PMKID_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002854 os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
2855 sm->pmksa->pmkid, PMKID_LEN);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002856 } else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
2857 /* No KCK available to derive PMKID */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002858 wpa_printf(MSG_DEBUG,
2859 "RSN: No KCK available to derive PMKID for message 1/4");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002860 pmkid = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07002861#ifdef CONFIG_FILS
2862 } else if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
2863 if (sm->pmkid_set) {
2864 wpa_hexdump(MSG_DEBUG,
2865 "RSN: Message 1/4 PMKID from FILS/ERP",
2866 sm->pmkid, PMKID_LEN);
2867 os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
2868 sm->pmkid, PMKID_LEN);
2869 } else {
2870 /* No PMKID available */
2871 wpa_printf(MSG_DEBUG,
2872 "RSN: No FILS/ERP PMKID available for message 1/4");
2873 pmkid = NULL;
2874 }
2875#endif /* CONFIG_FILS */
2876#ifdef CONFIG_IEEE80211R_AP
2877 } else if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
2878 sm->ft_completed) {
2879 wpa_printf(MSG_DEBUG,
2880 "FT: No PMKID in message 1/4 when using FT protocol");
2881 pmkid = NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07002882#endif /* CONFIG_IEEE80211R_AP */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002883#ifdef CONFIG_SAE
2884 } else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
2885 if (sm->pmkid_set) {
2886 wpa_hexdump(MSG_DEBUG,
2887 "RSN: Message 1/4 PMKID from SAE",
2888 sm->pmkid, PMKID_LEN);
2889 os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
2890 sm->pmkid, PMKID_LEN);
2891 } else {
2892 /* No PMKID available */
2893 wpa_printf(MSG_DEBUG,
2894 "RSN: No SAE PMKID available for message 1/4");
2895 pmkid = NULL;
2896 }
2897#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002898 } else {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002899 /*
2900 * Calculate PMKID since no PMKSA cache entry was
2901 * available with pre-calculated PMKID.
2902 */
Sunil Raviaf8751c2023-03-29 11:35:17 -07002903 rsn_pmkid(sm->PMK, sm->pmk_len,
2904 wpa_auth_get_aa(sm),
2905 wpa_auth_get_spa(sm),
2906 &pmkid[2 + RSN_SELECTOR_LEN],
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002907 sm->wpa_key_mgmt);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002908 wpa_hexdump(MSG_DEBUG,
2909 "RSN: Message 1/4 PMKID derived from PMK",
2910 &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002911 }
2912 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002913 if (!pmkid)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002914 kde_len = 0;
2915
2916#ifdef CONFIG_IEEE80211BE
2917 if (sm->mld_assoc_link_id >= 0) {
2918 wpa_printf(MSG_DEBUG,
2919 "RSN: MLD: Add MAC Address KDE: kde_len=%zu",
2920 kde_len);
2921 wpa_add_kde(buf + kde_len, RSN_KEY_DATA_MAC_ADDR,
Sunil Ravi7f769292024-07-23 22:21:32 +00002922 sm->wpa_auth->mld_addr, ETH_ALEN, NULL, 0);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002923 kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
2924 }
2925#endif /* CONFIG_IEEE80211BE */
2926
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002927#ifdef CONFIG_TESTING_OPTIONS
2928 if (conf->eapol_m1_elements) {
2929 os_memcpy(buf + kde_len, wpabuf_head(conf->eapol_m1_elements),
2930 wpabuf_len(conf->eapol_m1_elements));
2931 kde_len += wpabuf_len(conf->eapol_m1_elements);
2932 }
2933#endif /* CONFIG_TESTING_OPTIONS */
2934
Sunil8cd6f4d2022-06-28 18:40:46 +00002935 key_info = WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE;
2936 if (sm->pairwise_set && sm->wpa != WPA_VERSION_WPA)
2937 key_info |= WPA_KEY_INFO_SECURE;
2938 wpa_send_eapol(sm->wpa_auth, sm, key_info, NULL,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002939 sm->ANonce, kde_len ? buf : NULL, kde_len, 0, 0);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002940 os_free(buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002941}
2942
2943
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002944static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002945 const u8 *pmk, unsigned int pmk_len,
Sunil Raviaf8751c2023-03-29 11:35:17 -07002946 struct wpa_ptk *ptk, int force_sha256,
2947 u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
Sunil Ravi7f769292024-07-23 22:21:32 +00002948 size_t *key_len, bool no_kdk)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002949{
Hai Shalom021b0b52019-04-10 11:17:58 -07002950 const u8 *z = NULL;
Hai Shalom60840252021-02-19 19:02:11 -08002951 size_t z_len = 0, kdk_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07002952 int akmp;
Sunil Ravi89eba102022-09-13 21:04:37 -07002953 int ret;
Hai Shalom021b0b52019-04-10 11:17:58 -07002954
Hai Shalom60840252021-02-19 19:02:11 -08002955 if (sm->wpa_auth->conf.force_kdk_derivation ||
Sunil Ravi7f769292024-07-23 22:21:32 +00002956 (!no_kdk && sm->wpa_auth->conf.secure_ltf &&
Hai Shaloma20dcd72022-02-04 13:43:00 -08002957 ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
Hai Shalom60840252021-02-19 19:02:11 -08002958 kdk_len = WPA_KDK_MAX_LEN;
2959 else
2960 kdk_len = 0;
2961
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002962#ifdef CONFIG_IEEE80211R_AP
Hai Shalom81f62d82019-07-22 12:10:00 -07002963 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
2964 if (sm->ft_completed) {
2965 u8 ptk_name[WPA_PMK_NAME_LEN];
2966
Sunil Ravi89eba102022-09-13 21:04:37 -07002967 ret = wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
2968 sm->SNonce, sm->ANonce,
Sunil Raviaf8751c2023-03-29 11:35:17 -07002969 wpa_auth_get_spa(sm),
2970 wpa_auth_get_aa(sm),
Sunil Ravi89eba102022-09-13 21:04:37 -07002971 sm->pmk_r1_name, ptk,
2972 ptk_name, sm->wpa_key_mgmt,
2973 sm->pairwise, kdk_len);
2974 } else {
Sunil Raviaf8751c2023-03-29 11:35:17 -07002975 ret = wpa_auth_derive_ptk_ft(sm, ptk, pmk_r0, pmk_r1,
2976 pmk_r0_name, key_len,
2977 kdk_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07002978 }
Sunil Ravi89eba102022-09-13 21:04:37 -07002979 if (ret) {
2980 wpa_printf(MSG_ERROR, "FT: PTK derivation failed");
2981 return ret;
2982 }
2983
2984#ifdef CONFIG_PASN
Sunil Ravi7f769292024-07-23 22:21:32 +00002985 if (!no_kdk && sm->wpa_auth->conf.secure_ltf &&
Sunil Ravi89eba102022-09-13 21:04:37 -07002986 ieee802_11_rsnx_capab(sm->rsnxe,
2987 WLAN_RSNX_CAPAB_SECURE_LTF)) {
2988 ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt,
2989 sm->pairwise);
2990 if (ret) {
2991 wpa_printf(MSG_ERROR,
2992 "FT: LTF keyseed derivation failed");
2993 }
2994 }
2995#endif /* CONFIG_PASN */
2996 return ret;
Hai Shalom81f62d82019-07-22 12:10:00 -07002997 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002998#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002999
Hai Shalom021b0b52019-04-10 11:17:58 -07003000#ifdef CONFIG_DPP2
3001 if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
3002 z = wpabuf_head(sm->dpp_z);
3003 z_len = wpabuf_len(sm->dpp_z);
3004 }
3005#endif /* CONFIG_DPP2 */
3006
Hai Shalomfdcde762020-04-02 11:19:20 -07003007 akmp = sm->wpa_key_mgmt;
3008 if (force_sha256)
3009 akmp |= WPA_KEY_MGMT_PSK_SHA256;
Sunil Ravi89eba102022-09-13 21:04:37 -07003010 ret = wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
Sunil Raviaf8751c2023-03-29 11:35:17 -07003011 wpa_auth_get_aa(sm), wpa_auth_get_spa(sm),
3012 sm->ANonce, snonce, ptk, akmp,
3013 sm->pairwise, z, z_len, kdk_len);
Sunil Ravi89eba102022-09-13 21:04:37 -07003014 if (ret) {
3015 wpa_printf(MSG_DEBUG,
3016 "WPA: PTK derivation failed");
3017 return ret;
3018 }
3019
3020#ifdef CONFIG_PASN
Sunil Ravi7f769292024-07-23 22:21:32 +00003021 if (!no_kdk && sm->wpa_auth->conf.secure_ltf &&
Sunil Ravi89eba102022-09-13 21:04:37 -07003022 ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) {
3023 ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt, sm->pairwise);
3024 if (ret) {
3025 wpa_printf(MSG_DEBUG,
3026 "WPA: LTF keyseed derivation failed");
3027 }
3028 }
3029#endif /* CONFIG_PASN */
3030 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003031}
3032
3033
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003034#ifdef CONFIG_FILS
3035
3036int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003037 size_t pmk_len, const u8 *snonce, const u8 *anonce,
3038 const u8 *dhss, size_t dhss_len,
3039 struct wpabuf *g_sta, struct wpabuf *g_ap)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003040{
3041 u8 ick[FILS_ICK_MAX_LEN];
3042 size_t ick_len;
3043 int res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003044 u8 fils_ft[FILS_FT_MAX_LEN];
Hai Shalom60840252021-02-19 19:02:11 -08003045 size_t fils_ft_len = 0, kdk_len;
3046
3047 if (sm->wpa_auth->conf.force_kdk_derivation ||
3048 (sm->wpa_auth->conf.secure_ltf &&
Hai Shaloma20dcd72022-02-04 13:43:00 -08003049 ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
Hai Shalom60840252021-02-19 19:02:11 -08003050 kdk_len = WPA_KDK_MAX_LEN;
3051 else
3052 kdk_len = 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003053
Sunil Raviaf8751c2023-03-29 11:35:17 -07003054 res = fils_pmk_to_ptk(pmk, pmk_len, wpa_auth_get_spa(sm),
3055 wpa_auth_get_aa(sm),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003056 snonce, anonce, dhss, dhss_len,
3057 &sm->PTK, ick, &ick_len,
3058 sm->wpa_key_mgmt, sm->pairwise,
Hai Shalom60840252021-02-19 19:02:11 -08003059 fils_ft, &fils_ft_len, kdk_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003060 if (res < 0)
3061 return res;
Sunil Ravi89eba102022-09-13 21:04:37 -07003062
3063#ifdef CONFIG_PASN
3064 if (sm->wpa_auth->conf.secure_ltf &&
3065 ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) {
3066 res = wpa_ltf_keyseed(&sm->PTK, sm->wpa_key_mgmt, sm->pairwise);
3067 if (res) {
3068 wpa_printf(MSG_ERROR,
3069 "FILS: LTF keyseed derivation failed");
3070 return res;
3071 }
3072 }
3073#endif /* CONFIG_PASN */
3074
Hai Shalome21d4e82020-04-29 16:34:06 -07003075 sm->PTK_valid = true;
3076 sm->tk_already_set = false;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003077
3078#ifdef CONFIG_IEEE80211R_AP
3079 if (fils_ft_len) {
3080 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
3081 struct wpa_auth_config *conf = &wpa_auth->conf;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003082 u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003083
3084 if (wpa_derive_pmk_r0(fils_ft, fils_ft_len,
3085 conf->ssid, conf->ssid_len,
3086 conf->mobility_domain,
3087 conf->r0_key_holder,
3088 conf->r0_key_holder_len,
Sunil Raviaf8751c2023-03-29 11:35:17 -07003089 wpa_auth_get_spa(sm), pmk_r0, pmk_r0_name,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00003090 sm->wpa_key_mgmt) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003091 return -1;
3092
Roshan Pius3a1667e2018-07-03 15:17:14 -07003093 wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
Hai Shalom81f62d82019-07-22 12:10:00 -07003094 forced_memzero(fils_ft, sizeof(fils_ft));
Hai Shalom021b0b52019-04-10 11:17:58 -07003095
3096 res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
Sunil Raviaf8751c2023-03-29 11:35:17 -07003097 wpa_auth_get_spa(sm),
3098 sm->pmk_r1_name,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00003099 fils_ft_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003100 forced_memzero(pmk_r0, PMK_LEN_MAX);
Hai Shalom021b0b52019-04-10 11:17:58 -07003101 if (res < 0)
3102 return -1;
3103 wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
3104 WPA_PMK_NAME_LEN);
3105 sm->pmk_r1_name_valid = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003106 }
3107#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003108
3109 res = fils_key_auth_sk(ick, ick_len, snonce, anonce,
Sunil Raviaf8751c2023-03-29 11:35:17 -07003110 wpa_auth_get_spa(sm),
3111 wpa_auth_get_aa(sm),
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003112 g_sta ? wpabuf_head(g_sta) : NULL,
3113 g_sta ? wpabuf_len(g_sta) : 0,
3114 g_ap ? wpabuf_head(g_ap) : NULL,
3115 g_ap ? wpabuf_len(g_ap) : 0,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003116 sm->wpa_key_mgmt, sm->fils_key_auth_sta,
3117 sm->fils_key_auth_ap,
3118 &sm->fils_key_auth_len);
Hai Shalom81f62d82019-07-22 12:10:00 -07003119 forced_memzero(ick, sizeof(ick));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003120
3121 /* Store nonces for (Re)Association Request/Response frame processing */
3122 os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
3123 os_memcpy(sm->ANonce, anonce, FILS_NONCE_LEN);
3124
3125 return res;
3126}
3127
3128
3129static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
3130 u8 *buf, size_t buf_len, u16 *_key_data_len)
3131{
3132 struct ieee802_1x_hdr *hdr;
3133 struct wpa_eapol_key *key;
3134 u8 *pos;
3135 u16 key_data_len;
3136 u8 *tmp;
3137 const u8 *aad[1];
3138 size_t aad_len[1];
3139
3140 hdr = (struct ieee802_1x_hdr *) buf;
3141 key = (struct wpa_eapol_key *) (hdr + 1);
3142 pos = (u8 *) (key + 1);
3143 key_data_len = WPA_GET_BE16(pos);
3144 if (key_data_len < AES_BLOCK_SIZE ||
3145 key_data_len > buf_len - sizeof(*hdr) - sizeof(*key) - 2) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07003146 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003147 "No room for AES-SIV data in the frame");
3148 return -1;
3149 }
3150 pos += 2; /* Pointing at the Encrypted Key Data field */
3151
3152 tmp = os_malloc(key_data_len);
3153 if (!tmp)
3154 return -1;
3155
3156 /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
3157 * to Key Data (exclusive). */
3158 aad[0] = buf;
3159 aad_len[0] = pos - buf;
3160 if (aes_siv_decrypt(ptk->kek, ptk->kek_len, pos, key_data_len,
3161 1, aad, aad_len, tmp) < 0) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07003162 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003163 "Invalid AES-SIV data in the frame");
3164 bin_clear_free(tmp, key_data_len);
3165 return -1;
3166 }
3167
3168 /* AEAD decryption and validation completed successfully */
3169 key_data_len -= AES_BLOCK_SIZE;
3170 wpa_hexdump_key(MSG_DEBUG, "WPA: Decrypted Key Data",
3171 tmp, key_data_len);
3172
3173 /* Replace Key Data field with the decrypted version */
3174 os_memcpy(pos, tmp, key_data_len);
3175 pos -= 2; /* Key Data Length field */
3176 WPA_PUT_BE16(pos, key_data_len);
3177 bin_clear_free(tmp, key_data_len);
3178 if (_key_data_len)
3179 *_key_data_len = key_data_len;
3180 return 0;
3181}
3182
3183
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003184const u8 * wpa_fils_validate_fils_session(struct wpa_state_machine *sm,
3185 const u8 *ies, size_t ies_len,
3186 const u8 *fils_session)
3187{
3188 const u8 *ie, *end;
3189 const u8 *session = NULL;
3190
3191 if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
3192 wpa_printf(MSG_DEBUG,
3193 "FILS: Not a FILS AKM - reject association");
3194 return NULL;
3195 }
3196
3197 /* Verify Session element */
3198 ie = ies;
3199 end = ((const u8 *) ie) + ies_len;
3200 while (ie + 1 < end) {
3201 if (ie + 2 + ie[1] > end)
3202 break;
3203 if (ie[0] == WLAN_EID_EXTENSION &&
3204 ie[1] >= 1 + FILS_SESSION_LEN &&
3205 ie[2] == WLAN_EID_EXT_FILS_SESSION) {
3206 session = ie;
3207 break;
3208 }
3209 ie += 2 + ie[1];
3210 }
3211
3212 if (!session) {
3213 wpa_printf(MSG_DEBUG,
3214 "FILS: %s: Could not find FILS Session element in Assoc Req - reject",
3215 __func__);
3216 return NULL;
3217 }
3218
3219 if (!fils_session) {
3220 wpa_printf(MSG_DEBUG,
3221 "FILS: %s: Could not find FILS Session element in STA entry - reject",
3222 __func__);
3223 return NULL;
3224 }
3225
3226 if (os_memcmp(fils_session, session + 3, FILS_SESSION_LEN) != 0) {
3227 wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
3228 wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
3229 fils_session, FILS_SESSION_LEN);
3230 wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
3231 session + 3, FILS_SESSION_LEN);
3232 return NULL;
3233 }
3234 return session;
3235}
3236
3237
3238int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
3239 size_t ies_len)
3240{
3241 struct ieee802_11_elems elems;
3242
3243 if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
3244 wpa_printf(MSG_DEBUG,
3245 "FILS: Failed to parse decrypted elements");
3246 return -1;
3247 }
3248
3249 if (!elems.fils_session) {
3250 wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
3251 return -1;
3252 }
3253
3254 if (!elems.fils_key_confirm) {
3255 wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
3256 return -1;
3257 }
3258
3259 if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
3260 wpa_printf(MSG_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07003261 "FILS: Unexpected Key-Auth length %d (expected %zu)",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003262 elems.fils_key_confirm_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07003263 sm->fils_key_auth_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003264 return -1;
3265 }
3266
3267 if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_sta,
3268 sm->fils_key_auth_len) != 0) {
3269 wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
3270 wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
3271 elems.fils_key_confirm, elems.fils_key_confirm_len);
3272 wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
3273 sm->fils_key_auth_sta, sm->fils_key_auth_len);
3274 return -1;
3275 }
3276
3277 return 0;
3278}
3279
3280
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003281int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
3282 const struct ieee80211_mgmt *mgmt, size_t frame_len,
3283 u8 *pos, size_t left)
3284{
3285 u16 fc, stype;
3286 const u8 *end, *ie_start, *ie, *session, *crypt;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003287 const u8 *aad[5];
3288 size_t aad_len[5];
3289
3290 if (!sm || !sm->PTK_valid) {
3291 wpa_printf(MSG_DEBUG,
3292 "FILS: No KEK to decrypt Assocication Request frame");
3293 return -1;
3294 }
3295
3296 if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
3297 wpa_printf(MSG_DEBUG,
3298 "FILS: Not a FILS AKM - reject association");
3299 return -1;
3300 }
3301
3302 end = ((const u8 *) mgmt) + frame_len;
3303 fc = le_to_host16(mgmt->frame_control);
3304 stype = WLAN_FC_GET_STYPE(fc);
3305 if (stype == WLAN_FC_STYPE_REASSOC_REQ)
3306 ie_start = mgmt->u.reassoc_req.variable;
3307 else
3308 ie_start = mgmt->u.assoc_req.variable;
3309 ie = ie_start;
3310
3311 /*
3312 * Find FILS Session element which is the last unencrypted element in
3313 * the frame.
3314 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003315 session = wpa_fils_validate_fils_session(sm, ie, end - ie,
3316 fils_session);
3317 if (!session) {
3318 wpa_printf(MSG_DEBUG, "FILS: Session validation failed");
3319 return -1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003320 }
3321
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003322 crypt = session + 2 + session[1];
3323
3324 if (end - crypt < AES_BLOCK_SIZE) {
3325 wpa_printf(MSG_DEBUG,
3326 "FILS: Too short frame to include AES-SIV data");
3327 return -1;
3328 }
3329
3330 /* AES-SIV AAD vectors */
3331
3332 /* The STA's MAC address */
3333 aad[0] = mgmt->sa;
3334 aad_len[0] = ETH_ALEN;
3335 /* The AP's BSSID */
3336 aad[1] = mgmt->da;
3337 aad_len[1] = ETH_ALEN;
3338 /* The STA's nonce */
3339 aad[2] = sm->SNonce;
3340 aad_len[2] = FILS_NONCE_LEN;
3341 /* The AP's nonce */
3342 aad[3] = sm->ANonce;
3343 aad_len[3] = FILS_NONCE_LEN;
3344 /*
3345 * The (Re)Association Request frame from the Capability Information
3346 * field to the FILS Session element (both inclusive).
3347 */
3348 aad[4] = (const u8 *) &mgmt->u.assoc_req.capab_info;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003349 aad_len[4] = crypt - aad[4];
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003350
3351 if (aes_siv_decrypt(sm->PTK.kek, sm->PTK.kek_len, crypt, end - crypt,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003352 5, aad, aad_len, pos + (crypt - ie_start)) < 0) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003353 wpa_printf(MSG_DEBUG,
3354 "FILS: Invalid AES-SIV data in the frame");
3355 return -1;
3356 }
3357 wpa_hexdump(MSG_DEBUG, "FILS: Decrypted Association Request elements",
3358 pos, left - AES_BLOCK_SIZE);
3359
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003360 if (wpa_fils_validate_key_confirm(sm, pos, left - AES_BLOCK_SIZE) < 0) {
3361 wpa_printf(MSG_DEBUG, "FILS: Key Confirm validation failed");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003362 return -1;
3363 }
3364
3365 return left - AES_BLOCK_SIZE;
3366}
3367
3368
3369int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003370 size_t current_len, size_t max_len,
3371 const struct wpabuf *hlp)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003372{
3373 u8 *end = buf + max_len;
3374 u8 *pos = buf + current_len;
3375 struct ieee80211_mgmt *mgmt;
3376 struct wpabuf *plain;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003377 const u8 *aad[5];
3378 size_t aad_len[5];
3379
3380 if (!sm || !sm->PTK_valid)
3381 return -1;
3382
3383 wpa_hexdump(MSG_DEBUG,
3384 "FILS: Association Response frame before FILS processing",
3385 buf, current_len);
3386
3387 mgmt = (struct ieee80211_mgmt *) buf;
3388
3389 /* AES-SIV AAD vectors */
3390
3391 /* The AP's BSSID */
3392 aad[0] = mgmt->sa;
3393 aad_len[0] = ETH_ALEN;
3394 /* The STA's MAC address */
3395 aad[1] = mgmt->da;
3396 aad_len[1] = ETH_ALEN;
3397 /* The AP's nonce */
3398 aad[2] = sm->ANonce;
3399 aad_len[2] = FILS_NONCE_LEN;
3400 /* The STA's nonce */
3401 aad[3] = sm->SNonce;
3402 aad_len[3] = FILS_NONCE_LEN;
3403 /*
3404 * The (Re)Association Response frame from the Capability Information
3405 * field (the same offset in both Association and Reassociation
3406 * Response frames) to the FILS Session element (both inclusive).
3407 */
3408 aad[4] = (const u8 *) &mgmt->u.assoc_resp.capab_info;
3409 aad_len[4] = pos - aad[4];
3410
3411 /* The following elements will be encrypted with AES-SIV */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003412 plain = fils_prepare_plainbuf(sm, hlp);
3413 if (!plain) {
3414 wpa_printf(MSG_DEBUG, "FILS: Plain buffer prep failed");
3415 return -1;
3416 }
3417
3418 if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
3419 wpa_printf(MSG_DEBUG,
3420 "FILS: Not enough room for FILS elements");
Hai Shalom81f62d82019-07-22 12:10:00 -07003421 wpabuf_clear_free(plain);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003422 return -1;
3423 }
3424
3425 wpa_hexdump_buf_key(MSG_DEBUG, "FILS: Association Response plaintext",
3426 plain);
3427
3428 if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
3429 wpabuf_head(plain), wpabuf_len(plain),
3430 5, aad, aad_len, pos) < 0) {
Hai Shalom81f62d82019-07-22 12:10:00 -07003431 wpabuf_clear_free(plain);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003432 return -1;
3433 }
3434
3435 wpa_hexdump(MSG_DEBUG,
3436 "FILS: Encrypted Association Response elements",
3437 pos, AES_BLOCK_SIZE + wpabuf_len(plain));
3438 current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
Hai Shalom81f62d82019-07-22 12:10:00 -07003439 wpabuf_clear_free(plain);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003440
3441 sm->fils_completed = 1;
3442
3443 return current_len;
3444}
3445
3446
3447static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
3448 const struct wpabuf *hlp)
3449{
3450 struct wpabuf *plain;
3451 u8 *len, *tmp, *tmp2;
3452 u8 hdr[2];
Hai Shaloma20dcd72022-02-04 13:43:00 -08003453 u8 *gtk, stub_gtk[32];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003454 size_t gtk_len;
3455 struct wpa_group *gsm;
Hai Shalomfdcde762020-04-02 11:19:20 -07003456 size_t plain_len;
3457 struct wpa_auth_config *conf = &sm->wpa_auth->conf;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003458
Hai Shalomfdcde762020-04-02 11:19:20 -07003459 plain_len = 1000 + ieee80211w_kde_len(sm);
3460 if (conf->transition_disable)
3461 plain_len += 2 + RSN_SELECTOR_LEN + 1;
3462 plain = wpabuf_alloc(plain_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003463 if (!plain)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003464 return NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003465
3466 /* TODO: FILS Public Key */
3467
3468 /* FILS Key Confirmation */
3469 wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
3470 wpabuf_put_u8(plain, 1 + sm->fils_key_auth_len); /* Length */
3471 /* Element ID Extension */
3472 wpabuf_put_u8(plain, WLAN_EID_EXT_FILS_KEY_CONFIRM);
3473 wpabuf_put_data(plain, sm->fils_key_auth_ap, sm->fils_key_auth_len);
3474
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003475 /* FILS HLP Container */
3476 if (hlp)
3477 wpabuf_put_buf(plain, hlp);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003478
3479 /* TODO: FILS IP Address Assignment */
3480
3481 /* Key Delivery */
3482 gsm = sm->group;
3483 wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
3484 len = wpabuf_put(plain, 1);
3485 wpabuf_put_u8(plain, WLAN_EID_EXT_KEY_DELIVERY);
3486 wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN,
3487 wpabuf_put(plain, WPA_KEY_RSC_LEN));
3488 /* GTK KDE */
3489 gtk = gsm->GTK[gsm->GN - 1];
3490 gtk_len = gsm->GTK_len;
Sunil Ravi876a49b2025-02-03 19:18:32 +00003491 if (conf->disable_gtk) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003492 /*
3493 * Provide unique random GTK to each STA to prevent use
3494 * of GTK in the BSS.
3495 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08003496 if (random_get_bytes(stub_gtk, gtk_len) < 0) {
Hai Shalom81f62d82019-07-22 12:10:00 -07003497 wpabuf_clear_free(plain);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003498 return NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003499 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08003500 gtk = stub_gtk;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003501 }
3502 hdr[0] = gsm->GN & 0x03;
3503 hdr[1] = 0;
3504 tmp = wpabuf_put(plain, 0);
3505 tmp2 = wpa_add_kde(tmp, RSN_KEY_DATA_GROUPKEY, hdr, 2,
3506 gtk, gtk_len);
3507 wpabuf_put(plain, tmp2 - tmp);
3508
Hai Shalomfdcde762020-04-02 11:19:20 -07003509 /* IGTK KDE and BIGTK KDE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003510 tmp = wpabuf_put(plain, 0);
3511 tmp2 = ieee80211w_kde_add(sm, tmp);
3512 wpabuf_put(plain, tmp2 - tmp);
3513
Hai Shalomfdcde762020-04-02 11:19:20 -07003514 if (conf->transition_disable) {
3515 tmp = wpabuf_put(plain, 0);
3516 tmp2 = wpa_add_kde(tmp, WFA_KEY_DATA_TRANSITION_DISABLE,
3517 &conf->transition_disable, 1, NULL, 0);
3518 wpabuf_put(plain, tmp2 - tmp);
3519 }
3520
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003521 *len = (u8 *) wpabuf_put(plain, 0) - len - 1;
Hai Shalom74f70d42019-02-11 14:42:39 -08003522
3523#ifdef CONFIG_OCV
3524 if (wpa_auth_uses_ocv(sm)) {
3525 struct wpa_channel_info ci;
3526 u8 *pos;
3527
3528 if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
3529 wpa_printf(MSG_WARNING,
3530 "FILS: Failed to get channel info for OCI element");
Hai Shalom81f62d82019-07-22 12:10:00 -07003531 wpabuf_clear_free(plain);
Hai Shalom74f70d42019-02-11 14:42:39 -08003532 return NULL;
3533 }
Hai Shalom899fcc72020-10-19 14:38:18 -07003534#ifdef CONFIG_TESTING_OPTIONS
3535 if (conf->oci_freq_override_fils_assoc) {
3536 wpa_printf(MSG_INFO,
3537 "TEST: Override OCI frequency %d -> %u MHz",
3538 ci.frequency,
3539 conf->oci_freq_override_fils_assoc);
3540 ci.frequency = conf->oci_freq_override_fils_assoc;
3541 }
3542#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom74f70d42019-02-11 14:42:39 -08003543
3544 pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
3545 if (ocv_insert_extended_oci(&ci, pos) < 0) {
Hai Shalom81f62d82019-07-22 12:10:00 -07003546 wpabuf_clear_free(plain);
Hai Shalom74f70d42019-02-11 14:42:39 -08003547 return NULL;
3548 }
3549 }
3550#endif /* CONFIG_OCV */
3551
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003552 return plain;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003553}
3554
3555
3556int fils_set_tk(struct wpa_state_machine *sm)
3557{
3558 enum wpa_alg alg;
3559 int klen;
3560
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003561 if (!sm || !sm->PTK_valid) {
3562 wpa_printf(MSG_DEBUG, "FILS: No valid PTK available to set TK");
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003563 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003564 }
3565 if (sm->tk_already_set) {
3566 wpa_printf(MSG_DEBUG, "FILS: TK already set to the driver");
3567 return -1;
3568 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003569
3570 alg = wpa_cipher_to_alg(sm->pairwise);
3571 klen = wpa_cipher_key_len(sm->pairwise);
3572
3573 wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
3574 if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
Hai Shalomfdcde762020-04-02 11:19:20 -07003575 sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003576 wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
3577 return -1;
3578 }
Sunil Ravi89eba102022-09-13 21:04:37 -07003579
3580#ifdef CONFIG_PASN
3581 if (sm->wpa_auth->conf.secure_ltf &&
3582 ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) &&
3583 wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr,
3584 sm->PTK.ltf_keyseed,
3585 sm->PTK.ltf_keyseed_len)) {
3586 wpa_printf(MSG_ERROR,
3587 "FILS: Failed to set LTF keyseed to driver");
3588 return -1;
3589 }
3590#endif /* CONFIG_PASN */
3591
Sunil8cd6f4d2022-06-28 18:40:46 +00003592 sm->pairwise_set = true;
Hai Shalome21d4e82020-04-29 16:34:06 -07003593 sm->tk_already_set = true;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003594
Hai Shalom60840252021-02-19 19:02:11 -08003595 wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
3596 dot11RSNAConfigPMKLifetime, &sm->PTK);
3597
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003598 return 0;
3599}
3600
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003601
3602u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
3603 const u8 *fils_session, struct wpabuf *hlp)
3604{
3605 struct wpabuf *plain;
3606 u8 *pos = buf;
3607
3608 /* FILS Session */
3609 *pos++ = WLAN_EID_EXTENSION; /* Element ID */
3610 *pos++ = 1 + FILS_SESSION_LEN; /* Length */
3611 *pos++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
3612 os_memcpy(pos, fils_session, FILS_SESSION_LEN);
3613 pos += FILS_SESSION_LEN;
3614
3615 plain = fils_prepare_plainbuf(sm, hlp);
3616 if (!plain) {
3617 wpa_printf(MSG_DEBUG, "FILS: Plain buffer prep failed");
3618 return NULL;
3619 }
3620
3621 os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
3622 pos += wpabuf_len(plain);
3623
Hai Shalomfdcde762020-04-02 11:19:20 -07003624 wpa_printf(MSG_DEBUG, "%s: plain buf_len: %zu", __func__,
3625 wpabuf_len(plain));
Hai Shalom81f62d82019-07-22 12:10:00 -07003626 wpabuf_clear_free(plain);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003627 sm->fils_completed = 1;
3628 return pos;
3629}
3630
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003631#endif /* CONFIG_FILS */
3632
3633
Hai Shalom74f70d42019-02-11 14:42:39 -08003634#ifdef CONFIG_OCV
3635int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
3636 int ap_seg1_idx, int *bandwidth, int *seg1_idx)
3637{
3638 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
3639
3640 if (!wpa_auth->cb->get_sta_tx_params)
3641 return -1;
3642 return wpa_auth->cb->get_sta_tx_params(wpa_auth->cb_ctx, sm->addr,
3643 ap_max_chanwidth, ap_seg1_idx,
3644 bandwidth, seg1_idx);
3645}
3646#endif /* CONFIG_OCV */
3647
3648
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003649static int wpa_auth_validate_ml_kdes_m2(struct wpa_state_machine *sm,
3650 struct wpa_eapol_ie_parse *kde)
3651{
3652#ifdef CONFIG_IEEE80211BE
3653 int i;
3654 unsigned int n_links = 0;
3655
3656 if (sm->mld_assoc_link_id < 0)
3657 return 0;
3658
3659 /* MLD MAC address must be the same */
3660 if (!kde->mac_addr ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003661 !ether_addr_equal(kde->mac_addr, sm->peer_mld_addr)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003662 wpa_printf(MSG_DEBUG, "RSN: MLD: Invalid MLD address");
3663 return -1;
3664 }
3665
3666 /* Find matching link ID and the MAC address for each link */
Sunil Ravi99c035e2024-07-12 01:42:03 +00003667 for_each_link(kde->valid_mlo_links, i) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003668 /*
3669 * Each entry should contain the link information and the MAC
3670 * address.
3671 */
3672 if (kde->mlo_link_len[i] != 1 + ETH_ALEN) {
3673 wpa_printf(MSG_DEBUG,
3674 "RSN: MLD: Invalid MLO Link (ID %u) KDE len=%zu",
3675 i, kde->mlo_link_len[i]);
3676 return -1;
3677 }
3678
3679 if (!sm->mld_links[i].valid || i == sm->mld_assoc_link_id) {
3680 wpa_printf(MSG_DEBUG,
3681 "RSN: MLD: Invalid link ID=%u", i);
3682 return -1;
3683 }
3684
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003685 if (!ether_addr_equal(sm->mld_links[i].peer_addr,
3686 kde->mlo_link[i] + 1)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00003687 wpa_printf(MSG_DEBUG,
3688 "RSN: MLD: invalid MAC address=" MACSTR
3689 " expected " MACSTR " (link ID %u)",
3690 MAC2STR(kde->mlo_link[i] + 1),
3691 MAC2STR(sm->mld_links[i].peer_addr), i);
3692 return -1;
3693 }
3694
3695 n_links++;
3696 }
3697
3698 /* Must have the same number of MLO links (excluding the local one) */
3699 if (n_links != sm->n_mld_affiliated_links) {
3700 wpa_printf(MSG_DEBUG,
3701 "RSN: MLD: Expecting %u MLD links in msg 2, but got %u",
3702 sm->n_mld_affiliated_links, n_links);
3703 return -1;
3704 }
3705#endif /* CONFIG_IEEE80211BE */
3706
3707 return 0;
3708}
3709
3710
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003711SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
3712{
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003713 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003714 struct wpa_ptk PTK;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07003715 int ok = 0, psk_found = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003716 const u8 *pmk = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003717 size_t pmk_len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003718 int ft;
3719 const u8 *eapol_key_ie, *key_data, *mic;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003720 u16 key_info, ver, key_data_length;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003721 size_t mic_len, eapol_key_ie_len;
3722 struct ieee802_1x_hdr *hdr;
3723 struct wpa_eapol_key *key;
3724 struct wpa_eapol_ie_parse kde;
Hai Shalom021b0b52019-04-10 11:17:58 -07003725 int vlan_id = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07003726 int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
Sunil Raviaf8751c2023-03-29 11:35:17 -07003727 u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
3728 u8 pmk_r1[PMK_LEN_MAX];
3729 size_t key_len;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003730 u8 *key_data_buf = NULL;
3731 size_t key_data_buf_len = 0;
Sunil Ravi7f769292024-07-23 22:21:32 +00003732 bool derive_kdk, no_kdk = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003733
3734 SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
Hai Shalome21d4e82020-04-29 16:34:06 -07003735 sm->EAPOLKeyReceived = false;
3736 sm->update_snonce = false;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003737 os_memset(&PTK, 0, sizeof(PTK));
3738
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003739 mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003740
Sunil Ravi7f769292024-07-23 22:21:32 +00003741 derive_kdk = sm->wpa_auth->conf.secure_ltf &&
3742 ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF);
3743
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003744 /* WPA with IEEE 802.1X: use the derived PMK from EAP
3745 * WPA-PSK: iterate through possible PSKs and select the one matching
3746 * the packet */
3747 for (;;) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003748 if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
3749 !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07003750 pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
Hai Shalom021b0b52019-04-10 11:17:58 -07003751 sm->p2p_dev_addr, pmk, &pmk_len,
3752 &vlan_id);
Hai Shalomfdcde762020-04-02 11:19:20 -07003753 if (!pmk)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003754 break;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07003755 psk_found = 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003756#ifdef CONFIG_IEEE80211R_AP
3757 if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
3758 os_memcpy(sm->xxkey, pmk, pmk_len);
3759 sm->xxkey_len = pmk_len;
3760 }
3761#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003762 } else {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003763 pmk = sm->PMK;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003764 pmk_len = sm->pmk_len;
3765 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003766
Hai Shalom81f62d82019-07-22 12:10:00 -07003767 if ((!pmk || !pmk_len) && sm->pmksa) {
3768 wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache");
3769 pmk = sm->pmksa->pmk;
3770 pmk_len = sm->pmksa->pmk_len;
3771 }
3772
Sunil Ravi7f769292024-07-23 22:21:32 +00003773 no_kdk = false;
3774 try_without_kdk:
Hai Shalomfdcde762020-04-02 11:19:20 -07003775 if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
Sunil Raviaf8751c2023-03-29 11:35:17 -07003776 owe_ptk_workaround == 2, pmk_r0, pmk_r1,
Sunil Ravi7f769292024-07-23 22:21:32 +00003777 pmk_r0_name, &key_len, no_kdk) < 0)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003778 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003779
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003780 if (mic_len &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003781 wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003782 sm->last_rx_eapol_key,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003783 sm->last_rx_eapol_key_len) == 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07003784 if (sm->PMK != pmk) {
3785 os_memcpy(sm->PMK, pmk, pmk_len);
3786 sm->pmk_len = pmk_len;
3787 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003788 ok = 1;
3789 break;
3790 }
3791
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003792#ifdef CONFIG_FILS
3793 if (!mic_len &&
3794 wpa_aead_decrypt(sm, &PTK, sm->last_rx_eapol_key,
3795 sm->last_rx_eapol_key_len, NULL) == 0) {
3796 ok = 1;
3797 break;
3798 }
3799#endif /* CONFIG_FILS */
3800
Hai Shalomfdcde762020-04-02 11:19:20 -07003801#ifdef CONFIG_OWE
3802 if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
3803 owe_ptk_workaround == 1) {
3804 wpa_printf(MSG_DEBUG,
3805 "OWE: Try PTK derivation workaround with SHA256");
3806 owe_ptk_workaround = 2;
3807 continue;
3808 }
3809#endif /* CONFIG_OWE */
3810
Sunil Ravi7f769292024-07-23 22:21:32 +00003811 /* Some deployed STAs that advertise SecureLTF support in the
3812 * RSNXE in (Re)Association Request frames, do not derive KDK
3813 * during PTK generation. Try to work around this by checking if
3814 * a PTK derived without KDK would result in a matching MIC. */
3815 if (!sm->wpa_auth->conf.force_kdk_derivation &&
3816 derive_kdk && !no_kdk) {
3817 wpa_printf(MSG_DEBUG,
3818 "Try new PTK derivation without KDK as a workaround");
3819 no_kdk = true;
3820 goto try_without_kdk;
3821 }
3822
Roshan Pius3a1667e2018-07-03 15:17:14 -07003823 if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
3824 wpa_key_mgmt_sae(sm->wpa_key_mgmt))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003825 break;
3826 }
3827
Sunil Ravi7f769292024-07-23 22:21:32 +00003828 if (no_kdk && ok) {
3829 /* The workaround worked, so allow the 4-way handshake to be
3830 * completed with the PTK that was derived without the KDK. */
3831 wpa_printf(MSG_DEBUG,
3832 "PTK without KDK worked - misbehaving STA "
3833 MACSTR, MAC2STR(sm->addr));
3834 }
3835
Sunil Ravia04bd252022-05-02 22:54:18 -07003836 if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
3837 wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk &&
3838 !sm->waiting_radius_psk) {
3839 wpa_printf(MSG_DEBUG, "No PSK available - ask RADIUS server");
3840 wpa_auth->cb->request_radius_psk(wpa_auth->cb_ctx, sm->addr,
3841 sm->wpa_key_mgmt,
3842 sm->ANonce,
3843 sm->last_rx_eapol_key,
3844 sm->last_rx_eapol_key_len);
3845 sm->waiting_radius_psk = 1;
Sunil Raviaf8751c2023-03-29 11:35:17 -07003846 goto out;
Sunil Ravia04bd252022-05-02 22:54:18 -07003847 }
3848
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003849 if (!ok) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07003850 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
3851 LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003852 "invalid MIC in msg 2/4 of 4-Way Handshake");
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07003853 if (psk_found)
3854 wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
Sunil Raviaf8751c2023-03-29 11:35:17 -07003855 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003856 }
3857
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003858 /*
3859 * Note: last_rx_eapol_key length fields have already been validated in
3860 * wpa_receive().
3861 */
3862 hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
3863 key = (struct wpa_eapol_key *) (hdr + 1);
3864 mic = (u8 *) (key + 1);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003865 key_info = WPA_GET_BE16(key->key_info);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003866 key_data = mic + mic_len + 2;
3867 key_data_length = WPA_GET_BE16(mic + mic_len);
3868 if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
3869 sizeof(*key) - mic_len - 2)
Sunil Raviaf8751c2023-03-29 11:35:17 -07003870 goto out;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003871
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003872 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
3873 if (mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
3874 if (ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
3875 ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
3876 !wpa_use_aes_key_wrap(sm->wpa_key_mgmt)) {
3877 wpa_printf(MSG_INFO,
3878 "Unsupported EAPOL-Key Key Data field encryption");
3879 goto out;
3880 }
3881
3882 if (key_data_length < 8 || key_data_length % 8) {
3883 wpa_printf(MSG_INFO,
3884 "RSN: Unsupported AES-WRAP len %u",
3885 key_data_length);
3886 goto out;
3887 }
3888 key_data_length -= 8; /* AES-WRAP adds 8 bytes */
3889 key_data_buf = os_malloc(key_data_length);
3890 if (!key_data_buf)
3891 goto out;
3892 key_data_buf_len = key_data_length;
3893 if (aes_unwrap(PTK.kek, PTK.kek_len, key_data_length / 8,
3894 key_data, key_data_buf)) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003895 wpa_printf(MSG_INFO,
3896 "RSN: AES unwrap failed - could not decrypt EAPOL-Key key data");
3897 goto out;
3898 }
3899 key_data = key_data_buf;
3900 wpa_hexdump_key(MSG_DEBUG, "RSN: Decrypted EAPOL-Key Key Data",
3901 key_data, key_data_length);
3902 }
3903
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003904 if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07003905 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003906 "received EAPOL-Key msg 2/4 with invalid Key Data contents");
Sunil Raviaf8751c2023-03-29 11:35:17 -07003907 goto out;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003908 }
3909 if (kde.rsn_ie) {
3910 eapol_key_ie = kde.rsn_ie;
3911 eapol_key_ie_len = kde.rsn_ie_len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003912 } else {
3913 eapol_key_ie = kde.wpa_ie;
3914 eapol_key_ie_len = kde.wpa_ie_len;
3915 }
3916 ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
Hai Shalomfdcde762020-04-02 11:19:20 -07003917 if (!sm->wpa_ie ||
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003918 wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
3919 eapol_key_ie, eapol_key_ie_len)) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07003920 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003921 "WPA IE from (Re)AssocReq did not match with msg 2/4");
3922 if (sm->wpa_ie) {
3923 wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
3924 sm->wpa_ie, sm->wpa_ie_len);
3925 }
3926 wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
3927 eapol_key_ie, eapol_key_ie_len);
3928 /* MLME-DEAUTHENTICATE.request */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003929 wpa_sta_disconnect(wpa_auth, sm->addr,
3930 WLAN_REASON_PREV_AUTH_NOT_VALID);
Sunil Raviaf8751c2023-03-29 11:35:17 -07003931 goto out;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003932 }
Hai Shalomc3565922019-10-28 11:58:20 -07003933 if ((!sm->rsnxe && kde.rsnxe) ||
3934 (sm->rsnxe && !kde.rsnxe) ||
3935 (sm->rsnxe && kde.rsnxe &&
3936 (sm->rsnxe_len != kde.rsnxe_len ||
3937 os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07003938 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Hai Shalomc3565922019-10-28 11:58:20 -07003939 "RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
3940 wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq",
3941 sm->rsnxe, sm->rsnxe_len);
3942 wpa_hexdump(MSG_DEBUG, "RSNXE in EAPOL-Key msg 2/4",
3943 kde.rsnxe, kde.rsnxe_len);
3944 /* MLME-DEAUTHENTICATE.request */
3945 wpa_sta_disconnect(wpa_auth, sm->addr,
3946 WLAN_REASON_PREV_AUTH_NOT_VALID);
Sunil Raviaf8751c2023-03-29 11:35:17 -07003947 goto out;
Hai Shalomc3565922019-10-28 11:58:20 -07003948 }
Hai Shalom74f70d42019-02-11 14:42:39 -08003949#ifdef CONFIG_OCV
3950 if (wpa_auth_uses_ocv(sm)) {
3951 struct wpa_channel_info ci;
3952 int tx_chanwidth;
3953 int tx_seg1_idx;
Hai Shalom899fcc72020-10-19 14:38:18 -07003954 enum oci_verify_result res;
Hai Shalom74f70d42019-02-11 14:42:39 -08003955
3956 if (wpa_channel_info(wpa_auth, &ci) != 0) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07003957 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
3958 LOGGER_INFO,
Hai Shalom74f70d42019-02-11 14:42:39 -08003959 "Failed to get channel info to validate received OCI in EAPOL-Key 2/4");
Sunil Raviaf8751c2023-03-29 11:35:17 -07003960 goto out;
Hai Shalom74f70d42019-02-11 14:42:39 -08003961 }
3962
3963 if (get_sta_tx_parameters(sm,
3964 channel_width_to_int(ci.chanwidth),
3965 ci.seg1_idx, &tx_chanwidth,
3966 &tx_seg1_idx) < 0)
Sunil Raviaf8751c2023-03-29 11:35:17 -07003967 goto out;
Hai Shalom74f70d42019-02-11 14:42:39 -08003968
Hai Shalom899fcc72020-10-19 14:38:18 -07003969 res = ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
3970 tx_chanwidth, tx_seg1_idx);
3971 if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
3972 /* Work around misbehaving STAs */
Sunil Raviaf8751c2023-03-29 11:35:17 -07003973 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
3974 LOGGER_INFO,
Hai Shalom899fcc72020-10-19 14:38:18 -07003975 "Disable OCV with a STA that does not send OCI");
3976 wpa_auth_set_ocv(sm, 0);
3977 } else if (res != OCI_SUCCESS) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07003978 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
3979 LOGGER_INFO,
Hai Shalom899fcc72020-10-19 14:38:18 -07003980 "OCV failed: %s", ocv_errorstr);
3981 if (wpa_auth->conf.msg_ctx)
3982 wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
3983 OCV_FAILURE "addr=" MACSTR
3984 " frame=eapol-key-m2 error=%s",
Sunil Raviaf8751c2023-03-29 11:35:17 -07003985 MAC2STR(wpa_auth_get_spa(sm)),
3986 ocv_errorstr);
3987 goto out;
Hai Shalom74f70d42019-02-11 14:42:39 -08003988 }
3989 }
3990#endif /* CONFIG_OCV */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003991#ifdef CONFIG_IEEE80211R_AP
3992 if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003993 wpa_sta_disconnect(wpa_auth, sm->addr,
3994 WLAN_REASON_PREV_AUTH_NOT_VALID);
Sunil Raviaf8751c2023-03-29 11:35:17 -07003995 goto out;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003996 }
3997#endif /* CONFIG_IEEE80211R_AP */
Sunil Ravic0f5d412024-09-11 22:12:49 +00003998
3999 /* Verify RSN Selection element for RSN overriding */
4000 if ((wpa_auth->conf.rsn_override_key_mgmt ||
4001 wpa_auth->conf.rsn_override_key_mgmt_2) &&
4002 ((rsn_is_snonce_cookie(sm->SNonce) && !kde.rsn_selection) ||
4003 (!rsn_is_snonce_cookie(sm->SNonce) && kde.rsn_selection) ||
4004 (sm->rsn_selection && !kde.rsn_selection) ||
4005 (!sm->rsn_selection && kde.rsn_selection) ||
4006 (sm->rsn_selection && kde.rsn_selection &&
4007 (sm->rsn_selection_len != kde.rsn_selection_len ||
4008 os_memcmp(sm->rsn_selection, kde.rsn_selection,
4009 sm->rsn_selection_len) != 0)))) {
4010 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
4011 "RSN Selection element from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
4012 wpa_printf(MSG_DEBUG,
4013 "SNonce cookie for RSN overriding %sused",
4014 rsn_is_snonce_cookie(sm->SNonce) ? "" : "not ");
4015 wpa_hexdump(MSG_DEBUG, "RSN Selection in AssocReq",
4016 sm->rsn_selection, sm->rsn_selection_len);
4017 wpa_hexdump(MSG_DEBUG, "RSN Selection in EAPOL-Key msg 2/4",
4018 kde.rsn_selection, kde.rsn_selection_len);
4019 /* MLME-DEAUTHENTICATE.request */
4020 wpa_sta_disconnect(wpa_auth, sm->addr,
4021 WLAN_REASON_PREV_AUTH_NOT_VALID);
4022 goto out;
4023
4024 }
4025
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004026#ifdef CONFIG_P2P
4027 if (kde.ip_addr_req && kde.ip_addr_req[0] &&
4028 wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
4029 int idx;
4030 wpa_printf(MSG_DEBUG,
4031 "P2P: IP address requested in EAPOL-Key exchange");
4032 idx = bitfield_get_first_zero(wpa_auth->ip_pool);
4033 if (idx >= 0) {
4034 u32 start = WPA_GET_BE32(wpa_auth->conf.ip_addr_start);
4035 bitfield_set(wpa_auth->ip_pool, idx);
Sunil8cd6f4d2022-06-28 18:40:46 +00004036 sm->ip_addr_bit = idx;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004037 WPA_PUT_BE32(sm->ip_addr, start + idx);
4038 wpa_printf(MSG_DEBUG,
4039 "P2P: Assigned IP address %u.%u.%u.%u to "
Sunil8cd6f4d2022-06-28 18:40:46 +00004040 MACSTR " (bit %u)",
4041 sm->ip_addr[0], sm->ip_addr[1],
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004042 sm->ip_addr[2], sm->ip_addr[3],
Sunil Raviaf8751c2023-03-29 11:35:17 -07004043 MAC2STR(wpa_auth_get_spa(sm)),
4044 sm->ip_addr_bit);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004045 }
4046 }
4047#endif /* CONFIG_P2P */
4048
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004049#ifdef CONFIG_DPP2
4050 if (DPP_VERSION > 1 && kde.dpp_kde) {
4051 wpa_printf(MSG_DEBUG,
4052 "DPP: peer Protocol Version %u Flags 0x%x",
4053 kde.dpp_kde[0], kde.dpp_kde[1]);
4054 if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
4055 wpa_auth->conf.dpp_pfs != 2 &&
4056 (kde.dpp_kde[1] & DPP_KDE_PFS_ALLOWED) &&
4057 !sm->dpp_z) {
4058 wpa_printf(MSG_INFO,
4059 "DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association");
4060 wpa_sta_disconnect(wpa_auth, sm->addr,
4061 WLAN_REASON_PREV_AUTH_NOT_VALID);
Sunil Raviaf8751c2023-03-29 11:35:17 -07004062 goto out;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004063 }
4064 }
4065#endif /* CONFIG_DPP2 */
4066
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004067 if (wpa_auth_validate_ml_kdes_m2(sm, &kde) < 0) {
4068 wpa_sta_disconnect(wpa_auth, sm->addr,
4069 WLAN_REASON_PREV_AUTH_NOT_VALID);
4070 return;
4071 }
4072
Hai Shalom021b0b52019-04-10 11:17:58 -07004073 if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
4074 wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
4075 wpa_sta_disconnect(wpa_auth, sm->addr,
4076 WLAN_REASON_PREV_AUTH_NOT_VALID);
Sunil Raviaf8751c2023-03-29 11:35:17 -07004077 goto out;
Hai Shalom021b0b52019-04-10 11:17:58 -07004078 }
4079
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004080 sm->pending_1_of_4_timeout = 0;
4081 eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
4082
Hai Shalom60840252021-02-19 19:02:11 -08004083 if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && sm->PMK != pmk) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004084 /* PSK may have changed from the previous choice, so update
4085 * state machine data based on whatever PSK was selected here.
4086 */
4087 os_memcpy(sm->PMK, pmk, PMK_LEN);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004088 sm->pmk_len = PMK_LEN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004089 }
4090
Hai Shalome21d4e82020-04-29 16:34:06 -07004091 sm->MICVerified = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004092
Sunil Raviaf8751c2023-03-29 11:35:17 -07004093#ifdef CONFIG_IEEE80211R_AP
4094 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) {
4095 wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1");
4096 wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name,
4097 key_len);
4098 }
4099#endif /* CONFIG_IEEE80211R_AP */
4100
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004101 os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
Hai Shalom81f62d82019-07-22 12:10:00 -07004102 forced_memzero(&PTK, sizeof(PTK));
Hai Shalome21d4e82020-04-29 16:34:06 -07004103 sm->PTK_valid = true;
Sunil Raviaf8751c2023-03-29 11:35:17 -07004104out:
4105 forced_memzero(pmk_r0, sizeof(pmk_r0));
4106 forced_memzero(pmk_r1, sizeof(pmk_r1));
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004107 bin_clear_free(key_data_buf, key_data_buf_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004108}
4109
4110
4111SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
4112{
4113 SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk);
4114 sm->TimeoutCtr = 0;
4115}
4116
4117
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004118static int ieee80211w_kde_len(struct wpa_state_machine *sm)
4119{
Hai Shalomfdcde762020-04-02 11:19:20 -07004120 size_t len = 0;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004121 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
Hai Shalomfdcde762020-04-02 11:19:20 -07004122
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004123 if (sm->mgmt_frame_prot) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004124 len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004125 len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
Hai Shalomfdcde762020-04-02 11:19:20 -07004126 }
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004127
4128 if (wpa_auth->conf.tx_bss_auth)
4129 wpa_auth = wpa_auth->conf.tx_bss_auth;
Hai Shalomfdcde762020-04-02 11:19:20 -07004130 if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
4131 len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004132 len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004133 }
4134
Hai Shalomfdcde762020-04-02 11:19:20 -07004135 return len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004136}
4137
4138
4139static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
4140{
4141 struct wpa_igtk_kde igtk;
Hai Shalomfdcde762020-04-02 11:19:20 -07004142 struct wpa_bigtk_kde bigtk;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004143 struct wpa_group *gsm = sm->group;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004144 u8 rsc[WPA_KEY_RSC_LEN];
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004145 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
4146 struct wpa_auth_config *conf = &wpa_auth->conf;
Hai Shalomfdcde762020-04-02 11:19:20 -07004147 size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004148
4149 if (!sm->mgmt_frame_prot)
4150 return pos;
4151
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004152#ifdef CONFIG_IEEE80211BE
4153 if (sm->mld_assoc_link_id >= 0)
4154 return pos; /* Use per-link MLO KDEs instead */
4155#endif /* CONFIG_IEEE80211BE */
4156
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004157 igtk.keyid[0] = gsm->GN_igtk;
4158 igtk.keyid[1] = 0;
4159 if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004160 wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004161 os_memset(igtk.pn, 0, sizeof(igtk.pn));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07004162 else
4163 os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004164 os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
Sunil Ravi876a49b2025-02-03 19:18:32 +00004165 if (conf->disable_gtk) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004166 /*
4167 * Provide unique random IGTK to each STA to prevent use of
4168 * IGTK in the BSS.
4169 */
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004170 if (random_get_bytes(igtk.igtk, len) < 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004171 return pos;
4172 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004173 pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07004174 (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
4175 NULL, 0);
Sunil Ravia04bd252022-05-02 22:54:18 -07004176 forced_memzero(&igtk, sizeof(igtk));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004177
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004178 if (wpa_auth->conf.tx_bss_auth) {
4179 wpa_auth = wpa_auth->conf.tx_bss_auth;
4180 conf = &wpa_auth->conf;
4181 len = wpa_cipher_key_len(conf->group_mgmt_cipher);
4182 gsm = wpa_auth->group;
4183 }
4184
4185 if (!sm->wpa_auth->conf.beacon_prot)
Hai Shalomfdcde762020-04-02 11:19:20 -07004186 return pos;
4187
4188 bigtk.keyid[0] = gsm->GN_bigtk;
4189 bigtk.keyid[1] = 0;
4190 if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
4191 wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
4192 os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
4193 else
4194 os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
4195 os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
4196 pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
4197 (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
4198 NULL, 0);
Sunil Ravia04bd252022-05-02 22:54:18 -07004199 forced_memzero(&bigtk, sizeof(bigtk));
Hai Shalomfdcde762020-04-02 11:19:20 -07004200
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004201 return pos;
4202}
4203
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004204
Hai Shalom74f70d42019-02-11 14:42:39 -08004205static int ocv_oci_len(struct wpa_state_machine *sm)
4206{
4207#ifdef CONFIG_OCV
4208 if (wpa_auth_uses_ocv(sm))
4209 return OCV_OCI_KDE_LEN;
4210#endif /* CONFIG_OCV */
4211 return 0;
4212}
4213
Hai Shalom899fcc72020-10-19 14:38:18 -07004214
4215static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos,
4216 unsigned int freq)
Hai Shalom74f70d42019-02-11 14:42:39 -08004217{
4218#ifdef CONFIG_OCV
4219 struct wpa_channel_info ci;
4220
4221 if (!wpa_auth_uses_ocv(sm))
4222 return 0;
4223
4224 if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
4225 wpa_printf(MSG_WARNING,
4226 "Failed to get channel info for OCI element");
4227 return -1;
4228 }
Hai Shalom899fcc72020-10-19 14:38:18 -07004229#ifdef CONFIG_TESTING_OPTIONS
4230 if (freq) {
4231 wpa_printf(MSG_INFO,
4232 "TEST: Override OCI KDE frequency %d -> %u MHz",
4233 ci.frequency, freq);
4234 ci.frequency = freq;
4235 }
4236#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom74f70d42019-02-11 14:42:39 -08004237
4238 return ocv_insert_oci_kde(&ci, argpos);
4239#else /* CONFIG_OCV */
4240 return 0;
4241#endif /* CONFIG_OCV */
4242}
4243
4244
Hai Shalomfdcde762020-04-02 11:19:20 -07004245#ifdef CONFIG_TESTING_OPTIONS
4246static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
4247 const u8 *ie, size_t ie_len)
4248{
4249 const u8 *elem;
4250 u8 *buf;
4251
4252 wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name);
4253 wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override",
4254 old_buf, *len);
4255 buf = os_malloc(*len + ie_len);
4256 if (!buf)
4257 return NULL;
4258 os_memcpy(buf, old_buf, *len);
4259 elem = get_ie(buf, *len, eid);
4260 if (elem) {
4261 u8 elem_len = 2 + elem[1];
4262
4263 os_memmove((void *) elem, elem + elem_len,
4264 *len - (elem - buf) - elem_len);
4265 *len -= elem_len;
4266 }
4267 os_memcpy(buf + *len, ie, ie_len);
4268 *len += ie_len;
4269 wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override",
4270 buf, *len);
4271
4272 return buf;
4273}
4274#endif /* CONFIG_TESTING_OPTIONS */
4275
4276
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004277#ifdef CONFIG_IEEE80211BE
4278
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004279void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
4280 struct wpa_auth_ml_link_key_info *info,
Sunil Ravic0f5d412024-09-11 22:12:49 +00004281 bool mgmt_frame_prot, bool beacon_prot,
4282 bool rekey)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004283{
4284 struct wpa_group *gsm = a->group;
4285 u8 rsc[WPA_KEY_RSC_LEN];
4286
4287 wpa_printf(MSG_DEBUG,
4288 "MLD: Get group key info: link_id=%u, IGTK=%u, BIGTK=%u",
4289 info->link_id, mgmt_frame_prot, beacon_prot);
4290
4291 info->gtkidx = gsm->GN & 0x03;
4292 info->gtk = gsm->GTK[gsm->GN - 1];
4293 info->gtk_len = gsm->GTK_len;
4294
Sunil Ravic0f5d412024-09-11 22:12:49 +00004295 if (rekey || wpa_auth_get_seqnum(a, NULL, gsm->GN, rsc) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004296 os_memset(info->pn, 0, sizeof(info->pn));
4297 else
4298 os_memcpy(info->pn, rsc, sizeof(info->pn));
4299
4300 if (!mgmt_frame_prot)
4301 return;
4302
4303 info->igtkidx = gsm->GN_igtk;
4304 info->igtk = gsm->IGTK[gsm->GN_igtk - 4];
4305 info->igtk_len = wpa_cipher_key_len(a->conf.group_mgmt_cipher);
4306
Sunil Ravic0f5d412024-09-11 22:12:49 +00004307 if (rekey || wpa_auth_get_seqnum(a, NULL, gsm->GN_igtk, rsc) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004308 os_memset(info->ipn, 0, sizeof(info->ipn));
4309 else
4310 os_memcpy(info->ipn, rsc, sizeof(info->ipn));
4311
4312 if (!beacon_prot)
4313 return;
4314
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004315 if (a->conf.tx_bss_auth) {
4316 a = a->conf.tx_bss_auth;
4317 gsm = a->group;
4318 }
4319
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004320 info->bigtkidx = gsm->GN_bigtk;
4321 info->bigtk = gsm->BIGTK[gsm->GN_bigtk - 6];
4322
Sunil Ravic0f5d412024-09-11 22:12:49 +00004323 if (rekey || wpa_auth_get_seqnum(a, NULL, gsm->GN_bigtk, rsc) < 0)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004324 os_memset(info->bipn, 0, sizeof(info->bipn));
4325 else
4326 os_memcpy(info->bipn, rsc, sizeof(info->bipn));
4327}
4328
4329
4330static void wpa_auth_get_ml_key_info(struct wpa_authenticator *wpa_auth,
Sunil Ravic0f5d412024-09-11 22:12:49 +00004331 struct wpa_auth_ml_key_info *info,
4332 bool rekey)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004333{
4334 if (!wpa_auth->cb->get_ml_key_info)
4335 return;
4336
Sunil Ravic0f5d412024-09-11 22:12:49 +00004337 wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info, rekey);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004338}
4339
4340
Sunil Ravi876a49b2025-02-03 19:18:32 +00004341static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm,
4342 u16 req_links)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004343{
Sunil Ravi7f769292024-07-23 22:21:32 +00004344 struct wpa_authenticator *wpa_auth;
4345 size_t kde_len = 0;
4346 int link_id;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004347
4348 if (sm->mld_assoc_link_id < 0)
4349 return 0;
4350
Sunil Ravi7f769292024-07-23 22:21:32 +00004351 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
4352 if (!sm->mld_links[link_id].valid)
4353 continue;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004354
Sunil Ravi876a49b2025-02-03 19:18:32 +00004355 if (!(req_links & BIT(link_id)))
4356 continue;
4357
Sunil Ravi7f769292024-07-23 22:21:32 +00004358 wpa_auth = sm->mld_links[link_id].wpa_auth;
4359 if (!wpa_auth || !wpa_auth->group)
4360 continue;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004361
Sunil Ravi7f769292024-07-23 22:21:32 +00004362 /* MLO GTK KDE
4363 * Header + Key ID + Tx + LinkID + PN + GTK */
4364 kde_len += KDE_HDR_LEN + 1 + RSN_PN_LEN;
4365 kde_len += wpa_auth->group->GTK_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004366
Sunil Ravi7f769292024-07-23 22:21:32 +00004367 if (!sm->mgmt_frame_prot)
4368 continue;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004369
Sunil Ravi7f769292024-07-23 22:21:32 +00004370 if (wpa_auth->conf.tx_bss_auth)
4371 wpa_auth = wpa_auth->conf.tx_bss_auth;
4372
4373 /* MLO IGTK KDE
4374 * Header + Key ID + IPN + LinkID + IGTK */
4375 kde_len += KDE_HDR_LEN + WPA_IGTK_KDE_PREFIX_LEN + 1;
4376 kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
4377
4378 if (!wpa_auth->conf.beacon_prot)
4379 continue;
4380
4381 /* MLO BIGTK KDE
4382 * Header + Key ID + BIPN + LinkID + BIGTK */
4383 kde_len += KDE_HDR_LEN + WPA_BIGTK_KDE_PREFIX_LEN + 1;
4384 kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004385 }
4386
Sunil Ravi7f769292024-07-23 22:21:32 +00004387 wpa_printf(MSG_DEBUG, "MLO Group KDEs len = %zu", kde_len);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004388
4389 return kde_len;
4390}
4391
4392
Sunil Ravi876a49b2025-02-03 19:18:32 +00004393static u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos,
4394 u16 req_links)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004395{
4396 struct wpa_auth_ml_key_info ml_key_info;
4397 unsigned int i, link_id;
Sunil Ravi7f769292024-07-23 22:21:32 +00004398 u8 *start = pos;
Sunil Ravic0f5d412024-09-11 22:12:49 +00004399 bool rekey = sm->wpa_ptk_group_state == WPA_PTK_GROUP_REKEYNEGOTIATING;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004400
4401 /* First fetch the key information from all the authenticators */
4402 os_memset(&ml_key_info, 0, sizeof(ml_key_info));
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004403
4404 /*
4405 * Assume that management frame protection and beacon protection are the
4406 * same on all links.
4407 */
4408 ml_key_info.mgmt_frame_prot = sm->mgmt_frame_prot;
4409 ml_key_info.beacon_prot = sm->wpa_auth->conf.beacon_prot;
4410
4411 for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
4412 if (!sm->mld_links[link_id].valid)
4413 continue;
4414
Sunil Ravi876a49b2025-02-03 19:18:32 +00004415 if (!(req_links & BIT(link_id)))
4416 continue;
4417
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004418 ml_key_info.links[i++].link_id = link_id;
4419 }
Sunil Ravi876a49b2025-02-03 19:18:32 +00004420 ml_key_info.n_mld_links = i;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004421
Sunil Ravic0f5d412024-09-11 22:12:49 +00004422 wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info, rekey);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004423
4424 /* Add MLO GTK KDEs */
Sunil Ravi876a49b2025-02-03 19:18:32 +00004425 for (i = 0; i < ml_key_info.n_mld_links; i++) {
4426 link_id = ml_key_info.links[i].link_id;
4427
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004428 if (!sm->mld_links[link_id].valid ||
4429 !ml_key_info.links[i].gtk_len)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004430 continue;
4431
4432 wpa_printf(MSG_DEBUG, "RSN: MLO GTK: link=%u", link_id);
4433 wpa_hexdump_key(MSG_DEBUG, "RSN: MLO GTK",
4434 ml_key_info.links[i].gtk,
4435 ml_key_info.links[i].gtk_len);
4436
4437 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
4438 *pos++ = RSN_SELECTOR_LEN + 1 + 6 +
4439 ml_key_info.links[i].gtk_len;
4440
4441 RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_GTK);
4442 pos += RSN_SELECTOR_LEN;
4443
4444 *pos++ = (ml_key_info.links[i].gtkidx & 0x3) | (link_id << 4);
4445
4446 os_memcpy(pos, ml_key_info.links[i].pn, 6);
4447 pos += 6;
4448
4449 os_memcpy(pos, ml_key_info.links[i].gtk,
4450 ml_key_info.links[i].gtk_len);
4451 pos += ml_key_info.links[i].gtk_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004452 }
4453
Sunil Ravi7f769292024-07-23 22:21:32 +00004454 if (!sm->mgmt_frame_prot) {
4455 wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld",
4456 pos - start);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004457 return pos;
Sunil Ravi7f769292024-07-23 22:21:32 +00004458 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004459
4460 /* Add MLO IGTK KDEs */
Sunil Ravi876a49b2025-02-03 19:18:32 +00004461 for (i = 0; i < ml_key_info.n_mld_links; i++) {
4462 link_id = ml_key_info.links[i].link_id;
4463
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004464 if (!sm->mld_links[link_id].valid ||
4465 !ml_key_info.links[i].igtk_len)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004466 continue;
4467
4468 wpa_printf(MSG_DEBUG, "RSN: MLO IGTK: link=%u", link_id);
4469 wpa_hexdump_key(MSG_DEBUG, "RSN: MLO IGTK",
4470 ml_key_info.links[i].igtk,
4471 ml_key_info.links[i].igtk_len);
4472
4473 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
4474 *pos++ = RSN_SELECTOR_LEN + 2 + 1 +
4475 sizeof(ml_key_info.links[i].ipn) +
4476 ml_key_info.links[i].igtk_len;
4477
4478 RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_IGTK);
4479 pos += RSN_SELECTOR_LEN;
4480
4481 /* Add the Key ID */
4482 *pos++ = ml_key_info.links[i].igtkidx;
4483 *pos++ = 0;
4484
4485 /* Add the IPN */
4486 os_memcpy(pos, ml_key_info.links[i].ipn,
4487 sizeof(ml_key_info.links[i].ipn));
4488 pos += sizeof(ml_key_info.links[i].ipn);
4489
4490 *pos++ = ml_key_info.links[i].link_id << 4;
4491
4492 os_memcpy(pos, ml_key_info.links[i].igtk,
4493 ml_key_info.links[i].igtk_len);
4494 pos += ml_key_info.links[i].igtk_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004495 }
4496
Sunil Ravi7f769292024-07-23 22:21:32 +00004497 if (!sm->wpa_auth->conf.beacon_prot) {
4498 wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld",
4499 pos - start);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004500 return pos;
Sunil Ravi7f769292024-07-23 22:21:32 +00004501 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004502
4503 /* Add MLO BIGTK KDEs */
Sunil Ravi876a49b2025-02-03 19:18:32 +00004504 for (i = 0; i < ml_key_info.n_mld_links; i++) {
4505 link_id = ml_key_info.links[i].link_id;
4506
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004507 if (!sm->mld_links[link_id].valid ||
4508 !ml_key_info.links[i].bigtk ||
4509 !ml_key_info.links[i].igtk_len)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004510 continue;
4511
4512 wpa_printf(MSG_DEBUG, "RSN: MLO BIGTK: link=%u", link_id);
4513 wpa_hexdump_key(MSG_DEBUG, "RSN: MLO BIGTK",
4514 ml_key_info.links[i].bigtk,
4515 ml_key_info.links[i].igtk_len);
4516
4517 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
4518 *pos++ = RSN_SELECTOR_LEN + 2 + 1 +
4519 sizeof(ml_key_info.links[i].bipn) +
4520 ml_key_info.links[i].igtk_len;
4521
4522 RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_BIGTK);
4523 pos += RSN_SELECTOR_LEN;
4524
4525 /* Add the Key ID */
4526 *pos++ = ml_key_info.links[i].bigtkidx;
4527 *pos++ = 0;
4528
4529 /* Add the BIPN */
4530 os_memcpy(pos, ml_key_info.links[i].bipn,
4531 sizeof(ml_key_info.links[i].bipn));
4532 pos += sizeof(ml_key_info.links[i].bipn);
4533
4534 *pos++ = ml_key_info.links[i].link_id << 4;
4535
4536 os_memcpy(pos, ml_key_info.links[i].bigtk,
4537 ml_key_info.links[i].igtk_len);
4538 pos += ml_key_info.links[i].igtk_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004539 }
4540
Sunil Ravi7f769292024-07-23 22:21:32 +00004541 wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld", pos - start);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004542 return pos;
4543}
4544
4545#endif /* CONFIG_IEEE80211BE */
4546
4547
4548static size_t wpa_auth_ml_kdes_len(struct wpa_state_machine *sm)
4549{
4550 size_t kde_len = 0;
4551
4552#ifdef CONFIG_IEEE80211BE
4553 unsigned int link_id;
4554
4555 if (sm->mld_assoc_link_id < 0)
4556 return 0;
4557
4558 /* For the MAC Address KDE */
4559 kde_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN;
4560
Sunil Ravic0f5d412024-09-11 22:12:49 +00004561 /* MLO Link KDE and RSN Override Link KDE for each link */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004562 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
Sunil Ravi7f769292024-07-23 22:21:32 +00004563 struct wpa_authenticator *wpa_auth;
Sunil Ravic0f5d412024-09-11 22:12:49 +00004564 const u8 *ie;
Sunil Ravi7f769292024-07-23 22:21:32 +00004565
4566 wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id);
4567 if (!wpa_auth)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004568 continue;
4569
Sunil Ravic0f5d412024-09-11 22:12:49 +00004570 /* MLO Link KDE */
Sunil Ravi7f769292024-07-23 22:21:32 +00004571 kde_len += 2 + RSN_SELECTOR_LEN + 1 + ETH_ALEN;
Sunil Ravic0f5d412024-09-11 22:12:49 +00004572
Sunil Ravi7f769292024-07-23 22:21:32 +00004573 ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4574 WLAN_EID_RSN);
Sunil Ravic0f5d412024-09-11 22:12:49 +00004575 if (ie)
Sunil Ravi7f769292024-07-23 22:21:32 +00004576 kde_len += 2 + ie[1];
4577
4578 ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4579 WLAN_EID_RSNX);
Sunil Ravic0f5d412024-09-11 22:12:49 +00004580 if (ie)
4581 kde_len += 2 + ie[1];
4582
4583 if (!rsn_is_snonce_cookie(sm->SNonce))
4584 continue;
4585
4586 /* RSN Override Link KDE */
4587 kde_len += 2 + RSN_SELECTOR_LEN + 1;
4588
4589 ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4590 RSNE_OVERRIDE_IE_VENDOR_TYPE);
4591 if (ie)
4592 kde_len += 2 + ie[1];
4593
4594 ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4595 RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
4596 if (ie)
4597 kde_len += 2 + ie[1];
4598
4599 ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4600 RSNXE_OVERRIDE_IE_VENDOR_TYPE);
4601 if (ie)
Sunil Ravi7f769292024-07-23 22:21:32 +00004602 kde_len += 2 + ie[1];
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004603 }
4604
Sunil Ravi876a49b2025-02-03 19:18:32 +00004605 kde_len += wpa_auth_ml_group_kdes_len(sm, KDE_ALL_LINKS);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004606#endif /* CONFIG_IEEE80211BE */
4607
4608 return kde_len;
4609}
4610
4611
4612static u8 * wpa_auth_ml_kdes(struct wpa_state_machine *sm, u8 *pos)
4613{
4614#ifdef CONFIG_IEEE80211BE
4615 u8 link_id;
Sunil Ravi7f769292024-07-23 22:21:32 +00004616 u8 *start = pos;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004617
4618 if (sm->mld_assoc_link_id < 0)
4619 return pos;
4620
4621 wpa_printf(MSG_DEBUG, "RSN: MLD: Adding MAC Address KDE");
4622 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR,
Sunil Ravi7f769292024-07-23 22:21:32 +00004623 sm->wpa_auth->mld_addr, ETH_ALEN, NULL, 0);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004624
4625 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
Sunil Ravi7f769292024-07-23 22:21:32 +00004626 struct wpa_authenticator *wpa_auth;
Sunil Ravic0f5d412024-09-11 22:12:49 +00004627 const u8 *rsne, *rsnxe, *rsnoe, *rsno2e, *rsnxoe;
4628 size_t rsne_len, rsnxe_len, rsnoe_len, rsno2e_len, rsnxoe_len;
4629 size_t kde_len;
Sunil Ravi7f769292024-07-23 22:21:32 +00004630
4631 wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id);
4632 if (!wpa_auth)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004633 continue;
4634
Sunil Ravi7f769292024-07-23 22:21:32 +00004635 rsne = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4636 WLAN_EID_RSN);
4637 rsne_len = rsne ? 2 + rsne[1] : 0;
Sunil Ravi7f769292024-07-23 22:21:32 +00004638
4639 rsnxe = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4640 WLAN_EID_RSNX);
4641 rsnxe_len = rsnxe ? 2 + rsnxe[1] : 0;
Sunil Ravi7f769292024-07-23 22:21:32 +00004642
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004643 wpa_printf(MSG_DEBUG,
4644 "RSN: MLO Link: link=%u, len=%zu", link_id,
4645 RSN_SELECTOR_LEN + 1 + ETH_ALEN +
Sunil Ravi7f769292024-07-23 22:21:32 +00004646 rsne_len + rsnxe_len);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004647
Sunil Ravic0f5d412024-09-11 22:12:49 +00004648 /* MLO Link KDE */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004649 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
4650 *pos++ = RSN_SELECTOR_LEN + 1 + ETH_ALEN +
Sunil Ravi7f769292024-07-23 22:21:32 +00004651 rsne_len + rsnxe_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004652
4653 RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_LINK);
4654 pos += RSN_SELECTOR_LEN;
4655
4656 /* Add the Link Information */
4657 *pos = link_id;
Sunil Ravi7f769292024-07-23 22:21:32 +00004658 if (rsne_len)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004659 *pos |= RSN_MLO_LINK_KDE_LI_RSNE_INFO;
Sunil Ravi7f769292024-07-23 22:21:32 +00004660 if (rsnxe_len)
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004661 *pos |= RSN_MLO_LINK_KDE_LI_RSNXE_INFO;
4662
4663 pos++;
Sunil Ravi7f769292024-07-23 22:21:32 +00004664 os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004665 pos += ETH_ALEN;
4666
Sunil Ravi7f769292024-07-23 22:21:32 +00004667 if (rsne_len) {
Sunil Ravic0f5d412024-09-11 22:12:49 +00004668 os_memcpy(pos, rsne, rsne_len);
4669 pos += rsne_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004670 }
4671
Sunil Ravi7f769292024-07-23 22:21:32 +00004672 if (rsnxe_len) {
Sunil Ravic0f5d412024-09-11 22:12:49 +00004673 os_memcpy(pos, rsnxe, rsnxe_len);
4674 pos += rsnxe_len;
4675 }
4676
4677 if (!rsn_is_snonce_cookie(sm->SNonce))
4678 continue;
4679
4680 rsnoe = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4681 RSNE_OVERRIDE_IE_VENDOR_TYPE);
4682 rsnoe_len = rsnoe ? 2 + rsnoe[1] : 0;
4683
4684 rsno2e = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4685 RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
4686 rsno2e_len = rsno2e ? 2 + rsno2e[1] : 0;
4687
4688 rsnxoe = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
4689 RSNXE_OVERRIDE_IE_VENDOR_TYPE);
4690 rsnxoe_len = rsnxoe ? 2 + rsnxoe[1] : 0;
4691
4692 wpa_printf(MSG_DEBUG,
4693 "RSN: RSN Override Link KDE: link=%u, len=%zu",
4694 link_id, RSN_SELECTOR_LEN + rsnoe_len + rsno2e_len +
4695 rsnxoe_len);
4696
4697 /* RSN Override Link KDE */
4698 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
4699 kde_len = RSN_SELECTOR_LEN + 1 + rsnoe_len + rsno2e_len +
4700 rsnxoe_len;
4701 if (kde_len > 255) {
4702 wpa_printf(MSG_ERROR,
4703 "RSN: RSNOE/RSNO2E/RSNXOE too long (KDE length %zu) to fit in RSN Override Link KDE for link %u",
4704 kde_len, link_id);
4705 return NULL;
4706 }
4707 *pos++ = kde_len;
4708
4709 RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_RSN_OVERRIDE_LINK);
4710 pos += RSN_SELECTOR_LEN;
4711
4712 *pos++ = link_id;
4713
4714 if (rsnoe_len) {
4715 os_memcpy(pos, rsnoe, rsnoe_len);
4716 pos += rsnoe_len;
4717 }
4718
4719 if (rsno2e_len) {
4720 os_memcpy(pos, rsno2e, rsno2e_len);
4721 pos += rsno2e_len;
4722 }
4723
4724 if (rsnxoe_len) {
4725 os_memcpy(pos, rsnxoe, rsnxoe_len);
4726 pos += rsnxoe_len;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004727 }
4728 }
4729
Sunil Ravic0f5d412024-09-11 22:12:49 +00004730 wpa_printf(MSG_DEBUG,
4731 "RSN: MLO Link KDEs and RSN Override Link KDEs len = %ld",
4732 pos - start);
Sunil Ravi876a49b2025-02-03 19:18:32 +00004733 pos = wpa_auth_ml_group_kdes(sm, pos, KDE_ALL_LINKS);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004734#endif /* CONFIG_IEEE80211BE */
4735
4736 return pos;
4737}
4738
4739
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004740SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
4741{
Hai Shaloma20dcd72022-02-04 13:43:00 -08004742 u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, stub_gtk[32];
Sunil Ravia04bd252022-05-02 22:54:18 -07004743 size_t gtk_len, kde_len = 0, wpa_ie_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004744 struct wpa_group *gsm = sm->group;
4745 u8 *wpa_ie;
Hai Shalomfdcde762020-04-02 11:19:20 -07004746 int secure, gtkidx, encr = 0;
Sunil Ravi7f769292024-07-23 22:21:32 +00004747 u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL, *wpa_ie_buf3 = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07004748 u8 hdr[2];
4749 struct wpa_auth_config *conf = &sm->wpa_auth->conf;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004750#ifdef CONFIG_IEEE80211BE
4751 bool is_mld = sm->mld_assoc_link_id >= 0;
4752#else /* CONFIG_IEEE80211BE */
4753 bool is_mld = false;
4754#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004755
4756 SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
Hai Shalome21d4e82020-04-29 16:34:06 -07004757 sm->TimeoutEvt = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004758
4759 sm->TimeoutCtr++;
Hai Shalomfdcde762020-04-02 11:19:20 -07004760 if (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004761 /* Do not allow retransmission of EAPOL-Key msg 3/4 */
4762 return;
4763 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004764 if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004765 /* No point in sending the EAPOL-Key - we will disconnect
4766 * immediately following this. */
4767 return;
4768 }
4769
4770 /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
Hai Shalomfdcde762020-04-02 11:19:20 -07004771 GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004772 */
4773 os_memset(rsc, 0, WPA_KEY_RSC_LEN);
4774 wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
4775 /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
4776 wpa_ie = sm->wpa_auth->wpa_ie;
4777 wpa_ie_len = sm->wpa_auth->wpa_ie_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07004778 if (sm->wpa == WPA_VERSION_WPA && (conf->wpa & WPA_PROTO_RSN) &&
4779 wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004780 /* WPA-only STA, remove RSN IE and possible MDIE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004781 wpa_ie = wpa_ie + wpa_ie[1] + 2;
Hai Shalom60840252021-02-19 19:02:11 -08004782 if (wpa_ie[0] == WLAN_EID_RSNX)
4783 wpa_ie = wpa_ie + wpa_ie[1] + 2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004784 if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
4785 wpa_ie = wpa_ie + wpa_ie[1] + 2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004786 wpa_ie_len = wpa_ie[1] + 2;
4787 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00004788 if ((conf->rsn_override_key_mgmt || conf->rsn_override_key_mgmt_2) &&
4789 !rsn_is_snonce_cookie(sm->SNonce)) {
4790 u8 *ie;
4791 size_t ie_len;
4792 u32 ids[] = {
4793 RSNE_OVERRIDE_IE_VENDOR_TYPE,
4794 RSNE_OVERRIDE_2_IE_VENDOR_TYPE,
4795 RSNXE_OVERRIDE_IE_VENDOR_TYPE,
4796 0
4797 };
4798 int i;
Sunil Ravi7f769292024-07-23 22:21:32 +00004799
4800 wpa_printf(MSG_DEBUG,
Sunil Ravic0f5d412024-09-11 22:12:49 +00004801 "RSN: Remove RSNE/RSNXE override elements");
Sunil Ravi7f769292024-07-23 22:21:32 +00004802 wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs before edits",
4803 wpa_ie, wpa_ie_len);
Sunil Ravic0f5d412024-09-11 22:12:49 +00004804 wpa_ie_buf3 = os_memdup(wpa_ie, wpa_ie_len);
Sunil Ravi7f769292024-07-23 22:21:32 +00004805 if (!wpa_ie_buf3)
4806 goto done;
Sunil Ravi7f769292024-07-23 22:21:32 +00004807 wpa_ie = wpa_ie_buf3;
Sunil Ravic0f5d412024-09-11 22:12:49 +00004808
4809 for (i = 0; ids[i]; i++) {
4810 ie = (u8 *) get_vendor_ie(wpa_ie, wpa_ie_len, ids[i]);
4811 if (ie) {
4812 ie_len = 2 + ie[1];
4813 os_memmove(ie, ie + ie_len,
4814 wpa_ie_len - (ie + ie_len - wpa_ie));
4815 wpa_ie_len -= ie_len;
4816 }
4817 }
Sunil Ravi7f769292024-07-23 22:21:32 +00004818 wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs after edits",
4819 wpa_ie, wpa_ie_len);
4820 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004821#ifdef CONFIG_TESTING_OPTIONS
Hai Shalomfdcde762020-04-02 11:19:20 -07004822 if (conf->rsne_override_eapol_set) {
4823 wpa_ie_buf2 = replace_ie(
4824 "RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN,
4825 conf->rsne_override_eapol,
4826 conf->rsne_override_eapol_len);
4827 if (!wpa_ie_buf2)
4828 goto done;
4829 wpa_ie = wpa_ie_buf2;
4830 }
4831 if (conf->rsnxe_override_eapol_set) {
4832 wpa_ie_buf = replace_ie(
4833 "RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX,
4834 conf->rsnxe_override_eapol,
4835 conf->rsnxe_override_eapol_len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004836 if (!wpa_ie_buf)
Hai Shalomfdcde762020-04-02 11:19:20 -07004837 goto done;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004838 wpa_ie = wpa_ie_buf;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004839 }
4840#endif /* CONFIG_TESTING_OPTIONS */
Sunil Raviaf8751c2023-03-29 11:35:17 -07004841 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004842 "sending 3/4 msg of 4-Way Handshake");
4843 if (sm->wpa == WPA_VERSION_WPA2) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004844 if (sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
4845 wpa_auth_set_key(sm->wpa_auth, 0,
4846 wpa_cipher_to_alg(sm->pairwise),
4847 sm->addr,
4848 sm->keyidx_active, sm->PTK.tk,
4849 wpa_cipher_key_len(sm->pairwise),
4850 KEY_FLAG_PAIRWISE_RX)) {
4851 wpa_sta_disconnect(sm->wpa_auth, sm->addr,
4852 WLAN_REASON_PREV_AUTH_NOT_VALID);
4853 return;
4854 }
4855
Sunil Ravi876a49b2025-02-03 19:18:32 +00004856 if (!sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
4857 wpa_auth_set_key(sm->wpa_auth, 0,
4858 wpa_cipher_to_alg(sm->pairwise),
4859 sm->addr, 0, sm->PTK.tk,
4860 wpa_cipher_key_len(sm->pairwise),
4861 KEY_FLAG_PAIRWISE_NEXT)) {
4862 /* Continue anyway since the many drivers do not support
4863 * configuration of the TK for RX-only purposes for
4864 * cases where multiple keys might be in use in parallel
4865 * and this being an optional optimization to avoid race
4866 * condition during TK changes that could result in some
4867 * protected frames getting discarded. */
4868 }
4869
Sunil Ravi89eba102022-09-13 21:04:37 -07004870#ifdef CONFIG_PASN
4871 if (sm->wpa_auth->conf.secure_ltf &&
4872 ieee802_11_rsnx_capab(sm->rsnxe,
4873 WLAN_RSNX_CAPAB_SECURE_LTF) &&
4874 wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr,
4875 sm->PTK.ltf_keyseed,
4876 sm->PTK.ltf_keyseed_len)) {
4877 wpa_printf(MSG_ERROR,
4878 "WPA: Failed to set LTF keyseed to driver");
4879 wpa_sta_disconnect(sm->wpa_auth, sm->addr,
4880 WLAN_REASON_PREV_AUTH_NOT_VALID);
4881 return;
4882 }
4883#endif /* CONFIG_PASN */
4884
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004885 /* WPA2 send GTK in the 4-way handshake */
4886 secure = 1;
4887 gtk = gsm->GTK[gsm->GN - 1];
4888 gtk_len = gsm->GTK_len;
Sunil Ravi876a49b2025-02-03 19:18:32 +00004889 if (conf->disable_gtk) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004890 /*
4891 * Provide unique random GTK to each STA to prevent use
4892 * of GTK in the BSS.
4893 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08004894 if (random_get_bytes(stub_gtk, gtk_len) < 0)
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004895 goto done;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004896 gtk = stub_gtk;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004897 }
Hai Shalomc3565922019-10-28 11:58:20 -07004898 gtkidx = gsm->GN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004899 _rsc = rsc;
4900 encr = 1;
4901 } else {
4902 /* WPA does not include GTK in msg 3/4 */
4903 secure = 0;
4904 gtk = NULL;
4905 gtk_len = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004906 gtkidx = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004907 _rsc = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004908 if (sm->rx_eapol_key_secure) {
4909 /*
4910 * It looks like Windows 7 supplicant tries to use
4911 * Secure bit in msg 2/4 after having reported Michael
4912 * MIC failure and it then rejects the 4-way handshake
4913 * if msg 3/4 does not set Secure bit. Work around this
4914 * by setting the Secure bit here even in the case of
4915 * WPA if the supplicant used it first.
4916 */
Sunil Raviaf8751c2023-03-29 11:35:17 -07004917 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
4918 LOGGER_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07004919 "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004920 secure = 1;
4921 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004922 }
4923
Hai Shalom74f70d42019-02-11 14:42:39 -08004924 kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
Hai Shalomfdcde762020-04-02 11:19:20 -07004925
4926 if (sm->use_ext_key_id)
4927 kde_len += 2 + RSN_SELECTOR_LEN + 2;
4928
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004929 if (gtk)
4930 kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004931#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004932 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
4933 kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
4934 kde_len += 300; /* FTIE + 2 * TIE */
4935 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004936#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08004937#ifdef CONFIG_P2P
4938 if (WPA_GET_BE32(sm->ip_addr) > 0)
4939 kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
4940#endif /* CONFIG_P2P */
Hai Shalomfdcde762020-04-02 11:19:20 -07004941
4942 if (conf->transition_disable)
4943 kde_len += 2 + RSN_SELECTOR_LEN + 1;
4944
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004945#ifdef CONFIG_DPP2
4946 if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP)
4947 kde_len += 2 + RSN_SELECTOR_LEN + 2;
4948#endif /* CONFIG_DPP2 */
4949
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004950 kde_len += wpa_auth_ml_kdes_len(sm);
4951
Sunil Ravi7f769292024-07-23 22:21:32 +00004952 if (sm->ssid_protection)
4953 kde_len += 2 + conf->ssid_len;
4954
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004955#ifdef CONFIG_TESTING_OPTIONS
4956 if (conf->eapol_m3_elements)
4957 kde_len += wpabuf_len(conf->eapol_m3_elements);
4958#endif /* CONFIG_TESTING_OPTIONS */
4959
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004960 kde = os_malloc(kde_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07004961 if (!kde)
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004962 goto done;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004963
4964 pos = kde;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004965 if (!is_mld) {
4966 os_memcpy(pos, wpa_ie, wpa_ie_len);
4967 pos += wpa_ie_len;
4968 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004969#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004970 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08004971 int res;
4972 size_t elen;
4973
4974 elen = pos - kde;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004975 res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004976 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07004977 wpa_printf(MSG_ERROR,
4978 "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004979 goto done;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004980 }
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08004981 pos -= wpa_ie_len;
4982 pos += elen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004983 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08004984#endif /* CONFIG_IEEE80211R_AP */
Hai Shalomfdcde762020-04-02 11:19:20 -07004985 hdr[1] = 0;
4986
4987 if (sm->use_ext_key_id) {
4988 hdr[0] = sm->keyidx_active & 0x01;
4989 pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
4990 }
4991
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004992 if (gtk && !is_mld) {
Hai Shalomc3565922019-10-28 11:58:20 -07004993 hdr[0] = gtkidx & 0x03;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004994 pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
4995 gtk, gtk_len);
4996 }
4997 pos = ieee80211w_kde_add(sm, pos);
Hai Shalom899fcc72020-10-19 14:38:18 -07004998 if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0)
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004999 goto done;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005000
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005001#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005002 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
5003 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005004
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08005005 if (sm->assoc_resp_ftie &&
5006 kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
5007 os_memcpy(pos, sm->assoc_resp_ftie,
5008 2 + sm->assoc_resp_ftie[1]);
5009 res = 2 + sm->assoc_resp_ftie[1];
5010 } else {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00005011 res = wpa_write_ftie(conf, sm->wpa_key_mgmt,
5012 sm->xxkey_len,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005013 conf->r0_key_holder,
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08005014 conf->r0_key_holder_len,
5015 NULL, NULL, pos,
5016 kde + kde_len - pos,
Hai Shalomfdcde762020-04-02 11:19:20 -07005017 NULL, 0, 0);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08005018 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005019 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005020 wpa_printf(MSG_ERROR,
5021 "FT: Failed to insert FTIE into EAPOL-Key Key Data");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005022 goto done;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005023 }
5024 pos += res;
5025
5026 /* TIE[ReassociationDeadline] (TU) */
5027 *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
5028 *pos++ = 5;
5029 *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
5030 WPA_PUT_LE32(pos, conf->reassociation_deadline);
5031 pos += 4;
5032
5033 /* TIE[KeyLifetime] (seconds) */
5034 *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
5035 *pos++ = 5;
5036 *pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
Roshan Pius3a1667e2018-07-03 15:17:14 -07005037 WPA_PUT_LE32(pos, conf->r0_key_lifetime);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005038 pos += 4;
5039 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005040#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005041#ifdef CONFIG_P2P
5042 if (WPA_GET_BE32(sm->ip_addr) > 0) {
5043 u8 addr[3 * 4];
5044 os_memcpy(addr, sm->ip_addr, 4);
Hai Shalomfdcde762020-04-02 11:19:20 -07005045 os_memcpy(addr + 4, conf->ip_addr_mask, 4);
5046 os_memcpy(addr + 8, conf->ip_addr_go, 4);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005047 pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
5048 addr, sizeof(addr), NULL, 0);
5049 }
5050#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005051
Hai Shalomfdcde762020-04-02 11:19:20 -07005052 if (conf->transition_disable)
5053 pos = wpa_add_kde(pos, WFA_KEY_DATA_TRANSITION_DISABLE,
5054 &conf->transition_disable, 1, NULL, 0);
5055
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005056#ifdef CONFIG_DPP2
5057 if (DPP_VERSION > 1 && sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
5058 u8 payload[2];
5059
5060 payload[0] = DPP_VERSION; /* Protocol Version */
5061 payload[1] = 0; /* Flags */
5062 if (conf->dpp_pfs == 0)
5063 payload[1] |= DPP_KDE_PFS_ALLOWED;
5064 else if (conf->dpp_pfs == 1)
5065 payload[1] |= DPP_KDE_PFS_ALLOWED |
5066 DPP_KDE_PFS_REQUIRED;
5067 pos = wpa_add_kde(pos, WFA_KEY_DATA_DPP,
5068 payload, sizeof(payload), NULL, 0);
5069 }
5070#endif /* CONFIG_DPP2 */
5071
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005072 pos = wpa_auth_ml_kdes(sm, pos);
Sunil Ravic0f5d412024-09-11 22:12:49 +00005073 if (!pos) {
5074 wpa_printf(MSG_ERROR, "RSN: Failed to add MLO KDEs");
5075 goto done;
5076 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005077
Sunil Ravi7f769292024-07-23 22:21:32 +00005078 if (sm->ssid_protection) {
5079 *pos++ = WLAN_EID_SSID;
5080 *pos++ = conf->ssid_len;
5081 os_memcpy(pos, conf->ssid, conf->ssid_len);
5082 pos += conf->ssid_len;
5083 }
5084
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005085#ifdef CONFIG_TESTING_OPTIONS
5086 if (conf->eapol_m3_elements) {
5087 os_memcpy(pos, wpabuf_head(conf->eapol_m3_elements),
5088 wpabuf_len(conf->eapol_m3_elements));
5089 pos += wpabuf_len(conf->eapol_m3_elements);
5090 }
5091
5092 if (conf->eapol_m3_no_encrypt)
5093 encr = 0;
5094#endif /* CONFIG_TESTING_OPTIONS */
5095
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005096 wpa_send_eapol(sm->wpa_auth, sm,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005097 (secure ? WPA_KEY_INFO_SECURE : 0) |
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005098 (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
5099 WPA_KEY_INFO_MIC : 0) |
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005100 WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
5101 WPA_KEY_INFO_KEY_TYPE,
Hai Shalomc3565922019-10-28 11:58:20 -07005102 _rsc, sm->ANonce, kde, pos - kde, 0, encr);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005103done:
Sunil Ravia04bd252022-05-02 22:54:18 -07005104 bin_clear_free(kde, kde_len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08005105 os_free(wpa_ie_buf);
Hai Shalomfdcde762020-04-02 11:19:20 -07005106 os_free(wpa_ie_buf2);
Sunil Ravi7f769292024-07-23 22:21:32 +00005107 os_free(wpa_ie_buf3);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005108}
5109
5110
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005111static int wpa_auth_validate_ml_kdes_m4(struct wpa_state_machine *sm)
5112{
5113#ifdef CONFIG_IEEE80211BE
5114 const struct ieee802_1x_hdr *hdr;
5115 const struct wpa_eapol_key *key;
5116 struct wpa_eapol_ie_parse kde;
5117 const u8 *key_data, *mic;
5118 u16 key_data_length;
5119 size_t mic_len;
5120
5121 if (sm->mld_assoc_link_id < 0)
5122 return 0;
5123
5124 /*
5125 * Note: last_rx_eapol_key length fields have already been validated in
5126 * wpa_receive().
5127 */
5128 mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
5129
5130 hdr = (const struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
5131 key = (const struct wpa_eapol_key *) (hdr + 1);
5132 mic = (const u8 *) (key + 1);
5133 key_data = mic + mic_len + 2;
5134 key_data_length = WPA_GET_BE16(mic + mic_len);
5135 if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
5136 sizeof(*key) - mic_len - 2)
5137 return -1;
5138
5139 if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
5140 wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm),
5141 LOGGER_INFO,
5142 "received EAPOL-Key msg 4/4 with invalid Key Data contents");
5143 return -1;
5144 }
5145
5146 /* MLD MAC address must be the same */
5147 if (!kde.mac_addr ||
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005148 !ether_addr_equal(kde.mac_addr, sm->peer_mld_addr)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005149 wpa_printf(MSG_DEBUG,
5150 "MLD: Mismatching or missing MLD address in EAPOL-Key msg 4/4");
5151 return -1;
5152 }
5153
5154 wpa_printf(MSG_DEBUG, "MLD: MLD address in EAPOL-Key msg 4/4: " MACSTR,
5155 MAC2STR(kde.mac_addr));
5156#endif /* CONFIG_IEEE80211BE */
5157
5158 return 0;
5159}
5160
5161
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005162SM_STATE(WPA_PTK, PTKINITDONE)
5163{
5164 SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
Hai Shalome21d4e82020-04-29 16:34:06 -07005165 sm->EAPOLKeyReceived = false;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005166
5167 if (wpa_auth_validate_ml_kdes_m4(sm) < 0) {
5168 wpa_sta_disconnect(sm->wpa_auth, sm->addr,
5169 WLAN_REASON_PREV_AUTH_NOT_VALID);
5170 return;
5171 }
5172
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005173 if (sm->Pair) {
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07005174 enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
5175 int klen = wpa_cipher_key_len(sm->pairwise);
Hai Shalomfdcde762020-04-02 11:19:20 -07005176 int res;
5177
5178 if (sm->use_ext_key_id)
5179 res = wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
5180 sm->keyidx_active, NULL, 0,
5181 KEY_FLAG_PAIRWISE_RX_TX_MODIFY);
5182 else
5183 res = wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr,
5184 0, sm->PTK.tk, klen,
5185 KEY_FLAG_PAIRWISE_RX_TX);
5186 if (res) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005187 wpa_sta_disconnect(sm->wpa_auth, sm->addr,
5188 WLAN_REASON_PREV_AUTH_NOT_VALID);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005189 return;
5190 }
Sunil Ravi89eba102022-09-13 21:04:37 -07005191
5192#ifdef CONFIG_PASN
5193 if (sm->wpa_auth->conf.secure_ltf &&
5194 ieee802_11_rsnx_capab(sm->rsnxe,
5195 WLAN_RSNX_CAPAB_SECURE_LTF) &&
5196 wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr,
5197 sm->PTK.ltf_keyseed,
5198 sm->PTK.ltf_keyseed_len)) {
5199 wpa_printf(MSG_ERROR,
5200 "WPA: Failed to set LTF keyseed to driver");
5201 wpa_sta_disconnect(sm->wpa_auth, sm->addr,
5202 WLAN_REASON_PREV_AUTH_NOT_VALID);
5203 return;
5204 }
5205#endif /* CONFIG_PASN */
5206
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005207 /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
Hai Shalome21d4e82020-04-29 16:34:06 -07005208 sm->pairwise_set = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005209
Hai Shalom81f62d82019-07-22 12:10:00 -07005210 wpa_auth_set_ptk_rekey_timer(sm);
Hai Shalom60840252021-02-19 19:02:11 -08005211 wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
5212 dot11RSNAConfigPMKLifetime, &sm->PTK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005213
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005214 if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
5215 sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
5216 sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005217 wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
5218 WPA_EAPOL_authorized, 1);
5219 }
5220 }
5221
5222 if (0 /* IBSS == TRUE */) {
5223 sm->keycount++;
5224 if (sm->keycount == 2) {
5225 wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
5226 WPA_EAPOL_portValid, 1);
5227 }
5228 } else {
5229 wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
5230 1);
5231 }
Hai Shalome21d4e82020-04-29 16:34:06 -07005232 wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable,
5233 false);
5234 wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005235 if (sm->wpa == WPA_VERSION_WPA)
Hai Shalome21d4e82020-04-29 16:34:06 -07005236 sm->PInitAKeys = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005237 else
Hai Shalome21d4e82020-04-29 16:34:06 -07005238 sm->has_GTK = true;
Sunil Raviaf8751c2023-03-29 11:35:17 -07005239 wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005240 "pairwise key handshake completed (%s)",
5241 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
Hai Shaloma20dcd72022-02-04 13:43:00 -08005242 wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO, "EAPOL-4WAY-HS-COMPLETED "
5243 MACSTR, MAC2STR(sm->addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005244
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005245#ifdef CONFIG_IEEE80211R_AP
Sunil Raviaf8751c2023-03-29 11:35:17 -07005246 wpa_ft_push_pmk_r1(sm->wpa_auth, wpa_auth_get_spa(sm));
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005247#endif /* CONFIG_IEEE80211R_AP */
Sunil Ravia04bd252022-05-02 22:54:18 -07005248
5249 sm->ptkstart_without_success = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005250}
5251
5252
5253SM_STEP(WPA_PTK)
5254{
5255 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
Hai Shalomfdcde762020-04-02 11:19:20 -07005256 struct wpa_auth_config *conf = &wpa_auth->conf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005257
5258 if (sm->Init)
5259 SM_ENTER(WPA_PTK, INITIALIZE);
5260 else if (sm->Disconnect
5261 /* || FIX: dot11RSNAConfigSALifetime timeout */) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07005262 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005263 "WPA_PTK: sm->Disconnect");
5264 SM_ENTER(WPA_PTK, DISCONNECT);
5265 }
5266 else if (sm->DeauthenticationRequest)
5267 SM_ENTER(WPA_PTK, DISCONNECTED);
5268 else if (sm->AuthenticationRequest)
5269 SM_ENTER(WPA_PTK, AUTHENTICATION);
5270 else if (sm->ReAuthenticationRequest)
5271 SM_ENTER(WPA_PTK, AUTHENTICATION2);
Jouni Malinen1420a892017-10-01 12:32:57 +03005272 else if (sm->PTKRequest) {
5273 if (wpa_auth_sm_ptk_update(sm) < 0)
5274 SM_ENTER(WPA_PTK, DISCONNECTED);
5275 else
5276 SM_ENTER(WPA_PTK, PTKSTART);
5277 } else switch (sm->wpa_ptk_state) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005278 case WPA_PTK_INITIALIZE:
5279 break;
5280 case WPA_PTK_DISCONNECT:
5281 SM_ENTER(WPA_PTK, DISCONNECTED);
5282 break;
5283 case WPA_PTK_DISCONNECTED:
5284 SM_ENTER(WPA_PTK, INITIALIZE);
5285 break;
5286 case WPA_PTK_AUTHENTICATION:
5287 SM_ENTER(WPA_PTK, AUTHENTICATION2);
5288 break;
5289 case WPA_PTK_AUTHENTICATION2:
5290 if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
Hai Shalomfdcde762020-04-02 11:19:20 -07005291 wpa_auth_get_eapol(wpa_auth, sm->addr,
Hai Shalome21d4e82020-04-29 16:34:06 -07005292 WPA_EAPOL_keyRun))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005293 SM_ENTER(WPA_PTK, INITPMK);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005294 else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
5295 sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005296 /* FIX: && 802.1X::keyRun */)
5297 SM_ENTER(WPA_PTK, INITPSK);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005298 else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP)
5299 SM_ENTER(WPA_PTK, INITPMK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005300 break;
5301 case WPA_PTK_INITPMK:
Hai Shalomfdcde762020-04-02 11:19:20 -07005302 if (wpa_auth_get_eapol(wpa_auth, sm->addr,
Hai Shalome21d4e82020-04-29 16:34:06 -07005303 WPA_EAPOL_keyAvailable)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005304 SM_ENTER(WPA_PTK, PTKSTART);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005305#ifdef CONFIG_DPP
5306 } else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->pmksa) {
5307 SM_ENTER(WPA_PTK, PTKSTART);
5308#endif /* CONFIG_DPP */
5309 } else {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005310 wpa_auth->dot11RSNA4WayHandshakeFailures++;
Sunil Raviaf8751c2023-03-29 11:35:17 -07005311 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
5312 LOGGER_INFO,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005313 "INITPMK - keyAvailable = false");
5314 SM_ENTER(WPA_PTK, DISCONNECT);
5315 }
5316 break;
5317 case WPA_PTK_INITPSK:
Hai Shalomfdcde762020-04-02 11:19:20 -07005318 if (wpa_auth_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
Hai Shalom021b0b52019-04-10 11:17:58 -07005319 NULL, NULL, NULL)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005320 SM_ENTER(WPA_PTK, PTKSTART);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005321#ifdef CONFIG_SAE
5322 } else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
5323 SM_ENTER(WPA_PTK, PTKSTART);
5324#endif /* CONFIG_SAE */
Sunil Ravia04bd252022-05-02 22:54:18 -07005325 } else if (wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
5326 wpa_auth->conf.radius_psk) {
5327 wpa_printf(MSG_DEBUG,
5328 "INITPSK: No PSK yet available for STA - use RADIUS later");
5329 SM_ENTER(WPA_PTK, PTKSTART);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005330 } else {
Sunil Raviaf8751c2023-03-29 11:35:17 -07005331 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
5332 LOGGER_INFO,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005333 "no PSK configured for the STA");
5334 wpa_auth->dot11RSNA4WayHandshakeFailures++;
5335 SM_ENTER(WPA_PTK, DISCONNECT);
5336 }
5337 break;
5338 case WPA_PTK_PTKSTART:
5339 if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
5340 sm->EAPOLKeyPairwise)
5341 SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
Hai Shalomfdcde762020-04-02 11:19:20 -07005342 else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005343 wpa_auth->dot11RSNA4WayHandshakeFailures++;
Sunil Raviaf8751c2023-03-29 11:35:17 -07005344 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
5345 LOGGER_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07005346 "PTKSTART: Retry limit %u reached",
5347 conf->wpa_pairwise_update_count);
Hai Shalome21d4e82020-04-29 16:34:06 -07005348 sm->disconnect_reason =
5349 WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005350 SM_ENTER(WPA_PTK, DISCONNECT);
5351 } else if (sm->TimeoutEvt)
5352 SM_ENTER(WPA_PTK, PTKSTART);
5353 break;
5354 case WPA_PTK_PTKCALCNEGOTIATING:
5355 if (sm->MICVerified)
5356 SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2);
5357 else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
5358 sm->EAPOLKeyPairwise)
5359 SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
5360 else if (sm->TimeoutEvt)
5361 SM_ENTER(WPA_PTK, PTKSTART);
5362 break;
5363 case WPA_PTK_PTKCALCNEGOTIATING2:
5364 SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
5365 break;
5366 case WPA_PTK_PTKINITNEGOTIATING:
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005367 if (sm->update_snonce)
5368 SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
5369 else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
5370 sm->EAPOLKeyPairwise && sm->MICVerified)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005371 SM_ENTER(WPA_PTK, PTKINITDONE);
5372 else if (sm->TimeoutCtr >
Hai Shalomfdcde762020-04-02 11:19:20 -07005373 conf->wpa_pairwise_update_count ||
5374 (conf->wpa_disable_eapol_key_retries &&
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005375 sm->TimeoutCtr > 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005376 wpa_auth->dot11RSNA4WayHandshakeFailures++;
Sunil Raviaf8751c2023-03-29 11:35:17 -07005377 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
5378 LOGGER_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07005379 "PTKINITNEGOTIATING: Retry limit %u reached",
5380 conf->wpa_pairwise_update_count);
Hai Shalome21d4e82020-04-29 16:34:06 -07005381 sm->disconnect_reason =
5382 WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005383 SM_ENTER(WPA_PTK, DISCONNECT);
5384 } else if (sm->TimeoutEvt)
5385 SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
5386 break;
5387 case WPA_PTK_PTKINITDONE:
5388 break;
5389 }
5390}
5391
5392
5393SM_STATE(WPA_PTK_GROUP, IDLE)
5394{
5395 SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group);
5396 if (sm->Init) {
5397 /* Init flag is not cleared here, so avoid busy
5398 * loop by claiming nothing changed. */
Hai Shalome21d4e82020-04-29 16:34:06 -07005399 sm->changed = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005400 }
5401 sm->GTimeoutCtr = 0;
5402}
5403
5404
5405SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
5406{
5407 u8 rsc[WPA_KEY_RSC_LEN];
5408 struct wpa_group *gsm = sm->group;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005409 const u8 *kde = NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005410 u8 *kde_buf = NULL, *pos, hdr[2];
Sunil Ravia04bd252022-05-02 22:54:18 -07005411 size_t kde_len = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005412 u8 *gtk, stub_gtk[32];
Hai Shalomfdcde762020-04-02 11:19:20 -07005413 struct wpa_auth_config *conf = &sm->wpa_auth->conf;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005414 bool is_mld = false;
5415
5416#ifdef CONFIG_IEEE80211BE
5417 is_mld = sm->mld_assoc_link_id >= 0;
5418#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005419
5420 SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
5421
5422 sm->GTimeoutCtr++;
Hai Shalomfdcde762020-04-02 11:19:20 -07005423 if (conf->wpa_disable_eapol_key_retries && sm->GTimeoutCtr > 1) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005424 /* Do not allow retransmission of EAPOL-Key group msg 1/2 */
5425 return;
5426 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005427 if (sm->GTimeoutCtr > conf->wpa_group_update_count) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005428 /* No point in sending the EAPOL-Key - we will disconnect
5429 * immediately following this. */
5430 return;
5431 }
5432
5433 if (sm->wpa == WPA_VERSION_WPA)
Hai Shalome21d4e82020-04-29 16:34:06 -07005434 sm->PInitAKeys = false;
5435 sm->TimeoutEvt = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005436 /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
5437 os_memset(rsc, 0, WPA_KEY_RSC_LEN);
5438 if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
5439 wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
Sunil Raviaf8751c2023-03-29 11:35:17 -07005440 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005441 "sending 1/2 msg of Group Key Handshake");
5442
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005443 gtk = gsm->GTK[gsm->GN - 1];
Sunil Ravi876a49b2025-02-03 19:18:32 +00005444 if (conf->disable_gtk) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005445 /*
5446 * Provide unique random GTK to each STA to prevent use
5447 * of GTK in the BSS.
5448 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08005449 if (random_get_bytes(stub_gtk, gsm->GTK_len) < 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005450 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005451 gtk = stub_gtk;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005452 }
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005453
5454 if (sm->wpa == WPA_VERSION_WPA2 && !is_mld) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005455 kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
Hai Shalom74f70d42019-02-11 14:42:39 -08005456 ieee80211w_kde_len(sm) + ocv_oci_len(sm);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005457 kde_buf = os_malloc(kde_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07005458 if (!kde_buf)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005459 return;
5460
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005461 kde = pos = kde_buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005462 hdr[0] = gsm->GN & 0x03;
5463 hdr[1] = 0;
5464 pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005465 gtk, gsm->GTK_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005466 pos = ieee80211w_kde_add(sm, pos);
Hai Shalom899fcc72020-10-19 14:38:18 -07005467 if (ocv_oci_add(sm, &pos,
5468 conf->oci_freq_override_eapol_g1) < 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08005469 os_free(kde_buf);
5470 return;
5471 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005472 kde_len = pos - kde;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005473#ifdef CONFIG_IEEE80211BE
5474 } else if (sm->wpa == WPA_VERSION_WPA2 && is_mld) {
Sunil Ravi876a49b2025-02-03 19:18:32 +00005475 kde_len = wpa_auth_ml_group_kdes_len(sm, KDE_ALL_LINKS);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005476 if (kde_len) {
5477 kde_buf = os_malloc(kde_len);
5478 if (!kde_buf)
5479 return;
5480
5481 kde = pos = kde_buf;
Sunil Ravi876a49b2025-02-03 19:18:32 +00005482 pos = wpa_auth_ml_group_kdes(sm, pos, KDE_ALL_LINKS);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005483 kde_len = pos - kde_buf;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00005484 }
5485#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005486 } else {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005487 kde = gtk;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005488 kde_len = gsm->GTK_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005489 }
5490
5491 wpa_send_eapol(sm->wpa_auth, sm,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08005492 WPA_KEY_INFO_SECURE |
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005493 (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
5494 WPA_KEY_INFO_MIC : 0) |
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005495 WPA_KEY_INFO_ACK |
5496 (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005497 rsc, NULL, kde, kde_len, gsm->GN, 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005498
Sunil Ravia04bd252022-05-02 22:54:18 -07005499 bin_clear_free(kde_buf, kde_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005500}
5501
5502
5503SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
5504{
Hai Shalom74f70d42019-02-11 14:42:39 -08005505 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
Hai Shalomfdcde762020-04-02 11:19:20 -07005506#ifdef CONFIG_OCV
Hai Shalom74f70d42019-02-11 14:42:39 -08005507 const u8 *key_data, *mic;
5508 struct ieee802_1x_hdr *hdr;
5509 struct wpa_eapol_key *key;
5510 struct wpa_eapol_ie_parse kde;
5511 size_t mic_len;
5512 u16 key_data_length;
5513#endif /* CONFIG_OCV */
5514
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005515 SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
Hai Shalome21d4e82020-04-29 16:34:06 -07005516 sm->EAPOLKeyReceived = false;
Hai Shalom74f70d42019-02-11 14:42:39 -08005517
5518#ifdef CONFIG_OCV
5519 mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
5520
5521 /*
5522 * Note: last_rx_eapol_key length fields have already been validated in
5523 * wpa_receive().
5524 */
5525 hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
5526 key = (struct wpa_eapol_key *) (hdr + 1);
5527 mic = (u8 *) (key + 1);
5528 key_data = mic + mic_len + 2;
5529 key_data_length = WPA_GET_BE16(mic + mic_len);
5530 if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
5531 sizeof(*key) - mic_len - 2)
5532 return;
5533
5534 if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07005535 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Hai Shalom74f70d42019-02-11 14:42:39 -08005536 "received EAPOL-Key group msg 2/2 with invalid Key Data contents");
5537 return;
5538 }
5539
5540 if (wpa_auth_uses_ocv(sm)) {
5541 struct wpa_channel_info ci;
5542 int tx_chanwidth;
5543 int tx_seg1_idx;
5544
5545 if (wpa_channel_info(wpa_auth, &ci) != 0) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07005546 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
5547 LOGGER_INFO,
Hai Shalom899fcc72020-10-19 14:38:18 -07005548 "Failed to get channel info to validate received OCI in EAPOL-Key group 2/2");
Hai Shalom74f70d42019-02-11 14:42:39 -08005549 return;
5550 }
5551
5552 if (get_sta_tx_parameters(sm,
5553 channel_width_to_int(ci.chanwidth),
5554 ci.seg1_idx, &tx_chanwidth,
5555 &tx_seg1_idx) < 0)
5556 return;
5557
5558 if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
Hai Shalom899fcc72020-10-19 14:38:18 -07005559 tx_chanwidth, tx_seg1_idx) !=
5560 OCI_SUCCESS) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07005561 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
5562 LOGGER_INFO,
Hai Shalom899fcc72020-10-19 14:38:18 -07005563 "OCV failed: %s", ocv_errorstr);
5564 if (wpa_auth->conf.msg_ctx)
5565 wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
5566 OCV_FAILURE "addr=" MACSTR
5567 " frame=eapol-key-g2 error=%s",
Sunil Raviaf8751c2023-03-29 11:35:17 -07005568 MAC2STR(wpa_auth_get_spa(sm)),
5569 ocv_errorstr);
Hai Shalom74f70d42019-02-11 14:42:39 -08005570 return;
5571 }
5572 }
5573#endif /* CONFIG_OCV */
5574
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005575 if (sm->GUpdateStationKeys)
Sunil Ravi7f769292024-07-23 22:21:32 +00005576 wpa_gkeydone_sta(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005577 sm->GTimeoutCtr = 0;
5578 /* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
Sunil Raviaf8751c2023-03-29 11:35:17 -07005579 wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005580 "group key handshake completed (%s)",
5581 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
Hai Shalome21d4e82020-04-29 16:34:06 -07005582 sm->has_GTK = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005583}
5584
5585
5586SM_STATE(WPA_PTK_GROUP, KEYERROR)
5587{
5588 SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
5589 if (sm->GUpdateStationKeys)
Sunil Ravi7f769292024-07-23 22:21:32 +00005590 wpa_gkeydone_sta(sm);
5591 if (sm->wpa_auth->conf.no_disconnect_on_group_keyerror &&
5592 sm->wpa == WPA_VERSION_WPA2) {
5593 wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm),
5594 LOGGER_DEBUG,
5595 "group key handshake failed after %u tries - allow STA to remain connected",
5596 sm->wpa_auth->conf.wpa_group_update_count);
5597 return;
5598 }
Hai Shalome21d4e82020-04-29 16:34:06 -07005599 sm->Disconnect = true;
5600 sm->disconnect_reason = WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT;
Sunil Raviaf8751c2023-03-29 11:35:17 -07005601 wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08005602 "group key handshake failed (%s) after %u tries",
5603 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
5604 sm->wpa_auth->conf.wpa_group_update_count);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005605}
5606
5607
5608SM_STEP(WPA_PTK_GROUP)
5609{
5610 if (sm->Init || sm->PtkGroupInit) {
5611 SM_ENTER(WPA_PTK_GROUP, IDLE);
Hai Shalome21d4e82020-04-29 16:34:06 -07005612 sm->PtkGroupInit = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005613 } else switch (sm->wpa_ptk_group_state) {
5614 case WPA_PTK_GROUP_IDLE:
5615 if (sm->GUpdateStationKeys ||
5616 (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
5617 SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
5618 break;
5619 case WPA_PTK_GROUP_REKEYNEGOTIATING:
5620 if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
5621 !sm->EAPOLKeyPairwise && sm->MICVerified)
5622 SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
5623 else if (sm->GTimeoutCtr >
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005624 sm->wpa_auth->conf.wpa_group_update_count ||
5625 (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
5626 sm->GTimeoutCtr > 1))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005627 SM_ENTER(WPA_PTK_GROUP, KEYERROR);
5628 else if (sm->TimeoutEvt)
5629 SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
5630 break;
5631 case WPA_PTK_GROUP_KEYERROR:
5632 SM_ENTER(WPA_PTK_GROUP, IDLE);
5633 break;
5634 case WPA_PTK_GROUP_REKEYESTABLISHED:
5635 SM_ENTER(WPA_PTK_GROUP, IDLE);
5636 break;
5637 }
5638}
5639
5640
5641static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
5642 struct wpa_group *group)
5643{
Hai Shalomfdcde762020-04-02 11:19:20 -07005644 struct wpa_auth_config *conf = &wpa_auth->conf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005645 int ret = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07005646 size_t len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005647
5648 os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
5649 inc_byte_array(group->Counter, WPA_NONCE_LEN);
5650 if (wpa_gmk_to_gtk(group->GMK, "Group key expansion",
5651 wpa_auth->addr, group->GNonce,
5652 group->GTK[group->GN - 1], group->GTK_len) < 0)
5653 ret = -1;
5654 wpa_hexdump_key(MSG_DEBUG, "GTK",
5655 group->GTK[group->GN - 1], group->GTK_len);
5656
Sunil Ravi876a49b2025-02-03 19:18:32 +00005657 if (wpa_auth_pmf_enabled(conf)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005658 len = wpa_cipher_key_len(conf->group_mgmt_cipher);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005659 os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
5660 inc_byte_array(group->Counter, WPA_NONCE_LEN);
5661 if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
5662 wpa_auth->addr, group->GNonce,
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005663 group->IGTK[group->GN_igtk - 4], len) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005664 ret = -1;
5665 wpa_hexdump_key(MSG_DEBUG, "IGTK",
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005666 group->IGTK[group->GN_igtk - 4], len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005667 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005668
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005669 if (!wpa_auth->non_tx_beacon_prot &&
Sunil Ravi876a49b2025-02-03 19:18:32 +00005670 !wpa_auth_pmf_enabled(conf))
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005671 return ret;
5672 if (!conf->beacon_prot)
5673 return ret;
5674
5675 if (wpa_auth->conf.tx_bss_auth) {
5676 group = wpa_auth->conf.tx_bss_auth->group;
5677 if (group->bigtk_set)
5678 return ret;
5679 wpa_printf(MSG_DEBUG, "Set up BIGTK for TX BSS");
Hai Shalomfdcde762020-04-02 11:19:20 -07005680 }
5681
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005682 len = wpa_cipher_key_len(conf->group_mgmt_cipher);
5683 os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
5684 inc_byte_array(group->Counter, WPA_NONCE_LEN);
5685 if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
5686 wpa_auth->addr, group->GNonce,
5687 group->BIGTK[group->GN_bigtk - 6], len) < 0)
5688 return -1;
5689 group->bigtk_set = true;
5690 wpa_hexdump_key(MSG_DEBUG, "BIGTK",
5691 group->BIGTK[group->GN_bigtk - 6], len);
5692
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005693 return ret;
5694}
5695
5696
5697static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
5698 struct wpa_group *group)
5699{
Hai Shalomfdcde762020-04-02 11:19:20 -07005700 wpa_printf(MSG_DEBUG,
5701 "WPA: group state machine entering state GTK_INIT (VLAN-ID %d)",
5702 group->vlan_id);
Hai Shalome21d4e82020-04-29 16:34:06 -07005703 group->changed = false; /* GInit is not cleared here; avoid loop */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005704 group->wpa_group_state = WPA_GROUP_GTK_INIT;
5705
5706 /* GTK[0..N] = 0 */
5707 os_memset(group->GTK, 0, sizeof(group->GTK));
5708 group->GN = 1;
5709 group->GM = 2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005710 group->GN_igtk = 4;
5711 group->GM_igtk = 5;
Hai Shalomfdcde762020-04-02 11:19:20 -07005712 group->GN_bigtk = 6;
5713 group->GM_bigtk = 7;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005714 /* GTK[GN] = CalcGTK() */
5715 wpa_gtk_update(wpa_auth, group);
5716}
5717
5718
5719static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
5720{
Sunil Ravic0f5d412024-09-11 22:12:49 +00005721 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
5722 struct wpa_group *group = sm->group;
5723#ifdef CONFIG_IEEE80211BE
5724 int link_id;
5725
5726 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
5727 if (!sm->mld_links[link_id].valid)
5728 continue;
5729 if (sm->mld_links[link_id].wpa_auth &&
5730 sm->mld_links[link_id].wpa_auth->group == ctx) {
5731 group = sm->mld_links[link_id].wpa_auth->group;
5732 wpa_auth = sm->mld_links[link_id].wpa_auth;
5733 break;
5734 }
5735 }
5736#endif /* CONFIG_IEEE80211BE */
5737
5738 if (ctx && ctx != group)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005739 return 0;
5740
Sunil Ravic0f5d412024-09-11 22:12:49 +00005741#ifdef CONFIG_IEEE80211BE
5742 /* For ML STA, run rekey on the association link and send G1 with keys
5743 * for all links. This is based on assumption that MLD level
5744 * Authenticator updates group keys on all affiliated links in one shot
5745 * and not independently or concurrently for separate links. */
5746 if (sm->mld_assoc_link_id >= 0 &&
5747 sm->mld_assoc_link_id != wpa_auth->link_id)
5748 return 0;
5749#endif /* CONFIG_IEEE80211BE */
5750
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005751 if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
Sunil Ravic0f5d412024-09-11 22:12:49 +00005752 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
Sunil Raviaf8751c2023-03-29 11:35:17 -07005753 LOGGER_DEBUG,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005754 "Not in PTKINITDONE; skip Group Key update");
Hai Shalome21d4e82020-04-29 16:34:06 -07005755 sm->GUpdateStationKeys = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005756 return 0;
5757 }
5758 if (sm->GUpdateStationKeys) {
5759 /*
5760 * This should not really happen, so add a debug log entry.
5761 * Since we clear the GKeyDoneStations before the loop, the
5762 * station needs to be counted here anyway.
5763 */
Sunil Ravic0f5d412024-09-11 22:12:49 +00005764 wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
Sunil Raviaf8751c2023-03-29 11:35:17 -07005765 LOGGER_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07005766 "GUpdateStationKeys was already set when marking station for GTK rekeying");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005767 }
5768
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005769 /* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005770 if (sm->is_wnmsleep)
5771 return 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005772
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005773 sm->group->GKeyDoneStations++;
Sunil Ravic0f5d412024-09-11 22:12:49 +00005774#ifdef CONFIG_IEEE80211BE
5775 for_each_sm_auth(sm, link_id)
5776 sm->mld_links[link_id].wpa_auth->group->GKeyDoneStations++;
5777#endif /* CONFIG_IEEE80211BE */
5778
Hai Shalome21d4e82020-04-29 16:34:06 -07005779 sm->GUpdateStationKeys = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005780
5781 wpa_sm_step(sm);
5782 return 0;
5783}
5784
5785
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005786#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005787/* update GTK when exiting WNM-Sleep Mode */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005788void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
5789{
Hai Shalomfdcde762020-04-02 11:19:20 -07005790 if (!sm || sm->is_wnmsleep)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005791 return;
5792
5793 wpa_group_update_sta(sm, NULL);
5794}
5795
5796
5797void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
5798{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08005799 if (sm)
5800 sm->is_wnmsleep = !!flag;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005801}
5802
5803
5804int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
5805{
Hai Shalom899fcc72020-10-19 14:38:18 -07005806 struct wpa_auth_config *conf = &sm->wpa_auth->conf;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005807 struct wpa_group *gsm = sm->group;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005808 u8 *start = pos;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005809
5810 /*
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005811 * GTK subelement:
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005812 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005813 * Key[5..32]
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005814 */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005815 *pos++ = WNM_SLEEP_SUBELEM_GTK;
5816 *pos++ = 11 + gsm->GTK_len;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005817 /* Key ID in B0-B1 of Key Info */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005818 WPA_PUT_LE16(pos, gsm->GN & 0x03);
5819 pos += 2;
5820 *pos++ = gsm->GTK_len;
5821 if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005822 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005823 pos += 8;
5824 os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
Sunil Ravi876a49b2025-02-03 19:18:32 +00005825 if (conf->disable_gtk) {
Hai Shalom899fcc72020-10-19 14:38:18 -07005826 /*
5827 * Provide unique random GTK to each STA to prevent use
5828 * of GTK in the BSS.
5829 */
5830 if (random_get_bytes(pos, gsm->GTK_len) < 0)
5831 return 0;
5832 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005833 pos += gsm->GTK_len;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005834
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005835 wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
5836 gsm->GN);
5837 wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005838 gsm->GTK[gsm->GN - 1], gsm->GTK_len);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005839
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005840 return pos - start;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005841}
5842
5843
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005844int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
5845{
Hai Shalom899fcc72020-10-19 14:38:18 -07005846 struct wpa_auth_config *conf = &sm->wpa_auth->conf;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005847 struct wpa_group *gsm = sm->group;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005848 u8 *start = pos;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005849 size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005850
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005851 /*
5852 * IGTK subelement:
5853 * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
5854 */
5855 *pos++ = WNM_SLEEP_SUBELEM_IGTK;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005856 *pos++ = 2 + 6 + len;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005857 WPA_PUT_LE16(pos, gsm->GN_igtk);
5858 pos += 2;
5859 if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005860 return 0;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005861 pos += 6;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005862
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005863 os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
Sunil Ravi876a49b2025-02-03 19:18:32 +00005864 if (conf->disable_gtk) {
Hai Shalom899fcc72020-10-19 14:38:18 -07005865 /*
5866 * Provide unique random IGTK to each STA to prevent use
5867 * of IGTK in the BSS.
5868 */
5869 if (random_get_bytes(pos, len) < 0)
5870 return 0;
5871 }
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005872 pos += len;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005873
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005874 wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
5875 gsm->GN_igtk);
5876 wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005877 gsm->IGTK[gsm->GN_igtk - 4], len);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005878
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005879 return pos - start;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005880}
Hai Shalomc3565922019-10-28 11:58:20 -07005881
Hai Shalomfdcde762020-04-02 11:19:20 -07005882
5883int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
5884{
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005885 struct wpa_authenticator *wpa_auth = sm->wpa_auth;
5886 struct wpa_group *gsm = wpa_auth->group;
Hai Shalomfdcde762020-04-02 11:19:20 -07005887 u8 *start = pos;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005888 size_t len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
Hai Shalomfdcde762020-04-02 11:19:20 -07005889
5890 /*
5891 * BIGTK subelement:
5892 * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
5893 */
5894 *pos++ = WNM_SLEEP_SUBELEM_BIGTK;
5895 *pos++ = 2 + 6 + len;
5896 WPA_PUT_LE16(pos, gsm->GN_bigtk);
5897 pos += 2;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005898 if (wpa_auth_get_seqnum(wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
Hai Shalomfdcde762020-04-02 11:19:20 -07005899 return 0;
5900 pos += 6;
5901
5902 os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
5903 pos += len;
5904
5905 wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
5906 gsm->GN_bigtk);
5907 wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
Hai Shaloma20dcd72022-02-04 13:43:00 -08005908 gsm->BIGTK[gsm->GN_bigtk - 6], len);
Hai Shalomfdcde762020-04-02 11:19:20 -07005909
5910 return pos - start;
5911}
5912
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07005913#endif /* CONFIG_WNM_AP */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005914
5915
Sunil Ravi7f769292024-07-23 22:21:32 +00005916static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
5917 struct wpa_group *group)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005918{
5919 int tmp;
5920
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005921 tmp = group->GM;
5922 group->GM = group->GN;
5923 group->GN = tmp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005924 tmp = group->GM_igtk;
5925 group->GM_igtk = group->GN_igtk;
5926 group->GN_igtk = tmp;
Hai Shalomfdcde762020-04-02 11:19:20 -07005927 tmp = group->GM_bigtk;
5928 group->GM_bigtk = group->GN_bigtk;
5929 group->GN_bigtk = tmp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005930 /* "GKeyDoneStations = GNoStations" is done in more robust way by
5931 * counting the STAs that are marked with GUpdateStationKeys instead of
5932 * including all STAs that could be in not-yet-completed state. */
5933 wpa_gtk_update(wpa_auth, group);
Sunil Ravi7f769292024-07-23 22:21:32 +00005934}
5935
5936
5937static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
5938 struct wpa_group *group)
5939{
5940 wpa_printf(MSG_DEBUG,
5941 "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
5942 group->vlan_id);
5943 group->changed = true;
5944 group->wpa_group_state = WPA_GROUP_SETKEYS;
5945 group->GTKReKey = false;
5946
5947#ifdef CONFIG_IEEE80211BE
5948 if (wpa_auth->is_ml)
5949 goto skip_update;
5950#endif /* CONFIG_IEEE80211BE */
5951
5952 wpa_group_update_gtk(wpa_auth, group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005953
5954 if (group->GKeyDoneStations) {
Hai Shalomfdcde762020-04-02 11:19:20 -07005955 wpa_printf(MSG_DEBUG,
5956 "wpa_group_setkeys: Unexpected GKeyDoneStations=%d when starting new GTK rekey",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005957 group->GKeyDoneStations);
5958 group->GKeyDoneStations = 0;
5959 }
Sunil Ravi7f769292024-07-23 22:21:32 +00005960
5961#ifdef CONFIG_IEEE80211BE
5962skip_update:
5963#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005964 wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005965 wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
5966 group->GKeyDoneStations);
5967}
5968
5969
5970static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
5971 struct wpa_group *group)
5972{
Hai Shalomfdcde762020-04-02 11:19:20 -07005973 struct wpa_auth_config *conf = &wpa_auth->conf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005974 int ret = 0;
5975
5976 if (wpa_auth_set_key(wpa_auth, group->vlan_id,
Hai Shalomfdcde762020-04-02 11:19:20 -07005977 wpa_cipher_to_alg(conf->wpa_group),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005978 broadcast_ether_addr, group->GN,
Hai Shalomfdcde762020-04-02 11:19:20 -07005979 group->GTK[group->GN - 1], group->GTK_len,
5980 KEY_FLAG_GROUP_TX_DEFAULT) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005981 ret = -1;
5982
Sunil Ravi876a49b2025-02-03 19:18:32 +00005983 if (wpa_auth_pmf_enabled(conf)) {
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005984 enum wpa_alg alg;
5985 size_t len;
5986
Hai Shalomfdcde762020-04-02 11:19:20 -07005987 alg = wpa_cipher_to_alg(conf->group_mgmt_cipher);
5988 len = wpa_cipher_key_len(conf->group_mgmt_cipher);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07005989
5990 if (ret == 0 &&
5991 wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
5992 broadcast_ether_addr, group->GN_igtk,
Hai Shalomfdcde762020-04-02 11:19:20 -07005993 group->IGTK[group->GN_igtk - 4], len,
5994 KEY_FLAG_GROUP_TX_DEFAULT) < 0)
5995 ret = -1;
5996
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005997 if (ret || !conf->beacon_prot)
5998 return ret;
5999 if (wpa_auth->conf.tx_bss_auth) {
6000 wpa_auth = wpa_auth->conf.tx_bss_auth;
6001 group = wpa_auth->group;
6002 if (!group->bigtk_set || group->bigtk_configured)
6003 return ret;
6004 }
6005 if (wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
Hai Shalomfdcde762020-04-02 11:19:20 -07006006 broadcast_ether_addr, group->GN_bigtk,
6007 group->BIGTK[group->GN_bigtk - 6], len,
6008 KEY_FLAG_GROUP_TX_DEFAULT) < 0)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006009 ret = -1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006010 else
6011 group->bigtk_configured = true;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07006012 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006013
6014 return ret;
6015}
6016
6017
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006018static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
6019{
6020 if (sm->group == ctx) {
6021 wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
Hai Shalomfdcde762020-04-02 11:19:20 -07006022 " for disconnection due to fatal failure",
Sunil Raviaf8751c2023-03-29 11:35:17 -07006023 MAC2STR(wpa_auth_get_spa(sm)));
Hai Shalome21d4e82020-04-29 16:34:06 -07006024 sm->Disconnect = true;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006025 }
6026
6027 return 0;
6028}
6029
6030
6031static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
6032 struct wpa_group *group)
6033{
Hai Shalomfdcde762020-04-02 11:19:20 -07006034 wpa_printf(MSG_DEBUG,
6035 "WPA: group state machine entering state FATAL_FAILURE");
Hai Shalome21d4e82020-04-29 16:34:06 -07006036 group->changed = true;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006037 group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
6038 wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
6039}
6040
6041
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006042static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
6043 struct wpa_group *group)
6044{
Hai Shalomfdcde762020-04-02 11:19:20 -07006045 wpa_printf(MSG_DEBUG,
6046 "WPA: group state machine entering state SETKEYSDONE (VLAN-ID %d)",
6047 group->vlan_id);
Hai Shalome21d4e82020-04-29 16:34:06 -07006048 group->changed = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006049 group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
6050
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006051 if (wpa_group_config_group_keys(wpa_auth, group) < 0) {
6052 wpa_group_fatal_failure(wpa_auth, group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006053 return -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006054 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006055
6056 return 0;
6057}
6058
6059
6060static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
6061 struct wpa_group *group)
6062{
6063 if (group->GInit) {
6064 wpa_group_gtk_init(wpa_auth, group);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006065 } else if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) {
6066 /* Do not allow group operations */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006067 } else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
6068 group->GTKAuthenticator) {
6069 wpa_group_setkeysdone(wpa_auth, group);
6070 } else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE &&
6071 group->GTKReKey) {
6072 wpa_group_setkeys(wpa_auth, group);
6073 } else if (group->wpa_group_state == WPA_GROUP_SETKEYS) {
6074 if (group->GKeyDoneStations == 0)
6075 wpa_group_setkeysdone(wpa_auth, group);
6076 else if (group->GTKReKey)
6077 wpa_group_setkeys(wpa_auth, group);
6078 }
6079}
6080
6081
Sunil Ravi7f769292024-07-23 22:21:32 +00006082static void wpa_clear_changed(struct wpa_state_machine *sm)
6083{
6084#ifdef CONFIG_IEEE80211BE
6085 int link_id;
6086#endif /* CONFIG_IEEE80211BE */
6087
6088 sm->changed = false;
6089 sm->wpa_auth->group->changed = false;
6090
6091#ifdef CONFIG_IEEE80211BE
6092 for_each_sm_auth(sm, link_id)
6093 sm->mld_links[link_id].wpa_auth->group->changed = false;
6094#endif /* CONFIG_IEEE80211BE */
6095}
6096
6097
6098static void wpa_group_sm_step_links(struct wpa_state_machine *sm)
6099{
6100#ifdef CONFIG_IEEE80211BE
6101 int link_id;
6102#endif /* CONFIG_IEEE80211BE */
6103
6104 if (!sm || !sm->wpa_auth)
6105 return;
6106 wpa_group_sm_step(sm->wpa_auth, sm->wpa_auth->group);
6107
6108#ifdef CONFIG_IEEE80211BE
6109 for_each_sm_auth(sm, link_id) {
6110 wpa_group_sm_step(sm->mld_links[link_id].wpa_auth,
6111 sm->mld_links[link_id].wpa_auth->group);
6112 }
6113#endif /* CONFIG_IEEE80211BE */
6114}
6115
6116
6117static bool wpa_group_sm_changed(struct wpa_state_machine *sm)
6118{
6119#ifdef CONFIG_IEEE80211BE
6120 int link_id;
6121#endif /* CONFIG_IEEE80211BE */
6122 bool changed;
6123
6124 if (!sm || !sm->wpa_auth)
6125 return false;
6126 changed = sm->wpa_auth->group->changed;
6127
6128#ifdef CONFIG_IEEE80211BE
6129 for_each_sm_auth(sm, link_id)
6130 changed |= sm->mld_links[link_id].wpa_auth->group->changed;
6131#endif /* CONFIG_IEEE80211BE */
6132
6133 return changed;
6134}
6135
6136
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006137static int wpa_sm_step(struct wpa_state_machine *sm)
6138{
Hai Shalomfdcde762020-04-02 11:19:20 -07006139 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006140 return 0;
6141
6142 if (sm->in_step_loop) {
6143 /* This should not happen, but if it does, make sure we do not
6144 * end up freeing the state machine too early by exiting the
6145 * recursive call. */
6146 wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively");
6147 return 0;
6148 }
6149
6150 sm->in_step_loop = 1;
6151 do {
6152 if (sm->pending_deinit)
6153 break;
6154
Sunil Ravi7f769292024-07-23 22:21:32 +00006155 wpa_clear_changed(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006156
6157 SM_STEP_RUN(WPA_PTK);
6158 if (sm->pending_deinit)
6159 break;
6160 SM_STEP_RUN(WPA_PTK_GROUP);
6161 if (sm->pending_deinit)
6162 break;
Sunil Ravi7f769292024-07-23 22:21:32 +00006163 wpa_group_sm_step_links(sm);
6164 } while (sm->changed || wpa_group_sm_changed(sm));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006165 sm->in_step_loop = 0;
6166
6167 if (sm->pending_deinit) {
Hai Shalomfdcde762020-04-02 11:19:20 -07006168 wpa_printf(MSG_DEBUG,
6169 "WPA: Completing pending STA state machine deinit for "
Sunil Raviaf8751c2023-03-29 11:35:17 -07006170 MACSTR, MAC2STR(wpa_auth_get_spa(sm)));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006171 wpa_free_sta_sm(sm);
6172 return 1;
6173 }
6174 return 0;
6175}
6176
6177
6178static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
6179{
6180 struct wpa_state_machine *sm = eloop_ctx;
6181 wpa_sm_step(sm);
6182}
6183
6184
6185void wpa_auth_sm_notify(struct wpa_state_machine *sm)
6186{
Hai Shalomfdcde762020-04-02 11:19:20 -07006187 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006188 return;
6189 eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
6190}
6191
6192
6193void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
6194{
6195 int tmp, i;
6196 struct wpa_group *group;
6197
Hai Shalomfdcde762020-04-02 11:19:20 -07006198 if (!wpa_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006199 return;
6200
6201 group = wpa_auth->group;
6202
6203 for (i = 0; i < 2; i++) {
6204 tmp = group->GM;
6205 group->GM = group->GN;
6206 group->GN = tmp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006207 tmp = group->GM_igtk;
6208 group->GM_igtk = group->GN_igtk;
6209 group->GN_igtk = tmp;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006210 if (!wpa_auth->conf.tx_bss_auth) {
6211 tmp = group->GM_bigtk;
6212 group->GM_bigtk = group->GN_bigtk;
6213 group->GN_bigtk = tmp;
6214 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006215 wpa_gtk_update(wpa_auth, group);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006216 wpa_group_config_group_keys(wpa_auth, group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006217 }
6218}
6219
6220
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006221static const char * wpa_bool_txt(int val)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006222{
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006223 return val ? "TRUE" : "FALSE";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006224}
6225
6226
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006227#define RSN_SUITE "%02x-%02x-%02x-%d"
6228#define RSN_SUITE_ARG(s) \
6229((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
6230
6231int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
6232{
Hai Shalomfdcde762020-04-02 11:19:20 -07006233 struct wpa_auth_config *conf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006234 int len = 0, ret;
6235 char pmkid_txt[PMKID_LEN * 2 + 1];
6236#ifdef CONFIG_RSN_PREAUTH
6237 const int preauth = 1;
6238#else /* CONFIG_RSN_PREAUTH */
6239 const int preauth = 0;
6240#endif /* CONFIG_RSN_PREAUTH */
6241
Hai Shalomfdcde762020-04-02 11:19:20 -07006242 if (!wpa_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006243 return len;
Hai Shalomfdcde762020-04-02 11:19:20 -07006244 conf = &wpa_auth->conf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006245
6246 ret = os_snprintf(buf + len, buflen - len,
6247 "dot11RSNAOptionImplemented=TRUE\n"
6248 "dot11RSNAPreauthenticationImplemented=%s\n"
6249 "dot11RSNAEnabled=%s\n"
6250 "dot11RSNAPreauthenticationEnabled=%s\n",
6251 wpa_bool_txt(preauth),
Hai Shalomfdcde762020-04-02 11:19:20 -07006252 wpa_bool_txt(conf->wpa & WPA_PROTO_RSN),
6253 wpa_bool_txt(conf->rsn_preauth));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006254 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006255 return len;
6256 len += ret;
6257
6258 wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
6259 wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN);
6260
6261 ret = os_snprintf(
6262 buf + len, buflen - len,
6263 "dot11RSNAConfigVersion=%u\n"
6264 "dot11RSNAConfigPairwiseKeysSupported=9999\n"
6265 /* FIX: dot11RSNAConfigGroupCipher */
6266 /* FIX: dot11RSNAConfigGroupRekeyMethod */
6267 /* FIX: dot11RSNAConfigGroupRekeyTime */
6268 /* FIX: dot11RSNAConfigGroupRekeyPackets */
6269 "dot11RSNAConfigGroupRekeyStrict=%u\n"
6270 "dot11RSNAConfigGroupUpdateCount=%u\n"
6271 "dot11RSNAConfigPairwiseUpdateCount=%u\n"
6272 "dot11RSNAConfigGroupCipherSize=%u\n"
6273 "dot11RSNAConfigPMKLifetime=%u\n"
6274 "dot11RSNAConfigPMKReauthThreshold=%u\n"
6275 "dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n"
6276 "dot11RSNAConfigSATimeout=%u\n"
6277 "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
6278 "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
6279 "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
6280 "dot11RSNAPMKIDUsed=%s\n"
6281 "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
6282 "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
6283 "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
6284 "dot11RSNATKIPCounterMeasuresInvoked=%u\n"
6285 "dot11RSNA4WayHandshakeFailures=%u\n"
6286 "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
6287 RSN_VERSION,
Hai Shalomfdcde762020-04-02 11:19:20 -07006288 !!conf->wpa_strict_rekey,
6289 conf->wpa_group_update_count,
6290 conf->wpa_pairwise_update_count,
6291 wpa_cipher_key_len(conf->wpa_group) * 8,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006292 dot11RSNAConfigPMKLifetime,
6293 dot11RSNAConfigPMKReauthThreshold,
6294 dot11RSNAConfigSATimeout,
6295 RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteSelected),
6296 RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherSelected),
6297 RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected),
6298 pmkid_txt,
6299 RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteRequested),
6300 RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherRequested),
6301 RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
6302 wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
6303 wpa_auth->dot11RSNA4WayHandshakeFailures);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006304 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006305 return len;
6306 len += ret;
6307
6308 /* TODO: dot11RSNAConfigPairwiseCiphersTable */
6309 /* TODO: dot11RSNAConfigAuthenticationSuitesTable */
6310
6311 /* Private MIB */
6312 ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
6313 wpa_auth->group->wpa_group_state);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006314 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006315 return len;
6316 len += ret;
6317
6318 return len;
6319}
6320
6321
6322int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
6323{
6324 int len = 0, ret;
6325 u32 pairwise = 0;
6326
Hai Shalomfdcde762020-04-02 11:19:20 -07006327 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006328 return 0;
6329
6330 /* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
6331
6332 /* dot11RSNAStatsEntry */
6333
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07006334 pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ?
6335 WPA_PROTO_RSN : WPA_PROTO_WPA,
6336 sm->pairwise);
6337 if (pairwise == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006338 return 0;
6339
6340 ret = os_snprintf(
6341 buf + len, buflen - len,
6342 /* TODO: dot11RSNAStatsIndex */
6343 "dot11RSNAStatsSTAAddress=" MACSTR "\n"
6344 "dot11RSNAStatsVersion=1\n"
6345 "dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
6346 /* TODO: dot11RSNAStatsTKIPICVErrors */
6347 "dot11RSNAStatsTKIPLocalMICFailures=%u\n"
6348 "dot11RSNAStatsTKIPRemoteMICFailures=%u\n"
6349 /* TODO: dot11RSNAStatsCCMPReplays */
6350 /* TODO: dot11RSNAStatsCCMPDecryptErrors */
6351 /* TODO: dot11RSNAStatsTKIPReplays */,
6352 MAC2STR(sm->addr),
6353 RSN_SUITE_ARG(pairwise),
6354 sm->dot11RSNAStatsTKIPLocalMICFailures,
6355 sm->dot11RSNAStatsTKIPRemoteMICFailures);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006356 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006357 return len;
6358 len += ret;
6359
6360 /* Private MIB */
6361 ret = os_snprintf(buf + len, buflen - len,
Hai Shalomc3565922019-10-28 11:58:20 -07006362 "wpa=%d\n"
6363 "AKMSuiteSelector=" RSN_SUITE "\n"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006364 "hostapdWPAPTKState=%d\n"
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00006365 "hostapdWPAPTKGroupState=%d\n"
6366 "hostapdMFPR=%d\n",
Hai Shalomc3565922019-10-28 11:58:20 -07006367 sm->wpa,
6368 RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006369 sm->wpa_ptk_state,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00006370 sm->wpa_ptk_group_state,
6371 sm->mfpr);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006372 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006373 return len;
6374 len += ret;
6375
6376 return len;
6377}
6378
6379
6380void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth)
6381{
6382 if (wpa_auth)
6383 wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
6384}
6385
6386
6387int wpa_auth_pairwise_set(struct wpa_state_machine *sm)
6388{
6389 return sm && sm->pairwise_set;
6390}
6391
6392
6393int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
6394{
6395 return sm->pairwise;
6396}
6397
6398
Hai Shalom74f70d42019-02-11 14:42:39 -08006399const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
6400{
6401 if (!sm)
6402 return NULL;
6403 *len = sm->pmk_len;
6404 return sm->PMK;
6405}
6406
6407
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00006408const u8 * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm)
6409{
6410 if (!sm || !sm->pmksa)
6411 return NULL;
6412 return sm->pmksa->dpp_pkhash;
6413}
6414
6415
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006416int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
6417{
Hai Shalomfdcde762020-04-02 11:19:20 -07006418 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006419 return -1;
6420 return sm->wpa_key_mgmt;
6421}
6422
6423
6424int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
6425{
Hai Shalomfdcde762020-04-02 11:19:20 -07006426 if (!sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006427 return 0;
6428 return sm->wpa;
6429}
6430
6431
Mathy Vanhoeff6e1f662017-07-14 15:15:35 +02006432int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
6433{
6434 if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt))
6435 return 0;
6436 return sm->tk_already_set;
6437}
6438
6439
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006440int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm)
6441{
6442 if (!sm || !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
6443 return 0;
6444 return sm->tk_already_set;
6445}
6446
6447
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006448int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
6449 struct rsn_pmksa_cache_entry *entry)
6450{
Hai Shalomfdcde762020-04-02 11:19:20 -07006451 if (!sm || sm->pmksa != entry)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006452 return -1;
6453 sm->pmksa = NULL;
6454 return 0;
6455}
6456
6457
6458struct rsn_pmksa_cache_entry *
6459wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm)
6460{
6461 return sm ? sm->pmksa : NULL;
6462}
6463
6464
6465void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
6466{
6467 if (sm)
6468 sm->dot11RSNAStatsTKIPLocalMICFailures++;
6469}
6470
6471
6472const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
6473{
Hai Shalomfdcde762020-04-02 11:19:20 -07006474 if (!wpa_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006475 return NULL;
6476 *len = wpa_auth->wpa_ie_len;
6477 return wpa_auth->wpa_ie;
6478}
6479
6480
6481int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006482 unsigned int pmk_len,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006483 int session_timeout, struct eapol_state_machine *eapol)
6484{
Hai Shalomfdcde762020-04-02 11:19:20 -07006485 if (!sm || sm->wpa != WPA_VERSION_WPA2 ||
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006486 sm->wpa_auth->conf.disable_pmksa_caching)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006487 return -1;
6488
Hai Shalom81f62d82019-07-22 12:10:00 -07006489#ifdef CONFIG_IEEE80211R_AP
6490 if (pmk_len >= 2 * PMK_LEN && wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
6491 wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
6492 !wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
6493 /* Cache MPMK/XXKey instead of initial part from MSK */
6494 pmk = pmk + PMK_LEN;
6495 pmk_len = PMK_LEN;
6496 } else
6497#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08006498 if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006499 if (pmk_len > PMK_LEN_SUITE_B_192)
6500 pmk_len = PMK_LEN_SUITE_B_192;
6501 } else if (pmk_len > PMK_LEN) {
6502 pmk_len = PMK_LEN;
6503 }
6504
Hai Shalom81f62d82019-07-22 12:10:00 -07006505 wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006506 if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
Dmitry Shmidt807291d2015-01-27 13:40:23 -08006507 sm->PTK.kck, sm->PTK.kck_len,
Sunil Raviaf8751c2023-03-29 11:35:17 -07006508 wpa_auth_get_aa(sm),
6509 wpa_auth_get_spa(sm), session_timeout,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006510 eapol, sm->wpa_key_mgmt))
6511 return 0;
6512
6513 return -1;
6514}
6515
6516
6517int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
6518 const u8 *pmk, size_t len, const u8 *sta_addr,
6519 int session_timeout,
6520 struct eapol_state_machine *eapol)
6521{
Hai Shalomfdcde762020-04-02 11:19:20 -07006522 if (!wpa_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006523 return -1;
6524
Hai Shalom81f62d82019-07-22 12:10:00 -07006525 wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08006526 if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006527 NULL, 0,
6528 wpa_auth->addr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006529 sta_addr, session_timeout, eapol,
6530 WPA_KEY_MGMT_IEEE8021X))
6531 return 0;
6532
6533 return -1;
6534}
6535
6536
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006537int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
Sunil Ravi89eba102022-09-13 21:04:37 -07006538 const u8 *pmk, size_t pmk_len, const u8 *pmkid,
Sunil Ravi876a49b2025-02-03 19:18:32 +00006539 int akmp, bool is_ml)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006540{
Sunil Ravi876a49b2025-02-03 19:18:32 +00006541 struct rsn_pmksa_cache *pmksa = wpa_auth->pmksa;
6542 const u8 *aa = wpa_auth->addr;
6543
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006544 if (wpa_auth->conf.disable_pmksa_caching)
6545 return -1;
6546
Sunil Ravi89eba102022-09-13 21:04:37 -07006547 wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, pmk_len);
6548 if (!akmp)
6549 akmp = WPA_KEY_MGMT_SAE;
Sunil Ravi876a49b2025-02-03 19:18:32 +00006550
6551#ifdef CONFIG_IEEE80211BE
6552 if (is_ml) {
6553 pmksa = wpa_auth->ml_pmksa;
6554 aa = wpa_auth->mld_addr;
6555 }
6556#endif /* CONFIG_IEEE80211BE */
6557
6558 if (pmksa_cache_auth_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, aa, addr,
6559 0, NULL, akmp))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006560 return 0;
6561
6562 return -1;
6563}
6564
6565
Roshan Pius3a1667e2018-07-03 15:17:14 -07006566void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid)
6567{
6568 os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
6569 sm->pmkid_set = 1;
6570}
6571
6572
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006573int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
6574 const u8 *pmk, size_t pmk_len, const u8 *pmkid,
Sunil Ravi876a49b2025-02-03 19:18:32 +00006575 int session_timeout, int akmp, const u8 *dpp_pkhash,
6576 bool is_ml)
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00006577{
Sunil Ravi876a49b2025-02-03 19:18:32 +00006578 struct rsn_pmksa_cache *pmksa;
6579 const u8 *aa;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00006580 struct rsn_pmksa_cache_entry *entry;
6581
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006582 if (!wpa_auth || wpa_auth->conf.disable_pmksa_caching)
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00006583 return -1;
6584
6585 wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (3)", pmk, PMK_LEN);
Sunil Ravi876a49b2025-02-03 19:18:32 +00006586 pmksa = wpa_auth->pmksa;
6587 aa = wpa_auth->addr;
6588#ifdef CONFIG_IEEE80211BE
6589 if (is_ml) {
6590 pmksa = wpa_auth->ml_pmksa;
6591 aa = wpa_auth->mld_addr;
6592 }
6593#endif /* CONFIG_IEEE80211BE */
6594 entry = pmksa_cache_auth_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, aa,
6595 addr, session_timeout, NULL, akmp);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00006596 if (!entry)
6597 return -1;
6598
6599 if (dpp_pkhash)
6600 entry->dpp_pkhash = os_memdup(dpp_pkhash, SHA256_MAC_LEN);
6601
6602 return 0;
6603}
6604
6605
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07006606void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
6607 const u8 *sta_addr)
6608{
6609 struct rsn_pmksa_cache_entry *pmksa;
6610
Hai Shalomfdcde762020-04-02 11:19:20 -07006611 if (!wpa_auth || !wpa_auth->pmksa)
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07006612 return;
Sunil Ravi876a49b2025-02-03 19:18:32 +00006613
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07006614 pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
6615 if (pmksa) {
6616 wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
6617 MACSTR " based on request", MAC2STR(sta_addr));
6618 pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
6619 }
Sunil Ravi876a49b2025-02-03 19:18:32 +00006620
6621#ifdef CONFIG_IEEE80211BE
6622 if (wpa_auth->ml_pmksa) {
6623 pmksa = pmksa_cache_auth_get(wpa_auth->ml_pmksa,
6624 sta_addr, NULL);
6625 if (pmksa) {
6626 wpa_printf(MSG_DEBUG,
6627 "WPA: Remove PMKSA cache entry for " MACSTR
6628 " based on request (MLD)",
6629 MAC2STR(sta_addr));
6630 pmksa_cache_free_entry(wpa_auth->ml_pmksa, pmksa);
6631 }
6632 }
6633#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -07006634}
6635
6636
Dmitry Shmidte4663042016-04-04 10:07:49 -07006637int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
6638 size_t len)
6639{
Sunil Ravi876a49b2025-02-03 19:18:32 +00006640 int ret, index;
6641 char *pos = buf, *end = buf + len;
6642
Dmitry Shmidte4663042016-04-04 10:07:49 -07006643 if (!wpa_auth || !wpa_auth->pmksa)
6644 return 0;
Sunil Ravi876a49b2025-02-03 19:18:32 +00006645
6646 ret = os_snprintf(pos, len,
6647 "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
6648 if (os_snprintf_error(end - pos, ret))
6649 return pos - buf;
6650 pos += ret;
6651
6652 index = 0;
6653 pos += pmksa_cache_auth_list(wpa_auth->pmksa, pos, end - pos, &index);
6654#ifdef CONFIG_IEEE80211BE
6655 if (wpa_auth->ml_pmksa)
6656 pos += pmksa_cache_auth_list(wpa_auth->ml_pmksa,
6657 pos, end - pos, &index);
6658#endif /* CONFIG_IEEE80211BE */
6659
6660 return pos - buf;
Dmitry Shmidte4663042016-04-04 10:07:49 -07006661}
6662
6663
6664void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
6665{
Sunil Ravi876a49b2025-02-03 19:18:32 +00006666 if (wpa_auth && wpa_auth->pmksa) {
Dmitry Shmidte4663042016-04-04 10:07:49 -07006667 pmksa_cache_auth_flush(wpa_auth->pmksa);
Sunil Ravi876a49b2025-02-03 19:18:32 +00006668#ifdef CONFIG_IEEE80211BE
6669 if (wpa_auth->ml_pmksa && wpa_auth->primary_auth)
6670 pmksa_cache_auth_flush(wpa_auth->ml_pmksa);
6671#endif /* CONFIG_IEEE80211BE */
6672 }
Dmitry Shmidte4663042016-04-04 10:07:49 -07006673}
6674
6675
Paul Stewart092955c2017-02-06 09:13:09 -08006676#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
6677#ifdef CONFIG_MESH
6678
6679int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
6680 char *buf, size_t len)
6681{
6682 if (!wpa_auth || !wpa_auth->pmksa)
6683 return 0;
6684
6685 return pmksa_cache_auth_list_mesh(wpa_auth->pmksa, addr, buf, len);
6686}
6687
6688
6689struct rsn_pmksa_cache_entry *
6690wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
Sunil Ravi89eba102022-09-13 21:04:37 -07006691 size_t pmk_len, int akmp,
Paul Stewart092955c2017-02-06 09:13:09 -08006692 const u8 *pmkid, int expiration)
6693{
6694 struct rsn_pmksa_cache_entry *entry;
6695 struct os_reltime now;
6696
Sunil Ravi89eba102022-09-13 21:04:37 -07006697 entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, NULL, 0, aa,
6698 spa, 0, NULL, akmp);
Paul Stewart092955c2017-02-06 09:13:09 -08006699 if (!entry)
6700 return NULL;
6701
6702 os_get_reltime(&now);
6703 entry->expiration = now.sec + expiration;
6704 return entry;
6705}
6706
6707
6708int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
6709 struct rsn_pmksa_cache_entry *entry)
6710{
6711 int ret;
6712
6713 if (!wpa_auth || !wpa_auth->pmksa)
6714 return -1;
6715
6716 ret = pmksa_cache_auth_add_entry(wpa_auth->pmksa, entry);
6717 if (ret < 0)
6718 wpa_printf(MSG_DEBUG,
6719 "RSN: Failed to store external PMKSA cache for "
6720 MACSTR, MAC2STR(entry->spa));
6721
6722 return ret;
6723}
6724
6725#endif /* CONFIG_MESH */
6726#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
6727
6728
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00006729struct rsn_pmksa_cache *
6730wpa_auth_get_pmksa_cache(struct wpa_authenticator *wpa_auth)
6731{
6732 if (!wpa_auth || !wpa_auth->pmksa)
6733 return NULL;
6734 return wpa_auth->pmksa;
6735}
6736
6737
Dmitry Shmidte4663042016-04-04 10:07:49 -07006738struct rsn_pmksa_cache_entry *
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006739wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
6740 const u8 *pmkid)
Dmitry Shmidte4663042016-04-04 10:07:49 -07006741{
6742 if (!wpa_auth || !wpa_auth->pmksa)
6743 return NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08006744 return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, pmkid);
Dmitry Shmidte4663042016-04-04 10:07:49 -07006745}
6746
6747
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00006748int wpa_auth_pmksa_get_pmk(struct wpa_authenticator *wpa_auth,
6749 const u8 *sta_addr, const u8 **pmk, size_t *pmk_len,
6750 const u8 **pmkid)
6751{
6752 struct rsn_pmksa_cache_entry *pmksa;
6753
6754 pmksa = wpa_auth_pmksa_get(wpa_auth, sta_addr, NULL);
6755 if (!pmksa) {
6756 wpa_printf(MSG_DEBUG, "RSN: Failed to get PMKSA for " MACSTR,
6757 MAC2STR(sta_addr));
6758 return -1;
6759 }
6760
6761 *pmk = pmksa->pmk;
6762 *pmk_len = pmksa->pmk_len;
6763 *pmkid = pmksa->pmkid;
6764 return 0;
6765}
6766
6767
Dmitry Shmidte4663042016-04-04 10:07:49 -07006768void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
6769 struct wpa_state_machine *sm,
6770 struct wpa_authenticator *wpa_auth,
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006771 u8 *pmkid, u8 *pmk, size_t *pmk_len)
Dmitry Shmidte4663042016-04-04 10:07:49 -07006772{
6773 if (!sm)
6774 return;
6775
6776 sm->pmksa = pmksa;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00006777 os_memcpy(pmk, pmksa->pmk, pmksa->pmk_len);
6778 *pmk_len = pmksa->pmk_len;
Dmitry Shmidte4663042016-04-04 10:07:49 -07006779 os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN);
6780 os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN);
6781}
6782
6783
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006784/*
6785 * Remove and free the group from wpa_authenticator. This is triggered by a
6786 * callback to make sure nobody is currently iterating the group list while it
6787 * gets modified.
6788 */
6789static void wpa_group_free(struct wpa_authenticator *wpa_auth,
6790 struct wpa_group *group)
6791{
6792 struct wpa_group *prev = wpa_auth->group;
6793
6794 wpa_printf(MSG_DEBUG, "WPA: Remove group state machine for VLAN-ID %d",
6795 group->vlan_id);
6796
6797 while (prev) {
6798 if (prev->next == group) {
6799 /* This never frees the special first group as needed */
6800 prev->next = group->next;
6801 os_free(group);
6802 break;
6803 }
6804 prev = prev->next;
6805 }
6806
6807}
6808
6809
6810/* Increase the reference counter for group */
6811static void wpa_group_get(struct wpa_authenticator *wpa_auth,
6812 struct wpa_group *group)
6813{
6814 /* Skip the special first group */
6815 if (wpa_auth->group == group)
6816 return;
6817
6818 group->references++;
6819}
6820
6821
6822/* Decrease the reference counter and maybe free the group */
6823static void wpa_group_put(struct wpa_authenticator *wpa_auth,
6824 struct wpa_group *group)
6825{
6826 /* Skip the special first group */
6827 if (wpa_auth->group == group)
6828 return;
6829
6830 group->references--;
6831 if (group->references)
6832 return;
6833 wpa_group_free(wpa_auth, group);
6834}
6835
6836
6837/*
6838 * Add a group that has its references counter set to zero. Caller needs to
6839 * call wpa_group_get() on the return value to mark the entry in use.
6840 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006841static struct wpa_group *
6842wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
6843{
6844 struct wpa_group *group;
6845
Hai Shalomfdcde762020-04-02 11:19:20 -07006846 if (!wpa_auth || !wpa_auth->group)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006847 return NULL;
6848
6849 wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
6850 vlan_id);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006851 group = wpa_group_init(wpa_auth, vlan_id, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07006852 if (!group)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006853 return NULL;
6854
6855 group->next = wpa_auth->group->next;
6856 wpa_auth->group->next = group;
6857
6858 return group;
6859}
6860
6861
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006862/*
6863 * Enforce that the group state machine for the VLAN is running, increase
6864 * reference counter as interface is up. References might have been increased
6865 * even if a negative value is returned.
6866 * Returns: -1 on error (group missing, group already failed); otherwise, 0
6867 */
6868int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
6869{
6870 struct wpa_group *group;
6871
Hai Shalomfdcde762020-04-02 11:19:20 -07006872 if (!wpa_auth)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006873 return 0;
6874
6875 group = wpa_auth->group;
6876 while (group) {
6877 if (group->vlan_id == vlan_id)
6878 break;
6879 group = group->next;
6880 }
6881
Hai Shalomfdcde762020-04-02 11:19:20 -07006882 if (!group) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006883 group = wpa_auth_add_group(wpa_auth, vlan_id);
Hai Shalomfdcde762020-04-02 11:19:20 -07006884 if (!group)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006885 return -1;
6886 }
6887
6888 wpa_printf(MSG_DEBUG,
6889 "WPA: Ensure group state machine running for VLAN ID %d",
6890 vlan_id);
6891
6892 wpa_group_get(wpa_auth, group);
6893 group->num_setup_iface++;
6894
6895 if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
6896 return -1;
6897
6898 return 0;
6899}
6900
6901
6902/*
6903 * Decrease reference counter, expected to be zero afterwards.
6904 * returns: -1 on error (group not found, group in fail state)
6905 * -2 if wpa_group is still referenced
6906 * 0 else
6907 */
6908int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
6909{
6910 struct wpa_group *group;
6911 int ret = 0;
6912
Hai Shalomfdcde762020-04-02 11:19:20 -07006913 if (!wpa_auth)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006914 return 0;
6915
6916 group = wpa_auth->group;
6917 while (group) {
6918 if (group->vlan_id == vlan_id)
6919 break;
6920 group = group->next;
6921 }
6922
Hai Shalomfdcde762020-04-02 11:19:20 -07006923 if (!group)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08006924 return -1;
6925
6926 wpa_printf(MSG_DEBUG,
6927 "WPA: Try stopping group state machine for VLAN ID %d",
6928 vlan_id);
6929
6930 if (group->num_setup_iface <= 0) {
6931 wpa_printf(MSG_ERROR,
6932 "WPA: wpa_auth_release_group called more often than wpa_auth_ensure_group for VLAN ID %d, skipping.",
6933 vlan_id);
6934 return -1;
6935 }
6936 group->num_setup_iface--;
6937
6938 if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
6939 ret = -1;
6940
6941 if (group->references > 1) {
6942 wpa_printf(MSG_DEBUG,
6943 "WPA: Cannot stop group state machine for VLAN ID %d as references are still hold",
6944 vlan_id);
6945 ret = -2;
6946 }
6947
6948 wpa_group_put(wpa_auth, group);
6949
6950 return ret;
6951}
6952
6953
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006954int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
6955{
6956 struct wpa_group *group;
6957
Hai Shalomfdcde762020-04-02 11:19:20 -07006958 if (!sm || !sm->wpa_auth)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006959 return 0;
6960
6961 group = sm->wpa_auth->group;
6962 while (group) {
6963 if (group->vlan_id == vlan_id)
6964 break;
6965 group = group->next;
6966 }
6967
Hai Shalomfdcde762020-04-02 11:19:20 -07006968 if (!group) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006969 group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
Hai Shalomfdcde762020-04-02 11:19:20 -07006970 if (!group)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006971 return -1;
6972 }
6973
6974 if (sm->group == group)
6975 return 0;
6976
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08006977 if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
6978 return -1;
6979
Hai Shalomfdcde762020-04-02 11:19:20 -07006980 wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR
6981 " to use group state machine for VLAN ID %d",
Sunil Raviaf8751c2023-03-29 11:35:17 -07006982 MAC2STR(wpa_auth_get_spa(sm)), vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006983
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006984 wpa_group_get(sm->wpa_auth, group);
6985 wpa_group_put(sm->wpa_auth, sm->group);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006986 sm->group = group;
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07006987
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006988 return 0;
6989}
6990
6991
6992void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
6993 struct wpa_state_machine *sm, int ack)
6994{
Hai Shalomfdcde762020-04-02 11:19:20 -07006995 if (!wpa_auth || !sm)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006996 return;
6997 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
Sunil Raviaf8751c2023-03-29 11:35:17 -07006998 " ack=%d", MAC2STR(wpa_auth_get_spa(sm)), ack);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006999 if (sm->pending_1_of_4_timeout && ack) {
7000 /*
7001 * Some deployed supplicant implementations update their SNonce
7002 * for each EAPOL-Key 2/4 message even within the same 4-way
7003 * handshake and then fail to use the first SNonce when
7004 * deriving the PTK. This results in unsuccessful 4-way
7005 * handshake whenever the relatively short initial timeout is
7006 * reached and EAPOL-Key 1/4 is retransmitted. Try to work
7007 * around this by increasing the timeout now that we know that
7008 * the station has received the frame.
7009 */
7010 int timeout_ms = eapol_key_timeout_subseq;
Hai Shalomfdcde762020-04-02 11:19:20 -07007011 wpa_printf(MSG_DEBUG,
7012 "WPA: Increase initial EAPOL-Key 1/4 timeout by %u ms because of acknowledged frame",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007013 timeout_ms);
7014 eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
7015 eloop_register_timeout(timeout_ms / 1000,
7016 (timeout_ms % 1000) * 1000,
7017 wpa_send_eapol_timeout, wpa_auth, sm);
7018 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007019
7020#ifdef CONFIG_TESTING_OPTIONS
7021 if (sm->eapol_status_cb) {
7022 sm->eapol_status_cb(sm->eapol_status_cb_ctx1,
7023 sm->eapol_status_cb_ctx2);
7024 sm->eapol_status_cb = NULL;
7025 }
7026#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007027}
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007028
7029
7030int wpa_auth_uses_sae(struct wpa_state_machine *sm)
7031{
Hai Shalomfdcde762020-04-02 11:19:20 -07007032 if (!sm)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007033 return 0;
7034 return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
7035}
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007036
7037
7038int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
7039{
Hai Shalomfdcde762020-04-02 11:19:20 -07007040 if (!sm)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007041 return 0;
Sunil Ravi89eba102022-09-13 21:04:37 -07007042 return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE ||
7043 sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007044}
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08007045
7046
7047#ifdef CONFIG_P2P
7048int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
7049{
Hai Shalomfdcde762020-04-02 11:19:20 -07007050 if (!sm || WPA_GET_BE32(sm->ip_addr) == 0)
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08007051 return -1;
7052 os_memcpy(addr, sm->ip_addr, 4);
7053 return 0;
7054}
7055#endif /* CONFIG_P2P */
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08007056
7057
7058int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
7059 struct radius_das_attrs *attr)
7060{
7061 return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
7062}
Dmitry Shmidt7f656022015-02-25 14:36:37 -08007063
7064
7065void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth)
7066{
7067 struct wpa_group *group;
7068
7069 if (!wpa_auth)
7070 return;
7071 for (group = wpa_auth->group; group; group = group->next)
7072 wpa_group_config_group_keys(wpa_auth, group);
7073}
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007074
7075
7076#ifdef CONFIG_FILS
7077
7078struct wpa_auth_fils_iter_data {
7079 struct wpa_authenticator *auth;
7080 const u8 *cache_id;
7081 struct rsn_pmksa_cache_entry *pmksa;
7082 const u8 *spa;
7083 const u8 *pmkid;
7084};
7085
7086
7087static int wpa_auth_fils_iter(struct wpa_authenticator *a, void *ctx)
7088{
7089 struct wpa_auth_fils_iter_data *data = ctx;
7090
7091 if (a == data->auth || !a->conf.fils_cache_id_set ||
7092 os_memcmp(a->conf.fils_cache_id, data->cache_id,
7093 FILS_CACHE_ID_LEN) != 0)
7094 return 0;
7095 data->pmksa = pmksa_cache_auth_get(a->pmksa, data->spa, data->pmkid);
7096 return data->pmksa != NULL;
7097}
7098
7099
7100struct rsn_pmksa_cache_entry *
7101wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth,
7102 const u8 *sta_addr, const u8 *pmkid)
7103{
7104 struct wpa_auth_fils_iter_data idata;
7105
7106 if (!wpa_auth->conf.fils_cache_id_set)
7107 return NULL;
7108 idata.auth = wpa_auth;
7109 idata.cache_id = wpa_auth->conf.fils_cache_id;
7110 idata.pmksa = NULL;
7111 idata.spa = sta_addr;
7112 idata.pmkid = pmkid;
7113 wpa_auth_for_each_auth(wpa_auth, wpa_auth_fils_iter, &idata);
7114 return idata.pmksa;
7115}
7116
7117
7118#ifdef CONFIG_IEEE80211R_AP
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00007119int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth,
7120 struct wpa_state_machine *sm,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007121 u8 *buf, size_t len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007122{
7123 struct wpa_auth_config *conf = &wpa_auth->conf;
7124
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00007125 return wpa_write_ftie(conf, sm->wpa_key_mgmt, sm->xxkey_len,
7126 conf->r0_key_holder, conf->r0_key_holder_len,
Hai Shalomfdcde762020-04-02 11:19:20 -07007127 NULL, NULL, buf, len, NULL, 0, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007128}
7129#endif /* CONFIG_IEEE80211R_AP */
7130
7131
7132void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
7133 u8 *fils_anonce, u8 *fils_snonce,
7134 u8 *fils_kek, size_t *fils_kek_len)
7135{
7136 os_memcpy(fils_anonce, sm->ANonce, WPA_NONCE_LEN);
7137 os_memcpy(fils_snonce, sm->SNonce, WPA_NONCE_LEN);
7138 os_memcpy(fils_kek, sm->PTK.kek, WPA_KEK_MAX_LEN);
7139 *fils_kek_len = sm->PTK.kek_len;
7140}
7141
Hai Shalom81f62d82019-07-22 12:10:00 -07007142
7143void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
7144 size_t pmk_len, const u8 *pmkid)
7145{
7146 os_memcpy(sm->PMK, pmk, pmk_len);
7147 sm->pmk_len = pmk_len;
7148 os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
7149 sm->pmkid_set = 1;
7150}
7151
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007152#endif /* CONFIG_FILS */
7153
7154
Hai Shalom021b0b52019-04-10 11:17:58 -07007155void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
7156{
7157 if (sm)
7158 sm->auth_alg = auth_alg;
7159}
7160
7161
Sunil Ravic0f5d412024-09-11 22:12:49 +00007162void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
7163 size_t len)
Sunil Ravi7f769292024-07-23 22:21:32 +00007164{
Sunil Ravic0f5d412024-09-11 22:12:49 +00007165 if (!sm)
7166 return;
7167 os_free(sm->rsn_selection);
7168 sm->rsn_selection = NULL;
7169 sm->rsn_selection_len = 0;
7170 sm->rsn_override = false;
7171 sm->rsn_override_2 = false;
7172 if (ie) {
7173 if (len >= 1) {
7174 if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE)
7175 sm->rsn_override = true;
7176 else if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE_2)
7177 sm->rsn_override_2 = true;
7178 }
7179 sm->rsn_selection = os_memdup(ie, len);
7180 if (sm->rsn_selection)
7181 sm->rsn_selection_len = len;
7182 }
Sunil Ravi7f769292024-07-23 22:21:32 +00007183}
7184
7185
Hai Shalom021b0b52019-04-10 11:17:58 -07007186#ifdef CONFIG_DPP2
7187void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
7188{
7189 if (sm) {
7190 wpabuf_clear_free(sm->dpp_z);
7191 sm->dpp_z = z ? wpabuf_dup(z) : NULL;
7192 }
7193}
7194#endif /* CONFIG_DPP2 */
7195
7196
Sunil Ravi7f769292024-07-23 22:21:32 +00007197void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val)
7198{
7199 if (sm)
7200 sm->ssid_protection = val;
7201}
7202
7203
Hai Shalom899fcc72020-10-19 14:38:18 -07007204void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
7205 u8 val)
7206{
7207 if (wpa_auth)
7208 wpa_auth->conf.transition_disable = val;
7209}
7210
7211
Roshan Pius3a1667e2018-07-03 15:17:14 -07007212#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007213
7214int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
7215 void (*cb)(void *ctx1, void *ctx2),
7216 void *ctx1, void *ctx2)
7217{
7218 const u8 *anonce = sm->ANonce;
7219 u8 anonce_buf[WPA_NONCE_LEN];
7220
7221 if (change_anonce) {
7222 if (random_get_bytes(anonce_buf, WPA_NONCE_LEN))
7223 return -1;
7224 anonce = anonce_buf;
7225 }
7226
Sunil Raviaf8751c2023-03-29 11:35:17 -07007227 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007228 "sending 1/4 msg of 4-Way Handshake (TESTING)");
7229 wpa_send_eapol(sm->wpa_auth, sm,
7230 WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
7231 anonce, NULL, 0, 0, 0);
7232 return 0;
7233}
7234
7235
7236int wpa_auth_resend_m3(struct wpa_state_machine *sm,
7237 void (*cb)(void *ctx1, void *ctx2),
7238 void *ctx1, void *ctx2)
7239{
Roshan Pius3a1667e2018-07-03 15:17:14 -07007240 u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007241 u8 *opos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007242 size_t gtk_len, kde_len;
Hai Shalom899fcc72020-10-19 14:38:18 -07007243 struct wpa_auth_config *conf = &sm->wpa_auth->conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007244 struct wpa_group *gsm = sm->group;
7245 u8 *wpa_ie;
Hai Shalomc3565922019-10-28 11:58:20 -07007246 int wpa_ie_len, secure, gtkidx, encr = 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07007247 u8 hdr[2];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007248
7249 /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
Hai Shalomfdcde762020-04-02 11:19:20 -07007250 GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007251 */
7252
7253 /* Use 0 RSC */
7254 os_memset(rsc, 0, WPA_KEY_RSC_LEN);
7255 /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
7256 wpa_ie = sm->wpa_auth->wpa_ie;
7257 wpa_ie_len = sm->wpa_auth->wpa_ie_len;
7258 if (sm->wpa == WPA_VERSION_WPA &&
7259 (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
7260 wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
7261 /* WPA-only STA, remove RSN IE and possible MDIE */
7262 wpa_ie = wpa_ie + wpa_ie[1] + 2;
Hai Shalom60840252021-02-19 19:02:11 -08007263 if (wpa_ie[0] == WLAN_EID_RSNX)
7264 wpa_ie = wpa_ie + wpa_ie[1] + 2;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007265 if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
7266 wpa_ie = wpa_ie + wpa_ie[1] + 2;
7267 wpa_ie_len = wpa_ie[1] + 2;
7268 }
Sunil Raviaf8751c2023-03-29 11:35:17 -07007269 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007270 "sending 3/4 msg of 4-Way Handshake (TESTING)");
7271 if (sm->wpa == WPA_VERSION_WPA2) {
7272 /* WPA2 send GTK in the 4-way handshake */
7273 secure = 1;
7274 gtk = gsm->GTK[gsm->GN - 1];
7275 gtk_len = gsm->GTK_len;
Hai Shalomc3565922019-10-28 11:58:20 -07007276 gtkidx = gsm->GN;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007277 _rsc = rsc;
7278 encr = 1;
7279 } else {
7280 /* WPA does not include GTK in msg 3/4 */
7281 secure = 0;
7282 gtk = NULL;
7283 gtk_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007284 _rsc = NULL;
7285 if (sm->rx_eapol_key_secure) {
7286 /*
7287 * It looks like Windows 7 supplicant tries to use
7288 * Secure bit in msg 2/4 after having reported Michael
7289 * MIC failure and it then rejects the 4-way handshake
7290 * if msg 3/4 does not set Secure bit. Work around this
7291 * by setting the Secure bit here even in the case of
7292 * WPA if the supplicant used it first.
7293 */
Sunil Raviaf8751c2023-03-29 11:35:17 -07007294 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
7295 LOGGER_DEBUG,
Hai Shalomfdcde762020-04-02 11:19:20 -07007296 "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007297 secure = 1;
7298 }
7299 }
7300
Hai Shalom74f70d42019-02-11 14:42:39 -08007301 kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
Hai Shalomfdcde762020-04-02 11:19:20 -07007302
7303 if (sm->use_ext_key_id)
7304 kde_len += 2 + RSN_SELECTOR_LEN + 2;
7305
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007306 if (gtk)
7307 kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
7308#ifdef CONFIG_IEEE80211R_AP
7309 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
7310 kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
7311 kde_len += 300; /* FTIE + 2 * TIE */
7312 }
7313#endif /* CONFIG_IEEE80211R_AP */
7314 kde = os_malloc(kde_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07007315 if (!kde)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007316 return -1;
7317
7318 pos = kde;
7319 os_memcpy(pos, wpa_ie, wpa_ie_len);
7320 pos += wpa_ie_len;
7321#ifdef CONFIG_IEEE80211R_AP
7322 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
7323 int res;
7324 size_t elen;
7325
7326 elen = pos - kde;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00007327 res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name, true);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007328 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07007329 wpa_printf(MSG_ERROR,
7330 "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007331 os_free(kde);
7332 return -1;
7333 }
7334 pos -= wpa_ie_len;
7335 pos += elen;
7336 }
7337#endif /* CONFIG_IEEE80211R_AP */
Hai Shalomfdcde762020-04-02 11:19:20 -07007338 hdr[1] = 0;
7339
7340 if (sm->use_ext_key_id) {
7341 hdr[0] = sm->keyidx_active & 0x01;
7342 pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
7343 }
7344
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007345 if (gtk) {
Hai Shalomc3565922019-10-28 11:58:20 -07007346 hdr[0] = gtkidx & 0x03;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007347 pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
7348 gtk, gtk_len);
7349 }
7350 opos = pos;
7351 pos = ieee80211w_kde_add(sm, pos);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007352 if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
7353 /* skip KDE header and keyid */
7354 opos += 2 + RSN_SELECTOR_LEN + 2;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007355 os_memset(opos, 0, 6); /* clear PN */
7356 }
Hai Shalom899fcc72020-10-19 14:38:18 -07007357 if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08007358 os_free(kde);
7359 return -1;
7360 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007361
7362#ifdef CONFIG_IEEE80211R_AP
7363 if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
7364 int res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007365
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007366 if (sm->assoc_resp_ftie &&
7367 kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
7368 os_memcpy(pos, sm->assoc_resp_ftie,
7369 2 + sm->assoc_resp_ftie[1]);
7370 res = 2 + sm->assoc_resp_ftie[1];
7371 } else {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00007372 res = wpa_write_ftie(conf, sm->wpa_key_mgmt,
7373 sm->xxkey_len,
Roshan Pius3a1667e2018-07-03 15:17:14 -07007374 conf->r0_key_holder,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007375 conf->r0_key_holder_len,
7376 NULL, NULL, pos,
7377 kde + kde_len - pos,
Hai Shalomfdcde762020-04-02 11:19:20 -07007378 NULL, 0, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007379 }
7380 if (res < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07007381 wpa_printf(MSG_ERROR,
7382 "FT: Failed to insert FTIE into EAPOL-Key Key Data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007383 os_free(kde);
7384 return -1;
7385 }
7386 pos += res;
7387
7388 /* TIE[ReassociationDeadline] (TU) */
7389 *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
7390 *pos++ = 5;
7391 *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
7392 WPA_PUT_LE32(pos, conf->reassociation_deadline);
7393 pos += 4;
7394
7395 /* TIE[KeyLifetime] (seconds) */
7396 *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
7397 *pos++ = 5;
7398 *pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007399 WPA_PUT_LE32(pos, conf->r0_key_lifetime);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007400 pos += 4;
7401 }
7402#endif /* CONFIG_IEEE80211R_AP */
7403
7404 wpa_send_eapol(sm->wpa_auth, sm,
7405 (secure ? WPA_KEY_INFO_SECURE : 0) |
7406 (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
7407 WPA_KEY_INFO_MIC : 0) |
7408 WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
7409 WPA_KEY_INFO_KEY_TYPE,
Hai Shalomc3565922019-10-28 11:58:20 -07007410 _rsc, sm->ANonce, kde, pos - kde, 0, encr);
Sunil Ravia04bd252022-05-02 22:54:18 -07007411 bin_clear_free(kde, kde_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007412 return 0;
7413}
7414
7415
7416int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
7417 void (*cb)(void *ctx1, void *ctx2),
7418 void *ctx1, void *ctx2)
7419{
7420 u8 rsc[WPA_KEY_RSC_LEN];
Hai Shalom899fcc72020-10-19 14:38:18 -07007421 struct wpa_auth_config *conf = &sm->wpa_auth->conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007422 struct wpa_group *gsm = sm->group;
7423 const u8 *kde;
Roshan Pius3a1667e2018-07-03 15:17:14 -07007424 u8 *kde_buf = NULL, *pos, hdr[2];
Roshan Pius3a1667e2018-07-03 15:17:14 -07007425 u8 *opos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007426 size_t kde_len;
7427 u8 *gtk;
7428
7429 /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
7430 os_memset(rsc, 0, WPA_KEY_RSC_LEN);
7431 /* Use 0 RSC */
Sunil Raviaf8751c2023-03-29 11:35:17 -07007432 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007433 "sending 1/2 msg of Group Key Handshake (TESTING)");
7434
7435 gtk = gsm->GTK[gsm->GN - 1];
7436 if (sm->wpa == WPA_VERSION_WPA2) {
7437 kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
Hai Shalom74f70d42019-02-11 14:42:39 -08007438 ieee80211w_kde_len(sm) + ocv_oci_len(sm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007439 kde_buf = os_malloc(kde_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07007440 if (!kde_buf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007441 return -1;
7442
7443 kde = pos = kde_buf;
7444 hdr[0] = gsm->GN & 0x03;
7445 hdr[1] = 0;
7446 pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
7447 gtk, gsm->GTK_len);
7448 opos = pos;
7449 pos = ieee80211w_kde_add(sm, pos);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007450 if (pos - opos >=
7451 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
7452 /* skip KDE header and keyid */
7453 opos += 2 + RSN_SELECTOR_LEN + 2;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007454 os_memset(opos, 0, 6); /* clear PN */
7455 }
Hai Shalom899fcc72020-10-19 14:38:18 -07007456 if (ocv_oci_add(sm, &pos,
7457 conf->oci_freq_override_eapol_g1) < 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08007458 os_free(kde_buf);
7459 return -1;
7460 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007461 kde_len = pos - kde;
7462 } else {
7463 kde = gtk;
7464 kde_len = gsm->GTK_len;
7465 }
7466
7467 sm->eapol_status_cb = cb;
7468 sm->eapol_status_cb_ctx1 = ctx1;
7469 sm->eapol_status_cb_ctx2 = ctx2;
7470
7471 wpa_send_eapol(sm->wpa_auth, sm,
7472 WPA_KEY_INFO_SECURE |
7473 (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
7474 WPA_KEY_INFO_MIC : 0) |
7475 WPA_KEY_INFO_ACK |
7476 (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
7477 rsc, NULL, kde, kde_len, gsm->GN, 1);
7478
Sunil Ravia04bd252022-05-02 22:54:18 -07007479 bin_clear_free(kde_buf, kde_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007480 return 0;
7481}
7482
Roshan Pius3a1667e2018-07-03 15:17:14 -07007483
7484int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth)
7485{
7486 if (!wpa_auth)
7487 return -1;
Sunil Ravi7f769292024-07-23 22:21:32 +00007488 eloop_cancel_timeout(wpa_rekey_gtk,
7489 wpa_get_primary_auth(wpa_auth), NULL);
7490 return eloop_register_timeout(0, 0, wpa_rekey_gtk,
7491 wpa_get_primary_auth(wpa_auth), NULL);
Roshan Pius3a1667e2018-07-03 15:17:14 -07007492}
7493
Hai Shalomb755a2a2020-04-23 21:49:02 -07007494
Hai Shaloma20dcd72022-02-04 13:43:00 -08007495int wpa_auth_rekey_ptk(struct wpa_authenticator *wpa_auth,
7496 struct wpa_state_machine *sm)
7497{
7498 if (!wpa_auth || !sm)
7499 return -1;
7500 wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
7501 wpa_request_new_ptk(sm);
7502 wpa_sm_step(sm);
7503 return 0;
7504}
7505
7506
Hai Shalomb755a2a2020-04-23 21:49:02 -07007507void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val)
7508{
7509 if (wpa_auth)
7510 wpa_auth->conf.ft_rsnxe_used = val;
7511}
7512
Hai Shalom899fcc72020-10-19 14:38:18 -07007513
7514void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
7515 enum wpa_auth_ocv_override_frame frame,
7516 unsigned int freq)
7517{
7518 if (!wpa_auth)
7519 return;
7520 switch (frame) {
7521 case WPA_AUTH_OCV_OVERRIDE_EAPOL_M3:
7522 wpa_auth->conf.oci_freq_override_eapol_m3 = freq;
7523 break;
7524 case WPA_AUTH_OCV_OVERRIDE_EAPOL_G1:
7525 wpa_auth->conf.oci_freq_override_eapol_g1 = freq;
7526 break;
7527 case WPA_AUTH_OCV_OVERRIDE_FT_ASSOC:
7528 wpa_auth->conf.oci_freq_override_ft_assoc = freq;
7529 break;
7530 case WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC:
7531 wpa_auth->conf.oci_freq_override_fils_assoc = freq;
7532 break;
7533 }
7534}
7535
Kai Shie75b0652020-11-24 20:31:29 -08007536void wpa_auth_set_skip_send_eapol(struct wpa_authenticator *wpa_auth,
7537 u8 val)
7538{
7539 if (wpa_auth)
7540 wpa_auth->conf.skip_send_eapol = val;
7541}
7542
7543void wpa_auth_set_enable_eapol_large_timeout(struct wpa_authenticator *wpa_auth,
7544 u8 val)
7545{
7546 if (wpa_auth)
7547 wpa_auth->conf.enable_eapol_large_timeout = val;
7548}
7549
7550
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07007551#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravia04bd252022-05-02 22:54:18 -07007552
7553
7554void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success)
7555{
7556 if (!sm->waiting_radius_psk) {
7557 wpa_printf(MSG_DEBUG,
7558 "Ignore RADIUS PSK response for " MACSTR
7559 " that did not wait one",
7560 MAC2STR(sm->addr));
7561 return;
7562 }
7563
7564 wpa_printf(MSG_DEBUG, "RADIUS PSK response for " MACSTR " (%s)",
7565 MAC2STR(sm->addr), success ? "success" : "fail");
7566 sm->waiting_radius_psk = 0;
7567
7568 if (success) {
7569 /* Try to process the EAPOL-Key msg 2/4 again */
7570 sm->EAPOLKeyReceived = true;
7571 } else {
7572 sm->Disconnect = true;
7573 }
7574
7575 eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
7576}
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007577
7578
Sunil Ravi7f769292024-07-23 22:21:32 +00007579void wpa_auth_set_ml_info(struct wpa_state_machine *sm,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007580 u8 mld_assoc_link_id, struct mld_info *info)
7581{
7582#ifdef CONFIG_IEEE80211BE
Sunil Ravi7f769292024-07-23 22:21:32 +00007583 unsigned int link_id;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007584
7585 if (!info)
7586 return;
7587
7588 os_memset(sm->mld_links, 0, sizeof(sm->mld_links));
Sunil Ravi7f769292024-07-23 22:21:32 +00007589 sm->n_mld_affiliated_links = 0;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007590
7591 wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
7592 "MLD: Initialization");
7593
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007594 os_memcpy(sm->peer_mld_addr, info->common_info.mld_addr, ETH_ALEN);
7595
7596 sm->mld_assoc_link_id = mld_assoc_link_id;
7597
Sunil Ravi7f769292024-07-23 22:21:32 +00007598 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007599 struct mld_link_info *link = &info->links[link_id];
7600 struct mld_link *sm_link = &sm->mld_links[link_id];
Sunil Ravi7f769292024-07-23 22:21:32 +00007601 struct wpa_get_link_auth_ctx ctx;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007602
7603 sm_link->valid = link->valid;
7604 if (!link->valid)
7605 continue;
7606
7607 os_memcpy(sm_link->peer_addr, link->peer_addr, ETH_ALEN);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007608
7609 wpa_printf(MSG_DEBUG,
Sunil Ravi7f769292024-07-23 22:21:32 +00007610 "WPA_AUTH: MLD: id=%u, peer=" MACSTR,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007611 link_id,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007612 MAC2STR(sm_link->peer_addr));
7613
Sunil Ravi7f769292024-07-23 22:21:32 +00007614 if (link_id != mld_assoc_link_id) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007615 sm->n_mld_affiliated_links++;
Sunil Ravi7f769292024-07-23 22:21:32 +00007616 ctx.addr = link->local_addr;
7617 ctx.mld_addr = NULL;
7618 ctx.link_id = -1;
7619 ctx.wpa_auth = NULL;
7620 wpa_auth_for_each_auth(sm->wpa_auth,
7621 wpa_get_link_sta_auth, &ctx);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00007622 if (ctx.wpa_auth)
Sunil Ravi7f769292024-07-23 22:21:32 +00007623 sm_link->wpa_auth = ctx.wpa_auth;
Sunil Ravi7f769292024-07-23 22:21:32 +00007624 } else {
7625 sm_link->wpa_auth = sm->wpa_auth;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007626 }
7627
Sunil Ravi7f769292024-07-23 22:21:32 +00007628 if (!sm_link->wpa_auth)
7629 wpa_printf(MSG_ERROR,
7630 "Unable to find authenticator object for ML STA "
7631 MACSTR " on link id %d",
7632 MAC2STR(sm->wpa_auth->mld_addr),
7633 link_id);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00007634 }
7635#endif /* CONFIG_IEEE80211BE */
7636}
Sunil Ravi876a49b2025-02-03 19:18:32 +00007637
7638
7639bool wpa_auth_sm_known_sta_identification(struct wpa_state_machine *sm,
7640 const u8 *timestamp,
7641 const u8 *mic, size_t mic_len)
7642{
7643 size_t exp_mic_len;
7644 u8 exp_mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
7645 int ver;
7646
7647 if (!sm)
7648 return false;
7649
7650 if (!sm->PTK_valid || !mic_len || sm->PTK.kck_len == 0) {
7651 wpa_printf(MSG_DEBUG,
7652 "RSN: No KCK to verify Known STA Identification");
7653 return false;
7654 }
7655
7656 exp_mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
7657 if (mic_len != exp_mic_len) {
7658 wpa_printf(MSG_DEBUG,
7659 "RSN: MIC length mismatch in Known STA Identification (received %zu, expected %zu)",
7660 mic_len, exp_mic_len);
7661 return false;
7662 }
7663
7664 if (wpa_use_akm_defined(sm->wpa_key_mgmt))
7665 ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
7666 else if (wpa_use_cmac(sm->wpa_key_mgmt))
7667 ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
7668 else if (sm->pairwise != WPA_CIPHER_TKIP)
7669 ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
7670 else
7671 ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
7672
7673 if (wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len, sm->wpa_key_mgmt,
7674 ver, timestamp, 8, exp_mic) ||
7675 os_memcmp_const(mic, exp_mic, exp_mic_len) != 0) {
7676 wpa_printf(MSG_DEBUG,
7677 "RSN: Invalid MIC in Known STA Identification");
7678 return false;
7679 }
7680
7681 return true;
7682}