13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * IEEE 802.11 RSN / WPA Authenticator
3*a1157835SDaniel Fojt  * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "utils/includes.h"
103ff40c12SJohn Marino 
113ff40c12SJohn Marino #include "utils/common.h"
123ff40c12SJohn Marino #include "utils/eloop.h"
133ff40c12SJohn Marino #include "utils/state_machine.h"
143ff40c12SJohn Marino #include "utils/bitfield.h"
153ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
16*a1157835SDaniel Fojt #include "common/ocv.h"
17*a1157835SDaniel Fojt #include "crypto/aes.h"
183ff40c12SJohn Marino #include "crypto/aes_wrap.h"
19*a1157835SDaniel Fojt #include "crypto/aes_siv.h"
203ff40c12SJohn Marino #include "crypto/crypto.h"
213ff40c12SJohn Marino #include "crypto/sha1.h"
223ff40c12SJohn Marino #include "crypto/sha256.h"
23*a1157835SDaniel Fojt #include "crypto/sha384.h"
243ff40c12SJohn Marino #include "crypto/random.h"
253ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm.h"
26*a1157835SDaniel Fojt #include "drivers/driver.h"
273ff40c12SJohn Marino #include "ap_config.h"
283ff40c12SJohn Marino #include "ieee802_11.h"
293ff40c12SJohn Marino #include "wpa_auth.h"
303ff40c12SJohn Marino #include "pmksa_cache_auth.h"
313ff40c12SJohn Marino #include "wpa_auth_i.h"
323ff40c12SJohn Marino #include "wpa_auth_ie.h"
333ff40c12SJohn Marino 
343ff40c12SJohn Marino #define STATE_MACHINE_DATA struct wpa_state_machine
353ff40c12SJohn Marino #define STATE_MACHINE_DEBUG_PREFIX "WPA"
363ff40c12SJohn Marino #define STATE_MACHINE_ADDR sm->addr
373ff40c12SJohn Marino 
383ff40c12SJohn Marino 
393ff40c12SJohn Marino static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
403ff40c12SJohn Marino static int wpa_sm_step(struct wpa_state_machine *sm);
41*a1157835SDaniel Fojt static int wpa_verify_key_mic(int akmp, size_t pmk_len, struct wpa_ptk *PTK,
42*a1157835SDaniel Fojt 			      u8 *data, size_t data_len);
43*a1157835SDaniel Fojt #ifdef CONFIG_FILS
44*a1157835SDaniel Fojt static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
45*a1157835SDaniel Fojt 			    u8 *buf, size_t buf_len, u16 *_key_data_len);
46*a1157835SDaniel Fojt static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
47*a1157835SDaniel Fojt 					     const struct wpabuf *hlp);
48*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
493ff40c12SJohn Marino static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
503ff40c12SJohn Marino static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
513ff40c12SJohn Marino 			      struct wpa_group *group);
523ff40c12SJohn Marino static void wpa_request_new_ptk(struct wpa_state_machine *sm);
533ff40c12SJohn Marino static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
543ff40c12SJohn Marino 			  struct wpa_group *group);
553ff40c12SJohn Marino static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
563ff40c12SJohn Marino 				       struct wpa_group *group);
57*a1157835SDaniel Fojt static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
58*a1157835SDaniel Fojt 			  const u8 *pmk, unsigned int pmk_len,
59*a1157835SDaniel Fojt 			  struct wpa_ptk *ptk);
60*a1157835SDaniel Fojt static void wpa_group_free(struct wpa_authenticator *wpa_auth,
61*a1157835SDaniel Fojt 			   struct wpa_group *group);
62*a1157835SDaniel Fojt static void wpa_group_get(struct wpa_authenticator *wpa_auth,
63*a1157835SDaniel Fojt 			  struct wpa_group *group);
64*a1157835SDaniel Fojt static void wpa_group_put(struct wpa_authenticator *wpa_auth,
65*a1157835SDaniel Fojt 			  struct wpa_group *group);
66*a1157835SDaniel Fojt static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
673ff40c12SJohn Marino 
683ff40c12SJohn Marino static const u32 eapol_key_timeout_first = 100; /* ms */
693ff40c12SJohn Marino static const u32 eapol_key_timeout_subseq = 1000; /* ms */
703ff40c12SJohn Marino static const u32 eapol_key_timeout_first_group = 500; /* ms */
71*a1157835SDaniel Fojt static const u32 eapol_key_timeout_no_retrans = 4000; /* ms */
723ff40c12SJohn Marino 
733ff40c12SJohn Marino /* TODO: make these configurable */
743ff40c12SJohn Marino static const int dot11RSNAConfigPMKLifetime = 43200;
753ff40c12SJohn Marino static const int dot11RSNAConfigPMKReauthThreshold = 70;
763ff40c12SJohn Marino static const int dot11RSNAConfigSATimeout = 60;
773ff40c12SJohn Marino 
783ff40c12SJohn Marino 
wpa_auth_mic_failure_report(struct wpa_authenticator * wpa_auth,const u8 * addr)793ff40c12SJohn Marino static inline int wpa_auth_mic_failure_report(
803ff40c12SJohn Marino 	struct wpa_authenticator *wpa_auth, const u8 *addr)
813ff40c12SJohn Marino {
82*a1157835SDaniel Fojt 	if (wpa_auth->cb->mic_failure_report)
83*a1157835SDaniel Fojt 		return wpa_auth->cb->mic_failure_report(wpa_auth->cb_ctx, addr);
843ff40c12SJohn Marino 	return 0;
853ff40c12SJohn Marino }
863ff40c12SJohn Marino 
873ff40c12SJohn Marino 
wpa_auth_psk_failure_report(struct wpa_authenticator * wpa_auth,const u8 * addr)88*a1157835SDaniel Fojt static inline void wpa_auth_psk_failure_report(
89*a1157835SDaniel Fojt 	struct wpa_authenticator *wpa_auth, const u8 *addr)
90*a1157835SDaniel Fojt {
91*a1157835SDaniel Fojt 	if (wpa_auth->cb->psk_failure_report)
92*a1157835SDaniel Fojt 		wpa_auth->cb->psk_failure_report(wpa_auth->cb_ctx, addr);
93*a1157835SDaniel Fojt }
94*a1157835SDaniel Fojt 
95*a1157835SDaniel Fojt 
wpa_auth_set_eapol(struct wpa_authenticator * wpa_auth,const u8 * addr,wpa_eapol_variable var,int value)963ff40c12SJohn Marino static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
973ff40c12SJohn Marino 				      const u8 *addr, wpa_eapol_variable var,
983ff40c12SJohn Marino 				      int value)
993ff40c12SJohn Marino {
100*a1157835SDaniel Fojt 	if (wpa_auth->cb->set_eapol)
101*a1157835SDaniel Fojt 		wpa_auth->cb->set_eapol(wpa_auth->cb_ctx, addr, var, value);
1023ff40c12SJohn Marino }
1033ff40c12SJohn Marino 
1043ff40c12SJohn Marino 
wpa_auth_get_eapol(struct wpa_authenticator * wpa_auth,const u8 * addr,wpa_eapol_variable var)1053ff40c12SJohn Marino static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
1063ff40c12SJohn Marino 				     const u8 *addr, wpa_eapol_variable var)
1073ff40c12SJohn Marino {
108*a1157835SDaniel Fojt 	if (wpa_auth->cb->get_eapol == NULL)
1093ff40c12SJohn Marino 		return -1;
110*a1157835SDaniel Fojt 	return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
1113ff40c12SJohn Marino }
1123ff40c12SJohn Marino 
1133ff40c12SJohn Marino 
wpa_auth_get_psk(struct wpa_authenticator * wpa_auth,const u8 * addr,const u8 * p2p_dev_addr,const u8 * prev_psk,size_t * psk_len,int * vlan_id)1143ff40c12SJohn Marino static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
1153ff40c12SJohn Marino 					  const u8 *addr,
1163ff40c12SJohn Marino 					  const u8 *p2p_dev_addr,
117*a1157835SDaniel Fojt 					  const u8 *prev_psk, size_t *psk_len,
118*a1157835SDaniel Fojt 					  int *vlan_id)
1193ff40c12SJohn Marino {
120*a1157835SDaniel Fojt 	if (wpa_auth->cb->get_psk == NULL)
1213ff40c12SJohn Marino 		return NULL;
122*a1157835SDaniel Fojt 	return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
123*a1157835SDaniel Fojt 				     prev_psk, psk_len, vlan_id);
1243ff40c12SJohn Marino }
1253ff40c12SJohn Marino 
1263ff40c12SJohn Marino 
wpa_auth_get_msk(struct wpa_authenticator * wpa_auth,const u8 * addr,u8 * msk,size_t * len)1273ff40c12SJohn Marino static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
1283ff40c12SJohn Marino 				   const u8 *addr, u8 *msk, size_t *len)
1293ff40c12SJohn Marino {
130*a1157835SDaniel Fojt 	if (wpa_auth->cb->get_msk == NULL)
1313ff40c12SJohn Marino 		return -1;
132*a1157835SDaniel Fojt 	return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
1333ff40c12SJohn Marino }
1343ff40c12SJohn Marino 
1353ff40c12SJohn Marino 
wpa_auth_set_key(struct wpa_authenticator * wpa_auth,int vlan_id,enum wpa_alg alg,const u8 * addr,int idx,u8 * key,size_t key_len)1363ff40c12SJohn Marino static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
1373ff40c12SJohn Marino 				   int vlan_id,
1383ff40c12SJohn Marino 				   enum wpa_alg alg, const u8 *addr, int idx,
1393ff40c12SJohn Marino 				   u8 *key, size_t key_len)
1403ff40c12SJohn Marino {
141*a1157835SDaniel Fojt 	if (wpa_auth->cb->set_key == NULL)
1423ff40c12SJohn Marino 		return -1;
143*a1157835SDaniel Fojt 	return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
1443ff40c12SJohn Marino 				     key, key_len);
1453ff40c12SJohn Marino }
1463ff40c12SJohn Marino 
1473ff40c12SJohn Marino 
wpa_auth_get_seqnum(struct wpa_authenticator * wpa_auth,const u8 * addr,int idx,u8 * seq)1483ff40c12SJohn Marino static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
1493ff40c12SJohn Marino 				      const u8 *addr, int idx, u8 *seq)
1503ff40c12SJohn Marino {
151*a1157835SDaniel Fojt 	if (wpa_auth->cb->get_seqnum == NULL)
1523ff40c12SJohn Marino 		return -1;
153*a1157835SDaniel Fojt 	return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
1543ff40c12SJohn Marino }
1553ff40c12SJohn Marino 
1563ff40c12SJohn Marino 
1573ff40c12SJohn Marino static inline int
wpa_auth_send_eapol(struct wpa_authenticator * wpa_auth,const u8 * addr,const u8 * data,size_t data_len,int encrypt)1583ff40c12SJohn Marino wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
1593ff40c12SJohn Marino 		    const u8 *data, size_t data_len, int encrypt)
1603ff40c12SJohn Marino {
161*a1157835SDaniel Fojt 	if (wpa_auth->cb->send_eapol == NULL)
1623ff40c12SJohn Marino 		return -1;
163*a1157835SDaniel Fojt 	return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
1643ff40c12SJohn Marino 					encrypt);
1653ff40c12SJohn Marino }
1663ff40c12SJohn Marino 
1673ff40c12SJohn Marino 
168*a1157835SDaniel Fojt #ifdef CONFIG_MESH
wpa_auth_start_ampe(struct wpa_authenticator * wpa_auth,const u8 * addr)169*a1157835SDaniel Fojt static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
170*a1157835SDaniel Fojt 				      const u8 *addr)
171*a1157835SDaniel Fojt {
172*a1157835SDaniel Fojt 	if (wpa_auth->cb->start_ampe == NULL)
173*a1157835SDaniel Fojt 		return -1;
174*a1157835SDaniel Fojt 	return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
175*a1157835SDaniel Fojt }
176*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
177*a1157835SDaniel Fojt 
178*a1157835SDaniel Fojt 
wpa_auth_for_each_sta(struct wpa_authenticator * wpa_auth,int (* cb)(struct wpa_state_machine * sm,void * ctx),void * cb_ctx)1793ff40c12SJohn Marino int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
1803ff40c12SJohn Marino 			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
1813ff40c12SJohn Marino 			  void *cb_ctx)
1823ff40c12SJohn Marino {
183*a1157835SDaniel Fojt 	if (wpa_auth->cb->for_each_sta == NULL)
1843ff40c12SJohn Marino 		return 0;
185*a1157835SDaniel Fojt 	return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
1863ff40c12SJohn Marino }
1873ff40c12SJohn Marino 
1883ff40c12SJohn Marino 
wpa_auth_for_each_auth(struct wpa_authenticator * wpa_auth,int (* cb)(struct wpa_authenticator * a,void * ctx),void * cb_ctx)1893ff40c12SJohn Marino int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
1903ff40c12SJohn Marino 			   int (*cb)(struct wpa_authenticator *a, void *ctx),
1913ff40c12SJohn Marino 			   void *cb_ctx)
1923ff40c12SJohn Marino {
193*a1157835SDaniel Fojt 	if (wpa_auth->cb->for_each_auth == NULL)
1943ff40c12SJohn Marino 		return 0;
195*a1157835SDaniel Fojt 	return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
1963ff40c12SJohn Marino }
1973ff40c12SJohn Marino 
1983ff40c12SJohn Marino 
wpa_auth_logger(struct wpa_authenticator * wpa_auth,const u8 * addr,logger_level level,const char * txt)1993ff40c12SJohn Marino void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
2003ff40c12SJohn Marino 		     logger_level level, const char *txt)
2013ff40c12SJohn Marino {
202*a1157835SDaniel Fojt 	if (wpa_auth->cb->logger == NULL)
2033ff40c12SJohn Marino 		return;
204*a1157835SDaniel Fojt 	wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
2053ff40c12SJohn Marino }
2063ff40c12SJohn Marino 
2073ff40c12SJohn Marino 
wpa_auth_vlogger(struct wpa_authenticator * wpa_auth,const u8 * addr,logger_level level,const char * fmt,...)2083ff40c12SJohn Marino void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
2093ff40c12SJohn Marino 		      logger_level level, const char *fmt, ...)
2103ff40c12SJohn Marino {
2113ff40c12SJohn Marino 	char *format;
2123ff40c12SJohn Marino 	int maxlen;
2133ff40c12SJohn Marino 	va_list ap;
2143ff40c12SJohn Marino 
215*a1157835SDaniel Fojt 	if (wpa_auth->cb->logger == NULL)
2163ff40c12SJohn Marino 		return;
2173ff40c12SJohn Marino 
2183ff40c12SJohn Marino 	maxlen = os_strlen(fmt) + 100;
2193ff40c12SJohn Marino 	format = os_malloc(maxlen);
2203ff40c12SJohn Marino 	if (!format)
2213ff40c12SJohn Marino 		return;
2223ff40c12SJohn Marino 
2233ff40c12SJohn Marino 	va_start(ap, fmt);
2243ff40c12SJohn Marino 	vsnprintf(format, maxlen, fmt, ap);
2253ff40c12SJohn Marino 	va_end(ap);
2263ff40c12SJohn Marino 
2273ff40c12SJohn Marino 	wpa_auth_logger(wpa_auth, addr, level, format);
2283ff40c12SJohn Marino 
2293ff40c12SJohn Marino 	os_free(format);
2303ff40c12SJohn Marino }
2313ff40c12SJohn Marino 
2323ff40c12SJohn Marino 
wpa_sta_disconnect(struct wpa_authenticator * wpa_auth,const u8 * addr,u16 reason)2333ff40c12SJohn Marino static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
234*a1157835SDaniel Fojt 			       const u8 *addr, u16 reason)
2353ff40c12SJohn Marino {
236*a1157835SDaniel Fojt 	if (wpa_auth->cb->disconnect == NULL)
2373ff40c12SJohn Marino 		return;
238*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)",
239*a1157835SDaniel Fojt 		   MAC2STR(addr), reason);
240*a1157835SDaniel Fojt 	wpa_auth->cb->disconnect(wpa_auth->cb_ctx, addr, reason);
2413ff40c12SJohn Marino }
2423ff40c12SJohn Marino 
2433ff40c12SJohn Marino 
244*a1157835SDaniel Fojt #ifdef CONFIG_OCV
wpa_channel_info(struct wpa_authenticator * wpa_auth,struct wpa_channel_info * ci)245*a1157835SDaniel Fojt static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
246*a1157835SDaniel Fojt 			    struct wpa_channel_info *ci)
2473ff40c12SJohn Marino {
248*a1157835SDaniel Fojt 	if (!wpa_auth->cb->channel_info)
249*a1157835SDaniel Fojt 		return -1;
250*a1157835SDaniel Fojt 	return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
251*a1157835SDaniel Fojt }
252*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
253*a1157835SDaniel Fojt 
254*a1157835SDaniel Fojt 
wpa_auth_update_vlan(struct wpa_authenticator * wpa_auth,const u8 * addr,int vlan_id)255*a1157835SDaniel Fojt static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth,
256*a1157835SDaniel Fojt 				const u8 *addr, int vlan_id)
257*a1157835SDaniel Fojt {
258*a1157835SDaniel Fojt 	if (!wpa_auth->cb->update_vlan)
259*a1157835SDaniel Fojt 		return -1;
260*a1157835SDaniel Fojt 	return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id);
2613ff40c12SJohn Marino }
2623ff40c12SJohn Marino 
2633ff40c12SJohn Marino 
wpa_rekey_gmk(void * eloop_ctx,void * timeout_ctx)2643ff40c12SJohn Marino static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
2653ff40c12SJohn Marino {
2663ff40c12SJohn Marino 	struct wpa_authenticator *wpa_auth = eloop_ctx;
2673ff40c12SJohn Marino 
2683ff40c12SJohn Marino 	if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
2693ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
2703ff40c12SJohn Marino 			   "initialization.");
2713ff40c12SJohn Marino 	} else {
2723ff40c12SJohn Marino 		wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
2733ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "GMK",
2743ff40c12SJohn Marino 				wpa_auth->group->GMK, WPA_GMK_LEN);
2753ff40c12SJohn Marino 	}
2763ff40c12SJohn Marino 
2773ff40c12SJohn Marino 	if (wpa_auth->conf.wpa_gmk_rekey) {
2783ff40c12SJohn Marino 		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
2793ff40c12SJohn Marino 				       wpa_rekey_gmk, wpa_auth, NULL);
2803ff40c12SJohn Marino 	}
2813ff40c12SJohn Marino }
2823ff40c12SJohn Marino 
2833ff40c12SJohn Marino 
wpa_rekey_gtk(void * eloop_ctx,void * timeout_ctx)2843ff40c12SJohn Marino static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
2853ff40c12SJohn Marino {
2863ff40c12SJohn Marino 	struct wpa_authenticator *wpa_auth = eloop_ctx;
287*a1157835SDaniel Fojt 	struct wpa_group *group, *next;
2883ff40c12SJohn Marino 
2893ff40c12SJohn Marino 	wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
290*a1157835SDaniel Fojt 	group = wpa_auth->group;
291*a1157835SDaniel Fojt 	while (group) {
292*a1157835SDaniel Fojt 		wpa_group_get(wpa_auth, group);
293*a1157835SDaniel Fojt 
2943ff40c12SJohn Marino 		group->GTKReKey = TRUE;
2953ff40c12SJohn Marino 		do {
2963ff40c12SJohn Marino 			group->changed = FALSE;
2973ff40c12SJohn Marino 			wpa_group_sm_step(wpa_auth, group);
2983ff40c12SJohn Marino 		} while (group->changed);
299*a1157835SDaniel Fojt 
300*a1157835SDaniel Fojt 		next = group->next;
301*a1157835SDaniel Fojt 		wpa_group_put(wpa_auth, group);
302*a1157835SDaniel Fojt 		group = next;
3033ff40c12SJohn Marino 	}
3043ff40c12SJohn Marino 
3053ff40c12SJohn Marino 	if (wpa_auth->conf.wpa_group_rekey) {
3063ff40c12SJohn Marino 		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
3073ff40c12SJohn Marino 				       0, wpa_rekey_gtk, wpa_auth, NULL);
3083ff40c12SJohn Marino 	}
3093ff40c12SJohn Marino }
3103ff40c12SJohn Marino 
3113ff40c12SJohn Marino 
wpa_rekey_ptk(void * eloop_ctx,void * timeout_ctx)3123ff40c12SJohn Marino static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
3133ff40c12SJohn Marino {
3143ff40c12SJohn Marino 	struct wpa_authenticator *wpa_auth = eloop_ctx;
3153ff40c12SJohn Marino 	struct wpa_state_machine *sm = timeout_ctx;
3163ff40c12SJohn Marino 
3173ff40c12SJohn Marino 	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
3183ff40c12SJohn Marino 	wpa_request_new_ptk(sm);
3193ff40c12SJohn Marino 	wpa_sm_step(sm);
3203ff40c12SJohn Marino }
3213ff40c12SJohn Marino 
3223ff40c12SJohn Marino 
wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine * sm)323*a1157835SDaniel Fojt void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm)
324*a1157835SDaniel Fojt {
325*a1157835SDaniel Fojt 	if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) {
326*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for "
327*a1157835SDaniel Fojt 			   MACSTR " (%d seconds)", MAC2STR(sm->addr),
328*a1157835SDaniel Fojt 			   sm->wpa_auth->conf.wpa_ptk_rekey);
329*a1157835SDaniel Fojt 		eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
330*a1157835SDaniel Fojt 		eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0,
331*a1157835SDaniel Fojt 				       wpa_rekey_ptk, sm->wpa_auth, sm);
332*a1157835SDaniel Fojt 	}
333*a1157835SDaniel Fojt }
334*a1157835SDaniel Fojt 
335*a1157835SDaniel Fojt 
wpa_auth_pmksa_clear_cb(struct wpa_state_machine * sm,void * ctx)3363ff40c12SJohn Marino static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
3373ff40c12SJohn Marino {
3383ff40c12SJohn Marino 	if (sm->pmksa == ctx)
3393ff40c12SJohn Marino 		sm->pmksa = NULL;
3403ff40c12SJohn Marino 	return 0;
3413ff40c12SJohn Marino }
3423ff40c12SJohn Marino 
3433ff40c12SJohn Marino 
wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry * entry,void * ctx)3443ff40c12SJohn Marino static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
3453ff40c12SJohn Marino 				   void *ctx)
3463ff40c12SJohn Marino {
3473ff40c12SJohn Marino 	struct wpa_authenticator *wpa_auth = ctx;
3483ff40c12SJohn Marino 	wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
3493ff40c12SJohn Marino }
3503ff40c12SJohn Marino 
3513ff40c12SJohn Marino 
wpa_group_init_gmk_and_counter(struct wpa_authenticator * wpa_auth,struct wpa_group * group)3523ff40c12SJohn Marino static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
3533ff40c12SJohn Marino 					  struct wpa_group *group)
3543ff40c12SJohn Marino {
3553ff40c12SJohn Marino 	u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)];
3563ff40c12SJohn Marino 	u8 rkey[32];
3573ff40c12SJohn Marino 	unsigned long ptr;
3583ff40c12SJohn Marino 
3593ff40c12SJohn Marino 	if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
3603ff40c12SJohn Marino 		return -1;
3613ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "GMK", group->GMK, WPA_GMK_LEN);
3623ff40c12SJohn Marino 
3633ff40c12SJohn Marino 	/*
3643ff40c12SJohn Marino 	 * Counter = PRF-256(Random number, "Init Counter",
3653ff40c12SJohn Marino 	 *                   Local MAC Address || Time)
3663ff40c12SJohn Marino 	 */
3673ff40c12SJohn Marino 	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
3683ff40c12SJohn Marino 	wpa_get_ntp_timestamp(buf + ETH_ALEN);
3693ff40c12SJohn Marino 	ptr = (unsigned long) group;
3703ff40c12SJohn Marino 	os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
371*a1157835SDaniel Fojt #ifdef TEST_FUZZ
372*a1157835SDaniel Fojt 	os_memset(buf + ETH_ALEN, 0xab, 8);
373*a1157835SDaniel Fojt 	os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr));
374*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
3753ff40c12SJohn Marino 	if (random_get_bytes(rkey, sizeof(rkey)) < 0)
3763ff40c12SJohn Marino 		return -1;
3773ff40c12SJohn Marino 
3783ff40c12SJohn Marino 	if (sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
3793ff40c12SJohn Marino 		     group->Counter, WPA_NONCE_LEN) < 0)
3803ff40c12SJohn Marino 		return -1;
3813ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "Key Counter",
3823ff40c12SJohn Marino 			group->Counter, WPA_NONCE_LEN);
3833ff40c12SJohn Marino 
3843ff40c12SJohn Marino 	return 0;
3853ff40c12SJohn Marino }
3863ff40c12SJohn Marino 
3873ff40c12SJohn Marino 
wpa_group_init(struct wpa_authenticator * wpa_auth,int vlan_id,int delay_init)3883ff40c12SJohn Marino static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
3893ff40c12SJohn Marino 					 int vlan_id, int delay_init)
3903ff40c12SJohn Marino {
3913ff40c12SJohn Marino 	struct wpa_group *group;
3923ff40c12SJohn Marino 
3933ff40c12SJohn Marino 	group = os_zalloc(sizeof(struct wpa_group));
3943ff40c12SJohn Marino 	if (group == NULL)
3953ff40c12SJohn Marino 		return NULL;
3963ff40c12SJohn Marino 
3973ff40c12SJohn Marino 	group->GTKAuthenticator = TRUE;
3983ff40c12SJohn Marino 	group->vlan_id = vlan_id;
3993ff40c12SJohn Marino 	group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
4003ff40c12SJohn Marino 
4013ff40c12SJohn Marino 	if (random_pool_ready() != 1) {
4023ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
4033ff40c12SJohn Marino 			   "for secure operations - update keys later when "
4043ff40c12SJohn Marino 			   "the first station connects");
4053ff40c12SJohn Marino 	}
4063ff40c12SJohn Marino 
4073ff40c12SJohn Marino 	/*
4083ff40c12SJohn Marino 	 * Set initial GMK/Counter value here. The actual values that will be
4093ff40c12SJohn Marino 	 * used in negotiations will be set once the first station tries to
4103ff40c12SJohn Marino 	 * connect. This allows more time for collecting additional randomness
4113ff40c12SJohn Marino 	 * on embedded devices.
4123ff40c12SJohn Marino 	 */
4133ff40c12SJohn Marino 	if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
4143ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
4153ff40c12SJohn Marino 			   "initialization.");
4163ff40c12SJohn Marino 		os_free(group);
4173ff40c12SJohn Marino 		return NULL;
4183ff40c12SJohn Marino 	}
4193ff40c12SJohn Marino 
4203ff40c12SJohn Marino 	group->GInit = TRUE;
4213ff40c12SJohn Marino 	if (delay_init) {
4223ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
4233ff40c12SJohn Marino 			   "until Beacon frames have been configured");
4243ff40c12SJohn Marino 		/* Initialization is completed in wpa_init_keys(). */
4253ff40c12SJohn Marino 	} else {
4263ff40c12SJohn Marino 		wpa_group_sm_step(wpa_auth, group);
4273ff40c12SJohn Marino 		group->GInit = FALSE;
4283ff40c12SJohn Marino 		wpa_group_sm_step(wpa_auth, group);
4293ff40c12SJohn Marino 	}
4303ff40c12SJohn Marino 
4313ff40c12SJohn Marino 	return group;
4323ff40c12SJohn Marino }
4333ff40c12SJohn Marino 
4343ff40c12SJohn Marino 
4353ff40c12SJohn Marino /**
4363ff40c12SJohn Marino  * wpa_init - Initialize WPA authenticator
4373ff40c12SJohn Marino  * @addr: Authenticator address
4383ff40c12SJohn Marino  * @conf: Configuration for WPA authenticator
4393ff40c12SJohn Marino  * @cb: Callback functions for WPA authenticator
4403ff40c12SJohn Marino  * Returns: Pointer to WPA authenticator data or %NULL on failure
4413ff40c12SJohn Marino  */
wpa_init(const u8 * addr,struct wpa_auth_config * conf,const struct wpa_auth_callbacks * cb,void * cb_ctx)4423ff40c12SJohn Marino struct wpa_authenticator * wpa_init(const u8 *addr,
4433ff40c12SJohn Marino 				    struct wpa_auth_config *conf,
444*a1157835SDaniel Fojt 				    const struct wpa_auth_callbacks *cb,
445*a1157835SDaniel Fojt 				    void *cb_ctx)
4463ff40c12SJohn Marino {
4473ff40c12SJohn Marino 	struct wpa_authenticator *wpa_auth;
4483ff40c12SJohn Marino 
4493ff40c12SJohn Marino 	wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
4503ff40c12SJohn Marino 	if (wpa_auth == NULL)
4513ff40c12SJohn Marino 		return NULL;
4523ff40c12SJohn Marino 	os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
4533ff40c12SJohn Marino 	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
454*a1157835SDaniel Fojt 	wpa_auth->cb = cb;
455*a1157835SDaniel Fojt 	wpa_auth->cb_ctx = cb_ctx;
4563ff40c12SJohn Marino 
4573ff40c12SJohn Marino 	if (wpa_auth_gen_wpa_ie(wpa_auth)) {
4583ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
4593ff40c12SJohn Marino 		os_free(wpa_auth);
4603ff40c12SJohn Marino 		return NULL;
4613ff40c12SJohn Marino 	}
4623ff40c12SJohn Marino 
4633ff40c12SJohn Marino 	wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
4643ff40c12SJohn Marino 	if (wpa_auth->group == NULL) {
4653ff40c12SJohn Marino 		os_free(wpa_auth->wpa_ie);
4663ff40c12SJohn Marino 		os_free(wpa_auth);
4673ff40c12SJohn Marino 		return NULL;
4683ff40c12SJohn Marino 	}
4693ff40c12SJohn Marino 
4703ff40c12SJohn Marino 	wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
4713ff40c12SJohn Marino 						wpa_auth);
4723ff40c12SJohn Marino 	if (wpa_auth->pmksa == NULL) {
4733ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
474*a1157835SDaniel Fojt 		os_free(wpa_auth->group);
4753ff40c12SJohn Marino 		os_free(wpa_auth->wpa_ie);
4763ff40c12SJohn Marino 		os_free(wpa_auth);
4773ff40c12SJohn Marino 		return NULL;
4783ff40c12SJohn Marino 	}
4793ff40c12SJohn Marino 
480*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
4813ff40c12SJohn Marino 	wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
4823ff40c12SJohn Marino 	if (wpa_auth->ft_pmk_cache == NULL) {
4833ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
484*a1157835SDaniel Fojt 		os_free(wpa_auth->group);
4853ff40c12SJohn Marino 		os_free(wpa_auth->wpa_ie);
4863ff40c12SJohn Marino 		pmksa_cache_auth_deinit(wpa_auth->pmksa);
4873ff40c12SJohn Marino 		os_free(wpa_auth);
4883ff40c12SJohn Marino 		return NULL;
4893ff40c12SJohn Marino 	}
490*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
4913ff40c12SJohn Marino 
4923ff40c12SJohn Marino 	if (wpa_auth->conf.wpa_gmk_rekey) {
4933ff40c12SJohn Marino 		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
4943ff40c12SJohn Marino 				       wpa_rekey_gmk, wpa_auth, NULL);
4953ff40c12SJohn Marino 	}
4963ff40c12SJohn Marino 
4973ff40c12SJohn Marino 	if (wpa_auth->conf.wpa_group_rekey) {
4983ff40c12SJohn Marino 		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
4993ff40c12SJohn Marino 				       wpa_rekey_gtk, wpa_auth, NULL);
5003ff40c12SJohn Marino 	}
5013ff40c12SJohn Marino 
5023ff40c12SJohn Marino #ifdef CONFIG_P2P
5033ff40c12SJohn Marino 	if (WPA_GET_BE32(conf->ip_addr_start)) {
5043ff40c12SJohn Marino 		int count = WPA_GET_BE32(conf->ip_addr_end) -
5053ff40c12SJohn Marino 			WPA_GET_BE32(conf->ip_addr_start) + 1;
5063ff40c12SJohn Marino 		if (count > 1000)
5073ff40c12SJohn Marino 			count = 1000;
5083ff40c12SJohn Marino 		if (count > 0)
5093ff40c12SJohn Marino 			wpa_auth->ip_pool = bitfield_alloc(count);
5103ff40c12SJohn Marino 	}
5113ff40c12SJohn Marino #endif /* CONFIG_P2P */
5123ff40c12SJohn Marino 
5133ff40c12SJohn Marino 	return wpa_auth;
5143ff40c12SJohn Marino }
5153ff40c12SJohn Marino 
5163ff40c12SJohn Marino 
wpa_init_keys(struct wpa_authenticator * wpa_auth)5173ff40c12SJohn Marino int wpa_init_keys(struct wpa_authenticator *wpa_auth)
5183ff40c12SJohn Marino {
5193ff40c12SJohn Marino 	struct wpa_group *group = wpa_auth->group;
5203ff40c12SJohn Marino 
5213ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
5223ff40c12SJohn Marino 		   "keys");
5233ff40c12SJohn Marino 	wpa_group_sm_step(wpa_auth, group);
5243ff40c12SJohn Marino 	group->GInit = FALSE;
5253ff40c12SJohn Marino 	wpa_group_sm_step(wpa_auth, group);
5263ff40c12SJohn Marino 	if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
5273ff40c12SJohn Marino 		return -1;
5283ff40c12SJohn Marino 	return 0;
5293ff40c12SJohn Marino }
5303ff40c12SJohn Marino 
5313ff40c12SJohn Marino 
5323ff40c12SJohn Marino /**
5333ff40c12SJohn Marino  * wpa_deinit - Deinitialize WPA authenticator
5343ff40c12SJohn Marino  * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
5353ff40c12SJohn Marino  */
wpa_deinit(struct wpa_authenticator * wpa_auth)5363ff40c12SJohn Marino void wpa_deinit(struct wpa_authenticator *wpa_auth)
5373ff40c12SJohn Marino {
5383ff40c12SJohn Marino 	struct wpa_group *group, *prev;
5393ff40c12SJohn Marino 
5403ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
5413ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
5423ff40c12SJohn Marino 
5433ff40c12SJohn Marino 	pmksa_cache_auth_deinit(wpa_auth->pmksa);
5443ff40c12SJohn Marino 
545*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
5463ff40c12SJohn Marino 	wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
5473ff40c12SJohn Marino 	wpa_auth->ft_pmk_cache = NULL;
548*a1157835SDaniel Fojt 	wpa_ft_deinit(wpa_auth);
549*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
5503ff40c12SJohn Marino 
5513ff40c12SJohn Marino #ifdef CONFIG_P2P
5523ff40c12SJohn Marino 	bitfield_free(wpa_auth->ip_pool);
5533ff40c12SJohn Marino #endif /* CONFIG_P2P */
5543ff40c12SJohn Marino 
5553ff40c12SJohn Marino 
5563ff40c12SJohn Marino 	os_free(wpa_auth->wpa_ie);
5573ff40c12SJohn Marino 
5583ff40c12SJohn Marino 	group = wpa_auth->group;
5593ff40c12SJohn Marino 	while (group) {
5603ff40c12SJohn Marino 		prev = group;
5613ff40c12SJohn Marino 		group = group->next;
5623ff40c12SJohn Marino 		os_free(prev);
5633ff40c12SJohn Marino 	}
5643ff40c12SJohn Marino 
5653ff40c12SJohn Marino 	os_free(wpa_auth);
5663ff40c12SJohn Marino }
5673ff40c12SJohn Marino 
5683ff40c12SJohn Marino 
5693ff40c12SJohn Marino /**
5703ff40c12SJohn Marino  * wpa_reconfig - Update WPA authenticator configuration
5713ff40c12SJohn Marino  * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
5723ff40c12SJohn Marino  * @conf: Configuration for WPA authenticator
5733ff40c12SJohn Marino  */
wpa_reconfig(struct wpa_authenticator * wpa_auth,struct wpa_auth_config * conf)5743ff40c12SJohn Marino int wpa_reconfig(struct wpa_authenticator *wpa_auth,
5753ff40c12SJohn Marino 		 struct wpa_auth_config *conf)
5763ff40c12SJohn Marino {
5773ff40c12SJohn Marino 	struct wpa_group *group;
5783ff40c12SJohn Marino 	if (wpa_auth == NULL)
5793ff40c12SJohn Marino 		return 0;
5803ff40c12SJohn Marino 
5813ff40c12SJohn Marino 	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
5823ff40c12SJohn Marino 	if (wpa_auth_gen_wpa_ie(wpa_auth)) {
5833ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
5843ff40c12SJohn Marino 		return -1;
5853ff40c12SJohn Marino 	}
5863ff40c12SJohn Marino 
5873ff40c12SJohn Marino 	/*
5883ff40c12SJohn Marino 	 * Reinitialize GTK to make sure it is suitable for the new
5893ff40c12SJohn Marino 	 * configuration.
5903ff40c12SJohn Marino 	 */
5913ff40c12SJohn Marino 	group = wpa_auth->group;
5923ff40c12SJohn Marino 	group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
5933ff40c12SJohn Marino 	group->GInit = TRUE;
5943ff40c12SJohn Marino 	wpa_group_sm_step(wpa_auth, group);
5953ff40c12SJohn Marino 	group->GInit = FALSE;
5963ff40c12SJohn Marino 	wpa_group_sm_step(wpa_auth, group);
5973ff40c12SJohn Marino 
5983ff40c12SJohn Marino 	return 0;
5993ff40c12SJohn Marino }
6003ff40c12SJohn Marino 
6013ff40c12SJohn Marino 
6023ff40c12SJohn Marino struct wpa_state_machine *
wpa_auth_sta_init(struct wpa_authenticator * wpa_auth,const u8 * addr,const u8 * p2p_dev_addr)6033ff40c12SJohn Marino wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
6043ff40c12SJohn Marino 		  const u8 *p2p_dev_addr)
6053ff40c12SJohn Marino {
6063ff40c12SJohn Marino 	struct wpa_state_machine *sm;
6073ff40c12SJohn Marino 
6083ff40c12SJohn Marino 	if (wpa_auth->group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
6093ff40c12SJohn Marino 		return NULL;
6103ff40c12SJohn Marino 
6113ff40c12SJohn Marino 	sm = os_zalloc(sizeof(struct wpa_state_machine));
6123ff40c12SJohn Marino 	if (sm == NULL)
6133ff40c12SJohn Marino 		return NULL;
6143ff40c12SJohn Marino 	os_memcpy(sm->addr, addr, ETH_ALEN);
6153ff40c12SJohn Marino 	if (p2p_dev_addr)
6163ff40c12SJohn Marino 		os_memcpy(sm->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
6173ff40c12SJohn Marino 
6183ff40c12SJohn Marino 	sm->wpa_auth = wpa_auth;
6193ff40c12SJohn Marino 	sm->group = wpa_auth->group;
620*a1157835SDaniel Fojt 	wpa_group_get(sm->wpa_auth, sm->group);
6213ff40c12SJohn Marino 
6223ff40c12SJohn Marino 	return sm;
6233ff40c12SJohn Marino }
6243ff40c12SJohn Marino 
6253ff40c12SJohn Marino 
wpa_auth_sta_associated(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm)6263ff40c12SJohn Marino int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
6273ff40c12SJohn Marino 			    struct wpa_state_machine *sm)
6283ff40c12SJohn Marino {
6293ff40c12SJohn Marino 	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
6303ff40c12SJohn Marino 		return -1;
6313ff40c12SJohn Marino 
632*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
6333ff40c12SJohn Marino 	if (sm->ft_completed) {
6343ff40c12SJohn Marino 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
6353ff40c12SJohn Marino 				"FT authentication already completed - do not "
6363ff40c12SJohn Marino 				"start 4-way handshake");
637*a1157835SDaniel Fojt 		/* Go to PTKINITDONE state to allow GTK rekeying */
638*a1157835SDaniel Fojt 		sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
639*a1157835SDaniel Fojt 		sm->Pair = TRUE;
6403ff40c12SJohn Marino 		return 0;
6413ff40c12SJohn Marino 	}
642*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
643*a1157835SDaniel Fojt 
644*a1157835SDaniel Fojt #ifdef CONFIG_FILS
645*a1157835SDaniel Fojt 	if (sm->fils_completed) {
646*a1157835SDaniel Fojt 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
647*a1157835SDaniel Fojt 				"FILS authentication already completed - do not start 4-way handshake");
648*a1157835SDaniel Fojt 		/* Go to PTKINITDONE state to allow GTK rekeying */
649*a1157835SDaniel Fojt 		sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
650*a1157835SDaniel Fojt 		sm->Pair = TRUE;
651*a1157835SDaniel Fojt 		return 0;
652*a1157835SDaniel Fojt 	}
653*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
6543ff40c12SJohn Marino 
6553ff40c12SJohn Marino 	if (sm->started) {
6563ff40c12SJohn Marino 		os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
6573ff40c12SJohn Marino 		sm->ReAuthenticationRequest = TRUE;
6583ff40c12SJohn Marino 		return wpa_sm_step(sm);
6593ff40c12SJohn Marino 	}
6603ff40c12SJohn Marino 
6613ff40c12SJohn Marino 	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
6623ff40c12SJohn Marino 			"start authentication");
6633ff40c12SJohn Marino 	sm->started = 1;
6643ff40c12SJohn Marino 
6653ff40c12SJohn Marino 	sm->Init = TRUE;
6663ff40c12SJohn Marino 	if (wpa_sm_step(sm) == 1)
6673ff40c12SJohn Marino 		return 1; /* should not really happen */
6683ff40c12SJohn Marino 	sm->Init = FALSE;
6693ff40c12SJohn Marino 	sm->AuthenticationRequest = TRUE;
6703ff40c12SJohn Marino 	return wpa_sm_step(sm);
6713ff40c12SJohn Marino }
6723ff40c12SJohn Marino 
6733ff40c12SJohn Marino 
wpa_auth_sta_no_wpa(struct wpa_state_machine * sm)6743ff40c12SJohn Marino void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
6753ff40c12SJohn Marino {
6763ff40c12SJohn Marino 	/* WPA/RSN was not used - clear WPA state. This is needed if the STA
6773ff40c12SJohn Marino 	 * reassociates back to the same AP while the previous entry for the
6783ff40c12SJohn Marino 	 * STA has not yet been removed. */
6793ff40c12SJohn Marino 	if (sm == NULL)
6803ff40c12SJohn Marino 		return;
6813ff40c12SJohn Marino 
6823ff40c12SJohn Marino 	sm->wpa_key_mgmt = 0;
6833ff40c12SJohn Marino }
6843ff40c12SJohn Marino 
6853ff40c12SJohn Marino 
wpa_free_sta_sm(struct wpa_state_machine * sm)6863ff40c12SJohn Marino static void wpa_free_sta_sm(struct wpa_state_machine *sm)
6873ff40c12SJohn Marino {
6883ff40c12SJohn Marino #ifdef CONFIG_P2P
6893ff40c12SJohn Marino 	if (WPA_GET_BE32(sm->ip_addr)) {
6903ff40c12SJohn Marino 		u32 start;
6913ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
6923ff40c12SJohn Marino 			   "address %u.%u.%u.%u from " MACSTR,
6933ff40c12SJohn Marino 			   sm->ip_addr[0], sm->ip_addr[1],
6943ff40c12SJohn Marino 			   sm->ip_addr[2], sm->ip_addr[3],
6953ff40c12SJohn Marino 			   MAC2STR(sm->addr));
6963ff40c12SJohn Marino 		start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start);
6973ff40c12SJohn Marino 		bitfield_clear(sm->wpa_auth->ip_pool,
6983ff40c12SJohn Marino 			       WPA_GET_BE32(sm->ip_addr) - start);
6993ff40c12SJohn Marino 	}
7003ff40c12SJohn Marino #endif /* CONFIG_P2P */
7013ff40c12SJohn Marino 	if (sm->GUpdateStationKeys) {
7023ff40c12SJohn Marino 		sm->group->GKeyDoneStations--;
7033ff40c12SJohn Marino 		sm->GUpdateStationKeys = FALSE;
7043ff40c12SJohn Marino 	}
705*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
7063ff40c12SJohn Marino 	os_free(sm->assoc_resp_ftie);
707*a1157835SDaniel Fojt 	wpabuf_free(sm->ft_pending_req_ies);
708*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
7093ff40c12SJohn Marino 	os_free(sm->last_rx_eapol_key);
7103ff40c12SJohn Marino 	os_free(sm->wpa_ie);
711*a1157835SDaniel Fojt 	wpa_group_put(sm->wpa_auth, sm->group);
712*a1157835SDaniel Fojt #ifdef CONFIG_DPP2
713*a1157835SDaniel Fojt 	wpabuf_clear_free(sm->dpp_z);
714*a1157835SDaniel Fojt #endif /* CONFIG_DPP2 */
715*a1157835SDaniel Fojt 	bin_clear_free(sm, sizeof(*sm));
7163ff40c12SJohn Marino }
7173ff40c12SJohn Marino 
7183ff40c12SJohn Marino 
wpa_auth_sta_deinit(struct wpa_state_machine * sm)7193ff40c12SJohn Marino void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
7203ff40c12SJohn Marino {
7213ff40c12SJohn Marino 	if (sm == NULL)
7223ff40c12SJohn Marino 		return;
7233ff40c12SJohn Marino 
7243ff40c12SJohn Marino 	if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
7253ff40c12SJohn Marino 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
7263ff40c12SJohn Marino 				"strict rekeying - force GTK rekey since STA "
7273ff40c12SJohn Marino 				"is leaving");
728*a1157835SDaniel Fojt 		if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
729*a1157835SDaniel Fojt 					  sm->wpa_auth, NULL) == -1)
7303ff40c12SJohn Marino 			eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
7313ff40c12SJohn Marino 					       NULL);
7323ff40c12SJohn Marino 	}
7333ff40c12SJohn Marino 
7343ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
7353ff40c12SJohn Marino 	sm->pending_1_of_4_timeout = 0;
7363ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
7373ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
738*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
739*a1157835SDaniel Fojt 	wpa_ft_sta_deinit(sm);
740*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
7413ff40c12SJohn Marino 	if (sm->in_step_loop) {
7423ff40c12SJohn Marino 		/* Must not free state machine while wpa_sm_step() is running.
7433ff40c12SJohn Marino 		 * Freeing will be completed in the end of wpa_sm_step(). */
7443ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
7453ff40c12SJohn Marino 			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
7463ff40c12SJohn Marino 		sm->pending_deinit = 1;
7473ff40c12SJohn Marino 	} else
7483ff40c12SJohn Marino 		wpa_free_sta_sm(sm);
7493ff40c12SJohn Marino }
7503ff40c12SJohn Marino 
7513ff40c12SJohn Marino 
wpa_request_new_ptk(struct wpa_state_machine * sm)7523ff40c12SJohn Marino static void wpa_request_new_ptk(struct wpa_state_machine *sm)
7533ff40c12SJohn Marino {
7543ff40c12SJohn Marino 	if (sm == NULL)
7553ff40c12SJohn Marino 		return;
7563ff40c12SJohn Marino 
7573ff40c12SJohn Marino 	sm->PTKRequest = TRUE;
7583ff40c12SJohn Marino 	sm->PTK_valid = 0;
7593ff40c12SJohn Marino }
7603ff40c12SJohn Marino 
7613ff40c12SJohn Marino 
wpa_replay_counter_valid(struct wpa_key_replay_counter * ctr,const u8 * replay_counter)7623ff40c12SJohn Marino static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr,
7633ff40c12SJohn Marino 				    const u8 *replay_counter)
7643ff40c12SJohn Marino {
7653ff40c12SJohn Marino 	int i;
7663ff40c12SJohn Marino 	for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
7673ff40c12SJohn Marino 		if (!ctr[i].valid)
7683ff40c12SJohn Marino 			break;
7693ff40c12SJohn Marino 		if (os_memcmp(replay_counter, ctr[i].counter,
7703ff40c12SJohn Marino 			      WPA_REPLAY_COUNTER_LEN) == 0)
7713ff40c12SJohn Marino 			return 1;
7723ff40c12SJohn Marino 	}
7733ff40c12SJohn Marino 	return 0;
7743ff40c12SJohn Marino }
7753ff40c12SJohn Marino 
7763ff40c12SJohn Marino 
wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter * ctr,const u8 * replay_counter)7773ff40c12SJohn Marino static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
7783ff40c12SJohn Marino 					    const u8 *replay_counter)
7793ff40c12SJohn Marino {
7803ff40c12SJohn Marino 	int i;
7813ff40c12SJohn Marino 	for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
7823ff40c12SJohn Marino 		if (ctr[i].valid &&
7833ff40c12SJohn Marino 		    (replay_counter == NULL ||
7843ff40c12SJohn Marino 		     os_memcmp(replay_counter, ctr[i].counter,
7853ff40c12SJohn Marino 			       WPA_REPLAY_COUNTER_LEN) == 0))
7863ff40c12SJohn Marino 			ctr[i].valid = FALSE;
7873ff40c12SJohn Marino 	}
7883ff40c12SJohn Marino }
7893ff40c12SJohn Marino 
7903ff40c12SJohn Marino 
791*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
ft_check_msg_2_of_4(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,struct wpa_eapol_ie_parse * kde)7923ff40c12SJohn Marino static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
7933ff40c12SJohn Marino 			       struct wpa_state_machine *sm,
7943ff40c12SJohn Marino 			       struct wpa_eapol_ie_parse *kde)
7953ff40c12SJohn Marino {
7963ff40c12SJohn Marino 	struct wpa_ie_data ie;
7973ff40c12SJohn Marino 	struct rsn_mdie *mdie;
7983ff40c12SJohn Marino 
7993ff40c12SJohn Marino 	if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
8003ff40c12SJohn Marino 	    ie.num_pmkid != 1 || ie.pmkid == NULL) {
8013ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
8023ff40c12SJohn Marino 			   "FT 4-way handshake message 2/4");
8033ff40c12SJohn Marino 		return -1;
8043ff40c12SJohn Marino 	}
8053ff40c12SJohn Marino 
8063ff40c12SJohn Marino 	os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN);
8073ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant",
8083ff40c12SJohn Marino 		    sm->sup_pmk_r1_name, PMKID_LEN);
8093ff40c12SJohn Marino 
8103ff40c12SJohn Marino 	if (!kde->mdie || !kde->ftie) {
8113ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
8123ff40c12SJohn Marino 			   "message 2/4", kde->mdie ? "FTIE" : "MDIE");
8133ff40c12SJohn Marino 		return -1;
8143ff40c12SJohn Marino 	}
8153ff40c12SJohn Marino 
8163ff40c12SJohn Marino 	mdie = (struct rsn_mdie *) (kde->mdie + 2);
8173ff40c12SJohn Marino 	if (kde->mdie[1] < sizeof(struct rsn_mdie) ||
8183ff40c12SJohn Marino 	    os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain,
8193ff40c12SJohn Marino 		      MOBILITY_DOMAIN_ID_LEN) != 0) {
8203ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: MDIE mismatch");
8213ff40c12SJohn Marino 		return -1;
8223ff40c12SJohn Marino 	}
8233ff40c12SJohn Marino 
8243ff40c12SJohn Marino 	if (sm->assoc_resp_ftie &&
8253ff40c12SJohn Marino 	    (kde->ftie[1] != sm->assoc_resp_ftie[1] ||
8263ff40c12SJohn Marino 	     os_memcmp(kde->ftie, sm->assoc_resp_ftie,
8273ff40c12SJohn Marino 		       2 + sm->assoc_resp_ftie[1]) != 0)) {
8283ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: FTIE mismatch");
8293ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4",
8303ff40c12SJohn Marino 			    kde->ftie, kde->ftie_len);
8313ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp",
8323ff40c12SJohn Marino 			    sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]);
8333ff40c12SJohn Marino 		return -1;
8343ff40c12SJohn Marino 	}
8353ff40c12SJohn Marino 
8363ff40c12SJohn Marino 	return 0;
8373ff40c12SJohn Marino }
838*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
8393ff40c12SJohn Marino 
8403ff40c12SJohn Marino 
wpa_receive_error_report(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,int group)8413ff40c12SJohn Marino static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
8423ff40c12SJohn Marino 				    struct wpa_state_machine *sm, int group)
8433ff40c12SJohn Marino {
8443ff40c12SJohn Marino 	/* Supplicant reported a Michael MIC error */
8453ff40c12SJohn Marino 	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
8463ff40c12SJohn Marino 			 "received EAPOL-Key Error Request "
8473ff40c12SJohn Marino 			 "(STA detected Michael MIC failure (group=%d))",
8483ff40c12SJohn Marino 			 group);
8493ff40c12SJohn Marino 
8503ff40c12SJohn Marino 	if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
8513ff40c12SJohn Marino 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
8523ff40c12SJohn Marino 				"ignore Michael MIC failure report since "
8533ff40c12SJohn Marino 				"group cipher is not TKIP");
8543ff40c12SJohn Marino 	} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
8553ff40c12SJohn Marino 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
8563ff40c12SJohn Marino 				"ignore Michael MIC failure report since "
8573ff40c12SJohn Marino 				"pairwise cipher is not TKIP");
8583ff40c12SJohn Marino 	} else {
8593ff40c12SJohn Marino 		if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
8603ff40c12SJohn Marino 			return 1; /* STA entry was removed */
8613ff40c12SJohn Marino 		sm->dot11RSNAStatsTKIPRemoteMICFailures++;
8623ff40c12SJohn Marino 		wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
8633ff40c12SJohn Marino 	}
8643ff40c12SJohn Marino 
8653ff40c12SJohn Marino 	/*
8663ff40c12SJohn Marino 	 * Error report is not a request for a new key handshake, but since
8673ff40c12SJohn Marino 	 * Authenticator may do it, let's change the keys now anyway.
8683ff40c12SJohn Marino 	 */
8693ff40c12SJohn Marino 	wpa_request_new_ptk(sm);
8703ff40c12SJohn Marino 	return 0;
8713ff40c12SJohn Marino }
8723ff40c12SJohn Marino 
8733ff40c12SJohn Marino 
wpa_try_alt_snonce(struct wpa_state_machine * sm,u8 * data,size_t data_len)874*a1157835SDaniel Fojt static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
875*a1157835SDaniel Fojt 			      size_t data_len)
876*a1157835SDaniel Fojt {
877*a1157835SDaniel Fojt 	struct wpa_ptk PTK;
878*a1157835SDaniel Fojt 	int ok = 0;
879*a1157835SDaniel Fojt 	const u8 *pmk = NULL;
880*a1157835SDaniel Fojt 	size_t pmk_len;
881*a1157835SDaniel Fojt 	int vlan_id = 0;
882*a1157835SDaniel Fojt 
883*a1157835SDaniel Fojt 	os_memset(&PTK, 0, sizeof(PTK));
884*a1157835SDaniel Fojt 	for (;;) {
885*a1157835SDaniel Fojt 		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
886*a1157835SDaniel Fojt 		    !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
887*a1157835SDaniel Fojt 			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
888*a1157835SDaniel Fojt 					       sm->p2p_dev_addr, pmk, &pmk_len,
889*a1157835SDaniel Fojt 					       &vlan_id);
890*a1157835SDaniel Fojt 			if (pmk == NULL)
891*a1157835SDaniel Fojt 				break;
892*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
893*a1157835SDaniel Fojt 			if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
894*a1157835SDaniel Fojt 				os_memcpy(sm->xxkey, pmk, pmk_len);
895*a1157835SDaniel Fojt 				sm->xxkey_len = pmk_len;
896*a1157835SDaniel Fojt 			}
897*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
898*a1157835SDaniel Fojt 		} else {
899*a1157835SDaniel Fojt 			pmk = sm->PMK;
900*a1157835SDaniel Fojt 			pmk_len = sm->pmk_len;
901*a1157835SDaniel Fojt 		}
902*a1157835SDaniel Fojt 
903*a1157835SDaniel Fojt 		if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
904*a1157835SDaniel Fojt 			break;
905*a1157835SDaniel Fojt 
906*a1157835SDaniel Fojt 		if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
907*a1157835SDaniel Fojt 				       data, data_len) == 0) {
908*a1157835SDaniel Fojt 			if (sm->PMK != pmk) {
909*a1157835SDaniel Fojt 				os_memcpy(sm->PMK, pmk, pmk_len);
910*a1157835SDaniel Fojt 				sm->pmk_len = pmk_len;
911*a1157835SDaniel Fojt 			}
912*a1157835SDaniel Fojt 			ok = 1;
913*a1157835SDaniel Fojt 			break;
914*a1157835SDaniel Fojt 		}
915*a1157835SDaniel Fojt 
916*a1157835SDaniel Fojt 		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
917*a1157835SDaniel Fojt 		    wpa_key_mgmt_sae(sm->wpa_key_mgmt))
918*a1157835SDaniel Fojt 			break;
919*a1157835SDaniel Fojt 	}
920*a1157835SDaniel Fojt 
921*a1157835SDaniel Fojt 	if (!ok) {
922*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
923*a1157835SDaniel Fojt 			   "WPA: Earlier SNonce did not result in matching MIC");
924*a1157835SDaniel Fojt 		return -1;
925*a1157835SDaniel Fojt 	}
926*a1157835SDaniel Fojt 
927*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
928*a1157835SDaniel Fojt 		   "WPA: Earlier SNonce resulted in matching MIC");
929*a1157835SDaniel Fojt 	sm->alt_snonce_valid = 0;
930*a1157835SDaniel Fojt 
931*a1157835SDaniel Fojt 	if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
932*a1157835SDaniel Fojt 	    wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
933*a1157835SDaniel Fojt 		return -1;
934*a1157835SDaniel Fojt 
935*a1157835SDaniel Fojt 	os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
936*a1157835SDaniel Fojt 	os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
937*a1157835SDaniel Fojt 	forced_memzero(&PTK, sizeof(PTK));
938*a1157835SDaniel Fojt 	sm->PTK_valid = TRUE;
939*a1157835SDaniel Fojt 
940*a1157835SDaniel Fojt 	return 0;
941*a1157835SDaniel Fojt }
942*a1157835SDaniel Fojt 
943*a1157835SDaniel Fojt 
wpa_receive(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,u8 * data,size_t data_len)9443ff40c12SJohn Marino void wpa_receive(struct wpa_authenticator *wpa_auth,
9453ff40c12SJohn Marino 		 struct wpa_state_machine *sm,
9463ff40c12SJohn Marino 		 u8 *data, size_t data_len)
9473ff40c12SJohn Marino {
9483ff40c12SJohn Marino 	struct ieee802_1x_hdr *hdr;
9493ff40c12SJohn Marino 	struct wpa_eapol_key *key;
9503ff40c12SJohn Marino 	u16 key_info, key_data_length;
951*a1157835SDaniel Fojt 	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST } msg;
9523ff40c12SJohn Marino 	char *msgtxt;
9533ff40c12SJohn Marino 	struct wpa_eapol_ie_parse kde;
954*a1157835SDaniel Fojt 	const u8 *key_data;
955*a1157835SDaniel Fojt 	size_t keyhdrlen, mic_len;
956*a1157835SDaniel Fojt 	u8 *mic;
9573ff40c12SJohn Marino 
9583ff40c12SJohn Marino 	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
9593ff40c12SJohn Marino 		return;
960*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
9613ff40c12SJohn Marino 
962*a1157835SDaniel Fojt 	mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
963*a1157835SDaniel Fojt 	keyhdrlen = sizeof(*key) + mic_len + 2;
964*a1157835SDaniel Fojt 
965*a1157835SDaniel Fojt 	if (data_len < sizeof(*hdr) + keyhdrlen) {
966*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "WPA: Ignore too short EAPOL-Key frame");
9673ff40c12SJohn Marino 		return;
968*a1157835SDaniel Fojt 	}
9693ff40c12SJohn Marino 
9703ff40c12SJohn Marino 	hdr = (struct ieee802_1x_hdr *) data;
9713ff40c12SJohn Marino 	key = (struct wpa_eapol_key *) (hdr + 1);
972*a1157835SDaniel Fojt 	mic = (u8 *) (key + 1);
9733ff40c12SJohn Marino 	key_info = WPA_GET_BE16(key->key_info);
974*a1157835SDaniel Fojt 	key_data = mic + mic_len + 2;
975*a1157835SDaniel Fojt 	key_data_length = WPA_GET_BE16(mic + mic_len);
9763ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
977*a1157835SDaniel Fojt 		   " key_info=0x%x type=%u mic_len=%u key_data_length=%u",
978*a1157835SDaniel Fojt 		   MAC2STR(sm->addr), key_info, key->type,
979*a1157835SDaniel Fojt 		   (unsigned int) mic_len, key_data_length);
980*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP,
981*a1157835SDaniel Fojt 		    "WPA: EAPOL-Key header (ending before Key MIC)",
982*a1157835SDaniel Fojt 		    key, sizeof(*key));
983*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
984*a1157835SDaniel Fojt 		    mic, mic_len);
985*a1157835SDaniel Fojt 	if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
9863ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
9873ff40c12SJohn Marino 			   "key_data overflow (%d > %lu)",
9883ff40c12SJohn Marino 			   key_data_length,
9893ff40c12SJohn Marino 			   (unsigned long) (data_len - sizeof(*hdr) -
990*a1157835SDaniel Fojt 					    keyhdrlen));
9913ff40c12SJohn Marino 		return;
9923ff40c12SJohn Marino 	}
9933ff40c12SJohn Marino 
9943ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA2) {
9953ff40c12SJohn Marino 		if (key->type == EAPOL_KEY_TYPE_WPA) {
9963ff40c12SJohn Marino 			/*
9973ff40c12SJohn Marino 			 * Some deployed station implementations seem to send
9983ff40c12SJohn Marino 			 * msg 4/4 with incorrect type value in WPA2 mode.
9993ff40c12SJohn Marino 			 */
10003ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
10013ff40c12SJohn Marino 				   "with unexpected WPA type in RSN mode");
10023ff40c12SJohn Marino 		} else if (key->type != EAPOL_KEY_TYPE_RSN) {
10033ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
10043ff40c12SJohn Marino 				   "unexpected type %d in RSN mode",
10053ff40c12SJohn Marino 				   key->type);
10063ff40c12SJohn Marino 			return;
10073ff40c12SJohn Marino 		}
10083ff40c12SJohn Marino 	} else {
10093ff40c12SJohn Marino 		if (key->type != EAPOL_KEY_TYPE_WPA) {
10103ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
10113ff40c12SJohn Marino 				   "unexpected type %d in WPA mode",
10123ff40c12SJohn Marino 				   key->type);
10133ff40c12SJohn Marino 			return;
10143ff40c12SJohn Marino 		}
10153ff40c12SJohn Marino 	}
10163ff40c12SJohn Marino 
10173ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "WPA: Received Key Nonce", key->key_nonce,
10183ff40c12SJohn Marino 		    WPA_NONCE_LEN);
10193ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "WPA: Received Replay Counter",
10203ff40c12SJohn Marino 		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
10213ff40c12SJohn Marino 
10223ff40c12SJohn Marino 	/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
10233ff40c12SJohn Marino 	 * are set */
10243ff40c12SJohn Marino 
1025*a1157835SDaniel Fojt 	if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
1026*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "WPA: Ignore SMK message");
1027*a1157835SDaniel Fojt 		return;
10283ff40c12SJohn Marino 	}
1029*a1157835SDaniel Fojt 
1030*a1157835SDaniel Fojt 	if (key_info & WPA_KEY_INFO_REQUEST) {
10313ff40c12SJohn Marino 		msg = REQUEST;
10323ff40c12SJohn Marino 		msgtxt = "Request";
10333ff40c12SJohn Marino 	} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
10343ff40c12SJohn Marino 		msg = GROUP_2;
10353ff40c12SJohn Marino 		msgtxt = "2/2 Group";
1036*a1157835SDaniel Fojt 	} else if (key_data_length == 0 ||
1037*a1157835SDaniel Fojt 		   (mic_len == 0 && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
1038*a1157835SDaniel Fojt 		    key_data_length == AES_BLOCK_SIZE)) {
10393ff40c12SJohn Marino 		msg = PAIRWISE_4;
10403ff40c12SJohn Marino 		msgtxt = "4/4 Pairwise";
10413ff40c12SJohn Marino 	} else {
10423ff40c12SJohn Marino 		msg = PAIRWISE_2;
10433ff40c12SJohn Marino 		msgtxt = "2/4 Pairwise";
10443ff40c12SJohn Marino 	}
10453ff40c12SJohn Marino 
10463ff40c12SJohn Marino 	if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
10473ff40c12SJohn Marino 	    msg == GROUP_2) {
10483ff40c12SJohn Marino 		u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
10493ff40c12SJohn Marino 		if (sm->pairwise == WPA_CIPHER_CCMP ||
10503ff40c12SJohn Marino 		    sm->pairwise == WPA_CIPHER_GCMP) {
1051*a1157835SDaniel Fojt 			if (wpa_use_cmac(sm->wpa_key_mgmt) &&
1052*a1157835SDaniel Fojt 			    !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
10533ff40c12SJohn Marino 			    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
10543ff40c12SJohn Marino 				wpa_auth_logger(wpa_auth, sm->addr,
10553ff40c12SJohn Marino 						LOGGER_WARNING,
10563ff40c12SJohn Marino 						"advertised support for "
10573ff40c12SJohn Marino 						"AES-128-CMAC, but did not "
10583ff40c12SJohn Marino 						"use it");
10593ff40c12SJohn Marino 				return;
10603ff40c12SJohn Marino 			}
10613ff40c12SJohn Marino 
1062*a1157835SDaniel Fojt 			if (!wpa_use_cmac(sm->wpa_key_mgmt) &&
1063*a1157835SDaniel Fojt 			    !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
10643ff40c12SJohn Marino 			    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
10653ff40c12SJohn Marino 				wpa_auth_logger(wpa_auth, sm->addr,
10663ff40c12SJohn Marino 						LOGGER_WARNING,
10673ff40c12SJohn Marino 						"did not use HMAC-SHA1-AES "
10683ff40c12SJohn Marino 						"with CCMP/GCMP");
10693ff40c12SJohn Marino 				return;
10703ff40c12SJohn Marino 			}
10713ff40c12SJohn Marino 		}
1072*a1157835SDaniel Fojt 
1073*a1157835SDaniel Fojt 		if (wpa_use_akm_defined(sm->wpa_key_mgmt) &&
1074*a1157835SDaniel Fojt 		    ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
1075*a1157835SDaniel Fojt 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
1076*a1157835SDaniel Fojt 					"did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
1077*a1157835SDaniel Fojt 			return;
1078*a1157835SDaniel Fojt 		}
10793ff40c12SJohn Marino 	}
10803ff40c12SJohn Marino 
10813ff40c12SJohn Marino 	if (key_info & WPA_KEY_INFO_REQUEST) {
10823ff40c12SJohn Marino 		if (sm->req_replay_counter_used &&
10833ff40c12SJohn Marino 		    os_memcmp(key->replay_counter, sm->req_replay_counter,
10843ff40c12SJohn Marino 			      WPA_REPLAY_COUNTER_LEN) <= 0) {
10853ff40c12SJohn Marino 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
10863ff40c12SJohn Marino 					"received EAPOL-Key request with "
10873ff40c12SJohn Marino 					"replayed counter");
10883ff40c12SJohn Marino 			return;
10893ff40c12SJohn Marino 		}
10903ff40c12SJohn Marino 	}
10913ff40c12SJohn Marino 
10923ff40c12SJohn Marino 	if (!(key_info & WPA_KEY_INFO_REQUEST) &&
10933ff40c12SJohn Marino 	    !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) {
10943ff40c12SJohn Marino 		int i;
10953ff40c12SJohn Marino 
10963ff40c12SJohn Marino 		if (msg == PAIRWISE_2 &&
10973ff40c12SJohn Marino 		    wpa_replay_counter_valid(sm->prev_key_replay,
10983ff40c12SJohn Marino 					     key->replay_counter) &&
10993ff40c12SJohn Marino 		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
11003ff40c12SJohn Marino 		    os_memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0)
11013ff40c12SJohn Marino 		{
11023ff40c12SJohn Marino 			/*
11033ff40c12SJohn Marino 			 * Some supplicant implementations (e.g., Windows XP
11043ff40c12SJohn Marino 			 * WZC) update SNonce for each EAPOL-Key 2/4. This
11053ff40c12SJohn Marino 			 * breaks the workaround on accepting any of the
11063ff40c12SJohn Marino 			 * pending requests, so allow the SNonce to be updated
11073ff40c12SJohn Marino 			 * even if we have already sent out EAPOL-Key 3/4.
11083ff40c12SJohn Marino 			 */
11093ff40c12SJohn Marino 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
11103ff40c12SJohn Marino 					 "Process SNonce update from STA "
11113ff40c12SJohn Marino 					 "based on retransmitted EAPOL-Key "
11123ff40c12SJohn Marino 					 "1/4");
11133ff40c12SJohn Marino 			sm->update_snonce = 1;
1114*a1157835SDaniel Fojt 			os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
1115*a1157835SDaniel Fojt 			sm->alt_snonce_valid = TRUE;
1116*a1157835SDaniel Fojt 			os_memcpy(sm->alt_replay_counter,
1117*a1157835SDaniel Fojt 				  sm->key_replay[0].counter,
1118*a1157835SDaniel Fojt 				  WPA_REPLAY_COUNTER_LEN);
1119*a1157835SDaniel Fojt 			goto continue_processing;
1120*a1157835SDaniel Fojt 		}
1121*a1157835SDaniel Fojt 
1122*a1157835SDaniel Fojt 		if (msg == PAIRWISE_4 && sm->alt_snonce_valid &&
1123*a1157835SDaniel Fojt 		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
1124*a1157835SDaniel Fojt 		    os_memcmp(key->replay_counter, sm->alt_replay_counter,
1125*a1157835SDaniel Fojt 			      WPA_REPLAY_COUNTER_LEN) == 0) {
1126*a1157835SDaniel Fojt 			/*
1127*a1157835SDaniel Fojt 			 * Supplicant may still be using the old SNonce since
1128*a1157835SDaniel Fojt 			 * there was two EAPOL-Key 2/4 messages and they had
1129*a1157835SDaniel Fojt 			 * different SNonce values.
1130*a1157835SDaniel Fojt 			 */
1131*a1157835SDaniel Fojt 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
1132*a1157835SDaniel Fojt 					 "Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4");
11333ff40c12SJohn Marino 			goto continue_processing;
11343ff40c12SJohn Marino 		}
11353ff40c12SJohn Marino 
11363ff40c12SJohn Marino 		if (msg == PAIRWISE_2 &&
11373ff40c12SJohn Marino 		    wpa_replay_counter_valid(sm->prev_key_replay,
11383ff40c12SJohn Marino 					     key->replay_counter) &&
11393ff40c12SJohn Marino 		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
11403ff40c12SJohn Marino 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
11413ff40c12SJohn Marino 					 "ignore retransmitted EAPOL-Key %s - "
11423ff40c12SJohn Marino 					 "SNonce did not change", msgtxt);
11433ff40c12SJohn Marino 		} else {
11443ff40c12SJohn Marino 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
11453ff40c12SJohn Marino 					 "received EAPOL-Key %s with "
11463ff40c12SJohn Marino 					 "unexpected replay counter", msgtxt);
11473ff40c12SJohn Marino 		}
11483ff40c12SJohn Marino 		for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
11493ff40c12SJohn Marino 			if (!sm->key_replay[i].valid)
11503ff40c12SJohn Marino 				break;
11513ff40c12SJohn Marino 			wpa_hexdump(MSG_DEBUG, "pending replay counter",
11523ff40c12SJohn Marino 				    sm->key_replay[i].counter,
11533ff40c12SJohn Marino 				    WPA_REPLAY_COUNTER_LEN);
11543ff40c12SJohn Marino 		}
11553ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "received replay counter",
11563ff40c12SJohn Marino 			    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
11573ff40c12SJohn Marino 		return;
11583ff40c12SJohn Marino 	}
11593ff40c12SJohn Marino 
11603ff40c12SJohn Marino continue_processing:
1161*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1162*a1157835SDaniel Fojt 	if (sm->wpa == WPA_VERSION_WPA2 && mic_len == 0 &&
1163*a1157835SDaniel Fojt 	    !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
1164*a1157835SDaniel Fojt 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
1165*a1157835SDaniel Fojt 				 "WPA: Encr Key Data bit not set even though AEAD cipher is supposed to be used - drop frame");
1166*a1157835SDaniel Fojt 		return;
1167*a1157835SDaniel Fojt 	}
1168*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1169*a1157835SDaniel Fojt 
11703ff40c12SJohn Marino 	switch (msg) {
11713ff40c12SJohn Marino 	case PAIRWISE_2:
11723ff40c12SJohn Marino 		if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
11733ff40c12SJohn Marino 		    sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING &&
11743ff40c12SJohn Marino 		    (!sm->update_snonce ||
11753ff40c12SJohn Marino 		     sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
11763ff40c12SJohn Marino 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
11773ff40c12SJohn Marino 					 "received EAPOL-Key msg 2/4 in "
11783ff40c12SJohn Marino 					 "invalid state (%d) - dropped",
11793ff40c12SJohn Marino 					 sm->wpa_ptk_state);
11803ff40c12SJohn Marino 			return;
11813ff40c12SJohn Marino 		}
11823ff40c12SJohn Marino 		random_add_randomness(key->key_nonce, WPA_NONCE_LEN);
11833ff40c12SJohn Marino 		if (sm->group->reject_4way_hs_for_entropy) {
11843ff40c12SJohn Marino 			/*
11853ff40c12SJohn Marino 			 * The system did not have enough entropy to generate
11863ff40c12SJohn Marino 			 * strong random numbers. Reject the first 4-way
11873ff40c12SJohn Marino 			 * handshake(s) and collect some entropy based on the
11883ff40c12SJohn Marino 			 * information from it. Once enough entropy is
11893ff40c12SJohn Marino 			 * available, the next atempt will trigger GMK/Key
11903ff40c12SJohn Marino 			 * Counter update and the station will be allowed to
11913ff40c12SJohn Marino 			 * continue.
11923ff40c12SJohn Marino 			 */
11933ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
11943ff40c12SJohn Marino 				   "collect more entropy for random number "
11953ff40c12SJohn Marino 				   "generation");
11963ff40c12SJohn Marino 			random_mark_pool_ready();
1197*a1157835SDaniel Fojt 			wpa_sta_disconnect(wpa_auth, sm->addr,
1198*a1157835SDaniel Fojt 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
11993ff40c12SJohn Marino 			return;
12003ff40c12SJohn Marino 		}
12013ff40c12SJohn Marino 		break;
12023ff40c12SJohn Marino 	case PAIRWISE_4:
12033ff40c12SJohn Marino 		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
12043ff40c12SJohn Marino 		    !sm->PTK_valid) {
12053ff40c12SJohn Marino 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
12063ff40c12SJohn Marino 					 "received EAPOL-Key msg 4/4 in "
12073ff40c12SJohn Marino 					 "invalid state (%d) - dropped",
12083ff40c12SJohn Marino 					 sm->wpa_ptk_state);
12093ff40c12SJohn Marino 			return;
12103ff40c12SJohn Marino 		}
12113ff40c12SJohn Marino 		break;
12123ff40c12SJohn Marino 	case GROUP_2:
12133ff40c12SJohn Marino 		if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
12143ff40c12SJohn Marino 		    || !sm->PTK_valid) {
12153ff40c12SJohn Marino 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
12163ff40c12SJohn Marino 					 "received EAPOL-Key msg 2/2 in "
12173ff40c12SJohn Marino 					 "invalid state (%d) - dropped",
12183ff40c12SJohn Marino 					 sm->wpa_ptk_group_state);
12193ff40c12SJohn Marino 			return;
12203ff40c12SJohn Marino 		}
12213ff40c12SJohn Marino 		break;
12223ff40c12SJohn Marino 	case REQUEST:
12233ff40c12SJohn Marino 		break;
12243ff40c12SJohn Marino 	}
12253ff40c12SJohn Marino 
12263ff40c12SJohn Marino 	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
12273ff40c12SJohn Marino 			 "received EAPOL-Key frame (%s)", msgtxt);
12283ff40c12SJohn Marino 
12293ff40c12SJohn Marino 	if (key_info & WPA_KEY_INFO_ACK) {
12303ff40c12SJohn Marino 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
12313ff40c12SJohn Marino 				"received invalid EAPOL-Key: Key Ack set");
12323ff40c12SJohn Marino 		return;
12333ff40c12SJohn Marino 	}
12343ff40c12SJohn Marino 
1235*a1157835SDaniel Fojt 	if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
1236*a1157835SDaniel Fojt 	    !(key_info & WPA_KEY_INFO_MIC)) {
12373ff40c12SJohn Marino 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
12383ff40c12SJohn Marino 				"received invalid EAPOL-Key: Key MIC not set");
12393ff40c12SJohn Marino 		return;
12403ff40c12SJohn Marino 	}
12413ff40c12SJohn Marino 
1242*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1243*a1157835SDaniel Fojt 	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
1244*a1157835SDaniel Fojt 	    (key_info & WPA_KEY_INFO_MIC)) {
12453ff40c12SJohn Marino 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
1246*a1157835SDaniel Fojt 				"received invalid EAPOL-Key: Key MIC set");
12473ff40c12SJohn Marino 		return;
12483ff40c12SJohn Marino 	}
1249*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1250*a1157835SDaniel Fojt 
1251*a1157835SDaniel Fojt 	sm->MICVerified = FALSE;
1252*a1157835SDaniel Fojt 	if (sm->PTK_valid && !sm->update_snonce) {
1253*a1157835SDaniel Fojt 		if (mic_len &&
1254*a1157835SDaniel Fojt 		    wpa_verify_key_mic(sm->wpa_key_mgmt, sm->pmk_len, &sm->PTK,
1255*a1157835SDaniel Fojt 				       data, data_len) &&
1256*a1157835SDaniel Fojt 		    (msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
1257*a1157835SDaniel Fojt 		     wpa_try_alt_snonce(sm, data, data_len))) {
1258*a1157835SDaniel Fojt 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
1259*a1157835SDaniel Fojt 					"received EAPOL-Key with invalid MIC");
1260*a1157835SDaniel Fojt #ifdef TEST_FUZZ
1261*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
1262*a1157835SDaniel Fojt 				   "TEST: Ignore Key MIC failure for fuzz testing");
1263*a1157835SDaniel Fojt 			goto continue_fuzz;
1264*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
1265*a1157835SDaniel Fojt 			return;
1266*a1157835SDaniel Fojt 		}
1267*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1268*a1157835SDaniel Fojt 		if (!mic_len &&
1269*a1157835SDaniel Fojt 		    wpa_aead_decrypt(sm, &sm->PTK, data, data_len,
1270*a1157835SDaniel Fojt 				     &key_data_length) < 0) {
1271*a1157835SDaniel Fojt 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
1272*a1157835SDaniel Fojt 					"received EAPOL-Key with invalid MIC");
1273*a1157835SDaniel Fojt #ifdef TEST_FUZZ
1274*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
1275*a1157835SDaniel Fojt 				   "TEST: Ignore Key MIC failure for fuzz testing");
1276*a1157835SDaniel Fojt 			goto continue_fuzz;
1277*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
1278*a1157835SDaniel Fojt 			return;
1279*a1157835SDaniel Fojt 		}
1280*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1281*a1157835SDaniel Fojt #ifdef TEST_FUZZ
1282*a1157835SDaniel Fojt 	continue_fuzz:
1283*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
12843ff40c12SJohn Marino 		sm->MICVerified = TRUE;
12853ff40c12SJohn Marino 		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
12863ff40c12SJohn Marino 		sm->pending_1_of_4_timeout = 0;
12873ff40c12SJohn Marino 	}
12883ff40c12SJohn Marino 
12893ff40c12SJohn Marino 	if (key_info & WPA_KEY_INFO_REQUEST) {
12903ff40c12SJohn Marino 		if (sm->MICVerified) {
12913ff40c12SJohn Marino 			sm->req_replay_counter_used = 1;
12923ff40c12SJohn Marino 			os_memcpy(sm->req_replay_counter, key->replay_counter,
12933ff40c12SJohn Marino 				  WPA_REPLAY_COUNTER_LEN);
12943ff40c12SJohn Marino 		} else {
12953ff40c12SJohn Marino 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
12963ff40c12SJohn Marino 					"received EAPOL-Key request with "
12973ff40c12SJohn Marino 					"invalid MIC");
12983ff40c12SJohn Marino 			return;
12993ff40c12SJohn Marino 		}
13003ff40c12SJohn Marino 
13013ff40c12SJohn Marino 		/*
13023ff40c12SJohn Marino 		 * TODO: should decrypt key data field if encryption was used;
13033ff40c12SJohn Marino 		 * even though MAC address KDE is not normally encrypted,
13043ff40c12SJohn Marino 		 * supplicant is allowed to encrypt it.
13053ff40c12SJohn Marino 		 */
1306*a1157835SDaniel Fojt 		if (key_info & WPA_KEY_INFO_ERROR) {
13073ff40c12SJohn Marino 			if (wpa_receive_error_report(
13083ff40c12SJohn Marino 				    wpa_auth, sm,
13093ff40c12SJohn Marino 				    !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
13103ff40c12SJohn Marino 				return; /* STA entry was removed */
13113ff40c12SJohn Marino 		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
13123ff40c12SJohn Marino 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
13133ff40c12SJohn Marino 					"received EAPOL-Key Request for new "
13143ff40c12SJohn Marino 					"4-Way Handshake");
13153ff40c12SJohn Marino 			wpa_request_new_ptk(sm);
13163ff40c12SJohn Marino 		} else if (key_data_length > 0 &&
1317*a1157835SDaniel Fojt 			   wpa_parse_kde_ies(key_data, key_data_length,
1318*a1157835SDaniel Fojt 					     &kde) == 0 &&
13193ff40c12SJohn Marino 			   kde.mac_addr) {
13203ff40c12SJohn Marino 		} else {
13213ff40c12SJohn Marino 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
13223ff40c12SJohn Marino 					"received EAPOL-Key Request for GTK "
13233ff40c12SJohn Marino 					"rekeying");
13243ff40c12SJohn Marino 			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
13253ff40c12SJohn Marino 			wpa_rekey_gtk(wpa_auth, NULL);
13263ff40c12SJohn Marino 		}
13273ff40c12SJohn Marino 	} else {
13283ff40c12SJohn Marino 		/* Do not allow the same key replay counter to be reused. */
13293ff40c12SJohn Marino 		wpa_replay_counter_mark_invalid(sm->key_replay,
13303ff40c12SJohn Marino 						key->replay_counter);
13313ff40c12SJohn Marino 
13323ff40c12SJohn Marino 		if (msg == PAIRWISE_2) {
13333ff40c12SJohn Marino 			/*
13343ff40c12SJohn Marino 			 * Maintain a copy of the pending EAPOL-Key frames in
13353ff40c12SJohn Marino 			 * case the EAPOL-Key frame was retransmitted. This is
13363ff40c12SJohn Marino 			 * needed to allow EAPOL-Key msg 2/4 reply to another
13373ff40c12SJohn Marino 			 * pending msg 1/4 to update the SNonce to work around
13383ff40c12SJohn Marino 			 * unexpected supplicant behavior.
13393ff40c12SJohn Marino 			 */
13403ff40c12SJohn Marino 			os_memcpy(sm->prev_key_replay, sm->key_replay,
13413ff40c12SJohn Marino 				  sizeof(sm->key_replay));
13423ff40c12SJohn Marino 		} else {
13433ff40c12SJohn Marino 			os_memset(sm->prev_key_replay, 0,
13443ff40c12SJohn Marino 				  sizeof(sm->prev_key_replay));
13453ff40c12SJohn Marino 		}
13463ff40c12SJohn Marino 
13473ff40c12SJohn Marino 		/*
13483ff40c12SJohn Marino 		 * Make sure old valid counters are not accepted anymore and
13493ff40c12SJohn Marino 		 * do not get copied again.
13503ff40c12SJohn Marino 		 */
13513ff40c12SJohn Marino 		wpa_replay_counter_mark_invalid(sm->key_replay, NULL);
13523ff40c12SJohn Marino 	}
13533ff40c12SJohn Marino 
13543ff40c12SJohn Marino 	os_free(sm->last_rx_eapol_key);
1355*a1157835SDaniel Fojt 	sm->last_rx_eapol_key = os_memdup(data, data_len);
13563ff40c12SJohn Marino 	if (sm->last_rx_eapol_key == NULL)
13573ff40c12SJohn Marino 		return;
13583ff40c12SJohn Marino 	sm->last_rx_eapol_key_len = data_len;
13593ff40c12SJohn Marino 
13603ff40c12SJohn Marino 	sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
13613ff40c12SJohn Marino 	sm->EAPOLKeyReceived = TRUE;
13623ff40c12SJohn Marino 	sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
13633ff40c12SJohn Marino 	sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
13643ff40c12SJohn Marino 	os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
13653ff40c12SJohn Marino 	wpa_sm_step(sm);
13663ff40c12SJohn Marino }
13673ff40c12SJohn Marino 
13683ff40c12SJohn Marino 
wpa_gmk_to_gtk(const u8 * gmk,const char * label,const u8 * addr,const u8 * gnonce,u8 * gtk,size_t gtk_len)13693ff40c12SJohn Marino static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
13703ff40c12SJohn Marino 			  const u8 *gnonce, u8 *gtk, size_t gtk_len)
13713ff40c12SJohn Marino {
1372*a1157835SDaniel Fojt 	u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + WPA_GTK_MAX_LEN];
13733ff40c12SJohn Marino 	u8 *pos;
13743ff40c12SJohn Marino 	int ret = 0;
13753ff40c12SJohn Marino 
13763ff40c12SJohn Marino 	/* GTK = PRF-X(GMK, "Group key expansion",
13773ff40c12SJohn Marino 	 *	AA || GNonce || Time || random data)
13783ff40c12SJohn Marino 	 * The example described in the IEEE 802.11 standard uses only AA and
13793ff40c12SJohn Marino 	 * GNonce as inputs here. Add some more entropy since this derivation
13803ff40c12SJohn Marino 	 * is done only at the Authenticator and as such, does not need to be
13813ff40c12SJohn Marino 	 * exactly same.
13823ff40c12SJohn Marino 	 */
1383*a1157835SDaniel Fojt 	os_memset(data, 0, sizeof(data));
13843ff40c12SJohn Marino 	os_memcpy(data, addr, ETH_ALEN);
13853ff40c12SJohn Marino 	os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
13863ff40c12SJohn Marino 	pos = data + ETH_ALEN + WPA_NONCE_LEN;
13873ff40c12SJohn Marino 	wpa_get_ntp_timestamp(pos);
1388*a1157835SDaniel Fojt #ifdef TEST_FUZZ
1389*a1157835SDaniel Fojt 	os_memset(pos, 0xef, 8);
1390*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
13913ff40c12SJohn Marino 	pos += 8;
1392*a1157835SDaniel Fojt 	if (random_get_bytes(pos, gtk_len) < 0)
13933ff40c12SJohn Marino 		ret = -1;
13943ff40c12SJohn Marino 
1395*a1157835SDaniel Fojt #ifdef CONFIG_SHA384
1396*a1157835SDaniel Fojt 	if (sha384_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
1397*a1157835SDaniel Fojt 		       gtk, gtk_len) < 0)
13983ff40c12SJohn Marino 		ret = -1;
1399*a1157835SDaniel Fojt #else /* CONFIG_SHA384 */
1400*a1157835SDaniel Fojt #ifdef CONFIG_SHA256
1401*a1157835SDaniel Fojt 	if (sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
1402*a1157835SDaniel Fojt 		       gtk, gtk_len) < 0)
1403*a1157835SDaniel Fojt 		ret = -1;
1404*a1157835SDaniel Fojt #else /* CONFIG_SHA256 */
1405*a1157835SDaniel Fojt 	if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
1406*a1157835SDaniel Fojt 		     gtk, gtk_len) < 0)
1407*a1157835SDaniel Fojt 		ret = -1;
1408*a1157835SDaniel Fojt #endif /* CONFIG_SHA256 */
1409*a1157835SDaniel Fojt #endif /* CONFIG_SHA384 */
1410*a1157835SDaniel Fojt 
1411*a1157835SDaniel Fojt 	forced_memzero(data, sizeof(data));
14123ff40c12SJohn Marino 
14133ff40c12SJohn Marino 	return ret;
14143ff40c12SJohn Marino }
14153ff40c12SJohn Marino 
14163ff40c12SJohn Marino 
wpa_send_eapol_timeout(void * eloop_ctx,void * timeout_ctx)14173ff40c12SJohn Marino static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
14183ff40c12SJohn Marino {
14193ff40c12SJohn Marino 	struct wpa_authenticator *wpa_auth = eloop_ctx;
14203ff40c12SJohn Marino 	struct wpa_state_machine *sm = timeout_ctx;
14213ff40c12SJohn Marino 
14223ff40c12SJohn Marino 	sm->pending_1_of_4_timeout = 0;
14233ff40c12SJohn Marino 	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
14243ff40c12SJohn Marino 	sm->TimeoutEvt = TRUE;
14253ff40c12SJohn Marino 	wpa_sm_step(sm);
14263ff40c12SJohn Marino }
14273ff40c12SJohn Marino 
14283ff40c12SJohn Marino 
__wpa_send_eapol(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,int key_info,const u8 * key_rsc,const u8 * nonce,const u8 * kde,size_t kde_len,int keyidx,int encr,int force_version)14293ff40c12SJohn Marino void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
14303ff40c12SJohn Marino 		      struct wpa_state_machine *sm, int key_info,
14313ff40c12SJohn Marino 		      const u8 *key_rsc, const u8 *nonce,
14323ff40c12SJohn Marino 		      const u8 *kde, size_t kde_len,
14333ff40c12SJohn Marino 		      int keyidx, int encr, int force_version)
14343ff40c12SJohn Marino {
14353ff40c12SJohn Marino 	struct ieee802_1x_hdr *hdr;
14363ff40c12SJohn Marino 	struct wpa_eapol_key *key;
1437*a1157835SDaniel Fojt 	size_t len, mic_len, keyhdrlen;
14383ff40c12SJohn Marino 	int alg;
14393ff40c12SJohn Marino 	int key_data_len, pad_len = 0;
14403ff40c12SJohn Marino 	u8 *buf, *pos;
14413ff40c12SJohn Marino 	int version, pairwise;
14423ff40c12SJohn Marino 	int i;
1443*a1157835SDaniel Fojt 	u8 *key_mic, *key_data;
14443ff40c12SJohn Marino 
1445*a1157835SDaniel Fojt 	mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
1446*a1157835SDaniel Fojt 	keyhdrlen = sizeof(*key) + mic_len + 2;
1447*a1157835SDaniel Fojt 
1448*a1157835SDaniel Fojt 	len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
14493ff40c12SJohn Marino 
14503ff40c12SJohn Marino 	if (force_version)
14513ff40c12SJohn Marino 		version = force_version;
1452*a1157835SDaniel Fojt 	else if (wpa_use_akm_defined(sm->wpa_key_mgmt))
1453*a1157835SDaniel Fojt 		version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
1454*a1157835SDaniel Fojt 	else if (wpa_use_cmac(sm->wpa_key_mgmt))
14553ff40c12SJohn Marino 		version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
14563ff40c12SJohn Marino 	else if (sm->pairwise != WPA_CIPHER_TKIP)
14573ff40c12SJohn Marino 		version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
14583ff40c12SJohn Marino 	else
14593ff40c12SJohn Marino 		version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
14603ff40c12SJohn Marino 
14613ff40c12SJohn Marino 	pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
14623ff40c12SJohn Marino 
14633ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
14643ff40c12SJohn Marino 		   "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
14653ff40c12SJohn Marino 		   "encr=%d)",
14663ff40c12SJohn Marino 		   version,
14673ff40c12SJohn Marino 		   (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
14683ff40c12SJohn Marino 		   (key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
14693ff40c12SJohn Marino 		   (key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
14703ff40c12SJohn Marino 		   (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
14713ff40c12SJohn Marino 		   pairwise, (unsigned long) kde_len, keyidx, encr);
14723ff40c12SJohn Marino 
14733ff40c12SJohn Marino 	key_data_len = kde_len;
14743ff40c12SJohn Marino 
14753ff40c12SJohn Marino 	if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
1476*a1157835SDaniel Fojt 	     wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
14773ff40c12SJohn Marino 	     version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
14783ff40c12SJohn Marino 		pad_len = key_data_len % 8;
14793ff40c12SJohn Marino 		if (pad_len)
14803ff40c12SJohn Marino 			pad_len = 8 - pad_len;
14813ff40c12SJohn Marino 		key_data_len += pad_len + 8;
14823ff40c12SJohn Marino 	}
14833ff40c12SJohn Marino 
14843ff40c12SJohn Marino 	len += key_data_len;
1485*a1157835SDaniel Fojt 	if (!mic_len && encr)
1486*a1157835SDaniel Fojt 		len += AES_BLOCK_SIZE;
14873ff40c12SJohn Marino 
14883ff40c12SJohn Marino 	hdr = os_zalloc(len);
14893ff40c12SJohn Marino 	if (hdr == NULL)
14903ff40c12SJohn Marino 		return;
14913ff40c12SJohn Marino 	hdr->version = wpa_auth->conf.eapol_version;
14923ff40c12SJohn Marino 	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
14933ff40c12SJohn Marino 	hdr->length = host_to_be16(len  - sizeof(*hdr));
14943ff40c12SJohn Marino 	key = (struct wpa_eapol_key *) (hdr + 1);
1495*a1157835SDaniel Fojt 	key_mic = (u8 *) (key + 1);
1496*a1157835SDaniel Fojt 	key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
14973ff40c12SJohn Marino 
14983ff40c12SJohn Marino 	key->type = sm->wpa == WPA_VERSION_WPA2 ?
14993ff40c12SJohn Marino 		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
15003ff40c12SJohn Marino 	key_info |= version;
15013ff40c12SJohn Marino 	if (encr && sm->wpa == WPA_VERSION_WPA2)
15023ff40c12SJohn Marino 		key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
15033ff40c12SJohn Marino 	if (sm->wpa != WPA_VERSION_WPA2)
15043ff40c12SJohn Marino 		key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
15053ff40c12SJohn Marino 	WPA_PUT_BE16(key->key_info, key_info);
15063ff40c12SJohn Marino 
15073ff40c12SJohn Marino 	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
1508*a1157835SDaniel Fojt 	if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
15093ff40c12SJohn Marino 		WPA_PUT_BE16(key->key_length, 0);
1510*a1157835SDaniel Fojt 	else
1511*a1157835SDaniel Fojt 		WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
15123ff40c12SJohn Marino 
15133ff40c12SJohn Marino 	for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
15143ff40c12SJohn Marino 		sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
15153ff40c12SJohn Marino 		os_memcpy(sm->key_replay[i].counter,
15163ff40c12SJohn Marino 			  sm->key_replay[i - 1].counter,
15173ff40c12SJohn Marino 			  WPA_REPLAY_COUNTER_LEN);
15183ff40c12SJohn Marino 	}
15193ff40c12SJohn Marino 	inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
15203ff40c12SJohn Marino 	os_memcpy(key->replay_counter, sm->key_replay[0].counter,
15213ff40c12SJohn Marino 		  WPA_REPLAY_COUNTER_LEN);
1522*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
1523*a1157835SDaniel Fojt 		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
15243ff40c12SJohn Marino 	sm->key_replay[0].valid = TRUE;
15253ff40c12SJohn Marino 
15263ff40c12SJohn Marino 	if (nonce)
15273ff40c12SJohn Marino 		os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
15283ff40c12SJohn Marino 
15293ff40c12SJohn Marino 	if (key_rsc)
15303ff40c12SJohn Marino 		os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
15313ff40c12SJohn Marino 
15323ff40c12SJohn Marino 	if (kde && !encr) {
1533*a1157835SDaniel Fojt 		os_memcpy(key_data, kde, kde_len);
1534*a1157835SDaniel Fojt 		WPA_PUT_BE16(key_mic + mic_len, kde_len);
1535*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1536*a1157835SDaniel Fojt 	} else if (!mic_len && kde) {
1537*a1157835SDaniel Fojt 		const u8 *aad[1];
1538*a1157835SDaniel Fojt 		size_t aad_len[1];
1539*a1157835SDaniel Fojt 
1540*a1157835SDaniel Fojt 		WPA_PUT_BE16(key_mic, AES_BLOCK_SIZE + kde_len);
1541*a1157835SDaniel Fojt 		wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
1542*a1157835SDaniel Fojt 				kde, kde_len);
1543*a1157835SDaniel Fojt 
1544*a1157835SDaniel Fojt 		wpa_hexdump_key(MSG_DEBUG, "WPA: KEK",
1545*a1157835SDaniel Fojt 				sm->PTK.kek, sm->PTK.kek_len);
1546*a1157835SDaniel Fojt 		/* AES-SIV AAD from EAPOL protocol version field (inclusive) to
1547*a1157835SDaniel Fojt 		 * to Key Data (exclusive). */
1548*a1157835SDaniel Fojt 		aad[0] = (u8 *) hdr;
1549*a1157835SDaniel Fojt 		aad_len[0] = key_mic + 2 - (u8 *) hdr;
1550*a1157835SDaniel Fojt 		if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len, kde, kde_len,
1551*a1157835SDaniel Fojt 				    1, aad, aad_len, key_mic + 2) < 0) {
1552*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "WPA: AES-SIV encryption failed");
1553*a1157835SDaniel Fojt 			return;
1554*a1157835SDaniel Fojt 		}
1555*a1157835SDaniel Fojt 
1556*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "WPA: Encrypted Key Data from SIV",
1557*a1157835SDaniel Fojt 			    key_mic + 2, AES_BLOCK_SIZE + kde_len);
1558*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
15593ff40c12SJohn Marino 	} else if (encr && kde) {
15603ff40c12SJohn Marino 		buf = os_zalloc(key_data_len);
15613ff40c12SJohn Marino 		if (buf == NULL) {
15623ff40c12SJohn Marino 			os_free(hdr);
15633ff40c12SJohn Marino 			return;
15643ff40c12SJohn Marino 		}
15653ff40c12SJohn Marino 		pos = buf;
15663ff40c12SJohn Marino 		os_memcpy(pos, kde, kde_len);
15673ff40c12SJohn Marino 		pos += kde_len;
15683ff40c12SJohn Marino 
15693ff40c12SJohn Marino 		if (pad_len)
15703ff40c12SJohn Marino 			*pos++ = 0xdd;
15713ff40c12SJohn Marino 
15723ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
15733ff40c12SJohn Marino 				buf, key_data_len);
15743ff40c12SJohn Marino 		if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
1575*a1157835SDaniel Fojt 		    wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
15763ff40c12SJohn Marino 		    version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
1577*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1578*a1157835SDaniel Fojt 				   "WPA: Encrypt Key Data using AES-WRAP (KEK length %u)",
1579*a1157835SDaniel Fojt 				   (unsigned int) sm->PTK.kek_len);
1580*a1157835SDaniel Fojt 			if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
1581*a1157835SDaniel Fojt 				     (key_data_len - 8) / 8, buf, key_data)) {
15823ff40c12SJohn Marino 				os_free(hdr);
15833ff40c12SJohn Marino 				os_free(buf);
15843ff40c12SJohn Marino 				return;
15853ff40c12SJohn Marino 			}
1586*a1157835SDaniel Fojt 			WPA_PUT_BE16(key_mic + mic_len, key_data_len);
1587*a1157835SDaniel Fojt #ifndef CONFIG_NO_RC4
1588*a1157835SDaniel Fojt 		} else if (sm->PTK.kek_len == 16) {
15893ff40c12SJohn Marino 			u8 ek[32];
1590*a1157835SDaniel Fojt 
1591*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1592*a1157835SDaniel Fojt 				   "WPA: Encrypt Key Data using RC4");
15933ff40c12SJohn Marino 			os_memcpy(key->key_iv,
15943ff40c12SJohn Marino 				  sm->group->Counter + WPA_NONCE_LEN - 16, 16);
15953ff40c12SJohn Marino 			inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
15963ff40c12SJohn Marino 			os_memcpy(ek, key->key_iv, 16);
1597*a1157835SDaniel Fojt 			os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
1598*a1157835SDaniel Fojt 			os_memcpy(key_data, buf, key_data_len);
1599*a1157835SDaniel Fojt 			rc4_skip(ek, 32, 256, key_data, key_data_len);
1600*a1157835SDaniel Fojt 			WPA_PUT_BE16(key_mic + mic_len, key_data_len);
1601*a1157835SDaniel Fojt #endif /* CONFIG_NO_RC4 */
1602*a1157835SDaniel Fojt 		} else {
1603*a1157835SDaniel Fojt 			os_free(hdr);
1604*a1157835SDaniel Fojt 			os_free(buf);
1605*a1157835SDaniel Fojt 			return;
16063ff40c12SJohn Marino 		}
16073ff40c12SJohn Marino 		os_free(buf);
16083ff40c12SJohn Marino 	}
16093ff40c12SJohn Marino 
16103ff40c12SJohn Marino 	if (key_info & WPA_KEY_INFO_MIC) {
1611*a1157835SDaniel Fojt 		if (!sm->PTK_valid || !mic_len) {
16123ff40c12SJohn Marino 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
16133ff40c12SJohn Marino 					"PTK not valid when sending EAPOL-Key "
16143ff40c12SJohn Marino 					"frame");
16153ff40c12SJohn Marino 			os_free(hdr);
16163ff40c12SJohn Marino 			return;
16173ff40c12SJohn Marino 		}
1618*a1157835SDaniel Fojt 
1619*a1157835SDaniel Fojt 		if (wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
1620*a1157835SDaniel Fojt 				      sm->wpa_key_mgmt, version,
1621*a1157835SDaniel Fojt 				      (u8 *) hdr, len, key_mic) < 0) {
1622*a1157835SDaniel Fojt 			os_free(hdr);
1623*a1157835SDaniel Fojt 			return;
1624*a1157835SDaniel Fojt 		}
16253ff40c12SJohn Marino #ifdef CONFIG_TESTING_OPTIONS
16263ff40c12SJohn Marino 		if (!pairwise &&
1627*a1157835SDaniel Fojt 		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
16283ff40c12SJohn Marino 		    drand48() <
16293ff40c12SJohn Marino 		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
16303ff40c12SJohn Marino 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
16313ff40c12SJohn Marino 					"Corrupting group EAPOL-Key Key MIC");
1632*a1157835SDaniel Fojt 			key_mic[0]++;
16333ff40c12SJohn Marino 		}
16343ff40c12SJohn Marino #endif /* CONFIG_TESTING_OPTIONS */
16353ff40c12SJohn Marino 	}
16363ff40c12SJohn Marino 
16373ff40c12SJohn Marino 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
16383ff40c12SJohn Marino 			   1);
16393ff40c12SJohn Marino 	wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
16403ff40c12SJohn Marino 			    sm->pairwise_set);
16413ff40c12SJohn Marino 	os_free(hdr);
16423ff40c12SJohn Marino }
16433ff40c12SJohn Marino 
16443ff40c12SJohn Marino 
wpa_send_eapol(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,int key_info,const u8 * key_rsc,const u8 * nonce,const u8 * kde,size_t kde_len,int keyidx,int encr)16453ff40c12SJohn Marino static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
16463ff40c12SJohn Marino 			   struct wpa_state_machine *sm, int key_info,
16473ff40c12SJohn Marino 			   const u8 *key_rsc, const u8 *nonce,
16483ff40c12SJohn Marino 			   const u8 *kde, size_t kde_len,
16493ff40c12SJohn Marino 			   int keyidx, int encr)
16503ff40c12SJohn Marino {
16513ff40c12SJohn Marino 	int timeout_ms;
16523ff40c12SJohn Marino 	int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
1653*a1157835SDaniel Fojt 	u32 ctr;
16543ff40c12SJohn Marino 
16553ff40c12SJohn Marino 	if (sm == NULL)
16563ff40c12SJohn Marino 		return;
16573ff40c12SJohn Marino 
16583ff40c12SJohn Marino 	__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
16593ff40c12SJohn Marino 			 keyidx, encr, 0);
16603ff40c12SJohn Marino 
16613ff40c12SJohn Marino 	ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
16623ff40c12SJohn Marino 	if (ctr == 1 && wpa_auth->conf.tx_status)
16633ff40c12SJohn Marino 		timeout_ms = pairwise ? eapol_key_timeout_first :
16643ff40c12SJohn Marino 			eapol_key_timeout_first_group;
16653ff40c12SJohn Marino 	else
16663ff40c12SJohn Marino 		timeout_ms = eapol_key_timeout_subseq;
1667*a1157835SDaniel Fojt 	if (wpa_auth->conf.wpa_disable_eapol_key_retries &&
1668*a1157835SDaniel Fojt 	    (!pairwise || (key_info & WPA_KEY_INFO_MIC)))
1669*a1157835SDaniel Fojt 		timeout_ms = eapol_key_timeout_no_retrans;
16703ff40c12SJohn Marino 	if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
16713ff40c12SJohn Marino 		sm->pending_1_of_4_timeout = 1;
1672*a1157835SDaniel Fojt #ifdef TEST_FUZZ
1673*a1157835SDaniel Fojt 	timeout_ms = 1;
1674*a1157835SDaniel Fojt #endif /* TEST_FUZZ */
16753ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
1676*a1157835SDaniel Fojt 		   "counter %u)", timeout_ms, ctr);
16773ff40c12SJohn Marino 	eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
16783ff40c12SJohn Marino 			       wpa_send_eapol_timeout, wpa_auth, sm);
16793ff40c12SJohn Marino }
16803ff40c12SJohn Marino 
16813ff40c12SJohn Marino 
wpa_verify_key_mic(int akmp,size_t pmk_len,struct wpa_ptk * PTK,u8 * data,size_t data_len)1682*a1157835SDaniel Fojt static int wpa_verify_key_mic(int akmp, size_t pmk_len, struct wpa_ptk *PTK,
1683*a1157835SDaniel Fojt 			      u8 *data, size_t data_len)
16843ff40c12SJohn Marino {
16853ff40c12SJohn Marino 	struct ieee802_1x_hdr *hdr;
16863ff40c12SJohn Marino 	struct wpa_eapol_key *key;
16873ff40c12SJohn Marino 	u16 key_info;
16883ff40c12SJohn Marino 	int ret = 0;
1689*a1157835SDaniel Fojt 	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN], *mic_pos;
1690*a1157835SDaniel Fojt 	size_t mic_len = wpa_mic_len(akmp, pmk_len);
16913ff40c12SJohn Marino 
16923ff40c12SJohn Marino 	if (data_len < sizeof(*hdr) + sizeof(*key))
16933ff40c12SJohn Marino 		return -1;
16943ff40c12SJohn Marino 
16953ff40c12SJohn Marino 	hdr = (struct ieee802_1x_hdr *) data;
16963ff40c12SJohn Marino 	key = (struct wpa_eapol_key *) (hdr + 1);
1697*a1157835SDaniel Fojt 	mic_pos = (u8 *) (key + 1);
16983ff40c12SJohn Marino 	key_info = WPA_GET_BE16(key->key_info);
1699*a1157835SDaniel Fojt 	os_memcpy(mic, mic_pos, mic_len);
1700*a1157835SDaniel Fojt 	os_memset(mic_pos, 0, mic_len);
1701*a1157835SDaniel Fojt 	if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
1702*a1157835SDaniel Fojt 			      key_info & WPA_KEY_INFO_TYPE_MASK,
1703*a1157835SDaniel Fojt 			      data, data_len, mic_pos) ||
1704*a1157835SDaniel Fojt 	    os_memcmp_const(mic, mic_pos, mic_len) != 0)
17053ff40c12SJohn Marino 		ret = -1;
1706*a1157835SDaniel Fojt 	os_memcpy(mic_pos, mic, mic_len);
17073ff40c12SJohn Marino 	return ret;
17083ff40c12SJohn Marino }
17093ff40c12SJohn Marino 
17103ff40c12SJohn Marino 
wpa_remove_ptk(struct wpa_state_machine * sm)17113ff40c12SJohn Marino void wpa_remove_ptk(struct wpa_state_machine *sm)
17123ff40c12SJohn Marino {
17133ff40c12SJohn Marino 	sm->PTK_valid = FALSE;
17143ff40c12SJohn Marino 	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
1715*a1157835SDaniel Fojt 	if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
1716*a1157835SDaniel Fojt 			     0))
1717*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1718*a1157835SDaniel Fojt 			   "RSN: PTK removal from the driver failed");
17193ff40c12SJohn Marino 	sm->pairwise_set = FALSE;
17203ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
17213ff40c12SJohn Marino }
17223ff40c12SJohn Marino 
17233ff40c12SJohn Marino 
wpa_auth_sm_event(struct wpa_state_machine * sm,enum wpa_event event)1724*a1157835SDaniel Fojt int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
17253ff40c12SJohn Marino {
17263ff40c12SJohn Marino 	int remove_ptk = 1;
17273ff40c12SJohn Marino 
17283ff40c12SJohn Marino 	if (sm == NULL)
17293ff40c12SJohn Marino 		return -1;
17303ff40c12SJohn Marino 
17313ff40c12SJohn Marino 	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
17323ff40c12SJohn Marino 			 "event %d notification", event);
17333ff40c12SJohn Marino 
17343ff40c12SJohn Marino 	switch (event) {
17353ff40c12SJohn Marino 	case WPA_AUTH:
1736*a1157835SDaniel Fojt #ifdef CONFIG_MESH
1737*a1157835SDaniel Fojt 		/* PTKs are derived through AMPE */
1738*a1157835SDaniel Fojt 		if (wpa_auth_start_ampe(sm->wpa_auth, sm->addr)) {
1739*a1157835SDaniel Fojt 			/* not mesh */
1740*a1157835SDaniel Fojt 			break;
1741*a1157835SDaniel Fojt 		}
1742*a1157835SDaniel Fojt 		return 0;
1743*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
17443ff40c12SJohn Marino 	case WPA_ASSOC:
17453ff40c12SJohn Marino 		break;
17463ff40c12SJohn Marino 	case WPA_DEAUTH:
17473ff40c12SJohn Marino 	case WPA_DISASSOC:
17483ff40c12SJohn Marino 		sm->DeauthenticationRequest = TRUE;
1749*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
1750*a1157835SDaniel Fojt 		os_memset(sm->PMK, 0, sizeof(sm->PMK));
1751*a1157835SDaniel Fojt 		sm->pmk_len = 0;
1752*a1157835SDaniel Fojt 		os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
1753*a1157835SDaniel Fojt 		sm->xxkey_len = 0;
1754*a1157835SDaniel Fojt 		os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
1755*a1157835SDaniel Fojt 		sm->pmk_r1_len = 0;
1756*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
17573ff40c12SJohn Marino 		break;
17583ff40c12SJohn Marino 	case WPA_REAUTH:
17593ff40c12SJohn Marino 	case WPA_REAUTH_EAPOL:
17603ff40c12SJohn Marino 		if (!sm->started) {
17613ff40c12SJohn Marino 			/*
17623ff40c12SJohn Marino 			 * When using WPS, we may end up here if the STA
17633ff40c12SJohn Marino 			 * manages to re-associate without the previous STA
17643ff40c12SJohn Marino 			 * entry getting removed. Consequently, we need to make
17653ff40c12SJohn Marino 			 * sure that the WPA state machines gets initialized
17663ff40c12SJohn Marino 			 * properly at this point.
17673ff40c12SJohn Marino 			 */
17683ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "WPA state machine had not been "
17693ff40c12SJohn Marino 				   "started - initialize now");
17703ff40c12SJohn Marino 			sm->started = 1;
17713ff40c12SJohn Marino 			sm->Init = TRUE;
17723ff40c12SJohn Marino 			if (wpa_sm_step(sm) == 1)
17733ff40c12SJohn Marino 				return 1; /* should not really happen */
17743ff40c12SJohn Marino 			sm->Init = FALSE;
17753ff40c12SJohn Marino 			sm->AuthenticationRequest = TRUE;
17763ff40c12SJohn Marino 			break;
17773ff40c12SJohn Marino 		}
17783ff40c12SJohn Marino 		if (sm->GUpdateStationKeys) {
17793ff40c12SJohn Marino 			/*
17803ff40c12SJohn Marino 			 * Reauthentication cancels the pending group key
17813ff40c12SJohn Marino 			 * update for this STA.
17823ff40c12SJohn Marino 			 */
17833ff40c12SJohn Marino 			sm->group->GKeyDoneStations--;
17843ff40c12SJohn Marino 			sm->GUpdateStationKeys = FALSE;
17853ff40c12SJohn Marino 			sm->PtkGroupInit = TRUE;
17863ff40c12SJohn Marino 		}
17873ff40c12SJohn Marino 		sm->ReAuthenticationRequest = TRUE;
17883ff40c12SJohn Marino 		break;
17893ff40c12SJohn Marino 	case WPA_ASSOC_FT:
1790*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
17913ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
17923ff40c12SJohn Marino 			   "after association");
17933ff40c12SJohn Marino 		wpa_ft_install_ptk(sm);
17943ff40c12SJohn Marino 
17953ff40c12SJohn Marino 		/* Using FT protocol, not WPA auth state machine */
17963ff40c12SJohn Marino 		sm->ft_completed = 1;
1797*a1157835SDaniel Fojt 		wpa_auth_set_ptk_rekey_timer(sm);
17983ff40c12SJohn Marino 		return 0;
1799*a1157835SDaniel Fojt #else /* CONFIG_IEEE80211R_AP */
18003ff40c12SJohn Marino 		break;
1801*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
1802*a1157835SDaniel Fojt 	case WPA_ASSOC_FILS:
1803*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1804*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1805*a1157835SDaniel Fojt 			   "FILS: TK configuration after association");
1806*a1157835SDaniel Fojt 		fils_set_tk(sm);
1807*a1157835SDaniel Fojt 		sm->fils_completed = 1;
1808*a1157835SDaniel Fojt 		return 0;
1809*a1157835SDaniel Fojt #else /* CONFIG_FILS */
1810*a1157835SDaniel Fojt 		break;
1811*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1812*a1157835SDaniel Fojt 	case WPA_DRV_STA_REMOVED:
1813*a1157835SDaniel Fojt 		sm->tk_already_set = FALSE;
1814*a1157835SDaniel Fojt 		return 0;
18153ff40c12SJohn Marino 	}
18163ff40c12SJohn Marino 
1817*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
18183ff40c12SJohn Marino 	sm->ft_completed = 0;
1819*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
18203ff40c12SJohn Marino 
18213ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
18223ff40c12SJohn Marino 	if (sm->mgmt_frame_prot && event == WPA_AUTH)
18233ff40c12SJohn Marino 		remove_ptk = 0;
18243ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
1825*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1826*a1157835SDaniel Fojt 	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
1827*a1157835SDaniel Fojt 	    (event == WPA_AUTH || event == WPA_ASSOC))
1828*a1157835SDaniel Fojt 		remove_ptk = 0;
1829*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
18303ff40c12SJohn Marino 
18313ff40c12SJohn Marino 	if (remove_ptk) {
18323ff40c12SJohn Marino 		sm->PTK_valid = FALSE;
18333ff40c12SJohn Marino 		os_memset(&sm->PTK, 0, sizeof(sm->PTK));
18343ff40c12SJohn Marino 
18353ff40c12SJohn Marino 		if (event != WPA_REAUTH_EAPOL)
18363ff40c12SJohn Marino 			wpa_remove_ptk(sm);
18373ff40c12SJohn Marino 	}
18383ff40c12SJohn Marino 
1839*a1157835SDaniel Fojt 	if (sm->in_step_loop) {
1840*a1157835SDaniel Fojt 		/*
1841*a1157835SDaniel Fojt 		 * wpa_sm_step() is already running - avoid recursive call to
1842*a1157835SDaniel Fojt 		 * it by making the existing loop process the new update.
1843*a1157835SDaniel Fojt 		 */
1844*a1157835SDaniel Fojt 		sm->changed = TRUE;
1845*a1157835SDaniel Fojt 		return 0;
1846*a1157835SDaniel Fojt 	}
18473ff40c12SJohn Marino 	return wpa_sm_step(sm);
18483ff40c12SJohn Marino }
18493ff40c12SJohn Marino 
18503ff40c12SJohn Marino 
SM_STATE(WPA_PTK,INITIALIZE)18513ff40c12SJohn Marino SM_STATE(WPA_PTK, INITIALIZE)
18523ff40c12SJohn Marino {
18533ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
18543ff40c12SJohn Marino 	if (sm->Init) {
18553ff40c12SJohn Marino 		/* Init flag is not cleared here, so avoid busy
18563ff40c12SJohn Marino 		 * loop by claiming nothing changed. */
18573ff40c12SJohn Marino 		sm->changed = FALSE;
18583ff40c12SJohn Marino 	}
18593ff40c12SJohn Marino 
18603ff40c12SJohn Marino 	sm->keycount = 0;
18613ff40c12SJohn Marino 	if (sm->GUpdateStationKeys)
18623ff40c12SJohn Marino 		sm->group->GKeyDoneStations--;
18633ff40c12SJohn Marino 	sm->GUpdateStationKeys = FALSE;
18643ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA)
18653ff40c12SJohn Marino 		sm->PInitAKeys = FALSE;
18663ff40c12SJohn Marino 	if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
18673ff40c12SJohn Marino 	       * Local AA > Remote AA)) */) {
18683ff40c12SJohn Marino 		sm->Pair = TRUE;
18693ff40c12SJohn Marino 	}
18703ff40c12SJohn Marino 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
18713ff40c12SJohn Marino 	wpa_remove_ptk(sm);
18723ff40c12SJohn Marino 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
18733ff40c12SJohn Marino 	sm->TimeoutCtr = 0;
1874*a1157835SDaniel Fojt 	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
1875*a1157835SDaniel Fojt 	    sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
1876*a1157835SDaniel Fojt 	    sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) {
18773ff40c12SJohn Marino 		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
18783ff40c12SJohn Marino 				   WPA_EAPOL_authorized, 0);
18793ff40c12SJohn Marino 	}
18803ff40c12SJohn Marino }
18813ff40c12SJohn Marino 
18823ff40c12SJohn Marino 
SM_STATE(WPA_PTK,DISCONNECT)18833ff40c12SJohn Marino SM_STATE(WPA_PTK, DISCONNECT)
18843ff40c12SJohn Marino {
1885*a1157835SDaniel Fojt 	u16 reason = sm->disconnect_reason;
1886*a1157835SDaniel Fojt 
18873ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
18883ff40c12SJohn Marino 	sm->Disconnect = FALSE;
1889*a1157835SDaniel Fojt 	sm->disconnect_reason = 0;
1890*a1157835SDaniel Fojt 	if (!reason)
1891*a1157835SDaniel Fojt 		reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
1892*a1157835SDaniel Fojt 	wpa_sta_disconnect(sm->wpa_auth, sm->addr, reason);
18933ff40c12SJohn Marino }
18943ff40c12SJohn Marino 
18953ff40c12SJohn Marino 
SM_STATE(WPA_PTK,DISCONNECTED)18963ff40c12SJohn Marino SM_STATE(WPA_PTK, DISCONNECTED)
18973ff40c12SJohn Marino {
18983ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
18993ff40c12SJohn Marino 	sm->DeauthenticationRequest = FALSE;
19003ff40c12SJohn Marino }
19013ff40c12SJohn Marino 
19023ff40c12SJohn Marino 
SM_STATE(WPA_PTK,AUTHENTICATION)19033ff40c12SJohn Marino SM_STATE(WPA_PTK, AUTHENTICATION)
19043ff40c12SJohn Marino {
19053ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
19063ff40c12SJohn Marino 	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
19073ff40c12SJohn Marino 	sm->PTK_valid = FALSE;
19083ff40c12SJohn Marino 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
19093ff40c12SJohn Marino 			   1);
19103ff40c12SJohn Marino 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
19113ff40c12SJohn Marino 	sm->AuthenticationRequest = FALSE;
19123ff40c12SJohn Marino }
19133ff40c12SJohn Marino 
19143ff40c12SJohn Marino 
wpa_group_ensure_init(struct wpa_authenticator * wpa_auth,struct wpa_group * group)19153ff40c12SJohn Marino static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
19163ff40c12SJohn Marino 				  struct wpa_group *group)
19173ff40c12SJohn Marino {
19183ff40c12SJohn Marino 	if (group->first_sta_seen)
19193ff40c12SJohn Marino 		return;
19203ff40c12SJohn Marino 	/*
19213ff40c12SJohn Marino 	 * System has run bit further than at the time hostapd was started
19223ff40c12SJohn Marino 	 * potentially very early during boot up. This provides better chances
19233ff40c12SJohn Marino 	 * of collecting more randomness on embedded systems. Re-initialize the
19243ff40c12SJohn Marino 	 * GMK and Counter here to improve their strength if there was not
19253ff40c12SJohn Marino 	 * enough entropy available immediately after system startup.
19263ff40c12SJohn Marino 	 */
19273ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
19283ff40c12SJohn Marino 		   "station");
19293ff40c12SJohn Marino 	if (random_pool_ready() != 1) {
19303ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
19313ff40c12SJohn Marino 			   "to proceed - reject first 4-way handshake");
19323ff40c12SJohn Marino 		group->reject_4way_hs_for_entropy = TRUE;
19333ff40c12SJohn Marino 	} else {
19343ff40c12SJohn Marino 		group->first_sta_seen = TRUE;
19353ff40c12SJohn Marino 		group->reject_4way_hs_for_entropy = FALSE;
19363ff40c12SJohn Marino 	}
19373ff40c12SJohn Marino 
1938*a1157835SDaniel Fojt 	if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 ||
1939*a1157835SDaniel Fojt 	    wpa_gtk_update(wpa_auth, group) < 0 ||
1940*a1157835SDaniel Fojt 	    wpa_group_config_group_keys(wpa_auth, group) < 0) {
1941*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed");
1942*a1157835SDaniel Fojt 		group->first_sta_seen = FALSE;
1943*a1157835SDaniel Fojt 		group->reject_4way_hs_for_entropy = TRUE;
1944*a1157835SDaniel Fojt 	}
19453ff40c12SJohn Marino }
19463ff40c12SJohn Marino 
19473ff40c12SJohn Marino 
SM_STATE(WPA_PTK,AUTHENTICATION2)19483ff40c12SJohn Marino SM_STATE(WPA_PTK, AUTHENTICATION2)
19493ff40c12SJohn Marino {
19503ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
19513ff40c12SJohn Marino 
19523ff40c12SJohn Marino 	wpa_group_ensure_init(sm->wpa_auth, sm->group);
19533ff40c12SJohn Marino 	sm->ReAuthenticationRequest = FALSE;
19543ff40c12SJohn Marino 
19553ff40c12SJohn Marino 	/*
19563ff40c12SJohn Marino 	 * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
19573ff40c12SJohn Marino 	 * ambiguous. The Authenticator state machine uses a counter that is
19583ff40c12SJohn Marino 	 * incremented by one for each 4-way handshake. However, the security
19593ff40c12SJohn Marino 	 * analysis of 4-way handshake points out that unpredictable nonces
19603ff40c12SJohn Marino 	 * help in preventing precomputation attacks. Instead of the state
19613ff40c12SJohn Marino 	 * machine definition, use an unpredictable nonce value here to provide
19623ff40c12SJohn Marino 	 * stronger protection against potential precomputation attacks.
19633ff40c12SJohn Marino 	 */
19643ff40c12SJohn Marino 	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
19653ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
19663ff40c12SJohn Marino 			   "ANonce.");
19673ff40c12SJohn Marino 		sm->Disconnect = TRUE;
19683ff40c12SJohn Marino 		return;
19693ff40c12SJohn Marino 	}
19703ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
19713ff40c12SJohn Marino 		    WPA_NONCE_LEN);
19723ff40c12SJohn Marino 	/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
19733ff40c12SJohn Marino 	 * logical place than INITIALIZE since AUTHENTICATION2 can be
19743ff40c12SJohn Marino 	 * re-entered on ReAuthenticationRequest without going through
19753ff40c12SJohn Marino 	 * INITIALIZE. */
19763ff40c12SJohn Marino 	sm->TimeoutCtr = 0;
19773ff40c12SJohn Marino }
19783ff40c12SJohn Marino 
19793ff40c12SJohn Marino 
wpa_auth_sm_ptk_update(struct wpa_state_machine * sm)1980*a1157835SDaniel Fojt static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
1981*a1157835SDaniel Fojt {
1982*a1157835SDaniel Fojt 	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
1983*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
1984*a1157835SDaniel Fojt 			   "WPA: Failed to get random data for ANonce");
1985*a1157835SDaniel Fojt 		sm->Disconnect = TRUE;
1986*a1157835SDaniel Fojt 		return -1;
1987*a1157835SDaniel Fojt 	}
1988*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
1989*a1157835SDaniel Fojt 		    WPA_NONCE_LEN);
1990*a1157835SDaniel Fojt 	sm->TimeoutCtr = 0;
1991*a1157835SDaniel Fojt 	return 0;
1992*a1157835SDaniel Fojt }
1993*a1157835SDaniel Fojt 
1994*a1157835SDaniel Fojt 
SM_STATE(WPA_PTK,INITPMK)19953ff40c12SJohn Marino SM_STATE(WPA_PTK, INITPMK)
19963ff40c12SJohn Marino {
19973ff40c12SJohn Marino 	u8 msk[2 * PMK_LEN];
19983ff40c12SJohn Marino 	size_t len = 2 * PMK_LEN;
19993ff40c12SJohn Marino 
20003ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
2001*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
20023ff40c12SJohn Marino 	sm->xxkey_len = 0;
2003*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
20043ff40c12SJohn Marino 	if (sm->pmksa) {
20053ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
2006*a1157835SDaniel Fojt 		os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
2007*a1157835SDaniel Fojt 		sm->pmk_len = sm->pmksa->pmk_len;
2008*a1157835SDaniel Fojt #ifdef CONFIG_DPP
2009*a1157835SDaniel Fojt 	} else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
2010*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2011*a1157835SDaniel Fojt 			   "DPP: No PMKSA cache entry for STA - reject connection");
2012*a1157835SDaniel Fojt 		sm->Disconnect = TRUE;
2013*a1157835SDaniel Fojt 		sm->disconnect_reason = WLAN_REASON_INVALID_PMKID;
2014*a1157835SDaniel Fojt 		return;
2015*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
20163ff40c12SJohn Marino 	} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
2017*a1157835SDaniel Fojt 		unsigned int pmk_len;
2018*a1157835SDaniel Fojt 
2019*a1157835SDaniel Fojt 		if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt))
2020*a1157835SDaniel Fojt 			pmk_len = PMK_LEN_SUITE_B_192;
2021*a1157835SDaniel Fojt 		else
2022*a1157835SDaniel Fojt 			pmk_len = PMK_LEN;
20233ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
2024*a1157835SDaniel Fojt 			   "(MSK len=%lu PMK len=%u)", (unsigned long) len,
2025*a1157835SDaniel Fojt 			   pmk_len);
2026*a1157835SDaniel Fojt 		if (len < pmk_len) {
2027*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2028*a1157835SDaniel Fojt 				   "WPA: MSK not long enough (%u) to create PMK (%u)",
2029*a1157835SDaniel Fojt 				   (unsigned int) len, (unsigned int) pmk_len);
2030*a1157835SDaniel Fojt 			sm->Disconnect = TRUE;
2031*a1157835SDaniel Fojt 			return;
2032*a1157835SDaniel Fojt 		}
2033*a1157835SDaniel Fojt 		os_memcpy(sm->PMK, msk, pmk_len);
2034*a1157835SDaniel Fojt 		sm->pmk_len = pmk_len;
2035*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
20363ff40c12SJohn Marino 		if (len >= 2 * PMK_LEN) {
2037*a1157835SDaniel Fojt 			if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
2038*a1157835SDaniel Fojt 				os_memcpy(sm->xxkey, msk, SHA384_MAC_LEN);
2039*a1157835SDaniel Fojt 				sm->xxkey_len = SHA384_MAC_LEN;
2040*a1157835SDaniel Fojt 			} else {
20413ff40c12SJohn Marino 				os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
20423ff40c12SJohn Marino 				sm->xxkey_len = PMK_LEN;
20433ff40c12SJohn Marino 			}
20443ff40c12SJohn Marino 		}
2045*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
2046*a1157835SDaniel Fojt 	} else {
2047*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
2048*a1157835SDaniel Fojt 			   sm->wpa_auth->cb->get_msk);
2049*a1157835SDaniel Fojt 		sm->Disconnect = TRUE;
2050*a1157835SDaniel Fojt 		return;
2051*a1157835SDaniel Fojt 	}
2052*a1157835SDaniel Fojt 	forced_memzero(msk, sizeof(msk));
20533ff40c12SJohn Marino 
20543ff40c12SJohn Marino 	sm->req_replay_counter_used = 0;
20553ff40c12SJohn Marino 	/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
20563ff40c12SJohn Marino 	 * will break reauthentication since EAPOL state machines may not be
20573ff40c12SJohn Marino 	 * get into AUTHENTICATING state that clears keyRun before WPA state
20583ff40c12SJohn Marino 	 * machine enters AUTHENTICATION2 state and goes immediately to INITPMK
20593ff40c12SJohn Marino 	 * state and takes PMK from the previously used AAA Key. This will
20603ff40c12SJohn Marino 	 * eventually fail in 4-Way Handshake because Supplicant uses PMK
20613ff40c12SJohn Marino 	 * derived from the new AAA Key. Setting keyRun = FALSE here seems to
20623ff40c12SJohn Marino 	 * be good workaround for this issue. */
20633ff40c12SJohn Marino 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
20643ff40c12SJohn Marino }
20653ff40c12SJohn Marino 
20663ff40c12SJohn Marino 
SM_STATE(WPA_PTK,INITPSK)20673ff40c12SJohn Marino SM_STATE(WPA_PTK, INITPSK)
20683ff40c12SJohn Marino {
20693ff40c12SJohn Marino 	const u8 *psk;
2070*a1157835SDaniel Fojt 	size_t psk_len;
2071*a1157835SDaniel Fojt 
20723ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
2073*a1157835SDaniel Fojt 	psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
2074*a1157835SDaniel Fojt 			       &psk_len, NULL);
20753ff40c12SJohn Marino 	if (psk) {
2076*a1157835SDaniel Fojt 		os_memcpy(sm->PMK, psk, psk_len);
2077*a1157835SDaniel Fojt 		sm->pmk_len = psk_len;
2078*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
20793ff40c12SJohn Marino 		os_memcpy(sm->xxkey, psk, PMK_LEN);
20803ff40c12SJohn Marino 		sm->xxkey_len = PMK_LEN;
2081*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
20823ff40c12SJohn Marino 	}
2083*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2084*a1157835SDaniel Fojt 	if (wpa_auth_uses_sae(sm) && sm->pmksa) {
2085*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache");
2086*a1157835SDaniel Fojt 		os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
2087*a1157835SDaniel Fojt 		sm->pmk_len = sm->pmksa->pmk_len;
2088*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
2089*a1157835SDaniel Fojt 		os_memcpy(sm->xxkey, sm->pmksa->pmk, sm->pmksa->pmk_len);
2090*a1157835SDaniel Fojt 		sm->xxkey_len = sm->pmksa->pmk_len;
2091*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
2092*a1157835SDaniel Fojt 	}
2093*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
20943ff40c12SJohn Marino 	sm->req_replay_counter_used = 0;
20953ff40c12SJohn Marino }
20963ff40c12SJohn Marino 
20973ff40c12SJohn Marino 
SM_STATE(WPA_PTK,PTKSTART)20983ff40c12SJohn Marino SM_STATE(WPA_PTK, PTKSTART)
20993ff40c12SJohn Marino {
21003ff40c12SJohn Marino 	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
21013ff40c12SJohn Marino 	size_t pmkid_len = 0;
21023ff40c12SJohn Marino 
21033ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
21043ff40c12SJohn Marino 	sm->PTKRequest = FALSE;
21053ff40c12SJohn Marino 	sm->TimeoutEvt = FALSE;
2106*a1157835SDaniel Fojt 	sm->alt_snonce_valid = FALSE;
21073ff40c12SJohn Marino 
21083ff40c12SJohn Marino 	sm->TimeoutCtr++;
2109*a1157835SDaniel Fojt 	if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
21103ff40c12SJohn Marino 		/* No point in sending the EAPOL-Key - we will disconnect
21113ff40c12SJohn Marino 		 * immediately following this. */
21123ff40c12SJohn Marino 		return;
21133ff40c12SJohn Marino 	}
21143ff40c12SJohn Marino 
21153ff40c12SJohn Marino 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
21163ff40c12SJohn Marino 			"sending 1/4 msg of 4-Way Handshake");
21173ff40c12SJohn Marino 	/*
2118*a1157835SDaniel Fojt 	 * For infrastructure BSS cases, it is better for the AP not to include
2119*a1157835SDaniel Fojt 	 * the PMKID KDE in EAPOL-Key msg 1/4 since it could be used to initiate
2120*a1157835SDaniel Fojt 	 * offline search for the passphrase/PSK without having to be able to
2121*a1157835SDaniel Fojt 	 * capture a 4-way handshake from a STA that has access to the network.
2122*a1157835SDaniel Fojt 	 *
2123*a1157835SDaniel Fojt 	 * For IBSS cases, addition of PMKID KDE could be considered even with
2124*a1157835SDaniel Fojt 	 * WPA2-PSK cases that use multiple PSKs, but only if there is a single
2125*a1157835SDaniel Fojt 	 * possible PSK for this STA. However, this should not be done unless
2126*a1157835SDaniel Fojt 	 * there is support for using that information on the supplicant side.
2127*a1157835SDaniel Fojt 	 * The concern about exposing PMKID unnecessarily in infrastructure BSS
2128*a1157835SDaniel Fojt 	 * cases would also apply here, but at least in the IBSS case, this
2129*a1157835SDaniel Fojt 	 * would cover a potential real use case.
21303ff40c12SJohn Marino 	 */
21313ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA2 &&
2132*a1157835SDaniel Fojt 	    (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) ||
2133*a1157835SDaniel Fojt 	     (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && sm->pmksa) ||
2134*a1157835SDaniel Fojt 	     wpa_key_mgmt_sae(sm->wpa_key_mgmt)) &&
2135*a1157835SDaniel Fojt 	    sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN) {
21363ff40c12SJohn Marino 		pmkid = buf;
21373ff40c12SJohn Marino 		pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
21383ff40c12SJohn Marino 		pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
21393ff40c12SJohn Marino 		pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
21403ff40c12SJohn Marino 		RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
2141*a1157835SDaniel Fojt 		if (sm->pmksa) {
2142*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG,
2143*a1157835SDaniel Fojt 				    "RSN: Message 1/4 PMKID from PMKSA entry",
2144*a1157835SDaniel Fojt 				    sm->pmksa->pmkid, PMKID_LEN);
21453ff40c12SJohn Marino 			os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
21463ff40c12SJohn Marino 				  sm->pmksa->pmkid, PMKID_LEN);
2147*a1157835SDaniel Fojt 		} else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
2148*a1157835SDaniel Fojt 			/* No KCK available to derive PMKID */
2149*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2150*a1157835SDaniel Fojt 				   "RSN: No KCK available to derive PMKID for message 1/4");
2151*a1157835SDaniel Fojt 			pmkid = NULL;
2152*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2153*a1157835SDaniel Fojt 		} else if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
2154*a1157835SDaniel Fojt 			if (sm->pmkid_set) {
2155*a1157835SDaniel Fojt 				wpa_hexdump(MSG_DEBUG,
2156*a1157835SDaniel Fojt 					    "RSN: Message 1/4 PMKID from FILS/ERP",
2157*a1157835SDaniel Fojt 					    sm->pmkid, PMKID_LEN);
2158*a1157835SDaniel Fojt 				os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
2159*a1157835SDaniel Fojt 					  sm->pmkid, PMKID_LEN);
2160*a1157835SDaniel Fojt 			} else {
2161*a1157835SDaniel Fojt 				/* No PMKID available */
2162*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
2163*a1157835SDaniel Fojt 					   "RSN: No FILS/ERP PMKID available for message 1/4");
2164*a1157835SDaniel Fojt 				pmkid = NULL;
2165*a1157835SDaniel Fojt 			}
2166*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2167*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
2168*a1157835SDaniel Fojt 		} else if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
2169*a1157835SDaniel Fojt 			   sm->ft_completed) {
2170*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2171*a1157835SDaniel Fojt 				   "FT: No PMKID in message 1/4 when using FT protocol");
2172*a1157835SDaniel Fojt 			pmkid = NULL;
2173*a1157835SDaniel Fojt 			pmkid_len = 0;
2174*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
2175*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2176*a1157835SDaniel Fojt 		} else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
2177*a1157835SDaniel Fojt 			if (sm->pmkid_set) {
2178*a1157835SDaniel Fojt 				wpa_hexdump(MSG_DEBUG,
2179*a1157835SDaniel Fojt 					    "RSN: Message 1/4 PMKID from SAE",
2180*a1157835SDaniel Fojt 					    sm->pmkid, PMKID_LEN);
2181*a1157835SDaniel Fojt 				os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
2182*a1157835SDaniel Fojt 					  sm->pmkid, PMKID_LEN);
2183*a1157835SDaniel Fojt 			} else {
2184*a1157835SDaniel Fojt 				/* No PMKID available */
2185*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
2186*a1157835SDaniel Fojt 					   "RSN: No SAE PMKID available for message 1/4");
2187*a1157835SDaniel Fojt 				pmkid = NULL;
2188*a1157835SDaniel Fojt 			}
2189*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2190*a1157835SDaniel Fojt 		} else {
21913ff40c12SJohn Marino 			/*
21923ff40c12SJohn Marino 			 * Calculate PMKID since no PMKSA cache entry was
21933ff40c12SJohn Marino 			 * available with pre-calculated PMKID.
21943ff40c12SJohn Marino 			 */
2195*a1157835SDaniel Fojt 			rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
21963ff40c12SJohn Marino 				  sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
2197*a1157835SDaniel Fojt 				  sm->wpa_key_mgmt);
2198*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG,
2199*a1157835SDaniel Fojt 				    "RSN: Message 1/4 PMKID derived from PMK",
2200*a1157835SDaniel Fojt 				    &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
22013ff40c12SJohn Marino 		}
22023ff40c12SJohn Marino 	}
22033ff40c12SJohn Marino 	wpa_send_eapol(sm->wpa_auth, sm,
22043ff40c12SJohn Marino 		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
22053ff40c12SJohn Marino 		       sm->ANonce, pmkid, pmkid_len, 0, 0);
22063ff40c12SJohn Marino }
22073ff40c12SJohn Marino 
22083ff40c12SJohn Marino 
wpa_derive_ptk(struct wpa_state_machine * sm,const u8 * snonce,const u8 * pmk,unsigned int pmk_len,struct wpa_ptk * ptk)2209*a1157835SDaniel Fojt static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
2210*a1157835SDaniel Fojt 			  const u8 *pmk, unsigned int pmk_len,
22113ff40c12SJohn Marino 			  struct wpa_ptk *ptk)
22123ff40c12SJohn Marino {
2213*a1157835SDaniel Fojt 	const u8 *z = NULL;
2214*a1157835SDaniel Fojt 	size_t z_len = 0;
22153ff40c12SJohn Marino 
2216*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
2217*a1157835SDaniel Fojt 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
2218*a1157835SDaniel Fojt 		if (sm->ft_completed) {
2219*a1157835SDaniel Fojt 			u8 ptk_name[WPA_PMK_NAME_LEN];
2220*a1157835SDaniel Fojt 
2221*a1157835SDaniel Fojt 			return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
2222*a1157835SDaniel Fojt 						 sm->SNonce, sm->ANonce,
2223*a1157835SDaniel Fojt 						 sm->addr, sm->wpa_auth->addr,
2224*a1157835SDaniel Fojt 						 sm->pmk_r1_name,
2225*a1157835SDaniel Fojt 						 ptk, ptk_name,
2226*a1157835SDaniel Fojt 						 sm->wpa_key_mgmt,
2227*a1157835SDaniel Fojt 						 sm->pairwise);
2228*a1157835SDaniel Fojt 		}
2229*a1157835SDaniel Fojt 		return wpa_auth_derive_ptk_ft(sm, ptk);
2230*a1157835SDaniel Fojt 	}
2231*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
2232*a1157835SDaniel Fojt 
2233*a1157835SDaniel Fojt #ifdef CONFIG_DPP2
2234*a1157835SDaniel Fojt 	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
2235*a1157835SDaniel Fojt 		z = wpabuf_head(sm->dpp_z);
2236*a1157835SDaniel Fojt 		z_len = wpabuf_len(sm->dpp_z);
2237*a1157835SDaniel Fojt 	}
2238*a1157835SDaniel Fojt #endif /* CONFIG_DPP2 */
2239*a1157835SDaniel Fojt 
2240*a1157835SDaniel Fojt 	return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
2241*a1157835SDaniel Fojt 			      sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
2242*a1157835SDaniel Fojt 			      ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
2243*a1157835SDaniel Fojt }
2244*a1157835SDaniel Fojt 
2245*a1157835SDaniel Fojt 
2246*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2247*a1157835SDaniel Fojt 
fils_auth_pmk_to_ptk(struct wpa_state_machine * sm,const u8 * pmk,size_t pmk_len,const u8 * snonce,const u8 * anonce,const u8 * dhss,size_t dhss_len,struct wpabuf * g_sta,struct wpabuf * g_ap)2248*a1157835SDaniel Fojt int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
2249*a1157835SDaniel Fojt 			 size_t pmk_len, const u8 *snonce, const u8 *anonce,
2250*a1157835SDaniel Fojt 			 const u8 *dhss, size_t dhss_len,
2251*a1157835SDaniel Fojt 			 struct wpabuf *g_sta, struct wpabuf *g_ap)
2252*a1157835SDaniel Fojt {
2253*a1157835SDaniel Fojt 	u8 ick[FILS_ICK_MAX_LEN];
2254*a1157835SDaniel Fojt 	size_t ick_len;
2255*a1157835SDaniel Fojt 	int res;
2256*a1157835SDaniel Fojt 	u8 fils_ft[FILS_FT_MAX_LEN];
2257*a1157835SDaniel Fojt 	size_t fils_ft_len = 0;
2258*a1157835SDaniel Fojt 
2259*a1157835SDaniel Fojt 	res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr,
2260*a1157835SDaniel Fojt 			      snonce, anonce, dhss, dhss_len,
2261*a1157835SDaniel Fojt 			      &sm->PTK, ick, &ick_len,
2262*a1157835SDaniel Fojt 			      sm->wpa_key_mgmt, sm->pairwise,
2263*a1157835SDaniel Fojt 			      fils_ft, &fils_ft_len);
2264*a1157835SDaniel Fojt 	if (res < 0)
2265*a1157835SDaniel Fojt 		return res;
2266*a1157835SDaniel Fojt 	sm->PTK_valid = TRUE;
2267*a1157835SDaniel Fojt 	sm->tk_already_set = FALSE;
2268*a1157835SDaniel Fojt 
2269*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
2270*a1157835SDaniel Fojt 	if (fils_ft_len) {
2271*a1157835SDaniel Fojt 		struct wpa_authenticator *wpa_auth = sm->wpa_auth;
2272*a1157835SDaniel Fojt 		struct wpa_auth_config *conf = &wpa_auth->conf;
2273*a1157835SDaniel Fojt 		u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
2274*a1157835SDaniel Fojt 		int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
2275*a1157835SDaniel Fojt 		size_t pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
2276*a1157835SDaniel Fojt 
2277*a1157835SDaniel Fojt 		if (wpa_derive_pmk_r0(fils_ft, fils_ft_len,
2278*a1157835SDaniel Fojt 				      conf->ssid, conf->ssid_len,
2279*a1157835SDaniel Fojt 				      conf->mobility_domain,
2280*a1157835SDaniel Fojt 				      conf->r0_key_holder,
2281*a1157835SDaniel Fojt 				      conf->r0_key_holder_len,
2282*a1157835SDaniel Fojt 				      sm->addr, pmk_r0, pmk_r0_name,
2283*a1157835SDaniel Fojt 				      use_sha384) < 0)
2284*a1157835SDaniel Fojt 			return -1;
2285*a1157835SDaniel Fojt 
2286*a1157835SDaniel Fojt 		wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
2287*a1157835SDaniel Fojt 				pmk_r0, pmk_r0_len);
2288*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
2289*a1157835SDaniel Fojt 			    pmk_r0_name, WPA_PMK_NAME_LEN);
2290*a1157835SDaniel Fojt 		wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
2291*a1157835SDaniel Fojt 		forced_memzero(fils_ft, sizeof(fils_ft));
2292*a1157835SDaniel Fojt 
2293*a1157835SDaniel Fojt 		res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
2294*a1157835SDaniel Fojt 					     sm->addr, sm->pmk_r1_name,
2295*a1157835SDaniel Fojt 					     use_sha384);
2296*a1157835SDaniel Fojt 		forced_memzero(pmk_r0, PMK_LEN_MAX);
2297*a1157835SDaniel Fojt 		if (res < 0)
2298*a1157835SDaniel Fojt 			return -1;
2299*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
2300*a1157835SDaniel Fojt 			    WPA_PMK_NAME_LEN);
2301*a1157835SDaniel Fojt 		sm->pmk_r1_name_valid = 1;
2302*a1157835SDaniel Fojt 	}
2303*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
2304*a1157835SDaniel Fojt 
2305*a1157835SDaniel Fojt 	res = fils_key_auth_sk(ick, ick_len, snonce, anonce,
2306*a1157835SDaniel Fojt 			       sm->addr, sm->wpa_auth->addr,
2307*a1157835SDaniel Fojt 			       g_sta ? wpabuf_head(g_sta) : NULL,
2308*a1157835SDaniel Fojt 			       g_sta ? wpabuf_len(g_sta) : 0,
2309*a1157835SDaniel Fojt 			       g_ap ? wpabuf_head(g_ap) : NULL,
2310*a1157835SDaniel Fojt 			       g_ap ? wpabuf_len(g_ap) : 0,
2311*a1157835SDaniel Fojt 			       sm->wpa_key_mgmt, sm->fils_key_auth_sta,
2312*a1157835SDaniel Fojt 			       sm->fils_key_auth_ap,
2313*a1157835SDaniel Fojt 			       &sm->fils_key_auth_len);
2314*a1157835SDaniel Fojt 	forced_memzero(ick, sizeof(ick));
2315*a1157835SDaniel Fojt 
2316*a1157835SDaniel Fojt 	/* Store nonces for (Re)Association Request/Response frame processing */
2317*a1157835SDaniel Fojt 	os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
2318*a1157835SDaniel Fojt 	os_memcpy(sm->ANonce, anonce, FILS_NONCE_LEN);
2319*a1157835SDaniel Fojt 
2320*a1157835SDaniel Fojt 	return res;
2321*a1157835SDaniel Fojt }
2322*a1157835SDaniel Fojt 
2323*a1157835SDaniel Fojt 
wpa_aead_decrypt(struct wpa_state_machine * sm,struct wpa_ptk * ptk,u8 * buf,size_t buf_len,u16 * _key_data_len)2324*a1157835SDaniel Fojt static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
2325*a1157835SDaniel Fojt 			    u8 *buf, size_t buf_len, u16 *_key_data_len)
2326*a1157835SDaniel Fojt {
2327*a1157835SDaniel Fojt 	struct ieee802_1x_hdr *hdr;
2328*a1157835SDaniel Fojt 	struct wpa_eapol_key *key;
2329*a1157835SDaniel Fojt 	u8 *pos;
2330*a1157835SDaniel Fojt 	u16 key_data_len;
2331*a1157835SDaniel Fojt 	u8 *tmp;
2332*a1157835SDaniel Fojt 	const u8 *aad[1];
2333*a1157835SDaniel Fojt 	size_t aad_len[1];
2334*a1157835SDaniel Fojt 
2335*a1157835SDaniel Fojt 	hdr = (struct ieee802_1x_hdr *) buf;
2336*a1157835SDaniel Fojt 	key = (struct wpa_eapol_key *) (hdr + 1);
2337*a1157835SDaniel Fojt 	pos = (u8 *) (key + 1);
2338*a1157835SDaniel Fojt 	key_data_len = WPA_GET_BE16(pos);
2339*a1157835SDaniel Fojt 	if (key_data_len < AES_BLOCK_SIZE ||
2340*a1157835SDaniel Fojt 	    key_data_len > buf_len - sizeof(*hdr) - sizeof(*key) - 2) {
2341*a1157835SDaniel Fojt 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
2342*a1157835SDaniel Fojt 				"No room for AES-SIV data in the frame");
2343*a1157835SDaniel Fojt 		return -1;
2344*a1157835SDaniel Fojt 	}
2345*a1157835SDaniel Fojt 	pos += 2; /* Pointing at the Encrypted Key Data field */
2346*a1157835SDaniel Fojt 
2347*a1157835SDaniel Fojt 	tmp = os_malloc(key_data_len);
2348*a1157835SDaniel Fojt 	if (!tmp)
2349*a1157835SDaniel Fojt 		return -1;
2350*a1157835SDaniel Fojt 
2351*a1157835SDaniel Fojt 	/* AES-SIV AAD from EAPOL protocol version field (inclusive) to
2352*a1157835SDaniel Fojt 	 * to Key Data (exclusive). */
2353*a1157835SDaniel Fojt 	aad[0] = buf;
2354*a1157835SDaniel Fojt 	aad_len[0] = pos - buf;
2355*a1157835SDaniel Fojt 	if (aes_siv_decrypt(ptk->kek, ptk->kek_len, pos, key_data_len,
2356*a1157835SDaniel Fojt 			    1, aad, aad_len, tmp) < 0) {
2357*a1157835SDaniel Fojt 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
2358*a1157835SDaniel Fojt 				"Invalid AES-SIV data in the frame");
2359*a1157835SDaniel Fojt 		bin_clear_free(tmp, key_data_len);
2360*a1157835SDaniel Fojt 		return -1;
2361*a1157835SDaniel Fojt 	}
2362*a1157835SDaniel Fojt 
2363*a1157835SDaniel Fojt 	/* AEAD decryption and validation completed successfully */
2364*a1157835SDaniel Fojt 	key_data_len -= AES_BLOCK_SIZE;
2365*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "WPA: Decrypted Key Data",
2366*a1157835SDaniel Fojt 			tmp, key_data_len);
2367*a1157835SDaniel Fojt 
2368*a1157835SDaniel Fojt 	/* Replace Key Data field with the decrypted version */
2369*a1157835SDaniel Fojt 	os_memcpy(pos, tmp, key_data_len);
2370*a1157835SDaniel Fojt 	pos -= 2; /* Key Data Length field */
2371*a1157835SDaniel Fojt 	WPA_PUT_BE16(pos, key_data_len);
2372*a1157835SDaniel Fojt 	bin_clear_free(tmp, key_data_len);
2373*a1157835SDaniel Fojt 	if (_key_data_len)
2374*a1157835SDaniel Fojt 		*_key_data_len = key_data_len;
2375*a1157835SDaniel Fojt 	return 0;
2376*a1157835SDaniel Fojt }
2377*a1157835SDaniel Fojt 
2378*a1157835SDaniel Fojt 
wpa_fils_validate_fils_session(struct wpa_state_machine * sm,const u8 * ies,size_t ies_len,const u8 * fils_session)2379*a1157835SDaniel Fojt const u8 * wpa_fils_validate_fils_session(struct wpa_state_machine *sm,
2380*a1157835SDaniel Fojt 					  const u8 *ies, size_t ies_len,
2381*a1157835SDaniel Fojt 					  const u8 *fils_session)
2382*a1157835SDaniel Fojt {
2383*a1157835SDaniel Fojt 	const u8 *ie, *end;
2384*a1157835SDaniel Fojt 	const u8 *session = NULL;
2385*a1157835SDaniel Fojt 
2386*a1157835SDaniel Fojt 	if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
2387*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2388*a1157835SDaniel Fojt 			   "FILS: Not a FILS AKM - reject association");
2389*a1157835SDaniel Fojt 		return NULL;
2390*a1157835SDaniel Fojt 	}
2391*a1157835SDaniel Fojt 
2392*a1157835SDaniel Fojt 	/* Verify Session element */
2393*a1157835SDaniel Fojt 	ie = ies;
2394*a1157835SDaniel Fojt 	end = ((const u8 *) ie) + ies_len;
2395*a1157835SDaniel Fojt 	while (ie + 1 < end) {
2396*a1157835SDaniel Fojt 		if (ie + 2 + ie[1] > end)
2397*a1157835SDaniel Fojt 			break;
2398*a1157835SDaniel Fojt 		if (ie[0] == WLAN_EID_EXTENSION &&
2399*a1157835SDaniel Fojt 		    ie[1] >= 1 + FILS_SESSION_LEN &&
2400*a1157835SDaniel Fojt 		    ie[2] == WLAN_EID_EXT_FILS_SESSION) {
2401*a1157835SDaniel Fojt 			session = ie;
2402*a1157835SDaniel Fojt 			break;
2403*a1157835SDaniel Fojt 		}
2404*a1157835SDaniel Fojt 		ie += 2 + ie[1];
2405*a1157835SDaniel Fojt 	}
2406*a1157835SDaniel Fojt 
2407*a1157835SDaniel Fojt 	if (!session) {
2408*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2409*a1157835SDaniel Fojt 			   "FILS: %s: Could not find FILS Session element in Assoc Req - reject",
2410*a1157835SDaniel Fojt 			   __func__);
2411*a1157835SDaniel Fojt 		return NULL;
2412*a1157835SDaniel Fojt 	}
2413*a1157835SDaniel Fojt 
2414*a1157835SDaniel Fojt 	if (!fils_session) {
2415*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2416*a1157835SDaniel Fojt 			   "FILS: %s: Could not find FILS Session element in STA entry - reject",
2417*a1157835SDaniel Fojt 			   __func__);
2418*a1157835SDaniel Fojt 		return NULL;
2419*a1157835SDaniel Fojt 	}
2420*a1157835SDaniel Fojt 
2421*a1157835SDaniel Fojt 	if (os_memcmp(fils_session, session + 3, FILS_SESSION_LEN) != 0) {
2422*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
2423*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
2424*a1157835SDaniel Fojt 			    fils_session, FILS_SESSION_LEN);
2425*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
2426*a1157835SDaniel Fojt 			    session + 3, FILS_SESSION_LEN);
2427*a1157835SDaniel Fojt 		return NULL;
2428*a1157835SDaniel Fojt 	}
2429*a1157835SDaniel Fojt 	return session;
2430*a1157835SDaniel Fojt }
2431*a1157835SDaniel Fojt 
2432*a1157835SDaniel Fojt 
wpa_fils_validate_key_confirm(struct wpa_state_machine * sm,const u8 * ies,size_t ies_len)2433*a1157835SDaniel Fojt int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
2434*a1157835SDaniel Fojt 				  size_t ies_len)
2435*a1157835SDaniel Fojt {
2436*a1157835SDaniel Fojt 	struct ieee802_11_elems elems;
2437*a1157835SDaniel Fojt 
2438*a1157835SDaniel Fojt 	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
2439*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2440*a1157835SDaniel Fojt 			   "FILS: Failed to parse decrypted elements");
2441*a1157835SDaniel Fojt 		return -1;
2442*a1157835SDaniel Fojt 	}
2443*a1157835SDaniel Fojt 
2444*a1157835SDaniel Fojt 	if (!elems.fils_session) {
2445*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
2446*a1157835SDaniel Fojt 		return -1;
2447*a1157835SDaniel Fojt 	}
2448*a1157835SDaniel Fojt 
2449*a1157835SDaniel Fojt 	if (!elems.fils_key_confirm) {
2450*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
2451*a1157835SDaniel Fojt 		return -1;
2452*a1157835SDaniel Fojt 	}
2453*a1157835SDaniel Fojt 
2454*a1157835SDaniel Fojt 	if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
2455*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2456*a1157835SDaniel Fojt 			   "FILS: Unexpected Key-Auth length %d (expected %d)",
2457*a1157835SDaniel Fojt 			   elems.fils_key_confirm_len,
2458*a1157835SDaniel Fojt 			   (int) sm->fils_key_auth_len);
2459*a1157835SDaniel Fojt 		return -1;
2460*a1157835SDaniel Fojt 	}
2461*a1157835SDaniel Fojt 
2462*a1157835SDaniel Fojt 	if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_sta,
2463*a1157835SDaniel Fojt 		      sm->fils_key_auth_len) != 0) {
2464*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
2465*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
2466*a1157835SDaniel Fojt 			    elems.fils_key_confirm, elems.fils_key_confirm_len);
2467*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
2468*a1157835SDaniel Fojt 			    sm->fils_key_auth_sta, sm->fils_key_auth_len);
2469*a1157835SDaniel Fojt 		return -1;
2470*a1157835SDaniel Fojt 	}
24713ff40c12SJohn Marino 
24723ff40c12SJohn Marino 	return 0;
24733ff40c12SJohn Marino }
24743ff40c12SJohn Marino 
24753ff40c12SJohn Marino 
fils_decrypt_assoc(struct wpa_state_machine * sm,const u8 * fils_session,const struct ieee80211_mgmt * mgmt,size_t frame_len,u8 * pos,size_t left)2476*a1157835SDaniel Fojt int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
2477*a1157835SDaniel Fojt 		       const struct ieee80211_mgmt *mgmt, size_t frame_len,
2478*a1157835SDaniel Fojt 		       u8 *pos, size_t left)
2479*a1157835SDaniel Fojt {
2480*a1157835SDaniel Fojt 	u16 fc, stype;
2481*a1157835SDaniel Fojt 	const u8 *end, *ie_start, *ie, *session, *crypt;
2482*a1157835SDaniel Fojt 	const u8 *aad[5];
2483*a1157835SDaniel Fojt 	size_t aad_len[5];
2484*a1157835SDaniel Fojt 
2485*a1157835SDaniel Fojt 	if (!sm || !sm->PTK_valid) {
2486*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2487*a1157835SDaniel Fojt 			   "FILS: No KEK to decrypt Assocication Request frame");
2488*a1157835SDaniel Fojt 		return -1;
2489*a1157835SDaniel Fojt 	}
2490*a1157835SDaniel Fojt 
2491*a1157835SDaniel Fojt 	if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
2492*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2493*a1157835SDaniel Fojt 			   "FILS: Not a FILS AKM - reject association");
2494*a1157835SDaniel Fojt 		return -1;
2495*a1157835SDaniel Fojt 	}
2496*a1157835SDaniel Fojt 
2497*a1157835SDaniel Fojt 	end = ((const u8 *) mgmt) + frame_len;
2498*a1157835SDaniel Fojt 	fc = le_to_host16(mgmt->frame_control);
2499*a1157835SDaniel Fojt 	stype = WLAN_FC_GET_STYPE(fc);
2500*a1157835SDaniel Fojt 	if (stype == WLAN_FC_STYPE_REASSOC_REQ)
2501*a1157835SDaniel Fojt 		ie_start = mgmt->u.reassoc_req.variable;
2502*a1157835SDaniel Fojt 	else
2503*a1157835SDaniel Fojt 		ie_start = mgmt->u.assoc_req.variable;
2504*a1157835SDaniel Fojt 	ie = ie_start;
2505*a1157835SDaniel Fojt 
2506*a1157835SDaniel Fojt 	/*
2507*a1157835SDaniel Fojt 	 * Find FILS Session element which is the last unencrypted element in
2508*a1157835SDaniel Fojt 	 * the frame.
2509*a1157835SDaniel Fojt 	 */
2510*a1157835SDaniel Fojt 	session = wpa_fils_validate_fils_session(sm, ie, end - ie,
2511*a1157835SDaniel Fojt 						 fils_session);
2512*a1157835SDaniel Fojt 	if (!session) {
2513*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: Session validation failed");
2514*a1157835SDaniel Fojt 		return -1;
2515*a1157835SDaniel Fojt 	}
2516*a1157835SDaniel Fojt 
2517*a1157835SDaniel Fojt 	crypt = session + 2 + session[1];
2518*a1157835SDaniel Fojt 
2519*a1157835SDaniel Fojt 	if (end - crypt < AES_BLOCK_SIZE) {
2520*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2521*a1157835SDaniel Fojt 			   "FILS: Too short frame to include AES-SIV data");
2522*a1157835SDaniel Fojt 		return -1;
2523*a1157835SDaniel Fojt 	}
2524*a1157835SDaniel Fojt 
2525*a1157835SDaniel Fojt 	/* AES-SIV AAD vectors */
2526*a1157835SDaniel Fojt 
2527*a1157835SDaniel Fojt 	/* The STA's MAC address */
2528*a1157835SDaniel Fojt 	aad[0] = mgmt->sa;
2529*a1157835SDaniel Fojt 	aad_len[0] = ETH_ALEN;
2530*a1157835SDaniel Fojt 	/* The AP's BSSID */
2531*a1157835SDaniel Fojt 	aad[1] = mgmt->da;
2532*a1157835SDaniel Fojt 	aad_len[1] = ETH_ALEN;
2533*a1157835SDaniel Fojt 	/* The STA's nonce */
2534*a1157835SDaniel Fojt 	aad[2] = sm->SNonce;
2535*a1157835SDaniel Fojt 	aad_len[2] = FILS_NONCE_LEN;
2536*a1157835SDaniel Fojt 	/* The AP's nonce */
2537*a1157835SDaniel Fojt 	aad[3] = sm->ANonce;
2538*a1157835SDaniel Fojt 	aad_len[3] = FILS_NONCE_LEN;
2539*a1157835SDaniel Fojt 	/*
2540*a1157835SDaniel Fojt 	 * The (Re)Association Request frame from the Capability Information
2541*a1157835SDaniel Fojt 	 * field to the FILS Session element (both inclusive).
2542*a1157835SDaniel Fojt 	 */
2543*a1157835SDaniel Fojt 	aad[4] = (const u8 *) &mgmt->u.assoc_req.capab_info;
2544*a1157835SDaniel Fojt 	aad_len[4] = crypt - aad[4];
2545*a1157835SDaniel Fojt 
2546*a1157835SDaniel Fojt 	if (aes_siv_decrypt(sm->PTK.kek, sm->PTK.kek_len, crypt, end - crypt,
2547*a1157835SDaniel Fojt 			    5, aad, aad_len, pos + (crypt - ie_start)) < 0) {
2548*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2549*a1157835SDaniel Fojt 			   "FILS: Invalid AES-SIV data in the frame");
2550*a1157835SDaniel Fojt 		return -1;
2551*a1157835SDaniel Fojt 	}
2552*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FILS: Decrypted Association Request elements",
2553*a1157835SDaniel Fojt 		    pos, left - AES_BLOCK_SIZE);
2554*a1157835SDaniel Fojt 
2555*a1157835SDaniel Fojt 	if (wpa_fils_validate_key_confirm(sm, pos, left - AES_BLOCK_SIZE) < 0) {
2556*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: Key Confirm validation failed");
2557*a1157835SDaniel Fojt 		return -1;
2558*a1157835SDaniel Fojt 	}
2559*a1157835SDaniel Fojt 
2560*a1157835SDaniel Fojt 	return left - AES_BLOCK_SIZE;
2561*a1157835SDaniel Fojt }
2562*a1157835SDaniel Fojt 
2563*a1157835SDaniel Fojt 
fils_encrypt_assoc(struct wpa_state_machine * sm,u8 * buf,size_t current_len,size_t max_len,const struct wpabuf * hlp)2564*a1157835SDaniel Fojt int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
2565*a1157835SDaniel Fojt 		       size_t current_len, size_t max_len,
2566*a1157835SDaniel Fojt 		       const struct wpabuf *hlp)
2567*a1157835SDaniel Fojt {
2568*a1157835SDaniel Fojt 	u8 *end = buf + max_len;
2569*a1157835SDaniel Fojt 	u8 *pos = buf + current_len;
2570*a1157835SDaniel Fojt 	struct ieee80211_mgmt *mgmt;
2571*a1157835SDaniel Fojt 	struct wpabuf *plain;
2572*a1157835SDaniel Fojt 	const u8 *aad[5];
2573*a1157835SDaniel Fojt 	size_t aad_len[5];
2574*a1157835SDaniel Fojt 
2575*a1157835SDaniel Fojt 	if (!sm || !sm->PTK_valid)
2576*a1157835SDaniel Fojt 		return -1;
2577*a1157835SDaniel Fojt 
2578*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG,
2579*a1157835SDaniel Fojt 		    "FILS: Association Response frame before FILS processing",
2580*a1157835SDaniel Fojt 		    buf, current_len);
2581*a1157835SDaniel Fojt 
2582*a1157835SDaniel Fojt 	mgmt = (struct ieee80211_mgmt *) buf;
2583*a1157835SDaniel Fojt 
2584*a1157835SDaniel Fojt 	/* AES-SIV AAD vectors */
2585*a1157835SDaniel Fojt 
2586*a1157835SDaniel Fojt 	/* The AP's BSSID */
2587*a1157835SDaniel Fojt 	aad[0] = mgmt->sa;
2588*a1157835SDaniel Fojt 	aad_len[0] = ETH_ALEN;
2589*a1157835SDaniel Fojt 	/* The STA's MAC address */
2590*a1157835SDaniel Fojt 	aad[1] = mgmt->da;
2591*a1157835SDaniel Fojt 	aad_len[1] = ETH_ALEN;
2592*a1157835SDaniel Fojt 	/* The AP's nonce */
2593*a1157835SDaniel Fojt 	aad[2] = sm->ANonce;
2594*a1157835SDaniel Fojt 	aad_len[2] = FILS_NONCE_LEN;
2595*a1157835SDaniel Fojt 	/* The STA's nonce */
2596*a1157835SDaniel Fojt 	aad[3] = sm->SNonce;
2597*a1157835SDaniel Fojt 	aad_len[3] = FILS_NONCE_LEN;
2598*a1157835SDaniel Fojt 	/*
2599*a1157835SDaniel Fojt 	 * The (Re)Association Response frame from the Capability Information
2600*a1157835SDaniel Fojt 	 * field (the same offset in both Association and Reassociation
2601*a1157835SDaniel Fojt 	 * Response frames) to the FILS Session element (both inclusive).
2602*a1157835SDaniel Fojt 	 */
2603*a1157835SDaniel Fojt 	aad[4] = (const u8 *) &mgmt->u.assoc_resp.capab_info;
2604*a1157835SDaniel Fojt 	aad_len[4] = pos - aad[4];
2605*a1157835SDaniel Fojt 
2606*a1157835SDaniel Fojt 	/* The following elements will be encrypted with AES-SIV */
2607*a1157835SDaniel Fojt 	plain = fils_prepare_plainbuf(sm, hlp);
2608*a1157835SDaniel Fojt 	if (!plain) {
2609*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: Plain buffer prep failed");
2610*a1157835SDaniel Fojt 		return -1;
2611*a1157835SDaniel Fojt 	}
2612*a1157835SDaniel Fojt 
2613*a1157835SDaniel Fojt 	if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
2614*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2615*a1157835SDaniel Fojt 			   "FILS: Not enough room for FILS elements");
2616*a1157835SDaniel Fojt 		wpabuf_clear_free(plain);
2617*a1157835SDaniel Fojt 		return -1;
2618*a1157835SDaniel Fojt 	}
2619*a1157835SDaniel Fojt 
2620*a1157835SDaniel Fojt 	wpa_hexdump_buf_key(MSG_DEBUG, "FILS: Association Response plaintext",
2621*a1157835SDaniel Fojt 			    plain);
2622*a1157835SDaniel Fojt 
2623*a1157835SDaniel Fojt 	if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
2624*a1157835SDaniel Fojt 			    wpabuf_head(plain), wpabuf_len(plain),
2625*a1157835SDaniel Fojt 			    5, aad, aad_len, pos) < 0) {
2626*a1157835SDaniel Fojt 		wpabuf_clear_free(plain);
2627*a1157835SDaniel Fojt 		return -1;
2628*a1157835SDaniel Fojt 	}
2629*a1157835SDaniel Fojt 
2630*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG,
2631*a1157835SDaniel Fojt 		    "FILS: Encrypted Association Response elements",
2632*a1157835SDaniel Fojt 		    pos, AES_BLOCK_SIZE + wpabuf_len(plain));
2633*a1157835SDaniel Fojt 	current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
2634*a1157835SDaniel Fojt 	wpabuf_clear_free(plain);
2635*a1157835SDaniel Fojt 
2636*a1157835SDaniel Fojt 	sm->fils_completed = 1;
2637*a1157835SDaniel Fojt 
2638*a1157835SDaniel Fojt 	return current_len;
2639*a1157835SDaniel Fojt }
2640*a1157835SDaniel Fojt 
2641*a1157835SDaniel Fojt 
fils_prepare_plainbuf(struct wpa_state_machine * sm,const struct wpabuf * hlp)2642*a1157835SDaniel Fojt static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
2643*a1157835SDaniel Fojt 					     const struct wpabuf *hlp)
2644*a1157835SDaniel Fojt {
2645*a1157835SDaniel Fojt 	struct wpabuf *plain;
2646*a1157835SDaniel Fojt 	u8 *len, *tmp, *tmp2;
2647*a1157835SDaniel Fojt 	u8 hdr[2];
2648*a1157835SDaniel Fojt 	u8 *gtk, dummy_gtk[32];
2649*a1157835SDaniel Fojt 	size_t gtk_len;
2650*a1157835SDaniel Fojt 	struct wpa_group *gsm;
2651*a1157835SDaniel Fojt 
2652*a1157835SDaniel Fojt 	plain = wpabuf_alloc(1000);
2653*a1157835SDaniel Fojt 	if (!plain)
2654*a1157835SDaniel Fojt 		return NULL;
2655*a1157835SDaniel Fojt 
2656*a1157835SDaniel Fojt 	/* TODO: FILS Public Key */
2657*a1157835SDaniel Fojt 
2658*a1157835SDaniel Fojt 	/* FILS Key Confirmation */
2659*a1157835SDaniel Fojt 	wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
2660*a1157835SDaniel Fojt 	wpabuf_put_u8(plain, 1 + sm->fils_key_auth_len); /* Length */
2661*a1157835SDaniel Fojt 	/* Element ID Extension */
2662*a1157835SDaniel Fojt 	wpabuf_put_u8(plain, WLAN_EID_EXT_FILS_KEY_CONFIRM);
2663*a1157835SDaniel Fojt 	wpabuf_put_data(plain, sm->fils_key_auth_ap, sm->fils_key_auth_len);
2664*a1157835SDaniel Fojt 
2665*a1157835SDaniel Fojt 	/* FILS HLP Container */
2666*a1157835SDaniel Fojt 	if (hlp)
2667*a1157835SDaniel Fojt 		wpabuf_put_buf(plain, hlp);
2668*a1157835SDaniel Fojt 
2669*a1157835SDaniel Fojt 	/* TODO: FILS IP Address Assignment */
2670*a1157835SDaniel Fojt 
2671*a1157835SDaniel Fojt 	/* Key Delivery */
2672*a1157835SDaniel Fojt 	gsm = sm->group;
2673*a1157835SDaniel Fojt 	wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
2674*a1157835SDaniel Fojt 	len = wpabuf_put(plain, 1);
2675*a1157835SDaniel Fojt 	wpabuf_put_u8(plain, WLAN_EID_EXT_KEY_DELIVERY);
2676*a1157835SDaniel Fojt 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN,
2677*a1157835SDaniel Fojt 			    wpabuf_put(plain, WPA_KEY_RSC_LEN));
2678*a1157835SDaniel Fojt 	/* GTK KDE */
2679*a1157835SDaniel Fojt 	gtk = gsm->GTK[gsm->GN - 1];
2680*a1157835SDaniel Fojt 	gtk_len = gsm->GTK_len;
2681*a1157835SDaniel Fojt 	if (sm->wpa_auth->conf.disable_gtk ||
2682*a1157835SDaniel Fojt 	    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
2683*a1157835SDaniel Fojt 		/*
2684*a1157835SDaniel Fojt 		 * Provide unique random GTK to each STA to prevent use
2685*a1157835SDaniel Fojt 		 * of GTK in the BSS.
2686*a1157835SDaniel Fojt 		 */
2687*a1157835SDaniel Fojt 		if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
2688*a1157835SDaniel Fojt 			wpabuf_clear_free(plain);
2689*a1157835SDaniel Fojt 			return NULL;
2690*a1157835SDaniel Fojt 		}
2691*a1157835SDaniel Fojt 		gtk = dummy_gtk;
2692*a1157835SDaniel Fojt 	}
2693*a1157835SDaniel Fojt 	hdr[0] = gsm->GN & 0x03;
2694*a1157835SDaniel Fojt 	hdr[1] = 0;
2695*a1157835SDaniel Fojt 	tmp = wpabuf_put(plain, 0);
2696*a1157835SDaniel Fojt 	tmp2 = wpa_add_kde(tmp, RSN_KEY_DATA_GROUPKEY, hdr, 2,
2697*a1157835SDaniel Fojt 			   gtk, gtk_len);
2698*a1157835SDaniel Fojt 	wpabuf_put(plain, tmp2 - tmp);
2699*a1157835SDaniel Fojt 
2700*a1157835SDaniel Fojt 	/* IGTK KDE */
2701*a1157835SDaniel Fojt 	tmp = wpabuf_put(plain, 0);
2702*a1157835SDaniel Fojt 	tmp2 = ieee80211w_kde_add(sm, tmp);
2703*a1157835SDaniel Fojt 	wpabuf_put(plain, tmp2 - tmp);
2704*a1157835SDaniel Fojt 
2705*a1157835SDaniel Fojt 	*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
2706*a1157835SDaniel Fojt 
2707*a1157835SDaniel Fojt #ifdef CONFIG_OCV
2708*a1157835SDaniel Fojt 	if (wpa_auth_uses_ocv(sm)) {
2709*a1157835SDaniel Fojt 		struct wpa_channel_info ci;
2710*a1157835SDaniel Fojt 		u8 *pos;
2711*a1157835SDaniel Fojt 
2712*a1157835SDaniel Fojt 		if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
2713*a1157835SDaniel Fojt 			wpa_printf(MSG_WARNING,
2714*a1157835SDaniel Fojt 				   "FILS: Failed to get channel info for OCI element");
2715*a1157835SDaniel Fojt 			wpabuf_clear_free(plain);
2716*a1157835SDaniel Fojt 			return NULL;
2717*a1157835SDaniel Fojt 		}
2718*a1157835SDaniel Fojt 
2719*a1157835SDaniel Fojt 		pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
2720*a1157835SDaniel Fojt 		if (ocv_insert_extended_oci(&ci, pos) < 0) {
2721*a1157835SDaniel Fojt 			wpabuf_clear_free(plain);
2722*a1157835SDaniel Fojt 			return NULL;
2723*a1157835SDaniel Fojt 		}
2724*a1157835SDaniel Fojt 	}
2725*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
2726*a1157835SDaniel Fojt 
2727*a1157835SDaniel Fojt 	return plain;
2728*a1157835SDaniel Fojt }
2729*a1157835SDaniel Fojt 
2730*a1157835SDaniel Fojt 
fils_set_tk(struct wpa_state_machine * sm)2731*a1157835SDaniel Fojt int fils_set_tk(struct wpa_state_machine *sm)
2732*a1157835SDaniel Fojt {
2733*a1157835SDaniel Fojt 	enum wpa_alg alg;
2734*a1157835SDaniel Fojt 	int klen;
2735*a1157835SDaniel Fojt 
2736*a1157835SDaniel Fojt 	if (!sm || !sm->PTK_valid) {
2737*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: No valid PTK available to set TK");
2738*a1157835SDaniel Fojt 		return -1;
2739*a1157835SDaniel Fojt 	}
2740*a1157835SDaniel Fojt 	if (sm->tk_already_set) {
2741*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: TK already set to the driver");
2742*a1157835SDaniel Fojt 		return -1;
2743*a1157835SDaniel Fojt 	}
2744*a1157835SDaniel Fojt 
2745*a1157835SDaniel Fojt 	alg = wpa_cipher_to_alg(sm->pairwise);
2746*a1157835SDaniel Fojt 	klen = wpa_cipher_key_len(sm->pairwise);
2747*a1157835SDaniel Fojt 
2748*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
2749*a1157835SDaniel Fojt 	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
2750*a1157835SDaniel Fojt 			     sm->PTK.tk, klen)) {
2751*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
2752*a1157835SDaniel Fojt 		return -1;
2753*a1157835SDaniel Fojt 	}
2754*a1157835SDaniel Fojt 	sm->tk_already_set = TRUE;
2755*a1157835SDaniel Fojt 
2756*a1157835SDaniel Fojt 	return 0;
2757*a1157835SDaniel Fojt }
2758*a1157835SDaniel Fojt 
2759*a1157835SDaniel Fojt 
hostapd_eid_assoc_fils_session(struct wpa_state_machine * sm,u8 * buf,const u8 * fils_session,struct wpabuf * hlp)2760*a1157835SDaniel Fojt u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
2761*a1157835SDaniel Fojt 				    const u8 *fils_session, struct wpabuf *hlp)
2762*a1157835SDaniel Fojt {
2763*a1157835SDaniel Fojt 	struct wpabuf *plain;
2764*a1157835SDaniel Fojt 	u8 *pos = buf;
2765*a1157835SDaniel Fojt 
2766*a1157835SDaniel Fojt 	/* FILS Session */
2767*a1157835SDaniel Fojt 	*pos++ = WLAN_EID_EXTENSION; /* Element ID */
2768*a1157835SDaniel Fojt 	*pos++ = 1 + FILS_SESSION_LEN; /* Length */
2769*a1157835SDaniel Fojt 	*pos++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
2770*a1157835SDaniel Fojt 	os_memcpy(pos, fils_session, FILS_SESSION_LEN);
2771*a1157835SDaniel Fojt 	pos += FILS_SESSION_LEN;
2772*a1157835SDaniel Fojt 
2773*a1157835SDaniel Fojt 	plain = fils_prepare_plainbuf(sm, hlp);
2774*a1157835SDaniel Fojt 	if (!plain) {
2775*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FILS: Plain buffer prep failed");
2776*a1157835SDaniel Fojt 		return NULL;
2777*a1157835SDaniel Fojt 	}
2778*a1157835SDaniel Fojt 
2779*a1157835SDaniel Fojt 	os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
2780*a1157835SDaniel Fojt 	pos += wpabuf_len(plain);
2781*a1157835SDaniel Fojt 
2782*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
2783*a1157835SDaniel Fojt 		   (unsigned int) wpabuf_len(plain));
2784*a1157835SDaniel Fojt 	wpabuf_clear_free(plain);
2785*a1157835SDaniel Fojt 	sm->fils_completed = 1;
2786*a1157835SDaniel Fojt 	return pos;
2787*a1157835SDaniel Fojt }
2788*a1157835SDaniel Fojt 
2789*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2790*a1157835SDaniel Fojt 
2791*a1157835SDaniel Fojt 
2792*a1157835SDaniel Fojt #ifdef CONFIG_OCV
get_sta_tx_parameters(struct wpa_state_machine * sm,int ap_max_chanwidth,int ap_seg1_idx,int * bandwidth,int * seg1_idx)2793*a1157835SDaniel Fojt int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
2794*a1157835SDaniel Fojt 			  int ap_seg1_idx, int *bandwidth, int *seg1_idx)
2795*a1157835SDaniel Fojt {
2796*a1157835SDaniel Fojt 	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
2797*a1157835SDaniel Fojt 
2798*a1157835SDaniel Fojt 	if (!wpa_auth->cb->get_sta_tx_params)
2799*a1157835SDaniel Fojt 		return -1;
2800*a1157835SDaniel Fojt 	return wpa_auth->cb->get_sta_tx_params(wpa_auth->cb_ctx, sm->addr,
2801*a1157835SDaniel Fojt 					       ap_max_chanwidth, ap_seg1_idx,
2802*a1157835SDaniel Fojt 					       bandwidth, seg1_idx);
2803*a1157835SDaniel Fojt }
2804*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
2805*a1157835SDaniel Fojt 
2806*a1157835SDaniel Fojt 
SM_STATE(WPA_PTK,PTKCALCNEGOTIATING)28073ff40c12SJohn Marino SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
28083ff40c12SJohn Marino {
2809*a1157835SDaniel Fojt 	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
28103ff40c12SJohn Marino 	struct wpa_ptk PTK;
2811*a1157835SDaniel Fojt 	int ok = 0, psk_found = 0;
28123ff40c12SJohn Marino 	const u8 *pmk = NULL;
2813*a1157835SDaniel Fojt 	size_t pmk_len;
2814*a1157835SDaniel Fojt 	int ft;
2815*a1157835SDaniel Fojt 	const u8 *eapol_key_ie, *key_data, *mic;
2816*a1157835SDaniel Fojt 	u16 key_data_length;
2817*a1157835SDaniel Fojt 	size_t mic_len, eapol_key_ie_len;
2818*a1157835SDaniel Fojt 	struct ieee802_1x_hdr *hdr;
2819*a1157835SDaniel Fojt 	struct wpa_eapol_key *key;
2820*a1157835SDaniel Fojt 	struct wpa_eapol_ie_parse kde;
2821*a1157835SDaniel Fojt 	int vlan_id = 0;
28223ff40c12SJohn Marino 
28233ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
28243ff40c12SJohn Marino 	sm->EAPOLKeyReceived = FALSE;
28253ff40c12SJohn Marino 	sm->update_snonce = FALSE;
2826*a1157835SDaniel Fojt 	os_memset(&PTK, 0, sizeof(PTK));
2827*a1157835SDaniel Fojt 
2828*a1157835SDaniel Fojt 	mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
28293ff40c12SJohn Marino 
28303ff40c12SJohn Marino 	/* WPA with IEEE 802.1X: use the derived PMK from EAP
28313ff40c12SJohn Marino 	 * WPA-PSK: iterate through possible PSKs and select the one matching
28323ff40c12SJohn Marino 	 * the packet */
28333ff40c12SJohn Marino 	for (;;) {
2834*a1157835SDaniel Fojt 		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
2835*a1157835SDaniel Fojt 		    !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
28363ff40c12SJohn Marino 			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
2837*a1157835SDaniel Fojt 					       sm->p2p_dev_addr, pmk, &pmk_len,
2838*a1157835SDaniel Fojt 					       &vlan_id);
28393ff40c12SJohn Marino 			if (pmk == NULL)
28403ff40c12SJohn Marino 				break;
2841*a1157835SDaniel Fojt 			psk_found = 1;
2842*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
2843*a1157835SDaniel Fojt 			if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
2844*a1157835SDaniel Fojt 				os_memcpy(sm->xxkey, pmk, pmk_len);
2845*a1157835SDaniel Fojt 				sm->xxkey_len = pmk_len;
2846*a1157835SDaniel Fojt 			}
2847*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
2848*a1157835SDaniel Fojt 		} else {
28493ff40c12SJohn Marino 			pmk = sm->PMK;
2850*a1157835SDaniel Fojt 			pmk_len = sm->pmk_len;
2851*a1157835SDaniel Fojt 		}
28523ff40c12SJohn Marino 
2853*a1157835SDaniel Fojt 		if ((!pmk || !pmk_len) && sm->pmksa) {
2854*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache");
2855*a1157835SDaniel Fojt 			pmk = sm->pmksa->pmk;
2856*a1157835SDaniel Fojt 			pmk_len = sm->pmksa->pmk_len;
2857*a1157835SDaniel Fojt 		}
28583ff40c12SJohn Marino 
2859*a1157835SDaniel Fojt 		if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
2860*a1157835SDaniel Fojt 			break;
2861*a1157835SDaniel Fojt 
2862*a1157835SDaniel Fojt 		if (mic_len &&
2863*a1157835SDaniel Fojt 		    wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
2864*a1157835SDaniel Fojt 				       sm->last_rx_eapol_key,
28653ff40c12SJohn Marino 				       sm->last_rx_eapol_key_len) == 0) {
2866*a1157835SDaniel Fojt 			if (sm->PMK != pmk) {
2867*a1157835SDaniel Fojt 				os_memcpy(sm->PMK, pmk, pmk_len);
2868*a1157835SDaniel Fojt 				sm->pmk_len = pmk_len;
2869*a1157835SDaniel Fojt 			}
28703ff40c12SJohn Marino 			ok = 1;
28713ff40c12SJohn Marino 			break;
28723ff40c12SJohn Marino 		}
28733ff40c12SJohn Marino 
2874*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2875*a1157835SDaniel Fojt 		if (!mic_len &&
2876*a1157835SDaniel Fojt 		    wpa_aead_decrypt(sm, &PTK, sm->last_rx_eapol_key,
2877*a1157835SDaniel Fojt 				     sm->last_rx_eapol_key_len, NULL) == 0) {
2878*a1157835SDaniel Fojt 			ok = 1;
2879*a1157835SDaniel Fojt 			break;
2880*a1157835SDaniel Fojt 		}
2881*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2882*a1157835SDaniel Fojt 
2883*a1157835SDaniel Fojt 		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
2884*a1157835SDaniel Fojt 		    wpa_key_mgmt_sae(sm->wpa_key_mgmt))
28853ff40c12SJohn Marino 			break;
28863ff40c12SJohn Marino 	}
28873ff40c12SJohn Marino 
28883ff40c12SJohn Marino 	if (!ok) {
28893ff40c12SJohn Marino 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
28903ff40c12SJohn Marino 				"invalid MIC in msg 2/4 of 4-Way Handshake");
2891*a1157835SDaniel Fojt 		if (psk_found)
2892*a1157835SDaniel Fojt 			wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
28933ff40c12SJohn Marino 		return;
28943ff40c12SJohn Marino 	}
28953ff40c12SJohn Marino 
2896*a1157835SDaniel Fojt 	/*
2897*a1157835SDaniel Fojt 	 * Note: last_rx_eapol_key length fields have already been validated in
2898*a1157835SDaniel Fojt 	 * wpa_receive().
2899*a1157835SDaniel Fojt 	 */
2900*a1157835SDaniel Fojt 	hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
2901*a1157835SDaniel Fojt 	key = (struct wpa_eapol_key *) (hdr + 1);
2902*a1157835SDaniel Fojt 	mic = (u8 *) (key + 1);
2903*a1157835SDaniel Fojt 	key_data = mic + mic_len + 2;
2904*a1157835SDaniel Fojt 	key_data_length = WPA_GET_BE16(mic + mic_len);
2905*a1157835SDaniel Fojt 	if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
2906*a1157835SDaniel Fojt 	    sizeof(*key) - mic_len - 2)
2907*a1157835SDaniel Fojt 		return;
2908*a1157835SDaniel Fojt 
2909*a1157835SDaniel Fojt 	if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
2910*a1157835SDaniel Fojt 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
2911*a1157835SDaniel Fojt 				 "received EAPOL-Key msg 2/4 with invalid Key Data contents");
2912*a1157835SDaniel Fojt 		return;
2913*a1157835SDaniel Fojt 	}
2914*a1157835SDaniel Fojt 	if (kde.rsn_ie) {
2915*a1157835SDaniel Fojt 		eapol_key_ie = kde.rsn_ie;
2916*a1157835SDaniel Fojt 		eapol_key_ie_len = kde.rsn_ie_len;
2917*a1157835SDaniel Fojt 	} else if (kde.osen) {
2918*a1157835SDaniel Fojt 		eapol_key_ie = kde.osen;
2919*a1157835SDaniel Fojt 		eapol_key_ie_len = kde.osen_len;
2920*a1157835SDaniel Fojt 	} else {
2921*a1157835SDaniel Fojt 		eapol_key_ie = kde.wpa_ie;
2922*a1157835SDaniel Fojt 		eapol_key_ie_len = kde.wpa_ie_len;
2923*a1157835SDaniel Fojt 	}
2924*a1157835SDaniel Fojt 	ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
2925*a1157835SDaniel Fojt 	if (sm->wpa_ie == NULL ||
2926*a1157835SDaniel Fojt 	    wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
2927*a1157835SDaniel Fojt 			       eapol_key_ie, eapol_key_ie_len)) {
2928*a1157835SDaniel Fojt 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
2929*a1157835SDaniel Fojt 				"WPA IE from (Re)AssocReq did not match with msg 2/4");
2930*a1157835SDaniel Fojt 		if (sm->wpa_ie) {
2931*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
2932*a1157835SDaniel Fojt 				    sm->wpa_ie, sm->wpa_ie_len);
2933*a1157835SDaniel Fojt 		}
2934*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
2935*a1157835SDaniel Fojt 			    eapol_key_ie, eapol_key_ie_len);
2936*a1157835SDaniel Fojt 		/* MLME-DEAUTHENTICATE.request */
2937*a1157835SDaniel Fojt 		wpa_sta_disconnect(wpa_auth, sm->addr,
2938*a1157835SDaniel Fojt 				   WLAN_REASON_PREV_AUTH_NOT_VALID);
2939*a1157835SDaniel Fojt 		return;
2940*a1157835SDaniel Fojt 	}
2941*a1157835SDaniel Fojt #ifdef CONFIG_OCV
2942*a1157835SDaniel Fojt 	if (wpa_auth_uses_ocv(sm)) {
2943*a1157835SDaniel Fojt 		struct wpa_channel_info ci;
2944*a1157835SDaniel Fojt 		int tx_chanwidth;
2945*a1157835SDaniel Fojt 		int tx_seg1_idx;
2946*a1157835SDaniel Fojt 
2947*a1157835SDaniel Fojt 		if (wpa_channel_info(wpa_auth, &ci) != 0) {
2948*a1157835SDaniel Fojt 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
2949*a1157835SDaniel Fojt 					"Failed to get channel info to validate received OCI in EAPOL-Key 2/4");
2950*a1157835SDaniel Fojt 			return;
2951*a1157835SDaniel Fojt 		}
2952*a1157835SDaniel Fojt 
2953*a1157835SDaniel Fojt 		if (get_sta_tx_parameters(sm,
2954*a1157835SDaniel Fojt 					  channel_width_to_int(ci.chanwidth),
2955*a1157835SDaniel Fojt 					  ci.seg1_idx, &tx_chanwidth,
2956*a1157835SDaniel Fojt 					  &tx_seg1_idx) < 0)
2957*a1157835SDaniel Fojt 			return;
2958*a1157835SDaniel Fojt 
2959*a1157835SDaniel Fojt 		if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
2960*a1157835SDaniel Fojt 					 tx_chanwidth, tx_seg1_idx) != 0) {
2961*a1157835SDaniel Fojt 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
2962*a1157835SDaniel Fojt 					ocv_errorstr);
2963*a1157835SDaniel Fojt 			return;
2964*a1157835SDaniel Fojt 		}
2965*a1157835SDaniel Fojt 	}
2966*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
2967*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
2968*a1157835SDaniel Fojt 	if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
2969*a1157835SDaniel Fojt 		wpa_sta_disconnect(wpa_auth, sm->addr,
2970*a1157835SDaniel Fojt 				   WLAN_REASON_PREV_AUTH_NOT_VALID);
2971*a1157835SDaniel Fojt 		return;
2972*a1157835SDaniel Fojt 	}
2973*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
2974*a1157835SDaniel Fojt #ifdef CONFIG_P2P
2975*a1157835SDaniel Fojt 	if (kde.ip_addr_req && kde.ip_addr_req[0] &&
2976*a1157835SDaniel Fojt 	    wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
2977*a1157835SDaniel Fojt 		int idx;
2978*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2979*a1157835SDaniel Fojt 			   "P2P: IP address requested in EAPOL-Key exchange");
2980*a1157835SDaniel Fojt 		idx = bitfield_get_first_zero(wpa_auth->ip_pool);
2981*a1157835SDaniel Fojt 		if (idx >= 0) {
2982*a1157835SDaniel Fojt 			u32 start = WPA_GET_BE32(wpa_auth->conf.ip_addr_start);
2983*a1157835SDaniel Fojt 			bitfield_set(wpa_auth->ip_pool, idx);
2984*a1157835SDaniel Fojt 			WPA_PUT_BE32(sm->ip_addr, start + idx);
2985*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2986*a1157835SDaniel Fojt 				   "P2P: Assigned IP address %u.%u.%u.%u to "
2987*a1157835SDaniel Fojt 				   MACSTR, sm->ip_addr[0], sm->ip_addr[1],
2988*a1157835SDaniel Fojt 				   sm->ip_addr[2], sm->ip_addr[3],
2989*a1157835SDaniel Fojt 				   MAC2STR(sm->addr));
2990*a1157835SDaniel Fojt 		}
2991*a1157835SDaniel Fojt 	}
2992*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
2993*a1157835SDaniel Fojt 
2994*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
29953ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
29963ff40c12SJohn Marino 		/*
29973ff40c12SJohn Marino 		 * Verify that PMKR1Name from EAPOL-Key message 2/4 matches
29983ff40c12SJohn Marino 		 * with the value we derived.
29993ff40c12SJohn Marino 		 */
3000*a1157835SDaniel Fojt 		if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
30013ff40c12SJohn Marino 				    WPA_PMK_NAME_LEN) != 0) {
30023ff40c12SJohn Marino 			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
30033ff40c12SJohn Marino 					"PMKR1Name mismatch in FT 4-way "
30043ff40c12SJohn Marino 					"handshake");
30053ff40c12SJohn Marino 			wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
30063ff40c12SJohn Marino 				    "Supplicant",
30073ff40c12SJohn Marino 				    sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
30083ff40c12SJohn Marino 			wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
30093ff40c12SJohn Marino 				    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
30103ff40c12SJohn Marino 			return;
30113ff40c12SJohn Marino 		}
30123ff40c12SJohn Marino 	}
3013*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
3014*a1157835SDaniel Fojt 
3015*a1157835SDaniel Fojt 	if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
3016*a1157835SDaniel Fojt 	    wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
3017*a1157835SDaniel Fojt 		wpa_sta_disconnect(wpa_auth, sm->addr,
3018*a1157835SDaniel Fojt 				   WLAN_REASON_PREV_AUTH_NOT_VALID);
3019*a1157835SDaniel Fojt 		return;
3020*a1157835SDaniel Fojt 	}
30213ff40c12SJohn Marino 
30223ff40c12SJohn Marino 	sm->pending_1_of_4_timeout = 0;
30233ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
30243ff40c12SJohn Marino 
30253ff40c12SJohn Marino 	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
30263ff40c12SJohn Marino 		/* PSK may have changed from the previous choice, so update
30273ff40c12SJohn Marino 		 * state machine data based on whatever PSK was selected here.
30283ff40c12SJohn Marino 		 */
30293ff40c12SJohn Marino 		os_memcpy(sm->PMK, pmk, PMK_LEN);
3030*a1157835SDaniel Fojt 		sm->pmk_len = PMK_LEN;
30313ff40c12SJohn Marino 	}
30323ff40c12SJohn Marino 
30333ff40c12SJohn Marino 	sm->MICVerified = TRUE;
30343ff40c12SJohn Marino 
30353ff40c12SJohn Marino 	os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
3036*a1157835SDaniel Fojt 	forced_memzero(&PTK, sizeof(PTK));
30373ff40c12SJohn Marino 	sm->PTK_valid = TRUE;
30383ff40c12SJohn Marino }
30393ff40c12SJohn Marino 
30403ff40c12SJohn Marino 
SM_STATE(WPA_PTK,PTKCALCNEGOTIATING2)30413ff40c12SJohn Marino SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
30423ff40c12SJohn Marino {
30433ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk);
30443ff40c12SJohn Marino 	sm->TimeoutCtr = 0;
30453ff40c12SJohn Marino }
30463ff40c12SJohn Marino 
30473ff40c12SJohn Marino 
30483ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
30493ff40c12SJohn Marino 
ieee80211w_kde_len(struct wpa_state_machine * sm)30503ff40c12SJohn Marino static int ieee80211w_kde_len(struct wpa_state_machine *sm)
30513ff40c12SJohn Marino {
30523ff40c12SJohn Marino 	if (sm->mgmt_frame_prot) {
3053*a1157835SDaniel Fojt 		size_t len;
3054*a1157835SDaniel Fojt 		len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
3055*a1157835SDaniel Fojt 		return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
30563ff40c12SJohn Marino 	}
30573ff40c12SJohn Marino 
30583ff40c12SJohn Marino 	return 0;
30593ff40c12SJohn Marino }
30603ff40c12SJohn Marino 
30613ff40c12SJohn Marino 
ieee80211w_kde_add(struct wpa_state_machine * sm,u8 * pos)30623ff40c12SJohn Marino static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
30633ff40c12SJohn Marino {
30643ff40c12SJohn Marino 	struct wpa_igtk_kde igtk;
30653ff40c12SJohn Marino 	struct wpa_group *gsm = sm->group;
30663ff40c12SJohn Marino 	u8 rsc[WPA_KEY_RSC_LEN];
3067*a1157835SDaniel Fojt 	size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
30683ff40c12SJohn Marino 
30693ff40c12SJohn Marino 	if (!sm->mgmt_frame_prot)
30703ff40c12SJohn Marino 		return pos;
30713ff40c12SJohn Marino 
30723ff40c12SJohn Marino 	igtk.keyid[0] = gsm->GN_igtk;
30733ff40c12SJohn Marino 	igtk.keyid[1] = 0;
30743ff40c12SJohn Marino 	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
30753ff40c12SJohn Marino 	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0)
30763ff40c12SJohn Marino 		os_memset(igtk.pn, 0, sizeof(igtk.pn));
30773ff40c12SJohn Marino 	else
30783ff40c12SJohn Marino 		os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
3079*a1157835SDaniel Fojt 	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
3080*a1157835SDaniel Fojt 	if (sm->wpa_auth->conf.disable_gtk ||
3081*a1157835SDaniel Fojt 	    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
30823ff40c12SJohn Marino 		/*
30833ff40c12SJohn Marino 		 * Provide unique random IGTK to each STA to prevent use of
30843ff40c12SJohn Marino 		 * IGTK in the BSS.
30853ff40c12SJohn Marino 		 */
3086*a1157835SDaniel Fojt 		if (random_get_bytes(igtk.igtk, len) < 0)
30873ff40c12SJohn Marino 			return pos;
30883ff40c12SJohn Marino 	}
30893ff40c12SJohn Marino 	pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
3090*a1157835SDaniel Fojt 			  (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
3091*a1157835SDaniel Fojt 			  NULL, 0);
30923ff40c12SJohn Marino 
30933ff40c12SJohn Marino 	return pos;
30943ff40c12SJohn Marino }
30953ff40c12SJohn Marino 
30963ff40c12SJohn Marino #else /* CONFIG_IEEE80211W */
30973ff40c12SJohn Marino 
ieee80211w_kde_len(struct wpa_state_machine * sm)30983ff40c12SJohn Marino static int ieee80211w_kde_len(struct wpa_state_machine *sm)
30993ff40c12SJohn Marino {
31003ff40c12SJohn Marino 	return 0;
31013ff40c12SJohn Marino }
31023ff40c12SJohn Marino 
31033ff40c12SJohn Marino 
ieee80211w_kde_add(struct wpa_state_machine * sm,u8 * pos)31043ff40c12SJohn Marino static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
31053ff40c12SJohn Marino {
31063ff40c12SJohn Marino 	return pos;
31073ff40c12SJohn Marino }
31083ff40c12SJohn Marino 
31093ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
31103ff40c12SJohn Marino 
31113ff40c12SJohn Marino 
ocv_oci_len(struct wpa_state_machine * sm)3112*a1157835SDaniel Fojt static int ocv_oci_len(struct wpa_state_machine *sm)
3113*a1157835SDaniel Fojt {
3114*a1157835SDaniel Fojt #ifdef CONFIG_OCV
3115*a1157835SDaniel Fojt 	if (wpa_auth_uses_ocv(sm))
3116*a1157835SDaniel Fojt 		return OCV_OCI_KDE_LEN;
3117*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
3118*a1157835SDaniel Fojt 	return 0;
3119*a1157835SDaniel Fojt }
3120*a1157835SDaniel Fojt 
ocv_oci_add(struct wpa_state_machine * sm,u8 ** argpos)3121*a1157835SDaniel Fojt static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
3122*a1157835SDaniel Fojt {
3123*a1157835SDaniel Fojt #ifdef CONFIG_OCV
3124*a1157835SDaniel Fojt 	struct wpa_channel_info ci;
3125*a1157835SDaniel Fojt 
3126*a1157835SDaniel Fojt 	if (!wpa_auth_uses_ocv(sm))
3127*a1157835SDaniel Fojt 		return 0;
3128*a1157835SDaniel Fojt 
3129*a1157835SDaniel Fojt 	if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
3130*a1157835SDaniel Fojt 		wpa_printf(MSG_WARNING,
3131*a1157835SDaniel Fojt 			   "Failed to get channel info for OCI element");
3132*a1157835SDaniel Fojt 		return -1;
3133*a1157835SDaniel Fojt 	}
3134*a1157835SDaniel Fojt 
3135*a1157835SDaniel Fojt 	return ocv_insert_oci_kde(&ci, argpos);
3136*a1157835SDaniel Fojt #else /* CONFIG_OCV */
3137*a1157835SDaniel Fojt 	return 0;
3138*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
3139*a1157835SDaniel Fojt }
3140*a1157835SDaniel Fojt 
3141*a1157835SDaniel Fojt 
SM_STATE(WPA_PTK,PTKINITNEGOTIATING)31423ff40c12SJohn Marino SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
31433ff40c12SJohn Marino {
31443ff40c12SJohn Marino 	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
31453ff40c12SJohn Marino 	size_t gtk_len, kde_len;
31463ff40c12SJohn Marino 	struct wpa_group *gsm = sm->group;
31473ff40c12SJohn Marino 	u8 *wpa_ie;
31483ff40c12SJohn Marino 	int wpa_ie_len, secure, keyidx, encr = 0;
31493ff40c12SJohn Marino 
31503ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
31513ff40c12SJohn Marino 	sm->TimeoutEvt = FALSE;
31523ff40c12SJohn Marino 
31533ff40c12SJohn Marino 	sm->TimeoutCtr++;
3154*a1157835SDaniel Fojt 	if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
3155*a1157835SDaniel Fojt 	    sm->TimeoutCtr > 1) {
3156*a1157835SDaniel Fojt 		/* Do not allow retransmission of EAPOL-Key msg 3/4 */
3157*a1157835SDaniel Fojt 		return;
3158*a1157835SDaniel Fojt 	}
3159*a1157835SDaniel Fojt 	if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
31603ff40c12SJohn Marino 		/* No point in sending the EAPOL-Key - we will disconnect
31613ff40c12SJohn Marino 		 * immediately following this. */
31623ff40c12SJohn Marino 		return;
31633ff40c12SJohn Marino 	}
31643ff40c12SJohn Marino 
31653ff40c12SJohn Marino 	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
31663ff40c12SJohn Marino 	   GTK[GN], IGTK, [FTIE], [TIE * 2])
31673ff40c12SJohn Marino 	 */
31683ff40c12SJohn Marino 	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
31693ff40c12SJohn Marino 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
31703ff40c12SJohn Marino 	/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
31713ff40c12SJohn Marino 	wpa_ie = sm->wpa_auth->wpa_ie;
31723ff40c12SJohn Marino 	wpa_ie_len = sm->wpa_auth->wpa_ie_len;
31733ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA &&
31743ff40c12SJohn Marino 	    (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
31753ff40c12SJohn Marino 	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
3176*a1157835SDaniel Fojt 		/* WPA-only STA, remove RSN IE and possible MDIE */
3177*a1157835SDaniel Fojt 		wpa_ie = wpa_ie + wpa_ie[1] + 2;
3178*a1157835SDaniel Fojt 		if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
31793ff40c12SJohn Marino 			wpa_ie = wpa_ie + wpa_ie[1] + 2;
31803ff40c12SJohn Marino 		wpa_ie_len = wpa_ie[1] + 2;
31813ff40c12SJohn Marino 	}
31823ff40c12SJohn Marino 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
31833ff40c12SJohn Marino 			"sending 3/4 msg of 4-Way Handshake");
31843ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA2) {
31853ff40c12SJohn Marino 		/* WPA2 send GTK in the 4-way handshake */
31863ff40c12SJohn Marino 		secure = 1;
31873ff40c12SJohn Marino 		gtk = gsm->GTK[gsm->GN - 1];
31883ff40c12SJohn Marino 		gtk_len = gsm->GTK_len;
3189*a1157835SDaniel Fojt 		if (sm->wpa_auth->conf.disable_gtk ||
3190*a1157835SDaniel Fojt 		    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
31913ff40c12SJohn Marino 			/*
31923ff40c12SJohn Marino 			 * Provide unique random GTK to each STA to prevent use
31933ff40c12SJohn Marino 			 * of GTK in the BSS.
31943ff40c12SJohn Marino 			 */
31953ff40c12SJohn Marino 			if (random_get_bytes(dummy_gtk, gtk_len) < 0)
31963ff40c12SJohn Marino 				return;
31973ff40c12SJohn Marino 			gtk = dummy_gtk;
31983ff40c12SJohn Marino 		}
31993ff40c12SJohn Marino 		keyidx = gsm->GN;
32003ff40c12SJohn Marino 		_rsc = rsc;
32013ff40c12SJohn Marino 		encr = 1;
32023ff40c12SJohn Marino 	} else {
32033ff40c12SJohn Marino 		/* WPA does not include GTK in msg 3/4 */
32043ff40c12SJohn Marino 		secure = 0;
32053ff40c12SJohn Marino 		gtk = NULL;
32063ff40c12SJohn Marino 		gtk_len = 0;
32073ff40c12SJohn Marino 		keyidx = 0;
32083ff40c12SJohn Marino 		_rsc = NULL;
32093ff40c12SJohn Marino 		if (sm->rx_eapol_key_secure) {
32103ff40c12SJohn Marino 			/*
32113ff40c12SJohn Marino 			 * It looks like Windows 7 supplicant tries to use
32123ff40c12SJohn Marino 			 * Secure bit in msg 2/4 after having reported Michael
32133ff40c12SJohn Marino 			 * MIC failure and it then rejects the 4-way handshake
32143ff40c12SJohn Marino 			 * if msg 3/4 does not set Secure bit. Work around this
32153ff40c12SJohn Marino 			 * by setting the Secure bit here even in the case of
32163ff40c12SJohn Marino 			 * WPA if the supplicant used it first.
32173ff40c12SJohn Marino 			 */
32183ff40c12SJohn Marino 			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
32193ff40c12SJohn Marino 					"STA used Secure bit in WPA msg 2/4 - "
32203ff40c12SJohn Marino 					"set Secure for 3/4 as workaround");
32213ff40c12SJohn Marino 			secure = 1;
32223ff40c12SJohn Marino 		}
32233ff40c12SJohn Marino 	}
32243ff40c12SJohn Marino 
3225*a1157835SDaniel Fojt 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
32263ff40c12SJohn Marino 	if (gtk)
32273ff40c12SJohn Marino 		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
3228*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
32293ff40c12SJohn Marino 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
32303ff40c12SJohn Marino 		kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
32313ff40c12SJohn Marino 		kde_len += 300; /* FTIE + 2 * TIE */
32323ff40c12SJohn Marino 	}
3233*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
32343ff40c12SJohn Marino #ifdef CONFIG_P2P
32353ff40c12SJohn Marino 	if (WPA_GET_BE32(sm->ip_addr) > 0)
32363ff40c12SJohn Marino 		kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
32373ff40c12SJohn Marino #endif /* CONFIG_P2P */
32383ff40c12SJohn Marino 	kde = os_malloc(kde_len);
32393ff40c12SJohn Marino 	if (kde == NULL)
32403ff40c12SJohn Marino 		return;
32413ff40c12SJohn Marino 
32423ff40c12SJohn Marino 	pos = kde;
32433ff40c12SJohn Marino 	os_memcpy(pos, wpa_ie, wpa_ie_len);
32443ff40c12SJohn Marino 	pos += wpa_ie_len;
3245*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
32463ff40c12SJohn Marino 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
3247*a1157835SDaniel Fojt 		int res;
3248*a1157835SDaniel Fojt 		size_t elen;
3249*a1157835SDaniel Fojt 
3250*a1157835SDaniel Fojt 		elen = pos - kde;
3251*a1157835SDaniel Fojt 		res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
32523ff40c12SJohn Marino 		if (res < 0) {
32533ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "FT: Failed to insert "
32543ff40c12SJohn Marino 				   "PMKR1Name into RSN IE in EAPOL-Key data");
32553ff40c12SJohn Marino 			os_free(kde);
32563ff40c12SJohn Marino 			return;
32573ff40c12SJohn Marino 		}
3258*a1157835SDaniel Fojt 		pos -= wpa_ie_len;
3259*a1157835SDaniel Fojt 		pos += elen;
32603ff40c12SJohn Marino 	}
3261*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
32623ff40c12SJohn Marino 	if (gtk) {
32633ff40c12SJohn Marino 		u8 hdr[2];
32643ff40c12SJohn Marino 		hdr[0] = keyidx & 0x03;
32653ff40c12SJohn Marino 		hdr[1] = 0;
32663ff40c12SJohn Marino 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
32673ff40c12SJohn Marino 				  gtk, gtk_len);
32683ff40c12SJohn Marino 	}
32693ff40c12SJohn Marino 	pos = ieee80211w_kde_add(sm, pos);
3270*a1157835SDaniel Fojt 	if (ocv_oci_add(sm, &pos) < 0) {
3271*a1157835SDaniel Fojt 		os_free(kde);
3272*a1157835SDaniel Fojt 		return;
3273*a1157835SDaniel Fojt 	}
32743ff40c12SJohn Marino 
3275*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
32763ff40c12SJohn Marino 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
32773ff40c12SJohn Marino 		int res;
32783ff40c12SJohn Marino 		struct wpa_auth_config *conf;
32793ff40c12SJohn Marino 
32803ff40c12SJohn Marino 		conf = &sm->wpa_auth->conf;
3281*a1157835SDaniel Fojt 		if (sm->assoc_resp_ftie &&
3282*a1157835SDaniel Fojt 		    kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
3283*a1157835SDaniel Fojt 			os_memcpy(pos, sm->assoc_resp_ftie,
3284*a1157835SDaniel Fojt 				  2 + sm->assoc_resp_ftie[1]);
3285*a1157835SDaniel Fojt 			res = 2 + sm->assoc_resp_ftie[1];
3286*a1157835SDaniel Fojt 		} else {
3287*a1157835SDaniel Fojt 			int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
3288*a1157835SDaniel Fojt 
3289*a1157835SDaniel Fojt 			res = wpa_write_ftie(conf, use_sha384,
3290*a1157835SDaniel Fojt 					     conf->r0_key_holder,
32913ff40c12SJohn Marino 					     conf->r0_key_holder_len,
3292*a1157835SDaniel Fojt 					     NULL, NULL, pos,
3293*a1157835SDaniel Fojt 					     kde + kde_len - pos,
32943ff40c12SJohn Marino 					     NULL, 0);
3295*a1157835SDaniel Fojt 		}
32963ff40c12SJohn Marino 		if (res < 0) {
32973ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
32983ff40c12SJohn Marino 				   "into EAPOL-Key Key Data");
32993ff40c12SJohn Marino 			os_free(kde);
33003ff40c12SJohn Marino 			return;
33013ff40c12SJohn Marino 		}
33023ff40c12SJohn Marino 		pos += res;
33033ff40c12SJohn Marino 
33043ff40c12SJohn Marino 		/* TIE[ReassociationDeadline] (TU) */
33053ff40c12SJohn Marino 		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
33063ff40c12SJohn Marino 		*pos++ = 5;
33073ff40c12SJohn Marino 		*pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
33083ff40c12SJohn Marino 		WPA_PUT_LE32(pos, conf->reassociation_deadline);
33093ff40c12SJohn Marino 		pos += 4;
33103ff40c12SJohn Marino 
33113ff40c12SJohn Marino 		/* TIE[KeyLifetime] (seconds) */
33123ff40c12SJohn Marino 		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
33133ff40c12SJohn Marino 		*pos++ = 5;
33143ff40c12SJohn Marino 		*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
3315*a1157835SDaniel Fojt 		WPA_PUT_LE32(pos, conf->r0_key_lifetime);
33163ff40c12SJohn Marino 		pos += 4;
33173ff40c12SJohn Marino 	}
3318*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
33193ff40c12SJohn Marino #ifdef CONFIG_P2P
33203ff40c12SJohn Marino 	if (WPA_GET_BE32(sm->ip_addr) > 0) {
33213ff40c12SJohn Marino 		u8 addr[3 * 4];
33223ff40c12SJohn Marino 		os_memcpy(addr, sm->ip_addr, 4);
33233ff40c12SJohn Marino 		os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
33243ff40c12SJohn Marino 		os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
33253ff40c12SJohn Marino 		pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
33263ff40c12SJohn Marino 				  addr, sizeof(addr), NULL, 0);
33273ff40c12SJohn Marino 	}
33283ff40c12SJohn Marino #endif /* CONFIG_P2P */
33293ff40c12SJohn Marino 
33303ff40c12SJohn Marino 	wpa_send_eapol(sm->wpa_auth, sm,
3331*a1157835SDaniel Fojt 		       (secure ? WPA_KEY_INFO_SECURE : 0) |
3332*a1157835SDaniel Fojt 		       (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
3333*a1157835SDaniel Fojt 			WPA_KEY_INFO_MIC : 0) |
33343ff40c12SJohn Marino 		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
33353ff40c12SJohn Marino 		       WPA_KEY_INFO_KEY_TYPE,
33363ff40c12SJohn Marino 		       _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
33373ff40c12SJohn Marino 	os_free(kde);
33383ff40c12SJohn Marino }
33393ff40c12SJohn Marino 
33403ff40c12SJohn Marino 
SM_STATE(WPA_PTK,PTKINITDONE)33413ff40c12SJohn Marino SM_STATE(WPA_PTK, PTKINITDONE)
33423ff40c12SJohn Marino {
33433ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
33443ff40c12SJohn Marino 	sm->EAPOLKeyReceived = FALSE;
33453ff40c12SJohn Marino 	if (sm->Pair) {
33463ff40c12SJohn Marino 		enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
33473ff40c12SJohn Marino 		int klen = wpa_cipher_key_len(sm->pairwise);
33483ff40c12SJohn Marino 		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
3349*a1157835SDaniel Fojt 				     sm->PTK.tk, klen)) {
3350*a1157835SDaniel Fojt 			wpa_sta_disconnect(sm->wpa_auth, sm->addr,
3351*a1157835SDaniel Fojt 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
33523ff40c12SJohn Marino 			return;
33533ff40c12SJohn Marino 		}
33543ff40c12SJohn Marino 		/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
33553ff40c12SJohn Marino 		sm->pairwise_set = TRUE;
33563ff40c12SJohn Marino 
3357*a1157835SDaniel Fojt 		wpa_auth_set_ptk_rekey_timer(sm);
33583ff40c12SJohn Marino 
3359*a1157835SDaniel Fojt 		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
3360*a1157835SDaniel Fojt 		    sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
3361*a1157835SDaniel Fojt 		    sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) {
33623ff40c12SJohn Marino 			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
33633ff40c12SJohn Marino 					   WPA_EAPOL_authorized, 1);
33643ff40c12SJohn Marino 		}
33653ff40c12SJohn Marino 	}
33663ff40c12SJohn Marino 
33673ff40c12SJohn Marino 	if (0 /* IBSS == TRUE */) {
33683ff40c12SJohn Marino 		sm->keycount++;
33693ff40c12SJohn Marino 		if (sm->keycount == 2) {
33703ff40c12SJohn Marino 			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
33713ff40c12SJohn Marino 					   WPA_EAPOL_portValid, 1);
33723ff40c12SJohn Marino 		}
33733ff40c12SJohn Marino 	} else {
33743ff40c12SJohn Marino 		wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
33753ff40c12SJohn Marino 				   1);
33763ff40c12SJohn Marino 	}
33773ff40c12SJohn Marino 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
33783ff40c12SJohn Marino 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
33793ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA)
33803ff40c12SJohn Marino 		sm->PInitAKeys = TRUE;
33813ff40c12SJohn Marino 	else
33823ff40c12SJohn Marino 		sm->has_GTK = TRUE;
33833ff40c12SJohn Marino 	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
33843ff40c12SJohn Marino 			 "pairwise key handshake completed (%s)",
33853ff40c12SJohn Marino 			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
33863ff40c12SJohn Marino 
3387*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
33883ff40c12SJohn Marino 	wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
3389*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
33903ff40c12SJohn Marino }
33913ff40c12SJohn Marino 
33923ff40c12SJohn Marino 
SM_STEP(WPA_PTK)33933ff40c12SJohn Marino SM_STEP(WPA_PTK)
33943ff40c12SJohn Marino {
33953ff40c12SJohn Marino 	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
33963ff40c12SJohn Marino 
33973ff40c12SJohn Marino 	if (sm->Init)
33983ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, INITIALIZE);
33993ff40c12SJohn Marino 	else if (sm->Disconnect
34003ff40c12SJohn Marino 		 /* || FIX: dot11RSNAConfigSALifetime timeout */) {
34013ff40c12SJohn Marino 		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
34023ff40c12SJohn Marino 				"WPA_PTK: sm->Disconnect");
34033ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, DISCONNECT);
34043ff40c12SJohn Marino 	}
34053ff40c12SJohn Marino 	else if (sm->DeauthenticationRequest)
34063ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, DISCONNECTED);
34073ff40c12SJohn Marino 	else if (sm->AuthenticationRequest)
34083ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, AUTHENTICATION);
34093ff40c12SJohn Marino 	else if (sm->ReAuthenticationRequest)
34103ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, AUTHENTICATION2);
3411*a1157835SDaniel Fojt 	else if (sm->PTKRequest) {
3412*a1157835SDaniel Fojt 		if (wpa_auth_sm_ptk_update(sm) < 0)
3413*a1157835SDaniel Fojt 			SM_ENTER(WPA_PTK, DISCONNECTED);
3414*a1157835SDaniel Fojt 		else
34153ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKSTART);
3416*a1157835SDaniel Fojt 	} else switch (sm->wpa_ptk_state) {
34173ff40c12SJohn Marino 	case WPA_PTK_INITIALIZE:
34183ff40c12SJohn Marino 		break;
34193ff40c12SJohn Marino 	case WPA_PTK_DISCONNECT:
34203ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, DISCONNECTED);
34213ff40c12SJohn Marino 		break;
34223ff40c12SJohn Marino 	case WPA_PTK_DISCONNECTED:
34233ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, INITIALIZE);
34243ff40c12SJohn Marino 		break;
34253ff40c12SJohn Marino 	case WPA_PTK_AUTHENTICATION:
34263ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, AUTHENTICATION2);
34273ff40c12SJohn Marino 		break;
34283ff40c12SJohn Marino 	case WPA_PTK_AUTHENTICATION2:
34293ff40c12SJohn Marino 		if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
34303ff40c12SJohn Marino 		    wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
34313ff40c12SJohn Marino 				       WPA_EAPOL_keyRun) > 0)
34323ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, INITPMK);
3433*a1157835SDaniel Fojt 		else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
3434*a1157835SDaniel Fojt 			 sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE
34353ff40c12SJohn Marino 			 /* FIX: && 802.1X::keyRun */)
34363ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, INITPSK);
3437*a1157835SDaniel Fojt 		else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP)
3438*a1157835SDaniel Fojt 			SM_ENTER(WPA_PTK, INITPMK);
34393ff40c12SJohn Marino 		break;
34403ff40c12SJohn Marino 	case WPA_PTK_INITPMK:
34413ff40c12SJohn Marino 		if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
3442*a1157835SDaniel Fojt 				       WPA_EAPOL_keyAvailable) > 0) {
34433ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKSTART);
3444*a1157835SDaniel Fojt #ifdef CONFIG_DPP
3445*a1157835SDaniel Fojt 		} else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->pmksa) {
3446*a1157835SDaniel Fojt 			SM_ENTER(WPA_PTK, PTKSTART);
3447*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
3448*a1157835SDaniel Fojt 		} else {
34493ff40c12SJohn Marino 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
34503ff40c12SJohn Marino 			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
34513ff40c12SJohn Marino 					"INITPMK - keyAvailable = false");
34523ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, DISCONNECT);
34533ff40c12SJohn Marino 		}
34543ff40c12SJohn Marino 		break;
34553ff40c12SJohn Marino 	case WPA_PTK_INITPSK:
34563ff40c12SJohn Marino 		if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
3457*a1157835SDaniel Fojt 				     NULL, NULL, NULL)) {
34583ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKSTART);
3459*a1157835SDaniel Fojt #ifdef CONFIG_SAE
3460*a1157835SDaniel Fojt 		} else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
3461*a1157835SDaniel Fojt 			SM_ENTER(WPA_PTK, PTKSTART);
3462*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
3463*a1157835SDaniel Fojt 		} else {
34643ff40c12SJohn Marino 			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
34653ff40c12SJohn Marino 					"no PSK configured for the STA");
34663ff40c12SJohn Marino 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
34673ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, DISCONNECT);
34683ff40c12SJohn Marino 		}
34693ff40c12SJohn Marino 		break;
34703ff40c12SJohn Marino 	case WPA_PTK_PTKSTART:
34713ff40c12SJohn Marino 		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
34723ff40c12SJohn Marino 		    sm->EAPOLKeyPairwise)
34733ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
34743ff40c12SJohn Marino 		else if (sm->TimeoutCtr >
3475*a1157835SDaniel Fojt 			 sm->wpa_auth->conf.wpa_pairwise_update_count) {
34763ff40c12SJohn Marino 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
3477*a1157835SDaniel Fojt 			wpa_auth_vlogger(
3478*a1157835SDaniel Fojt 				sm->wpa_auth, sm->addr, LOGGER_DEBUG,
3479*a1157835SDaniel Fojt 				"PTKSTART: Retry limit %u reached",
3480*a1157835SDaniel Fojt 				sm->wpa_auth->conf.wpa_pairwise_update_count);
34813ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, DISCONNECT);
34823ff40c12SJohn Marino 		} else if (sm->TimeoutEvt)
34833ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKSTART);
34843ff40c12SJohn Marino 		break;
34853ff40c12SJohn Marino 	case WPA_PTK_PTKCALCNEGOTIATING:
34863ff40c12SJohn Marino 		if (sm->MICVerified)
34873ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2);
34883ff40c12SJohn Marino 		else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
34893ff40c12SJohn Marino 			 sm->EAPOLKeyPairwise)
34903ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
34913ff40c12SJohn Marino 		else if (sm->TimeoutEvt)
34923ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKSTART);
34933ff40c12SJohn Marino 		break;
34943ff40c12SJohn Marino 	case WPA_PTK_PTKCALCNEGOTIATING2:
34953ff40c12SJohn Marino 		SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
34963ff40c12SJohn Marino 		break;
34973ff40c12SJohn Marino 	case WPA_PTK_PTKINITNEGOTIATING:
34983ff40c12SJohn Marino 		if (sm->update_snonce)
34993ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
35003ff40c12SJohn Marino 		else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
35013ff40c12SJohn Marino 			 sm->EAPOLKeyPairwise && sm->MICVerified)
35023ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKINITDONE);
35033ff40c12SJohn Marino 		else if (sm->TimeoutCtr >
3504*a1157835SDaniel Fojt 			 sm->wpa_auth->conf.wpa_pairwise_update_count ||
3505*a1157835SDaniel Fojt 			 (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
3506*a1157835SDaniel Fojt 			  sm->TimeoutCtr > 1)) {
35073ff40c12SJohn Marino 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
3508*a1157835SDaniel Fojt 			wpa_auth_vlogger(
3509*a1157835SDaniel Fojt 				sm->wpa_auth, sm->addr, LOGGER_DEBUG,
3510*a1157835SDaniel Fojt 				"PTKINITNEGOTIATING: Retry limit %u reached",
3511*a1157835SDaniel Fojt 				sm->wpa_auth->conf.wpa_pairwise_update_count);
35123ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, DISCONNECT);
35133ff40c12SJohn Marino 		} else if (sm->TimeoutEvt)
35143ff40c12SJohn Marino 			SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
35153ff40c12SJohn Marino 		break;
35163ff40c12SJohn Marino 	case WPA_PTK_PTKINITDONE:
35173ff40c12SJohn Marino 		break;
35183ff40c12SJohn Marino 	}
35193ff40c12SJohn Marino }
35203ff40c12SJohn Marino 
35213ff40c12SJohn Marino 
SM_STATE(WPA_PTK_GROUP,IDLE)35223ff40c12SJohn Marino SM_STATE(WPA_PTK_GROUP, IDLE)
35233ff40c12SJohn Marino {
35243ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group);
35253ff40c12SJohn Marino 	if (sm->Init) {
35263ff40c12SJohn Marino 		/* Init flag is not cleared here, so avoid busy
35273ff40c12SJohn Marino 		 * loop by claiming nothing changed. */
35283ff40c12SJohn Marino 		sm->changed = FALSE;
35293ff40c12SJohn Marino 	}
35303ff40c12SJohn Marino 	sm->GTimeoutCtr = 0;
35313ff40c12SJohn Marino }
35323ff40c12SJohn Marino 
35333ff40c12SJohn Marino 
SM_STATE(WPA_PTK_GROUP,REKEYNEGOTIATING)35343ff40c12SJohn Marino SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
35353ff40c12SJohn Marino {
35363ff40c12SJohn Marino 	u8 rsc[WPA_KEY_RSC_LEN];
35373ff40c12SJohn Marino 	struct wpa_group *gsm = sm->group;
3538*a1157835SDaniel Fojt 	const u8 *kde;
3539*a1157835SDaniel Fojt 	u8 *kde_buf = NULL, *pos, hdr[2];
35403ff40c12SJohn Marino 	size_t kde_len;
35413ff40c12SJohn Marino 	u8 *gtk, dummy_gtk[32];
35423ff40c12SJohn Marino 
35433ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
35443ff40c12SJohn Marino 
35453ff40c12SJohn Marino 	sm->GTimeoutCtr++;
3546*a1157835SDaniel Fojt 	if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
3547*a1157835SDaniel Fojt 	    sm->GTimeoutCtr > 1) {
3548*a1157835SDaniel Fojt 		/* Do not allow retransmission of EAPOL-Key group msg 1/2 */
3549*a1157835SDaniel Fojt 		return;
3550*a1157835SDaniel Fojt 	}
3551*a1157835SDaniel Fojt 	if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
35523ff40c12SJohn Marino 		/* No point in sending the EAPOL-Key - we will disconnect
35533ff40c12SJohn Marino 		 * immediately following this. */
35543ff40c12SJohn Marino 		return;
35553ff40c12SJohn Marino 	}
35563ff40c12SJohn Marino 
35573ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA)
35583ff40c12SJohn Marino 		sm->PInitAKeys = FALSE;
35593ff40c12SJohn Marino 	sm->TimeoutEvt = FALSE;
35603ff40c12SJohn Marino 	/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
35613ff40c12SJohn Marino 	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
35623ff40c12SJohn Marino 	if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
35633ff40c12SJohn Marino 		wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
35643ff40c12SJohn Marino 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
35653ff40c12SJohn Marino 			"sending 1/2 msg of Group Key Handshake");
35663ff40c12SJohn Marino 
35673ff40c12SJohn Marino 	gtk = gsm->GTK[gsm->GN - 1];
3568*a1157835SDaniel Fojt 	if (sm->wpa_auth->conf.disable_gtk ||
3569*a1157835SDaniel Fojt 	    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
35703ff40c12SJohn Marino 		/*
35713ff40c12SJohn Marino 		 * Provide unique random GTK to each STA to prevent use
35723ff40c12SJohn Marino 		 * of GTK in the BSS.
35733ff40c12SJohn Marino 		 */
35743ff40c12SJohn Marino 		if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0)
35753ff40c12SJohn Marino 			return;
35763ff40c12SJohn Marino 		gtk = dummy_gtk;
35773ff40c12SJohn Marino 	}
35783ff40c12SJohn Marino 	if (sm->wpa == WPA_VERSION_WPA2) {
35793ff40c12SJohn Marino 		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
3580*a1157835SDaniel Fojt 			ieee80211w_kde_len(sm) + ocv_oci_len(sm);
3581*a1157835SDaniel Fojt 		kde_buf = os_malloc(kde_len);
3582*a1157835SDaniel Fojt 		if (kde_buf == NULL)
35833ff40c12SJohn Marino 			return;
35843ff40c12SJohn Marino 
3585*a1157835SDaniel Fojt 		kde = pos = kde_buf;
35863ff40c12SJohn Marino 		hdr[0] = gsm->GN & 0x03;
35873ff40c12SJohn Marino 		hdr[1] = 0;
35883ff40c12SJohn Marino 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
35893ff40c12SJohn Marino 				  gtk, gsm->GTK_len);
35903ff40c12SJohn Marino 		pos = ieee80211w_kde_add(sm, pos);
3591*a1157835SDaniel Fojt 		if (ocv_oci_add(sm, &pos) < 0) {
3592*a1157835SDaniel Fojt 			os_free(kde_buf);
3593*a1157835SDaniel Fojt 			return;
3594*a1157835SDaniel Fojt 		}
3595*a1157835SDaniel Fojt 		kde_len = pos - kde;
35963ff40c12SJohn Marino 	} else {
35973ff40c12SJohn Marino 		kde = gtk;
3598*a1157835SDaniel Fojt 		kde_len = gsm->GTK_len;
35993ff40c12SJohn Marino 	}
36003ff40c12SJohn Marino 
36013ff40c12SJohn Marino 	wpa_send_eapol(sm->wpa_auth, sm,
3602*a1157835SDaniel Fojt 		       WPA_KEY_INFO_SECURE |
3603*a1157835SDaniel Fojt 		       (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
3604*a1157835SDaniel Fojt 			WPA_KEY_INFO_MIC : 0) |
36053ff40c12SJohn Marino 		       WPA_KEY_INFO_ACK |
36063ff40c12SJohn Marino 		       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
3607*a1157835SDaniel Fojt 		       rsc, NULL, kde, kde_len, gsm->GN, 1);
3608*a1157835SDaniel Fojt 
3609*a1157835SDaniel Fojt 	os_free(kde_buf);
36103ff40c12SJohn Marino }
36113ff40c12SJohn Marino 
36123ff40c12SJohn Marino 
SM_STATE(WPA_PTK_GROUP,REKEYESTABLISHED)36133ff40c12SJohn Marino SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
36143ff40c12SJohn Marino {
3615*a1157835SDaniel Fojt #ifdef CONFIG_OCV
3616*a1157835SDaniel Fojt 	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
3617*a1157835SDaniel Fojt 	const u8 *key_data, *mic;
3618*a1157835SDaniel Fojt 	struct ieee802_1x_hdr *hdr;
3619*a1157835SDaniel Fojt 	struct wpa_eapol_key *key;
3620*a1157835SDaniel Fojt 	struct wpa_eapol_ie_parse kde;
3621*a1157835SDaniel Fojt 	size_t mic_len;
3622*a1157835SDaniel Fojt 	u16 key_data_length;
3623*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
3624*a1157835SDaniel Fojt 
36253ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
36263ff40c12SJohn Marino 	sm->EAPOLKeyReceived = FALSE;
3627*a1157835SDaniel Fojt 
3628*a1157835SDaniel Fojt #ifdef CONFIG_OCV
3629*a1157835SDaniel Fojt 	mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
3630*a1157835SDaniel Fojt 
3631*a1157835SDaniel Fojt 	/*
3632*a1157835SDaniel Fojt 	 * Note: last_rx_eapol_key length fields have already been validated in
3633*a1157835SDaniel Fojt 	 * wpa_receive().
3634*a1157835SDaniel Fojt 	 */
3635*a1157835SDaniel Fojt 	hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
3636*a1157835SDaniel Fojt 	key = (struct wpa_eapol_key *) (hdr + 1);
3637*a1157835SDaniel Fojt 	mic = (u8 *) (key + 1);
3638*a1157835SDaniel Fojt 	key_data = mic + mic_len + 2;
3639*a1157835SDaniel Fojt 	key_data_length = WPA_GET_BE16(mic + mic_len);
3640*a1157835SDaniel Fojt 	if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
3641*a1157835SDaniel Fojt 	    sizeof(*key) - mic_len - 2)
3642*a1157835SDaniel Fojt 		return;
3643*a1157835SDaniel Fojt 
3644*a1157835SDaniel Fojt 	if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
3645*a1157835SDaniel Fojt 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
3646*a1157835SDaniel Fojt 				 "received EAPOL-Key group msg 2/2 with invalid Key Data contents");
3647*a1157835SDaniel Fojt 		return;
3648*a1157835SDaniel Fojt 	}
3649*a1157835SDaniel Fojt 
3650*a1157835SDaniel Fojt 	if (wpa_auth_uses_ocv(sm)) {
3651*a1157835SDaniel Fojt 		struct wpa_channel_info ci;
3652*a1157835SDaniel Fojt 		int tx_chanwidth;
3653*a1157835SDaniel Fojt 		int tx_seg1_idx;
3654*a1157835SDaniel Fojt 
3655*a1157835SDaniel Fojt 		if (wpa_channel_info(wpa_auth, &ci) != 0) {
3656*a1157835SDaniel Fojt 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
3657*a1157835SDaniel Fojt 					"Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
3658*a1157835SDaniel Fojt 			return;
3659*a1157835SDaniel Fojt 		}
3660*a1157835SDaniel Fojt 
3661*a1157835SDaniel Fojt 		if (get_sta_tx_parameters(sm,
3662*a1157835SDaniel Fojt 					  channel_width_to_int(ci.chanwidth),
3663*a1157835SDaniel Fojt 					  ci.seg1_idx, &tx_chanwidth,
3664*a1157835SDaniel Fojt 					  &tx_seg1_idx) < 0)
3665*a1157835SDaniel Fojt 			return;
3666*a1157835SDaniel Fojt 
3667*a1157835SDaniel Fojt 		if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
3668*a1157835SDaniel Fojt 					 tx_chanwidth, tx_seg1_idx) != 0) {
3669*a1157835SDaniel Fojt 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
3670*a1157835SDaniel Fojt 					ocv_errorstr);
3671*a1157835SDaniel Fojt 			return;
3672*a1157835SDaniel Fojt 		}
3673*a1157835SDaniel Fojt 	}
3674*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
3675*a1157835SDaniel Fojt 
36763ff40c12SJohn Marino 	if (sm->GUpdateStationKeys)
36773ff40c12SJohn Marino 		sm->group->GKeyDoneStations--;
36783ff40c12SJohn Marino 	sm->GUpdateStationKeys = FALSE;
36793ff40c12SJohn Marino 	sm->GTimeoutCtr = 0;
36803ff40c12SJohn Marino 	/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
36813ff40c12SJohn Marino 	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
36823ff40c12SJohn Marino 			 "group key handshake completed (%s)",
36833ff40c12SJohn Marino 			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
36843ff40c12SJohn Marino 	sm->has_GTK = TRUE;
36853ff40c12SJohn Marino }
36863ff40c12SJohn Marino 
36873ff40c12SJohn Marino 
SM_STATE(WPA_PTK_GROUP,KEYERROR)36883ff40c12SJohn Marino SM_STATE(WPA_PTK_GROUP, KEYERROR)
36893ff40c12SJohn Marino {
36903ff40c12SJohn Marino 	SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
36913ff40c12SJohn Marino 	if (sm->GUpdateStationKeys)
36923ff40c12SJohn Marino 		sm->group->GKeyDoneStations--;
36933ff40c12SJohn Marino 	sm->GUpdateStationKeys = FALSE;
36943ff40c12SJohn Marino 	sm->Disconnect = TRUE;
3695*a1157835SDaniel Fojt 	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
3696*a1157835SDaniel Fojt 			 "group key handshake failed (%s) after %u tries",
3697*a1157835SDaniel Fojt 			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
3698*a1157835SDaniel Fojt 			 sm->wpa_auth->conf.wpa_group_update_count);
36993ff40c12SJohn Marino }
37003ff40c12SJohn Marino 
37013ff40c12SJohn Marino 
SM_STEP(WPA_PTK_GROUP)37023ff40c12SJohn Marino SM_STEP(WPA_PTK_GROUP)
37033ff40c12SJohn Marino {
37043ff40c12SJohn Marino 	if (sm->Init || sm->PtkGroupInit) {
37053ff40c12SJohn Marino 		SM_ENTER(WPA_PTK_GROUP, IDLE);
37063ff40c12SJohn Marino 		sm->PtkGroupInit = FALSE;
37073ff40c12SJohn Marino 	} else switch (sm->wpa_ptk_group_state) {
37083ff40c12SJohn Marino 	case WPA_PTK_GROUP_IDLE:
37093ff40c12SJohn Marino 		if (sm->GUpdateStationKeys ||
37103ff40c12SJohn Marino 		    (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
37113ff40c12SJohn Marino 			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
37123ff40c12SJohn Marino 		break;
37133ff40c12SJohn Marino 	case WPA_PTK_GROUP_REKEYNEGOTIATING:
37143ff40c12SJohn Marino 		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
37153ff40c12SJohn Marino 		    !sm->EAPOLKeyPairwise && sm->MICVerified)
37163ff40c12SJohn Marino 			SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
37173ff40c12SJohn Marino 		else if (sm->GTimeoutCtr >
3718*a1157835SDaniel Fojt 			 sm->wpa_auth->conf.wpa_group_update_count ||
3719*a1157835SDaniel Fojt 			 (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
3720*a1157835SDaniel Fojt 			  sm->GTimeoutCtr > 1))
37213ff40c12SJohn Marino 			SM_ENTER(WPA_PTK_GROUP, KEYERROR);
37223ff40c12SJohn Marino 		else if (sm->TimeoutEvt)
37233ff40c12SJohn Marino 			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
37243ff40c12SJohn Marino 		break;
37253ff40c12SJohn Marino 	case WPA_PTK_GROUP_KEYERROR:
37263ff40c12SJohn Marino 		SM_ENTER(WPA_PTK_GROUP, IDLE);
37273ff40c12SJohn Marino 		break;
37283ff40c12SJohn Marino 	case WPA_PTK_GROUP_REKEYESTABLISHED:
37293ff40c12SJohn Marino 		SM_ENTER(WPA_PTK_GROUP, IDLE);
37303ff40c12SJohn Marino 		break;
37313ff40c12SJohn Marino 	}
37323ff40c12SJohn Marino }
37333ff40c12SJohn Marino 
37343ff40c12SJohn Marino 
wpa_gtk_update(struct wpa_authenticator * wpa_auth,struct wpa_group * group)37353ff40c12SJohn Marino static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
37363ff40c12SJohn Marino 			  struct wpa_group *group)
37373ff40c12SJohn Marino {
37383ff40c12SJohn Marino 	int ret = 0;
37393ff40c12SJohn Marino 
37403ff40c12SJohn Marino 	os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
37413ff40c12SJohn Marino 	inc_byte_array(group->Counter, WPA_NONCE_LEN);
37423ff40c12SJohn Marino 	if (wpa_gmk_to_gtk(group->GMK, "Group key expansion",
37433ff40c12SJohn Marino 			   wpa_auth->addr, group->GNonce,
37443ff40c12SJohn Marino 			   group->GTK[group->GN - 1], group->GTK_len) < 0)
37453ff40c12SJohn Marino 		ret = -1;
37463ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "GTK",
37473ff40c12SJohn Marino 			group->GTK[group->GN - 1], group->GTK_len);
37483ff40c12SJohn Marino 
37493ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
37503ff40c12SJohn Marino 	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
3751*a1157835SDaniel Fojt 		size_t len;
3752*a1157835SDaniel Fojt 		len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
37533ff40c12SJohn Marino 		os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
37543ff40c12SJohn Marino 		inc_byte_array(group->Counter, WPA_NONCE_LEN);
37553ff40c12SJohn Marino 		if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
37563ff40c12SJohn Marino 				   wpa_auth->addr, group->GNonce,
3757*a1157835SDaniel Fojt 				   group->IGTK[group->GN_igtk - 4], len) < 0)
37583ff40c12SJohn Marino 			ret = -1;
37593ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "IGTK",
3760*a1157835SDaniel Fojt 				group->IGTK[group->GN_igtk - 4], len);
37613ff40c12SJohn Marino 	}
37623ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
37633ff40c12SJohn Marino 
37643ff40c12SJohn Marino 	return ret;
37653ff40c12SJohn Marino }
37663ff40c12SJohn Marino 
37673ff40c12SJohn Marino 
wpa_group_gtk_init(struct wpa_authenticator * wpa_auth,struct wpa_group * group)37683ff40c12SJohn Marino static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
37693ff40c12SJohn Marino 			       struct wpa_group *group)
37703ff40c12SJohn Marino {
37713ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
37723ff40c12SJohn Marino 		   "GTK_INIT (VLAN-ID %d)", group->vlan_id);
37733ff40c12SJohn Marino 	group->changed = FALSE; /* GInit is not cleared here; avoid loop */
37743ff40c12SJohn Marino 	group->wpa_group_state = WPA_GROUP_GTK_INIT;
37753ff40c12SJohn Marino 
37763ff40c12SJohn Marino 	/* GTK[0..N] = 0 */
37773ff40c12SJohn Marino 	os_memset(group->GTK, 0, sizeof(group->GTK));
37783ff40c12SJohn Marino 	group->GN = 1;
37793ff40c12SJohn Marino 	group->GM = 2;
37803ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
37813ff40c12SJohn Marino 	group->GN_igtk = 4;
37823ff40c12SJohn Marino 	group->GM_igtk = 5;
37833ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
37843ff40c12SJohn Marino 	/* GTK[GN] = CalcGTK() */
37853ff40c12SJohn Marino 	wpa_gtk_update(wpa_auth, group);
37863ff40c12SJohn Marino }
37873ff40c12SJohn Marino 
37883ff40c12SJohn Marino 
wpa_group_update_sta(struct wpa_state_machine * sm,void * ctx)37893ff40c12SJohn Marino static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
37903ff40c12SJohn Marino {
37913ff40c12SJohn Marino 	if (ctx != NULL && ctx != sm->group)
37923ff40c12SJohn Marino 		return 0;
37933ff40c12SJohn Marino 
37943ff40c12SJohn Marino 	if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
37953ff40c12SJohn Marino 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
37963ff40c12SJohn Marino 				"Not in PTKINITDONE; skip Group Key update");
37973ff40c12SJohn Marino 		sm->GUpdateStationKeys = FALSE;
37983ff40c12SJohn Marino 		return 0;
37993ff40c12SJohn Marino 	}
38003ff40c12SJohn Marino 	if (sm->GUpdateStationKeys) {
38013ff40c12SJohn Marino 		/*
38023ff40c12SJohn Marino 		 * This should not really happen, so add a debug log entry.
38033ff40c12SJohn Marino 		 * Since we clear the GKeyDoneStations before the loop, the
38043ff40c12SJohn Marino 		 * station needs to be counted here anyway.
38053ff40c12SJohn Marino 		 */
38063ff40c12SJohn Marino 		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
38073ff40c12SJohn Marino 				"GUpdateStationKeys was already set when "
38083ff40c12SJohn Marino 				"marking station for GTK rekeying");
38093ff40c12SJohn Marino 	}
38103ff40c12SJohn Marino 
38113ff40c12SJohn Marino 	/* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
38123ff40c12SJohn Marino 	if (sm->is_wnmsleep)
38133ff40c12SJohn Marino 		return 0;
38143ff40c12SJohn Marino 
38153ff40c12SJohn Marino 	sm->group->GKeyDoneStations++;
38163ff40c12SJohn Marino 	sm->GUpdateStationKeys = TRUE;
38173ff40c12SJohn Marino 
38183ff40c12SJohn Marino 	wpa_sm_step(sm);
38193ff40c12SJohn Marino 	return 0;
38203ff40c12SJohn Marino }
38213ff40c12SJohn Marino 
38223ff40c12SJohn Marino 
3823*a1157835SDaniel Fojt #ifdef CONFIG_WNM_AP
38243ff40c12SJohn Marino /* update GTK when exiting WNM-Sleep Mode */
wpa_wnmsleep_rekey_gtk(struct wpa_state_machine * sm)38253ff40c12SJohn Marino void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
38263ff40c12SJohn Marino {
38273ff40c12SJohn Marino 	if (sm == NULL || sm->is_wnmsleep)
38283ff40c12SJohn Marino 		return;
38293ff40c12SJohn Marino 
38303ff40c12SJohn Marino 	wpa_group_update_sta(sm, NULL);
38313ff40c12SJohn Marino }
38323ff40c12SJohn Marino 
38333ff40c12SJohn Marino 
wpa_set_wnmsleep(struct wpa_state_machine * sm,int flag)38343ff40c12SJohn Marino void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
38353ff40c12SJohn Marino {
38363ff40c12SJohn Marino 	if (sm)
38373ff40c12SJohn Marino 		sm->is_wnmsleep = !!flag;
38383ff40c12SJohn Marino }
38393ff40c12SJohn Marino 
38403ff40c12SJohn Marino 
wpa_wnmsleep_gtk_subelem(struct wpa_state_machine * sm,u8 * pos)38413ff40c12SJohn Marino int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
38423ff40c12SJohn Marino {
38433ff40c12SJohn Marino 	struct wpa_group *gsm = sm->group;
38443ff40c12SJohn Marino 	u8 *start = pos;
38453ff40c12SJohn Marino 
38463ff40c12SJohn Marino 	/*
38473ff40c12SJohn Marino 	 * GTK subelement:
38483ff40c12SJohn Marino 	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
38493ff40c12SJohn Marino 	 * Key[5..32]
38503ff40c12SJohn Marino 	 */
38513ff40c12SJohn Marino 	*pos++ = WNM_SLEEP_SUBELEM_GTK;
38523ff40c12SJohn Marino 	*pos++ = 11 + gsm->GTK_len;
38533ff40c12SJohn Marino 	/* Key ID in B0-B1 of Key Info */
38543ff40c12SJohn Marino 	WPA_PUT_LE16(pos, gsm->GN & 0x03);
38553ff40c12SJohn Marino 	pos += 2;
38563ff40c12SJohn Marino 	*pos++ = gsm->GTK_len;
38573ff40c12SJohn Marino 	if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
38583ff40c12SJohn Marino 		return 0;
38593ff40c12SJohn Marino 	pos += 8;
38603ff40c12SJohn Marino 	os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
38613ff40c12SJohn Marino 	pos += gsm->GTK_len;
38623ff40c12SJohn Marino 
38633ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
38643ff40c12SJohn Marino 		   gsm->GN);
38653ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
38663ff40c12SJohn Marino 			gsm->GTK[gsm->GN - 1], gsm->GTK_len);
38673ff40c12SJohn Marino 
38683ff40c12SJohn Marino 	return pos - start;
38693ff40c12SJohn Marino }
38703ff40c12SJohn Marino 
38713ff40c12SJohn Marino 
38723ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
wpa_wnmsleep_igtk_subelem(struct wpa_state_machine * sm,u8 * pos)38733ff40c12SJohn Marino int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
38743ff40c12SJohn Marino {
38753ff40c12SJohn Marino 	struct wpa_group *gsm = sm->group;
38763ff40c12SJohn Marino 	u8 *start = pos;
3877*a1157835SDaniel Fojt 	size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
38783ff40c12SJohn Marino 
38793ff40c12SJohn Marino 	/*
38803ff40c12SJohn Marino 	 * IGTK subelement:
38813ff40c12SJohn Marino 	 * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
38823ff40c12SJohn Marino 	 */
38833ff40c12SJohn Marino 	*pos++ = WNM_SLEEP_SUBELEM_IGTK;
3884*a1157835SDaniel Fojt 	*pos++ = 2 + 6 + len;
38853ff40c12SJohn Marino 	WPA_PUT_LE16(pos, gsm->GN_igtk);
38863ff40c12SJohn Marino 	pos += 2;
38873ff40c12SJohn Marino 	if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
38883ff40c12SJohn Marino 		return 0;
38893ff40c12SJohn Marino 	pos += 6;
38903ff40c12SJohn Marino 
3891*a1157835SDaniel Fojt 	os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
3892*a1157835SDaniel Fojt 	pos += len;
38933ff40c12SJohn Marino 
38943ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
38953ff40c12SJohn Marino 		   gsm->GN_igtk);
38963ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
3897*a1157835SDaniel Fojt 			gsm->IGTK[gsm->GN_igtk - 4], len);
38983ff40c12SJohn Marino 
38993ff40c12SJohn Marino 	return pos - start;
39003ff40c12SJohn Marino }
39013ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
3902*a1157835SDaniel Fojt #endif /* CONFIG_WNM_AP */
39033ff40c12SJohn Marino 
39043ff40c12SJohn Marino 
wpa_group_setkeys(struct wpa_authenticator * wpa_auth,struct wpa_group * group)39053ff40c12SJohn Marino static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
39063ff40c12SJohn Marino 			      struct wpa_group *group)
39073ff40c12SJohn Marino {
39083ff40c12SJohn Marino 	int tmp;
39093ff40c12SJohn Marino 
39103ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
39113ff40c12SJohn Marino 		   "SETKEYS (VLAN-ID %d)", group->vlan_id);
39123ff40c12SJohn Marino 	group->changed = TRUE;
39133ff40c12SJohn Marino 	group->wpa_group_state = WPA_GROUP_SETKEYS;
39143ff40c12SJohn Marino 	group->GTKReKey = FALSE;
39153ff40c12SJohn Marino 	tmp = group->GM;
39163ff40c12SJohn Marino 	group->GM = group->GN;
39173ff40c12SJohn Marino 	group->GN = tmp;
39183ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
39193ff40c12SJohn Marino 	tmp = group->GM_igtk;
39203ff40c12SJohn Marino 	group->GM_igtk = group->GN_igtk;
39213ff40c12SJohn Marino 	group->GN_igtk = tmp;
39223ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
39233ff40c12SJohn Marino 	/* "GKeyDoneStations = GNoStations" is done in more robust way by
39243ff40c12SJohn Marino 	 * counting the STAs that are marked with GUpdateStationKeys instead of
39253ff40c12SJohn Marino 	 * including all STAs that could be in not-yet-completed state. */
39263ff40c12SJohn Marino 	wpa_gtk_update(wpa_auth, group);
39273ff40c12SJohn Marino 
39283ff40c12SJohn Marino 	if (group->GKeyDoneStations) {
39293ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
39303ff40c12SJohn Marino 			   "GKeyDoneStations=%d when starting new GTK rekey",
39313ff40c12SJohn Marino 			   group->GKeyDoneStations);
39323ff40c12SJohn Marino 		group->GKeyDoneStations = 0;
39333ff40c12SJohn Marino 	}
39343ff40c12SJohn Marino 	wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
39353ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
39363ff40c12SJohn Marino 		   group->GKeyDoneStations);
39373ff40c12SJohn Marino }
39383ff40c12SJohn Marino 
39393ff40c12SJohn Marino 
wpa_group_config_group_keys(struct wpa_authenticator * wpa_auth,struct wpa_group * group)39403ff40c12SJohn Marino static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
39413ff40c12SJohn Marino 				       struct wpa_group *group)
39423ff40c12SJohn Marino {
39433ff40c12SJohn Marino 	int ret = 0;
39443ff40c12SJohn Marino 
39453ff40c12SJohn Marino 	if (wpa_auth_set_key(wpa_auth, group->vlan_id,
39463ff40c12SJohn Marino 			     wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
39473ff40c12SJohn Marino 			     broadcast_ether_addr, group->GN,
39483ff40c12SJohn Marino 			     group->GTK[group->GN - 1], group->GTK_len) < 0)
39493ff40c12SJohn Marino 		ret = -1;
39503ff40c12SJohn Marino 
39513ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
3952*a1157835SDaniel Fojt 	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
3953*a1157835SDaniel Fojt 		enum wpa_alg alg;
3954*a1157835SDaniel Fojt 		size_t len;
3955*a1157835SDaniel Fojt 
3956*a1157835SDaniel Fojt 		alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
3957*a1157835SDaniel Fojt 		len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
3958*a1157835SDaniel Fojt 
3959*a1157835SDaniel Fojt 		if (ret == 0 &&
3960*a1157835SDaniel Fojt 		    wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
39613ff40c12SJohn Marino 				     broadcast_ether_addr, group->GN_igtk,
3962*a1157835SDaniel Fojt 				     group->IGTK[group->GN_igtk - 4], len) < 0)
39633ff40c12SJohn Marino 			ret = -1;
3964*a1157835SDaniel Fojt 	}
39653ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
39663ff40c12SJohn Marino 
39673ff40c12SJohn Marino 	return ret;
39683ff40c12SJohn Marino }
39693ff40c12SJohn Marino 
39703ff40c12SJohn Marino 
wpa_group_disconnect_cb(struct wpa_state_machine * sm,void * ctx)39713ff40c12SJohn Marino static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
39723ff40c12SJohn Marino {
39733ff40c12SJohn Marino 	if (sm->group == ctx) {
39743ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
39753ff40c12SJohn Marino 			   " for discconnection due to fatal failure",
39763ff40c12SJohn Marino 			   MAC2STR(sm->addr));
39773ff40c12SJohn Marino 		sm->Disconnect = TRUE;
39783ff40c12SJohn Marino 	}
39793ff40c12SJohn Marino 
39803ff40c12SJohn Marino 	return 0;
39813ff40c12SJohn Marino }
39823ff40c12SJohn Marino 
39833ff40c12SJohn Marino 
wpa_group_fatal_failure(struct wpa_authenticator * wpa_auth,struct wpa_group * group)39843ff40c12SJohn Marino static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
39853ff40c12SJohn Marino 				    struct wpa_group *group)
39863ff40c12SJohn Marino {
39873ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
39883ff40c12SJohn Marino 	group->changed = TRUE;
39893ff40c12SJohn Marino 	group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
39903ff40c12SJohn Marino 	wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
39913ff40c12SJohn Marino }
39923ff40c12SJohn Marino 
39933ff40c12SJohn Marino 
wpa_group_setkeysdone(struct wpa_authenticator * wpa_auth,struct wpa_group * group)39943ff40c12SJohn Marino static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
39953ff40c12SJohn Marino 				 struct wpa_group *group)
39963ff40c12SJohn Marino {
39973ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
39983ff40c12SJohn Marino 		   "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
39993ff40c12SJohn Marino 	group->changed = TRUE;
40003ff40c12SJohn Marino 	group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
40013ff40c12SJohn Marino 
40023ff40c12SJohn Marino 	if (wpa_group_config_group_keys(wpa_auth, group) < 0) {
40033ff40c12SJohn Marino 		wpa_group_fatal_failure(wpa_auth, group);
40043ff40c12SJohn Marino 		return -1;
40053ff40c12SJohn Marino 	}
40063ff40c12SJohn Marino 
40073ff40c12SJohn Marino 	return 0;
40083ff40c12SJohn Marino }
40093ff40c12SJohn Marino 
40103ff40c12SJohn Marino 
wpa_group_sm_step(struct wpa_authenticator * wpa_auth,struct wpa_group * group)40113ff40c12SJohn Marino static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
40123ff40c12SJohn Marino 			      struct wpa_group *group)
40133ff40c12SJohn Marino {
40143ff40c12SJohn Marino 	if (group->GInit) {
40153ff40c12SJohn Marino 		wpa_group_gtk_init(wpa_auth, group);
40163ff40c12SJohn Marino 	} else if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) {
40173ff40c12SJohn Marino 		/* Do not allow group operations */
40183ff40c12SJohn Marino 	} else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
40193ff40c12SJohn Marino 		   group->GTKAuthenticator) {
40203ff40c12SJohn Marino 		wpa_group_setkeysdone(wpa_auth, group);
40213ff40c12SJohn Marino 	} else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE &&
40223ff40c12SJohn Marino 		   group->GTKReKey) {
40233ff40c12SJohn Marino 		wpa_group_setkeys(wpa_auth, group);
40243ff40c12SJohn Marino 	} else if (group->wpa_group_state == WPA_GROUP_SETKEYS) {
40253ff40c12SJohn Marino 		if (group->GKeyDoneStations == 0)
40263ff40c12SJohn Marino 			wpa_group_setkeysdone(wpa_auth, group);
40273ff40c12SJohn Marino 		else if (group->GTKReKey)
40283ff40c12SJohn Marino 			wpa_group_setkeys(wpa_auth, group);
40293ff40c12SJohn Marino 	}
40303ff40c12SJohn Marino }
40313ff40c12SJohn Marino 
40323ff40c12SJohn Marino 
wpa_sm_step(struct wpa_state_machine * sm)40333ff40c12SJohn Marino static int wpa_sm_step(struct wpa_state_machine *sm)
40343ff40c12SJohn Marino {
40353ff40c12SJohn Marino 	if (sm == NULL)
40363ff40c12SJohn Marino 		return 0;
40373ff40c12SJohn Marino 
40383ff40c12SJohn Marino 	if (sm->in_step_loop) {
40393ff40c12SJohn Marino 		/* This should not happen, but if it does, make sure we do not
40403ff40c12SJohn Marino 		 * end up freeing the state machine too early by exiting the
40413ff40c12SJohn Marino 		 * recursive call. */
40423ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively");
40433ff40c12SJohn Marino 		return 0;
40443ff40c12SJohn Marino 	}
40453ff40c12SJohn Marino 
40463ff40c12SJohn Marino 	sm->in_step_loop = 1;
40473ff40c12SJohn Marino 	do {
40483ff40c12SJohn Marino 		if (sm->pending_deinit)
40493ff40c12SJohn Marino 			break;
40503ff40c12SJohn Marino 
40513ff40c12SJohn Marino 		sm->changed = FALSE;
40523ff40c12SJohn Marino 		sm->wpa_auth->group->changed = FALSE;
40533ff40c12SJohn Marino 
40543ff40c12SJohn Marino 		SM_STEP_RUN(WPA_PTK);
40553ff40c12SJohn Marino 		if (sm->pending_deinit)
40563ff40c12SJohn Marino 			break;
40573ff40c12SJohn Marino 		SM_STEP_RUN(WPA_PTK_GROUP);
40583ff40c12SJohn Marino 		if (sm->pending_deinit)
40593ff40c12SJohn Marino 			break;
40603ff40c12SJohn Marino 		wpa_group_sm_step(sm->wpa_auth, sm->group);
40613ff40c12SJohn Marino 	} while (sm->changed || sm->wpa_auth->group->changed);
40623ff40c12SJohn Marino 	sm->in_step_loop = 0;
40633ff40c12SJohn Marino 
40643ff40c12SJohn Marino 	if (sm->pending_deinit) {
40653ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
40663ff40c12SJohn Marino 			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
40673ff40c12SJohn Marino 		wpa_free_sta_sm(sm);
40683ff40c12SJohn Marino 		return 1;
40693ff40c12SJohn Marino 	}
40703ff40c12SJohn Marino 	return 0;
40713ff40c12SJohn Marino }
40723ff40c12SJohn Marino 
40733ff40c12SJohn Marino 
wpa_sm_call_step(void * eloop_ctx,void * timeout_ctx)40743ff40c12SJohn Marino static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
40753ff40c12SJohn Marino {
40763ff40c12SJohn Marino 	struct wpa_state_machine *sm = eloop_ctx;
40773ff40c12SJohn Marino 	wpa_sm_step(sm);
40783ff40c12SJohn Marino }
40793ff40c12SJohn Marino 
40803ff40c12SJohn Marino 
wpa_auth_sm_notify(struct wpa_state_machine * sm)40813ff40c12SJohn Marino void wpa_auth_sm_notify(struct wpa_state_machine *sm)
40823ff40c12SJohn Marino {
40833ff40c12SJohn Marino 	if (sm == NULL)
40843ff40c12SJohn Marino 		return;
40853ff40c12SJohn Marino 	eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
40863ff40c12SJohn Marino }
40873ff40c12SJohn Marino 
40883ff40c12SJohn Marino 
wpa_gtk_rekey(struct wpa_authenticator * wpa_auth)40893ff40c12SJohn Marino void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
40903ff40c12SJohn Marino {
40913ff40c12SJohn Marino 	int tmp, i;
40923ff40c12SJohn Marino 	struct wpa_group *group;
40933ff40c12SJohn Marino 
40943ff40c12SJohn Marino 	if (wpa_auth == NULL)
40953ff40c12SJohn Marino 		return;
40963ff40c12SJohn Marino 
40973ff40c12SJohn Marino 	group = wpa_auth->group;
40983ff40c12SJohn Marino 
40993ff40c12SJohn Marino 	for (i = 0; i < 2; i++) {
41003ff40c12SJohn Marino 		tmp = group->GM;
41013ff40c12SJohn Marino 		group->GM = group->GN;
41023ff40c12SJohn Marino 		group->GN = tmp;
41033ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
41043ff40c12SJohn Marino 		tmp = group->GM_igtk;
41053ff40c12SJohn Marino 		group->GM_igtk = group->GN_igtk;
41063ff40c12SJohn Marino 		group->GN_igtk = tmp;
41073ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
41083ff40c12SJohn Marino 		wpa_gtk_update(wpa_auth, group);
41093ff40c12SJohn Marino 		wpa_group_config_group_keys(wpa_auth, group);
41103ff40c12SJohn Marino 	}
41113ff40c12SJohn Marino }
41123ff40c12SJohn Marino 
41133ff40c12SJohn Marino 
wpa_bool_txt(int val)4114*a1157835SDaniel Fojt static const char * wpa_bool_txt(int val)
41153ff40c12SJohn Marino {
4116*a1157835SDaniel Fojt 	return val ? "TRUE" : "FALSE";
41173ff40c12SJohn Marino }
41183ff40c12SJohn Marino 
41193ff40c12SJohn Marino 
41203ff40c12SJohn Marino #define RSN_SUITE "%02x-%02x-%02x-%d"
41213ff40c12SJohn Marino #define RSN_SUITE_ARG(s) \
41223ff40c12SJohn Marino ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
41233ff40c12SJohn Marino 
wpa_get_mib(struct wpa_authenticator * wpa_auth,char * buf,size_t buflen)41243ff40c12SJohn Marino int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
41253ff40c12SJohn Marino {
41263ff40c12SJohn Marino 	int len = 0, ret;
41273ff40c12SJohn Marino 	char pmkid_txt[PMKID_LEN * 2 + 1];
41283ff40c12SJohn Marino #ifdef CONFIG_RSN_PREAUTH
41293ff40c12SJohn Marino 	const int preauth = 1;
41303ff40c12SJohn Marino #else /* CONFIG_RSN_PREAUTH */
41313ff40c12SJohn Marino 	const int preauth = 0;
41323ff40c12SJohn Marino #endif /* CONFIG_RSN_PREAUTH */
41333ff40c12SJohn Marino 
41343ff40c12SJohn Marino 	if (wpa_auth == NULL)
41353ff40c12SJohn Marino 		return len;
41363ff40c12SJohn Marino 
41373ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
41383ff40c12SJohn Marino 			  "dot11RSNAOptionImplemented=TRUE\n"
41393ff40c12SJohn Marino 			  "dot11RSNAPreauthenticationImplemented=%s\n"
41403ff40c12SJohn Marino 			  "dot11RSNAEnabled=%s\n"
41413ff40c12SJohn Marino 			  "dot11RSNAPreauthenticationEnabled=%s\n",
41423ff40c12SJohn Marino 			  wpa_bool_txt(preauth),
41433ff40c12SJohn Marino 			  wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
41443ff40c12SJohn Marino 			  wpa_bool_txt(wpa_auth->conf.rsn_preauth));
4145*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
41463ff40c12SJohn Marino 		return len;
41473ff40c12SJohn Marino 	len += ret;
41483ff40c12SJohn Marino 
41493ff40c12SJohn Marino 	wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
41503ff40c12SJohn Marino 			 wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN);
41513ff40c12SJohn Marino 
41523ff40c12SJohn Marino 	ret = os_snprintf(
41533ff40c12SJohn Marino 		buf + len, buflen - len,
41543ff40c12SJohn Marino 		"dot11RSNAConfigVersion=%u\n"
41553ff40c12SJohn Marino 		"dot11RSNAConfigPairwiseKeysSupported=9999\n"
41563ff40c12SJohn Marino 		/* FIX: dot11RSNAConfigGroupCipher */
41573ff40c12SJohn Marino 		/* FIX: dot11RSNAConfigGroupRekeyMethod */
41583ff40c12SJohn Marino 		/* FIX: dot11RSNAConfigGroupRekeyTime */
41593ff40c12SJohn Marino 		/* FIX: dot11RSNAConfigGroupRekeyPackets */
41603ff40c12SJohn Marino 		"dot11RSNAConfigGroupRekeyStrict=%u\n"
41613ff40c12SJohn Marino 		"dot11RSNAConfigGroupUpdateCount=%u\n"
41623ff40c12SJohn Marino 		"dot11RSNAConfigPairwiseUpdateCount=%u\n"
41633ff40c12SJohn Marino 		"dot11RSNAConfigGroupCipherSize=%u\n"
41643ff40c12SJohn Marino 		"dot11RSNAConfigPMKLifetime=%u\n"
41653ff40c12SJohn Marino 		"dot11RSNAConfigPMKReauthThreshold=%u\n"
41663ff40c12SJohn Marino 		"dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n"
41673ff40c12SJohn Marino 		"dot11RSNAConfigSATimeout=%u\n"
41683ff40c12SJohn Marino 		"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
41693ff40c12SJohn Marino 		"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
41703ff40c12SJohn Marino 		"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
41713ff40c12SJohn Marino 		"dot11RSNAPMKIDUsed=%s\n"
41723ff40c12SJohn Marino 		"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
41733ff40c12SJohn Marino 		"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
41743ff40c12SJohn Marino 		"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
41753ff40c12SJohn Marino 		"dot11RSNATKIPCounterMeasuresInvoked=%u\n"
41763ff40c12SJohn Marino 		"dot11RSNA4WayHandshakeFailures=%u\n"
41773ff40c12SJohn Marino 		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
41783ff40c12SJohn Marino 		RSN_VERSION,
41793ff40c12SJohn Marino 		!!wpa_auth->conf.wpa_strict_rekey,
4180*a1157835SDaniel Fojt 		wpa_auth->conf.wpa_group_update_count,
4181*a1157835SDaniel Fojt 		wpa_auth->conf.wpa_pairwise_update_count,
41823ff40c12SJohn Marino 		wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
41833ff40c12SJohn Marino 		dot11RSNAConfigPMKLifetime,
41843ff40c12SJohn Marino 		dot11RSNAConfigPMKReauthThreshold,
41853ff40c12SJohn Marino 		dot11RSNAConfigSATimeout,
41863ff40c12SJohn Marino 		RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteSelected),
41873ff40c12SJohn Marino 		RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherSelected),
41883ff40c12SJohn Marino 		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected),
41893ff40c12SJohn Marino 		pmkid_txt,
41903ff40c12SJohn Marino 		RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteRequested),
41913ff40c12SJohn Marino 		RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherRequested),
41923ff40c12SJohn Marino 		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
41933ff40c12SJohn Marino 		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
41943ff40c12SJohn Marino 		wpa_auth->dot11RSNA4WayHandshakeFailures);
4195*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
41963ff40c12SJohn Marino 		return len;
41973ff40c12SJohn Marino 	len += ret;
41983ff40c12SJohn Marino 
41993ff40c12SJohn Marino 	/* TODO: dot11RSNAConfigPairwiseCiphersTable */
42003ff40c12SJohn Marino 	/* TODO: dot11RSNAConfigAuthenticationSuitesTable */
42013ff40c12SJohn Marino 
42023ff40c12SJohn Marino 	/* Private MIB */
42033ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
42043ff40c12SJohn Marino 			  wpa_auth->group->wpa_group_state);
4205*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
42063ff40c12SJohn Marino 		return len;
42073ff40c12SJohn Marino 	len += ret;
42083ff40c12SJohn Marino 
42093ff40c12SJohn Marino 	return len;
42103ff40c12SJohn Marino }
42113ff40c12SJohn Marino 
42123ff40c12SJohn Marino 
wpa_get_mib_sta(struct wpa_state_machine * sm,char * buf,size_t buflen)42133ff40c12SJohn Marino int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
42143ff40c12SJohn Marino {
42153ff40c12SJohn Marino 	int len = 0, ret;
42163ff40c12SJohn Marino 	u32 pairwise = 0;
42173ff40c12SJohn Marino 
42183ff40c12SJohn Marino 	if (sm == NULL)
42193ff40c12SJohn Marino 		return 0;
42203ff40c12SJohn Marino 
42213ff40c12SJohn Marino 	/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
42223ff40c12SJohn Marino 
42233ff40c12SJohn Marino 	/* dot11RSNAStatsEntry */
42243ff40c12SJohn Marino 
42253ff40c12SJohn Marino 	pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ?
42263ff40c12SJohn Marino 				       WPA_PROTO_RSN : WPA_PROTO_WPA,
42273ff40c12SJohn Marino 				       sm->pairwise);
42283ff40c12SJohn Marino 	if (pairwise == 0)
42293ff40c12SJohn Marino 		return 0;
42303ff40c12SJohn Marino 
42313ff40c12SJohn Marino 	ret = os_snprintf(
42323ff40c12SJohn Marino 		buf + len, buflen - len,
42333ff40c12SJohn Marino 		/* TODO: dot11RSNAStatsIndex */
42343ff40c12SJohn Marino 		"dot11RSNAStatsSTAAddress=" MACSTR "\n"
42353ff40c12SJohn Marino 		"dot11RSNAStatsVersion=1\n"
42363ff40c12SJohn Marino 		"dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
42373ff40c12SJohn Marino 		/* TODO: dot11RSNAStatsTKIPICVErrors */
42383ff40c12SJohn Marino 		"dot11RSNAStatsTKIPLocalMICFailures=%u\n"
42393ff40c12SJohn Marino 		"dot11RSNAStatsTKIPRemoteMICFailures=%u\n"
42403ff40c12SJohn Marino 		/* TODO: dot11RSNAStatsCCMPReplays */
42413ff40c12SJohn Marino 		/* TODO: dot11RSNAStatsCCMPDecryptErrors */
42423ff40c12SJohn Marino 		/* TODO: dot11RSNAStatsTKIPReplays */,
42433ff40c12SJohn Marino 		MAC2STR(sm->addr),
42443ff40c12SJohn Marino 		RSN_SUITE_ARG(pairwise),
42453ff40c12SJohn Marino 		sm->dot11RSNAStatsTKIPLocalMICFailures,
42463ff40c12SJohn Marino 		sm->dot11RSNAStatsTKIPRemoteMICFailures);
4247*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
42483ff40c12SJohn Marino 		return len;
42493ff40c12SJohn Marino 	len += ret;
42503ff40c12SJohn Marino 
42513ff40c12SJohn Marino 	/* Private MIB */
42523ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
4253*a1157835SDaniel Fojt 			  "wpa=%d\n"
4254*a1157835SDaniel Fojt 			  "AKMSuiteSelector=" RSN_SUITE "\n"
42553ff40c12SJohn Marino 			  "hostapdWPAPTKState=%d\n"
42563ff40c12SJohn Marino 			  "hostapdWPAPTKGroupState=%d\n",
4257*a1157835SDaniel Fojt 			  sm->wpa,
4258*a1157835SDaniel Fojt 			  RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)),
42593ff40c12SJohn Marino 			  sm->wpa_ptk_state,
42603ff40c12SJohn Marino 			  sm->wpa_ptk_group_state);
4261*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
42623ff40c12SJohn Marino 		return len;
42633ff40c12SJohn Marino 	len += ret;
42643ff40c12SJohn Marino 
42653ff40c12SJohn Marino 	return len;
42663ff40c12SJohn Marino }
42673ff40c12SJohn Marino 
42683ff40c12SJohn Marino 
wpa_auth_countermeasures_start(struct wpa_authenticator * wpa_auth)42693ff40c12SJohn Marino void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth)
42703ff40c12SJohn Marino {
42713ff40c12SJohn Marino 	if (wpa_auth)
42723ff40c12SJohn Marino 		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
42733ff40c12SJohn Marino }
42743ff40c12SJohn Marino 
42753ff40c12SJohn Marino 
wpa_auth_pairwise_set(struct wpa_state_machine * sm)42763ff40c12SJohn Marino int wpa_auth_pairwise_set(struct wpa_state_machine *sm)
42773ff40c12SJohn Marino {
42783ff40c12SJohn Marino 	return sm && sm->pairwise_set;
42793ff40c12SJohn Marino }
42803ff40c12SJohn Marino 
42813ff40c12SJohn Marino 
wpa_auth_get_pairwise(struct wpa_state_machine * sm)42823ff40c12SJohn Marino int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
42833ff40c12SJohn Marino {
42843ff40c12SJohn Marino 	return sm->pairwise;
42853ff40c12SJohn Marino }
42863ff40c12SJohn Marino 
42873ff40c12SJohn Marino 
wpa_auth_get_pmk(struct wpa_state_machine * sm,int * len)4288*a1157835SDaniel Fojt const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
4289*a1157835SDaniel Fojt {
4290*a1157835SDaniel Fojt 	if (!sm)
4291*a1157835SDaniel Fojt 		return NULL;
4292*a1157835SDaniel Fojt 	*len = sm->pmk_len;
4293*a1157835SDaniel Fojt 	return sm->PMK;
4294*a1157835SDaniel Fojt }
4295*a1157835SDaniel Fojt 
4296*a1157835SDaniel Fojt 
wpa_auth_sta_key_mgmt(struct wpa_state_machine * sm)42973ff40c12SJohn Marino int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
42983ff40c12SJohn Marino {
42993ff40c12SJohn Marino 	if (sm == NULL)
43003ff40c12SJohn Marino 		return -1;
43013ff40c12SJohn Marino 	return sm->wpa_key_mgmt;
43023ff40c12SJohn Marino }
43033ff40c12SJohn Marino 
43043ff40c12SJohn Marino 
wpa_auth_sta_wpa_version(struct wpa_state_machine * sm)43053ff40c12SJohn Marino int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
43063ff40c12SJohn Marino {
43073ff40c12SJohn Marino 	if (sm == NULL)
43083ff40c12SJohn Marino 		return 0;
43093ff40c12SJohn Marino 	return sm->wpa;
43103ff40c12SJohn Marino }
43113ff40c12SJohn Marino 
43123ff40c12SJohn Marino 
wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine * sm)4313*a1157835SDaniel Fojt int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
4314*a1157835SDaniel Fojt {
4315*a1157835SDaniel Fojt 	if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt))
4316*a1157835SDaniel Fojt 		return 0;
4317*a1157835SDaniel Fojt 	return sm->tk_already_set;
4318*a1157835SDaniel Fojt }
4319*a1157835SDaniel Fojt 
4320*a1157835SDaniel Fojt 
wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine * sm)4321*a1157835SDaniel Fojt int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm)
4322*a1157835SDaniel Fojt {
4323*a1157835SDaniel Fojt 	if (!sm || !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
4324*a1157835SDaniel Fojt 		return 0;
4325*a1157835SDaniel Fojt 	return sm->tk_already_set;
4326*a1157835SDaniel Fojt }
4327*a1157835SDaniel Fojt 
4328*a1157835SDaniel Fojt 
wpa_auth_sta_clear_pmksa(struct wpa_state_machine * sm,struct rsn_pmksa_cache_entry * entry)43293ff40c12SJohn Marino int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
43303ff40c12SJohn Marino 			     struct rsn_pmksa_cache_entry *entry)
43313ff40c12SJohn Marino {
43323ff40c12SJohn Marino 	if (sm == NULL || sm->pmksa != entry)
43333ff40c12SJohn Marino 		return -1;
43343ff40c12SJohn Marino 	sm->pmksa = NULL;
43353ff40c12SJohn Marino 	return 0;
43363ff40c12SJohn Marino }
43373ff40c12SJohn Marino 
43383ff40c12SJohn Marino 
43393ff40c12SJohn Marino struct rsn_pmksa_cache_entry *
wpa_auth_sta_get_pmksa(struct wpa_state_machine * sm)43403ff40c12SJohn Marino wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm)
43413ff40c12SJohn Marino {
43423ff40c12SJohn Marino 	return sm ? sm->pmksa : NULL;
43433ff40c12SJohn Marino }
43443ff40c12SJohn Marino 
43453ff40c12SJohn Marino 
wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine * sm)43463ff40c12SJohn Marino void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
43473ff40c12SJohn Marino {
43483ff40c12SJohn Marino 	if (sm)
43493ff40c12SJohn Marino 		sm->dot11RSNAStatsTKIPLocalMICFailures++;
43503ff40c12SJohn Marino }
43513ff40c12SJohn Marino 
43523ff40c12SJohn Marino 
wpa_auth_get_wpa_ie(struct wpa_authenticator * wpa_auth,size_t * len)43533ff40c12SJohn Marino const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
43543ff40c12SJohn Marino {
43553ff40c12SJohn Marino 	if (wpa_auth == NULL)
43563ff40c12SJohn Marino 		return NULL;
43573ff40c12SJohn Marino 	*len = wpa_auth->wpa_ie_len;
43583ff40c12SJohn Marino 	return wpa_auth->wpa_ie;
43593ff40c12SJohn Marino }
43603ff40c12SJohn Marino 
43613ff40c12SJohn Marino 
wpa_auth_pmksa_add(struct wpa_state_machine * sm,const u8 * pmk,unsigned int pmk_len,int session_timeout,struct eapol_state_machine * eapol)43623ff40c12SJohn Marino int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
4363*a1157835SDaniel Fojt 		       unsigned int pmk_len,
43643ff40c12SJohn Marino 		       int session_timeout, struct eapol_state_machine *eapol)
43653ff40c12SJohn Marino {
43663ff40c12SJohn Marino 	if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
43673ff40c12SJohn Marino 	    sm->wpa_auth->conf.disable_pmksa_caching)
43683ff40c12SJohn Marino 		return -1;
43693ff40c12SJohn Marino 
4370*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
4371*a1157835SDaniel Fojt 	if (pmk_len >= 2 * PMK_LEN && wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
4372*a1157835SDaniel Fojt 	    wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
4373*a1157835SDaniel Fojt 	    !wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
4374*a1157835SDaniel Fojt 		/* Cache MPMK/XXKey instead of initial part from MSK */
4375*a1157835SDaniel Fojt 		pmk = pmk + PMK_LEN;
4376*a1157835SDaniel Fojt 		pmk_len = PMK_LEN;
4377*a1157835SDaniel Fojt 	} else
4378*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
4379*a1157835SDaniel Fojt 	if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
4380*a1157835SDaniel Fojt 		if (pmk_len > PMK_LEN_SUITE_B_192)
4381*a1157835SDaniel Fojt 			pmk_len = PMK_LEN_SUITE_B_192;
4382*a1157835SDaniel Fojt 	} else if (pmk_len > PMK_LEN) {
4383*a1157835SDaniel Fojt 		pmk_len = PMK_LEN;
4384*a1157835SDaniel Fojt 	}
4385*a1157835SDaniel Fojt 
4386*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
4387*a1157835SDaniel Fojt 	if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
4388*a1157835SDaniel Fojt 				 sm->PTK.kck, sm->PTK.kck_len,
43893ff40c12SJohn Marino 				 sm->wpa_auth->addr, sm->addr, session_timeout,
43903ff40c12SJohn Marino 				 eapol, sm->wpa_key_mgmt))
43913ff40c12SJohn Marino 		return 0;
43923ff40c12SJohn Marino 
43933ff40c12SJohn Marino 	return -1;
43943ff40c12SJohn Marino }
43953ff40c12SJohn Marino 
43963ff40c12SJohn Marino 
wpa_auth_pmksa_add_preauth(struct wpa_authenticator * wpa_auth,const u8 * pmk,size_t len,const u8 * sta_addr,int session_timeout,struct eapol_state_machine * eapol)43973ff40c12SJohn Marino int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
43983ff40c12SJohn Marino 			       const u8 *pmk, size_t len, const u8 *sta_addr,
43993ff40c12SJohn Marino 			       int session_timeout,
44003ff40c12SJohn Marino 			       struct eapol_state_machine *eapol)
44013ff40c12SJohn Marino {
44023ff40c12SJohn Marino 	if (wpa_auth == NULL)
44033ff40c12SJohn Marino 		return -1;
44043ff40c12SJohn Marino 
4405*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
4406*a1157835SDaniel Fojt 	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
4407*a1157835SDaniel Fojt 				 NULL, 0,
4408*a1157835SDaniel Fojt 				 wpa_auth->addr,
44093ff40c12SJohn Marino 				 sta_addr, session_timeout, eapol,
44103ff40c12SJohn Marino 				 WPA_KEY_MGMT_IEEE8021X))
44113ff40c12SJohn Marino 		return 0;
44123ff40c12SJohn Marino 
44133ff40c12SJohn Marino 	return -1;
44143ff40c12SJohn Marino }
44153ff40c12SJohn Marino 
44163ff40c12SJohn Marino 
wpa_auth_pmksa_add_sae(struct wpa_authenticator * wpa_auth,const u8 * addr,const u8 * pmk,const u8 * pmkid)4417*a1157835SDaniel Fojt int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
4418*a1157835SDaniel Fojt 			   const u8 *pmk, const u8 *pmkid)
4419*a1157835SDaniel Fojt {
4420*a1157835SDaniel Fojt 	if (wpa_auth->conf.disable_pmksa_caching)
4421*a1157835SDaniel Fojt 		return -1;
4422*a1157835SDaniel Fojt 
4423*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN);
4424*a1157835SDaniel Fojt 	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
4425*a1157835SDaniel Fojt 				 NULL, 0,
4426*a1157835SDaniel Fojt 				 wpa_auth->addr, addr, 0, NULL,
4427*a1157835SDaniel Fojt 				 WPA_KEY_MGMT_SAE))
4428*a1157835SDaniel Fojt 		return 0;
4429*a1157835SDaniel Fojt 
4430*a1157835SDaniel Fojt 	return -1;
4431*a1157835SDaniel Fojt }
4432*a1157835SDaniel Fojt 
4433*a1157835SDaniel Fojt 
wpa_auth_add_sae_pmkid(struct wpa_state_machine * sm,const u8 * pmkid)4434*a1157835SDaniel Fojt void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid)
4435*a1157835SDaniel Fojt {
4436*a1157835SDaniel Fojt 	os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
4437*a1157835SDaniel Fojt 	sm->pmkid_set = 1;
4438*a1157835SDaniel Fojt }
4439*a1157835SDaniel Fojt 
4440*a1157835SDaniel Fojt 
wpa_auth_pmksa_add2(struct wpa_authenticator * wpa_auth,const u8 * addr,const u8 * pmk,size_t pmk_len,const u8 * pmkid,int session_timeout,int akmp)4441*a1157835SDaniel Fojt int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
4442*a1157835SDaniel Fojt 			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
4443*a1157835SDaniel Fojt 			int session_timeout, int akmp)
4444*a1157835SDaniel Fojt {
4445*a1157835SDaniel Fojt 	if (wpa_auth->conf.disable_pmksa_caching)
4446*a1157835SDaniel Fojt 		return -1;
4447*a1157835SDaniel Fojt 
4448*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
4449*a1157835SDaniel Fojt 	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
4450*a1157835SDaniel Fojt 				 NULL, 0, wpa_auth->addr, addr, session_timeout,
4451*a1157835SDaniel Fojt 				 NULL, akmp))
4452*a1157835SDaniel Fojt 		return 0;
4453*a1157835SDaniel Fojt 
4454*a1157835SDaniel Fojt 	return -1;
4455*a1157835SDaniel Fojt }
4456*a1157835SDaniel Fojt 
4457*a1157835SDaniel Fojt 
wpa_auth_pmksa_remove(struct wpa_authenticator * wpa_auth,const u8 * sta_addr)44583ff40c12SJohn Marino void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
44593ff40c12SJohn Marino 			   const u8 *sta_addr)
44603ff40c12SJohn Marino {
44613ff40c12SJohn Marino 	struct rsn_pmksa_cache_entry *pmksa;
44623ff40c12SJohn Marino 
44633ff40c12SJohn Marino 	if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
44643ff40c12SJohn Marino 		return;
44653ff40c12SJohn Marino 	pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
44663ff40c12SJohn Marino 	if (pmksa) {
44673ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
44683ff40c12SJohn Marino 			   MACSTR " based on request", MAC2STR(sta_addr));
44693ff40c12SJohn Marino 		pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
44703ff40c12SJohn Marino 	}
44713ff40c12SJohn Marino }
44723ff40c12SJohn Marino 
44733ff40c12SJohn Marino 
wpa_auth_pmksa_list(struct wpa_authenticator * wpa_auth,char * buf,size_t len)4474*a1157835SDaniel Fojt int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
4475*a1157835SDaniel Fojt 			size_t len)
4476*a1157835SDaniel Fojt {
4477*a1157835SDaniel Fojt 	if (!wpa_auth || !wpa_auth->pmksa)
4478*a1157835SDaniel Fojt 		return 0;
4479*a1157835SDaniel Fojt 	return pmksa_cache_auth_list(wpa_auth->pmksa, buf, len);
4480*a1157835SDaniel Fojt }
4481*a1157835SDaniel Fojt 
4482*a1157835SDaniel Fojt 
wpa_auth_pmksa_flush(struct wpa_authenticator * wpa_auth)4483*a1157835SDaniel Fojt void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
4484*a1157835SDaniel Fojt {
4485*a1157835SDaniel Fojt 	if (wpa_auth && wpa_auth->pmksa)
4486*a1157835SDaniel Fojt 		pmksa_cache_auth_flush(wpa_auth->pmksa);
4487*a1157835SDaniel Fojt }
4488*a1157835SDaniel Fojt 
4489*a1157835SDaniel Fojt 
4490*a1157835SDaniel Fojt #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
4491*a1157835SDaniel Fojt #ifdef CONFIG_MESH
4492*a1157835SDaniel Fojt 
wpa_auth_pmksa_list_mesh(struct wpa_authenticator * wpa_auth,const u8 * addr,char * buf,size_t len)4493*a1157835SDaniel Fojt int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
4494*a1157835SDaniel Fojt 			     char *buf, size_t len)
4495*a1157835SDaniel Fojt {
4496*a1157835SDaniel Fojt 	if (!wpa_auth || !wpa_auth->pmksa)
4497*a1157835SDaniel Fojt 		return 0;
4498*a1157835SDaniel Fojt 
4499*a1157835SDaniel Fojt 	return pmksa_cache_auth_list_mesh(wpa_auth->pmksa, addr, buf, len);
4500*a1157835SDaniel Fojt }
4501*a1157835SDaniel Fojt 
4502*a1157835SDaniel Fojt 
4503*a1157835SDaniel Fojt struct rsn_pmksa_cache_entry *
wpa_auth_pmksa_create_entry(const u8 * aa,const u8 * spa,const u8 * pmk,const u8 * pmkid,int expiration)4504*a1157835SDaniel Fojt wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
4505*a1157835SDaniel Fojt 			    const u8 *pmkid, int expiration)
4506*a1157835SDaniel Fojt {
4507*a1157835SDaniel Fojt 	struct rsn_pmksa_cache_entry *entry;
4508*a1157835SDaniel Fojt 	struct os_reltime now;
4509*a1157835SDaniel Fojt 
4510*a1157835SDaniel Fojt 	entry = pmksa_cache_auth_create_entry(pmk, PMK_LEN, pmkid, NULL, 0, aa,
4511*a1157835SDaniel Fojt 					      spa, 0, NULL, WPA_KEY_MGMT_SAE);
4512*a1157835SDaniel Fojt 	if (!entry)
4513*a1157835SDaniel Fojt 		return NULL;
4514*a1157835SDaniel Fojt 
4515*a1157835SDaniel Fojt 	os_get_reltime(&now);
4516*a1157835SDaniel Fojt 	entry->expiration = now.sec + expiration;
4517*a1157835SDaniel Fojt 	return entry;
4518*a1157835SDaniel Fojt }
4519*a1157835SDaniel Fojt 
4520*a1157835SDaniel Fojt 
wpa_auth_pmksa_add_entry(struct wpa_authenticator * wpa_auth,struct rsn_pmksa_cache_entry * entry)4521*a1157835SDaniel Fojt int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
4522*a1157835SDaniel Fojt 			     struct rsn_pmksa_cache_entry *entry)
4523*a1157835SDaniel Fojt {
4524*a1157835SDaniel Fojt 	int ret;
4525*a1157835SDaniel Fojt 
4526*a1157835SDaniel Fojt 	if (!wpa_auth || !wpa_auth->pmksa)
4527*a1157835SDaniel Fojt 		return -1;
4528*a1157835SDaniel Fojt 
4529*a1157835SDaniel Fojt 	ret = pmksa_cache_auth_add_entry(wpa_auth->pmksa, entry);
4530*a1157835SDaniel Fojt 	if (ret < 0)
4531*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
4532*a1157835SDaniel Fojt 			   "RSN: Failed to store external PMKSA cache for "
4533*a1157835SDaniel Fojt 			   MACSTR, MAC2STR(entry->spa));
4534*a1157835SDaniel Fojt 
4535*a1157835SDaniel Fojt 	return ret;
4536*a1157835SDaniel Fojt }
4537*a1157835SDaniel Fojt 
4538*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
4539*a1157835SDaniel Fojt #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
4540*a1157835SDaniel Fojt 
4541*a1157835SDaniel Fojt 
4542*a1157835SDaniel Fojt struct rsn_pmksa_cache_entry *
wpa_auth_pmksa_get(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,const u8 * pmkid)4543*a1157835SDaniel Fojt wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
4544*a1157835SDaniel Fojt 		   const u8 *pmkid)
4545*a1157835SDaniel Fojt {
4546*a1157835SDaniel Fojt 	if (!wpa_auth || !wpa_auth->pmksa)
4547*a1157835SDaniel Fojt 		return NULL;
4548*a1157835SDaniel Fojt 	return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, pmkid);
4549*a1157835SDaniel Fojt }
4550*a1157835SDaniel Fojt 
4551*a1157835SDaniel Fojt 
wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry * pmksa,struct wpa_state_machine * sm,struct wpa_authenticator * wpa_auth,u8 * pmkid,u8 * pmk)4552*a1157835SDaniel Fojt void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
4553*a1157835SDaniel Fojt 			      struct wpa_state_machine *sm,
4554*a1157835SDaniel Fojt 			      struct wpa_authenticator *wpa_auth,
4555*a1157835SDaniel Fojt 			      u8 *pmkid, u8 *pmk)
4556*a1157835SDaniel Fojt {
4557*a1157835SDaniel Fojt 	if (!sm)
4558*a1157835SDaniel Fojt 		return;
4559*a1157835SDaniel Fojt 
4560*a1157835SDaniel Fojt 	sm->pmksa = pmksa;
4561*a1157835SDaniel Fojt 	os_memcpy(pmk, pmksa->pmk, PMK_LEN);
4562*a1157835SDaniel Fojt 	os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN);
4563*a1157835SDaniel Fojt 	os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN);
4564*a1157835SDaniel Fojt }
4565*a1157835SDaniel Fojt 
4566*a1157835SDaniel Fojt 
4567*a1157835SDaniel Fojt /*
4568*a1157835SDaniel Fojt  * Remove and free the group from wpa_authenticator. This is triggered by a
4569*a1157835SDaniel Fojt  * callback to make sure nobody is currently iterating the group list while it
4570*a1157835SDaniel Fojt  * gets modified.
4571*a1157835SDaniel Fojt  */
wpa_group_free(struct wpa_authenticator * wpa_auth,struct wpa_group * group)4572*a1157835SDaniel Fojt static void wpa_group_free(struct wpa_authenticator *wpa_auth,
4573*a1157835SDaniel Fojt 			   struct wpa_group *group)
4574*a1157835SDaniel Fojt {
4575*a1157835SDaniel Fojt 	struct wpa_group *prev = wpa_auth->group;
4576*a1157835SDaniel Fojt 
4577*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "WPA: Remove group state machine for VLAN-ID %d",
4578*a1157835SDaniel Fojt 		   group->vlan_id);
4579*a1157835SDaniel Fojt 
4580*a1157835SDaniel Fojt 	while (prev) {
4581*a1157835SDaniel Fojt 		if (prev->next == group) {
4582*a1157835SDaniel Fojt 			/* This never frees the special first group as needed */
4583*a1157835SDaniel Fojt 			prev->next = group->next;
4584*a1157835SDaniel Fojt 			os_free(group);
4585*a1157835SDaniel Fojt 			break;
4586*a1157835SDaniel Fojt 		}
4587*a1157835SDaniel Fojt 		prev = prev->next;
4588*a1157835SDaniel Fojt 	}
4589*a1157835SDaniel Fojt 
4590*a1157835SDaniel Fojt }
4591*a1157835SDaniel Fojt 
4592*a1157835SDaniel Fojt 
4593*a1157835SDaniel Fojt /* Increase the reference counter for group */
wpa_group_get(struct wpa_authenticator * wpa_auth,struct wpa_group * group)4594*a1157835SDaniel Fojt static void wpa_group_get(struct wpa_authenticator *wpa_auth,
4595*a1157835SDaniel Fojt 			  struct wpa_group *group)
4596*a1157835SDaniel Fojt {
4597*a1157835SDaniel Fojt 	/* Skip the special first group */
4598*a1157835SDaniel Fojt 	if (wpa_auth->group == group)
4599*a1157835SDaniel Fojt 		return;
4600*a1157835SDaniel Fojt 
4601*a1157835SDaniel Fojt 	group->references++;
4602*a1157835SDaniel Fojt }
4603*a1157835SDaniel Fojt 
4604*a1157835SDaniel Fojt 
4605*a1157835SDaniel Fojt /* Decrease the reference counter and maybe free the group */
wpa_group_put(struct wpa_authenticator * wpa_auth,struct wpa_group * group)4606*a1157835SDaniel Fojt static void wpa_group_put(struct wpa_authenticator *wpa_auth,
4607*a1157835SDaniel Fojt 			  struct wpa_group *group)
4608*a1157835SDaniel Fojt {
4609*a1157835SDaniel Fojt 	/* Skip the special first group */
4610*a1157835SDaniel Fojt 	if (wpa_auth->group == group)
4611*a1157835SDaniel Fojt 		return;
4612*a1157835SDaniel Fojt 
4613*a1157835SDaniel Fojt 	group->references--;
4614*a1157835SDaniel Fojt 	if (group->references)
4615*a1157835SDaniel Fojt 		return;
4616*a1157835SDaniel Fojt 	wpa_group_free(wpa_auth, group);
4617*a1157835SDaniel Fojt }
4618*a1157835SDaniel Fojt 
4619*a1157835SDaniel Fojt 
4620*a1157835SDaniel Fojt /*
4621*a1157835SDaniel Fojt  * Add a group that has its references counter set to zero. Caller needs to
4622*a1157835SDaniel Fojt  * call wpa_group_get() on the return value to mark the entry in use.
4623*a1157835SDaniel Fojt  */
46243ff40c12SJohn Marino static struct wpa_group *
wpa_auth_add_group(struct wpa_authenticator * wpa_auth,int vlan_id)46253ff40c12SJohn Marino wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
46263ff40c12SJohn Marino {
46273ff40c12SJohn Marino 	struct wpa_group *group;
46283ff40c12SJohn Marino 
46293ff40c12SJohn Marino 	if (wpa_auth == NULL || wpa_auth->group == NULL)
46303ff40c12SJohn Marino 		return NULL;
46313ff40c12SJohn Marino 
46323ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
46333ff40c12SJohn Marino 		   vlan_id);
46343ff40c12SJohn Marino 	group = wpa_group_init(wpa_auth, vlan_id, 0);
46353ff40c12SJohn Marino 	if (group == NULL)
46363ff40c12SJohn Marino 		return NULL;
46373ff40c12SJohn Marino 
46383ff40c12SJohn Marino 	group->next = wpa_auth->group->next;
46393ff40c12SJohn Marino 	wpa_auth->group->next = group;
46403ff40c12SJohn Marino 
46413ff40c12SJohn Marino 	return group;
46423ff40c12SJohn Marino }
46433ff40c12SJohn Marino 
46443ff40c12SJohn Marino 
4645*a1157835SDaniel Fojt /*
4646*a1157835SDaniel Fojt  * Enforce that the group state machine for the VLAN is running, increase
4647*a1157835SDaniel Fojt  * reference counter as interface is up. References might have been increased
4648*a1157835SDaniel Fojt  * even if a negative value is returned.
4649*a1157835SDaniel Fojt  * Returns: -1 on error (group missing, group already failed); otherwise, 0
4650*a1157835SDaniel Fojt  */
wpa_auth_ensure_group(struct wpa_authenticator * wpa_auth,int vlan_id)4651*a1157835SDaniel Fojt int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
4652*a1157835SDaniel Fojt {
4653*a1157835SDaniel Fojt 	struct wpa_group *group;
4654*a1157835SDaniel Fojt 
4655*a1157835SDaniel Fojt 	if (wpa_auth == NULL)
4656*a1157835SDaniel Fojt 		return 0;
4657*a1157835SDaniel Fojt 
4658*a1157835SDaniel Fojt 	group = wpa_auth->group;
4659*a1157835SDaniel Fojt 	while (group) {
4660*a1157835SDaniel Fojt 		if (group->vlan_id == vlan_id)
4661*a1157835SDaniel Fojt 			break;
4662*a1157835SDaniel Fojt 		group = group->next;
4663*a1157835SDaniel Fojt 	}
4664*a1157835SDaniel Fojt 
4665*a1157835SDaniel Fojt 	if (group == NULL) {
4666*a1157835SDaniel Fojt 		group = wpa_auth_add_group(wpa_auth, vlan_id);
4667*a1157835SDaniel Fojt 		if (group == NULL)
4668*a1157835SDaniel Fojt 			return -1;
4669*a1157835SDaniel Fojt 	}
4670*a1157835SDaniel Fojt 
4671*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
4672*a1157835SDaniel Fojt 		   "WPA: Ensure group state machine running for VLAN ID %d",
4673*a1157835SDaniel Fojt 		   vlan_id);
4674*a1157835SDaniel Fojt 
4675*a1157835SDaniel Fojt 	wpa_group_get(wpa_auth, group);
4676*a1157835SDaniel Fojt 	group->num_setup_iface++;
4677*a1157835SDaniel Fojt 
4678*a1157835SDaniel Fojt 	if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
4679*a1157835SDaniel Fojt 		return -1;
4680*a1157835SDaniel Fojt 
4681*a1157835SDaniel Fojt 	return 0;
4682*a1157835SDaniel Fojt }
4683*a1157835SDaniel Fojt 
4684*a1157835SDaniel Fojt 
4685*a1157835SDaniel Fojt /*
4686*a1157835SDaniel Fojt  * Decrease reference counter, expected to be zero afterwards.
4687*a1157835SDaniel Fojt  * returns: -1 on error (group not found, group in fail state)
4688*a1157835SDaniel Fojt  *          -2 if wpa_group is still referenced
4689*a1157835SDaniel Fojt  *           0 else
4690*a1157835SDaniel Fojt  */
wpa_auth_release_group(struct wpa_authenticator * wpa_auth,int vlan_id)4691*a1157835SDaniel Fojt int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
4692*a1157835SDaniel Fojt {
4693*a1157835SDaniel Fojt 	struct wpa_group *group;
4694*a1157835SDaniel Fojt 	int ret = 0;
4695*a1157835SDaniel Fojt 
4696*a1157835SDaniel Fojt 	if (wpa_auth == NULL)
4697*a1157835SDaniel Fojt 		return 0;
4698*a1157835SDaniel Fojt 
4699*a1157835SDaniel Fojt 	group = wpa_auth->group;
4700*a1157835SDaniel Fojt 	while (group) {
4701*a1157835SDaniel Fojt 		if (group->vlan_id == vlan_id)
4702*a1157835SDaniel Fojt 			break;
4703*a1157835SDaniel Fojt 		group = group->next;
4704*a1157835SDaniel Fojt 	}
4705*a1157835SDaniel Fojt 
4706*a1157835SDaniel Fojt 	if (group == NULL)
4707*a1157835SDaniel Fojt 		return -1;
4708*a1157835SDaniel Fojt 
4709*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
4710*a1157835SDaniel Fojt 		   "WPA: Try stopping group state machine for VLAN ID %d",
4711*a1157835SDaniel Fojt 		   vlan_id);
4712*a1157835SDaniel Fojt 
4713*a1157835SDaniel Fojt 	if (group->num_setup_iface <= 0) {
4714*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
4715*a1157835SDaniel Fojt 			   "WPA: wpa_auth_release_group called more often than wpa_auth_ensure_group for VLAN ID %d, skipping.",
4716*a1157835SDaniel Fojt 			   vlan_id);
4717*a1157835SDaniel Fojt 		return -1;
4718*a1157835SDaniel Fojt 	}
4719*a1157835SDaniel Fojt 	group->num_setup_iface--;
4720*a1157835SDaniel Fojt 
4721*a1157835SDaniel Fojt 	if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
4722*a1157835SDaniel Fojt 		ret = -1;
4723*a1157835SDaniel Fojt 
4724*a1157835SDaniel Fojt 	if (group->references > 1) {
4725*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
4726*a1157835SDaniel Fojt 			   "WPA: Cannot stop group state machine for VLAN ID %d as references are still hold",
4727*a1157835SDaniel Fojt 			   vlan_id);
4728*a1157835SDaniel Fojt 		ret = -2;
4729*a1157835SDaniel Fojt 	}
4730*a1157835SDaniel Fojt 
4731*a1157835SDaniel Fojt 	wpa_group_put(wpa_auth, group);
4732*a1157835SDaniel Fojt 
4733*a1157835SDaniel Fojt 	return ret;
4734*a1157835SDaniel Fojt }
4735*a1157835SDaniel Fojt 
4736*a1157835SDaniel Fojt 
wpa_auth_sta_set_vlan(struct wpa_state_machine * sm,int vlan_id)47373ff40c12SJohn Marino int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
47383ff40c12SJohn Marino {
47393ff40c12SJohn Marino 	struct wpa_group *group;
47403ff40c12SJohn Marino 
47413ff40c12SJohn Marino 	if (sm == NULL || sm->wpa_auth == NULL)
47423ff40c12SJohn Marino 		return 0;
47433ff40c12SJohn Marino 
47443ff40c12SJohn Marino 	group = sm->wpa_auth->group;
47453ff40c12SJohn Marino 	while (group) {
47463ff40c12SJohn Marino 		if (group->vlan_id == vlan_id)
47473ff40c12SJohn Marino 			break;
47483ff40c12SJohn Marino 		group = group->next;
47493ff40c12SJohn Marino 	}
47503ff40c12SJohn Marino 
47513ff40c12SJohn Marino 	if (group == NULL) {
47523ff40c12SJohn Marino 		group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
47533ff40c12SJohn Marino 		if (group == NULL)
47543ff40c12SJohn Marino 			return -1;
47553ff40c12SJohn Marino 	}
47563ff40c12SJohn Marino 
47573ff40c12SJohn Marino 	if (sm->group == group)
47583ff40c12SJohn Marino 		return 0;
47593ff40c12SJohn Marino 
47603ff40c12SJohn Marino 	if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
47613ff40c12SJohn Marino 		return -1;
47623ff40c12SJohn Marino 
47633ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
47643ff40c12SJohn Marino 		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
47653ff40c12SJohn Marino 
4766*a1157835SDaniel Fojt 	wpa_group_get(sm->wpa_auth, group);
4767*a1157835SDaniel Fojt 	wpa_group_put(sm->wpa_auth, sm->group);
47683ff40c12SJohn Marino 	sm->group = group;
4769*a1157835SDaniel Fojt 
47703ff40c12SJohn Marino 	return 0;
47713ff40c12SJohn Marino }
47723ff40c12SJohn Marino 
47733ff40c12SJohn Marino 
wpa_auth_eapol_key_tx_status(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,int ack)47743ff40c12SJohn Marino void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
47753ff40c12SJohn Marino 				  struct wpa_state_machine *sm, int ack)
47763ff40c12SJohn Marino {
47773ff40c12SJohn Marino 	if (wpa_auth == NULL || sm == NULL)
47783ff40c12SJohn Marino 		return;
47793ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
47803ff40c12SJohn Marino 		   " ack=%d", MAC2STR(sm->addr), ack);
47813ff40c12SJohn Marino 	if (sm->pending_1_of_4_timeout && ack) {
47823ff40c12SJohn Marino 		/*
47833ff40c12SJohn Marino 		 * Some deployed supplicant implementations update their SNonce
47843ff40c12SJohn Marino 		 * for each EAPOL-Key 2/4 message even within the same 4-way
47853ff40c12SJohn Marino 		 * handshake and then fail to use the first SNonce when
47863ff40c12SJohn Marino 		 * deriving the PTK. This results in unsuccessful 4-way
47873ff40c12SJohn Marino 		 * handshake whenever the relatively short initial timeout is
47883ff40c12SJohn Marino 		 * reached and EAPOL-Key 1/4 is retransmitted. Try to work
47893ff40c12SJohn Marino 		 * around this by increasing the timeout now that we know that
47903ff40c12SJohn Marino 		 * the station has received the frame.
47913ff40c12SJohn Marino 		 */
47923ff40c12SJohn Marino 		int timeout_ms = eapol_key_timeout_subseq;
47933ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
47943ff40c12SJohn Marino 			   "timeout by %u ms because of acknowledged frame",
47953ff40c12SJohn Marino 			   timeout_ms);
47963ff40c12SJohn Marino 		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
47973ff40c12SJohn Marino 		eloop_register_timeout(timeout_ms / 1000,
47983ff40c12SJohn Marino 				       (timeout_ms % 1000) * 1000,
47993ff40c12SJohn Marino 				       wpa_send_eapol_timeout, wpa_auth, sm);
48003ff40c12SJohn Marino 	}
4801*a1157835SDaniel Fojt 
4802*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
4803*a1157835SDaniel Fojt 	if (sm->eapol_status_cb) {
4804*a1157835SDaniel Fojt 		sm->eapol_status_cb(sm->eapol_status_cb_ctx1,
4805*a1157835SDaniel Fojt 				    sm->eapol_status_cb_ctx2);
4806*a1157835SDaniel Fojt 		sm->eapol_status_cb = NULL;
4807*a1157835SDaniel Fojt 	}
4808*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
48093ff40c12SJohn Marino }
48103ff40c12SJohn Marino 
48113ff40c12SJohn Marino 
wpa_auth_uses_sae(struct wpa_state_machine * sm)48123ff40c12SJohn Marino int wpa_auth_uses_sae(struct wpa_state_machine *sm)
48133ff40c12SJohn Marino {
48143ff40c12SJohn Marino 	if (sm == NULL)
48153ff40c12SJohn Marino 		return 0;
48163ff40c12SJohn Marino 	return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
48173ff40c12SJohn Marino }
48183ff40c12SJohn Marino 
48193ff40c12SJohn Marino 
wpa_auth_uses_ft_sae(struct wpa_state_machine * sm)48203ff40c12SJohn Marino int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
48213ff40c12SJohn Marino {
48223ff40c12SJohn Marino 	if (sm == NULL)
48233ff40c12SJohn Marino 		return 0;
48243ff40c12SJohn Marino 	return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
48253ff40c12SJohn Marino }
48263ff40c12SJohn Marino 
48273ff40c12SJohn Marino 
48283ff40c12SJohn Marino #ifdef CONFIG_P2P
wpa_auth_get_ip_addr(struct wpa_state_machine * sm,u8 * addr)48293ff40c12SJohn Marino int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
48303ff40c12SJohn Marino {
48313ff40c12SJohn Marino 	if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
48323ff40c12SJohn Marino 		return -1;
48333ff40c12SJohn Marino 	os_memcpy(addr, sm->ip_addr, 4);
48343ff40c12SJohn Marino 	return 0;
48353ff40c12SJohn Marino }
48363ff40c12SJohn Marino #endif /* CONFIG_P2P */
4837*a1157835SDaniel Fojt 
4838*a1157835SDaniel Fojt 
wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator * wpa_auth,struct radius_das_attrs * attr)4839*a1157835SDaniel Fojt int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
4840*a1157835SDaniel Fojt 					 struct radius_das_attrs *attr)
4841*a1157835SDaniel Fojt {
4842*a1157835SDaniel Fojt 	return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
4843*a1157835SDaniel Fojt }
4844*a1157835SDaniel Fojt 
4845*a1157835SDaniel Fojt 
wpa_auth_reconfig_group_keys(struct wpa_authenticator * wpa_auth)4846*a1157835SDaniel Fojt void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth)
4847*a1157835SDaniel Fojt {
4848*a1157835SDaniel Fojt 	struct wpa_group *group;
4849*a1157835SDaniel Fojt 
4850*a1157835SDaniel Fojt 	if (!wpa_auth)
4851*a1157835SDaniel Fojt 		return;
4852*a1157835SDaniel Fojt 	for (group = wpa_auth->group; group; group = group->next)
4853*a1157835SDaniel Fojt 		wpa_group_config_group_keys(wpa_auth, group);
4854*a1157835SDaniel Fojt }
4855*a1157835SDaniel Fojt 
4856*a1157835SDaniel Fojt 
4857*a1157835SDaniel Fojt #ifdef CONFIG_FILS
4858*a1157835SDaniel Fojt 
4859*a1157835SDaniel Fojt struct wpa_auth_fils_iter_data {
4860*a1157835SDaniel Fojt 	struct wpa_authenticator *auth;
4861*a1157835SDaniel Fojt 	const u8 *cache_id;
4862*a1157835SDaniel Fojt 	struct rsn_pmksa_cache_entry *pmksa;
4863*a1157835SDaniel Fojt 	const u8 *spa;
4864*a1157835SDaniel Fojt 	const u8 *pmkid;
4865*a1157835SDaniel Fojt };
4866*a1157835SDaniel Fojt 
4867*a1157835SDaniel Fojt 
wpa_auth_fils_iter(struct wpa_authenticator * a,void * ctx)4868*a1157835SDaniel Fojt static int wpa_auth_fils_iter(struct wpa_authenticator *a, void *ctx)
4869*a1157835SDaniel Fojt {
4870*a1157835SDaniel Fojt 	struct wpa_auth_fils_iter_data *data = ctx;
4871*a1157835SDaniel Fojt 
4872*a1157835SDaniel Fojt 	if (a == data->auth || !a->conf.fils_cache_id_set ||
4873*a1157835SDaniel Fojt 	    os_memcmp(a->conf.fils_cache_id, data->cache_id,
4874*a1157835SDaniel Fojt 		      FILS_CACHE_ID_LEN) != 0)
4875*a1157835SDaniel Fojt 		return 0;
4876*a1157835SDaniel Fojt 	data->pmksa = pmksa_cache_auth_get(a->pmksa, data->spa, data->pmkid);
4877*a1157835SDaniel Fojt 	return data->pmksa != NULL;
4878*a1157835SDaniel Fojt }
4879*a1157835SDaniel Fojt 
4880*a1157835SDaniel Fojt 
4881*a1157835SDaniel Fojt struct rsn_pmksa_cache_entry *
wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,const u8 * pmkid)4882*a1157835SDaniel Fojt wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth,
4883*a1157835SDaniel Fojt 				 const u8 *sta_addr, const u8 *pmkid)
4884*a1157835SDaniel Fojt {
4885*a1157835SDaniel Fojt 	struct wpa_auth_fils_iter_data idata;
4886*a1157835SDaniel Fojt 
4887*a1157835SDaniel Fojt 	if (!wpa_auth->conf.fils_cache_id_set)
4888*a1157835SDaniel Fojt 		return NULL;
4889*a1157835SDaniel Fojt 	idata.auth = wpa_auth;
4890*a1157835SDaniel Fojt 	idata.cache_id = wpa_auth->conf.fils_cache_id;
4891*a1157835SDaniel Fojt 	idata.pmksa = NULL;
4892*a1157835SDaniel Fojt 	idata.spa = sta_addr;
4893*a1157835SDaniel Fojt 	idata.pmkid = pmkid;
4894*a1157835SDaniel Fojt 	wpa_auth_for_each_auth(wpa_auth, wpa_auth_fils_iter, &idata);
4895*a1157835SDaniel Fojt 	return idata.pmksa;
4896*a1157835SDaniel Fojt }
4897*a1157835SDaniel Fojt 
4898*a1157835SDaniel Fojt 
4899*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
wpa_auth_write_fte(struct wpa_authenticator * wpa_auth,int use_sha384,u8 * buf,size_t len)4900*a1157835SDaniel Fojt int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
4901*a1157835SDaniel Fojt 		       u8 *buf, size_t len)
4902*a1157835SDaniel Fojt {
4903*a1157835SDaniel Fojt 	struct wpa_auth_config *conf = &wpa_auth->conf;
4904*a1157835SDaniel Fojt 
4905*a1157835SDaniel Fojt 	return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
4906*a1157835SDaniel Fojt 			      conf->r0_key_holder_len,
4907*a1157835SDaniel Fojt 			      NULL, NULL, buf, len, NULL, 0);
4908*a1157835SDaniel Fojt }
4909*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
4910*a1157835SDaniel Fojt 
4911*a1157835SDaniel Fojt 
wpa_auth_get_fils_aead_params(struct wpa_state_machine * sm,u8 * fils_anonce,u8 * fils_snonce,u8 * fils_kek,size_t * fils_kek_len)4912*a1157835SDaniel Fojt void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
4913*a1157835SDaniel Fojt 				   u8 *fils_anonce, u8 *fils_snonce,
4914*a1157835SDaniel Fojt 				   u8 *fils_kek, size_t *fils_kek_len)
4915*a1157835SDaniel Fojt {
4916*a1157835SDaniel Fojt 	os_memcpy(fils_anonce, sm->ANonce, WPA_NONCE_LEN);
4917*a1157835SDaniel Fojt 	os_memcpy(fils_snonce, sm->SNonce, WPA_NONCE_LEN);
4918*a1157835SDaniel Fojt 	os_memcpy(fils_kek, sm->PTK.kek, WPA_KEK_MAX_LEN);
4919*a1157835SDaniel Fojt 	*fils_kek_len = sm->PTK.kek_len;
4920*a1157835SDaniel Fojt }
4921*a1157835SDaniel Fojt 
4922*a1157835SDaniel Fojt 
wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine * sm,const u8 * pmk,size_t pmk_len,const u8 * pmkid)4923*a1157835SDaniel Fojt void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
4924*a1157835SDaniel Fojt 				 size_t pmk_len, const u8 *pmkid)
4925*a1157835SDaniel Fojt {
4926*a1157835SDaniel Fojt 	os_memcpy(sm->PMK, pmk, pmk_len);
4927*a1157835SDaniel Fojt 	sm->pmk_len = pmk_len;
4928*a1157835SDaniel Fojt 	os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
4929*a1157835SDaniel Fojt 	sm->pmkid_set = 1;
4930*a1157835SDaniel Fojt }
4931*a1157835SDaniel Fojt 
4932*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
4933*a1157835SDaniel Fojt 
4934*a1157835SDaniel Fojt 
wpa_auth_set_auth_alg(struct wpa_state_machine * sm,u16 auth_alg)4935*a1157835SDaniel Fojt void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
4936*a1157835SDaniel Fojt {
4937*a1157835SDaniel Fojt 	if (sm)
4938*a1157835SDaniel Fojt 		sm->auth_alg = auth_alg;
4939*a1157835SDaniel Fojt }
4940*a1157835SDaniel Fojt 
4941*a1157835SDaniel Fojt 
4942*a1157835SDaniel Fojt #ifdef CONFIG_DPP2
wpa_auth_set_dpp_z(struct wpa_state_machine * sm,const struct wpabuf * z)4943*a1157835SDaniel Fojt void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
4944*a1157835SDaniel Fojt {
4945*a1157835SDaniel Fojt 	if (sm) {
4946*a1157835SDaniel Fojt 		wpabuf_clear_free(sm->dpp_z);
4947*a1157835SDaniel Fojt 		sm->dpp_z = z ? wpabuf_dup(z) : NULL;
4948*a1157835SDaniel Fojt 	}
4949*a1157835SDaniel Fojt }
4950*a1157835SDaniel Fojt #endif /* CONFIG_DPP2 */
4951*a1157835SDaniel Fojt 
4952*a1157835SDaniel Fojt 
4953*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
4954*a1157835SDaniel Fojt 
wpa_auth_resend_m1(struct wpa_state_machine * sm,int change_anonce,void (* cb)(void * ctx1,void * ctx2),void * ctx1,void * ctx2)4955*a1157835SDaniel Fojt int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
4956*a1157835SDaniel Fojt 		       void (*cb)(void *ctx1, void *ctx2),
4957*a1157835SDaniel Fojt 		       void *ctx1, void *ctx2)
4958*a1157835SDaniel Fojt {
4959*a1157835SDaniel Fojt 	const u8 *anonce = sm->ANonce;
4960*a1157835SDaniel Fojt 	u8 anonce_buf[WPA_NONCE_LEN];
4961*a1157835SDaniel Fojt 
4962*a1157835SDaniel Fojt 	if (change_anonce) {
4963*a1157835SDaniel Fojt 		if (random_get_bytes(anonce_buf, WPA_NONCE_LEN))
4964*a1157835SDaniel Fojt 			return -1;
4965*a1157835SDaniel Fojt 		anonce = anonce_buf;
4966*a1157835SDaniel Fojt 	}
4967*a1157835SDaniel Fojt 
4968*a1157835SDaniel Fojt 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
4969*a1157835SDaniel Fojt 			"sending 1/4 msg of 4-Way Handshake (TESTING)");
4970*a1157835SDaniel Fojt 	wpa_send_eapol(sm->wpa_auth, sm,
4971*a1157835SDaniel Fojt 		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
4972*a1157835SDaniel Fojt 		       anonce, NULL, 0, 0, 0);
4973*a1157835SDaniel Fojt 	return 0;
4974*a1157835SDaniel Fojt }
4975*a1157835SDaniel Fojt 
4976*a1157835SDaniel Fojt 
wpa_auth_resend_m3(struct wpa_state_machine * sm,void (* cb)(void * ctx1,void * ctx2),void * ctx1,void * ctx2)4977*a1157835SDaniel Fojt int wpa_auth_resend_m3(struct wpa_state_machine *sm,
4978*a1157835SDaniel Fojt 		       void (*cb)(void *ctx1, void *ctx2),
4979*a1157835SDaniel Fojt 		       void *ctx1, void *ctx2)
4980*a1157835SDaniel Fojt {
4981*a1157835SDaniel Fojt 	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
4982*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211W
4983*a1157835SDaniel Fojt 	u8 *opos;
4984*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211W */
4985*a1157835SDaniel Fojt 	size_t gtk_len, kde_len;
4986*a1157835SDaniel Fojt 	struct wpa_group *gsm = sm->group;
4987*a1157835SDaniel Fojt 	u8 *wpa_ie;
4988*a1157835SDaniel Fojt 	int wpa_ie_len, secure, keyidx, encr = 0;
4989*a1157835SDaniel Fojt 
4990*a1157835SDaniel Fojt 	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
4991*a1157835SDaniel Fojt 	   GTK[GN], IGTK, [FTIE], [TIE * 2])
4992*a1157835SDaniel Fojt 	 */
4993*a1157835SDaniel Fojt 
4994*a1157835SDaniel Fojt 	/* Use 0 RSC */
4995*a1157835SDaniel Fojt 	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
4996*a1157835SDaniel Fojt 	/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
4997*a1157835SDaniel Fojt 	wpa_ie = sm->wpa_auth->wpa_ie;
4998*a1157835SDaniel Fojt 	wpa_ie_len = sm->wpa_auth->wpa_ie_len;
4999*a1157835SDaniel Fojt 	if (sm->wpa == WPA_VERSION_WPA &&
5000*a1157835SDaniel Fojt 	    (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
5001*a1157835SDaniel Fojt 	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
5002*a1157835SDaniel Fojt 		/* WPA-only STA, remove RSN IE and possible MDIE */
5003*a1157835SDaniel Fojt 		wpa_ie = wpa_ie + wpa_ie[1] + 2;
5004*a1157835SDaniel Fojt 		if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
5005*a1157835SDaniel Fojt 			wpa_ie = wpa_ie + wpa_ie[1] + 2;
5006*a1157835SDaniel Fojt 		wpa_ie_len = wpa_ie[1] + 2;
5007*a1157835SDaniel Fojt 	}
5008*a1157835SDaniel Fojt 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
5009*a1157835SDaniel Fojt 			"sending 3/4 msg of 4-Way Handshake (TESTING)");
5010*a1157835SDaniel Fojt 	if (sm->wpa == WPA_VERSION_WPA2) {
5011*a1157835SDaniel Fojt 		/* WPA2 send GTK in the 4-way handshake */
5012*a1157835SDaniel Fojt 		secure = 1;
5013*a1157835SDaniel Fojt 		gtk = gsm->GTK[gsm->GN - 1];
5014*a1157835SDaniel Fojt 		gtk_len = gsm->GTK_len;
5015*a1157835SDaniel Fojt 		keyidx = gsm->GN;
5016*a1157835SDaniel Fojt 		_rsc = rsc;
5017*a1157835SDaniel Fojt 		encr = 1;
5018*a1157835SDaniel Fojt 	} else {
5019*a1157835SDaniel Fojt 		/* WPA does not include GTK in msg 3/4 */
5020*a1157835SDaniel Fojt 		secure = 0;
5021*a1157835SDaniel Fojt 		gtk = NULL;
5022*a1157835SDaniel Fojt 		gtk_len = 0;
5023*a1157835SDaniel Fojt 		keyidx = 0;
5024*a1157835SDaniel Fojt 		_rsc = NULL;
5025*a1157835SDaniel Fojt 		if (sm->rx_eapol_key_secure) {
5026*a1157835SDaniel Fojt 			/*
5027*a1157835SDaniel Fojt 			 * It looks like Windows 7 supplicant tries to use
5028*a1157835SDaniel Fojt 			 * Secure bit in msg 2/4 after having reported Michael
5029*a1157835SDaniel Fojt 			 * MIC failure and it then rejects the 4-way handshake
5030*a1157835SDaniel Fojt 			 * if msg 3/4 does not set Secure bit. Work around this
5031*a1157835SDaniel Fojt 			 * by setting the Secure bit here even in the case of
5032*a1157835SDaniel Fojt 			 * WPA if the supplicant used it first.
5033*a1157835SDaniel Fojt 			 */
5034*a1157835SDaniel Fojt 			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
5035*a1157835SDaniel Fojt 					"STA used Secure bit in WPA msg 2/4 - "
5036*a1157835SDaniel Fojt 					"set Secure for 3/4 as workaround");
5037*a1157835SDaniel Fojt 			secure = 1;
5038*a1157835SDaniel Fojt 		}
5039*a1157835SDaniel Fojt 	}
5040*a1157835SDaniel Fojt 
5041*a1157835SDaniel Fojt 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
5042*a1157835SDaniel Fojt 	if (gtk)
5043*a1157835SDaniel Fojt 		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
5044*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
5045*a1157835SDaniel Fojt 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
5046*a1157835SDaniel Fojt 		kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
5047*a1157835SDaniel Fojt 		kde_len += 300; /* FTIE + 2 * TIE */
5048*a1157835SDaniel Fojt 	}
5049*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
5050*a1157835SDaniel Fojt 	kde = os_malloc(kde_len);
5051*a1157835SDaniel Fojt 	if (kde == NULL)
5052*a1157835SDaniel Fojt 		return -1;
5053*a1157835SDaniel Fojt 
5054*a1157835SDaniel Fojt 	pos = kde;
5055*a1157835SDaniel Fojt 	os_memcpy(pos, wpa_ie, wpa_ie_len);
5056*a1157835SDaniel Fojt 	pos += wpa_ie_len;
5057*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
5058*a1157835SDaniel Fojt 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
5059*a1157835SDaniel Fojt 		int res;
5060*a1157835SDaniel Fojt 		size_t elen;
5061*a1157835SDaniel Fojt 
5062*a1157835SDaniel Fojt 		elen = pos - kde;
5063*a1157835SDaniel Fojt 		res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
5064*a1157835SDaniel Fojt 		if (res < 0) {
5065*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR, "FT: Failed to insert "
5066*a1157835SDaniel Fojt 				   "PMKR1Name into RSN IE in EAPOL-Key data");
5067*a1157835SDaniel Fojt 			os_free(kde);
5068*a1157835SDaniel Fojt 			return -1;
5069*a1157835SDaniel Fojt 		}
5070*a1157835SDaniel Fojt 		pos -= wpa_ie_len;
5071*a1157835SDaniel Fojt 		pos += elen;
5072*a1157835SDaniel Fojt 	}
5073*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
5074*a1157835SDaniel Fojt 	if (gtk) {
5075*a1157835SDaniel Fojt 		u8 hdr[2];
5076*a1157835SDaniel Fojt 		hdr[0] = keyidx & 0x03;
5077*a1157835SDaniel Fojt 		hdr[1] = 0;
5078*a1157835SDaniel Fojt 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
5079*a1157835SDaniel Fojt 				  gtk, gtk_len);
5080*a1157835SDaniel Fojt 	}
5081*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211W
5082*a1157835SDaniel Fojt 	opos = pos;
5083*a1157835SDaniel Fojt 	pos = ieee80211w_kde_add(sm, pos);
5084*a1157835SDaniel Fojt 	if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
5085*a1157835SDaniel Fojt 		/* skip KDE header and keyid */
5086*a1157835SDaniel Fojt 		opos += 2 + RSN_SELECTOR_LEN + 2;
5087*a1157835SDaniel Fojt 		os_memset(opos, 0, 6); /* clear PN */
5088*a1157835SDaniel Fojt 	}
5089*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211W */
5090*a1157835SDaniel Fojt 	if (ocv_oci_add(sm, &pos) < 0) {
5091*a1157835SDaniel Fojt 		os_free(kde);
5092*a1157835SDaniel Fojt 		return -1;
5093*a1157835SDaniel Fojt 	}
5094*a1157835SDaniel Fojt 
5095*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
5096*a1157835SDaniel Fojt 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
5097*a1157835SDaniel Fojt 		int res;
5098*a1157835SDaniel Fojt 		struct wpa_auth_config *conf;
5099*a1157835SDaniel Fojt 
5100*a1157835SDaniel Fojt 		conf = &sm->wpa_auth->conf;
5101*a1157835SDaniel Fojt 		if (sm->assoc_resp_ftie &&
5102*a1157835SDaniel Fojt 		    kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
5103*a1157835SDaniel Fojt 			os_memcpy(pos, sm->assoc_resp_ftie,
5104*a1157835SDaniel Fojt 				  2 + sm->assoc_resp_ftie[1]);
5105*a1157835SDaniel Fojt 			res = 2 + sm->assoc_resp_ftie[1];
5106*a1157835SDaniel Fojt 		} else {
5107*a1157835SDaniel Fojt 			int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
5108*a1157835SDaniel Fojt 
5109*a1157835SDaniel Fojt 			res = wpa_write_ftie(conf, use_sha384,
5110*a1157835SDaniel Fojt 					     conf->r0_key_holder,
5111*a1157835SDaniel Fojt 					     conf->r0_key_holder_len,
5112*a1157835SDaniel Fojt 					     NULL, NULL, pos,
5113*a1157835SDaniel Fojt 					     kde + kde_len - pos,
5114*a1157835SDaniel Fojt 					     NULL, 0);
5115*a1157835SDaniel Fojt 		}
5116*a1157835SDaniel Fojt 		if (res < 0) {
5117*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
5118*a1157835SDaniel Fojt 				   "into EAPOL-Key Key Data");
5119*a1157835SDaniel Fojt 			os_free(kde);
5120*a1157835SDaniel Fojt 			return -1;
5121*a1157835SDaniel Fojt 		}
5122*a1157835SDaniel Fojt 		pos += res;
5123*a1157835SDaniel Fojt 
5124*a1157835SDaniel Fojt 		/* TIE[ReassociationDeadline] (TU) */
5125*a1157835SDaniel Fojt 		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
5126*a1157835SDaniel Fojt 		*pos++ = 5;
5127*a1157835SDaniel Fojt 		*pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
5128*a1157835SDaniel Fojt 		WPA_PUT_LE32(pos, conf->reassociation_deadline);
5129*a1157835SDaniel Fojt 		pos += 4;
5130*a1157835SDaniel Fojt 
5131*a1157835SDaniel Fojt 		/* TIE[KeyLifetime] (seconds) */
5132*a1157835SDaniel Fojt 		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
5133*a1157835SDaniel Fojt 		*pos++ = 5;
5134*a1157835SDaniel Fojt 		*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
5135*a1157835SDaniel Fojt 		WPA_PUT_LE32(pos, conf->r0_key_lifetime);
5136*a1157835SDaniel Fojt 		pos += 4;
5137*a1157835SDaniel Fojt 	}
5138*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
5139*a1157835SDaniel Fojt 
5140*a1157835SDaniel Fojt 	wpa_send_eapol(sm->wpa_auth, sm,
5141*a1157835SDaniel Fojt 		       (secure ? WPA_KEY_INFO_SECURE : 0) |
5142*a1157835SDaniel Fojt 		       (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
5143*a1157835SDaniel Fojt 			WPA_KEY_INFO_MIC : 0) |
5144*a1157835SDaniel Fojt 		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
5145*a1157835SDaniel Fojt 		       WPA_KEY_INFO_KEY_TYPE,
5146*a1157835SDaniel Fojt 		       _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
5147*a1157835SDaniel Fojt 	os_free(kde);
5148*a1157835SDaniel Fojt 	return 0;
5149*a1157835SDaniel Fojt }
5150*a1157835SDaniel Fojt 
5151*a1157835SDaniel Fojt 
wpa_auth_resend_group_m1(struct wpa_state_machine * sm,void (* cb)(void * ctx1,void * ctx2),void * ctx1,void * ctx2)5152*a1157835SDaniel Fojt int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
5153*a1157835SDaniel Fojt 			     void (*cb)(void *ctx1, void *ctx2),
5154*a1157835SDaniel Fojt 			     void *ctx1, void *ctx2)
5155*a1157835SDaniel Fojt {
5156*a1157835SDaniel Fojt 	u8 rsc[WPA_KEY_RSC_LEN];
5157*a1157835SDaniel Fojt 	struct wpa_group *gsm = sm->group;
5158*a1157835SDaniel Fojt 	const u8 *kde;
5159*a1157835SDaniel Fojt 	u8 *kde_buf = NULL, *pos, hdr[2];
5160*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211W
5161*a1157835SDaniel Fojt 	u8 *opos;
5162*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211W */
5163*a1157835SDaniel Fojt 	size_t kde_len;
5164*a1157835SDaniel Fojt 	u8 *gtk;
5165*a1157835SDaniel Fojt 
5166*a1157835SDaniel Fojt 	/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
5167*a1157835SDaniel Fojt 	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
5168*a1157835SDaniel Fojt 	/* Use 0 RSC */
5169*a1157835SDaniel Fojt 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
5170*a1157835SDaniel Fojt 			"sending 1/2 msg of Group Key Handshake (TESTING)");
5171*a1157835SDaniel Fojt 
5172*a1157835SDaniel Fojt 	gtk = gsm->GTK[gsm->GN - 1];
5173*a1157835SDaniel Fojt 	if (sm->wpa == WPA_VERSION_WPA2) {
5174*a1157835SDaniel Fojt 		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
5175*a1157835SDaniel Fojt 			ieee80211w_kde_len(sm) + ocv_oci_len(sm);
5176*a1157835SDaniel Fojt 		kde_buf = os_malloc(kde_len);
5177*a1157835SDaniel Fojt 		if (kde_buf == NULL)
5178*a1157835SDaniel Fojt 			return -1;
5179*a1157835SDaniel Fojt 
5180*a1157835SDaniel Fojt 		kde = pos = kde_buf;
5181*a1157835SDaniel Fojt 		hdr[0] = gsm->GN & 0x03;
5182*a1157835SDaniel Fojt 		hdr[1] = 0;
5183*a1157835SDaniel Fojt 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
5184*a1157835SDaniel Fojt 				  gtk, gsm->GTK_len);
5185*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211W
5186*a1157835SDaniel Fojt 		opos = pos;
5187*a1157835SDaniel Fojt 		pos = ieee80211w_kde_add(sm, pos);
5188*a1157835SDaniel Fojt 		if (pos - opos >=
5189*a1157835SDaniel Fojt 		    2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
5190*a1157835SDaniel Fojt 			/* skip KDE header and keyid */
5191*a1157835SDaniel Fojt 			opos += 2 + RSN_SELECTOR_LEN + 2;
5192*a1157835SDaniel Fojt 			os_memset(opos, 0, 6); /* clear PN */
5193*a1157835SDaniel Fojt 		}
5194*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211W */
5195*a1157835SDaniel Fojt 		if (ocv_oci_add(sm, &pos) < 0) {
5196*a1157835SDaniel Fojt 			os_free(kde_buf);
5197*a1157835SDaniel Fojt 			return -1;
5198*a1157835SDaniel Fojt 		}
5199*a1157835SDaniel Fojt 		kde_len = pos - kde;
5200*a1157835SDaniel Fojt 	} else {
5201*a1157835SDaniel Fojt 		kde = gtk;
5202*a1157835SDaniel Fojt 		kde_len = gsm->GTK_len;
5203*a1157835SDaniel Fojt 	}
5204*a1157835SDaniel Fojt 
5205*a1157835SDaniel Fojt 	sm->eapol_status_cb = cb;
5206*a1157835SDaniel Fojt 	sm->eapol_status_cb_ctx1 = ctx1;
5207*a1157835SDaniel Fojt 	sm->eapol_status_cb_ctx2 = ctx2;
5208*a1157835SDaniel Fojt 
5209*a1157835SDaniel Fojt 	wpa_send_eapol(sm->wpa_auth, sm,
5210*a1157835SDaniel Fojt 		       WPA_KEY_INFO_SECURE |
5211*a1157835SDaniel Fojt 		       (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
5212*a1157835SDaniel Fojt 			WPA_KEY_INFO_MIC : 0) |
5213*a1157835SDaniel Fojt 		       WPA_KEY_INFO_ACK |
5214*a1157835SDaniel Fojt 		       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
5215*a1157835SDaniel Fojt 		       rsc, NULL, kde, kde_len, gsm->GN, 1);
5216*a1157835SDaniel Fojt 
5217*a1157835SDaniel Fojt 	os_free(kde_buf);
5218*a1157835SDaniel Fojt 	return 0;
5219*a1157835SDaniel Fojt }
5220*a1157835SDaniel Fojt 
5221*a1157835SDaniel Fojt 
wpa_auth_rekey_gtk(struct wpa_authenticator * wpa_auth)5222*a1157835SDaniel Fojt int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth)
5223*a1157835SDaniel Fojt {
5224*a1157835SDaniel Fojt 	if (!wpa_auth)
5225*a1157835SDaniel Fojt 		return -1;
5226*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
5227*a1157835SDaniel Fojt 	return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
5228*a1157835SDaniel Fojt }
5229*a1157835SDaniel Fojt 
5230*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
5231