1189251Ssam/*
2189251Ssam * WPA Supplicant - WPA state machine and EAPOL-Key processing
3252726Srpaulo * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#include "common.h"
12214734Srpaulo#include "crypto/aes_wrap.h"
13214734Srpaulo#include "crypto/crypto.h"
14252726Srpaulo#include "crypto/random.h"
15214734Srpaulo#include "common/ieee802_11_defs.h"
16214734Srpaulo#include "eapol_supp/eapol_supp_sm.h"
17189251Ssam#include "wpa.h"
18189251Ssam#include "eloop.h"
19189251Ssam#include "preauth.h"
20189251Ssam#include "pmksa_cache.h"
21189251Ssam#include "wpa_i.h"
22189251Ssam#include "wpa_ie.h"
23189251Ssam#include "peerkey.h"
24189251Ssam
25189251Ssam
26189251Ssam/**
27189251Ssam * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
28189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
29189251Ssam * @kck: Key Confirmation Key (KCK, part of PTK)
30189251Ssam * @ver: Version field from Key Info
31189251Ssam * @dest: Destination address for the frame
32189251Ssam * @proto: Ethertype (usually ETH_P_EAPOL)
33189251Ssam * @msg: EAPOL-Key message
34189251Ssam * @msg_len: Length of message
35189251Ssam * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
36189251Ssam */
37189251Ssamvoid wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
38189251Ssam			int ver, const u8 *dest, u16 proto,
39189251Ssam			u8 *msg, size_t msg_len, u8 *key_mic)
40189251Ssam{
41189251Ssam	if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
42189251Ssam		/*
43189251Ssam		 * Association event was not yet received; try to fetch
44189251Ssam		 * BSSID from the driver.
45189251Ssam		 */
46189251Ssam		if (wpa_sm_get_bssid(sm, sm->bssid) < 0) {
47252726Srpaulo			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
48252726Srpaulo				"WPA: Failed to read BSSID for "
49252726Srpaulo				"EAPOL-Key destination address");
50189251Ssam		} else {
51189251Ssam			dest = sm->bssid;
52252726Srpaulo			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
53252726Srpaulo				"WPA: Use BSSID (" MACSTR
54252726Srpaulo				") as the destination for EAPOL-Key",
55252726Srpaulo				MAC2STR(dest));
56189251Ssam		}
57189251Ssam	}
58214734Srpaulo	if (key_mic &&
59214734Srpaulo	    wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
60252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
61252726Srpaulo			"WPA: Failed to generate EAPOL-Key "
62252726Srpaulo			"version %d MIC", ver);
63214734Srpaulo		goto out;
64214734Srpaulo	}
65252726Srpaulo	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
66252726Srpaulo	wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
67189251Ssam	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
68189251Ssam	wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
69189251Ssam	eapol_sm_notify_tx_eapol_key(sm->eapol);
70214734Srpauloout:
71189251Ssam	os_free(msg);
72189251Ssam}
73189251Ssam
74189251Ssam
75189251Ssam/**
76189251Ssam * wpa_sm_key_request - Send EAPOL-Key Request
77189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
78189251Ssam * @error: Indicate whether this is an Michael MIC error report
79189251Ssam * @pairwise: 1 = error report for pairwise packet, 0 = for group packet
80189251Ssam *
81189251Ssam * Send an EAPOL-Key Request to the current authenticator. This function is
82189251Ssam * used to request rekeying and it is usually called when a local Michael MIC
83189251Ssam * failure is detected.
84189251Ssam */
85189251Ssamvoid wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
86189251Ssam{
87189251Ssam	size_t rlen;
88189251Ssam	struct wpa_eapol_key *reply;
89189251Ssam	int key_info, ver;
90189251Ssam	u8 bssid[ETH_ALEN], *rbuf;
91189251Ssam
92189251Ssam	if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
93189251Ssam		ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
94252726Srpaulo	else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
95189251Ssam		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
96189251Ssam	else
97189251Ssam		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
98189251Ssam
99189251Ssam	if (wpa_sm_get_bssid(sm, bssid) < 0) {
100252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
101252726Srpaulo			"Failed to read BSSID for EAPOL-Key request");
102189251Ssam		return;
103189251Ssam	}
104189251Ssam
105189251Ssam	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
106189251Ssam				  sizeof(*reply), &rlen, (void *) &reply);
107189251Ssam	if (rbuf == NULL)
108189251Ssam		return;
109189251Ssam
110189251Ssam	reply->type = sm->proto == WPA_PROTO_RSN ?
111189251Ssam		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
112189251Ssam	key_info = WPA_KEY_INFO_REQUEST | ver;
113189251Ssam	if (sm->ptk_set)
114189251Ssam		key_info |= WPA_KEY_INFO_MIC;
115189251Ssam	if (error)
116189251Ssam		key_info |= WPA_KEY_INFO_ERROR;
117189251Ssam	if (pairwise)
118189251Ssam		key_info |= WPA_KEY_INFO_KEY_TYPE;
119189251Ssam	WPA_PUT_BE16(reply->key_info, key_info);
120189251Ssam	WPA_PUT_BE16(reply->key_length, 0);
121189251Ssam	os_memcpy(reply->replay_counter, sm->request_counter,
122189251Ssam		  WPA_REPLAY_COUNTER_LEN);
123189251Ssam	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
124189251Ssam
125189251Ssam	WPA_PUT_BE16(reply->key_data_length, 0);
126189251Ssam
127252726Srpaulo	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
128252726Srpaulo		"WPA: Sending EAPOL-Key Request (error=%d "
129252726Srpaulo		"pairwise=%d ptk_set=%d len=%lu)",
130252726Srpaulo		error, pairwise, sm->ptk_set, (unsigned long) rlen);
131189251Ssam	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
132189251Ssam			   rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
133189251Ssam			   reply->key_mic : NULL);
134189251Ssam}
135189251Ssam
136189251Ssam
137189251Ssamstatic int wpa_supplicant_get_pmk(struct wpa_sm *sm,
138189251Ssam				  const unsigned char *src_addr,
139189251Ssam				  const u8 *pmkid)
140189251Ssam{
141189251Ssam	int abort_cached = 0;
142189251Ssam
143189251Ssam	if (pmkid && !sm->cur_pmksa) {
144189251Ssam		/* When using drivers that generate RSN IE, wpa_supplicant may
145189251Ssam		 * not have enough time to get the association information
146189251Ssam		 * event before receiving this 1/4 message, so try to find a
147189251Ssam		 * matching PMKSA cache entry here. */
148252726Srpaulo		sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
149252726Srpaulo						NULL);
150189251Ssam		if (sm->cur_pmksa) {
151252726Srpaulo			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
152252726Srpaulo				"RSN: found matching PMKID from PMKSA cache");
153189251Ssam		} else {
154252726Srpaulo			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
155252726Srpaulo				"RSN: no matching PMKID found");
156189251Ssam			abort_cached = 1;
157189251Ssam		}
158189251Ssam	}
159189251Ssam
160189251Ssam	if (pmkid && sm->cur_pmksa &&
161189251Ssam	    os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
162189251Ssam		wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
163189251Ssam		wpa_sm_set_pmk_from_pmksa(sm);
164189251Ssam		wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
165189251Ssam				sm->pmk, sm->pmk_len);
166189251Ssam		eapol_sm_notify_cached(sm->eapol);
167189251Ssam#ifdef CONFIG_IEEE80211R
168189251Ssam		sm->xxkey_len = 0;
169189251Ssam#endif /* CONFIG_IEEE80211R */
170189251Ssam	} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
171189251Ssam		int res, pmk_len;
172189251Ssam		pmk_len = PMK_LEN;
173189251Ssam		res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
174189251Ssam		if (res) {
175189251Ssam			/*
176189251Ssam			 * EAP-LEAP is an exception from other EAP methods: it
177189251Ssam			 * uses only 16-byte PMK.
178189251Ssam			 */
179189251Ssam			res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
180189251Ssam			pmk_len = 16;
181189251Ssam		} else {
182189251Ssam#ifdef CONFIG_IEEE80211R
183189251Ssam			u8 buf[2 * PMK_LEN];
184189251Ssam			if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
185189251Ssam			{
186189251Ssam				os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN);
187189251Ssam				sm->xxkey_len = PMK_LEN;
188189251Ssam				os_memset(buf, 0, sizeof(buf));
189189251Ssam			}
190189251Ssam#endif /* CONFIG_IEEE80211R */
191189251Ssam		}
192189251Ssam		if (res == 0) {
193252726Srpaulo			struct rsn_pmksa_cache_entry *sa = NULL;
194189251Ssam			wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
195189251Ssam					"machines", sm->pmk, pmk_len);
196189251Ssam			sm->pmk_len = pmk_len;
197252726Srpaulo			if (sm->proto == WPA_PROTO_RSN &&
198252726Srpaulo			    !wpa_key_mgmt_ft(sm->key_mgmt)) {
199252726Srpaulo				sa = pmksa_cache_add(sm->pmksa,
200252726Srpaulo						     sm->pmk, pmk_len,
201252726Srpaulo						     src_addr, sm->own_addr,
202252726Srpaulo						     sm->network_ctx,
203252726Srpaulo						     sm->key_mgmt);
204214734Srpaulo			}
205189251Ssam			if (!sm->cur_pmksa && pmkid &&
206252726Srpaulo			    pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
207252726Srpaulo			{
208252726Srpaulo				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
209252726Srpaulo					"RSN: the new PMK matches with the "
210252726Srpaulo					"PMKID");
211189251Ssam				abort_cached = 0;
212189251Ssam			}
213252726Srpaulo
214252726Srpaulo			if (!sm->cur_pmksa)
215252726Srpaulo				sm->cur_pmksa = sa;
216189251Ssam		} else {
217214734Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
218189251Ssam				"WPA: Failed to get master session key from "
219252726Srpaulo				"EAPOL state machines - key handshake "
220252726Srpaulo				"aborted");
221189251Ssam			if (sm->cur_pmksa) {
222252726Srpaulo				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
223252726Srpaulo					"RSN: Cancelled PMKSA caching "
224252726Srpaulo					"attempt");
225189251Ssam				sm->cur_pmksa = NULL;
226189251Ssam				abort_cached = 1;
227189251Ssam			} else if (!abort_cached) {
228189251Ssam				return -1;
229189251Ssam			}
230189251Ssam		}
231189251Ssam	}
232189251Ssam
233252726Srpaulo	if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
234252726Srpaulo	    !wpa_key_mgmt_ft(sm->key_mgmt)) {
235189251Ssam		/* Send EAPOL-Start to trigger full EAP authentication. */
236189251Ssam		u8 *buf;
237189251Ssam		size_t buflen;
238189251Ssam
239252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
240252726Srpaulo			"RSN: no PMKSA entry found - trigger "
241252726Srpaulo			"full EAP authentication");
242189251Ssam		buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
243189251Ssam					 NULL, 0, &buflen, NULL);
244189251Ssam		if (buf) {
245189251Ssam			wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
246189251Ssam					  buf, buflen);
247189251Ssam			os_free(buf);
248214734Srpaulo			return -2;
249189251Ssam		}
250189251Ssam
251189251Ssam		return -1;
252189251Ssam	}
253189251Ssam
254189251Ssam	return 0;
255189251Ssam}
256189251Ssam
257189251Ssam
258189251Ssam/**
259189251Ssam * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake
260189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
261189251Ssam * @dst: Destination address for the frame
262189251Ssam * @key: Pointer to the EAPOL-Key frame header
263189251Ssam * @ver: Version bits from EAPOL-Key Key Info
264189251Ssam * @nonce: Nonce value for the EAPOL-Key frame
265189251Ssam * @wpa_ie: WPA/RSN IE
266189251Ssam * @wpa_ie_len: Length of the WPA/RSN IE
267189251Ssam * @ptk: PTK to use for keyed hash and encryption
268189251Ssam * Returns: 0 on success, -1 on failure
269189251Ssam */
270189251Ssamint wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
271189251Ssam			       const struct wpa_eapol_key *key,
272189251Ssam			       int ver, const u8 *nonce,
273189251Ssam			       const u8 *wpa_ie, size_t wpa_ie_len,
274189251Ssam			       struct wpa_ptk *ptk)
275189251Ssam{
276189251Ssam	size_t rlen;
277189251Ssam	struct wpa_eapol_key *reply;
278189251Ssam	u8 *rbuf;
279214734Srpaulo	u8 *rsn_ie_buf = NULL;
280189251Ssam
281189251Ssam	if (wpa_ie == NULL) {
282252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - "
283252726Srpaulo			"cannot generate msg 2/4");
284189251Ssam		return -1;
285189251Ssam	}
286189251Ssam
287214734Srpaulo#ifdef CONFIG_IEEE80211R
288214734Srpaulo	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
289214734Srpaulo		int res;
290214734Srpaulo
291214734Srpaulo		/*
292214734Srpaulo		 * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and
293214734Srpaulo		 * FTIE from (Re)Association Response.
294214734Srpaulo		 */
295214734Srpaulo		rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN +
296214734Srpaulo				       sm->assoc_resp_ies_len);
297214734Srpaulo		if (rsn_ie_buf == NULL)
298214734Srpaulo			return -1;
299214734Srpaulo		os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len);
300214734Srpaulo		res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len,
301214734Srpaulo				       sm->pmk_r1_name);
302214734Srpaulo		if (res < 0) {
303214734Srpaulo			os_free(rsn_ie_buf);
304214734Srpaulo			return -1;
305214734Srpaulo		}
306214734Srpaulo		wpa_ie_len += res;
307214734Srpaulo
308214734Srpaulo		if (sm->assoc_resp_ies) {
309214734Srpaulo			os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
310214734Srpaulo				  sm->assoc_resp_ies_len);
311214734Srpaulo			wpa_ie_len += sm->assoc_resp_ies_len;
312214734Srpaulo		}
313214734Srpaulo
314214734Srpaulo		wpa_ie = rsn_ie_buf;
315214734Srpaulo	}
316214734Srpaulo#endif /* CONFIG_IEEE80211R */
317214734Srpaulo
318189251Ssam	wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
319189251Ssam
320189251Ssam	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
321189251Ssam				  NULL, sizeof(*reply) + wpa_ie_len,
322189251Ssam				  &rlen, (void *) &reply);
323214734Srpaulo	if (rbuf == NULL) {
324214734Srpaulo		os_free(rsn_ie_buf);
325189251Ssam		return -1;
326214734Srpaulo	}
327189251Ssam
328189251Ssam	reply->type = sm->proto == WPA_PROTO_RSN ?
329189251Ssam		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
330189251Ssam	WPA_PUT_BE16(reply->key_info,
331189251Ssam		     ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
332189251Ssam	if (sm->proto == WPA_PROTO_RSN)
333189251Ssam		WPA_PUT_BE16(reply->key_length, 0);
334189251Ssam	else
335189251Ssam		os_memcpy(reply->key_length, key->key_length, 2);
336189251Ssam	os_memcpy(reply->replay_counter, key->replay_counter,
337189251Ssam		  WPA_REPLAY_COUNTER_LEN);
338252726Srpaulo	wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
339252726Srpaulo		    WPA_REPLAY_COUNTER_LEN);
340189251Ssam
341189251Ssam	WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
342189251Ssam	os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
343214734Srpaulo	os_free(rsn_ie_buf);
344189251Ssam
345189251Ssam	os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
346189251Ssam
347252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
348189251Ssam	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
349189251Ssam			   rbuf, rlen, reply->key_mic);
350189251Ssam
351189251Ssam	return 0;
352189251Ssam}
353189251Ssam
354189251Ssam
355189251Ssamstatic int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
356189251Ssam			  const struct wpa_eapol_key *key,
357189251Ssam			  struct wpa_ptk *ptk)
358189251Ssam{
359252726Srpaulo	size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
360189251Ssam#ifdef CONFIG_IEEE80211R
361189251Ssam	if (wpa_key_mgmt_ft(sm->key_mgmt))
362209158Srpaulo		return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
363189251Ssam#endif /* CONFIG_IEEE80211R */
364189251Ssam
365189251Ssam	wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
366189251Ssam		       sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
367209158Srpaulo		       (u8 *) ptk, ptk_len,
368189251Ssam		       wpa_key_mgmt_sha256(sm->key_mgmt));
369189251Ssam	return 0;
370189251Ssam}
371189251Ssam
372189251Ssam
373189251Ssamstatic void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
374189251Ssam					  const unsigned char *src_addr,
375189251Ssam					  const struct wpa_eapol_key *key,
376189251Ssam					  u16 ver)
377189251Ssam{
378189251Ssam	struct wpa_eapol_ie_parse ie;
379189251Ssam	struct wpa_ptk *ptk;
380189251Ssam	u8 buf[8];
381214734Srpaulo	int res;
382189251Ssam
383189251Ssam	if (wpa_sm_get_network_ctx(sm) == NULL) {
384252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
385252726Srpaulo			"found (msg 1 of 4)");
386189251Ssam		return;
387189251Ssam	}
388189251Ssam
389189251Ssam	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
390252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way "
391252726Srpaulo		"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
392189251Ssam
393189251Ssam	os_memset(&ie, 0, sizeof(ie));
394189251Ssam
395189251Ssam#ifndef CONFIG_NO_WPA2
396189251Ssam	if (sm->proto == WPA_PROTO_RSN) {
397189251Ssam		/* RSN: msg 1/4 should contain PMKID for the selected PMK */
398189251Ssam		const u8 *_buf = (const u8 *) (key + 1);
399189251Ssam		size_t len = WPA_GET_BE16(key->key_data_length);
400189251Ssam		wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
401252726Srpaulo		if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
402252726Srpaulo			goto failed;
403189251Ssam		if (ie.pmkid) {
404189251Ssam			wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
405189251Ssam				    "Authenticator", ie.pmkid, PMKID_LEN);
406189251Ssam		}
407189251Ssam	}
408189251Ssam#endif /* CONFIG_NO_WPA2 */
409189251Ssam
410214734Srpaulo	res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
411214734Srpaulo	if (res == -2) {
412252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to "
413252726Srpaulo			"msg 1/4 - requesting full EAP authentication");
414214734Srpaulo		return;
415214734Srpaulo	}
416214734Srpaulo	if (res)
417209158Srpaulo		goto failed;
418189251Ssam
419189251Ssam	if (sm->renew_snonce) {
420252726Srpaulo		if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
421214734Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
422189251Ssam				"WPA: Failed to get random data for SNonce");
423209158Srpaulo			goto failed;
424189251Ssam		}
425189251Ssam		sm->renew_snonce = 0;
426189251Ssam		wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
427189251Ssam			    sm->snonce, WPA_NONCE_LEN);
428189251Ssam	}
429189251Ssam
430189251Ssam	/* Calculate PTK which will be stored as a temporary PTK until it has
431189251Ssam	 * been verified when processing message 3/4. */
432189251Ssam	ptk = &sm->tptk;
433189251Ssam	wpa_derive_ptk(sm, src_addr, key, ptk);
434189251Ssam	/* Supplicant: swap tx/rx Mic keys */
435189251Ssam	os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
436189251Ssam	os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
437189251Ssam	os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
438189251Ssam	sm->tptk_set = 1;
439189251Ssam
440189251Ssam	if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
441189251Ssam				       sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
442189251Ssam				       ptk))
443209158Srpaulo		goto failed;
444189251Ssam
445189251Ssam	os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
446209158Srpaulo	return;
447209158Srpaulo
448209158Srpaulofailed:
449209158Srpaulo	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
450189251Ssam}
451189251Ssam
452189251Ssam
453189251Ssamstatic void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx)
454189251Ssam{
455189251Ssam	struct wpa_sm *sm = eloop_ctx;
456189251Ssam	rsn_preauth_candidate_process(sm);
457189251Ssam}
458189251Ssam
459189251Ssam
460189251Ssamstatic void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
461189251Ssam					    const u8 *addr, int secure)
462189251Ssam{
463214734Srpaulo	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
464214734Srpaulo		"WPA: Key negotiation completed with "
465189251Ssam		MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr),
466189251Ssam		wpa_cipher_txt(sm->pairwise_cipher),
467189251Ssam		wpa_cipher_txt(sm->group_cipher));
468189251Ssam	wpa_sm_cancel_auth_timeout(sm);
469189251Ssam	wpa_sm_set_state(sm, WPA_COMPLETED);
470189251Ssam
471189251Ssam	if (secure) {
472189251Ssam		wpa_sm_mlme_setprotection(
473189251Ssam			sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
474189251Ssam			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
475189251Ssam		eapol_sm_notify_portValid(sm->eapol, TRUE);
476189251Ssam		if (wpa_key_mgmt_wpa_psk(sm->key_mgmt))
477189251Ssam			eapol_sm_notify_eap_success(sm->eapol, TRUE);
478189251Ssam		/*
479189251Ssam		 * Start preauthentication after a short wait to avoid a
480189251Ssam		 * possible race condition between the data receive and key
481189251Ssam		 * configuration after the 4-Way Handshake. This increases the
482252726Srpaulo		 * likelihood of the first preauth EAPOL-Start frame getting to
483189251Ssam		 * the target AP.
484189251Ssam		 */
485189251Ssam		eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
486189251Ssam	}
487189251Ssam
488189251Ssam	if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
489252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
490252726Srpaulo			"RSN: Authenticator accepted "
491252726Srpaulo			"opportunistic PMKSA entry - marking it valid");
492189251Ssam		sm->cur_pmksa->opportunistic = 0;
493189251Ssam	}
494189251Ssam
495189251Ssam#ifdef CONFIG_IEEE80211R
496189251Ssam	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
497189251Ssam		/* Prepare for the next transition */
498214734Srpaulo		wpa_ft_prepare_auth_request(sm, NULL);
499189251Ssam	}
500189251Ssam#endif /* CONFIG_IEEE80211R */
501189251Ssam}
502189251Ssam
503189251Ssam
504189251Ssamstatic void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
505189251Ssam{
506189251Ssam	struct wpa_sm *sm = eloop_ctx;
507252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Request PTK rekeying");
508189251Ssam	wpa_sm_key_request(sm, 0, 1);
509189251Ssam}
510189251Ssam
511189251Ssam
512189251Ssamstatic int wpa_supplicant_install_ptk(struct wpa_sm *sm,
513189251Ssam				      const struct wpa_eapol_key *key)
514189251Ssam{
515189251Ssam	int keylen, rsclen;
516214734Srpaulo	enum wpa_alg alg;
517189251Ssam	const u8 *key_rsc;
518189251Ssam	u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
519189251Ssam
520252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
521252726Srpaulo		"WPA: Installing PTK to the driver");
522189251Ssam
523252726Srpaulo	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
524252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher "
525252726Srpaulo			"Suite: NONE - do not use pairwise keys");
526189251Ssam		return 0;
527252726Srpaulo	}
528252726Srpaulo
529252726Srpaulo	if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
530252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
531252726Srpaulo			"WPA: Unsupported pairwise cipher %d",
532252726Srpaulo			sm->pairwise_cipher);
533189251Ssam		return -1;
534189251Ssam	}
535189251Ssam
536252726Srpaulo	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
537252726Srpaulo	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
538252726Srpaulo	rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
539252726Srpaulo
540189251Ssam	if (sm->proto == WPA_PROTO_RSN) {
541189251Ssam		key_rsc = null_rsc;
542189251Ssam	} else {
543189251Ssam		key_rsc = key->key_rsc;
544189251Ssam		wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
545189251Ssam	}
546189251Ssam
547189251Ssam	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
548189251Ssam			   (u8 *) sm->ptk.tk1, keylen) < 0) {
549252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
550252726Srpaulo			"WPA: Failed to set PTK to the "
551252726Srpaulo			"driver (alg=%d keylen=%d bssid=" MACSTR ")",
552252726Srpaulo			alg, keylen, MAC2STR(sm->bssid));
553189251Ssam		return -1;
554189251Ssam	}
555189251Ssam
556189251Ssam	if (sm->wpa_ptk_rekey) {
557189251Ssam		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
558189251Ssam		eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
559189251Ssam				       sm, NULL);
560189251Ssam	}
561189251Ssam
562189251Ssam	return 0;
563189251Ssam}
564189251Ssam
565189251Ssam
566252726Srpaulostatic int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
567252726Srpaulo					     int group_cipher,
568189251Ssam					     int keylen, int maxkeylen,
569214734Srpaulo					     int *key_rsc_len,
570214734Srpaulo					     enum wpa_alg *alg)
571189251Ssam{
572252726Srpaulo	int klen;
573189251Ssam
574252726Srpaulo	*alg = wpa_cipher_to_alg(group_cipher);
575252726Srpaulo	if (*alg == WPA_ALG_NONE) {
576252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
577252726Srpaulo			"WPA: Unsupported Group Cipher %d",
578252726Srpaulo			group_cipher);
579189251Ssam		return -1;
580189251Ssam	}
581252726Srpaulo	*key_rsc_len = wpa_cipher_rsc_len(group_cipher);
582189251Ssam
583252726Srpaulo	klen = wpa_cipher_key_len(group_cipher);
584252726Srpaulo	if (keylen != klen || maxkeylen < klen) {
585252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
586252726Srpaulo			"WPA: Unsupported %s Group Cipher key length %d (%d)",
587252726Srpaulo			wpa_cipher_txt(group_cipher), keylen, maxkeylen);
588252726Srpaulo		return -1;
589189251Ssam	}
590252726Srpaulo	return 0;
591189251Ssam}
592189251Ssam
593189251Ssam
594189251Ssamstruct wpa_gtk_data {
595214734Srpaulo	enum wpa_alg alg;
596189251Ssam	int tx, key_rsc_len, keyidx;
597189251Ssam	u8 gtk[32];
598189251Ssam	int gtk_len;
599189251Ssam};
600189251Ssam
601189251Ssam
602189251Ssamstatic int wpa_supplicant_install_gtk(struct wpa_sm *sm,
603189251Ssam				      const struct wpa_gtk_data *gd,
604189251Ssam				      const u8 *key_rsc)
605189251Ssam{
606189251Ssam	const u8 *_gtk = gd->gtk;
607189251Ssam	u8 gtk_buf[32];
608189251Ssam
609189251Ssam	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
610252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
611252726Srpaulo		"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
612252726Srpaulo		gd->keyidx, gd->tx, gd->gtk_len);
613189251Ssam	wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len);
614189251Ssam	if (sm->group_cipher == WPA_CIPHER_TKIP) {
615189251Ssam		/* Swap Tx/Rx keys for Michael MIC */
616189251Ssam		os_memcpy(gtk_buf, gd->gtk, 16);
617189251Ssam		os_memcpy(gtk_buf + 16, gd->gtk + 24, 8);
618189251Ssam		os_memcpy(gtk_buf + 24, gd->gtk + 16, 8);
619189251Ssam		_gtk = gtk_buf;
620189251Ssam	}
621189251Ssam	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
622252726Srpaulo		if (wpa_sm_set_key(sm, gd->alg, NULL,
623189251Ssam				   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
624189251Ssam				   _gtk, gd->gtk_len) < 0) {
625252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
626252726Srpaulo				"WPA: Failed to set GTK to the driver "
627252726Srpaulo				"(Group only)");
628189251Ssam			return -1;
629189251Ssam		}
630252726Srpaulo	} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
631189251Ssam				  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
632189251Ssam				  _gtk, gd->gtk_len) < 0) {
633252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
634252726Srpaulo			"WPA: Failed to set GTK to "
635252726Srpaulo			"the driver (alg=%d keylen=%d keyidx=%d)",
636252726Srpaulo			gd->alg, gd->gtk_len, gd->keyidx);
637189251Ssam		return -1;
638189251Ssam	}
639189251Ssam
640189251Ssam	return 0;
641189251Ssam}
642189251Ssam
643189251Ssam
644189251Ssamstatic int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
645189251Ssam						int tx)
646189251Ssam{
647189251Ssam	if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) {
648189251Ssam		/* Ignore Tx bit for GTK if a pairwise key is used. One AP
649189251Ssam		 * seemed to set this bit (incorrectly, since Tx is only when
650189251Ssam		 * doing Group Key only APs) and without this workaround, the
651189251Ssam		 * data connection does not work because wpa_supplicant
652189251Ssam		 * configured non-zero keyidx to be used for unicast. */
653252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
654252726Srpaulo			"WPA: Tx bit set for GTK, but pairwise "
655252726Srpaulo			"keys are used - ignore Tx bit");
656189251Ssam		return 0;
657189251Ssam	}
658189251Ssam	return tx;
659189251Ssam}
660189251Ssam
661189251Ssam
662189251Ssamstatic int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
663189251Ssam				       const struct wpa_eapol_key *key,
664189251Ssam				       const u8 *gtk, size_t gtk_len,
665189251Ssam				       int key_info)
666189251Ssam{
667189251Ssam#ifndef CONFIG_NO_WPA2
668189251Ssam	struct wpa_gtk_data gd;
669189251Ssam
670189251Ssam	/*
671189251Ssam	 * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
672189251Ssam	 * GTK KDE format:
673189251Ssam	 * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7]
674189251Ssam	 * Reserved [bits 0-7]
675189251Ssam	 * GTK
676189251Ssam	 */
677189251Ssam
678189251Ssam	os_memset(&gd, 0, sizeof(gd));
679189251Ssam	wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake",
680189251Ssam			gtk, gtk_len);
681189251Ssam
682189251Ssam	if (gtk_len < 2 || gtk_len - 2 > sizeof(gd.gtk))
683189251Ssam		return -1;
684189251Ssam
685189251Ssam	gd.keyidx = gtk[0] & 0x3;
686189251Ssam	gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
687189251Ssam						     !!(gtk[0] & BIT(2)));
688189251Ssam	gtk += 2;
689189251Ssam	gtk_len -= 2;
690189251Ssam
691189251Ssam	os_memcpy(gd.gtk, gtk, gtk_len);
692189251Ssam	gd.gtk_len = gtk_len;
693189251Ssam
694252726Srpaulo	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
695189251Ssam					      gtk_len, gtk_len,
696189251Ssam					      &gd.key_rsc_len, &gd.alg) ||
697189251Ssam	    wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) {
698252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
699252726Srpaulo			"RSN: Failed to install GTK");
700189251Ssam		return -1;
701189251Ssam	}
702189251Ssam
703189251Ssam	wpa_supplicant_key_neg_complete(sm, sm->bssid,
704189251Ssam					key_info & WPA_KEY_INFO_SECURE);
705189251Ssam	return 0;
706189251Ssam#else /* CONFIG_NO_WPA2 */
707189251Ssam	return -1;
708189251Ssam#endif /* CONFIG_NO_WPA2 */
709189251Ssam}
710189251Ssam
711189251Ssam
712189251Ssamstatic int ieee80211w_set_keys(struct wpa_sm *sm,
713189251Ssam			       struct wpa_eapol_ie_parse *ie)
714189251Ssam{
715189251Ssam#ifdef CONFIG_IEEE80211W
716189251Ssam	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
717189251Ssam		return 0;
718189251Ssam
719189251Ssam	if (ie->igtk) {
720189251Ssam		const struct wpa_igtk_kde *igtk;
721189251Ssam		u16 keyidx;
722189251Ssam		if (ie->igtk_len != sizeof(*igtk))
723189251Ssam			return -1;
724189251Ssam		igtk = (const struct wpa_igtk_kde *) ie->igtk;
725189251Ssam		keyidx = WPA_GET_LE16(igtk->keyid);
726252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
727252726Srpaulo			"pn %02x%02x%02x%02x%02x%02x",
728252726Srpaulo			keyidx, MAC2STR(igtk->pn));
729189251Ssam		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
730189251Ssam				igtk->igtk, WPA_IGTK_LEN);
731189251Ssam		if (keyidx > 4095) {
732252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
733252726Srpaulo				"WPA: Invalid IGTK KeyID %d", keyidx);
734189251Ssam			return -1;
735189251Ssam		}
736252726Srpaulo		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
737189251Ssam				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
738189251Ssam				   igtk->igtk, WPA_IGTK_LEN) < 0) {
739252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
740252726Srpaulo				"WPA: Failed to configure IGTK to the driver");
741189251Ssam			return -1;
742189251Ssam		}
743189251Ssam	}
744189251Ssam
745189251Ssam	return 0;
746189251Ssam#else /* CONFIG_IEEE80211W */
747189251Ssam	return 0;
748189251Ssam#endif /* CONFIG_IEEE80211W */
749189251Ssam}
750189251Ssam
751189251Ssam
752189251Ssamstatic void wpa_report_ie_mismatch(struct wpa_sm *sm,
753189251Ssam				   const char *reason, const u8 *src_addr,
754189251Ssam				   const u8 *wpa_ie, size_t wpa_ie_len,
755189251Ssam				   const u8 *rsn_ie, size_t rsn_ie_len)
756189251Ssam{
757214734Srpaulo	wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")",
758189251Ssam		reason, MAC2STR(src_addr));
759189251Ssam
760189251Ssam	if (sm->ap_wpa_ie) {
761189251Ssam		wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp",
762189251Ssam			    sm->ap_wpa_ie, sm->ap_wpa_ie_len);
763189251Ssam	}
764189251Ssam	if (wpa_ie) {
765189251Ssam		if (!sm->ap_wpa_ie) {
766252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
767252726Srpaulo				"WPA: No WPA IE in Beacon/ProbeResp");
768189251Ssam		}
769189251Ssam		wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg",
770189251Ssam			    wpa_ie, wpa_ie_len);
771189251Ssam	}
772189251Ssam
773189251Ssam	if (sm->ap_rsn_ie) {
774189251Ssam		wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp",
775189251Ssam			    sm->ap_rsn_ie, sm->ap_rsn_ie_len);
776189251Ssam	}
777189251Ssam	if (rsn_ie) {
778189251Ssam		if (!sm->ap_rsn_ie) {
779252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
780252726Srpaulo				"WPA: No RSN IE in Beacon/ProbeResp");
781189251Ssam		}
782189251Ssam		wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg",
783189251Ssam			    rsn_ie, rsn_ie_len);
784189251Ssam	}
785189251Ssam
786252726Srpaulo	wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
787189251Ssam}
788189251Ssam
789189251Ssam
790214734Srpaulo#ifdef CONFIG_IEEE80211R
791214734Srpaulo
792214734Srpaulostatic int ft_validate_mdie(struct wpa_sm *sm,
793214734Srpaulo			    const unsigned char *src_addr,
794214734Srpaulo			    struct wpa_eapol_ie_parse *ie,
795214734Srpaulo			    const u8 *assoc_resp_mdie)
796214734Srpaulo{
797214734Srpaulo	struct rsn_mdie *mdie;
798214734Srpaulo
799214734Srpaulo	mdie = (struct rsn_mdie *) (ie->mdie + 2);
800214734Srpaulo	if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) ||
801214734Srpaulo	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
802214734Srpaulo		      MOBILITY_DOMAIN_ID_LEN) != 0) {
803252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE in msg 3/4 did "
804252726Srpaulo			"not match with the current mobility domain");
805214734Srpaulo		return -1;
806214734Srpaulo	}
807214734Srpaulo
808214734Srpaulo	if (assoc_resp_mdie &&
809214734Srpaulo	    (assoc_resp_mdie[1] != ie->mdie[1] ||
810214734Srpaulo	     os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) {
811252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE mismatch");
812214734Srpaulo		wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4",
813214734Srpaulo			    ie->mdie, 2 + ie->mdie[1]);
814214734Srpaulo		wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response",
815214734Srpaulo			    assoc_resp_mdie, 2 + assoc_resp_mdie[1]);
816214734Srpaulo		return -1;
817214734Srpaulo	}
818214734Srpaulo
819214734Srpaulo	return 0;
820214734Srpaulo}
821214734Srpaulo
822214734Srpaulo
823214734Srpaulostatic int ft_validate_ftie(struct wpa_sm *sm,
824214734Srpaulo			    const unsigned char *src_addr,
825214734Srpaulo			    struct wpa_eapol_ie_parse *ie,
826214734Srpaulo			    const u8 *assoc_resp_ftie)
827214734Srpaulo{
828214734Srpaulo	if (ie->ftie == NULL) {
829252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
830252726Srpaulo			"FT: No FTIE in EAPOL-Key msg 3/4");
831214734Srpaulo		return -1;
832214734Srpaulo	}
833214734Srpaulo
834214734Srpaulo	if (assoc_resp_ftie == NULL)
835214734Srpaulo		return 0;
836214734Srpaulo
837214734Srpaulo	if (assoc_resp_ftie[1] != ie->ftie[1] ||
838214734Srpaulo	    os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) {
839252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: FTIE mismatch");
840214734Srpaulo		wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4",
841214734Srpaulo			    ie->ftie, 2 + ie->ftie[1]);
842214734Srpaulo		wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response",
843214734Srpaulo			    assoc_resp_ftie, 2 + assoc_resp_ftie[1]);
844214734Srpaulo		return -1;
845214734Srpaulo	}
846214734Srpaulo
847214734Srpaulo	return 0;
848214734Srpaulo}
849214734Srpaulo
850214734Srpaulo
851214734Srpaulostatic int ft_validate_rsnie(struct wpa_sm *sm,
852214734Srpaulo			     const unsigned char *src_addr,
853214734Srpaulo			     struct wpa_eapol_ie_parse *ie)
854214734Srpaulo{
855214734Srpaulo	struct wpa_ie_data rsn;
856214734Srpaulo
857214734Srpaulo	if (!ie->rsn_ie)
858214734Srpaulo		return 0;
859214734Srpaulo
860214734Srpaulo	/*
861214734Srpaulo	 * Verify that PMKR1Name from EAPOL-Key message 3/4
862214734Srpaulo	 * matches with the value we derived.
863214734Srpaulo	 */
864214734Srpaulo	if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 ||
865214734Srpaulo	    rsn.num_pmkid != 1 || rsn.pmkid == NULL) {
866252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: No PMKR1Name in "
867252726Srpaulo			"FT 4-way handshake message 3/4");
868214734Srpaulo		return -1;
869214734Srpaulo	}
870214734Srpaulo
871214734Srpaulo	if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
872252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
873252726Srpaulo			"FT: PMKR1Name mismatch in "
874252726Srpaulo			"FT 4-way handshake message 3/4");
875214734Srpaulo		wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator",
876214734Srpaulo			    rsn.pmkid, WPA_PMK_NAME_LEN);
877214734Srpaulo		wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
878214734Srpaulo			    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
879214734Srpaulo		return -1;
880214734Srpaulo	}
881214734Srpaulo
882214734Srpaulo	return 0;
883214734Srpaulo}
884214734Srpaulo
885214734Srpaulo
886214734Srpaulostatic int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm,
887214734Srpaulo					 const unsigned char *src_addr,
888214734Srpaulo					 struct wpa_eapol_ie_parse *ie)
889214734Srpaulo{
890214734Srpaulo	const u8 *pos, *end, *mdie = NULL, *ftie = NULL;
891214734Srpaulo
892214734Srpaulo	if (sm->assoc_resp_ies) {
893214734Srpaulo		pos = sm->assoc_resp_ies;
894214734Srpaulo		end = pos + sm->assoc_resp_ies_len;
895214734Srpaulo		while (pos + 2 < end) {
896214734Srpaulo			if (pos + 2 + pos[1] > end)
897214734Srpaulo				break;
898214734Srpaulo			switch (*pos) {
899214734Srpaulo			case WLAN_EID_MOBILITY_DOMAIN:
900214734Srpaulo				mdie = pos;
901214734Srpaulo				break;
902214734Srpaulo			case WLAN_EID_FAST_BSS_TRANSITION:
903214734Srpaulo				ftie = pos;
904214734Srpaulo				break;
905214734Srpaulo			}
906214734Srpaulo			pos += 2 + pos[1];
907214734Srpaulo		}
908214734Srpaulo	}
909214734Srpaulo
910214734Srpaulo	if (ft_validate_mdie(sm, src_addr, ie, mdie) < 0 ||
911214734Srpaulo	    ft_validate_ftie(sm, src_addr, ie, ftie) < 0 ||
912214734Srpaulo	    ft_validate_rsnie(sm, src_addr, ie) < 0)
913214734Srpaulo		return -1;
914214734Srpaulo
915214734Srpaulo	return 0;
916214734Srpaulo}
917214734Srpaulo
918214734Srpaulo#endif /* CONFIG_IEEE80211R */
919214734Srpaulo
920214734Srpaulo
921189251Ssamstatic int wpa_supplicant_validate_ie(struct wpa_sm *sm,
922189251Ssam				      const unsigned char *src_addr,
923189251Ssam				      struct wpa_eapol_ie_parse *ie)
924189251Ssam{
925189251Ssam	if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) {
926252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
927252726Srpaulo			"WPA: No WPA/RSN IE for this AP known. "
928252726Srpaulo			"Trying to get from scan results");
929189251Ssam		if (wpa_sm_get_beacon_ie(sm) < 0) {
930252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
931252726Srpaulo				"WPA: Could not find AP from "
932252726Srpaulo				"the scan results");
933189251Ssam		} else {
934252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
935252726Srpaulo				"WPA: Found the current AP from "
936252726Srpaulo				"updated scan results");
937189251Ssam		}
938189251Ssam	}
939189251Ssam
940189251Ssam	if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
941189251Ssam	    (sm->ap_wpa_ie || sm->ap_rsn_ie)) {
942189251Ssam		wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
943189251Ssam				       "with IE in Beacon/ProbeResp (no IE?)",
944189251Ssam				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
945189251Ssam				       ie->rsn_ie, ie->rsn_ie_len);
946189251Ssam		return -1;
947189251Ssam	}
948189251Ssam
949189251Ssam	if ((ie->wpa_ie && sm->ap_wpa_ie &&
950189251Ssam	     (ie->wpa_ie_len != sm->ap_wpa_ie_len ||
951189251Ssam	      os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) ||
952189251Ssam	    (ie->rsn_ie && sm->ap_rsn_ie &&
953214734Srpaulo	     wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
954214734Srpaulo				sm->ap_rsn_ie, sm->ap_rsn_ie_len,
955214734Srpaulo				ie->rsn_ie, ie->rsn_ie_len))) {
956189251Ssam		wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
957189251Ssam				       "with IE in Beacon/ProbeResp",
958189251Ssam				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
959189251Ssam				       ie->rsn_ie, ie->rsn_ie_len);
960189251Ssam		return -1;
961189251Ssam	}
962189251Ssam
963189251Ssam	if (sm->proto == WPA_PROTO_WPA &&
964189251Ssam	    ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) {
965189251Ssam		wpa_report_ie_mismatch(sm, "Possible downgrade attack "
966189251Ssam				       "detected - RSN was enabled and RSN IE "
967189251Ssam				       "was in msg 3/4, but not in "
968189251Ssam				       "Beacon/ProbeResp",
969189251Ssam				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
970189251Ssam				       ie->rsn_ie, ie->rsn_ie_len);
971189251Ssam		return -1;
972189251Ssam	}
973189251Ssam
974189251Ssam#ifdef CONFIG_IEEE80211R
975214734Srpaulo	if (wpa_key_mgmt_ft(sm->key_mgmt) &&
976214734Srpaulo	    wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
977214734Srpaulo		return -1;
978189251Ssam#endif /* CONFIG_IEEE80211R */
979189251Ssam
980189251Ssam	return 0;
981189251Ssam}
982189251Ssam
983189251Ssam
984189251Ssam/**
985189251Ssam * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake
986189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
987189251Ssam * @dst: Destination address for the frame
988189251Ssam * @key: Pointer to the EAPOL-Key frame header
989189251Ssam * @ver: Version bits from EAPOL-Key Key Info
990189251Ssam * @key_info: Key Info
991189251Ssam * @kde: KDEs to include the EAPOL-Key frame
992189251Ssam * @kde_len: Length of KDEs
993189251Ssam * @ptk: PTK to use for keyed hash and encryption
994189251Ssam * Returns: 0 on success, -1 on failure
995189251Ssam */
996189251Ssamint wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
997189251Ssam			       const struct wpa_eapol_key *key,
998189251Ssam			       u16 ver, u16 key_info,
999189251Ssam			       const u8 *kde, size_t kde_len,
1000189251Ssam			       struct wpa_ptk *ptk)
1001189251Ssam{
1002189251Ssam	size_t rlen;
1003189251Ssam	struct wpa_eapol_key *reply;
1004189251Ssam	u8 *rbuf;
1005189251Ssam
1006189251Ssam	if (kde)
1007189251Ssam		wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len);
1008189251Ssam
1009189251Ssam	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
1010189251Ssam				  sizeof(*reply) + kde_len,
1011189251Ssam				  &rlen, (void *) &reply);
1012189251Ssam	if (rbuf == NULL)
1013189251Ssam		return -1;
1014189251Ssam
1015189251Ssam	reply->type = sm->proto == WPA_PROTO_RSN ?
1016189251Ssam		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
1017189251Ssam	key_info &= WPA_KEY_INFO_SECURE;
1018189251Ssam	key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
1019189251Ssam	WPA_PUT_BE16(reply->key_info, key_info);
1020189251Ssam	if (sm->proto == WPA_PROTO_RSN)
1021189251Ssam		WPA_PUT_BE16(reply->key_length, 0);
1022189251Ssam	else
1023189251Ssam		os_memcpy(reply->key_length, key->key_length, 2);
1024189251Ssam	os_memcpy(reply->replay_counter, key->replay_counter,
1025189251Ssam		  WPA_REPLAY_COUNTER_LEN);
1026189251Ssam
1027189251Ssam	WPA_PUT_BE16(reply->key_data_length, kde_len);
1028189251Ssam	if (kde)
1029189251Ssam		os_memcpy(reply + 1, kde, kde_len);
1030189251Ssam
1031252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
1032189251Ssam	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
1033189251Ssam			   rbuf, rlen, reply->key_mic);
1034189251Ssam
1035189251Ssam	return 0;
1036189251Ssam}
1037189251Ssam
1038189251Ssam
1039189251Ssamstatic void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
1040189251Ssam					  const struct wpa_eapol_key *key,
1041189251Ssam					  u16 ver)
1042189251Ssam{
1043189251Ssam	u16 key_info, keylen, len;
1044189251Ssam	const u8 *pos;
1045189251Ssam	struct wpa_eapol_ie_parse ie;
1046189251Ssam
1047189251Ssam	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
1048252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way "
1049252726Srpaulo		"Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver);
1050189251Ssam
1051189251Ssam	key_info = WPA_GET_BE16(key->key_info);
1052189251Ssam
1053189251Ssam	pos = (const u8 *) (key + 1);
1054189251Ssam	len = WPA_GET_BE16(key->key_data_length);
1055189251Ssam	wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
1056252726Srpaulo	if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
1057252726Srpaulo		goto failed;
1058189251Ssam	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
1059252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1060252726Srpaulo			"WPA: GTK IE in unencrypted key data");
1061209158Srpaulo		goto failed;
1062189251Ssam	}
1063189251Ssam#ifdef CONFIG_IEEE80211W
1064189251Ssam	if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
1065252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1066252726Srpaulo			"WPA: IGTK KDE in unencrypted key data");
1067209158Srpaulo		goto failed;
1068189251Ssam	}
1069189251Ssam
1070189251Ssam	if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
1071252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1072252726Srpaulo			"WPA: Invalid IGTK KDE length %lu",
1073252726Srpaulo			(unsigned long) ie.igtk_len);
1074209158Srpaulo		goto failed;
1075189251Ssam	}
1076189251Ssam#endif /* CONFIG_IEEE80211W */
1077189251Ssam
1078189251Ssam	if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
1079209158Srpaulo		goto failed;
1080189251Ssam
1081189251Ssam	if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
1082252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1083252726Srpaulo			"WPA: ANonce from message 1 of 4-Way Handshake "
1084252726Srpaulo			"differs from 3 of 4-Way Handshake - drop packet (src="
1085252726Srpaulo			MACSTR ")", MAC2STR(sm->bssid));
1086209158Srpaulo		goto failed;
1087189251Ssam	}
1088189251Ssam
1089189251Ssam	keylen = WPA_GET_BE16(key->key_length);
1090252726Srpaulo	if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) {
1091252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1092252726Srpaulo			"WPA: Invalid %s key length %d (src=" MACSTR
1093252726Srpaulo			")", wpa_cipher_txt(sm->pairwise_cipher), keylen,
1094252726Srpaulo			MAC2STR(sm->bssid));
1095252726Srpaulo		goto failed;
1096189251Ssam	}
1097189251Ssam
1098189251Ssam	if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
1099209158Srpaulo				       NULL, 0, &sm->ptk)) {
1100209158Srpaulo		goto failed;
1101209158Srpaulo	}
1102189251Ssam
1103189251Ssam	/* SNonce was successfully used in msg 3/4, so mark it to be renewed
1104189251Ssam	 * for the next 4-Way Handshake. If msg 3 is received again, the old
1105189251Ssam	 * SNonce will still be used to avoid changing PTK. */
1106189251Ssam	sm->renew_snonce = 1;
1107189251Ssam
1108189251Ssam	if (key_info & WPA_KEY_INFO_INSTALL) {
1109209158Srpaulo		if (wpa_supplicant_install_ptk(sm, key))
1110209158Srpaulo			goto failed;
1111189251Ssam	}
1112189251Ssam
1113189251Ssam	if (key_info & WPA_KEY_INFO_SECURE) {
1114189251Ssam		wpa_sm_mlme_setprotection(
1115189251Ssam			sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX,
1116189251Ssam			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
1117189251Ssam		eapol_sm_notify_portValid(sm->eapol, TRUE);
1118189251Ssam	}
1119189251Ssam	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
1120189251Ssam
1121189251Ssam	if (ie.gtk &&
1122189251Ssam	    wpa_supplicant_pairwise_gtk(sm, key,
1123189251Ssam					ie.gtk, ie.gtk_len, key_info) < 0) {
1124252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1125252726Srpaulo			"RSN: Failed to configure GTK");
1126209158Srpaulo		goto failed;
1127189251Ssam	}
1128189251Ssam
1129209158Srpaulo	if (ieee80211w_set_keys(sm, &ie) < 0) {
1130252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1131252726Srpaulo			"RSN: Failed to configure IGTK");
1132209158Srpaulo		goto failed;
1133209158Srpaulo	}
1134209158Srpaulo
1135252726Srpaulo	wpa_sm_set_rekey_offload(sm);
1136252726Srpaulo
1137209158Srpaulo	return;
1138209158Srpaulo
1139209158Srpaulofailed:
1140209158Srpaulo	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
1141189251Ssam}
1142189251Ssam
1143189251Ssam
1144189251Ssamstatic int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
1145189251Ssam					     const u8 *keydata,
1146189251Ssam					     size_t keydatalen,
1147189251Ssam					     u16 key_info,
1148189251Ssam					     struct wpa_gtk_data *gd)
1149189251Ssam{
1150189251Ssam	int maxkeylen;
1151189251Ssam	struct wpa_eapol_ie_parse ie;
1152189251Ssam
1153189251Ssam	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
1154252726Srpaulo	if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
1155252726Srpaulo		return -1;
1156189251Ssam	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
1157252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1158252726Srpaulo			"WPA: GTK IE in unencrypted key data");
1159189251Ssam		return -1;
1160189251Ssam	}
1161189251Ssam	if (ie.gtk == NULL) {
1162252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1163252726Srpaulo			"WPA: No GTK IE in Group Key msg 1/2");
1164189251Ssam		return -1;
1165189251Ssam	}
1166189251Ssam	maxkeylen = gd->gtk_len = ie.gtk_len - 2;
1167189251Ssam
1168252726Srpaulo	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
1169189251Ssam					      gd->gtk_len, maxkeylen,
1170189251Ssam					      &gd->key_rsc_len, &gd->alg))
1171189251Ssam		return -1;
1172189251Ssam
1173189251Ssam	wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake",
1174189251Ssam		    ie.gtk, ie.gtk_len);
1175189251Ssam	gd->keyidx = ie.gtk[0] & 0x3;
1176189251Ssam	gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
1177189251Ssam						      !!(ie.gtk[0] & BIT(2)));
1178189251Ssam	if (ie.gtk_len - 2 > sizeof(gd->gtk)) {
1179252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1180252726Srpaulo			"RSN: Too long GTK in GTK IE (len=%lu)",
1181252726Srpaulo			(unsigned long) ie.gtk_len - 2);
1182189251Ssam		return -1;
1183189251Ssam	}
1184189251Ssam	os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
1185189251Ssam
1186189251Ssam	if (ieee80211w_set_keys(sm, &ie) < 0)
1187252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1188252726Srpaulo			"RSN: Failed to configure IGTK");
1189189251Ssam
1190189251Ssam	return 0;
1191189251Ssam}
1192189251Ssam
1193189251Ssam
1194189251Ssamstatic int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
1195189251Ssam					     const struct wpa_eapol_key *key,
1196189251Ssam					     size_t keydatalen, int key_info,
1197189251Ssam					     size_t extra_len, u16 ver,
1198189251Ssam					     struct wpa_gtk_data *gd)
1199189251Ssam{
1200189251Ssam	size_t maxkeylen;
1201189251Ssam	u8 ek[32];
1202189251Ssam
1203189251Ssam	gd->gtk_len = WPA_GET_BE16(key->key_length);
1204189251Ssam	maxkeylen = keydatalen;
1205189251Ssam	if (keydatalen > extra_len) {
1206252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1207252726Srpaulo			"WPA: Truncated EAPOL-Key packet: "
1208252726Srpaulo			"key_data_length=%lu > extra_len=%lu",
1209252726Srpaulo			(unsigned long) keydatalen, (unsigned long) extra_len);
1210189251Ssam		return -1;
1211189251Ssam	}
1212189251Ssam	if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
1213189251Ssam		if (maxkeylen < 8) {
1214252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1215252726Srpaulo				"WPA: Too short maxkeylen (%lu)",
1216252726Srpaulo				(unsigned long) maxkeylen);
1217189251Ssam			return -1;
1218189251Ssam		}
1219189251Ssam		maxkeylen -= 8;
1220189251Ssam	}
1221189251Ssam
1222252726Srpaulo	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
1223189251Ssam					      gd->gtk_len, maxkeylen,
1224189251Ssam					      &gd->key_rsc_len, &gd->alg))
1225189251Ssam		return -1;
1226189251Ssam
1227189251Ssam	gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
1228189251Ssam		WPA_KEY_INFO_KEY_INDEX_SHIFT;
1229189251Ssam	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
1230189251Ssam		os_memcpy(ek, key->key_iv, 16);
1231189251Ssam		os_memcpy(ek + 16, sm->ptk.kek, 16);
1232189251Ssam		if (keydatalen > sizeof(gd->gtk)) {
1233252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1234252726Srpaulo				"WPA: RC4 key data too long (%lu)",
1235252726Srpaulo				(unsigned long) keydatalen);
1236189251Ssam			return -1;
1237189251Ssam		}
1238189251Ssam		os_memcpy(gd->gtk, key + 1, keydatalen);
1239214734Srpaulo		if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
1240252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
1241252726Srpaulo				"WPA: RC4 failed");
1242214734Srpaulo			return -1;
1243214734Srpaulo		}
1244189251Ssam	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
1245189251Ssam		if (keydatalen % 8) {
1246252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1247252726Srpaulo				"WPA: Unsupported AES-WRAP len %lu",
1248252726Srpaulo				(unsigned long) keydatalen);
1249189251Ssam			return -1;
1250189251Ssam		}
1251189251Ssam		if (maxkeylen > sizeof(gd->gtk)) {
1252252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1253252726Srpaulo				"WPA: AES-WRAP key data "
1254252726Srpaulo				"too long (keydatalen=%lu maxkeylen=%lu)",
1255252726Srpaulo				(unsigned long) keydatalen,
1256252726Srpaulo				(unsigned long) maxkeylen);
1257189251Ssam			return -1;
1258189251Ssam		}
1259189251Ssam		if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
1260189251Ssam			       (const u8 *) (key + 1), gd->gtk)) {
1261252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1262252726Srpaulo				"WPA: AES unwrap failed - could not decrypt "
1263252726Srpaulo				"GTK");
1264189251Ssam			return -1;
1265189251Ssam		}
1266189251Ssam	} else {
1267252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1268252726Srpaulo			"WPA: Unsupported key_info type %d", ver);
1269189251Ssam		return -1;
1270189251Ssam	}
1271189251Ssam	gd->tx = wpa_supplicant_gtk_tx_bit_workaround(
1272189251Ssam		sm, !!(key_info & WPA_KEY_INFO_TXRX));
1273189251Ssam	return 0;
1274189251Ssam}
1275189251Ssam
1276189251Ssam
1277189251Ssamstatic int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
1278189251Ssam				      const struct wpa_eapol_key *key,
1279189251Ssam				      int ver, u16 key_info)
1280189251Ssam{
1281189251Ssam	size_t rlen;
1282189251Ssam	struct wpa_eapol_key *reply;
1283189251Ssam	u8 *rbuf;
1284189251Ssam
1285189251Ssam	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
1286189251Ssam				  sizeof(*reply), &rlen, (void *) &reply);
1287189251Ssam	if (rbuf == NULL)
1288189251Ssam		return -1;
1289189251Ssam
1290189251Ssam	reply->type = sm->proto == WPA_PROTO_RSN ?
1291189251Ssam		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
1292189251Ssam	key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
1293189251Ssam	key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
1294189251Ssam	WPA_PUT_BE16(reply->key_info, key_info);
1295189251Ssam	if (sm->proto == WPA_PROTO_RSN)
1296189251Ssam		WPA_PUT_BE16(reply->key_length, 0);
1297189251Ssam	else
1298189251Ssam		os_memcpy(reply->key_length, key->key_length, 2);
1299189251Ssam	os_memcpy(reply->replay_counter, key->replay_counter,
1300189251Ssam		  WPA_REPLAY_COUNTER_LEN);
1301189251Ssam
1302189251Ssam	WPA_PUT_BE16(reply->key_data_length, 0);
1303189251Ssam
1304252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
1305189251Ssam	wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
1306189251Ssam			   rbuf, rlen, reply->key_mic);
1307189251Ssam
1308189251Ssam	return 0;
1309189251Ssam}
1310189251Ssam
1311189251Ssam
1312189251Ssamstatic void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
1313189251Ssam					  const unsigned char *src_addr,
1314189251Ssam					  const struct wpa_eapol_key *key,
1315189251Ssam					  int extra_len, u16 ver)
1316189251Ssam{
1317189251Ssam	u16 key_info, keydatalen;
1318189251Ssam	int rekey, ret;
1319189251Ssam	struct wpa_gtk_data gd;
1320189251Ssam
1321189251Ssam	os_memset(&gd, 0, sizeof(gd));
1322189251Ssam
1323189251Ssam	rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
1324252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of Group Key "
1325252726Srpaulo		"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
1326189251Ssam
1327189251Ssam	key_info = WPA_GET_BE16(key->key_info);
1328189251Ssam	keydatalen = WPA_GET_BE16(key->key_data_length);
1329189251Ssam
1330189251Ssam	if (sm->proto == WPA_PROTO_RSN) {
1331189251Ssam		ret = wpa_supplicant_process_1_of_2_rsn(sm,
1332189251Ssam							(const u8 *) (key + 1),
1333189251Ssam							keydatalen, key_info,
1334189251Ssam							&gd);
1335189251Ssam	} else {
1336189251Ssam		ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
1337189251Ssam							key_info, extra_len,
1338189251Ssam							ver, &gd);
1339189251Ssam	}
1340189251Ssam
1341189251Ssam	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
1342189251Ssam
1343189251Ssam	if (ret)
1344209158Srpaulo		goto failed;
1345189251Ssam
1346189251Ssam	if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
1347189251Ssam	    wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
1348209158Srpaulo		goto failed;
1349189251Ssam
1350189251Ssam	if (rekey) {
1351253040Shiren		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Group rekeying "
1352189251Ssam			"completed with " MACSTR " [GTK=%s]",
1353189251Ssam			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
1354189251Ssam		wpa_sm_cancel_auth_timeout(sm);
1355189251Ssam		wpa_sm_set_state(sm, WPA_COMPLETED);
1356252726Srpaulo
1357252726Srpaulo		wpa_sm_set_rekey_offload(sm);
1358189251Ssam	} else {
1359189251Ssam		wpa_supplicant_key_neg_complete(sm, sm->bssid,
1360189251Ssam						key_info &
1361189251Ssam						WPA_KEY_INFO_SECURE);
1362189251Ssam	}
1363209158Srpaulo	return;
1364209158Srpaulo
1365209158Srpaulofailed:
1366209158Srpaulo	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
1367189251Ssam}
1368189251Ssam
1369189251Ssam
1370189251Ssamstatic int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
1371189251Ssam					       struct wpa_eapol_key *key,
1372189251Ssam					       u16 ver,
1373189251Ssam					       const u8 *buf, size_t len)
1374189251Ssam{
1375189251Ssam	u8 mic[16];
1376189251Ssam	int ok = 0;
1377189251Ssam
1378189251Ssam	os_memcpy(mic, key->key_mic, 16);
1379189251Ssam	if (sm->tptk_set) {
1380189251Ssam		os_memset(key->key_mic, 0, 16);
1381189251Ssam		wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
1382189251Ssam				  key->key_mic);
1383189251Ssam		if (os_memcmp(mic, key->key_mic, 16) != 0) {
1384252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1385252726Srpaulo				"WPA: Invalid EAPOL-Key MIC "
1386252726Srpaulo				"when using TPTK - ignoring TPTK");
1387189251Ssam		} else {
1388189251Ssam			ok = 1;
1389189251Ssam			sm->tptk_set = 0;
1390189251Ssam			sm->ptk_set = 1;
1391189251Ssam			os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
1392189251Ssam		}
1393189251Ssam	}
1394189251Ssam
1395189251Ssam	if (!ok && sm->ptk_set) {
1396189251Ssam		os_memset(key->key_mic, 0, 16);
1397189251Ssam		wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
1398189251Ssam				  key->key_mic);
1399189251Ssam		if (os_memcmp(mic, key->key_mic, 16) != 0) {
1400252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1401252726Srpaulo				"WPA: Invalid EAPOL-Key MIC - "
1402252726Srpaulo				"dropping packet");
1403189251Ssam			return -1;
1404189251Ssam		}
1405189251Ssam		ok = 1;
1406189251Ssam	}
1407189251Ssam
1408189251Ssam	if (!ok) {
1409252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1410252726Srpaulo			"WPA: Could not verify EAPOL-Key MIC - "
1411252726Srpaulo			"dropping packet");
1412189251Ssam		return -1;
1413189251Ssam	}
1414189251Ssam
1415189251Ssam	os_memcpy(sm->rx_replay_counter, key->replay_counter,
1416189251Ssam		  WPA_REPLAY_COUNTER_LEN);
1417189251Ssam	sm->rx_replay_counter_set = 1;
1418189251Ssam	return 0;
1419189251Ssam}
1420189251Ssam
1421189251Ssam
1422189251Ssam/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
1423189251Ssamstatic int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
1424189251Ssam					   struct wpa_eapol_key *key, u16 ver)
1425189251Ssam{
1426189251Ssam	u16 keydatalen = WPA_GET_BE16(key->key_data_length);
1427189251Ssam
1428189251Ssam	wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
1429189251Ssam		    (u8 *) (key + 1), keydatalen);
1430189251Ssam	if (!sm->ptk_set) {
1431252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1432252726Srpaulo			"WPA: PTK not available, cannot decrypt EAPOL-Key Key "
1433252726Srpaulo			"Data");
1434189251Ssam		return -1;
1435189251Ssam	}
1436189251Ssam
1437189251Ssam	/* Decrypt key data here so that this operation does not need
1438189251Ssam	 * to be implemented separately for each message type. */
1439189251Ssam	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
1440189251Ssam		u8 ek[32];
1441189251Ssam		os_memcpy(ek, key->key_iv, 16);
1442189251Ssam		os_memcpy(ek + 16, sm->ptk.kek, 16);
1443214734Srpaulo		if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
1444252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
1445252726Srpaulo				"WPA: RC4 failed");
1446214734Srpaulo			return -1;
1447214734Srpaulo		}
1448189251Ssam	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
1449189251Ssam		   ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
1450189251Ssam		u8 *buf;
1451189251Ssam		if (keydatalen % 8) {
1452252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1453252726Srpaulo				"WPA: Unsupported AES-WRAP len %d",
1454252726Srpaulo				keydatalen);
1455189251Ssam			return -1;
1456189251Ssam		}
1457189251Ssam		keydatalen -= 8; /* AES-WRAP adds 8 bytes */
1458189251Ssam		buf = os_malloc(keydatalen);
1459189251Ssam		if (buf == NULL) {
1460252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1461252726Srpaulo				"WPA: No memory for AES-UNWRAP buffer");
1462189251Ssam			return -1;
1463189251Ssam		}
1464189251Ssam		if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
1465189251Ssam			       (u8 *) (key + 1), buf)) {
1466189251Ssam			os_free(buf);
1467252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1468252726Srpaulo				"WPA: AES unwrap failed - "
1469252726Srpaulo				"could not decrypt EAPOL-Key key data");
1470189251Ssam			return -1;
1471189251Ssam		}
1472189251Ssam		os_memcpy(key + 1, buf, keydatalen);
1473189251Ssam		os_free(buf);
1474189251Ssam		WPA_PUT_BE16(key->key_data_length, keydatalen);
1475189251Ssam	} else {
1476252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1477252726Srpaulo			"WPA: Unsupported key_info type %d", ver);
1478189251Ssam		return -1;
1479189251Ssam	}
1480189251Ssam	wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
1481189251Ssam			(u8 *) (key + 1), keydatalen);
1482189251Ssam	return 0;
1483189251Ssam}
1484189251Ssam
1485189251Ssam
1486189251Ssam/**
1487189251Ssam * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted
1488189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
1489189251Ssam */
1490189251Ssamvoid wpa_sm_aborted_cached(struct wpa_sm *sm)
1491189251Ssam{
1492189251Ssam	if (sm && sm->cur_pmksa) {
1493252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1494252726Srpaulo			"RSN: Cancelling PMKSA caching attempt");
1495189251Ssam		sm->cur_pmksa = NULL;
1496189251Ssam	}
1497189251Ssam}
1498189251Ssam
1499189251Ssam
1500252726Srpaulostatic void wpa_eapol_key_dump(struct wpa_sm *sm,
1501252726Srpaulo			       const struct wpa_eapol_key *key)
1502189251Ssam{
1503189251Ssam#ifndef CONFIG_NO_STDOUT_DEBUG
1504189251Ssam	u16 key_info = WPA_GET_BE16(key->key_info);
1505189251Ssam
1506252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "  EAPOL-Key type=%d", key->type);
1507252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1508252726Srpaulo		"  key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s%s%s%s%s%s%s%s)",
1509252726Srpaulo		key_info, key_info & WPA_KEY_INFO_TYPE_MASK,
1510252726Srpaulo		(key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
1511252726Srpaulo		WPA_KEY_INFO_KEY_INDEX_SHIFT,
1512252726Srpaulo		(key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13,
1513252726Srpaulo		key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group",
1514252726Srpaulo		key_info & WPA_KEY_INFO_INSTALL ? " Install" : "",
1515252726Srpaulo		key_info & WPA_KEY_INFO_ACK ? " Ack" : "",
1516252726Srpaulo		key_info & WPA_KEY_INFO_MIC ? " MIC" : "",
1517252726Srpaulo		key_info & WPA_KEY_INFO_SECURE ? " Secure" : "",
1518252726Srpaulo		key_info & WPA_KEY_INFO_ERROR ? " Error" : "",
1519252726Srpaulo		key_info & WPA_KEY_INFO_REQUEST ? " Request" : "",
1520252726Srpaulo		key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
1521252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1522252726Srpaulo		"  key_length=%u key_data_length=%u",
1523252726Srpaulo		WPA_GET_BE16(key->key_length),
1524252726Srpaulo		WPA_GET_BE16(key->key_data_length));
1525189251Ssam	wpa_hexdump(MSG_DEBUG, "  replay_counter",
1526189251Ssam		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
1527189251Ssam	wpa_hexdump(MSG_DEBUG, "  key_nonce", key->key_nonce, WPA_NONCE_LEN);
1528189251Ssam	wpa_hexdump(MSG_DEBUG, "  key_iv", key->key_iv, 16);
1529189251Ssam	wpa_hexdump(MSG_DEBUG, "  key_rsc", key->key_rsc, 8);
1530189251Ssam	wpa_hexdump(MSG_DEBUG, "  key_id (reserved)", key->key_id, 8);
1531189251Ssam	wpa_hexdump(MSG_DEBUG, "  key_mic", key->key_mic, 16);
1532189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */
1533189251Ssam}
1534189251Ssam
1535189251Ssam
1536189251Ssam/**
1537189251Ssam * wpa_sm_rx_eapol - Process received WPA EAPOL frames
1538189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
1539189251Ssam * @src_addr: Source MAC address of the EAPOL packet
1540189251Ssam * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1541189251Ssam * @len: Length of the EAPOL frame
1542189251Ssam * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure
1543189251Ssam *
1544189251Ssam * This function is called for each received EAPOL frame. Other than EAPOL-Key
1545189251Ssam * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is
1546189251Ssam * only processing WPA and WPA2 EAPOL-Key frames.
1547189251Ssam *
1548189251Ssam * The received EAPOL-Key packets are validated and valid packets are replied
1549189251Ssam * to. In addition, key material (PTK, GTK) is configured at the end of a
1550189251Ssam * successful key handshake.
1551189251Ssam */
1552189251Ssamint wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
1553189251Ssam		    const u8 *buf, size_t len)
1554189251Ssam{
1555189251Ssam	size_t plen, data_len, extra_len;
1556189251Ssam	struct ieee802_1x_hdr *hdr;
1557189251Ssam	struct wpa_eapol_key *key;
1558189251Ssam	u16 key_info, ver;
1559189251Ssam	u8 *tmp;
1560189251Ssam	int ret = -1;
1561189251Ssam	struct wpa_peerkey *peerkey = NULL;
1562189251Ssam
1563189251Ssam#ifdef CONFIG_IEEE80211R
1564189251Ssam	sm->ft_completed = 0;
1565189251Ssam#endif /* CONFIG_IEEE80211R */
1566189251Ssam
1567189251Ssam	if (len < sizeof(*hdr) + sizeof(*key)) {
1568252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1569252726Srpaulo			"WPA: EAPOL frame too short to be a WPA "
1570252726Srpaulo			"EAPOL-Key (len %lu, expecting at least %lu)",
1571252726Srpaulo			(unsigned long) len,
1572252726Srpaulo			(unsigned long) sizeof(*hdr) + sizeof(*key));
1573189251Ssam		return 0;
1574189251Ssam	}
1575189251Ssam
1576189251Ssam	tmp = os_malloc(len);
1577189251Ssam	if (tmp == NULL)
1578189251Ssam		return -1;
1579189251Ssam	os_memcpy(tmp, buf, len);
1580189251Ssam
1581189251Ssam	hdr = (struct ieee802_1x_hdr *) tmp;
1582189251Ssam	key = (struct wpa_eapol_key *) (hdr + 1);
1583189251Ssam	plen = be_to_host16(hdr->length);
1584189251Ssam	data_len = plen + sizeof(*hdr);
1585252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1586252726Srpaulo		"IEEE 802.1X RX: version=%d type=%d length=%lu",
1587252726Srpaulo		hdr->version, hdr->type, (unsigned long) plen);
1588189251Ssam
1589189251Ssam	if (hdr->version < EAPOL_VERSION) {
1590189251Ssam		/* TODO: backwards compatibility */
1591189251Ssam	}
1592189251Ssam	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
1593252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1594252726Srpaulo			"WPA: EAPOL frame (type %u) discarded, "
1595189251Ssam			"not a Key frame", hdr->type);
1596189251Ssam		ret = 0;
1597189251Ssam		goto out;
1598189251Ssam	}
1599189251Ssam	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
1600252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1601252726Srpaulo			"WPA: EAPOL frame payload size %lu "
1602252726Srpaulo			"invalid (frame size %lu)",
1603252726Srpaulo			(unsigned long) plen, (unsigned long) len);
1604189251Ssam		ret = 0;
1605189251Ssam		goto out;
1606189251Ssam	}
1607189251Ssam
1608189251Ssam	if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
1609189251Ssam	{
1610252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1611252726Srpaulo			"WPA: EAPOL-Key type (%d) unknown, discarded",
1612252726Srpaulo			key->type);
1613189251Ssam		ret = 0;
1614189251Ssam		goto out;
1615189251Ssam	}
1616252726Srpaulo	wpa_eapol_key_dump(sm, key);
1617189251Ssam
1618189251Ssam	eapol_sm_notify_lower_layer_success(sm->eapol, 0);
1619189251Ssam	wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
1620189251Ssam	if (data_len < len) {
1621252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1622252726Srpaulo			"WPA: ignoring %lu bytes after the IEEE 802.1X data",
1623252726Srpaulo			(unsigned long) len - data_len);
1624189251Ssam	}
1625189251Ssam	key_info = WPA_GET_BE16(key->key_info);
1626189251Ssam	ver = key_info & WPA_KEY_INFO_TYPE_MASK;
1627189251Ssam	if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
1628209158Srpaulo#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
1629189251Ssam	    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
1630209158Srpaulo#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
1631189251Ssam	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
1632252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1633252726Srpaulo			"WPA: Unsupported EAPOL-Key descriptor version %d",
1634252726Srpaulo			ver);
1635189251Ssam		goto out;
1636189251Ssam	}
1637189251Ssam
1638189251Ssam#ifdef CONFIG_IEEE80211R
1639189251Ssam	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
1640189251Ssam		/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
1641189251Ssam		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
1642252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1643252726Srpaulo				"FT: AP did not use AES-128-CMAC");
1644189251Ssam			goto out;
1645189251Ssam		}
1646189251Ssam	} else
1647189251Ssam#endif /* CONFIG_IEEE80211R */
1648189251Ssam#ifdef CONFIG_IEEE80211W
1649189251Ssam	if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
1650189251Ssam		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
1651252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1652252726Srpaulo				"WPA: AP did not use the "
1653252726Srpaulo				"negotiated AES-128-CMAC");
1654189251Ssam			goto out;
1655189251Ssam		}
1656189251Ssam	} else
1657189251Ssam#endif /* CONFIG_IEEE80211W */
1658189251Ssam	if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
1659189251Ssam	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
1660252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1661252726Srpaulo			"WPA: CCMP is used, but EAPOL-Key "
1662252726Srpaulo			"descriptor version (%d) is not 2", ver);
1663189251Ssam		if (sm->group_cipher != WPA_CIPHER_CCMP &&
1664189251Ssam		    !(key_info & WPA_KEY_INFO_KEY_TYPE)) {
1665189251Ssam			/* Earlier versions of IEEE 802.11i did not explicitly
1666189251Ssam			 * require version 2 descriptor for all EAPOL-Key
1667189251Ssam			 * packets, so allow group keys to use version 1 if
1668189251Ssam			 * CCMP is not used for them. */
1669252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1670252726Srpaulo				"WPA: Backwards compatibility: allow invalid "
1671252726Srpaulo				"version for non-CCMP group keys");
1672189251Ssam		} else
1673189251Ssam			goto out;
1674189251Ssam	}
1675252726Srpaulo	if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
1676252726Srpaulo	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
1677252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1678252726Srpaulo			"WPA: GCMP is used, but EAPOL-Key "
1679252726Srpaulo			"descriptor version (%d) is not 2", ver);
1680252726Srpaulo		goto out;
1681252726Srpaulo	}
1682189251Ssam
1683189251Ssam#ifdef CONFIG_PEERKEY
1684189251Ssam	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
1685189251Ssam		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
1686189251Ssam			break;
1687189251Ssam	}
1688189251Ssam
1689189251Ssam	if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
1690189251Ssam		if (!peerkey->initiator && peerkey->replay_counter_set &&
1691189251Ssam		    os_memcmp(key->replay_counter, peerkey->replay_counter,
1692189251Ssam			      WPA_REPLAY_COUNTER_LEN) <= 0) {
1693252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1694252726Srpaulo				"RSN: EAPOL-Key Replay Counter did not "
1695252726Srpaulo				"increase (STK) - dropping packet");
1696189251Ssam			goto out;
1697189251Ssam		} else if (peerkey->initiator) {
1698189251Ssam			u8 _tmp[WPA_REPLAY_COUNTER_LEN];
1699189251Ssam			os_memcpy(_tmp, key->replay_counter,
1700189251Ssam				  WPA_REPLAY_COUNTER_LEN);
1701189251Ssam			inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
1702189251Ssam			if (os_memcmp(_tmp, peerkey->replay_counter,
1703189251Ssam				      WPA_REPLAY_COUNTER_LEN) != 0) {
1704252726Srpaulo				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1705252726Srpaulo					"RSN: EAPOL-Key Replay "
1706252726Srpaulo					"Counter did not match (STK) - "
1707252726Srpaulo					"dropping packet");
1708189251Ssam				goto out;
1709189251Ssam			}
1710189251Ssam		}
1711189251Ssam	}
1712189251Ssam
1713189251Ssam	if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
1714252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1715252726Srpaulo			"RSN: Ack bit in key_info from STK peer");
1716189251Ssam		goto out;
1717189251Ssam	}
1718189251Ssam#endif /* CONFIG_PEERKEY */
1719189251Ssam
1720189251Ssam	if (!peerkey && sm->rx_replay_counter_set &&
1721189251Ssam	    os_memcmp(key->replay_counter, sm->rx_replay_counter,
1722189251Ssam		      WPA_REPLAY_COUNTER_LEN) <= 0) {
1723252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1724252726Srpaulo			"WPA: EAPOL-Key Replay Counter did not increase - "
1725252726Srpaulo			"dropping packet");
1726189251Ssam		goto out;
1727189251Ssam	}
1728189251Ssam
1729189251Ssam	if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
1730189251Ssam#ifdef CONFIG_PEERKEY
1731189251Ssam	    && (peerkey == NULL || !peerkey->initiator)
1732189251Ssam#endif /* CONFIG_PEERKEY */
1733189251Ssam		) {
1734252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1735252726Srpaulo			"WPA: No Ack bit in key_info");
1736189251Ssam		goto out;
1737189251Ssam	}
1738189251Ssam
1739189251Ssam	if (key_info & WPA_KEY_INFO_REQUEST) {
1740252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1741252726Srpaulo			"WPA: EAPOL-Key with Request bit - dropped");
1742189251Ssam		goto out;
1743189251Ssam	}
1744189251Ssam
1745189251Ssam	if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
1746189251Ssam	    wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
1747189251Ssam		goto out;
1748189251Ssam
1749189251Ssam#ifdef CONFIG_PEERKEY
1750189251Ssam	if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
1751189251Ssam	    peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
1752189251Ssam		goto out;
1753189251Ssam#endif /* CONFIG_PEERKEY */
1754189251Ssam
1755189251Ssam	extra_len = data_len - sizeof(*hdr) - sizeof(*key);
1756189251Ssam
1757189251Ssam	if (WPA_GET_BE16(key->key_data_length) > extra_len) {
1758214734Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
1759189251Ssam			"frame - key_data overflow (%d > %lu)",
1760189251Ssam			WPA_GET_BE16(key->key_data_length),
1761189251Ssam			(unsigned long) extra_len);
1762189251Ssam		goto out;
1763189251Ssam	}
1764189251Ssam	extra_len = WPA_GET_BE16(key->key_data_length);
1765189251Ssam
1766189251Ssam	if (sm->proto == WPA_PROTO_RSN &&
1767189251Ssam	    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
1768189251Ssam		if (wpa_supplicant_decrypt_key_data(sm, key, ver))
1769189251Ssam			goto out;
1770189251Ssam		extra_len = WPA_GET_BE16(key->key_data_length);
1771189251Ssam	}
1772189251Ssam
1773189251Ssam	if (key_info & WPA_KEY_INFO_KEY_TYPE) {
1774189251Ssam		if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
1775252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1776252726Srpaulo				"WPA: Ignored EAPOL-Key (Pairwise) with "
1777252726Srpaulo				"non-zero key index");
1778189251Ssam			goto out;
1779189251Ssam		}
1780189251Ssam		if (peerkey) {
1781189251Ssam			/* PeerKey 4-Way Handshake */
1782189251Ssam			peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
1783189251Ssam		} else if (key_info & WPA_KEY_INFO_MIC) {
1784189251Ssam			/* 3/4 4-Way Handshake */
1785189251Ssam			wpa_supplicant_process_3_of_4(sm, key, ver);
1786189251Ssam		} else {
1787189251Ssam			/* 1/4 4-Way Handshake */
1788189251Ssam			wpa_supplicant_process_1_of_4(sm, src_addr, key,
1789189251Ssam						      ver);
1790189251Ssam		}
1791189251Ssam	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
1792189251Ssam		/* PeerKey SMK Handshake */
1793189251Ssam		peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,
1794189251Ssam				     ver);
1795189251Ssam	} else {
1796189251Ssam		if (key_info & WPA_KEY_INFO_MIC) {
1797189251Ssam			/* 1/2 Group Key Handshake */
1798189251Ssam			wpa_supplicant_process_1_of_2(sm, src_addr, key,
1799189251Ssam						      extra_len, ver);
1800189251Ssam		} else {
1801252726Srpaulo			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
1802252726Srpaulo				"WPA: EAPOL-Key (Group) without Mic bit - "
1803252726Srpaulo				"dropped");
1804189251Ssam		}
1805189251Ssam	}
1806189251Ssam
1807189251Ssam	ret = 1;
1808189251Ssam
1809189251Ssamout:
1810189251Ssam	os_free(tmp);
1811189251Ssam	return ret;
1812189251Ssam}
1813189251Ssam
1814189251Ssam
1815189251Ssam#ifdef CONFIG_CTRL_IFACE
1816189251Ssamstatic u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
1817189251Ssam{
1818189251Ssam	switch (sm->key_mgmt) {
1819189251Ssam	case WPA_KEY_MGMT_IEEE8021X:
1820189251Ssam		return (sm->proto == WPA_PROTO_RSN ?
1821189251Ssam			RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
1822189251Ssam			WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
1823189251Ssam	case WPA_KEY_MGMT_PSK:
1824189251Ssam		return (sm->proto == WPA_PROTO_RSN ?
1825189251Ssam			RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X :
1826189251Ssam			WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
1827189251Ssam#ifdef CONFIG_IEEE80211R
1828189251Ssam	case WPA_KEY_MGMT_FT_IEEE8021X:
1829189251Ssam		return RSN_AUTH_KEY_MGMT_FT_802_1X;
1830189251Ssam	case WPA_KEY_MGMT_FT_PSK:
1831189251Ssam		return RSN_AUTH_KEY_MGMT_FT_PSK;
1832189251Ssam#endif /* CONFIG_IEEE80211R */
1833189251Ssam#ifdef CONFIG_IEEE80211W
1834189251Ssam	case WPA_KEY_MGMT_IEEE8021X_SHA256:
1835189251Ssam		return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
1836189251Ssam	case WPA_KEY_MGMT_PSK_SHA256:
1837189251Ssam		return RSN_AUTH_KEY_MGMT_PSK_SHA256;
1838189251Ssam#endif /* CONFIG_IEEE80211W */
1839252726Srpaulo	case WPA_KEY_MGMT_CCKM:
1840252726Srpaulo		return (sm->proto == WPA_PROTO_RSN ?
1841252726Srpaulo			RSN_AUTH_KEY_MGMT_CCKM:
1842252726Srpaulo			WPA_AUTH_KEY_MGMT_CCKM);
1843189251Ssam	case WPA_KEY_MGMT_WPA_NONE:
1844189251Ssam		return WPA_AUTH_KEY_MGMT_NONE;
1845189251Ssam	default:
1846189251Ssam		return 0;
1847189251Ssam	}
1848189251Ssam}
1849189251Ssam
1850189251Ssam
1851189251Ssam#define RSN_SUITE "%02x-%02x-%02x-%d"
1852189251Ssam#define RSN_SUITE_ARG(s) \
1853189251Ssam((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
1854189251Ssam
1855189251Ssam/**
1856189251Ssam * wpa_sm_get_mib - Dump text list of MIB entries
1857189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
1858189251Ssam * @buf: Buffer for the list
1859189251Ssam * @buflen: Length of the buffer
1860189251Ssam * Returns: Number of bytes written to buffer
1861189251Ssam *
1862189251Ssam * This function is used fetch dot11 MIB variables.
1863189251Ssam */
1864189251Ssamint wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
1865189251Ssam{
1866189251Ssam	char pmkid_txt[PMKID_LEN * 2 + 1];
1867189251Ssam	int rsna, ret;
1868189251Ssam	size_t len;
1869189251Ssam
1870189251Ssam	if (sm->cur_pmksa) {
1871189251Ssam		wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
1872189251Ssam				 sm->cur_pmksa->pmkid, PMKID_LEN);
1873189251Ssam	} else
1874189251Ssam		pmkid_txt[0] = '\0';
1875189251Ssam
1876189251Ssam	if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
1877189251Ssam	     wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
1878189251Ssam	    sm->proto == WPA_PROTO_RSN)
1879189251Ssam		rsna = 1;
1880189251Ssam	else
1881189251Ssam		rsna = 0;
1882189251Ssam
1883189251Ssam	ret = os_snprintf(buf, buflen,
1884189251Ssam			  "dot11RSNAOptionImplemented=TRUE\n"
1885189251Ssam			  "dot11RSNAPreauthenticationImplemented=TRUE\n"
1886189251Ssam			  "dot11RSNAEnabled=%s\n"
1887189251Ssam			  "dot11RSNAPreauthenticationEnabled=%s\n"
1888189251Ssam			  "dot11RSNAConfigVersion=%d\n"
1889189251Ssam			  "dot11RSNAConfigPairwiseKeysSupported=5\n"
1890189251Ssam			  "dot11RSNAConfigGroupCipherSize=%d\n"
1891189251Ssam			  "dot11RSNAConfigPMKLifetime=%d\n"
1892189251Ssam			  "dot11RSNAConfigPMKReauthThreshold=%d\n"
1893189251Ssam			  "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n"
1894189251Ssam			  "dot11RSNAConfigSATimeout=%d\n",
1895189251Ssam			  rsna ? "TRUE" : "FALSE",
1896189251Ssam			  rsna ? "TRUE" : "FALSE",
1897189251Ssam			  RSN_VERSION,
1898252726Srpaulo			  wpa_cipher_key_len(sm->group_cipher) * 8,
1899189251Ssam			  sm->dot11RSNAConfigPMKLifetime,
1900189251Ssam			  sm->dot11RSNAConfigPMKReauthThreshold,
1901189251Ssam			  sm->dot11RSNAConfigSATimeout);
1902189251Ssam	if (ret < 0 || (size_t) ret >= buflen)
1903189251Ssam		return 0;
1904189251Ssam	len = ret;
1905189251Ssam
1906189251Ssam	ret = os_snprintf(
1907189251Ssam		buf + len, buflen - len,
1908189251Ssam		"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
1909189251Ssam		"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
1910189251Ssam		"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
1911189251Ssam		"dot11RSNAPMKIDUsed=%s\n"
1912189251Ssam		"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
1913189251Ssam		"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
1914189251Ssam		"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
1915189251Ssam		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
1916189251Ssam		"dot11RSNA4WayHandshakeFailures=%u\n",
1917189251Ssam		RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
1918252726Srpaulo		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
1919252726Srpaulo						  sm->pairwise_cipher)),
1920252726Srpaulo		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
1921252726Srpaulo						  sm->group_cipher)),
1922189251Ssam		pmkid_txt,
1923189251Ssam		RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
1924252726Srpaulo		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
1925252726Srpaulo						  sm->pairwise_cipher)),
1926252726Srpaulo		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
1927252726Srpaulo						  sm->group_cipher)),
1928189251Ssam		sm->dot11RSNA4WayHandshakeFailures);
1929189251Ssam	if (ret >= 0 && (size_t) ret < buflen)
1930189251Ssam		len += ret;
1931189251Ssam
1932189251Ssam	return (int) len;
1933189251Ssam}
1934189251Ssam#endif /* CONFIG_CTRL_IFACE */
1935189251Ssam
1936189251Ssam
1937189251Ssamstatic void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
1938252726Srpaulo				 void *ctx, enum pmksa_free_reason reason)
1939189251Ssam{
1940189251Ssam	struct wpa_sm *sm = ctx;
1941252726Srpaulo	int deauth = 0;
1942189251Ssam
1943252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA cache entry free_cb: "
1944252726Srpaulo		MACSTR " reason=%d", MAC2STR(entry->aa), reason);
1945252726Srpaulo
1946252726Srpaulo	if (sm->cur_pmksa == entry) {
1947252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1948252726Srpaulo			"RSN: %s current PMKSA entry",
1949252726Srpaulo			reason == PMKSA_REPLACE ? "replaced" : "removed");
1950252726Srpaulo		pmksa_cache_clear_current(sm);
1951252726Srpaulo
1952252726Srpaulo		/*
1953252726Srpaulo		 * If an entry is simply being replaced, there's no need to
1954252726Srpaulo		 * deauthenticate because it will be immediately re-added.
1955252726Srpaulo		 * This happens when EAP authentication is completed again
1956252726Srpaulo		 * (reauth or failed PMKSA caching attempt).
1957252726Srpaulo		 */
1958252726Srpaulo		if (reason != PMKSA_REPLACE)
1959252726Srpaulo			deauth = 1;
1960252726Srpaulo	}
1961252726Srpaulo
1962252726Srpaulo	if (reason == PMKSA_EXPIRE &&
1963189251Ssam	    (sm->pmk_len == entry->pmk_len &&
1964189251Ssam	     os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
1965252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
1966252726Srpaulo			"RSN: deauthenticating due to expired PMK");
1967252726Srpaulo		pmksa_cache_clear_current(sm);
1968252726Srpaulo		deauth = 1;
1969252726Srpaulo	}
1970189251Ssam
1971252726Srpaulo	if (deauth) {
1972189251Ssam		os_memset(sm->pmk, 0, sizeof(sm->pmk));
1973189251Ssam		wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
1974189251Ssam	}
1975189251Ssam}
1976189251Ssam
1977189251Ssam
1978189251Ssam/**
1979189251Ssam * wpa_sm_init - Initialize WPA state machine
1980189251Ssam * @ctx: Context pointer for callbacks; this needs to be an allocated buffer
1981189251Ssam * Returns: Pointer to the allocated WPA state machine data
1982189251Ssam *
1983189251Ssam * This function is used to allocate a new WPA state machine and the returned
1984189251Ssam * value is passed to all WPA state machine calls.
1985189251Ssam */
1986189251Ssamstruct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
1987189251Ssam{
1988189251Ssam	struct wpa_sm *sm;
1989189251Ssam
1990189251Ssam	sm = os_zalloc(sizeof(*sm));
1991189251Ssam	if (sm == NULL)
1992189251Ssam		return NULL;
1993214734Srpaulo	dl_list_init(&sm->pmksa_candidates);
1994189251Ssam	sm->renew_snonce = 1;
1995189251Ssam	sm->ctx = ctx;
1996189251Ssam
1997189251Ssam	sm->dot11RSNAConfigPMKLifetime = 43200;
1998189251Ssam	sm->dot11RSNAConfigPMKReauthThreshold = 70;
1999189251Ssam	sm->dot11RSNAConfigSATimeout = 60;
2000189251Ssam
2001189251Ssam	sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
2002189251Ssam	if (sm->pmksa == NULL) {
2003252726Srpaulo		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
2004252726Srpaulo			"RSN: PMKSA cache initialization failed");
2005189251Ssam		os_free(sm);
2006189251Ssam		return NULL;
2007189251Ssam	}
2008189251Ssam
2009189251Ssam	return sm;
2010189251Ssam}
2011189251Ssam
2012189251Ssam
2013189251Ssam/**
2014189251Ssam * wpa_sm_deinit - Deinitialize WPA state machine
2015189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2016189251Ssam */
2017189251Ssamvoid wpa_sm_deinit(struct wpa_sm *sm)
2018189251Ssam{
2019189251Ssam	if (sm == NULL)
2020189251Ssam		return;
2021189251Ssam	pmksa_cache_deinit(sm->pmksa);
2022189251Ssam	eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
2023189251Ssam	eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
2024189251Ssam	os_free(sm->assoc_wpa_ie);
2025189251Ssam	os_free(sm->ap_wpa_ie);
2026189251Ssam	os_free(sm->ap_rsn_ie);
2027189251Ssam	os_free(sm->ctx);
2028189251Ssam	peerkey_deinit(sm);
2029214734Srpaulo#ifdef CONFIG_IEEE80211R
2030214734Srpaulo	os_free(sm->assoc_resp_ies);
2031214734Srpaulo#endif /* CONFIG_IEEE80211R */
2032189251Ssam	os_free(sm);
2033189251Ssam}
2034189251Ssam
2035189251Ssam
2036189251Ssam/**
2037189251Ssam * wpa_sm_notify_assoc - Notify WPA state machine about association
2038189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2039189251Ssam * @bssid: The BSSID of the new association
2040189251Ssam *
2041189251Ssam * This function is called to let WPA state machine know that the connection
2042189251Ssam * was established.
2043189251Ssam */
2044189251Ssamvoid wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
2045189251Ssam{
2046189251Ssam	int clear_ptk = 1;
2047189251Ssam
2048189251Ssam	if (sm == NULL)
2049189251Ssam		return;
2050189251Ssam
2051252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
2052252726Srpaulo		"WPA: Association event - clear replay counter");
2053189251Ssam	os_memcpy(sm->bssid, bssid, ETH_ALEN);
2054189251Ssam	os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
2055189251Ssam	sm->rx_replay_counter_set = 0;
2056189251Ssam	sm->renew_snonce = 1;
2057189251Ssam	if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0)
2058189251Ssam		rsn_preauth_deinit(sm);
2059189251Ssam
2060189251Ssam#ifdef CONFIG_IEEE80211R
2061189251Ssam	if (wpa_ft_is_completed(sm)) {
2062214734Srpaulo		/*
2063214734Srpaulo		 * Clear portValid to kick EAPOL state machine to re-enter
2064214734Srpaulo		 * AUTHENTICATED state to get the EAPOL port Authorized.
2065214734Srpaulo		 */
2066214734Srpaulo		eapol_sm_notify_portValid(sm->eapol, FALSE);
2067189251Ssam		wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
2068189251Ssam
2069189251Ssam		/* Prepare for the next transition */
2070214734Srpaulo		wpa_ft_prepare_auth_request(sm, NULL);
2071189251Ssam
2072189251Ssam		clear_ptk = 0;
2073189251Ssam	}
2074189251Ssam#endif /* CONFIG_IEEE80211R */
2075189251Ssam
2076189251Ssam	if (clear_ptk) {
2077189251Ssam		/*
2078189251Ssam		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
2079189251Ssam		 * this is not part of a Fast BSS Transition.
2080189251Ssam		 */
2081252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK");
2082189251Ssam		sm->ptk_set = 0;
2083189251Ssam		sm->tptk_set = 0;
2084189251Ssam	}
2085252726Srpaulo
2086252726Srpaulo#ifdef CONFIG_TDLS
2087252726Srpaulo	wpa_tdls_assoc(sm);
2088252726Srpaulo#endif /* CONFIG_TDLS */
2089189251Ssam}
2090189251Ssam
2091189251Ssam
2092189251Ssam/**
2093189251Ssam * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation
2094189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2095189251Ssam *
2096189251Ssam * This function is called to let WPA state machine know that the connection
2097189251Ssam * was lost. This will abort any existing pre-authentication session.
2098189251Ssam */
2099189251Ssamvoid wpa_sm_notify_disassoc(struct wpa_sm *sm)
2100189251Ssam{
2101189251Ssam	rsn_preauth_deinit(sm);
2102252726Srpaulo	pmksa_cache_clear_current(sm);
2103189251Ssam	if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
2104189251Ssam		sm->dot11RSNA4WayHandshakeFailures++;
2105252726Srpaulo#ifdef CONFIG_TDLS
2106252726Srpaulo	wpa_tdls_disassoc(sm);
2107252726Srpaulo#endif /* CONFIG_TDLS */
2108189251Ssam}
2109189251Ssam
2110189251Ssam
2111189251Ssam/**
2112189251Ssam * wpa_sm_set_pmk - Set PMK
2113189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2114189251Ssam * @pmk: The new PMK
2115189251Ssam * @pmk_len: The length of the new PMK in bytes
2116189251Ssam *
2117189251Ssam * Configure the PMK for WPA state machine.
2118189251Ssam */
2119189251Ssamvoid wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
2120189251Ssam{
2121189251Ssam	if (sm == NULL)
2122189251Ssam		return;
2123189251Ssam
2124189251Ssam	sm->pmk_len = pmk_len;
2125189251Ssam	os_memcpy(sm->pmk, pmk, pmk_len);
2126189251Ssam
2127189251Ssam#ifdef CONFIG_IEEE80211R
2128189251Ssam	/* Set XXKey to be PSK for FT key derivation */
2129189251Ssam	sm->xxkey_len = pmk_len;
2130189251Ssam	os_memcpy(sm->xxkey, pmk, pmk_len);
2131189251Ssam#endif /* CONFIG_IEEE80211R */
2132189251Ssam}
2133189251Ssam
2134189251Ssam
2135189251Ssam/**
2136189251Ssam * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA
2137189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2138189251Ssam *
2139189251Ssam * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK
2140189251Ssam * will be cleared.
2141189251Ssam */
2142189251Ssamvoid wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
2143189251Ssam{
2144189251Ssam	if (sm == NULL)
2145189251Ssam		return;
2146189251Ssam
2147189251Ssam	if (sm->cur_pmksa) {
2148189251Ssam		sm->pmk_len = sm->cur_pmksa->pmk_len;
2149189251Ssam		os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
2150189251Ssam	} else {
2151189251Ssam		sm->pmk_len = PMK_LEN;
2152189251Ssam		os_memset(sm->pmk, 0, PMK_LEN);
2153189251Ssam	}
2154189251Ssam}
2155189251Ssam
2156189251Ssam
2157189251Ssam/**
2158189251Ssam * wpa_sm_set_fast_reauth - Set fast reauthentication (EAP) enabled/disabled
2159189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2160189251Ssam * @fast_reauth: Whether fast reauthentication (EAP) is allowed
2161189251Ssam */
2162189251Ssamvoid wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
2163189251Ssam{
2164189251Ssam	if (sm)
2165189251Ssam		sm->fast_reauth = fast_reauth;
2166189251Ssam}
2167189251Ssam
2168189251Ssam
2169189251Ssam/**
2170189251Ssam * wpa_sm_set_scard_ctx - Set context pointer for smartcard callbacks
2171189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2172189251Ssam * @scard_ctx: Context pointer for smartcard related callback functions
2173189251Ssam */
2174189251Ssamvoid wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
2175189251Ssam{
2176189251Ssam	if (sm == NULL)
2177189251Ssam		return;
2178189251Ssam	sm->scard_ctx = scard_ctx;
2179189251Ssam	if (sm->preauth_eapol)
2180189251Ssam		eapol_sm_register_scard_ctx(sm->preauth_eapol, scard_ctx);
2181189251Ssam}
2182189251Ssam
2183189251Ssam
2184189251Ssam/**
2185189251Ssam * wpa_sm_set_config - Notification of current configration change
2186189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2187189251Ssam * @config: Pointer to current network configuration
2188189251Ssam *
2189189251Ssam * Notify WPA state machine that configuration has changed. config will be
2190189251Ssam * stored as a backpointer to network configuration. This can be %NULL to clear
2191189251Ssam * the stored pointed.
2192189251Ssam */
2193189251Ssamvoid wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
2194189251Ssam{
2195189251Ssam	if (!sm)
2196189251Ssam		return;
2197189251Ssam
2198189251Ssam	if (config) {
2199189251Ssam		sm->network_ctx = config->network_ctx;
2200189251Ssam		sm->peerkey_enabled = config->peerkey_enabled;
2201189251Ssam		sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher;
2202189251Ssam		sm->proactive_key_caching = config->proactive_key_caching;
2203189251Ssam		sm->eap_workaround = config->eap_workaround;
2204189251Ssam		sm->eap_conf_ctx = config->eap_conf_ctx;
2205189251Ssam		if (config->ssid) {
2206189251Ssam			os_memcpy(sm->ssid, config->ssid, config->ssid_len);
2207189251Ssam			sm->ssid_len = config->ssid_len;
2208189251Ssam		} else
2209189251Ssam			sm->ssid_len = 0;
2210189251Ssam		sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
2211189251Ssam	} else {
2212189251Ssam		sm->network_ctx = NULL;
2213189251Ssam		sm->peerkey_enabled = 0;
2214189251Ssam		sm->allowed_pairwise_cipher = 0;
2215189251Ssam		sm->proactive_key_caching = 0;
2216189251Ssam		sm->eap_workaround = 0;
2217189251Ssam		sm->eap_conf_ctx = NULL;
2218189251Ssam		sm->ssid_len = 0;
2219189251Ssam		sm->wpa_ptk_rekey = 0;
2220189251Ssam	}
2221189251Ssam}
2222189251Ssam
2223189251Ssam
2224189251Ssam/**
2225189251Ssam * wpa_sm_set_own_addr - Set own MAC address
2226189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2227189251Ssam * @addr: Own MAC address
2228189251Ssam */
2229189251Ssamvoid wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
2230189251Ssam{
2231189251Ssam	if (sm)
2232189251Ssam		os_memcpy(sm->own_addr, addr, ETH_ALEN);
2233189251Ssam}
2234189251Ssam
2235189251Ssam
2236189251Ssam/**
2237189251Ssam * wpa_sm_set_ifname - Set network interface name
2238189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2239189251Ssam * @ifname: Interface name
2240189251Ssam * @bridge_ifname: Optional bridge interface name (for pre-auth)
2241189251Ssam */
2242189251Ssamvoid wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
2243189251Ssam		       const char *bridge_ifname)
2244189251Ssam{
2245189251Ssam	if (sm) {
2246189251Ssam		sm->ifname = ifname;
2247189251Ssam		sm->bridge_ifname = bridge_ifname;
2248189251Ssam	}
2249189251Ssam}
2250189251Ssam
2251189251Ssam
2252189251Ssam/**
2253189251Ssam * wpa_sm_set_eapol - Set EAPOL state machine pointer
2254189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2255189251Ssam * @eapol: Pointer to EAPOL state machine allocated with eapol_sm_init()
2256189251Ssam */
2257189251Ssamvoid wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
2258189251Ssam{
2259189251Ssam	if (sm)
2260189251Ssam		sm->eapol = eapol;
2261189251Ssam}
2262189251Ssam
2263189251Ssam
2264189251Ssam/**
2265189251Ssam * wpa_sm_set_param - Set WPA state machine parameters
2266189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2267189251Ssam * @param: Parameter field
2268189251Ssam * @value: Parameter value
2269189251Ssam * Returns: 0 on success, -1 on failure
2270189251Ssam */
2271189251Ssamint wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
2272189251Ssam		     unsigned int value)
2273189251Ssam{
2274189251Ssam	int ret = 0;
2275189251Ssam
2276189251Ssam	if (sm == NULL)
2277189251Ssam		return -1;
2278189251Ssam
2279189251Ssam	switch (param) {
2280189251Ssam	case RSNA_PMK_LIFETIME:
2281189251Ssam		if (value > 0)
2282189251Ssam			sm->dot11RSNAConfigPMKLifetime = value;
2283189251Ssam		else
2284189251Ssam			ret = -1;
2285189251Ssam		break;
2286189251Ssam	case RSNA_PMK_REAUTH_THRESHOLD:
2287189251Ssam		if (value > 0 && value <= 100)
2288189251Ssam			sm->dot11RSNAConfigPMKReauthThreshold = value;
2289189251Ssam		else
2290189251Ssam			ret = -1;
2291189251Ssam		break;
2292189251Ssam	case RSNA_SA_TIMEOUT:
2293189251Ssam		if (value > 0)
2294189251Ssam			sm->dot11RSNAConfigSATimeout = value;
2295189251Ssam		else
2296189251Ssam			ret = -1;
2297189251Ssam		break;
2298189251Ssam	case WPA_PARAM_PROTO:
2299189251Ssam		sm->proto = value;
2300189251Ssam		break;
2301189251Ssam	case WPA_PARAM_PAIRWISE:
2302189251Ssam		sm->pairwise_cipher = value;
2303189251Ssam		break;
2304189251Ssam	case WPA_PARAM_GROUP:
2305189251Ssam		sm->group_cipher = value;
2306189251Ssam		break;
2307189251Ssam	case WPA_PARAM_KEY_MGMT:
2308189251Ssam		sm->key_mgmt = value;
2309189251Ssam		break;
2310189251Ssam#ifdef CONFIG_IEEE80211W
2311189251Ssam	case WPA_PARAM_MGMT_GROUP:
2312189251Ssam		sm->mgmt_group_cipher = value;
2313189251Ssam		break;
2314189251Ssam#endif /* CONFIG_IEEE80211W */
2315189251Ssam	case WPA_PARAM_RSN_ENABLED:
2316189251Ssam		sm->rsn_enabled = value;
2317189251Ssam		break;
2318214734Srpaulo	case WPA_PARAM_MFP:
2319214734Srpaulo		sm->mfp = value;
2320214734Srpaulo		break;
2321189251Ssam	default:
2322189251Ssam		break;
2323189251Ssam	}
2324189251Ssam
2325189251Ssam	return ret;
2326189251Ssam}
2327189251Ssam
2328189251Ssam
2329189251Ssam/**
2330189251Ssam * wpa_sm_get_param - Get WPA state machine parameters
2331189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2332189251Ssam * @param: Parameter field
2333189251Ssam * Returns: Parameter value
2334189251Ssam */
2335189251Ssamunsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
2336189251Ssam{
2337189251Ssam	if (sm == NULL)
2338189251Ssam		return 0;
2339189251Ssam
2340189251Ssam	switch (param) {
2341189251Ssam	case RSNA_PMK_LIFETIME:
2342189251Ssam		return sm->dot11RSNAConfigPMKLifetime;
2343189251Ssam	case RSNA_PMK_REAUTH_THRESHOLD:
2344189251Ssam		return sm->dot11RSNAConfigPMKReauthThreshold;
2345189251Ssam	case RSNA_SA_TIMEOUT:
2346189251Ssam		return sm->dot11RSNAConfigSATimeout;
2347189251Ssam	case WPA_PARAM_PROTO:
2348189251Ssam		return sm->proto;
2349189251Ssam	case WPA_PARAM_PAIRWISE:
2350189251Ssam		return sm->pairwise_cipher;
2351189251Ssam	case WPA_PARAM_GROUP:
2352189251Ssam		return sm->group_cipher;
2353189251Ssam	case WPA_PARAM_KEY_MGMT:
2354189251Ssam		return sm->key_mgmt;
2355189251Ssam#ifdef CONFIG_IEEE80211W
2356189251Ssam	case WPA_PARAM_MGMT_GROUP:
2357189251Ssam		return sm->mgmt_group_cipher;
2358189251Ssam#endif /* CONFIG_IEEE80211W */
2359189251Ssam	case WPA_PARAM_RSN_ENABLED:
2360189251Ssam		return sm->rsn_enabled;
2361189251Ssam	default:
2362189251Ssam		return 0;
2363189251Ssam	}
2364189251Ssam}
2365189251Ssam
2366189251Ssam
2367189251Ssam/**
2368189251Ssam * wpa_sm_get_status - Get WPA state machine
2369189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2370189251Ssam * @buf: Buffer for status information
2371189251Ssam * @buflen: Maximum buffer length
2372189251Ssam * @verbose: Whether to include verbose status information
2373189251Ssam * Returns: Number of bytes written to buf.
2374189251Ssam *
2375189251Ssam * Query WPA state machine for status information. This function fills in
2376189251Ssam * a text area with current status information. If the buffer (buf) is not
2377189251Ssam * large enough, status information will be truncated to fit the buffer.
2378189251Ssam */
2379189251Ssamint wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
2380189251Ssam		      int verbose)
2381189251Ssam{
2382189251Ssam	char *pos = buf, *end = buf + buflen;
2383189251Ssam	int ret;
2384189251Ssam
2385189251Ssam	ret = os_snprintf(pos, end - pos,
2386189251Ssam			  "pairwise_cipher=%s\n"
2387189251Ssam			  "group_cipher=%s\n"
2388189251Ssam			  "key_mgmt=%s\n",
2389189251Ssam			  wpa_cipher_txt(sm->pairwise_cipher),
2390189251Ssam			  wpa_cipher_txt(sm->group_cipher),
2391189251Ssam			  wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
2392189251Ssam	if (ret < 0 || ret >= end - pos)
2393189251Ssam		return pos - buf;
2394189251Ssam	pos += ret;
2395252726Srpaulo
2396252726Srpaulo	if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
2397252726Srpaulo		struct wpa_ie_data rsn;
2398252726Srpaulo		if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
2399252726Srpaulo		    >= 0 &&
2400252726Srpaulo		    rsn.capabilities & (WPA_CAPABILITY_MFPR |
2401252726Srpaulo					WPA_CAPABILITY_MFPC)) {
2402252726Srpaulo			ret = os_snprintf(pos, end - pos, "pmf=%d\n",
2403252726Srpaulo					  (rsn.capabilities &
2404252726Srpaulo					   WPA_CAPABILITY_MFPR) ? 2 : 1);
2405252726Srpaulo			if (ret < 0 || ret >= end - pos)
2406252726Srpaulo				return pos - buf;
2407252726Srpaulo			pos += ret;
2408252726Srpaulo		}
2409252726Srpaulo	}
2410252726Srpaulo
2411189251Ssam	return pos - buf;
2412189251Ssam}
2413189251Ssam
2414189251Ssam
2415189251Ssam/**
2416189251Ssam * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
2417189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2418189251Ssam * @wpa_ie: Pointer to buffer for WPA/RSN IE
2419189251Ssam * @wpa_ie_len: Pointer to the length of the wpa_ie buffer
2420189251Ssam * Returns: 0 on success, -1 on failure
2421189251Ssam */
2422189251Ssamint wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
2423189251Ssam				    size_t *wpa_ie_len)
2424189251Ssam{
2425189251Ssam	int res;
2426189251Ssam
2427189251Ssam	if (sm == NULL)
2428189251Ssam		return -1;
2429189251Ssam
2430189251Ssam	res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
2431189251Ssam	if (res < 0)
2432189251Ssam		return -1;
2433189251Ssam	*wpa_ie_len = res;
2434189251Ssam
2435189251Ssam	wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default",
2436189251Ssam		    wpa_ie, *wpa_ie_len);
2437189251Ssam
2438189251Ssam	if (sm->assoc_wpa_ie == NULL) {
2439189251Ssam		/*
2440189251Ssam		 * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets
2441189251Ssam		 * the correct version of the IE even if PMKSA caching is
2442189251Ssam		 * aborted (which would remove PMKID from IE generation).
2443189251Ssam		 */
2444189251Ssam		sm->assoc_wpa_ie = os_malloc(*wpa_ie_len);
2445189251Ssam		if (sm->assoc_wpa_ie == NULL)
2446189251Ssam			return -1;
2447189251Ssam
2448189251Ssam		os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
2449189251Ssam		sm->assoc_wpa_ie_len = *wpa_ie_len;
2450189251Ssam	}
2451189251Ssam
2452189251Ssam	return 0;
2453189251Ssam}
2454189251Ssam
2455189251Ssam
2456189251Ssam/**
2457189251Ssam * wpa_sm_set_assoc_wpa_ie - Set own WPA/RSN IE from (Re)AssocReq
2458189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2459189251Ssam * @ie: Pointer to IE data (starting from id)
2460189251Ssam * @len: IE length
2461189251Ssam * Returns: 0 on success, -1 on failure
2462189251Ssam *
2463189251Ssam * Inform WPA state machine about the WPA/RSN IE used in (Re)Association
2464189251Ssam * Request frame. The IE will be used to override the default value generated
2465189251Ssam * with wpa_sm_set_assoc_wpa_ie_default().
2466189251Ssam */
2467189251Ssamint wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
2468189251Ssam{
2469189251Ssam	if (sm == NULL)
2470189251Ssam		return -1;
2471189251Ssam
2472189251Ssam	os_free(sm->assoc_wpa_ie);
2473189251Ssam	if (ie == NULL || len == 0) {
2474252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
2475252726Srpaulo			"WPA: clearing own WPA/RSN IE");
2476189251Ssam		sm->assoc_wpa_ie = NULL;
2477189251Ssam		sm->assoc_wpa_ie_len = 0;
2478189251Ssam	} else {
2479189251Ssam		wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len);
2480189251Ssam		sm->assoc_wpa_ie = os_malloc(len);
2481189251Ssam		if (sm->assoc_wpa_ie == NULL)
2482189251Ssam			return -1;
2483189251Ssam
2484189251Ssam		os_memcpy(sm->assoc_wpa_ie, ie, len);
2485189251Ssam		sm->assoc_wpa_ie_len = len;
2486189251Ssam	}
2487189251Ssam
2488189251Ssam	return 0;
2489189251Ssam}
2490189251Ssam
2491189251Ssam
2492189251Ssam/**
2493189251Ssam * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
2494189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2495189251Ssam * @ie: Pointer to IE data (starting from id)
2496189251Ssam * @len: IE length
2497189251Ssam * Returns: 0 on success, -1 on failure
2498189251Ssam *
2499189251Ssam * Inform WPA state machine about the WPA IE used in Beacon / Probe Response
2500189251Ssam * frame.
2501189251Ssam */
2502189251Ssamint wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
2503189251Ssam{
2504189251Ssam	if (sm == NULL)
2505189251Ssam		return -1;
2506189251Ssam
2507189251Ssam	os_free(sm->ap_wpa_ie);
2508189251Ssam	if (ie == NULL || len == 0) {
2509252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
2510252726Srpaulo			"WPA: clearing AP WPA IE");
2511189251Ssam		sm->ap_wpa_ie = NULL;
2512189251Ssam		sm->ap_wpa_ie_len = 0;
2513189251Ssam	} else {
2514189251Ssam		wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len);
2515189251Ssam		sm->ap_wpa_ie = os_malloc(len);
2516189251Ssam		if (sm->ap_wpa_ie == NULL)
2517189251Ssam			return -1;
2518189251Ssam
2519189251Ssam		os_memcpy(sm->ap_wpa_ie, ie, len);
2520189251Ssam		sm->ap_wpa_ie_len = len;
2521189251Ssam	}
2522189251Ssam
2523189251Ssam	return 0;
2524189251Ssam}
2525189251Ssam
2526189251Ssam
2527189251Ssam/**
2528189251Ssam * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp
2529189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2530189251Ssam * @ie: Pointer to IE data (starting from id)
2531189251Ssam * @len: IE length
2532189251Ssam * Returns: 0 on success, -1 on failure
2533189251Ssam *
2534189251Ssam * Inform WPA state machine about the RSN IE used in Beacon / Probe Response
2535189251Ssam * frame.
2536189251Ssam */
2537189251Ssamint wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
2538189251Ssam{
2539189251Ssam	if (sm == NULL)
2540189251Ssam		return -1;
2541189251Ssam
2542189251Ssam	os_free(sm->ap_rsn_ie);
2543189251Ssam	if (ie == NULL || len == 0) {
2544252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
2545252726Srpaulo			"WPA: clearing AP RSN IE");
2546189251Ssam		sm->ap_rsn_ie = NULL;
2547189251Ssam		sm->ap_rsn_ie_len = 0;
2548189251Ssam	} else {
2549189251Ssam		wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
2550189251Ssam		sm->ap_rsn_ie = os_malloc(len);
2551189251Ssam		if (sm->ap_rsn_ie == NULL)
2552189251Ssam			return -1;
2553189251Ssam
2554189251Ssam		os_memcpy(sm->ap_rsn_ie, ie, len);
2555189251Ssam		sm->ap_rsn_ie_len = len;
2556189251Ssam	}
2557189251Ssam
2558189251Ssam	return 0;
2559189251Ssam}
2560189251Ssam
2561189251Ssam
2562189251Ssam/**
2563189251Ssam * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
2564189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init()
2565189251Ssam * @data: Pointer to data area for parsing results
2566189251Ssam * Returns: 0 on success, -1 if IE is not known, or -2 on parsing failure
2567189251Ssam *
2568189251Ssam * Parse the contents of the own WPA or RSN IE from (Re)AssocReq and write the
2569189251Ssam * parsed data into data.
2570189251Ssam */
2571189251Ssamint wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
2572189251Ssam{
2573252726Srpaulo	if (sm == NULL)
2574189251Ssam		return -1;
2575252726Srpaulo
2576252726Srpaulo	if (sm->assoc_wpa_ie == NULL) {
2577252726Srpaulo		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
2578252726Srpaulo			"WPA: No WPA/RSN IE available from association info");
2579252726Srpaulo		return -1;
2580189251Ssam	}
2581189251Ssam	if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data))
2582189251Ssam		return -2;
2583189251Ssam	return 0;
2584189251Ssam}
2585214734Srpaulo
2586214734Srpaulo
2587214734Srpauloint wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
2588214734Srpaulo{
2589214734Srpaulo#ifndef CONFIG_NO_WPA2
2590214734Srpaulo	return pmksa_cache_list(sm->pmksa, buf, len);
2591214734Srpaulo#else /* CONFIG_NO_WPA2 */
2592214734Srpaulo	return -1;
2593214734Srpaulo#endif /* CONFIG_NO_WPA2 */
2594214734Srpaulo}
2595214734Srpaulo
2596214734Srpaulo
2597214734Srpaulovoid wpa_sm_drop_sa(struct wpa_sm *sm)
2598214734Srpaulo{
2599252726Srpaulo	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
2600214734Srpaulo	sm->ptk_set = 0;
2601214734Srpaulo	sm->tptk_set = 0;
2602214734Srpaulo	os_memset(sm->pmk, 0, sizeof(sm->pmk));
2603214734Srpaulo	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
2604214734Srpaulo	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
2605214734Srpaulo}
2606214734Srpaulo
2607214734Srpaulo
2608214734Srpauloint wpa_sm_has_ptk(struct wpa_sm *sm)
2609214734Srpaulo{
2610214734Srpaulo	if (sm == NULL)
2611214734Srpaulo		return 0;
2612214734Srpaulo	return sm->ptk_set;
2613214734Srpaulo}
2614252726Srpaulo
2615252726Srpaulo
2616252726Srpaulovoid wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
2617252726Srpaulo{
2618252726Srpaulo	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
2619252726Srpaulo}
2620252726Srpaulo
2621252726Srpaulo
2622252726Srpaulovoid wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
2623252726Srpaulo{
2624252726Srpaulo#ifndef CONFIG_NO_WPA2
2625252726Srpaulo	pmksa_cache_flush(sm->pmksa, network_ctx);
2626252726Srpaulo#endif /* CONFIG_NO_WPA2 */
2627252726Srpaulo}
2628252726Srpaulo
2629252726Srpaulo
2630252726Srpaulo#ifdef CONFIG_WNM
2631252726Srpauloint wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
2632252726Srpaulo{
2633252726Srpaulo	struct wpa_gtk_data gd;
2634252726Srpaulo#ifdef CONFIG_IEEE80211W
2635252726Srpaulo	struct wpa_igtk_kde igd;
2636252726Srpaulo	u16 keyidx;
2637252726Srpaulo#endif /* CONFIG_IEEE80211W */
2638252726Srpaulo	u16 keyinfo;
2639252726Srpaulo	u8 keylen;  /* plaintext key len */
2640252726Srpaulo	u8 *key_rsc;
2641252726Srpaulo
2642252726Srpaulo	os_memset(&gd, 0, sizeof(gd));
2643252726Srpaulo#ifdef CONFIG_IEEE80211W
2644252726Srpaulo	os_memset(&igd, 0, sizeof(igd));
2645252726Srpaulo#endif /* CONFIG_IEEE80211W */
2646252726Srpaulo
2647252726Srpaulo	keylen = wpa_cipher_key_len(sm->group_cipher);
2648252726Srpaulo	gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
2649252726Srpaulo	gd.alg = wpa_cipher_to_alg(sm->group_cipher);
2650252726Srpaulo	if (gd.alg == WPA_ALG_NONE) {
2651252726Srpaulo		wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
2652252726Srpaulo		return -1;
2653252726Srpaulo	}
2654252726Srpaulo
2655252726Srpaulo	if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
2656252726Srpaulo		key_rsc = buf + 5;
2657252726Srpaulo		keyinfo = WPA_GET_LE16(buf + 2);
2658252726Srpaulo		gd.gtk_len = keylen;
2659252726Srpaulo		if (gd.gtk_len != buf[4]) {
2660252726Srpaulo			wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d",
2661252726Srpaulo				   gd.gtk_len, buf[4]);
2662252726Srpaulo			return -1;
2663252726Srpaulo		}
2664252726Srpaulo		gd.keyidx = keyinfo & 0x03; /* B0 - B1 */
2665252726Srpaulo		gd.tx = wpa_supplicant_gtk_tx_bit_workaround(
2666252726Srpaulo		         sm, !!(keyinfo & WPA_KEY_INFO_TXRX));
2667252726Srpaulo
2668252726Srpaulo		os_memcpy(gd.gtk, buf + 13, gd.gtk_len);
2669252726Srpaulo
2670252726Srpaulo		wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
2671252726Srpaulo				gd.gtk, gd.gtk_len);
2672252726Srpaulo		if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
2673252726Srpaulo			wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
2674252726Srpaulo				   "WNM mode");
2675252726Srpaulo			return -1;
2676252726Srpaulo		}
2677252726Srpaulo#ifdef CONFIG_IEEE80211W
2678252726Srpaulo	} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
2679252726Srpaulo		os_memcpy(igd.keyid, buf + 2, 2);
2680252726Srpaulo		os_memcpy(igd.pn, buf + 4, 6);
2681252726Srpaulo
2682252726Srpaulo		keyidx = WPA_GET_LE16(igd.keyid);
2683252726Srpaulo		os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN);
2684252726Srpaulo
2685252726Srpaulo		wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
2686252726Srpaulo				igd.igtk, WPA_IGTK_LEN);
2687252726Srpaulo		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
2688252726Srpaulo				   keyidx, 0, igd.pn, sizeof(igd.pn),
2689252726Srpaulo				   igd.igtk, WPA_IGTK_LEN) < 0) {
2690252726Srpaulo			wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
2691252726Srpaulo				   "WNM mode");
2692252726Srpaulo			return -1;
2693252726Srpaulo		}
2694252726Srpaulo#endif /* CONFIG_IEEE80211W */
2695252726Srpaulo	} else {
2696252726Srpaulo		wpa_printf(MSG_DEBUG, "Unknown element id");
2697252726Srpaulo		return -1;
2698252726Srpaulo	}
2699252726Srpaulo
2700252726Srpaulo	return 0;
2701252726Srpaulo}
2702252726Srpaulo#endif /* CONFIG_WNM */
2703