1214501Srpaulo/*
2214501Srpaulo * EAP-FAST server (RFC 4851)
3214501Srpaulo * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "includes.h"
10214501Srpaulo
11214501Srpaulo#include "common.h"
12214501Srpaulo#include "crypto/aes_wrap.h"
13214501Srpaulo#include "crypto/sha1.h"
14214501Srpaulo#include "crypto/tls.h"
15252726Srpaulo#include "crypto/random.h"
16214501Srpaulo#include "eap_common/eap_tlv_common.h"
17214501Srpaulo#include "eap_common/eap_fast_common.h"
18214501Srpaulo#include "eap_i.h"
19214501Srpaulo#include "eap_tls_common.h"
20214501Srpaulo
21214501Srpaulo
22214501Srpaulostatic void eap_fast_reset(struct eap_sm *sm, void *priv);
23214501Srpaulo
24214501Srpaulo
25214501Srpaulo/* Private PAC-Opaque TLV types */
26214501Srpaulo#define PAC_OPAQUE_TYPE_PAD 0
27214501Srpaulo#define PAC_OPAQUE_TYPE_KEY 1
28214501Srpaulo#define PAC_OPAQUE_TYPE_LIFETIME 2
29214501Srpaulo#define PAC_OPAQUE_TYPE_IDENTITY 3
30214501Srpaulo
31214501Srpaulostruct eap_fast_data {
32214501Srpaulo	struct eap_ssl_data ssl;
33214501Srpaulo	enum {
34214501Srpaulo		START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD,
35214501Srpaulo		CRYPTO_BINDING, REQUEST_PAC, SUCCESS, FAILURE
36214501Srpaulo	} state;
37214501Srpaulo
38214501Srpaulo	int fast_version;
39214501Srpaulo	const struct eap_method *phase2_method;
40214501Srpaulo	void *phase2_priv;
41214501Srpaulo	int force_version;
42214501Srpaulo	int peer_version;
43214501Srpaulo
44214501Srpaulo	u8 crypto_binding_nonce[32];
45214501Srpaulo	int final_result;
46214501Srpaulo
47214501Srpaulo	struct eap_fast_key_block_provisioning *key_block_p;
48214501Srpaulo
49214501Srpaulo	u8 simck[EAP_FAST_SIMCK_LEN];
50214501Srpaulo	u8 cmk[EAP_FAST_CMK_LEN];
51214501Srpaulo	int simck_idx;
52214501Srpaulo
53214501Srpaulo	u8 pac_opaque_encr[16];
54214501Srpaulo	u8 *srv_id;
55214501Srpaulo	size_t srv_id_len;
56214501Srpaulo	char *srv_id_info;
57214501Srpaulo
58214501Srpaulo	int anon_provisioning;
59214501Srpaulo	int send_new_pac; /* server triggered re-keying of Tunnel PAC */
60214501Srpaulo	struct wpabuf *pending_phase2_resp;
61214501Srpaulo	u8 *identity; /* from PAC-Opaque */
62214501Srpaulo	size_t identity_len;
63214501Srpaulo	int eap_seq;
64214501Srpaulo	int tnc_started;
65214501Srpaulo
66214501Srpaulo	int pac_key_lifetime;
67214501Srpaulo	int pac_key_refresh_time;
68214501Srpaulo};
69214501Srpaulo
70214501Srpaulo
71214501Srpaulostatic int eap_fast_process_phase2_start(struct eap_sm *sm,
72214501Srpaulo					 struct eap_fast_data *data);
73214501Srpaulo
74214501Srpaulo
75214501Srpaulostatic const char * eap_fast_state_txt(int state)
76214501Srpaulo{
77214501Srpaulo	switch (state) {
78214501Srpaulo	case START:
79214501Srpaulo		return "START";
80214501Srpaulo	case PHASE1:
81214501Srpaulo		return "PHASE1";
82214501Srpaulo	case PHASE2_START:
83214501Srpaulo		return "PHASE2_START";
84214501Srpaulo	case PHASE2_ID:
85214501Srpaulo		return "PHASE2_ID";
86214501Srpaulo	case PHASE2_METHOD:
87214501Srpaulo		return "PHASE2_METHOD";
88214501Srpaulo	case CRYPTO_BINDING:
89214501Srpaulo		return "CRYPTO_BINDING";
90214501Srpaulo	case REQUEST_PAC:
91214501Srpaulo		return "REQUEST_PAC";
92214501Srpaulo	case SUCCESS:
93214501Srpaulo		return "SUCCESS";
94214501Srpaulo	case FAILURE:
95214501Srpaulo		return "FAILURE";
96214501Srpaulo	default:
97214501Srpaulo		return "Unknown?!";
98214501Srpaulo	}
99214501Srpaulo}
100214501Srpaulo
101214501Srpaulo
102214501Srpaulostatic void eap_fast_state(struct eap_fast_data *data, int state)
103214501Srpaulo{
104214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: %s -> %s",
105214501Srpaulo		   eap_fast_state_txt(data->state),
106214501Srpaulo		   eap_fast_state_txt(state));
107214501Srpaulo	data->state = state;
108214501Srpaulo}
109214501Srpaulo
110214501Srpaulo
111214501Srpaulostatic EapType eap_fast_req_failure(struct eap_sm *sm,
112214501Srpaulo				    struct eap_fast_data *data)
113214501Srpaulo{
114214501Srpaulo	/* TODO: send Result TLV(FAILURE) */
115214501Srpaulo	eap_fast_state(data, FAILURE);
116214501Srpaulo	return EAP_TYPE_NONE;
117214501Srpaulo}
118214501Srpaulo
119214501Srpaulo
120214501Srpaulostatic int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
121214501Srpaulo				      const u8 *client_random,
122214501Srpaulo				      const u8 *server_random,
123214501Srpaulo				      u8 *master_secret)
124214501Srpaulo{
125214501Srpaulo	struct eap_fast_data *data = ctx;
126214501Srpaulo	const u8 *pac_opaque;
127214501Srpaulo	size_t pac_opaque_len;
128214501Srpaulo	u8 *buf, *pos, *end, *pac_key = NULL;
129214501Srpaulo	os_time_t lifetime = 0;
130214501Srpaulo	struct os_time now;
131214501Srpaulo	u8 *identity = NULL;
132214501Srpaulo	size_t identity_len = 0;
133214501Srpaulo
134214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
135214501Srpaulo	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)",
136214501Srpaulo		    ticket, len);
137214501Srpaulo
138214501Srpaulo	if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
139214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid "
140214501Srpaulo			   "SessionTicket");
141214501Srpaulo		return 0;
142214501Srpaulo	}
143214501Srpaulo
144214501Srpaulo	pac_opaque_len = WPA_GET_BE16(ticket + 2);
145214501Srpaulo	pac_opaque = ticket + 4;
146214501Srpaulo	if (pac_opaque_len < 8 || pac_opaque_len % 8 ||
147214501Srpaulo	    pac_opaque_len > len - 4) {
148214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid PAC-Opaque "
149214501Srpaulo			   "(len=%lu left=%lu)",
150214501Srpaulo			   (unsigned long) pac_opaque_len,
151214501Srpaulo			   (unsigned long) len);
152214501Srpaulo		return 0;
153214501Srpaulo	}
154214501Srpaulo	wpa_hexdump(MSG_DEBUG, "EAP-FAST: Received PAC-Opaque",
155214501Srpaulo		    pac_opaque, pac_opaque_len);
156214501Srpaulo
157214501Srpaulo	buf = os_malloc(pac_opaque_len - 8);
158214501Srpaulo	if (buf == NULL) {
159214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
160214501Srpaulo			   "for decrypting PAC-Opaque");
161214501Srpaulo		return 0;
162214501Srpaulo	}
163214501Srpaulo
164214501Srpaulo	if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8,
165214501Srpaulo		       pac_opaque, buf) < 0) {
166214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt "
167214501Srpaulo			   "PAC-Opaque");
168214501Srpaulo		os_free(buf);
169214501Srpaulo		/*
170214501Srpaulo		 * This may have been caused by server changing the PAC-Opaque
171214501Srpaulo		 * encryption key, so just ignore this PAC-Opaque instead of
172214501Srpaulo		 * failing the authentication completely. Provisioning can now
173214501Srpaulo		 * be used to provision a new PAC.
174214501Srpaulo		 */
175214501Srpaulo		return 0;
176214501Srpaulo	}
177214501Srpaulo
178214501Srpaulo	end = buf + pac_opaque_len - 8;
179214501Srpaulo	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted PAC-Opaque",
180214501Srpaulo			buf, end - buf);
181214501Srpaulo
182214501Srpaulo	pos = buf;
183214501Srpaulo	while (pos + 1 < end) {
184214501Srpaulo		if (pos + 2 + pos[1] > end)
185214501Srpaulo			break;
186214501Srpaulo
187214501Srpaulo		switch (*pos) {
188214501Srpaulo		case PAC_OPAQUE_TYPE_PAD:
189214501Srpaulo			pos = end;
190214501Srpaulo			break;
191214501Srpaulo		case PAC_OPAQUE_TYPE_KEY:
192214501Srpaulo			if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
193214501Srpaulo				wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
194214501Srpaulo					   "PAC-Key length %d", pos[1]);
195214501Srpaulo				os_free(buf);
196214501Srpaulo				return -1;
197214501Srpaulo			}
198214501Srpaulo			pac_key = pos + 2;
199214501Srpaulo			wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from "
200214501Srpaulo					"decrypted PAC-Opaque",
201214501Srpaulo					pac_key, EAP_FAST_PAC_KEY_LEN);
202214501Srpaulo			break;
203214501Srpaulo		case PAC_OPAQUE_TYPE_LIFETIME:
204214501Srpaulo			if (pos[1] != 4) {
205214501Srpaulo				wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
206214501Srpaulo					   "PAC-Key lifetime length %d",
207214501Srpaulo					   pos[1]);
208214501Srpaulo				os_free(buf);
209214501Srpaulo				return -1;
210214501Srpaulo			}
211214501Srpaulo			lifetime = WPA_GET_BE32(pos + 2);
212214501Srpaulo			break;
213214501Srpaulo		case PAC_OPAQUE_TYPE_IDENTITY:
214214501Srpaulo			identity = pos + 2;
215214501Srpaulo			identity_len = pos[1];
216214501Srpaulo			break;
217214501Srpaulo		}
218214501Srpaulo
219214501Srpaulo		pos += 2 + pos[1];
220214501Srpaulo	}
221214501Srpaulo
222214501Srpaulo	if (pac_key == NULL) {
223214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
224214501Srpaulo			   "PAC-Opaque");
225214501Srpaulo		os_free(buf);
226214501Srpaulo		return -1;
227214501Srpaulo	}
228214501Srpaulo
229214501Srpaulo	if (identity) {
230214501Srpaulo		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from "
231214501Srpaulo				  "PAC-Opaque", identity, identity_len);
232214501Srpaulo		os_free(data->identity);
233214501Srpaulo		data->identity = os_malloc(identity_len);
234214501Srpaulo		if (data->identity) {
235214501Srpaulo			os_memcpy(data->identity, identity, identity_len);
236214501Srpaulo			data->identity_len = identity_len;
237214501Srpaulo		}
238214501Srpaulo	}
239214501Srpaulo
240214501Srpaulo	if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
241214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore "
242214501Srpaulo			   "(lifetime=%ld now=%ld)", lifetime, now.sec);
243214501Srpaulo		data->send_new_pac = 2;
244214501Srpaulo		/*
245214501Srpaulo		 * Allow PAC to be used to allow a PAC update with some level
246214501Srpaulo		 * of server authentication (i.e., do not fall back to full TLS
247214501Srpaulo		 * handshake since we cannot be sure that the peer would be
248214501Srpaulo		 * able to validate server certificate now). However, reject
249214501Srpaulo		 * the authentication since the PAC was not valid anymore. Peer
250214501Srpaulo		 * can connect again with the newly provisioned PAC after this.
251214501Srpaulo		 */
252214501Srpaulo	} else if (lifetime - now.sec < data->pac_key_refresh_time) {
253214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key soft timeout; send "
254214501Srpaulo			   "an update if authentication succeeds");
255214501Srpaulo		data->send_new_pac = 1;
256214501Srpaulo	}
257214501Srpaulo
258214501Srpaulo	eap_fast_derive_master_secret(pac_key, server_random, client_random,
259214501Srpaulo				      master_secret);
260214501Srpaulo
261214501Srpaulo	os_free(buf);
262214501Srpaulo
263214501Srpaulo	return 1;
264214501Srpaulo}
265214501Srpaulo
266214501Srpaulo
267214501Srpaulostatic void eap_fast_derive_key_auth(struct eap_sm *sm,
268214501Srpaulo				     struct eap_fast_data *data)
269214501Srpaulo{
270214501Srpaulo	u8 *sks;
271214501Srpaulo
272214501Srpaulo	/* RFC 4851, Section 5.1:
273214501Srpaulo	 * Extra key material after TLS key_block: session_key_seed[40]
274214501Srpaulo	 */
275214501Srpaulo
276214501Srpaulo	sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
277214501Srpaulo				  EAP_FAST_SKS_LEN);
278214501Srpaulo	if (sks == NULL) {
279214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
280214501Srpaulo			   "session_key_seed");
281214501Srpaulo		return;
282214501Srpaulo	}
283214501Srpaulo
284214501Srpaulo	/*
285214501Srpaulo	 * RFC 4851, Section 5.2:
286214501Srpaulo	 * S-IMCK[0] = session_key_seed
287214501Srpaulo	 */
288214501Srpaulo	wpa_hexdump_key(MSG_DEBUG,
289214501Srpaulo			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
290214501Srpaulo			sks, EAP_FAST_SKS_LEN);
291214501Srpaulo	data->simck_idx = 0;
292214501Srpaulo	os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
293214501Srpaulo	os_free(sks);
294214501Srpaulo}
295214501Srpaulo
296214501Srpaulo
297214501Srpaulostatic void eap_fast_derive_key_provisioning(struct eap_sm *sm,
298214501Srpaulo					     struct eap_fast_data *data)
299214501Srpaulo{
300214501Srpaulo	os_free(data->key_block_p);
301214501Srpaulo	data->key_block_p = (struct eap_fast_key_block_provisioning *)
302214501Srpaulo		eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
303214501Srpaulo				    "key expansion",
304214501Srpaulo				    sizeof(*data->key_block_p));
305214501Srpaulo	if (data->key_block_p == NULL) {
306214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
307214501Srpaulo		return;
308214501Srpaulo	}
309214501Srpaulo	/*
310214501Srpaulo	 * RFC 4851, Section 5.2:
311214501Srpaulo	 * S-IMCK[0] = session_key_seed
312214501Srpaulo	 */
313214501Srpaulo	wpa_hexdump_key(MSG_DEBUG,
314214501Srpaulo			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
315214501Srpaulo			data->key_block_p->session_key_seed,
316214501Srpaulo			sizeof(data->key_block_p->session_key_seed));
317214501Srpaulo	data->simck_idx = 0;
318214501Srpaulo	os_memcpy(data->simck, data->key_block_p->session_key_seed,
319214501Srpaulo		  EAP_FAST_SIMCK_LEN);
320214501Srpaulo	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
321214501Srpaulo			data->key_block_p->server_challenge,
322214501Srpaulo			sizeof(data->key_block_p->server_challenge));
323214501Srpaulo	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
324214501Srpaulo			data->key_block_p->client_challenge,
325214501Srpaulo			sizeof(data->key_block_p->client_challenge));
326214501Srpaulo}
327214501Srpaulo
328214501Srpaulo
329214501Srpaulostatic int eap_fast_get_phase2_key(struct eap_sm *sm,
330214501Srpaulo				   struct eap_fast_data *data,
331214501Srpaulo				   u8 *isk, size_t isk_len)
332214501Srpaulo{
333214501Srpaulo	u8 *key;
334214501Srpaulo	size_t key_len;
335214501Srpaulo
336214501Srpaulo	os_memset(isk, 0, isk_len);
337214501Srpaulo
338214501Srpaulo	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
339214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
340214501Srpaulo			   "available");
341214501Srpaulo		return -1;
342214501Srpaulo	}
343214501Srpaulo
344214501Srpaulo	if (data->phase2_method->getKey == NULL)
345214501Srpaulo		return 0;
346214501Srpaulo
347214501Srpaulo	if ((key = data->phase2_method->getKey(sm, data->phase2_priv,
348214501Srpaulo					       &key_len)) == NULL) {
349214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material "
350214501Srpaulo			   "from Phase 2");
351214501Srpaulo		return -1;
352214501Srpaulo	}
353214501Srpaulo
354214501Srpaulo	if (key_len > isk_len)
355214501Srpaulo		key_len = isk_len;
356214501Srpaulo	if (key_len == 32 &&
357214501Srpaulo	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
358214501Srpaulo	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
359214501Srpaulo		/*
360214501Srpaulo		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
361214501Srpaulo		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
362214501Srpaulo		 * ISK for EAP-FAST cryptobinding.
363214501Srpaulo		 */
364214501Srpaulo		os_memcpy(isk, key + 16, 16);
365214501Srpaulo		os_memcpy(isk + 16, key, 16);
366214501Srpaulo	} else
367214501Srpaulo		os_memcpy(isk, key, key_len);
368214501Srpaulo	os_free(key);
369214501Srpaulo
370214501Srpaulo	return 0;
371214501Srpaulo}
372214501Srpaulo
373214501Srpaulo
374214501Srpaulostatic int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data)
375214501Srpaulo{
376214501Srpaulo	u8 isk[32], imck[60];
377214501Srpaulo
378214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: Deriving ICMK[%d] (S-IMCK and CMK)",
379214501Srpaulo		   data->simck_idx + 1);
380214501Srpaulo
381214501Srpaulo	/*
382214501Srpaulo	 * RFC 4851, Section 5.2:
383214501Srpaulo	 * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
384214501Srpaulo	 *                 MSK[j], 60)
385214501Srpaulo	 * S-IMCK[j] = first 40 octets of IMCK[j]
386214501Srpaulo	 * CMK[j] = last 20 octets of IMCK[j]
387214501Srpaulo	 */
388214501Srpaulo
389214501Srpaulo	if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0)
390214501Srpaulo		return -1;
391214501Srpaulo	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
392214501Srpaulo	sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
393214501Srpaulo		   "Inner Methods Compound Keys",
394214501Srpaulo		   isk, sizeof(isk), imck, sizeof(imck));
395214501Srpaulo	data->simck_idx++;
396214501Srpaulo	os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
397214501Srpaulo	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
398214501Srpaulo			data->simck, EAP_FAST_SIMCK_LEN);
399214501Srpaulo	os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
400214501Srpaulo	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
401214501Srpaulo			data->cmk, EAP_FAST_CMK_LEN);
402214501Srpaulo
403214501Srpaulo	return 0;
404214501Srpaulo}
405214501Srpaulo
406214501Srpaulo
407214501Srpaulostatic void * eap_fast_init(struct eap_sm *sm)
408214501Srpaulo{
409214501Srpaulo	struct eap_fast_data *data;
410214501Srpaulo	u8 ciphers[5] = {
411214501Srpaulo		TLS_CIPHER_ANON_DH_AES128_SHA,
412214501Srpaulo		TLS_CIPHER_AES128_SHA,
413214501Srpaulo		TLS_CIPHER_RSA_DHE_AES128_SHA,
414214501Srpaulo		TLS_CIPHER_RC4_SHA,
415214501Srpaulo		TLS_CIPHER_NONE
416214501Srpaulo	};
417214501Srpaulo
418214501Srpaulo	data = os_zalloc(sizeof(*data));
419214501Srpaulo	if (data == NULL)
420214501Srpaulo		return NULL;
421214501Srpaulo	data->fast_version = EAP_FAST_VERSION;
422214501Srpaulo	data->force_version = -1;
423214501Srpaulo	if (sm->user && sm->user->force_version >= 0) {
424214501Srpaulo		data->force_version = sm->user->force_version;
425214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: forcing version %d",
426214501Srpaulo			   data->force_version);
427214501Srpaulo		data->fast_version = data->force_version;
428214501Srpaulo	}
429214501Srpaulo	data->state = START;
430214501Srpaulo
431214501Srpaulo	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
432214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
433214501Srpaulo		eap_fast_reset(sm, data);
434214501Srpaulo		return NULL;
435214501Srpaulo	}
436214501Srpaulo
437214501Srpaulo	if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
438214501Srpaulo					   ciphers) < 0) {
439214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
440214501Srpaulo			   "suites");
441214501Srpaulo		eap_fast_reset(sm, data);
442214501Srpaulo		return NULL;
443214501Srpaulo	}
444214501Srpaulo
445214501Srpaulo	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
446214501Srpaulo						 eap_fast_session_ticket_cb,
447214501Srpaulo						 data) < 0) {
448214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
449214501Srpaulo			   "callback");
450214501Srpaulo		eap_fast_reset(sm, data);
451214501Srpaulo		return NULL;
452214501Srpaulo	}
453214501Srpaulo
454214501Srpaulo	if (sm->pac_opaque_encr_key == NULL) {
455214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
456214501Srpaulo			   "configured");
457214501Srpaulo		eap_fast_reset(sm, data);
458214501Srpaulo		return NULL;
459214501Srpaulo	}
460214501Srpaulo	os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
461214501Srpaulo		  sizeof(data->pac_opaque_encr));
462214501Srpaulo
463214501Srpaulo	if (sm->eap_fast_a_id == NULL) {
464214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
465214501Srpaulo		eap_fast_reset(sm, data);
466214501Srpaulo		return NULL;
467214501Srpaulo	}
468214501Srpaulo	data->srv_id = os_malloc(sm->eap_fast_a_id_len);
469214501Srpaulo	if (data->srv_id == NULL) {
470214501Srpaulo		eap_fast_reset(sm, data);
471214501Srpaulo		return NULL;
472214501Srpaulo	}
473214501Srpaulo	os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len);
474214501Srpaulo	data->srv_id_len = sm->eap_fast_a_id_len;
475214501Srpaulo
476214501Srpaulo	if (sm->eap_fast_a_id_info == NULL) {
477214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured");
478214501Srpaulo		eap_fast_reset(sm, data);
479214501Srpaulo		return NULL;
480214501Srpaulo	}
481214501Srpaulo	data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
482214501Srpaulo	if (data->srv_id_info == NULL) {
483214501Srpaulo		eap_fast_reset(sm, data);
484214501Srpaulo		return NULL;
485214501Srpaulo	}
486214501Srpaulo
487214501Srpaulo	/* PAC-Key lifetime in seconds (hard limit) */
488214501Srpaulo	data->pac_key_lifetime = sm->pac_key_lifetime;
489214501Srpaulo
490214501Srpaulo	/*
491214501Srpaulo	 * PAC-Key refresh time in seconds (soft limit on remaining hard
492214501Srpaulo	 * limit). The server will generate a new PAC-Key when this number of
493214501Srpaulo	 * seconds (or fewer) of the lifetime remains.
494214501Srpaulo	 */
495214501Srpaulo	data->pac_key_refresh_time = sm->pac_key_refresh_time;
496214501Srpaulo
497214501Srpaulo	return data;
498214501Srpaulo}
499214501Srpaulo
500214501Srpaulo
501214501Srpaulostatic void eap_fast_reset(struct eap_sm *sm, void *priv)
502214501Srpaulo{
503214501Srpaulo	struct eap_fast_data *data = priv;
504214501Srpaulo	if (data == NULL)
505214501Srpaulo		return;
506214501Srpaulo	if (data->phase2_priv && data->phase2_method)
507214501Srpaulo		data->phase2_method->reset(sm, data->phase2_priv);
508214501Srpaulo	eap_server_tls_ssl_deinit(sm, &data->ssl);
509214501Srpaulo	os_free(data->srv_id);
510214501Srpaulo	os_free(data->srv_id_info);
511214501Srpaulo	os_free(data->key_block_p);
512214501Srpaulo	wpabuf_free(data->pending_phase2_resp);
513214501Srpaulo	os_free(data->identity);
514214501Srpaulo	os_free(data);
515214501Srpaulo}
516214501Srpaulo
517214501Srpaulo
518214501Srpaulostatic struct wpabuf * eap_fast_build_start(struct eap_sm *sm,
519214501Srpaulo					    struct eap_fast_data *data, u8 id)
520214501Srpaulo{
521214501Srpaulo	struct wpabuf *req;
522214501Srpaulo
523214501Srpaulo	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST,
524214501Srpaulo			    1 + sizeof(struct pac_tlv_hdr) + data->srv_id_len,
525214501Srpaulo			    EAP_CODE_REQUEST, id);
526214501Srpaulo	if (req == NULL) {
527214501Srpaulo		wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for"
528214501Srpaulo			   " request");
529214501Srpaulo		eap_fast_state(data, FAILURE);
530214501Srpaulo		return NULL;
531214501Srpaulo	}
532214501Srpaulo
533214501Srpaulo	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version);
534214501Srpaulo
535214501Srpaulo	/* RFC 4851, 4.1.1. Authority ID Data */
536214501Srpaulo	eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
537214501Srpaulo
538214501Srpaulo	eap_fast_state(data, PHASE1);
539214501Srpaulo
540214501Srpaulo	return req;
541214501Srpaulo}
542214501Srpaulo
543214501Srpaulo
544214501Srpaulostatic int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data)
545214501Srpaulo{
546214501Srpaulo	char cipher[64];
547214501Srpaulo
548214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
549214501Srpaulo
550214501Srpaulo	if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
551214501Srpaulo	    < 0) {
552214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
553214501Srpaulo			   "information");
554214501Srpaulo		eap_fast_state(data, FAILURE);
555214501Srpaulo		return -1;
556214501Srpaulo	}
557214501Srpaulo	data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
558214501Srpaulo
559214501Srpaulo	if (data->anon_provisioning) {
560214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning");
561214501Srpaulo		eap_fast_derive_key_provisioning(sm, data);
562214501Srpaulo	} else
563214501Srpaulo		eap_fast_derive_key_auth(sm, data);
564214501Srpaulo
565214501Srpaulo	eap_fast_state(data, PHASE2_START);
566214501Srpaulo
567214501Srpaulo	return 0;
568214501Srpaulo}
569214501Srpaulo
570214501Srpaulo
571214501Srpaulostatic struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm,
572214501Srpaulo						 struct eap_fast_data *data,
573214501Srpaulo						 u8 id)
574214501Srpaulo{
575214501Srpaulo	struct wpabuf *req;
576214501Srpaulo
577214501Srpaulo	if (data->phase2_priv == NULL) {
578214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
579214501Srpaulo			   "initialized");
580214501Srpaulo		return NULL;
581214501Srpaulo	}
582214501Srpaulo	req = data->phase2_method->buildReq(sm, data->phase2_priv, id);
583214501Srpaulo	if (req == NULL)
584214501Srpaulo		return NULL;
585214501Srpaulo
586214501Srpaulo	wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request", req);
587214501Srpaulo	return eap_fast_tlv_eap_payload(req);
588214501Srpaulo}
589214501Srpaulo
590214501Srpaulo
591214501Srpaulostatic struct wpabuf * eap_fast_build_crypto_binding(
592214501Srpaulo	struct eap_sm *sm, struct eap_fast_data *data)
593214501Srpaulo{
594214501Srpaulo	struct wpabuf *buf;
595214501Srpaulo	struct eap_tlv_result_tlv *result;
596214501Srpaulo	struct eap_tlv_crypto_binding_tlv *binding;
597214501Srpaulo
598214501Srpaulo	buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding));
599214501Srpaulo	if (buf == NULL)
600214501Srpaulo		return NULL;
601214501Srpaulo
602214501Srpaulo	if (data->send_new_pac || data->anon_provisioning ||
603214501Srpaulo	    data->phase2_method)
604214501Srpaulo		data->final_result = 0;
605214501Srpaulo	else
606214501Srpaulo		data->final_result = 1;
607214501Srpaulo
608214501Srpaulo	if (!data->final_result || data->eap_seq > 1) {
609214501Srpaulo		/* Intermediate-Result */
610214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV "
611214501Srpaulo			   "(status=SUCCESS)");
612214501Srpaulo		result = wpabuf_put(buf, sizeof(*result));
613214501Srpaulo		result->tlv_type = host_to_be16(
614214501Srpaulo			EAP_TLV_TYPE_MANDATORY |
615214501Srpaulo			EAP_TLV_INTERMEDIATE_RESULT_TLV);
616214501Srpaulo		result->length = host_to_be16(2);
617214501Srpaulo		result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
618214501Srpaulo	}
619214501Srpaulo
620214501Srpaulo	if (data->final_result) {
621214501Srpaulo		/* Result TLV */
622214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV "
623214501Srpaulo			   "(status=SUCCESS)");
624214501Srpaulo		result = wpabuf_put(buf, sizeof(*result));
625214501Srpaulo		result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
626214501Srpaulo						EAP_TLV_RESULT_TLV);
627214501Srpaulo		result->length = host_to_be16(2);
628214501Srpaulo		result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
629214501Srpaulo	}
630214501Srpaulo
631214501Srpaulo	/* Crypto-Binding TLV */
632214501Srpaulo	binding = wpabuf_put(buf, sizeof(*binding));
633214501Srpaulo	binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
634214501Srpaulo					 EAP_TLV_CRYPTO_BINDING_TLV);
635214501Srpaulo	binding->length = host_to_be16(sizeof(*binding) -
636214501Srpaulo				       sizeof(struct eap_tlv_hdr));
637214501Srpaulo	binding->version = EAP_FAST_VERSION;
638214501Srpaulo	binding->received_version = data->peer_version;
639214501Srpaulo	binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
640252726Srpaulo	if (random_get_bytes(binding->nonce, sizeof(binding->nonce)) < 0) {
641214501Srpaulo		wpabuf_free(buf);
642214501Srpaulo		return NULL;
643214501Srpaulo	}
644214501Srpaulo
645214501Srpaulo	/*
646214501Srpaulo	 * RFC 4851, Section 4.2.8:
647214501Srpaulo	 * The nonce in a request MUST have its least significant bit set to 0.
648214501Srpaulo	 */
649214501Srpaulo	binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01;
650214501Srpaulo
651214501Srpaulo	os_memcpy(data->crypto_binding_nonce, binding->nonce,
652214501Srpaulo		  sizeof(binding->nonce));
653214501Srpaulo
654214501Srpaulo	/*
655214501Srpaulo	 * RFC 4851, Section 5.3:
656214501Srpaulo	 * CMK = CMK[j]
657214501Srpaulo	 * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV )
658214501Srpaulo	 */
659214501Srpaulo
660214501Srpaulo	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN,
661214501Srpaulo		  (u8 *) binding, sizeof(*binding),
662214501Srpaulo		  binding->compound_mac);
663214501Srpaulo
664214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d "
665214501Srpaulo		   "Received Version %d SubType %d",
666214501Srpaulo		   binding->version, binding->received_version,
667214501Srpaulo		   binding->subtype);
668214501Srpaulo	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
669214501Srpaulo		    binding->nonce, sizeof(binding->nonce));
670214501Srpaulo	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
671214501Srpaulo		    binding->compound_mac, sizeof(binding->compound_mac));
672214501Srpaulo
673214501Srpaulo	return buf;
674214501Srpaulo}
675214501Srpaulo
676214501Srpaulo
677214501Srpaulostatic struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
678214501Srpaulo					  struct eap_fast_data *data)
679214501Srpaulo{
680214501Srpaulo	u8 pac_key[EAP_FAST_PAC_KEY_LEN];
681214501Srpaulo	u8 *pac_buf, *pac_opaque;
682214501Srpaulo	struct wpabuf *buf;
683214501Srpaulo	u8 *pos;
684214501Srpaulo	size_t buf_len, srv_id_info_len, pac_len;
685214501Srpaulo	struct eap_tlv_hdr *pac_tlv;
686214501Srpaulo	struct pac_tlv_hdr *pac_info;
687214501Srpaulo	struct eap_tlv_result_tlv *result;
688214501Srpaulo	struct os_time now;
689214501Srpaulo
690252726Srpaulo	if (random_get_bytes(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
691214501Srpaulo	    os_get_time(&now) < 0)
692214501Srpaulo		return NULL;
693214501Srpaulo	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
694214501Srpaulo			pac_key, EAP_FAST_PAC_KEY_LEN);
695214501Srpaulo
696214501Srpaulo	pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) +
697214501Srpaulo		(2 + sm->identity_len) + 8;
698214501Srpaulo	pac_buf = os_malloc(pac_len);
699214501Srpaulo	if (pac_buf == NULL)
700214501Srpaulo		return NULL;
701214501Srpaulo
702214501Srpaulo	srv_id_info_len = os_strlen(data->srv_id_info);
703214501Srpaulo
704214501Srpaulo	pos = pac_buf;
705214501Srpaulo	*pos++ = PAC_OPAQUE_TYPE_KEY;
706214501Srpaulo	*pos++ = EAP_FAST_PAC_KEY_LEN;
707214501Srpaulo	os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN);
708214501Srpaulo	pos += EAP_FAST_PAC_KEY_LEN;
709214501Srpaulo
710214501Srpaulo	*pos++ = PAC_OPAQUE_TYPE_LIFETIME;
711214501Srpaulo	*pos++ = 4;
712214501Srpaulo	WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime);
713214501Srpaulo	pos += 4;
714214501Srpaulo
715214501Srpaulo	if (sm->identity) {
716214501Srpaulo		*pos++ = PAC_OPAQUE_TYPE_IDENTITY;
717214501Srpaulo		*pos++ = sm->identity_len;
718214501Srpaulo		os_memcpy(pos, sm->identity, sm->identity_len);
719214501Srpaulo		pos += sm->identity_len;
720214501Srpaulo	}
721214501Srpaulo
722214501Srpaulo	pac_len = pos - pac_buf;
723214501Srpaulo	while (pac_len % 8) {
724214501Srpaulo		*pos++ = PAC_OPAQUE_TYPE_PAD;
725214501Srpaulo		pac_len++;
726214501Srpaulo	}
727214501Srpaulo
728214501Srpaulo	pac_opaque = os_malloc(pac_len + 8);
729214501Srpaulo	if (pac_opaque == NULL) {
730214501Srpaulo		os_free(pac_buf);
731214501Srpaulo		return NULL;
732214501Srpaulo	}
733214501Srpaulo	if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
734214501Srpaulo		     pac_opaque) < 0) {
735214501Srpaulo		os_free(pac_buf);
736214501Srpaulo		os_free(pac_opaque);
737214501Srpaulo		return NULL;
738214501Srpaulo	}
739214501Srpaulo	os_free(pac_buf);
740214501Srpaulo
741214501Srpaulo	pac_len += 8;
742214501Srpaulo	wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
743214501Srpaulo		    pac_opaque, pac_len);
744214501Srpaulo
745214501Srpaulo	buf_len = sizeof(*pac_tlv) +
746214501Srpaulo		sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN +
747214501Srpaulo		sizeof(struct pac_tlv_hdr) + pac_len +
748214501Srpaulo		data->srv_id_len + srv_id_info_len + 100 + sizeof(*result);
749214501Srpaulo	buf = wpabuf_alloc(buf_len);
750214501Srpaulo	if (buf == NULL) {
751214501Srpaulo		os_free(pac_opaque);
752214501Srpaulo		return NULL;
753214501Srpaulo	}
754214501Srpaulo
755214501Srpaulo	/* Result TLV */
756214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
757214501Srpaulo	result = wpabuf_put(buf, sizeof(*result));
758214501Srpaulo	WPA_PUT_BE16((u8 *) &result->tlv_type,
759214501Srpaulo		     EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV);
760214501Srpaulo	WPA_PUT_BE16((u8 *) &result->length, 2);
761214501Srpaulo	WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS);
762214501Srpaulo
763214501Srpaulo	/* PAC TLV */
764214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV");
765214501Srpaulo	pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv));
766214501Srpaulo	pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
767214501Srpaulo					 EAP_TLV_PAC_TLV);
768214501Srpaulo
769214501Srpaulo	/* PAC-Key */
770214501Srpaulo	eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN);
771214501Srpaulo
772214501Srpaulo	/* PAC-Opaque */
773214501Srpaulo	eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len);
774214501Srpaulo	os_free(pac_opaque);
775214501Srpaulo
776214501Srpaulo	/* PAC-Info */
777214501Srpaulo	pac_info = wpabuf_put(buf, sizeof(*pac_info));
778214501Srpaulo	pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
779214501Srpaulo
780214501Srpaulo	/* PAC-Lifetime (inside PAC-Info) */
781214501Srpaulo	eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4);
782214501Srpaulo	wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime);
783214501Srpaulo
784214501Srpaulo	/* A-ID (inside PAC-Info) */
785214501Srpaulo	eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
786214501Srpaulo
787214501Srpaulo	/* Note: headers may be misaligned after A-ID */
788214501Srpaulo
789214501Srpaulo	if (sm->identity) {
790214501Srpaulo		eap_fast_put_tlv(buf, PAC_TYPE_I_ID, sm->identity,
791214501Srpaulo				 sm->identity_len);
792214501Srpaulo	}
793214501Srpaulo
794214501Srpaulo	/* A-ID-Info (inside PAC-Info) */
795214501Srpaulo	eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info,
796214501Srpaulo			 srv_id_info_len);
797214501Srpaulo
798214501Srpaulo	/* PAC-Type (inside PAC-Info) */
799214501Srpaulo	eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2);
800214501Srpaulo	wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC);
801214501Srpaulo
802214501Srpaulo	/* Update PAC-Info and PAC TLV Length fields */
803214501Srpaulo	pos = wpabuf_put(buf, 0);
804214501Srpaulo	pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1));
805214501Srpaulo	pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1));
806214501Srpaulo
807214501Srpaulo	return buf;
808214501Srpaulo}
809214501Srpaulo
810214501Srpaulo
811214501Srpaulostatic int eap_fast_encrypt_phase2(struct eap_sm *sm,
812214501Srpaulo				   struct eap_fast_data *data,
813214501Srpaulo				   struct wpabuf *plain, int piggyback)
814214501Srpaulo{
815214501Srpaulo	struct wpabuf *encr;
816214501Srpaulo
817214501Srpaulo	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
818214501Srpaulo			    plain);
819214501Srpaulo	encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
820214501Srpaulo	wpabuf_free(plain);
821214501Srpaulo
822214501Srpaulo	if (data->ssl.tls_out && piggyback) {
823214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
824214501Srpaulo			   "(len=%d) with last Phase 1 Message (len=%d "
825214501Srpaulo			   "used=%d)",
826214501Srpaulo			   (int) wpabuf_len(encr),
827214501Srpaulo			   (int) wpabuf_len(data->ssl.tls_out),
828214501Srpaulo			   (int) data->ssl.tls_out_pos);
829214501Srpaulo		if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
830214501Srpaulo			wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize "
831214501Srpaulo				   "output buffer");
832214501Srpaulo			wpabuf_free(encr);
833214501Srpaulo			return -1;
834214501Srpaulo		}
835214501Srpaulo		wpabuf_put_buf(data->ssl.tls_out, encr);
836214501Srpaulo		wpabuf_free(encr);
837214501Srpaulo	} else {
838214501Srpaulo		wpabuf_free(data->ssl.tls_out);
839214501Srpaulo		data->ssl.tls_out_pos = 0;
840214501Srpaulo		data->ssl.tls_out = encr;
841214501Srpaulo	}
842214501Srpaulo
843214501Srpaulo	return 0;
844214501Srpaulo}
845214501Srpaulo
846214501Srpaulo
847214501Srpaulostatic struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
848214501Srpaulo{
849214501Srpaulo	struct eap_fast_data *data = priv;
850214501Srpaulo	struct wpabuf *req = NULL;
851214501Srpaulo	int piggyback = 0;
852214501Srpaulo
853214501Srpaulo	if (data->ssl.state == FRAG_ACK) {
854214501Srpaulo		return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
855214501Srpaulo						data->fast_version);
856214501Srpaulo	}
857214501Srpaulo
858214501Srpaulo	if (data->ssl.state == WAIT_FRAG_ACK) {
859214501Srpaulo		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
860214501Srpaulo						data->fast_version, id);
861214501Srpaulo	}
862214501Srpaulo
863214501Srpaulo	switch (data->state) {
864214501Srpaulo	case START:
865214501Srpaulo		return eap_fast_build_start(sm, data, id);
866214501Srpaulo	case PHASE1:
867214501Srpaulo		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
868214501Srpaulo			if (eap_fast_phase1_done(sm, data) < 0)
869214501Srpaulo				return NULL;
870214501Srpaulo			if (data->state == PHASE2_START) {
871214501Srpaulo				/*
872214501Srpaulo				 * Try to generate Phase 2 data to piggyback
873214501Srpaulo				 * with the end of Phase 1 to avoid extra
874214501Srpaulo				 * roundtrip.
875214501Srpaulo				 */
876214501Srpaulo				wpa_printf(MSG_DEBUG, "EAP-FAST: Try to start "
877214501Srpaulo					   "Phase 2");
878214501Srpaulo				if (eap_fast_process_phase2_start(sm, data))
879214501Srpaulo					break;
880214501Srpaulo				req = eap_fast_build_phase2_req(sm, data, id);
881214501Srpaulo				piggyback = 1;
882214501Srpaulo			}
883214501Srpaulo		}
884214501Srpaulo		break;
885214501Srpaulo	case PHASE2_ID:
886214501Srpaulo	case PHASE2_METHOD:
887214501Srpaulo		req = eap_fast_build_phase2_req(sm, data, id);
888214501Srpaulo		break;
889214501Srpaulo	case CRYPTO_BINDING:
890214501Srpaulo		req = eap_fast_build_crypto_binding(sm, data);
891214501Srpaulo		if (data->phase2_method) {
892214501Srpaulo			/*
893214501Srpaulo			 * Include the start of the next EAP method in the
894214501Srpaulo			 * sequence in the same message with Crypto-Binding to
895214501Srpaulo			 * save a round-trip.
896214501Srpaulo			 */
897214501Srpaulo			struct wpabuf *eap;
898214501Srpaulo			eap = eap_fast_build_phase2_req(sm, data, id);
899214501Srpaulo			req = wpabuf_concat(req, eap);
900214501Srpaulo			eap_fast_state(data, PHASE2_METHOD);
901214501Srpaulo		}
902214501Srpaulo		break;
903214501Srpaulo	case REQUEST_PAC:
904214501Srpaulo		req = eap_fast_build_pac(sm, data);
905214501Srpaulo		break;
906214501Srpaulo	default:
907214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
908214501Srpaulo			   __func__, data->state);
909214501Srpaulo		return NULL;
910214501Srpaulo	}
911214501Srpaulo
912214501Srpaulo	if (req &&
913214501Srpaulo	    eap_fast_encrypt_phase2(sm, data, req, piggyback) < 0)
914214501Srpaulo		return NULL;
915214501Srpaulo
916214501Srpaulo	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
917214501Srpaulo					data->fast_version, id);
918214501Srpaulo}
919214501Srpaulo
920214501Srpaulo
921214501Srpaulostatic Boolean eap_fast_check(struct eap_sm *sm, void *priv,
922214501Srpaulo			      struct wpabuf *respData)
923214501Srpaulo{
924214501Srpaulo	const u8 *pos;
925214501Srpaulo	size_t len;
926214501Srpaulo
927214501Srpaulo	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len);
928214501Srpaulo	if (pos == NULL || len < 1) {
929214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
930214501Srpaulo		return TRUE;
931214501Srpaulo	}
932214501Srpaulo
933214501Srpaulo	return FALSE;
934214501Srpaulo}
935214501Srpaulo
936214501Srpaulo
937214501Srpaulostatic int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
938214501Srpaulo				EapType eap_type)
939214501Srpaulo{
940214501Srpaulo	if (data->phase2_priv && data->phase2_method) {
941214501Srpaulo		data->phase2_method->reset(sm, data->phase2_priv);
942214501Srpaulo		data->phase2_method = NULL;
943214501Srpaulo		data->phase2_priv = NULL;
944214501Srpaulo	}
945214501Srpaulo	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
946214501Srpaulo							eap_type);
947214501Srpaulo	if (!data->phase2_method)
948214501Srpaulo		return -1;
949214501Srpaulo
950214501Srpaulo	if (data->key_block_p) {
951214501Srpaulo		sm->auth_challenge = data->key_block_p->server_challenge;
952214501Srpaulo		sm->peer_challenge = data->key_block_p->client_challenge;
953214501Srpaulo	}
954214501Srpaulo	sm->init_phase2 = 1;
955214501Srpaulo	data->phase2_priv = data->phase2_method->init(sm);
956214501Srpaulo	sm->init_phase2 = 0;
957214501Srpaulo	sm->auth_challenge = NULL;
958214501Srpaulo	sm->peer_challenge = NULL;
959214501Srpaulo
960214501Srpaulo	return data->phase2_priv == NULL ? -1 : 0;
961214501Srpaulo}
962214501Srpaulo
963214501Srpaulo
964214501Srpaulostatic void eap_fast_process_phase2_response(struct eap_sm *sm,
965214501Srpaulo					     struct eap_fast_data *data,
966214501Srpaulo					     u8 *in_data, size_t in_len)
967214501Srpaulo{
968214501Srpaulo	u8 next_type = EAP_TYPE_NONE;
969214501Srpaulo	struct eap_hdr *hdr;
970214501Srpaulo	u8 *pos;
971214501Srpaulo	size_t left;
972214501Srpaulo	struct wpabuf buf;
973214501Srpaulo	const struct eap_method *m = data->phase2_method;
974214501Srpaulo	void *priv = data->phase2_priv;
975214501Srpaulo
976214501Srpaulo	if (priv == NULL) {
977214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not "
978214501Srpaulo			   "initialized?!", __func__);
979214501Srpaulo		return;
980214501Srpaulo	}
981214501Srpaulo
982214501Srpaulo	hdr = (struct eap_hdr *) in_data;
983214501Srpaulo	pos = (u8 *) (hdr + 1);
984214501Srpaulo
985214501Srpaulo	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
986214501Srpaulo		left = in_len - sizeof(*hdr);
987214501Srpaulo		wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; "
988214501Srpaulo			    "allowed types", pos + 1, left - 1);
989214501Srpaulo#ifdef EAP_SERVER_TNC
990214501Srpaulo		if (m && m->vendor == EAP_VENDOR_IETF &&
991214501Srpaulo		    m->method == EAP_TYPE_TNC) {
992214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
993214501Srpaulo				   "TNC negotiation");
994214501Srpaulo			next_type = eap_fast_req_failure(sm, data);
995214501Srpaulo			eap_fast_phase2_init(sm, data, next_type);
996214501Srpaulo			return;
997214501Srpaulo		}
998214501Srpaulo#endif /* EAP_SERVER_TNC */
999214501Srpaulo		eap_sm_process_nak(sm, pos + 1, left - 1);
1000214501Srpaulo		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
1001214501Srpaulo		    sm->user->methods[sm->user_eap_method_index].method !=
1002214501Srpaulo		    EAP_TYPE_NONE) {
1003214501Srpaulo			next_type = sm->user->methods[
1004214501Srpaulo				sm->user_eap_method_index++].method;
1005214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
1006214501Srpaulo				   next_type);
1007214501Srpaulo		} else {
1008214501Srpaulo			next_type = eap_fast_req_failure(sm, data);
1009214501Srpaulo		}
1010214501Srpaulo		eap_fast_phase2_init(sm, data, next_type);
1011214501Srpaulo		return;
1012214501Srpaulo	}
1013214501Srpaulo
1014214501Srpaulo	wpabuf_set(&buf, in_data, in_len);
1015214501Srpaulo
1016214501Srpaulo	if (m->check(sm, priv, &buf)) {
1017214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
1018214501Srpaulo			   "ignore the packet");
1019214501Srpaulo		next_type = eap_fast_req_failure(sm, data);
1020214501Srpaulo		return;
1021214501Srpaulo	}
1022214501Srpaulo
1023214501Srpaulo	m->process(sm, priv, &buf);
1024214501Srpaulo
1025214501Srpaulo	if (!m->isDone(sm, priv))
1026214501Srpaulo		return;
1027214501Srpaulo
1028214501Srpaulo	if (!m->isSuccess(sm, priv)) {
1029214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
1030214501Srpaulo		next_type = eap_fast_req_failure(sm, data);
1031214501Srpaulo		eap_fast_phase2_init(sm, data, next_type);
1032214501Srpaulo		return;
1033214501Srpaulo	}
1034214501Srpaulo
1035214501Srpaulo	switch (data->state) {
1036214501Srpaulo	case PHASE2_ID:
1037214501Srpaulo		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
1038214501Srpaulo			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 "
1039214501Srpaulo					  "Identity not found in the user "
1040214501Srpaulo					  "database",
1041214501Srpaulo					  sm->identity, sm->identity_len);
1042214501Srpaulo			next_type = eap_fast_req_failure(sm, data);
1043214501Srpaulo			break;
1044214501Srpaulo		}
1045214501Srpaulo
1046214501Srpaulo		eap_fast_state(data, PHASE2_METHOD);
1047214501Srpaulo		if (data->anon_provisioning) {
1048214501Srpaulo			/*
1049214501Srpaulo			 * Only EAP-MSCHAPv2 is allowed for anonymous
1050214501Srpaulo			 * provisioning.
1051214501Srpaulo			 */
1052214501Srpaulo			next_type = EAP_TYPE_MSCHAPV2;
1053214501Srpaulo			sm->user_eap_method_index = 0;
1054214501Srpaulo		} else {
1055214501Srpaulo			next_type = sm->user->methods[0].method;
1056214501Srpaulo			sm->user_eap_method_index = 1;
1057214501Srpaulo		}
1058214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
1059214501Srpaulo		break;
1060214501Srpaulo	case PHASE2_METHOD:
1061214501Srpaulo	case CRYPTO_BINDING:
1062214501Srpaulo		eap_fast_update_icmk(sm, data);
1063214501Srpaulo		eap_fast_state(data, CRYPTO_BINDING);
1064214501Srpaulo		data->eap_seq++;
1065214501Srpaulo		next_type = EAP_TYPE_NONE;
1066214501Srpaulo#ifdef EAP_SERVER_TNC
1067214501Srpaulo		if (sm->tnc && !data->tnc_started) {
1068214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
1069214501Srpaulo			next_type = EAP_TYPE_TNC;
1070214501Srpaulo			data->tnc_started = 1;
1071214501Srpaulo		}
1072214501Srpaulo#endif /* EAP_SERVER_TNC */
1073214501Srpaulo		break;
1074214501Srpaulo	case FAILURE:
1075214501Srpaulo		break;
1076214501Srpaulo	default:
1077214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
1078214501Srpaulo			   __func__, data->state);
1079214501Srpaulo		break;
1080214501Srpaulo	}
1081214501Srpaulo
1082214501Srpaulo	eap_fast_phase2_init(sm, data, next_type);
1083214501Srpaulo}
1084214501Srpaulo
1085214501Srpaulo
1086214501Srpaulostatic void eap_fast_process_phase2_eap(struct eap_sm *sm,
1087214501Srpaulo					struct eap_fast_data *data,
1088214501Srpaulo					u8 *in_data, size_t in_len)
1089214501Srpaulo{
1090214501Srpaulo	struct eap_hdr *hdr;
1091214501Srpaulo	size_t len;
1092214501Srpaulo
1093214501Srpaulo	hdr = (struct eap_hdr *) in_data;
1094214501Srpaulo	if (in_len < (int) sizeof(*hdr)) {
1095214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
1096214501Srpaulo			   "EAP frame (len=%lu)", (unsigned long) in_len);
1097214501Srpaulo		eap_fast_req_failure(sm, data);
1098214501Srpaulo		return;
1099214501Srpaulo	}
1100214501Srpaulo	len = be_to_host16(hdr->length);
1101214501Srpaulo	if (len > in_len) {
1102214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in "
1103214501Srpaulo			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
1104214501Srpaulo			   (unsigned long) in_len, (unsigned long) len);
1105214501Srpaulo		eap_fast_req_failure(sm, data);
1106214501Srpaulo		return;
1107214501Srpaulo	}
1108214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d "
1109214501Srpaulo		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
1110214501Srpaulo		   (unsigned long) len);
1111214501Srpaulo	switch (hdr->code) {
1112214501Srpaulo	case EAP_CODE_RESPONSE:
1113214501Srpaulo		eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len);
1114214501Srpaulo		break;
1115214501Srpaulo	default:
1116214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
1117214501Srpaulo			   "Phase 2 EAP header", hdr->code);
1118214501Srpaulo		break;
1119214501Srpaulo	}
1120214501Srpaulo}
1121214501Srpaulo
1122214501Srpaulo
1123214501Srpaulostatic int eap_fast_parse_tlvs(struct wpabuf *data,
1124214501Srpaulo			       struct eap_fast_tlv_parse *tlv)
1125214501Srpaulo{
1126214501Srpaulo	int mandatory, tlv_type, len, res;
1127214501Srpaulo	u8 *pos, *end;
1128214501Srpaulo
1129214501Srpaulo	os_memset(tlv, 0, sizeof(*tlv));
1130214501Srpaulo
1131214501Srpaulo	pos = wpabuf_mhead(data);
1132214501Srpaulo	end = pos + wpabuf_len(data);
1133214501Srpaulo	while (pos + 4 < end) {
1134214501Srpaulo		mandatory = pos[0] & 0x80;
1135214501Srpaulo		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
1136214501Srpaulo		pos += 2;
1137214501Srpaulo		len = WPA_GET_BE16(pos);
1138214501Srpaulo		pos += 2;
1139214501Srpaulo		if (pos + len > end) {
1140214501Srpaulo			wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
1141214501Srpaulo			return -1;
1142214501Srpaulo		}
1143214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
1144214501Srpaulo			   "TLV type %d length %d%s",
1145214501Srpaulo			   tlv_type, len, mandatory ? " (mandatory)" : "");
1146214501Srpaulo
1147214501Srpaulo		res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
1148214501Srpaulo		if (res == -2)
1149214501Srpaulo			break;
1150214501Srpaulo		if (res < 0) {
1151214501Srpaulo			if (mandatory) {
1152214501Srpaulo				wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
1153214501Srpaulo					   "mandatory TLV type %d", tlv_type);
1154214501Srpaulo				/* TODO: generate Nak TLV */
1155214501Srpaulo				break;
1156214501Srpaulo			} else {
1157214501Srpaulo				wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored "
1158214501Srpaulo					   "unknown optional TLV type %d",
1159214501Srpaulo					   tlv_type);
1160214501Srpaulo			}
1161214501Srpaulo		}
1162214501Srpaulo
1163214501Srpaulo		pos += len;
1164214501Srpaulo	}
1165214501Srpaulo
1166214501Srpaulo	return 0;
1167214501Srpaulo}
1168214501Srpaulo
1169214501Srpaulo
1170214501Srpaulostatic int eap_fast_validate_crypto_binding(
1171214501Srpaulo	struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b,
1172214501Srpaulo	size_t bind_len)
1173214501Srpaulo{
1174214501Srpaulo	u8 cmac[SHA1_MAC_LEN];
1175214501Srpaulo
1176214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: "
1177214501Srpaulo		   "Version %d Received Version %d SubType %d",
1178214501Srpaulo		   b->version, b->received_version, b->subtype);
1179214501Srpaulo	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
1180214501Srpaulo		    b->nonce, sizeof(b->nonce));
1181214501Srpaulo	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
1182214501Srpaulo		    b->compound_mac, sizeof(b->compound_mac));
1183214501Srpaulo
1184214501Srpaulo	if (b->version != EAP_FAST_VERSION ||
1185214501Srpaulo	    b->received_version != EAP_FAST_VERSION) {
1186214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version "
1187214501Srpaulo			   "in Crypto-Binding: version %d "
1188214501Srpaulo			   "received_version %d", b->version,
1189214501Srpaulo			   b->received_version);
1190214501Srpaulo		return -1;
1191214501Srpaulo	}
1192214501Srpaulo
1193214501Srpaulo	if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) {
1194214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in "
1195214501Srpaulo			   "Crypto-Binding: %d", b->subtype);
1196214501Srpaulo		return -1;
1197214501Srpaulo	}
1198214501Srpaulo
1199214501Srpaulo	if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
1200214501Srpaulo	    (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
1201214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
1202214501Srpaulo			   "Crypto-Binding");
1203214501Srpaulo		return -1;
1204214501Srpaulo	}
1205214501Srpaulo
1206214501Srpaulo	os_memcpy(cmac, b->compound_mac, sizeof(cmac));
1207214501Srpaulo	os_memset(b->compound_mac, 0, sizeof(cmac));
1208214501Srpaulo	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for "
1209214501Srpaulo		    "Compound MAC calculation",
1210214501Srpaulo		    (u8 *) b, bind_len);
1211214501Srpaulo	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len,
1212214501Srpaulo		  b->compound_mac);
1213214501Srpaulo	if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
1214214501Srpaulo		wpa_hexdump(MSG_MSGDUMP,
1215214501Srpaulo			    "EAP-FAST: Calculated Compound MAC",
1216214501Srpaulo			    b->compound_mac, sizeof(cmac));
1217214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not "
1218214501Srpaulo			   "match");
1219214501Srpaulo		return -1;
1220214501Srpaulo	}
1221214501Srpaulo
1222214501Srpaulo	return 0;
1223214501Srpaulo}
1224214501Srpaulo
1225214501Srpaulo
1226214501Srpaulostatic int eap_fast_pac_type(u8 *pac, size_t len, u16 type)
1227214501Srpaulo{
1228214501Srpaulo	struct eap_tlv_pac_type_tlv *tlv;
1229214501Srpaulo
1230214501Srpaulo	if (pac == NULL || len != sizeof(*tlv))
1231214501Srpaulo		return 0;
1232214501Srpaulo
1233214501Srpaulo	tlv = (struct eap_tlv_pac_type_tlv *) pac;
1234214501Srpaulo
1235214501Srpaulo	return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE &&
1236214501Srpaulo		be_to_host16(tlv->length) == 2 &&
1237214501Srpaulo		be_to_host16(tlv->pac_type) == type;
1238214501Srpaulo}
1239214501Srpaulo
1240214501Srpaulo
1241214501Srpaulostatic void eap_fast_process_phase2_tlvs(struct eap_sm *sm,
1242214501Srpaulo					 struct eap_fast_data *data,
1243214501Srpaulo					 struct wpabuf *in_data)
1244214501Srpaulo{
1245214501Srpaulo	struct eap_fast_tlv_parse tlv;
1246214501Srpaulo	int check_crypto_binding = data->state == CRYPTO_BINDING;
1247214501Srpaulo
1248214501Srpaulo	if (eap_fast_parse_tlvs(in_data, &tlv) < 0) {
1249214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received "
1250214501Srpaulo			   "Phase 2 TLVs");
1251214501Srpaulo		return;
1252214501Srpaulo	}
1253214501Srpaulo
1254214501Srpaulo	if (tlv.result == EAP_TLV_RESULT_FAILURE) {
1255214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated "
1256214501Srpaulo			   "failure");
1257214501Srpaulo		eap_fast_state(data, FAILURE);
1258214501Srpaulo		return;
1259214501Srpaulo	}
1260214501Srpaulo
1261214501Srpaulo	if (data->state == REQUEST_PAC) {
1262214501Srpaulo		u16 type, len, res;
1263214501Srpaulo		if (tlv.pac == NULL || tlv.pac_len < 6) {
1264214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC "
1265214501Srpaulo				   "Acknowledgement received");
1266214501Srpaulo			eap_fast_state(data, FAILURE);
1267214501Srpaulo			return;
1268214501Srpaulo		}
1269214501Srpaulo
1270214501Srpaulo		type = WPA_GET_BE16(tlv.pac);
1271214501Srpaulo		len = WPA_GET_BE16(tlv.pac + 2);
1272214501Srpaulo		res = WPA_GET_BE16(tlv.pac + 4);
1273214501Srpaulo
1274214501Srpaulo		if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 ||
1275214501Srpaulo		    res != EAP_TLV_RESULT_SUCCESS) {
1276214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not "
1277214501Srpaulo				   "contain acknowledgement");
1278214501Srpaulo			eap_fast_state(data, FAILURE);
1279214501Srpaulo			return;
1280214501Srpaulo		}
1281214501Srpaulo
1282214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received "
1283214501Srpaulo			   "- PAC provisioning succeeded");
1284214501Srpaulo		eap_fast_state(data, (data->anon_provisioning ||
1285214501Srpaulo				      data->send_new_pac == 2) ?
1286214501Srpaulo			       FAILURE : SUCCESS);
1287214501Srpaulo		return;
1288214501Srpaulo	}
1289214501Srpaulo
1290214501Srpaulo	if (check_crypto_binding) {
1291214501Srpaulo		if (tlv.crypto_binding == NULL) {
1292214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding "
1293214501Srpaulo				   "TLV received");
1294214501Srpaulo			eap_fast_state(data, FAILURE);
1295214501Srpaulo			return;
1296214501Srpaulo		}
1297214501Srpaulo
1298214501Srpaulo		if (data->final_result &&
1299214501Srpaulo		    tlv.result != EAP_TLV_RESULT_SUCCESS) {
1300214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
1301214501Srpaulo				   "without Success Result");
1302214501Srpaulo			eap_fast_state(data, FAILURE);
1303214501Srpaulo			return;
1304214501Srpaulo		}
1305214501Srpaulo
1306214501Srpaulo		if (!data->final_result &&
1307214501Srpaulo		    tlv.iresult != EAP_TLV_RESULT_SUCCESS) {
1308214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
1309214501Srpaulo				   "without intermediate Success Result");
1310214501Srpaulo			eap_fast_state(data, FAILURE);
1311214501Srpaulo			return;
1312214501Srpaulo		}
1313214501Srpaulo
1314214501Srpaulo		if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding,
1315214501Srpaulo						     tlv.crypto_binding_len)) {
1316214501Srpaulo			eap_fast_state(data, FAILURE);
1317214501Srpaulo			return;
1318214501Srpaulo		}
1319214501Srpaulo
1320214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV "
1321214501Srpaulo			   "received");
1322214501Srpaulo		if (data->final_result) {
1323214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
1324214501Srpaulo				   "completed successfully");
1325214501Srpaulo		}
1326214501Srpaulo
1327214501Srpaulo		if (data->anon_provisioning &&
1328214501Srpaulo		    sm->eap_fast_prov != ANON_PROV &&
1329214501Srpaulo		    sm->eap_fast_prov != BOTH_PROV) {
1330214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
1331214501Srpaulo				   "use unauthenticated provisioning which is "
1332214501Srpaulo				   "disabled");
1333214501Srpaulo			eap_fast_state(data, FAILURE);
1334214501Srpaulo			return;
1335214501Srpaulo		}
1336214501Srpaulo
1337214501Srpaulo		if (sm->eap_fast_prov != AUTH_PROV &&
1338214501Srpaulo		    sm->eap_fast_prov != BOTH_PROV &&
1339214501Srpaulo		    tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
1340214501Srpaulo		    eap_fast_pac_type(tlv.pac, tlv.pac_len,
1341214501Srpaulo				      PAC_TYPE_TUNNEL_PAC)) {
1342214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
1343214501Srpaulo				   "use authenticated provisioning which is "
1344214501Srpaulo				   "disabled");
1345214501Srpaulo			eap_fast_state(data, FAILURE);
1346214501Srpaulo			return;
1347214501Srpaulo		}
1348214501Srpaulo
1349214501Srpaulo		if (data->anon_provisioning ||
1350214501Srpaulo		    (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
1351214501Srpaulo		     eap_fast_pac_type(tlv.pac, tlv.pac_len,
1352214501Srpaulo				       PAC_TYPE_TUNNEL_PAC))) {
1353214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new "
1354214501Srpaulo				   "Tunnel PAC");
1355214501Srpaulo			eap_fast_state(data, REQUEST_PAC);
1356214501Srpaulo		} else if (data->send_new_pac) {
1357214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered "
1358214501Srpaulo				   "re-keying of Tunnel PAC");
1359214501Srpaulo			eap_fast_state(data, REQUEST_PAC);
1360214501Srpaulo		} else if (data->final_result)
1361214501Srpaulo			eap_fast_state(data, SUCCESS);
1362214501Srpaulo	}
1363214501Srpaulo
1364214501Srpaulo	if (tlv.eap_payload_tlv) {
1365214501Srpaulo		eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
1366214501Srpaulo					    tlv.eap_payload_tlv_len);
1367214501Srpaulo	}
1368214501Srpaulo}
1369214501Srpaulo
1370214501Srpaulo
1371214501Srpaulostatic void eap_fast_process_phase2(struct eap_sm *sm,
1372214501Srpaulo				    struct eap_fast_data *data,
1373214501Srpaulo				    struct wpabuf *in_buf)
1374214501Srpaulo{
1375214501Srpaulo	struct wpabuf *in_decrypted;
1376214501Srpaulo
1377214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
1378214501Srpaulo		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
1379214501Srpaulo
1380214501Srpaulo	if (data->pending_phase2_resp) {
1381214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
1382214501Srpaulo			   "skip decryption and use old data");
1383214501Srpaulo		eap_fast_process_phase2_tlvs(sm, data,
1384214501Srpaulo					     data->pending_phase2_resp);
1385214501Srpaulo		wpabuf_free(data->pending_phase2_resp);
1386214501Srpaulo		data->pending_phase2_resp = NULL;
1387214501Srpaulo		return;
1388214501Srpaulo	}
1389214501Srpaulo
1390214501Srpaulo	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
1391214501Srpaulo					      in_buf);
1392214501Srpaulo	if (in_decrypted == NULL) {
1393214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
1394214501Srpaulo			   "data");
1395214501Srpaulo		eap_fast_state(data, FAILURE);
1396214501Srpaulo		return;
1397214501Srpaulo	}
1398214501Srpaulo
1399214501Srpaulo	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs",
1400214501Srpaulo			    in_decrypted);
1401214501Srpaulo
1402214501Srpaulo	eap_fast_process_phase2_tlvs(sm, data, in_decrypted);
1403214501Srpaulo
1404214501Srpaulo	if (sm->method_pending == METHOD_PENDING_WAIT) {
1405214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in "
1406214501Srpaulo			   "pending wait state - save decrypted response");
1407214501Srpaulo		wpabuf_free(data->pending_phase2_resp);
1408214501Srpaulo		data->pending_phase2_resp = in_decrypted;
1409214501Srpaulo		return;
1410214501Srpaulo	}
1411214501Srpaulo
1412214501Srpaulo	wpabuf_free(in_decrypted);
1413214501Srpaulo}
1414214501Srpaulo
1415214501Srpaulo
1416214501Srpaulostatic int eap_fast_process_version(struct eap_sm *sm, void *priv,
1417214501Srpaulo				    int peer_version)
1418214501Srpaulo{
1419214501Srpaulo	struct eap_fast_data *data = priv;
1420214501Srpaulo
1421214501Srpaulo	data->peer_version = peer_version;
1422214501Srpaulo
1423214501Srpaulo	if (data->force_version >= 0 && peer_version != data->force_version) {
1424214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced"
1425214501Srpaulo			   " version (forced=%d peer=%d) - reject",
1426214501Srpaulo			   data->force_version, peer_version);
1427214501Srpaulo		return -1;
1428214501Srpaulo	}
1429214501Srpaulo
1430214501Srpaulo	if (peer_version < data->fast_version) {
1431214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; "
1432214501Srpaulo			   "use version %d",
1433214501Srpaulo			   peer_version, data->fast_version, peer_version);
1434214501Srpaulo		data->fast_version = peer_version;
1435214501Srpaulo	}
1436214501Srpaulo
1437214501Srpaulo	return 0;
1438214501Srpaulo}
1439214501Srpaulo
1440214501Srpaulo
1441214501Srpaulostatic int eap_fast_process_phase1(struct eap_sm *sm,
1442214501Srpaulo				   struct eap_fast_data *data)
1443214501Srpaulo{
1444214501Srpaulo	if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
1445214501Srpaulo		wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed");
1446214501Srpaulo		eap_fast_state(data, FAILURE);
1447214501Srpaulo		return -1;
1448214501Srpaulo	}
1449214501Srpaulo
1450214501Srpaulo	if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
1451214501Srpaulo	    wpabuf_len(data->ssl.tls_out) > 0)
1452214501Srpaulo		return 1;
1453214501Srpaulo
1454214501Srpaulo	/*
1455214501Srpaulo	 * Phase 1 was completed with the received message (e.g., when using
1456214501Srpaulo	 * abbreviated handshake), so Phase 2 can be started immediately
1457214501Srpaulo	 * without having to send through an empty message to the peer.
1458214501Srpaulo	 */
1459214501Srpaulo
1460214501Srpaulo	return eap_fast_phase1_done(sm, data);
1461214501Srpaulo}
1462214501Srpaulo
1463214501Srpaulo
1464214501Srpaulostatic int eap_fast_process_phase2_start(struct eap_sm *sm,
1465214501Srpaulo					 struct eap_fast_data *data)
1466214501Srpaulo{
1467214501Srpaulo	u8 next_type;
1468214501Srpaulo
1469214501Srpaulo	if (data->identity) {
1470214501Srpaulo		os_free(sm->identity);
1471214501Srpaulo		sm->identity = data->identity;
1472214501Srpaulo		data->identity = NULL;
1473214501Srpaulo		sm->identity_len = data->identity_len;
1474214501Srpaulo		data->identity_len = 0;
1475214501Srpaulo		sm->require_identity_match = 1;
1476214501Srpaulo		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
1477214501Srpaulo			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: "
1478214501Srpaulo					  "Phase2 Identity not found "
1479214501Srpaulo					  "in the user database",
1480214501Srpaulo					  sm->identity, sm->identity_len);
1481214501Srpaulo			next_type = eap_fast_req_failure(sm, data);
1482214501Srpaulo		} else {
1483214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
1484214501Srpaulo				   "known - skip Phase 2 Identity Request");
1485214501Srpaulo			next_type = sm->user->methods[0].method;
1486214501Srpaulo			sm->user_eap_method_index = 1;
1487214501Srpaulo		}
1488214501Srpaulo
1489214501Srpaulo		eap_fast_state(data, PHASE2_METHOD);
1490214501Srpaulo	} else {
1491214501Srpaulo		eap_fast_state(data, PHASE2_ID);
1492214501Srpaulo		next_type = EAP_TYPE_IDENTITY;
1493214501Srpaulo	}
1494214501Srpaulo
1495214501Srpaulo	return eap_fast_phase2_init(sm, data, next_type);
1496214501Srpaulo}
1497214501Srpaulo
1498214501Srpaulo
1499214501Srpaulostatic void eap_fast_process_msg(struct eap_sm *sm, void *priv,
1500214501Srpaulo				 const struct wpabuf *respData)
1501214501Srpaulo{
1502214501Srpaulo	struct eap_fast_data *data = priv;
1503214501Srpaulo
1504214501Srpaulo	switch (data->state) {
1505214501Srpaulo	case PHASE1:
1506214501Srpaulo		if (eap_fast_process_phase1(sm, data))
1507214501Srpaulo			break;
1508214501Srpaulo
1509214501Srpaulo		/* fall through to PHASE2_START */
1510214501Srpaulo	case PHASE2_START:
1511214501Srpaulo		eap_fast_process_phase2_start(sm, data);
1512214501Srpaulo		break;
1513214501Srpaulo	case PHASE2_ID:
1514214501Srpaulo	case PHASE2_METHOD:
1515214501Srpaulo	case CRYPTO_BINDING:
1516214501Srpaulo	case REQUEST_PAC:
1517214501Srpaulo		eap_fast_process_phase2(sm, data, data->ssl.tls_in);
1518214501Srpaulo		break;
1519214501Srpaulo	default:
1520214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s",
1521214501Srpaulo			   data->state, __func__);
1522214501Srpaulo		break;
1523214501Srpaulo	}
1524214501Srpaulo}
1525214501Srpaulo
1526214501Srpaulo
1527214501Srpaulostatic void eap_fast_process(struct eap_sm *sm, void *priv,
1528214501Srpaulo			     struct wpabuf *respData)
1529214501Srpaulo{
1530214501Srpaulo	struct eap_fast_data *data = priv;
1531214501Srpaulo	if (eap_server_tls_process(sm, &data->ssl, respData, data,
1532214501Srpaulo				   EAP_TYPE_FAST, eap_fast_process_version,
1533214501Srpaulo				   eap_fast_process_msg) < 0)
1534214501Srpaulo		eap_fast_state(data, FAILURE);
1535214501Srpaulo}
1536214501Srpaulo
1537214501Srpaulo
1538214501Srpaulostatic Boolean eap_fast_isDone(struct eap_sm *sm, void *priv)
1539214501Srpaulo{
1540214501Srpaulo	struct eap_fast_data *data = priv;
1541214501Srpaulo	return data->state == SUCCESS || data->state == FAILURE;
1542214501Srpaulo}
1543214501Srpaulo
1544214501Srpaulo
1545214501Srpaulostatic u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
1546214501Srpaulo{
1547214501Srpaulo	struct eap_fast_data *data = priv;
1548214501Srpaulo	u8 *eapKeyData;
1549214501Srpaulo
1550214501Srpaulo	if (data->state != SUCCESS)
1551214501Srpaulo		return NULL;
1552214501Srpaulo
1553214501Srpaulo	eapKeyData = os_malloc(EAP_FAST_KEY_LEN);
1554214501Srpaulo	if (eapKeyData == NULL)
1555214501Srpaulo		return NULL;
1556214501Srpaulo
1557214501Srpaulo	eap_fast_derive_eap_msk(data->simck, eapKeyData);
1558214501Srpaulo	*len = EAP_FAST_KEY_LEN;
1559214501Srpaulo
1560214501Srpaulo	return eapKeyData;
1561214501Srpaulo}
1562214501Srpaulo
1563214501Srpaulo
1564214501Srpaulostatic u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1565214501Srpaulo{
1566214501Srpaulo	struct eap_fast_data *data = priv;
1567214501Srpaulo	u8 *eapKeyData;
1568214501Srpaulo
1569214501Srpaulo	if (data->state != SUCCESS)
1570214501Srpaulo		return NULL;
1571214501Srpaulo
1572214501Srpaulo	eapKeyData = os_malloc(EAP_EMSK_LEN);
1573214501Srpaulo	if (eapKeyData == NULL)
1574214501Srpaulo		return NULL;
1575214501Srpaulo
1576214501Srpaulo	eap_fast_derive_eap_emsk(data->simck, eapKeyData);
1577214501Srpaulo	*len = EAP_EMSK_LEN;
1578214501Srpaulo
1579214501Srpaulo	return eapKeyData;
1580214501Srpaulo}
1581214501Srpaulo
1582214501Srpaulo
1583214501Srpaulostatic Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
1584214501Srpaulo{
1585214501Srpaulo	struct eap_fast_data *data = priv;
1586214501Srpaulo	return data->state == SUCCESS;
1587214501Srpaulo}
1588214501Srpaulo
1589214501Srpaulo
1590214501Srpauloint eap_server_fast_register(void)
1591214501Srpaulo{
1592214501Srpaulo	struct eap_method *eap;
1593214501Srpaulo	int ret;
1594214501Srpaulo
1595214501Srpaulo	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1596214501Srpaulo				      EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
1597214501Srpaulo	if (eap == NULL)
1598214501Srpaulo		return -1;
1599214501Srpaulo
1600214501Srpaulo	eap->init = eap_fast_init;
1601214501Srpaulo	eap->reset = eap_fast_reset;
1602214501Srpaulo	eap->buildReq = eap_fast_buildReq;
1603214501Srpaulo	eap->check = eap_fast_check;
1604214501Srpaulo	eap->process = eap_fast_process;
1605214501Srpaulo	eap->isDone = eap_fast_isDone;
1606214501Srpaulo	eap->getKey = eap_fast_getKey;
1607214501Srpaulo	eap->get_emsk = eap_fast_get_emsk;
1608214501Srpaulo	eap->isSuccess = eap_fast_isSuccess;
1609214501Srpaulo
1610214501Srpaulo	ret = eap_server_method_register(eap);
1611214501Srpaulo	if (ret)
1612214501Srpaulo		eap_server_method_free(eap);
1613214501Srpaulo	return ret;
1614214501Srpaulo}
1615