1/*
2 * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
3 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "common.h"
18#include "eap_i.h"
19#include "eap_tls_common.h"
20#include "config_ssid.h"
21#include "tls.h"
22#include "eap_tlv.h"
23
24
25/* Maximum supported PEAP version
26 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
27 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
28 * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
29 */
30#define EAP_PEAP_VERSION 1
31
32
33static void eap_peap_deinit(struct eap_sm *sm, void *priv);
34
35
36struct eap_peap_data {
37	struct eap_ssl_data ssl;
38
39	int peap_version, force_peap_version, force_new_label;
40
41	const struct eap_method *phase2_method;
42	void *phase2_priv;
43	int phase2_success;
44	int phase2_eap_success;
45	int phase2_eap_started;
46
47	struct eap_method_type phase2_type;
48	struct eap_method_type *phase2_types;
49	size_t num_phase2_types;
50
51	int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
52				 * EAP-Success
53				 * 1 = reply with tunneled EAP-Success to inner
54				 * EAP-Success and expect AS to send outer
55				 * (unencrypted) EAP-Success after this
56				 * 2 = reply with PEAP/TLS ACK to inner
57				 * EAP-Success and expect AS to send outer
58				 * (unencrypted) EAP-Success after this */
59	int resuming; /* starting a resumed session */
60	u8 *key_data;
61
62	u8 *pending_phase2_req;
63	size_t pending_phase2_req_len;
64};
65
66
67static void * eap_peap_init(struct eap_sm *sm)
68{
69	struct eap_peap_data *data;
70	struct wpa_ssid *config = eap_get_config(sm);
71
72	data = os_zalloc(sizeof(*data));
73	if (data == NULL)
74		return NULL;
75	sm->peap_done = FALSE;
76	data->peap_version = EAP_PEAP_VERSION;
77	data->force_peap_version = -1;
78	data->peap_outer_success = 2;
79
80	if (config && config->phase1) {
81		char *pos = os_strstr(config->phase1, "peapver=");
82		if (pos) {
83			data->force_peap_version = atoi(pos + 8);
84			data->peap_version = data->force_peap_version;
85			wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version "
86				   "%d", data->force_peap_version);
87		}
88
89		if (os_strstr(config->phase1, "peaplabel=1")) {
90			data->force_new_label = 1;
91			wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for "
92				   "key derivation");
93		}
94
95		if (os_strstr(config->phase1, "peap_outer_success=0")) {
96			data->peap_outer_success = 0;
97			wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate "
98				   "authentication on tunneled EAP-Success");
99		} else if (os_strstr(config->phase1, "peap_outer_success=1")) {
100			data->peap_outer_success = 1;
101			wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled "
102				   "EAP-Success after receiving tunneled "
103				   "EAP-Success");
104		} else if (os_strstr(config->phase1, "peap_outer_success=2")) {
105			data->peap_outer_success = 2;
106			wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK "
107				   "after receiving tunneled EAP-Success");
108		}
109	}
110
111	if (config && config->phase2) {
112		char *start, *pos, *buf;
113		struct eap_method_type *methods = NULL, *_methods;
114		u8 method;
115		size_t num_methods = 0;
116		start = buf = os_strdup(config->phase2);
117		if (buf == NULL) {
118			eap_peap_deinit(sm, data);
119			return NULL;
120		}
121		while (start && *start != '\0') {
122			int vendor;
123			pos = os_strstr(start, "auth=");
124			if (pos == NULL)
125				break;
126			if (start != pos && *(pos - 1) != ' ') {
127				start = pos + 5;
128				continue;
129			}
130
131			start = pos + 5;
132			pos = os_strchr(start, ' ');
133			if (pos)
134				*pos++ = '\0';
135			method = eap_get_phase2_type(start, &vendor);
136			if (vendor == EAP_VENDOR_IETF &&
137			    method == EAP_TYPE_NONE) {
138				wpa_printf(MSG_ERROR, "EAP-PEAP: Unsupported "
139					   "Phase2 method '%s'", start);
140			} else {
141				num_methods++;
142				_methods = os_realloc(
143					methods,
144					num_methods * sizeof(*methods));
145				if (_methods == NULL) {
146					os_free(methods);
147					os_free(buf);
148					eap_peap_deinit(sm, data);
149					return NULL;
150				}
151				methods = _methods;
152				methods[num_methods - 1].vendor = vendor;
153				methods[num_methods - 1].method = method;
154			}
155
156			start = pos;
157		}
158		os_free(buf);
159		data->phase2_types = methods;
160		data->num_phase2_types = num_methods;
161	}
162	if (data->phase2_types == NULL) {
163		data->phase2_types =
164			eap_get_phase2_types(config, &data->num_phase2_types);
165	}
166	if (data->phase2_types == NULL) {
167		wpa_printf(MSG_ERROR, "EAP-PEAP: No Phase2 method available");
168		eap_peap_deinit(sm, data);
169		return NULL;
170	}
171	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 EAP types",
172		    (u8 *) data->phase2_types,
173		    data->num_phase2_types * sizeof(struct eap_method_type));
174	data->phase2_type.vendor = EAP_VENDOR_IETF;
175	data->phase2_type.method = EAP_TYPE_NONE;
176
177	if (eap_tls_ssl_init(sm, &data->ssl, config)) {
178		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
179		eap_peap_deinit(sm, data);
180		return NULL;
181	}
182
183	return data;
184}
185
186
187static void eap_peap_deinit(struct eap_sm *sm, void *priv)
188{
189	struct eap_peap_data *data = priv;
190	if (data == NULL)
191		return;
192	if (data->phase2_priv && data->phase2_method)
193		data->phase2_method->deinit(sm, data->phase2_priv);
194	os_free(data->phase2_types);
195	eap_tls_ssl_deinit(sm, &data->ssl);
196	os_free(data->key_data);
197	os_free(data->pending_phase2_req);
198	os_free(data);
199}
200
201
202static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
203			    int id, const u8 *plain, size_t plain_len,
204			    u8 **out_data, size_t *out_len)
205{
206	int res;
207	u8 *pos;
208	struct eap_hdr *resp;
209
210	/* TODO: add support for fragmentation, if needed. This will need to
211	 * add TLS Message Length field, if the frame is fragmented.
212	 * Note: Microsoft IAS did not seem to like TLS Message Length with
213	 * PEAP/MSCHAPv2. */
214	resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
215	if (resp == NULL)
216		return -1;
217
218	resp->code = EAP_CODE_RESPONSE;
219	resp->identifier = id;
220
221	pos = (u8 *) (resp + 1);
222	*pos++ = EAP_TYPE_PEAP;
223	*pos++ = data->peap_version;
224
225	res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
226				     plain, plain_len,
227				     pos, data->ssl.tls_out_limit);
228	if (res < 0) {
229		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
230			   "data");
231		os_free(resp);
232		return -1;
233	}
234
235	*out_len = sizeof(struct eap_hdr) + 2 + res;
236	resp->length = host_to_be16(*out_len);
237	*out_data = (u8 *) resp;
238	return 0;
239}
240
241
242static int eap_peap_phase2_nak(struct eap_peap_data *data, struct eap_hdr *hdr,
243			       u8 **resp, size_t *resp_len)
244{
245	struct eap_hdr *resp_hdr;
246	u8 *pos = (u8 *) (hdr + 1);
247	size_t i;
248
249	/* TODO: add support for expanded Nak */
250	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: Nak type=%d", *pos);
251	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Allowed Phase2 EAP types",
252		    (u8 *) data->phase2_types,
253		    data->num_phase2_types * sizeof(struct eap_method_type));
254	*resp_len = sizeof(struct eap_hdr) + 1;
255	*resp = os_malloc(*resp_len + data->num_phase2_types);
256	if (*resp == NULL)
257		return -1;
258
259	resp_hdr = (struct eap_hdr *) (*resp);
260	resp_hdr->code = EAP_CODE_RESPONSE;
261	resp_hdr->identifier = hdr->identifier;
262	pos = (u8 *) (resp_hdr + 1);
263	*pos++ = EAP_TYPE_NAK;
264	for (i = 0; i < data->num_phase2_types; i++) {
265		if (data->phase2_types[i].vendor == EAP_VENDOR_IETF &&
266		    data->phase2_types[i].method < 256) {
267			(*resp_len)++;
268			*pos++ = data->phase2_types[i].method;
269		}
270	}
271	resp_hdr->length = host_to_be16(*resp_len);
272
273	return 0;
274}
275
276
277static int eap_peap_phase2_request(struct eap_sm *sm,
278				   struct eap_peap_data *data,
279				   struct eap_method_ret *ret,
280				   struct eap_hdr *hdr,
281				   u8 **resp, size_t *resp_len)
282{
283	size_t len = be_to_host16(hdr->length);
284	u8 *pos;
285	struct eap_method_ret iret;
286	struct wpa_ssid *config = eap_get_config(sm);
287
288	if (len <= sizeof(struct eap_hdr)) {
289		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
290			   "Phase 2 request (len=%lu)", (unsigned long) len);
291		return -1;
292	}
293	pos = (u8 *) (hdr + 1);
294	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
295	switch (*pos) {
296	case EAP_TYPE_IDENTITY:
297		*resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
298		break;
299	case EAP_TYPE_TLV:
300		os_memset(&iret, 0, sizeof(iret));
301		if (eap_tlv_process(sm, &iret, hdr, resp, resp_len,
302				    data->phase2_eap_started &&
303				    !data->phase2_eap_success)) {
304			ret->methodState = METHOD_DONE;
305			ret->decision = DECISION_FAIL;
306			return -1;
307		}
308		if (iret.methodState == METHOD_DONE ||
309		    iret.methodState == METHOD_MAY_CONT) {
310			ret->methodState = iret.methodState;
311			ret->decision = iret.decision;
312			data->phase2_success = 1;
313		}
314		break;
315	default:
316		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
317		    data->phase2_type.method == EAP_TYPE_NONE) {
318			size_t i;
319			for (i = 0; i < data->num_phase2_types; i++) {
320				if (data->phase2_types[i].vendor !=
321				    EAP_VENDOR_IETF ||
322				    data->phase2_types[i].method != *pos)
323					continue;
324
325				data->phase2_type.vendor =
326					data->phase2_types[i].vendor;
327				data->phase2_type.method =
328					data->phase2_types[i].method;
329				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
330					   "Phase 2 EAP vendor %d method %d",
331					   data->phase2_type.vendor,
332					   data->phase2_type.method);
333				break;
334			}
335		}
336		if (*pos != data->phase2_type.method ||
337		    *pos == EAP_TYPE_NONE) {
338			if (eap_peap_phase2_nak(data, hdr, resp, resp_len))
339				return -1;
340			return 0;
341		}
342
343		if (data->phase2_priv == NULL) {
344			data->phase2_method = eap_sm_get_eap_methods(
345				data->phase2_type.vendor,
346				data->phase2_type.method);
347			if (data->phase2_method) {
348				sm->init_phase2 = 1;
349				data->phase2_priv =
350					data->phase2_method->init(sm);
351				sm->init_phase2 = 0;
352			}
353		}
354		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
355			wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
356				   "Phase 2 EAP method %d", *pos);
357			ret->methodState = METHOD_DONE;
358			ret->decision = DECISION_FAIL;
359			return -1;
360		}
361		data->phase2_eap_started = 1;
362		os_memset(&iret, 0, sizeof(iret));
363		*resp = data->phase2_method->process(sm, data->phase2_priv,
364						     &iret, (u8 *) hdr, len,
365						     resp_len);
366		if ((iret.methodState == METHOD_DONE ||
367		     iret.methodState == METHOD_MAY_CONT) &&
368		    (iret.decision == DECISION_UNCOND_SUCC ||
369		     iret.decision == DECISION_COND_SUCC)) {
370			data->phase2_eap_success = 1;
371			data->phase2_success = 1;
372		}
373		break;
374	}
375
376	if (*resp == NULL &&
377	    (config->pending_req_identity || config->pending_req_password ||
378	     config->pending_req_otp || config->pending_req_new_password)) {
379		os_free(data->pending_phase2_req);
380		data->pending_phase2_req = os_malloc(len);
381		if (data->pending_phase2_req) {
382			os_memcpy(data->pending_phase2_req, hdr, len);
383			data->pending_phase2_req_len = len;
384		}
385	}
386
387	return 0;
388}
389
390
391static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
392			    struct eap_method_ret *ret,
393			    const struct eap_hdr *req,
394			    const u8 *in_data, size_t in_len,
395			    u8 **out_data, size_t *out_len)
396{
397	u8 *in_decrypted;
398	int res, skip_change = 0;
399	struct eap_hdr *hdr, *rhdr;
400	u8 *resp = NULL;
401	size_t resp_len, len_decrypted, len, buf_len;
402	const u8 *msg;
403	size_t msg_len;
404	int need_more_input;
405
406	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
407		   " Phase 2", (unsigned long) in_len);
408
409	if (data->pending_phase2_req) {
410		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
411			   "skip decryption and use old data");
412		/* Clear TLS reassembly state. */
413		os_free(data->ssl.tls_in);
414		data->ssl.tls_in = NULL;
415		data->ssl.tls_in_len = 0;
416		data->ssl.tls_in_left = 0;
417		data->ssl.tls_in_total = 0;
418		in_decrypted = data->pending_phase2_req;
419		data->pending_phase2_req = NULL;
420		len_decrypted = data->pending_phase2_req_len;
421		skip_change = 1;
422		goto continue_req;
423	}
424
425	msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
426				      &msg_len, &need_more_input);
427	if (msg == NULL)
428		return need_more_input ? 1 : -1;
429
430	if (in_len == 0 && sm->workaround && data->phase2_success) {
431		/*
432		 * Cisco ACS seems to be using TLS ACK to terminate
433		 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
434		 */
435		wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
436			   "expected data - acknowledge with TLS ACK since "
437			   "Phase 2 has been completed");
438		ret->decision = DECISION_COND_SUCC;
439		ret->methodState = METHOD_DONE;
440		return 1;
441	}
442
443	buf_len = in_len;
444	if (data->ssl.tls_in_total > buf_len)
445		buf_len = data->ssl.tls_in_total;
446	in_decrypted = os_malloc(buf_len);
447	if (in_decrypted == NULL) {
448		os_free(data->ssl.tls_in);
449		data->ssl.tls_in = NULL;
450		data->ssl.tls_in_len = 0;
451		wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
452			   "for decryption");
453		return -1;
454	}
455
456	res = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
457				     msg, msg_len, in_decrypted, buf_len);
458	os_free(data->ssl.tls_in);
459	data->ssl.tls_in = NULL;
460	data->ssl.tls_in_len = 0;
461	if (res < 0) {
462		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
463			   "data");
464		os_free(in_decrypted);
465		return 0;
466	}
467	len_decrypted = res;
468
469continue_req:
470	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted,
471		    len_decrypted);
472
473	hdr = (struct eap_hdr *) in_decrypted;
474	if (len_decrypted == 5 && hdr->code == EAP_CODE_REQUEST &&
475	    be_to_host16(hdr->length) == 5 &&
476	    in_decrypted[4] == EAP_TYPE_IDENTITY) {
477		/* At least FreeRADIUS seems to send full EAP header with
478		 * EAP Request Identity */
479		skip_change = 1;
480	}
481	if (len_decrypted >= 5 && hdr->code == EAP_CODE_REQUEST &&
482	    in_decrypted[4] == EAP_TYPE_TLV) {
483		skip_change = 1;
484	}
485
486	if (data->peap_version == 0 && !skip_change) {
487		struct eap_hdr *nhdr = os_malloc(sizeof(struct eap_hdr) +
488						 len_decrypted);
489		if (nhdr == NULL) {
490			os_free(in_decrypted);
491			return 0;
492		}
493		os_memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
494		os_free(in_decrypted);
495		nhdr->code = req->code;
496		nhdr->identifier = req->identifier;
497		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
498					    len_decrypted);
499
500		len_decrypted += sizeof(struct eap_hdr);
501		in_decrypted = (u8 *) nhdr;
502	}
503	hdr = (struct eap_hdr *) in_decrypted;
504	if (len_decrypted < sizeof(*hdr)) {
505		os_free(in_decrypted);
506		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
507			   "EAP frame (len=%lu)",
508			   (unsigned long) len_decrypted);
509		return 0;
510	}
511	len = be_to_host16(hdr->length);
512	if (len > len_decrypted) {
513		os_free(in_decrypted);
514		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
515			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
516			   (unsigned long) len_decrypted, (unsigned long) len);
517		return 0;
518	}
519	if (len < len_decrypted) {
520		wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
521			   "shorter length than full decrypted data "
522			   "(%lu < %lu)",
523			   (unsigned long) len, (unsigned long) len_decrypted);
524		if (sm->workaround && len == 4 && len_decrypted == 5 &&
525		    in_decrypted[4] == EAP_TYPE_IDENTITY) {
526			/* Radiator 3.9 seems to set Phase 2 EAP header to use
527			 * incorrect length for the EAP-Request Identity
528			 * packet, so fix the inner header to interoperate..
529			 * This was fixed in 2004-06-23 patch for Radiator and
530			 * this workaround can be removed at some point. */
531			wpa_printf(MSG_INFO, "EAP-PEAP: workaround -> replace "
532				   "Phase 2 EAP header len (%lu) with real "
533				   "decrypted len (%lu)",
534				   (unsigned long) len,
535				   (unsigned long) len_decrypted);
536			len = len_decrypted;
537			hdr->length = host_to_be16(len);
538		}
539	}
540	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
541		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
542		   (unsigned long) len);
543	switch (hdr->code) {
544	case EAP_CODE_REQUEST:
545		if (eap_peap_phase2_request(sm, data, ret, hdr,
546					    &resp, &resp_len)) {
547			os_free(in_decrypted);
548			wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
549				   "processing failed");
550			return 0;
551		}
552		break;
553	case EAP_CODE_SUCCESS:
554		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
555		if (data->peap_version == 1) {
556			/* EAP-Success within TLS tunnel is used to indicate
557			 * shutdown of the TLS channel. The authentication has
558			 * been completed. */
559			if (data->phase2_eap_started &&
560			    !data->phase2_eap_success) {
561				wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
562					   "Success used to indicate success, "
563					   "but Phase 2 EAP was not yet "
564					   "completed successfully");
565				ret->methodState = METHOD_DONE;
566				ret->decision = DECISION_FAIL;
567				os_free(in_decrypted);
568				return 0;
569			}
570			wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
571				   "EAP-Success within TLS tunnel - "
572				   "authentication completed");
573			ret->decision = DECISION_UNCOND_SUCC;
574			ret->methodState = METHOD_DONE;
575			data->phase2_success = 1;
576			if (data->peap_outer_success == 2) {
577				os_free(in_decrypted);
578				wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
579					   "to finish authentication");
580				return 1;
581			} else if (data->peap_outer_success == 1) {
582				/* Reply with EAP-Success within the TLS
583				 * channel to complete the authentication. */
584				resp_len = sizeof(struct eap_hdr);
585				resp = os_zalloc(resp_len);
586				if (resp) {
587					rhdr = (struct eap_hdr *) resp;
588					rhdr->code = EAP_CODE_SUCCESS;
589					rhdr->identifier = hdr->identifier;
590					rhdr->length = host_to_be16(resp_len);
591				}
592			} else {
593				/* No EAP-Success expected for Phase 1 (outer,
594				 * unencrypted auth), so force EAP state
595				 * machine to SUCCESS state. */
596				sm->peap_done = TRUE;
597			}
598		} else {
599			/* FIX: ? */
600		}
601		break;
602	case EAP_CODE_FAILURE:
603		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
604		ret->decision = DECISION_FAIL;
605		ret->methodState = METHOD_MAY_CONT;
606		ret->allowNotifications = FALSE;
607		/* Reply with EAP-Failure within the TLS channel to complete
608		 * failure reporting. */
609		resp_len = sizeof(struct eap_hdr);
610		resp = os_zalloc(resp_len);
611		if (resp) {
612			rhdr = (struct eap_hdr *) resp;
613			rhdr->code = EAP_CODE_FAILURE;
614			rhdr->identifier = hdr->identifier;
615			rhdr->length = host_to_be16(resp_len);
616		}
617		break;
618	default:
619		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
620			   "Phase 2 EAP header", hdr->code);
621		break;
622	}
623
624	os_free(in_decrypted);
625
626	if (resp) {
627		u8 *resp_pos;
628		size_t resp_send_len;
629		int skip_change2 = 0;
630
631		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
632				resp, resp_len);
633		/* PEAP version changes */
634		if (resp_len >= 5 && resp[0] == EAP_CODE_RESPONSE &&
635		    resp[4] == EAP_TYPE_TLV)
636			skip_change2 = 1;
637		if (data->peap_version == 0 && !skip_change2) {
638			resp_pos = resp + sizeof(struct eap_hdr);
639			resp_send_len = resp_len - sizeof(struct eap_hdr);
640		} else {
641			resp_pos = resp;
642			resp_send_len = resp_len;
643		}
644
645		if (eap_peap_encrypt(sm, data, req->identifier,
646				     resp_pos, resp_send_len,
647				     out_data, out_len)) {
648			wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
649				   "a Phase 2 frame");
650		}
651		os_free(resp);
652	}
653
654	return 0;
655}
656
657
658static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
659			     struct eap_method_ret *ret,
660			     const u8 *reqData, size_t reqDataLen,
661			     size_t *respDataLen)
662{
663	const struct eap_hdr *req;
664	size_t left;
665	int res;
666	u8 flags, *resp, id;
667	const u8 *pos;
668	struct eap_peap_data *data = priv;
669
670	pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
671				   reqData, reqDataLen, &left, &flags);
672	if (pos == NULL)
673		return NULL;
674	req = (const struct eap_hdr *) reqData;
675	id = req->identifier;
676
677	if (flags & EAP_TLS_FLAGS_START) {
678		wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
679			   "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
680			data->peap_version);
681		if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version)
682			data->peap_version = flags & EAP_PEAP_VERSION_MASK;
683		if (data->force_peap_version >= 0 &&
684		    data->force_peap_version != data->peap_version) {
685			wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
686				   "forced PEAP version %d",
687				   data->force_peap_version);
688			ret->methodState = METHOD_DONE;
689			ret->decision = DECISION_FAIL;
690			ret->allowNotifications = FALSE;
691			return NULL;
692		}
693		wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
694			   data->peap_version);
695		left = 0; /* make sure that this frame is empty, even though it
696			   * should always be, anyway */
697	}
698
699	resp = NULL;
700	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
701	    !data->resuming) {
702		res = eap_peap_decrypt(sm, data, ret, req, pos, left,
703				       &resp, respDataLen);
704	} else {
705		res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_PEAP,
706					     data->peap_version, id, pos, left,
707					     &resp, respDataLen);
708
709		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
710			char *label;
711			wpa_printf(MSG_DEBUG,
712				   "EAP-PEAP: TLS done, proceed to Phase 2");
713			os_free(data->key_data);
714			/* draft-josefsson-ppext-eap-tls-eap-05.txt
715			 * specifies that PEAPv1 would use "client PEAP
716			 * encryption" as the label. However, most existing
717			 * PEAPv1 implementations seem to be using the old
718			 * label, "client EAP encryption", instead. Use the old
719			 * label by default, but allow it to be configured with
720			 * phase1 parameter peaplabel=1. */
721			if (data->peap_version > 1 || data->force_new_label)
722				label = "client PEAP encryption";
723			else
724				label = "client EAP encryption";
725			wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
726				   "key derivation", label);
727			data->key_data =
728				eap_tls_derive_key(sm, &data->ssl, label,
729						   EAP_TLS_KEY_LEN);
730			if (data->key_data) {
731				wpa_hexdump_key(MSG_DEBUG,
732						"EAP-PEAP: Derived key",
733						data->key_data,
734						EAP_TLS_KEY_LEN);
735			} else {
736				wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
737					   "derive key");
738			}
739
740			if (sm->workaround && data->resuming) {
741				/*
742				 * At least few RADIUS servers (Aegis v1.1.6;
743				 * but not v1.1.4; and Cisco ACS) seem to be
744				 * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
745				 * ACS) session resumption with outer
746				 * EAP-Success. This does not seem to follow
747				 * draft-josefsson-pppext-eap-tls-eap-05.txt
748				 * section 4.2, so only allow this if EAP
749				 * workarounds are enabled.
750				 */
751				wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
752					   "allow outer EAP-Success to "
753					   "terminate PEAP resumption");
754				ret->decision = DECISION_COND_SUCC;
755				data->phase2_success = 1;
756			}
757
758			data->resuming = 0;
759		}
760
761		if (res == 2) {
762			/*
763			 * Application data included in the handshake message.
764			 */
765			os_free(data->pending_phase2_req);
766			data->pending_phase2_req = resp;
767			data->pending_phase2_req_len = *respDataLen;
768			resp = NULL;
769			*respDataLen = 0;
770			res = eap_peap_decrypt(sm, data, ret, req, pos, left,
771					       &resp, respDataLen);
772		}
773	}
774
775	if (ret->methodState == METHOD_DONE) {
776		ret->allowNotifications = FALSE;
777	}
778
779	if (res == 1) {
780		return eap_tls_build_ack(&data->ssl, respDataLen, id,
781					 EAP_TYPE_PEAP, data->peap_version);
782	}
783
784	return resp;
785}
786
787
788static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
789{
790	struct eap_peap_data *data = priv;
791	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
792		data->phase2_success;
793}
794
795
796static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
797{
798	struct eap_peap_data *data = priv;
799	os_free(data->pending_phase2_req);
800	data->pending_phase2_req = NULL;
801}
802
803
804static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
805{
806	struct eap_peap_data *data = priv;
807	os_free(data->key_data);
808	data->key_data = NULL;
809	if (eap_tls_reauth_init(sm, &data->ssl)) {
810		os_free(data);
811		return NULL;
812	}
813	if (data->phase2_priv && data->phase2_method &&
814	    data->phase2_method->init_for_reauth)
815		data->phase2_method->init_for_reauth(sm, data->phase2_priv);
816	data->phase2_success = 0;
817	data->phase2_eap_success = 0;
818	data->phase2_eap_started = 0;
819	data->resuming = 1;
820	sm->peap_done = FALSE;
821	return priv;
822}
823
824
825static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
826			       size_t buflen, int verbose)
827{
828	struct eap_peap_data *data = priv;
829	int len, ret;
830
831	len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
832	if (data->phase2_method) {
833		ret = os_snprintf(buf + len, buflen - len,
834				  "EAP-PEAPv%d Phase2 method=%s\n",
835				  data->peap_version,
836				  data->phase2_method->name);
837		if (ret < 0 || (size_t) ret >= buflen - len)
838			return len;
839		len += ret;
840	}
841	return len;
842}
843
844
845static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
846{
847	struct eap_peap_data *data = priv;
848	return data->key_data != NULL && data->phase2_success;
849}
850
851
852static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
853{
854	struct eap_peap_data *data = priv;
855	u8 *key;
856
857	if (data->key_data == NULL || !data->phase2_success)
858		return NULL;
859
860	key = os_malloc(EAP_TLS_KEY_LEN);
861	if (key == NULL)
862		return NULL;
863
864	*len = EAP_TLS_KEY_LEN;
865	os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
866
867	return key;
868}
869
870
871int eap_peer_peap_register(void)
872{
873	struct eap_method *eap;
874	int ret;
875
876	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
877				    EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
878	if (eap == NULL)
879		return -1;
880
881	eap->init = eap_peap_init;
882	eap->deinit = eap_peap_deinit;
883	eap->process = eap_peap_process;
884	eap->isKeyAvailable = eap_peap_isKeyAvailable;
885	eap->getKey = eap_peap_getKey;
886	eap->get_status = eap_peap_get_status;
887	eap->has_reauth_data = eap_peap_has_reauth_data;
888	eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
889	eap->init_for_reauth = eap_peap_init_for_reauth;
890
891	ret = eap_peer_method_register(eap);
892	if (ret)
893		eap_peer_method_free(eap);
894	return ret;
895}
896