xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_peer/eap_peap.c (revision 6d49e1aea1f916afb9e202b8d2ad09cfab6e48c3)
1*6d49e1aeSJan Lentfer /*
2*6d49e1aeSJan Lentfer  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3*6d49e1aeSJan Lentfer  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4*6d49e1aeSJan Lentfer  *
5*6d49e1aeSJan Lentfer  * This program is free software; you can redistribute it and/or modify
6*6d49e1aeSJan Lentfer  * it under the terms of the GNU General Public License version 2 as
7*6d49e1aeSJan Lentfer  * published by the Free Software Foundation.
8*6d49e1aeSJan Lentfer  *
9*6d49e1aeSJan Lentfer  * Alternatively, this software may be distributed under the terms of BSD
10*6d49e1aeSJan Lentfer  * license.
11*6d49e1aeSJan Lentfer  *
12*6d49e1aeSJan Lentfer  * See README and COPYING for more details.
13*6d49e1aeSJan Lentfer  */
14*6d49e1aeSJan Lentfer 
15*6d49e1aeSJan Lentfer #include "includes.h"
16*6d49e1aeSJan Lentfer 
17*6d49e1aeSJan Lentfer #include "common.h"
18*6d49e1aeSJan Lentfer #include "crypto/sha1.h"
19*6d49e1aeSJan Lentfer #include "eap_i.h"
20*6d49e1aeSJan Lentfer #include "eap_tls_common.h"
21*6d49e1aeSJan Lentfer #include "eap_config.h"
22*6d49e1aeSJan Lentfer #include "tls.h"
23*6d49e1aeSJan Lentfer #include "eap_common/eap_tlv_common.h"
24*6d49e1aeSJan Lentfer #include "eap_common/eap_peap_common.h"
25*6d49e1aeSJan Lentfer #include "tncc.h"
26*6d49e1aeSJan Lentfer 
27*6d49e1aeSJan Lentfer 
28*6d49e1aeSJan Lentfer /* Maximum supported PEAP version
29*6d49e1aeSJan Lentfer  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
30*6d49e1aeSJan Lentfer  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
31*6d49e1aeSJan Lentfer  * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
32*6d49e1aeSJan Lentfer  */
33*6d49e1aeSJan Lentfer #define EAP_PEAP_VERSION 1
34*6d49e1aeSJan Lentfer 
35*6d49e1aeSJan Lentfer 
36*6d49e1aeSJan Lentfer static void eap_peap_deinit(struct eap_sm *sm, void *priv);
37*6d49e1aeSJan Lentfer 
38*6d49e1aeSJan Lentfer 
39*6d49e1aeSJan Lentfer struct eap_peap_data {
40*6d49e1aeSJan Lentfer 	struct eap_ssl_data ssl;
41*6d49e1aeSJan Lentfer 
42*6d49e1aeSJan Lentfer 	int peap_version, force_peap_version, force_new_label;
43*6d49e1aeSJan Lentfer 
44*6d49e1aeSJan Lentfer 	const struct eap_method *phase2_method;
45*6d49e1aeSJan Lentfer 	void *phase2_priv;
46*6d49e1aeSJan Lentfer 	int phase2_success;
47*6d49e1aeSJan Lentfer 	int phase2_eap_success;
48*6d49e1aeSJan Lentfer 	int phase2_eap_started;
49*6d49e1aeSJan Lentfer 
50*6d49e1aeSJan Lentfer 	struct eap_method_type phase2_type;
51*6d49e1aeSJan Lentfer 	struct eap_method_type *phase2_types;
52*6d49e1aeSJan Lentfer 	size_t num_phase2_types;
53*6d49e1aeSJan Lentfer 
54*6d49e1aeSJan Lentfer 	int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
55*6d49e1aeSJan Lentfer 				 * EAP-Success
56*6d49e1aeSJan Lentfer 				 * 1 = reply with tunneled EAP-Success to inner
57*6d49e1aeSJan Lentfer 				 * EAP-Success and expect AS to send outer
58*6d49e1aeSJan Lentfer 				 * (unencrypted) EAP-Success after this
59*6d49e1aeSJan Lentfer 				 * 2 = reply with PEAP/TLS ACK to inner
60*6d49e1aeSJan Lentfer 				 * EAP-Success and expect AS to send outer
61*6d49e1aeSJan Lentfer 				 * (unencrypted) EAP-Success after this */
62*6d49e1aeSJan Lentfer 	int resuming; /* starting a resumed session */
63*6d49e1aeSJan Lentfer 	int reauth; /* reauthentication */
64*6d49e1aeSJan Lentfer 	u8 *key_data;
65*6d49e1aeSJan Lentfer 
66*6d49e1aeSJan Lentfer 	struct wpabuf *pending_phase2_req;
67*6d49e1aeSJan Lentfer 	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
68*6d49e1aeSJan Lentfer 	int crypto_binding_used;
69*6d49e1aeSJan Lentfer 	u8 binding_nonce[32];
70*6d49e1aeSJan Lentfer 	u8 ipmk[40];
71*6d49e1aeSJan Lentfer 	u8 cmk[20];
72*6d49e1aeSJan Lentfer 	int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
73*6d49e1aeSJan Lentfer 		  * is enabled. */
74*6d49e1aeSJan Lentfer };
75*6d49e1aeSJan Lentfer 
76*6d49e1aeSJan Lentfer 
77*6d49e1aeSJan Lentfer static int eap_peap_parse_phase1(struct eap_peap_data *data,
78*6d49e1aeSJan Lentfer 				 const char *phase1)
79*6d49e1aeSJan Lentfer {
80*6d49e1aeSJan Lentfer 	const char *pos;
81*6d49e1aeSJan Lentfer 
82*6d49e1aeSJan Lentfer 	pos = os_strstr(phase1, "peapver=");
83*6d49e1aeSJan Lentfer 	if (pos) {
84*6d49e1aeSJan Lentfer 		data->force_peap_version = atoi(pos + 8);
85*6d49e1aeSJan Lentfer 		data->peap_version = data->force_peap_version;
86*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d",
87*6d49e1aeSJan Lentfer 			   data->force_peap_version);
88*6d49e1aeSJan Lentfer 	}
89*6d49e1aeSJan Lentfer 
90*6d49e1aeSJan Lentfer 	if (os_strstr(phase1, "peaplabel=1")) {
91*6d49e1aeSJan Lentfer 		data->force_new_label = 1;
92*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key "
93*6d49e1aeSJan Lentfer 			   "derivation");
94*6d49e1aeSJan Lentfer 	}
95*6d49e1aeSJan Lentfer 
96*6d49e1aeSJan Lentfer 	if (os_strstr(phase1, "peap_outer_success=0")) {
97*6d49e1aeSJan Lentfer 		data->peap_outer_success = 0;
98*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on "
99*6d49e1aeSJan Lentfer 			   "tunneled EAP-Success");
100*6d49e1aeSJan Lentfer 	} else if (os_strstr(phase1, "peap_outer_success=1")) {
101*6d49e1aeSJan Lentfer 		data->peap_outer_success = 1;
102*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success "
103*6d49e1aeSJan Lentfer 			   "after receiving tunneled EAP-Success");
104*6d49e1aeSJan Lentfer 	} else if (os_strstr(phase1, "peap_outer_success=2")) {
105*6d49e1aeSJan Lentfer 		data->peap_outer_success = 2;
106*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after "
107*6d49e1aeSJan Lentfer 			   "receiving tunneled EAP-Success");
108*6d49e1aeSJan Lentfer 	}
109*6d49e1aeSJan Lentfer 
110*6d49e1aeSJan Lentfer 	if (os_strstr(phase1, "crypto_binding=0")) {
111*6d49e1aeSJan Lentfer 		data->crypto_binding = NO_BINDING;
112*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
113*6d49e1aeSJan Lentfer 	} else if (os_strstr(phase1, "crypto_binding=1")) {
114*6d49e1aeSJan Lentfer 		data->crypto_binding = OPTIONAL_BINDING;
115*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
116*6d49e1aeSJan Lentfer 	} else if (os_strstr(phase1, "crypto_binding=2")) {
117*6d49e1aeSJan Lentfer 		data->crypto_binding = REQUIRE_BINDING;
118*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
119*6d49e1aeSJan Lentfer 	}
120*6d49e1aeSJan Lentfer 
121*6d49e1aeSJan Lentfer #ifdef EAP_TNC
122*6d49e1aeSJan Lentfer 	if (os_strstr(phase1, "tnc=soh2")) {
123*6d49e1aeSJan Lentfer 		data->soh = 2;
124*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
125*6d49e1aeSJan Lentfer 	} else if (os_strstr(phase1, "tnc=soh1")) {
126*6d49e1aeSJan Lentfer 		data->soh = 1;
127*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled");
128*6d49e1aeSJan Lentfer 	} else if (os_strstr(phase1, "tnc=soh")) {
129*6d49e1aeSJan Lentfer 		data->soh = 2;
130*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
131*6d49e1aeSJan Lentfer 	}
132*6d49e1aeSJan Lentfer #endif /* EAP_TNC */
133*6d49e1aeSJan Lentfer 
134*6d49e1aeSJan Lentfer 	return 0;
135*6d49e1aeSJan Lentfer }
136*6d49e1aeSJan Lentfer 
137*6d49e1aeSJan Lentfer 
138*6d49e1aeSJan Lentfer static void * eap_peap_init(struct eap_sm *sm)
139*6d49e1aeSJan Lentfer {
140*6d49e1aeSJan Lentfer 	struct eap_peap_data *data;
141*6d49e1aeSJan Lentfer 	struct eap_peer_config *config = eap_get_config(sm);
142*6d49e1aeSJan Lentfer 
143*6d49e1aeSJan Lentfer 	data = os_zalloc(sizeof(*data));
144*6d49e1aeSJan Lentfer 	if (data == NULL)
145*6d49e1aeSJan Lentfer 		return NULL;
146*6d49e1aeSJan Lentfer 	sm->peap_done = FALSE;
147*6d49e1aeSJan Lentfer 	data->peap_version = EAP_PEAP_VERSION;
148*6d49e1aeSJan Lentfer 	data->force_peap_version = -1;
149*6d49e1aeSJan Lentfer 	data->peap_outer_success = 2;
150*6d49e1aeSJan Lentfer 	data->crypto_binding = OPTIONAL_BINDING;
151*6d49e1aeSJan Lentfer 
152*6d49e1aeSJan Lentfer 	if (config && config->phase1 &&
153*6d49e1aeSJan Lentfer 	    eap_peap_parse_phase1(data, config->phase1) < 0) {
154*6d49e1aeSJan Lentfer 		eap_peap_deinit(sm, data);
155*6d49e1aeSJan Lentfer 		return NULL;
156*6d49e1aeSJan Lentfer 	}
157*6d49e1aeSJan Lentfer 
158*6d49e1aeSJan Lentfer 	if (eap_peer_select_phase2_methods(config, "auth=",
159*6d49e1aeSJan Lentfer 					   &data->phase2_types,
160*6d49e1aeSJan Lentfer 					   &data->num_phase2_types) < 0) {
161*6d49e1aeSJan Lentfer 		eap_peap_deinit(sm, data);
162*6d49e1aeSJan Lentfer 		return NULL;
163*6d49e1aeSJan Lentfer 	}
164*6d49e1aeSJan Lentfer 
165*6d49e1aeSJan Lentfer 	data->phase2_type.vendor = EAP_VENDOR_IETF;
166*6d49e1aeSJan Lentfer 	data->phase2_type.method = EAP_TYPE_NONE;
167*6d49e1aeSJan Lentfer 
168*6d49e1aeSJan Lentfer 	if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
169*6d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
170*6d49e1aeSJan Lentfer 		eap_peap_deinit(sm, data);
171*6d49e1aeSJan Lentfer 		return NULL;
172*6d49e1aeSJan Lentfer 	}
173*6d49e1aeSJan Lentfer 
174*6d49e1aeSJan Lentfer 	return data;
175*6d49e1aeSJan Lentfer }
176*6d49e1aeSJan Lentfer 
177*6d49e1aeSJan Lentfer 
178*6d49e1aeSJan Lentfer static void eap_peap_deinit(struct eap_sm *sm, void *priv)
179*6d49e1aeSJan Lentfer {
180*6d49e1aeSJan Lentfer 	struct eap_peap_data *data = priv;
181*6d49e1aeSJan Lentfer 	if (data == NULL)
182*6d49e1aeSJan Lentfer 		return;
183*6d49e1aeSJan Lentfer 	if (data->phase2_priv && data->phase2_method)
184*6d49e1aeSJan Lentfer 		data->phase2_method->deinit(sm, data->phase2_priv);
185*6d49e1aeSJan Lentfer 	os_free(data->phase2_types);
186*6d49e1aeSJan Lentfer 	eap_peer_tls_ssl_deinit(sm, &data->ssl);
187*6d49e1aeSJan Lentfer 	os_free(data->key_data);
188*6d49e1aeSJan Lentfer 	wpabuf_free(data->pending_phase2_req);
189*6d49e1aeSJan Lentfer 	os_free(data);
190*6d49e1aeSJan Lentfer }
191*6d49e1aeSJan Lentfer 
192*6d49e1aeSJan Lentfer 
193*6d49e1aeSJan Lentfer /**
194*6d49e1aeSJan Lentfer  * eap_tlv_build_nak - Build EAP-TLV NAK message
195*6d49e1aeSJan Lentfer  * @id: EAP identifier for the header
196*6d49e1aeSJan Lentfer  * @nak_type: TLV type (EAP_TLV_*)
197*6d49e1aeSJan Lentfer  * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
198*6d49e1aeSJan Lentfer  *
199*6d49e1aeSJan Lentfer  * This funtion builds an EAP-TLV NAK message. The caller is responsible for
200*6d49e1aeSJan Lentfer  * freeing the returned buffer.
201*6d49e1aeSJan Lentfer  */
202*6d49e1aeSJan Lentfer static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
203*6d49e1aeSJan Lentfer {
204*6d49e1aeSJan Lentfer 	struct wpabuf *msg;
205*6d49e1aeSJan Lentfer 
206*6d49e1aeSJan Lentfer 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
207*6d49e1aeSJan Lentfer 			    EAP_CODE_RESPONSE, id);
208*6d49e1aeSJan Lentfer 	if (msg == NULL)
209*6d49e1aeSJan Lentfer 		return NULL;
210*6d49e1aeSJan Lentfer 
211*6d49e1aeSJan Lentfer 	wpabuf_put_u8(msg, 0x80); /* Mandatory */
212*6d49e1aeSJan Lentfer 	wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
213*6d49e1aeSJan Lentfer 	wpabuf_put_be16(msg, 6); /* Length */
214*6d49e1aeSJan Lentfer 	wpabuf_put_be32(msg, 0); /* Vendor-Id */
215*6d49e1aeSJan Lentfer 	wpabuf_put_be16(msg, nak_type); /* NAK-Type */
216*6d49e1aeSJan Lentfer 
217*6d49e1aeSJan Lentfer 	return msg;
218*6d49e1aeSJan Lentfer }
219*6d49e1aeSJan Lentfer 
220*6d49e1aeSJan Lentfer 
221*6d49e1aeSJan Lentfer static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
222*6d49e1aeSJan Lentfer 			    u8 *isk, size_t isk_len)
223*6d49e1aeSJan Lentfer {
224*6d49e1aeSJan Lentfer 	u8 *key;
225*6d49e1aeSJan Lentfer 	size_t key_len;
226*6d49e1aeSJan Lentfer 
227*6d49e1aeSJan Lentfer 	os_memset(isk, 0, isk_len);
228*6d49e1aeSJan Lentfer 	if (data->phase2_method == NULL || data->phase2_priv == NULL ||
229*6d49e1aeSJan Lentfer 	    data->phase2_method->isKeyAvailable == NULL ||
230*6d49e1aeSJan Lentfer 	    data->phase2_method->getKey == NULL)
231*6d49e1aeSJan Lentfer 		return 0;
232*6d49e1aeSJan Lentfer 
233*6d49e1aeSJan Lentfer 	if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
234*6d49e1aeSJan Lentfer 	    (key = data->phase2_method->getKey(sm, data->phase2_priv,
235*6d49e1aeSJan Lentfer 					       &key_len)) == NULL) {
236*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
237*6d49e1aeSJan Lentfer 			   "from Phase 2");
238*6d49e1aeSJan Lentfer 		return -1;
239*6d49e1aeSJan Lentfer 	}
240*6d49e1aeSJan Lentfer 
241*6d49e1aeSJan Lentfer 	if (key_len > isk_len)
242*6d49e1aeSJan Lentfer 		key_len = isk_len;
243*6d49e1aeSJan Lentfer 	os_memcpy(isk, key, key_len);
244*6d49e1aeSJan Lentfer 	os_free(key);
245*6d49e1aeSJan Lentfer 
246*6d49e1aeSJan Lentfer 	return 0;
247*6d49e1aeSJan Lentfer }
248*6d49e1aeSJan Lentfer 
249*6d49e1aeSJan Lentfer 
250*6d49e1aeSJan Lentfer static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
251*6d49e1aeSJan Lentfer {
252*6d49e1aeSJan Lentfer 	u8 *tk;
253*6d49e1aeSJan Lentfer 	u8 isk[32], imck[60];
254*6d49e1aeSJan Lentfer 
255*6d49e1aeSJan Lentfer 	/*
256*6d49e1aeSJan Lentfer 	 * Tunnel key (TK) is the first 60 octets of the key generated by
257*6d49e1aeSJan Lentfer 	 * phase 1 of PEAP (based on TLS).
258*6d49e1aeSJan Lentfer 	 */
259*6d49e1aeSJan Lentfer 	tk = data->key_data;
260*6d49e1aeSJan Lentfer 	if (tk == NULL)
261*6d49e1aeSJan Lentfer 		return -1;
262*6d49e1aeSJan Lentfer 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
263*6d49e1aeSJan Lentfer 
264*6d49e1aeSJan Lentfer 	if (data->reauth &&
265*6d49e1aeSJan Lentfer 	    tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
266*6d49e1aeSJan Lentfer 		/* Fast-connect: IPMK|CMK = TK */
267*6d49e1aeSJan Lentfer 		os_memcpy(data->ipmk, tk, 40);
268*6d49e1aeSJan Lentfer 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
269*6d49e1aeSJan Lentfer 				data->ipmk, 40);
270*6d49e1aeSJan Lentfer 		os_memcpy(data->cmk, tk + 40, 20);
271*6d49e1aeSJan Lentfer 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
272*6d49e1aeSJan Lentfer 				data->cmk, 20);
273*6d49e1aeSJan Lentfer 		return 0;
274*6d49e1aeSJan Lentfer 	}
275*6d49e1aeSJan Lentfer 
276*6d49e1aeSJan Lentfer 	if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
277*6d49e1aeSJan Lentfer 		return -1;
278*6d49e1aeSJan Lentfer 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
279*6d49e1aeSJan Lentfer 
280*6d49e1aeSJan Lentfer 	/*
281*6d49e1aeSJan Lentfer 	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
282*6d49e1aeSJan Lentfer 	 * TempKey = First 40 octets of TK
283*6d49e1aeSJan Lentfer 	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
284*6d49e1aeSJan Lentfer 	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
285*6d49e1aeSJan Lentfer 	 * in the end of the label just before ISK; is that just a typo?)
286*6d49e1aeSJan Lentfer 	 */
287*6d49e1aeSJan Lentfer 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
288*6d49e1aeSJan Lentfer 	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
289*6d49e1aeSJan Lentfer 		     isk, sizeof(isk), imck, sizeof(imck));
290*6d49e1aeSJan Lentfer 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
291*6d49e1aeSJan Lentfer 			imck, sizeof(imck));
292*6d49e1aeSJan Lentfer 
293*6d49e1aeSJan Lentfer 	os_memcpy(data->ipmk, imck, 40);
294*6d49e1aeSJan Lentfer 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
295*6d49e1aeSJan Lentfer 	os_memcpy(data->cmk, imck + 40, 20);
296*6d49e1aeSJan Lentfer 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
297*6d49e1aeSJan Lentfer 
298*6d49e1aeSJan Lentfer 	return 0;
299*6d49e1aeSJan Lentfer }
300*6d49e1aeSJan Lentfer 
301*6d49e1aeSJan Lentfer 
302*6d49e1aeSJan Lentfer static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
303*6d49e1aeSJan Lentfer 				     struct eap_peap_data *data,
304*6d49e1aeSJan Lentfer 				     struct wpabuf *buf)
305*6d49e1aeSJan Lentfer {
306*6d49e1aeSJan Lentfer 	u8 *mac;
307*6d49e1aeSJan Lentfer 	u8 eap_type = EAP_TYPE_PEAP;
308*6d49e1aeSJan Lentfer 	const u8 *addr[2];
309*6d49e1aeSJan Lentfer 	size_t len[2];
310*6d49e1aeSJan Lentfer 	u16 tlv_type;
311*6d49e1aeSJan Lentfer 
312*6d49e1aeSJan Lentfer 	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
313*6d49e1aeSJan Lentfer 	addr[0] = wpabuf_put(buf, 0);
314*6d49e1aeSJan Lentfer 	len[0] = 60;
315*6d49e1aeSJan Lentfer 	addr[1] = &eap_type;
316*6d49e1aeSJan Lentfer 	len[1] = 1;
317*6d49e1aeSJan Lentfer 
318*6d49e1aeSJan Lentfer 	tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
319*6d49e1aeSJan Lentfer 	if (data->peap_version >= 2)
320*6d49e1aeSJan Lentfer 		tlv_type |= EAP_TLV_TYPE_MANDATORY;
321*6d49e1aeSJan Lentfer 	wpabuf_put_be16(buf, tlv_type);
322*6d49e1aeSJan Lentfer 	wpabuf_put_be16(buf, 56);
323*6d49e1aeSJan Lentfer 
324*6d49e1aeSJan Lentfer 	wpabuf_put_u8(buf, 0); /* Reserved */
325*6d49e1aeSJan Lentfer 	wpabuf_put_u8(buf, data->peap_version); /* Version */
326*6d49e1aeSJan Lentfer 	wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
327*6d49e1aeSJan Lentfer 	wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
328*6d49e1aeSJan Lentfer 	wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
329*6d49e1aeSJan Lentfer 	mac = wpabuf_put(buf, 20); /* Compound_MAC */
330*6d49e1aeSJan Lentfer 	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
331*6d49e1aeSJan Lentfer 	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
332*6d49e1aeSJan Lentfer 		    addr[0], len[0]);
333*6d49e1aeSJan Lentfer 	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
334*6d49e1aeSJan Lentfer 		    addr[1], len[1]);
335*6d49e1aeSJan Lentfer 	hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
336*6d49e1aeSJan Lentfer 	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
337*6d49e1aeSJan Lentfer 	data->crypto_binding_used = 1;
338*6d49e1aeSJan Lentfer 
339*6d49e1aeSJan Lentfer 	return 0;
340*6d49e1aeSJan Lentfer }
341*6d49e1aeSJan Lentfer 
342*6d49e1aeSJan Lentfer 
343*6d49e1aeSJan Lentfer /**
344*6d49e1aeSJan Lentfer  * eap_tlv_build_result - Build EAP-TLV Result message
345*6d49e1aeSJan Lentfer  * @id: EAP identifier for the header
346*6d49e1aeSJan Lentfer  * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
347*6d49e1aeSJan Lentfer  * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
348*6d49e1aeSJan Lentfer  *
349*6d49e1aeSJan Lentfer  * This funtion builds an EAP-TLV Result message. The caller is responsible for
350*6d49e1aeSJan Lentfer  * freeing the returned buffer.
351*6d49e1aeSJan Lentfer  */
352*6d49e1aeSJan Lentfer static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
353*6d49e1aeSJan Lentfer 					    struct eap_peap_data *data,
354*6d49e1aeSJan Lentfer 					    int crypto_tlv_used,
355*6d49e1aeSJan Lentfer 					    int id, u16 status)
356*6d49e1aeSJan Lentfer {
357*6d49e1aeSJan Lentfer 	struct wpabuf *msg;
358*6d49e1aeSJan Lentfer 	size_t len;
359*6d49e1aeSJan Lentfer 
360*6d49e1aeSJan Lentfer 	if (data->crypto_binding == NO_BINDING)
361*6d49e1aeSJan Lentfer 		crypto_tlv_used = 0;
362*6d49e1aeSJan Lentfer 
363*6d49e1aeSJan Lentfer 	len = 6;
364*6d49e1aeSJan Lentfer 	if (crypto_tlv_used)
365*6d49e1aeSJan Lentfer 		len += 60; /* Cryptobinding TLV */
366*6d49e1aeSJan Lentfer 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
367*6d49e1aeSJan Lentfer 			    EAP_CODE_RESPONSE, id);
368*6d49e1aeSJan Lentfer 	if (msg == NULL)
369*6d49e1aeSJan Lentfer 		return NULL;
370*6d49e1aeSJan Lentfer 
371*6d49e1aeSJan Lentfer 	wpabuf_put_u8(msg, 0x80); /* Mandatory */
372*6d49e1aeSJan Lentfer 	wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
373*6d49e1aeSJan Lentfer 	wpabuf_put_be16(msg, 2); /* Length */
374*6d49e1aeSJan Lentfer 	wpabuf_put_be16(msg, status); /* Status */
375*6d49e1aeSJan Lentfer 
376*6d49e1aeSJan Lentfer 	if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
377*6d49e1aeSJan Lentfer 		wpabuf_free(msg);
378*6d49e1aeSJan Lentfer 		return NULL;
379*6d49e1aeSJan Lentfer 	}
380*6d49e1aeSJan Lentfer 
381*6d49e1aeSJan Lentfer 	return msg;
382*6d49e1aeSJan Lentfer }
383*6d49e1aeSJan Lentfer 
384*6d49e1aeSJan Lentfer 
385*6d49e1aeSJan Lentfer static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
386*6d49e1aeSJan Lentfer 					  struct eap_peap_data *data,
387*6d49e1aeSJan Lentfer 					  const u8 *crypto_tlv,
388*6d49e1aeSJan Lentfer 					  size_t crypto_tlv_len)
389*6d49e1aeSJan Lentfer {
390*6d49e1aeSJan Lentfer 	u8 buf[61], mac[SHA1_MAC_LEN];
391*6d49e1aeSJan Lentfer 	const u8 *pos;
392*6d49e1aeSJan Lentfer 
393*6d49e1aeSJan Lentfer 	if (eap_peap_derive_cmk(sm, data) < 0) {
394*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
395*6d49e1aeSJan Lentfer 		return -1;
396*6d49e1aeSJan Lentfer 	}
397*6d49e1aeSJan Lentfer 
398*6d49e1aeSJan Lentfer 	if (crypto_tlv_len != 4 + 56) {
399*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
400*6d49e1aeSJan Lentfer 			   "length %d", (int) crypto_tlv_len);
401*6d49e1aeSJan Lentfer 		return -1;
402*6d49e1aeSJan Lentfer 	}
403*6d49e1aeSJan Lentfer 
404*6d49e1aeSJan Lentfer 	pos = crypto_tlv;
405*6d49e1aeSJan Lentfer 	pos += 4; /* TLV header */
406*6d49e1aeSJan Lentfer 	if (pos[1] != data->peap_version) {
407*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
408*6d49e1aeSJan Lentfer 			   "mismatch (was %d; expected %d)",
409*6d49e1aeSJan Lentfer 			   pos[1], data->peap_version);
410*6d49e1aeSJan Lentfer 		return -1;
411*6d49e1aeSJan Lentfer 	}
412*6d49e1aeSJan Lentfer 
413*6d49e1aeSJan Lentfer 	if (pos[3] != 0) {
414*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
415*6d49e1aeSJan Lentfer 			   "SubType %d", pos[3]);
416*6d49e1aeSJan Lentfer 		return -1;
417*6d49e1aeSJan Lentfer 	}
418*6d49e1aeSJan Lentfer 	pos += 4;
419*6d49e1aeSJan Lentfer 	os_memcpy(data->binding_nonce, pos, 32);
420*6d49e1aeSJan Lentfer 	pos += 32; /* Nonce */
421*6d49e1aeSJan Lentfer 
422*6d49e1aeSJan Lentfer 	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
423*6d49e1aeSJan Lentfer 	os_memcpy(buf, crypto_tlv, 60);
424*6d49e1aeSJan Lentfer 	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
425*6d49e1aeSJan Lentfer 	buf[60] = EAP_TYPE_PEAP;
426*6d49e1aeSJan Lentfer 	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
427*6d49e1aeSJan Lentfer 		    buf, sizeof(buf));
428*6d49e1aeSJan Lentfer 	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
429*6d49e1aeSJan Lentfer 
430*6d49e1aeSJan Lentfer 	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
431*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
432*6d49e1aeSJan Lentfer 			   "cryptobinding TLV");
433*6d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
434*6d49e1aeSJan Lentfer 			    pos, SHA1_MAC_LEN);
435*6d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
436*6d49e1aeSJan Lentfer 			    mac, SHA1_MAC_LEN);
437*6d49e1aeSJan Lentfer 		return -1;
438*6d49e1aeSJan Lentfer 	}
439*6d49e1aeSJan Lentfer 
440*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
441*6d49e1aeSJan Lentfer 
442*6d49e1aeSJan Lentfer 	return 0;
443*6d49e1aeSJan Lentfer }
444*6d49e1aeSJan Lentfer 
445*6d49e1aeSJan Lentfer 
446*6d49e1aeSJan Lentfer /**
447*6d49e1aeSJan Lentfer  * eap_tlv_process - Process a received EAP-TLV message and generate a response
448*6d49e1aeSJan Lentfer  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
449*6d49e1aeSJan Lentfer  * @ret: Return values from EAP request validation and processing
450*6d49e1aeSJan Lentfer  * @req: EAP-TLV request to be processed. The caller must have validated that
451*6d49e1aeSJan Lentfer  * the buffer is large enough to contain full request (hdr->length bytes) and
452*6d49e1aeSJan Lentfer  * that the EAP type is EAP_TYPE_TLV.
453*6d49e1aeSJan Lentfer  * @resp: Buffer to return a pointer to the allocated response message. This
454*6d49e1aeSJan Lentfer  * field should be initialized to %NULL before the call. The value will be
455*6d49e1aeSJan Lentfer  * updated if a response message is generated. The caller is responsible for
456*6d49e1aeSJan Lentfer  * freeing the allocated message.
457*6d49e1aeSJan Lentfer  * @force_failure: Force negotiation to fail
458*6d49e1aeSJan Lentfer  * Returns: 0 on success, -1 on failure
459*6d49e1aeSJan Lentfer  */
460*6d49e1aeSJan Lentfer static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
461*6d49e1aeSJan Lentfer 			   struct eap_method_ret *ret,
462*6d49e1aeSJan Lentfer 			   const struct wpabuf *req, struct wpabuf **resp,
463*6d49e1aeSJan Lentfer 			   int force_failure)
464*6d49e1aeSJan Lentfer {
465*6d49e1aeSJan Lentfer 	size_t left, tlv_len;
466*6d49e1aeSJan Lentfer 	const u8 *pos;
467*6d49e1aeSJan Lentfer 	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
468*6d49e1aeSJan Lentfer 	size_t result_tlv_len = 0, crypto_tlv_len = 0;
469*6d49e1aeSJan Lentfer 	int tlv_type, mandatory;
470*6d49e1aeSJan Lentfer 
471*6d49e1aeSJan Lentfer 	/* Parse TLVs */
472*6d49e1aeSJan Lentfer 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
473*6d49e1aeSJan Lentfer 	if (pos == NULL)
474*6d49e1aeSJan Lentfer 		return -1;
475*6d49e1aeSJan Lentfer 	wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
476*6d49e1aeSJan Lentfer 	while (left >= 4) {
477*6d49e1aeSJan Lentfer 		mandatory = !!(pos[0] & 0x80);
478*6d49e1aeSJan Lentfer 		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
479*6d49e1aeSJan Lentfer 		pos += 2;
480*6d49e1aeSJan Lentfer 		tlv_len = WPA_GET_BE16(pos);
481*6d49e1aeSJan Lentfer 		pos += 2;
482*6d49e1aeSJan Lentfer 		left -= 4;
483*6d49e1aeSJan Lentfer 		if (tlv_len > left) {
484*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
485*6d49e1aeSJan Lentfer 				   "(tlv_len=%lu left=%lu)",
486*6d49e1aeSJan Lentfer 				   (unsigned long) tlv_len,
487*6d49e1aeSJan Lentfer 				   (unsigned long) left);
488*6d49e1aeSJan Lentfer 			return -1;
489*6d49e1aeSJan Lentfer 		}
490*6d49e1aeSJan Lentfer 		switch (tlv_type) {
491*6d49e1aeSJan Lentfer 		case EAP_TLV_RESULT_TLV:
492*6d49e1aeSJan Lentfer 			result_tlv = pos;
493*6d49e1aeSJan Lentfer 			result_tlv_len = tlv_len;
494*6d49e1aeSJan Lentfer 			break;
495*6d49e1aeSJan Lentfer 		case EAP_TLV_CRYPTO_BINDING_TLV:
496*6d49e1aeSJan Lentfer 			crypto_tlv = pos;
497*6d49e1aeSJan Lentfer 			crypto_tlv_len = tlv_len;
498*6d49e1aeSJan Lentfer 			break;
499*6d49e1aeSJan Lentfer 		default:
500*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
501*6d49e1aeSJan Lentfer 				   "%d%s", tlv_type,
502*6d49e1aeSJan Lentfer 				   mandatory ? " (mandatory)" : "");
503*6d49e1aeSJan Lentfer 			if (mandatory) {
504*6d49e1aeSJan Lentfer 				/* NAK TLV and ignore all TLVs in this packet.
505*6d49e1aeSJan Lentfer 				 */
506*6d49e1aeSJan Lentfer 				*resp = eap_tlv_build_nak(eap_get_id(req),
507*6d49e1aeSJan Lentfer 							  tlv_type);
508*6d49e1aeSJan Lentfer 				return *resp == NULL ? -1 : 0;
509*6d49e1aeSJan Lentfer 			}
510*6d49e1aeSJan Lentfer 			/* Ignore this TLV, but process other TLVs */
511*6d49e1aeSJan Lentfer 			break;
512*6d49e1aeSJan Lentfer 		}
513*6d49e1aeSJan Lentfer 
514*6d49e1aeSJan Lentfer 		pos += tlv_len;
515*6d49e1aeSJan Lentfer 		left -= tlv_len;
516*6d49e1aeSJan Lentfer 	}
517*6d49e1aeSJan Lentfer 	if (left) {
518*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
519*6d49e1aeSJan Lentfer 			   "Request (left=%lu)", (unsigned long) left);
520*6d49e1aeSJan Lentfer 		return -1;
521*6d49e1aeSJan Lentfer 	}
522*6d49e1aeSJan Lentfer 
523*6d49e1aeSJan Lentfer 	/* Process supported TLVs */
524*6d49e1aeSJan Lentfer 	if (crypto_tlv && data->crypto_binding != NO_BINDING) {
525*6d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
526*6d49e1aeSJan Lentfer 			    crypto_tlv, crypto_tlv_len);
527*6d49e1aeSJan Lentfer 		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
528*6d49e1aeSJan Lentfer 						   crypto_tlv_len + 4) < 0) {
529*6d49e1aeSJan Lentfer 			if (result_tlv == NULL)
530*6d49e1aeSJan Lentfer 				return -1;
531*6d49e1aeSJan Lentfer 			force_failure = 1;
532*6d49e1aeSJan Lentfer 			crypto_tlv = NULL; /* do not include Cryptobinding TLV
533*6d49e1aeSJan Lentfer 					    * in response, if the received
534*6d49e1aeSJan Lentfer 					    * cryptobinding was invalid. */
535*6d49e1aeSJan Lentfer 		}
536*6d49e1aeSJan Lentfer 	} else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
537*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
538*6d49e1aeSJan Lentfer 		return -1;
539*6d49e1aeSJan Lentfer 	}
540*6d49e1aeSJan Lentfer 
541*6d49e1aeSJan Lentfer 	if (result_tlv) {
542*6d49e1aeSJan Lentfer 		int status, resp_status;
543*6d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
544*6d49e1aeSJan Lentfer 			    result_tlv, result_tlv_len);
545*6d49e1aeSJan Lentfer 		if (result_tlv_len < 2) {
546*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
547*6d49e1aeSJan Lentfer 				   "(len=%lu)",
548*6d49e1aeSJan Lentfer 				   (unsigned long) result_tlv_len);
549*6d49e1aeSJan Lentfer 			return -1;
550*6d49e1aeSJan Lentfer 		}
551*6d49e1aeSJan Lentfer 		status = WPA_GET_BE16(result_tlv);
552*6d49e1aeSJan Lentfer 		if (status == EAP_TLV_RESULT_SUCCESS) {
553*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
554*6d49e1aeSJan Lentfer 				   "- EAP-TLV/Phase2 Completed");
555*6d49e1aeSJan Lentfer 			if (force_failure) {
556*6d49e1aeSJan Lentfer 				wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
557*6d49e1aeSJan Lentfer 					   " - force failed Phase 2");
558*6d49e1aeSJan Lentfer 				resp_status = EAP_TLV_RESULT_FAILURE;
559*6d49e1aeSJan Lentfer 				ret->decision = DECISION_FAIL;
560*6d49e1aeSJan Lentfer 			} else {
561*6d49e1aeSJan Lentfer 				resp_status = EAP_TLV_RESULT_SUCCESS;
562*6d49e1aeSJan Lentfer 				ret->decision = DECISION_UNCOND_SUCC;
563*6d49e1aeSJan Lentfer 			}
564*6d49e1aeSJan Lentfer 		} else if (status == EAP_TLV_RESULT_FAILURE) {
565*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
566*6d49e1aeSJan Lentfer 			resp_status = EAP_TLV_RESULT_FAILURE;
567*6d49e1aeSJan Lentfer 			ret->decision = DECISION_FAIL;
568*6d49e1aeSJan Lentfer 		} else {
569*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
570*6d49e1aeSJan Lentfer 				   "Status %d", status);
571*6d49e1aeSJan Lentfer 			resp_status = EAP_TLV_RESULT_FAILURE;
572*6d49e1aeSJan Lentfer 			ret->decision = DECISION_FAIL;
573*6d49e1aeSJan Lentfer 		}
574*6d49e1aeSJan Lentfer 		ret->methodState = METHOD_DONE;
575*6d49e1aeSJan Lentfer 
576*6d49e1aeSJan Lentfer 		*resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
577*6d49e1aeSJan Lentfer 					     eap_get_id(req), resp_status);
578*6d49e1aeSJan Lentfer 	}
579*6d49e1aeSJan Lentfer 
580*6d49e1aeSJan Lentfer 	return 0;
581*6d49e1aeSJan Lentfer }
582*6d49e1aeSJan Lentfer 
583*6d49e1aeSJan Lentfer 
584*6d49e1aeSJan Lentfer static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
585*6d49e1aeSJan Lentfer {
586*6d49e1aeSJan Lentfer 	struct wpabuf *e;
587*6d49e1aeSJan Lentfer 	struct eap_tlv_hdr *tlv;
588*6d49e1aeSJan Lentfer 
589*6d49e1aeSJan Lentfer 	if (buf == NULL)
590*6d49e1aeSJan Lentfer 		return NULL;
591*6d49e1aeSJan Lentfer 
592*6d49e1aeSJan Lentfer 	/* Encapsulate EAP packet in EAP-Payload TLV */
593*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
594*6d49e1aeSJan Lentfer 	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
595*6d49e1aeSJan Lentfer 	if (e == NULL) {
596*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
597*6d49e1aeSJan Lentfer 			   "for TLV encapsulation");
598*6d49e1aeSJan Lentfer 		wpabuf_free(buf);
599*6d49e1aeSJan Lentfer 		return NULL;
600*6d49e1aeSJan Lentfer 	}
601*6d49e1aeSJan Lentfer 	tlv = wpabuf_put(e, sizeof(*tlv));
602*6d49e1aeSJan Lentfer 	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
603*6d49e1aeSJan Lentfer 				     EAP_TLV_EAP_PAYLOAD_TLV);
604*6d49e1aeSJan Lentfer 	tlv->length = host_to_be16(wpabuf_len(buf));
605*6d49e1aeSJan Lentfer 	wpabuf_put_buf(e, buf);
606*6d49e1aeSJan Lentfer 	wpabuf_free(buf);
607*6d49e1aeSJan Lentfer 	return e;
608*6d49e1aeSJan Lentfer }
609*6d49e1aeSJan Lentfer 
610*6d49e1aeSJan Lentfer 
611*6d49e1aeSJan Lentfer static int eap_peap_phase2_request(struct eap_sm *sm,
612*6d49e1aeSJan Lentfer 				   struct eap_peap_data *data,
613*6d49e1aeSJan Lentfer 				   struct eap_method_ret *ret,
614*6d49e1aeSJan Lentfer 				   struct wpabuf *req,
615*6d49e1aeSJan Lentfer 				   struct wpabuf **resp)
616*6d49e1aeSJan Lentfer {
617*6d49e1aeSJan Lentfer 	struct eap_hdr *hdr = wpabuf_mhead(req);
618*6d49e1aeSJan Lentfer 	size_t len = be_to_host16(hdr->length);
619*6d49e1aeSJan Lentfer 	u8 *pos;
620*6d49e1aeSJan Lentfer 	struct eap_method_ret iret;
621*6d49e1aeSJan Lentfer 	struct eap_peer_config *config = eap_get_config(sm);
622*6d49e1aeSJan Lentfer 
623*6d49e1aeSJan Lentfer 	if (len <= sizeof(struct eap_hdr)) {
624*6d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
625*6d49e1aeSJan Lentfer 			   "Phase 2 request (len=%lu)", (unsigned long) len);
626*6d49e1aeSJan Lentfer 		return -1;
627*6d49e1aeSJan Lentfer 	}
628*6d49e1aeSJan Lentfer 	pos = (u8 *) (hdr + 1);
629*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
630*6d49e1aeSJan Lentfer 	switch (*pos) {
631*6d49e1aeSJan Lentfer 	case EAP_TYPE_IDENTITY:
632*6d49e1aeSJan Lentfer 		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
633*6d49e1aeSJan Lentfer 		break;
634*6d49e1aeSJan Lentfer 	case EAP_TYPE_TLV:
635*6d49e1aeSJan Lentfer 		os_memset(&iret, 0, sizeof(iret));
636*6d49e1aeSJan Lentfer 		if (eap_tlv_process(sm, data, &iret, req, resp,
637*6d49e1aeSJan Lentfer 				    data->phase2_eap_started &&
638*6d49e1aeSJan Lentfer 				    !data->phase2_eap_success)) {
639*6d49e1aeSJan Lentfer 			ret->methodState = METHOD_DONE;
640*6d49e1aeSJan Lentfer 			ret->decision = DECISION_FAIL;
641*6d49e1aeSJan Lentfer 			return -1;
642*6d49e1aeSJan Lentfer 		}
643*6d49e1aeSJan Lentfer 		if (iret.methodState == METHOD_DONE ||
644*6d49e1aeSJan Lentfer 		    iret.methodState == METHOD_MAY_CONT) {
645*6d49e1aeSJan Lentfer 			ret->methodState = iret.methodState;
646*6d49e1aeSJan Lentfer 			ret->decision = iret.decision;
647*6d49e1aeSJan Lentfer 			data->phase2_success = 1;
648*6d49e1aeSJan Lentfer 		}
649*6d49e1aeSJan Lentfer 		break;
650*6d49e1aeSJan Lentfer 	case EAP_TYPE_EXPANDED:
651*6d49e1aeSJan Lentfer #ifdef EAP_TNC
652*6d49e1aeSJan Lentfer 		if (data->soh) {
653*6d49e1aeSJan Lentfer 			const u8 *epos;
654*6d49e1aeSJan Lentfer 			size_t eleft;
655*6d49e1aeSJan Lentfer 
656*6d49e1aeSJan Lentfer 			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
657*6d49e1aeSJan Lentfer 						req, &eleft);
658*6d49e1aeSJan Lentfer 			if (epos) {
659*6d49e1aeSJan Lentfer 				struct wpabuf *buf;
660*6d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG,
661*6d49e1aeSJan Lentfer 					   "EAP-PEAP: SoH EAP Extensions");
662*6d49e1aeSJan Lentfer 				buf = tncc_process_soh_request(data->soh,
663*6d49e1aeSJan Lentfer 							       epos, eleft);
664*6d49e1aeSJan Lentfer 				if (buf) {
665*6d49e1aeSJan Lentfer 					*resp = eap_msg_alloc(
666*6d49e1aeSJan Lentfer 						EAP_VENDOR_MICROSOFT, 0x21,
667*6d49e1aeSJan Lentfer 						wpabuf_len(buf),
668*6d49e1aeSJan Lentfer 						EAP_CODE_RESPONSE,
669*6d49e1aeSJan Lentfer 						hdr->identifier);
670*6d49e1aeSJan Lentfer 					if (*resp == NULL) {
671*6d49e1aeSJan Lentfer 						ret->methodState = METHOD_DONE;
672*6d49e1aeSJan Lentfer 						ret->decision = DECISION_FAIL;
673*6d49e1aeSJan Lentfer 						return -1;
674*6d49e1aeSJan Lentfer 					}
675*6d49e1aeSJan Lentfer 					wpabuf_put_buf(*resp, buf);
676*6d49e1aeSJan Lentfer 					wpabuf_free(buf);
677*6d49e1aeSJan Lentfer 					break;
678*6d49e1aeSJan Lentfer 				}
679*6d49e1aeSJan Lentfer 			}
680*6d49e1aeSJan Lentfer 		}
681*6d49e1aeSJan Lentfer #endif /* EAP_TNC */
682*6d49e1aeSJan Lentfer 		/* fall through */
683*6d49e1aeSJan Lentfer 	default:
684*6d49e1aeSJan Lentfer 		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
685*6d49e1aeSJan Lentfer 		    data->phase2_type.method == EAP_TYPE_NONE) {
686*6d49e1aeSJan Lentfer 			size_t i;
687*6d49e1aeSJan Lentfer 			for (i = 0; i < data->num_phase2_types; i++) {
688*6d49e1aeSJan Lentfer 				if (data->phase2_types[i].vendor !=
689*6d49e1aeSJan Lentfer 				    EAP_VENDOR_IETF ||
690*6d49e1aeSJan Lentfer 				    data->phase2_types[i].method != *pos)
691*6d49e1aeSJan Lentfer 					continue;
692*6d49e1aeSJan Lentfer 
693*6d49e1aeSJan Lentfer 				data->phase2_type.vendor =
694*6d49e1aeSJan Lentfer 					data->phase2_types[i].vendor;
695*6d49e1aeSJan Lentfer 				data->phase2_type.method =
696*6d49e1aeSJan Lentfer 					data->phase2_types[i].method;
697*6d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
698*6d49e1aeSJan Lentfer 					   "Phase 2 EAP vendor %d method %d",
699*6d49e1aeSJan Lentfer 					   data->phase2_type.vendor,
700*6d49e1aeSJan Lentfer 					   data->phase2_type.method);
701*6d49e1aeSJan Lentfer 				break;
702*6d49e1aeSJan Lentfer 			}
703*6d49e1aeSJan Lentfer 		}
704*6d49e1aeSJan Lentfer 		if (*pos != data->phase2_type.method ||
705*6d49e1aeSJan Lentfer 		    *pos == EAP_TYPE_NONE) {
706*6d49e1aeSJan Lentfer 			if (eap_peer_tls_phase2_nak(data->phase2_types,
707*6d49e1aeSJan Lentfer 						    data->num_phase2_types,
708*6d49e1aeSJan Lentfer 						    hdr, resp))
709*6d49e1aeSJan Lentfer 				return -1;
710*6d49e1aeSJan Lentfer 			return 0;
711*6d49e1aeSJan Lentfer 		}
712*6d49e1aeSJan Lentfer 
713*6d49e1aeSJan Lentfer 		if (data->phase2_priv == NULL) {
714*6d49e1aeSJan Lentfer 			data->phase2_method = eap_peer_get_eap_method(
715*6d49e1aeSJan Lentfer 				data->phase2_type.vendor,
716*6d49e1aeSJan Lentfer 				data->phase2_type.method);
717*6d49e1aeSJan Lentfer 			if (data->phase2_method) {
718*6d49e1aeSJan Lentfer 				sm->init_phase2 = 1;
719*6d49e1aeSJan Lentfer 				data->phase2_priv =
720*6d49e1aeSJan Lentfer 					data->phase2_method->init(sm);
721*6d49e1aeSJan Lentfer 				sm->init_phase2 = 0;
722*6d49e1aeSJan Lentfer 			}
723*6d49e1aeSJan Lentfer 		}
724*6d49e1aeSJan Lentfer 		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
725*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
726*6d49e1aeSJan Lentfer 				   "Phase 2 EAP method %d", *pos);
727*6d49e1aeSJan Lentfer 			ret->methodState = METHOD_DONE;
728*6d49e1aeSJan Lentfer 			ret->decision = DECISION_FAIL;
729*6d49e1aeSJan Lentfer 			return -1;
730*6d49e1aeSJan Lentfer 		}
731*6d49e1aeSJan Lentfer 		data->phase2_eap_started = 1;
732*6d49e1aeSJan Lentfer 		os_memset(&iret, 0, sizeof(iret));
733*6d49e1aeSJan Lentfer 		*resp = data->phase2_method->process(sm, data->phase2_priv,
734*6d49e1aeSJan Lentfer 						     &iret, req);
735*6d49e1aeSJan Lentfer 		if ((iret.methodState == METHOD_DONE ||
736*6d49e1aeSJan Lentfer 		     iret.methodState == METHOD_MAY_CONT) &&
737*6d49e1aeSJan Lentfer 		    (iret.decision == DECISION_UNCOND_SUCC ||
738*6d49e1aeSJan Lentfer 		     iret.decision == DECISION_COND_SUCC)) {
739*6d49e1aeSJan Lentfer 			data->phase2_eap_success = 1;
740*6d49e1aeSJan Lentfer 			data->phase2_success = 1;
741*6d49e1aeSJan Lentfer 		}
742*6d49e1aeSJan Lentfer 		break;
743*6d49e1aeSJan Lentfer 	}
744*6d49e1aeSJan Lentfer 
745*6d49e1aeSJan Lentfer 	if (*resp == NULL &&
746*6d49e1aeSJan Lentfer 	    (config->pending_req_identity || config->pending_req_password ||
747*6d49e1aeSJan Lentfer 	     config->pending_req_otp || config->pending_req_new_password)) {
748*6d49e1aeSJan Lentfer 		wpabuf_free(data->pending_phase2_req);
749*6d49e1aeSJan Lentfer 		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
750*6d49e1aeSJan Lentfer 	}
751*6d49e1aeSJan Lentfer 
752*6d49e1aeSJan Lentfer 	return 0;
753*6d49e1aeSJan Lentfer }
754*6d49e1aeSJan Lentfer 
755*6d49e1aeSJan Lentfer 
756*6d49e1aeSJan Lentfer static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
757*6d49e1aeSJan Lentfer 			    struct eap_method_ret *ret,
758*6d49e1aeSJan Lentfer 			    const struct eap_hdr *req,
759*6d49e1aeSJan Lentfer 			    const struct wpabuf *in_data,
760*6d49e1aeSJan Lentfer 			    struct wpabuf **out_data)
761*6d49e1aeSJan Lentfer {
762*6d49e1aeSJan Lentfer 	struct wpabuf *in_decrypted = NULL;
763*6d49e1aeSJan Lentfer 	int res, skip_change = 0;
764*6d49e1aeSJan Lentfer 	struct eap_hdr *hdr, *rhdr;
765*6d49e1aeSJan Lentfer 	struct wpabuf *resp = NULL;
766*6d49e1aeSJan Lentfer 	size_t len;
767*6d49e1aeSJan Lentfer 
768*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
769*6d49e1aeSJan Lentfer 		   " Phase 2", (unsigned long) wpabuf_len(in_data));
770*6d49e1aeSJan Lentfer 
771*6d49e1aeSJan Lentfer 	if (data->pending_phase2_req) {
772*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
773*6d49e1aeSJan Lentfer 			   "skip decryption and use old data");
774*6d49e1aeSJan Lentfer 		/* Clear TLS reassembly state. */
775*6d49e1aeSJan Lentfer 		eap_peer_tls_reset_input(&data->ssl);
776*6d49e1aeSJan Lentfer 		in_decrypted = data->pending_phase2_req;
777*6d49e1aeSJan Lentfer 		data->pending_phase2_req = NULL;
778*6d49e1aeSJan Lentfer 		skip_change = 1;
779*6d49e1aeSJan Lentfer 		goto continue_req;
780*6d49e1aeSJan Lentfer 	}
781*6d49e1aeSJan Lentfer 
782*6d49e1aeSJan Lentfer 	if (wpabuf_len(in_data) == 0 && sm->workaround &&
783*6d49e1aeSJan Lentfer 	    data->phase2_success) {
784*6d49e1aeSJan Lentfer 		/*
785*6d49e1aeSJan Lentfer 		 * Cisco ACS seems to be using TLS ACK to terminate
786*6d49e1aeSJan Lentfer 		 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
787*6d49e1aeSJan Lentfer 		 */
788*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
789*6d49e1aeSJan Lentfer 			   "expected data - acknowledge with TLS ACK since "
790*6d49e1aeSJan Lentfer 			   "Phase 2 has been completed");
791*6d49e1aeSJan Lentfer 		ret->decision = DECISION_COND_SUCC;
792*6d49e1aeSJan Lentfer 		ret->methodState = METHOD_DONE;
793*6d49e1aeSJan Lentfer 		return 1;
794*6d49e1aeSJan Lentfer 	} else if (wpabuf_len(in_data) == 0) {
795*6d49e1aeSJan Lentfer 		/* Received TLS ACK - requesting more fragments */
796*6d49e1aeSJan Lentfer 		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
797*6d49e1aeSJan Lentfer 					    data->peap_version,
798*6d49e1aeSJan Lentfer 					    req->identifier, NULL, out_data);
799*6d49e1aeSJan Lentfer 	}
800*6d49e1aeSJan Lentfer 
801*6d49e1aeSJan Lentfer 	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
802*6d49e1aeSJan Lentfer 	if (res)
803*6d49e1aeSJan Lentfer 		return res;
804*6d49e1aeSJan Lentfer 
805*6d49e1aeSJan Lentfer continue_req:
806*6d49e1aeSJan Lentfer 	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
807*6d49e1aeSJan Lentfer 			in_decrypted);
808*6d49e1aeSJan Lentfer 
809*6d49e1aeSJan Lentfer 	hdr = wpabuf_mhead(in_decrypted);
810*6d49e1aeSJan Lentfer 	if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
811*6d49e1aeSJan Lentfer 	    be_to_host16(hdr->length) == 5 &&
812*6d49e1aeSJan Lentfer 	    eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
813*6d49e1aeSJan Lentfer 		/* At least FreeRADIUS seems to send full EAP header with
814*6d49e1aeSJan Lentfer 		 * EAP Request Identity */
815*6d49e1aeSJan Lentfer 		skip_change = 1;
816*6d49e1aeSJan Lentfer 	}
817*6d49e1aeSJan Lentfer 	if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
818*6d49e1aeSJan Lentfer 	    eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
819*6d49e1aeSJan Lentfer 		skip_change = 1;
820*6d49e1aeSJan Lentfer 	}
821*6d49e1aeSJan Lentfer 
822*6d49e1aeSJan Lentfer 	if (data->peap_version == 0 && !skip_change) {
823*6d49e1aeSJan Lentfer 		struct eap_hdr *nhdr;
824*6d49e1aeSJan Lentfer 		struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
825*6d49e1aeSJan Lentfer 						   wpabuf_len(in_decrypted));
826*6d49e1aeSJan Lentfer 		if (nmsg == NULL) {
827*6d49e1aeSJan Lentfer 			wpabuf_free(in_decrypted);
828*6d49e1aeSJan Lentfer 			return 0;
829*6d49e1aeSJan Lentfer 		}
830*6d49e1aeSJan Lentfer 		nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
831*6d49e1aeSJan Lentfer 		wpabuf_put_buf(nmsg, in_decrypted);
832*6d49e1aeSJan Lentfer 		nhdr->code = req->code;
833*6d49e1aeSJan Lentfer 		nhdr->identifier = req->identifier;
834*6d49e1aeSJan Lentfer 		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
835*6d49e1aeSJan Lentfer 					    wpabuf_len(in_decrypted));
836*6d49e1aeSJan Lentfer 
837*6d49e1aeSJan Lentfer 		wpabuf_free(in_decrypted);
838*6d49e1aeSJan Lentfer 		in_decrypted = nmsg;
839*6d49e1aeSJan Lentfer 	}
840*6d49e1aeSJan Lentfer 
841*6d49e1aeSJan Lentfer 	if (data->peap_version >= 2) {
842*6d49e1aeSJan Lentfer 		struct eap_tlv_hdr *tlv;
843*6d49e1aeSJan Lentfer 		struct wpabuf *nmsg;
844*6d49e1aeSJan Lentfer 
845*6d49e1aeSJan Lentfer 		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
846*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
847*6d49e1aeSJan Lentfer 				   "EAP TLV");
848*6d49e1aeSJan Lentfer 			wpabuf_free(in_decrypted);
849*6d49e1aeSJan Lentfer 			return 0;
850*6d49e1aeSJan Lentfer 		}
851*6d49e1aeSJan Lentfer 		tlv = wpabuf_mhead(in_decrypted);
852*6d49e1aeSJan Lentfer 		if ((be_to_host16(tlv->tlv_type) & 0x3fff) !=
853*6d49e1aeSJan Lentfer 		    EAP_TLV_EAP_PAYLOAD_TLV) {
854*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
855*6d49e1aeSJan Lentfer 			wpabuf_free(in_decrypted);
856*6d49e1aeSJan Lentfer 			return 0;
857*6d49e1aeSJan Lentfer 		}
858*6d49e1aeSJan Lentfer 		if (sizeof(*tlv) + be_to_host16(tlv->length) >
859*6d49e1aeSJan Lentfer 		    wpabuf_len(in_decrypted)) {
860*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
861*6d49e1aeSJan Lentfer 				   "length");
862*6d49e1aeSJan Lentfer 			wpabuf_free(in_decrypted);
863*6d49e1aeSJan Lentfer 			return 0;
864*6d49e1aeSJan Lentfer 		}
865*6d49e1aeSJan Lentfer 		hdr = (struct eap_hdr *) (tlv + 1);
866*6d49e1aeSJan Lentfer 		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
867*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
868*6d49e1aeSJan Lentfer 				   "EAP packet in EAP TLV");
869*6d49e1aeSJan Lentfer 			wpabuf_free(in_decrypted);
870*6d49e1aeSJan Lentfer 			return 0;
871*6d49e1aeSJan Lentfer 		}
872*6d49e1aeSJan Lentfer 
873*6d49e1aeSJan Lentfer 		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
874*6d49e1aeSJan Lentfer 		if (nmsg == NULL) {
875*6d49e1aeSJan Lentfer 			wpabuf_free(in_decrypted);
876*6d49e1aeSJan Lentfer 			return 0;
877*6d49e1aeSJan Lentfer 		}
878*6d49e1aeSJan Lentfer 
879*6d49e1aeSJan Lentfer 		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
880*6d49e1aeSJan Lentfer 		wpabuf_free(in_decrypted);
881*6d49e1aeSJan Lentfer 		in_decrypted = nmsg;
882*6d49e1aeSJan Lentfer 	}
883*6d49e1aeSJan Lentfer 
884*6d49e1aeSJan Lentfer 	hdr = wpabuf_mhead(in_decrypted);
885*6d49e1aeSJan Lentfer 	if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
886*6d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
887*6d49e1aeSJan Lentfer 			   "EAP frame (len=%lu)",
888*6d49e1aeSJan Lentfer 			   (unsigned long) wpabuf_len(in_decrypted));
889*6d49e1aeSJan Lentfer 		wpabuf_free(in_decrypted);
890*6d49e1aeSJan Lentfer 		return 0;
891*6d49e1aeSJan Lentfer 	}
892*6d49e1aeSJan Lentfer 	len = be_to_host16(hdr->length);
893*6d49e1aeSJan Lentfer 	if (len > wpabuf_len(in_decrypted)) {
894*6d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
895*6d49e1aeSJan Lentfer 			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
896*6d49e1aeSJan Lentfer 			   (unsigned long) wpabuf_len(in_decrypted),
897*6d49e1aeSJan Lentfer 			   (unsigned long) len);
898*6d49e1aeSJan Lentfer 		wpabuf_free(in_decrypted);
899*6d49e1aeSJan Lentfer 		return 0;
900*6d49e1aeSJan Lentfer 	}
901*6d49e1aeSJan Lentfer 	if (len < wpabuf_len(in_decrypted)) {
902*6d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
903*6d49e1aeSJan Lentfer 			   "shorter length than full decrypted data "
904*6d49e1aeSJan Lentfer 			   "(%lu < %lu)",
905*6d49e1aeSJan Lentfer 			   (unsigned long) len,
906*6d49e1aeSJan Lentfer 			   (unsigned long) wpabuf_len(in_decrypted));
907*6d49e1aeSJan Lentfer 	}
908*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
909*6d49e1aeSJan Lentfer 		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
910*6d49e1aeSJan Lentfer 		   (unsigned long) len);
911*6d49e1aeSJan Lentfer 	switch (hdr->code) {
912*6d49e1aeSJan Lentfer 	case EAP_CODE_REQUEST:
913*6d49e1aeSJan Lentfer 		if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
914*6d49e1aeSJan Lentfer 					    &resp)) {
915*6d49e1aeSJan Lentfer 			wpabuf_free(in_decrypted);
916*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
917*6d49e1aeSJan Lentfer 				   "processing failed");
918*6d49e1aeSJan Lentfer 			return 0;
919*6d49e1aeSJan Lentfer 		}
920*6d49e1aeSJan Lentfer 		break;
921*6d49e1aeSJan Lentfer 	case EAP_CODE_SUCCESS:
922*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
923*6d49e1aeSJan Lentfer 		if (data->peap_version == 1) {
924*6d49e1aeSJan Lentfer 			/* EAP-Success within TLS tunnel is used to indicate
925*6d49e1aeSJan Lentfer 			 * shutdown of the TLS channel. The authentication has
926*6d49e1aeSJan Lentfer 			 * been completed. */
927*6d49e1aeSJan Lentfer 			if (data->phase2_eap_started &&
928*6d49e1aeSJan Lentfer 			    !data->phase2_eap_success) {
929*6d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
930*6d49e1aeSJan Lentfer 					   "Success used to indicate success, "
931*6d49e1aeSJan Lentfer 					   "but Phase 2 EAP was not yet "
932*6d49e1aeSJan Lentfer 					   "completed successfully");
933*6d49e1aeSJan Lentfer 				ret->methodState = METHOD_DONE;
934*6d49e1aeSJan Lentfer 				ret->decision = DECISION_FAIL;
935*6d49e1aeSJan Lentfer 				wpabuf_free(in_decrypted);
936*6d49e1aeSJan Lentfer 				return 0;
937*6d49e1aeSJan Lentfer 			}
938*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
939*6d49e1aeSJan Lentfer 				   "EAP-Success within TLS tunnel - "
940*6d49e1aeSJan Lentfer 				   "authentication completed");
941*6d49e1aeSJan Lentfer 			ret->decision = DECISION_UNCOND_SUCC;
942*6d49e1aeSJan Lentfer 			ret->methodState = METHOD_DONE;
943*6d49e1aeSJan Lentfer 			data->phase2_success = 1;
944*6d49e1aeSJan Lentfer 			if (data->peap_outer_success == 2) {
945*6d49e1aeSJan Lentfer 				wpabuf_free(in_decrypted);
946*6d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
947*6d49e1aeSJan Lentfer 					   "to finish authentication");
948*6d49e1aeSJan Lentfer 				return 1;
949*6d49e1aeSJan Lentfer 			} else if (data->peap_outer_success == 1) {
950*6d49e1aeSJan Lentfer 				/* Reply with EAP-Success within the TLS
951*6d49e1aeSJan Lentfer 				 * channel to complete the authentication. */
952*6d49e1aeSJan Lentfer 				resp = wpabuf_alloc(sizeof(struct eap_hdr));
953*6d49e1aeSJan Lentfer 				if (resp) {
954*6d49e1aeSJan Lentfer 					rhdr = wpabuf_put(resp, sizeof(*rhdr));
955*6d49e1aeSJan Lentfer 					rhdr->code = EAP_CODE_SUCCESS;
956*6d49e1aeSJan Lentfer 					rhdr->identifier = hdr->identifier;
957*6d49e1aeSJan Lentfer 					rhdr->length =
958*6d49e1aeSJan Lentfer 						host_to_be16(sizeof(*rhdr));
959*6d49e1aeSJan Lentfer 				}
960*6d49e1aeSJan Lentfer 			} else {
961*6d49e1aeSJan Lentfer 				/* No EAP-Success expected for Phase 1 (outer,
962*6d49e1aeSJan Lentfer 				 * unencrypted auth), so force EAP state
963*6d49e1aeSJan Lentfer 				 * machine to SUCCESS state. */
964*6d49e1aeSJan Lentfer 				sm->peap_done = TRUE;
965*6d49e1aeSJan Lentfer 			}
966*6d49e1aeSJan Lentfer 		} else {
967*6d49e1aeSJan Lentfer 			/* FIX: ? */
968*6d49e1aeSJan Lentfer 		}
969*6d49e1aeSJan Lentfer 		break;
970*6d49e1aeSJan Lentfer 	case EAP_CODE_FAILURE:
971*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
972*6d49e1aeSJan Lentfer 		ret->decision = DECISION_FAIL;
973*6d49e1aeSJan Lentfer 		ret->methodState = METHOD_MAY_CONT;
974*6d49e1aeSJan Lentfer 		ret->allowNotifications = FALSE;
975*6d49e1aeSJan Lentfer 		/* Reply with EAP-Failure within the TLS channel to complete
976*6d49e1aeSJan Lentfer 		 * failure reporting. */
977*6d49e1aeSJan Lentfer 		resp = wpabuf_alloc(sizeof(struct eap_hdr));
978*6d49e1aeSJan Lentfer 		if (resp) {
979*6d49e1aeSJan Lentfer 			rhdr = wpabuf_put(resp, sizeof(*rhdr));
980*6d49e1aeSJan Lentfer 			rhdr->code = EAP_CODE_FAILURE;
981*6d49e1aeSJan Lentfer 			rhdr->identifier = hdr->identifier;
982*6d49e1aeSJan Lentfer 			rhdr->length = host_to_be16(sizeof(*rhdr));
983*6d49e1aeSJan Lentfer 		}
984*6d49e1aeSJan Lentfer 		break;
985*6d49e1aeSJan Lentfer 	default:
986*6d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
987*6d49e1aeSJan Lentfer 			   "Phase 2 EAP header", hdr->code);
988*6d49e1aeSJan Lentfer 		break;
989*6d49e1aeSJan Lentfer 	}
990*6d49e1aeSJan Lentfer 
991*6d49e1aeSJan Lentfer 	wpabuf_free(in_decrypted);
992*6d49e1aeSJan Lentfer 
993*6d49e1aeSJan Lentfer 	if (resp) {
994*6d49e1aeSJan Lentfer 		int skip_change2 = 0;
995*6d49e1aeSJan Lentfer 		struct wpabuf *rmsg, buf;
996*6d49e1aeSJan Lentfer 
997*6d49e1aeSJan Lentfer 		wpa_hexdump_buf_key(MSG_DEBUG,
998*6d49e1aeSJan Lentfer 				    "EAP-PEAP: Encrypting Phase 2 data", resp);
999*6d49e1aeSJan Lentfer 		/* PEAP version changes */
1000*6d49e1aeSJan Lentfer 		if (data->peap_version >= 2) {
1001*6d49e1aeSJan Lentfer 			resp = eap_peapv2_tlv_eap_payload(resp);
1002*6d49e1aeSJan Lentfer 			if (resp == NULL)
1003*6d49e1aeSJan Lentfer 				return -1;
1004*6d49e1aeSJan Lentfer 		}
1005*6d49e1aeSJan Lentfer 		if (wpabuf_len(resp) >= 5 &&
1006*6d49e1aeSJan Lentfer 		    wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
1007*6d49e1aeSJan Lentfer 		    eap_get_type(resp) == EAP_TYPE_TLV)
1008*6d49e1aeSJan Lentfer 			skip_change2 = 1;
1009*6d49e1aeSJan Lentfer 		rmsg = resp;
1010*6d49e1aeSJan Lentfer 		if (data->peap_version == 0 && !skip_change2) {
1011*6d49e1aeSJan Lentfer 			wpabuf_set(&buf, wpabuf_head_u8(resp) +
1012*6d49e1aeSJan Lentfer 				   sizeof(struct eap_hdr),
1013*6d49e1aeSJan Lentfer 				   wpabuf_len(resp) - sizeof(struct eap_hdr));
1014*6d49e1aeSJan Lentfer 			rmsg = &buf;
1015*6d49e1aeSJan Lentfer 		}
1016*6d49e1aeSJan Lentfer 
1017*6d49e1aeSJan Lentfer 		if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
1018*6d49e1aeSJan Lentfer 					 data->peap_version, req->identifier,
1019*6d49e1aeSJan Lentfer 					 rmsg, out_data)) {
1020*6d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
1021*6d49e1aeSJan Lentfer 				   "a Phase 2 frame");
1022*6d49e1aeSJan Lentfer 		}
1023*6d49e1aeSJan Lentfer 		wpabuf_free(resp);
1024*6d49e1aeSJan Lentfer 	}
1025*6d49e1aeSJan Lentfer 
1026*6d49e1aeSJan Lentfer 	return 0;
1027*6d49e1aeSJan Lentfer }
1028*6d49e1aeSJan Lentfer 
1029*6d49e1aeSJan Lentfer 
1030*6d49e1aeSJan Lentfer static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
1031*6d49e1aeSJan Lentfer 					struct eap_method_ret *ret,
1032*6d49e1aeSJan Lentfer 					const struct wpabuf *reqData)
1033*6d49e1aeSJan Lentfer {
1034*6d49e1aeSJan Lentfer 	const struct eap_hdr *req;
1035*6d49e1aeSJan Lentfer 	size_t left;
1036*6d49e1aeSJan Lentfer 	int res;
1037*6d49e1aeSJan Lentfer 	u8 flags, id;
1038*6d49e1aeSJan Lentfer 	struct wpabuf *resp;
1039*6d49e1aeSJan Lentfer 	const u8 *pos;
1040*6d49e1aeSJan Lentfer 	struct eap_peap_data *data = priv;
1041*6d49e1aeSJan Lentfer 
1042*6d49e1aeSJan Lentfer 	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
1043*6d49e1aeSJan Lentfer 					reqData, &left, &flags);
1044*6d49e1aeSJan Lentfer 	if (pos == NULL)
1045*6d49e1aeSJan Lentfer 		return NULL;
1046*6d49e1aeSJan Lentfer 	req = wpabuf_head(reqData);
1047*6d49e1aeSJan Lentfer 	id = req->identifier;
1048*6d49e1aeSJan Lentfer 
1049*6d49e1aeSJan Lentfer 	if (flags & EAP_TLS_FLAGS_START) {
1050*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
1051*6d49e1aeSJan Lentfer 			   "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
1052*6d49e1aeSJan Lentfer 			data->peap_version);
1053*6d49e1aeSJan Lentfer 		if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version)
1054*6d49e1aeSJan Lentfer 			data->peap_version = flags & EAP_PEAP_VERSION_MASK;
1055*6d49e1aeSJan Lentfer 		if (data->force_peap_version >= 0 &&
1056*6d49e1aeSJan Lentfer 		    data->force_peap_version != data->peap_version) {
1057*6d49e1aeSJan Lentfer 			wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
1058*6d49e1aeSJan Lentfer 				   "forced PEAP version %d",
1059*6d49e1aeSJan Lentfer 				   data->force_peap_version);
1060*6d49e1aeSJan Lentfer 			ret->methodState = METHOD_DONE;
1061*6d49e1aeSJan Lentfer 			ret->decision = DECISION_FAIL;
1062*6d49e1aeSJan Lentfer 			ret->allowNotifications = FALSE;
1063*6d49e1aeSJan Lentfer 			return NULL;
1064*6d49e1aeSJan Lentfer 		}
1065*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
1066*6d49e1aeSJan Lentfer 			   data->peap_version);
1067*6d49e1aeSJan Lentfer 		left = 0; /* make sure that this frame is empty, even though it
1068*6d49e1aeSJan Lentfer 			   * should always be, anyway */
1069*6d49e1aeSJan Lentfer 	}
1070*6d49e1aeSJan Lentfer 
1071*6d49e1aeSJan Lentfer 	resp = NULL;
1072*6d49e1aeSJan Lentfer 	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1073*6d49e1aeSJan Lentfer 	    !data->resuming) {
1074*6d49e1aeSJan Lentfer 		struct wpabuf msg;
1075*6d49e1aeSJan Lentfer 		wpabuf_set(&msg, pos, left);
1076*6d49e1aeSJan Lentfer 		res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
1077*6d49e1aeSJan Lentfer 	} else {
1078*6d49e1aeSJan Lentfer 		res = eap_peer_tls_process_helper(sm, &data->ssl,
1079*6d49e1aeSJan Lentfer 						  EAP_TYPE_PEAP,
1080*6d49e1aeSJan Lentfer 						  data->peap_version, id, pos,
1081*6d49e1aeSJan Lentfer 						  left, &resp);
1082*6d49e1aeSJan Lentfer 
1083*6d49e1aeSJan Lentfer 		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
1084*6d49e1aeSJan Lentfer 			char *label;
1085*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG,
1086*6d49e1aeSJan Lentfer 				   "EAP-PEAP: TLS done, proceed to Phase 2");
1087*6d49e1aeSJan Lentfer 			os_free(data->key_data);
1088*6d49e1aeSJan Lentfer 			/* draft-josefsson-ppext-eap-tls-eap-05.txt
1089*6d49e1aeSJan Lentfer 			 * specifies that PEAPv1 would use "client PEAP
1090*6d49e1aeSJan Lentfer 			 * encryption" as the label. However, most existing
1091*6d49e1aeSJan Lentfer 			 * PEAPv1 implementations seem to be using the old
1092*6d49e1aeSJan Lentfer 			 * label, "client EAP encryption", instead. Use the old
1093*6d49e1aeSJan Lentfer 			 * label by default, but allow it to be configured with
1094*6d49e1aeSJan Lentfer 			 * phase1 parameter peaplabel=1. */
1095*6d49e1aeSJan Lentfer 			if (data->peap_version > 1 || data->force_new_label)
1096*6d49e1aeSJan Lentfer 				label = "client PEAP encryption";
1097*6d49e1aeSJan Lentfer 			else
1098*6d49e1aeSJan Lentfer 				label = "client EAP encryption";
1099*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
1100*6d49e1aeSJan Lentfer 				   "key derivation", label);
1101*6d49e1aeSJan Lentfer 			data->key_data =
1102*6d49e1aeSJan Lentfer 				eap_peer_tls_derive_key(sm, &data->ssl, label,
1103*6d49e1aeSJan Lentfer 							EAP_TLS_KEY_LEN);
1104*6d49e1aeSJan Lentfer 			if (data->key_data) {
1105*6d49e1aeSJan Lentfer 				wpa_hexdump_key(MSG_DEBUG,
1106*6d49e1aeSJan Lentfer 						"EAP-PEAP: Derived key",
1107*6d49e1aeSJan Lentfer 						data->key_data,
1108*6d49e1aeSJan Lentfer 						EAP_TLS_KEY_LEN);
1109*6d49e1aeSJan Lentfer 			} else {
1110*6d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
1111*6d49e1aeSJan Lentfer 					   "derive key");
1112*6d49e1aeSJan Lentfer 			}
1113*6d49e1aeSJan Lentfer 
1114*6d49e1aeSJan Lentfer 			if (sm->workaround && data->resuming) {
1115*6d49e1aeSJan Lentfer 				/*
1116*6d49e1aeSJan Lentfer 				 * At least few RADIUS servers (Aegis v1.1.6;
1117*6d49e1aeSJan Lentfer 				 * but not v1.1.4; and Cisco ACS) seem to be
1118*6d49e1aeSJan Lentfer 				 * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
1119*6d49e1aeSJan Lentfer 				 * ACS) session resumption with outer
1120*6d49e1aeSJan Lentfer 				 * EAP-Success. This does not seem to follow
1121*6d49e1aeSJan Lentfer 				 * draft-josefsson-pppext-eap-tls-eap-05.txt
1122*6d49e1aeSJan Lentfer 				 * section 4.2, so only allow this if EAP
1123*6d49e1aeSJan Lentfer 				 * workarounds are enabled.
1124*6d49e1aeSJan Lentfer 				 */
1125*6d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
1126*6d49e1aeSJan Lentfer 					   "allow outer EAP-Success to "
1127*6d49e1aeSJan Lentfer 					   "terminate PEAP resumption");
1128*6d49e1aeSJan Lentfer 				ret->decision = DECISION_COND_SUCC;
1129*6d49e1aeSJan Lentfer 				data->phase2_success = 1;
1130*6d49e1aeSJan Lentfer 			}
1131*6d49e1aeSJan Lentfer 
1132*6d49e1aeSJan Lentfer 			data->resuming = 0;
1133*6d49e1aeSJan Lentfer 		}
1134*6d49e1aeSJan Lentfer 
1135*6d49e1aeSJan Lentfer 		if (res == 2) {
1136*6d49e1aeSJan Lentfer 			struct wpabuf msg;
1137*6d49e1aeSJan Lentfer 			/*
1138*6d49e1aeSJan Lentfer 			 * Application data included in the handshake message.
1139*6d49e1aeSJan Lentfer 			 */
1140*6d49e1aeSJan Lentfer 			wpabuf_free(data->pending_phase2_req);
1141*6d49e1aeSJan Lentfer 			data->pending_phase2_req = resp;
1142*6d49e1aeSJan Lentfer 			resp = NULL;
1143*6d49e1aeSJan Lentfer 			wpabuf_set(&msg, pos, left);
1144*6d49e1aeSJan Lentfer 			res = eap_peap_decrypt(sm, data, ret, req, &msg,
1145*6d49e1aeSJan Lentfer 					       &resp);
1146*6d49e1aeSJan Lentfer 		}
1147*6d49e1aeSJan Lentfer 	}
1148*6d49e1aeSJan Lentfer 
1149*6d49e1aeSJan Lentfer 	if (ret->methodState == METHOD_DONE) {
1150*6d49e1aeSJan Lentfer 		ret->allowNotifications = FALSE;
1151*6d49e1aeSJan Lentfer 	}
1152*6d49e1aeSJan Lentfer 
1153*6d49e1aeSJan Lentfer 	if (res == 1) {
1154*6d49e1aeSJan Lentfer 		wpabuf_free(resp);
1155*6d49e1aeSJan Lentfer 		return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
1156*6d49e1aeSJan Lentfer 					      data->peap_version);
1157*6d49e1aeSJan Lentfer 	}
1158*6d49e1aeSJan Lentfer 
1159*6d49e1aeSJan Lentfer 	return resp;
1160*6d49e1aeSJan Lentfer }
1161*6d49e1aeSJan Lentfer 
1162*6d49e1aeSJan Lentfer 
1163*6d49e1aeSJan Lentfer static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
1164*6d49e1aeSJan Lentfer {
1165*6d49e1aeSJan Lentfer 	struct eap_peap_data *data = priv;
1166*6d49e1aeSJan Lentfer 	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1167*6d49e1aeSJan Lentfer 		data->phase2_success;
1168*6d49e1aeSJan Lentfer }
1169*6d49e1aeSJan Lentfer 
1170*6d49e1aeSJan Lentfer 
1171*6d49e1aeSJan Lentfer static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
1172*6d49e1aeSJan Lentfer {
1173*6d49e1aeSJan Lentfer 	struct eap_peap_data *data = priv;
1174*6d49e1aeSJan Lentfer 	wpabuf_free(data->pending_phase2_req);
1175*6d49e1aeSJan Lentfer 	data->pending_phase2_req = NULL;
1176*6d49e1aeSJan Lentfer 	data->crypto_binding_used = 0;
1177*6d49e1aeSJan Lentfer }
1178*6d49e1aeSJan Lentfer 
1179*6d49e1aeSJan Lentfer 
1180*6d49e1aeSJan Lentfer static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
1181*6d49e1aeSJan Lentfer {
1182*6d49e1aeSJan Lentfer 	struct eap_peap_data *data = priv;
1183*6d49e1aeSJan Lentfer 	os_free(data->key_data);
1184*6d49e1aeSJan Lentfer 	data->key_data = NULL;
1185*6d49e1aeSJan Lentfer 	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
1186*6d49e1aeSJan Lentfer 		os_free(data);
1187*6d49e1aeSJan Lentfer 		return NULL;
1188*6d49e1aeSJan Lentfer 	}
1189*6d49e1aeSJan Lentfer 	if (data->phase2_priv && data->phase2_method &&
1190*6d49e1aeSJan Lentfer 	    data->phase2_method->init_for_reauth)
1191*6d49e1aeSJan Lentfer 		data->phase2_method->init_for_reauth(sm, data->phase2_priv);
1192*6d49e1aeSJan Lentfer 	data->phase2_success = 0;
1193*6d49e1aeSJan Lentfer 	data->phase2_eap_success = 0;
1194*6d49e1aeSJan Lentfer 	data->phase2_eap_started = 0;
1195*6d49e1aeSJan Lentfer 	data->resuming = 1;
1196*6d49e1aeSJan Lentfer 	data->reauth = 1;
1197*6d49e1aeSJan Lentfer 	sm->peap_done = FALSE;
1198*6d49e1aeSJan Lentfer 	return priv;
1199*6d49e1aeSJan Lentfer }
1200*6d49e1aeSJan Lentfer 
1201*6d49e1aeSJan Lentfer 
1202*6d49e1aeSJan Lentfer static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
1203*6d49e1aeSJan Lentfer 			       size_t buflen, int verbose)
1204*6d49e1aeSJan Lentfer {
1205*6d49e1aeSJan Lentfer 	struct eap_peap_data *data = priv;
1206*6d49e1aeSJan Lentfer 	int len, ret;
1207*6d49e1aeSJan Lentfer 
1208*6d49e1aeSJan Lentfer 	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
1209*6d49e1aeSJan Lentfer 	if (data->phase2_method) {
1210*6d49e1aeSJan Lentfer 		ret = os_snprintf(buf + len, buflen - len,
1211*6d49e1aeSJan Lentfer 				  "EAP-PEAPv%d Phase2 method=%s\n",
1212*6d49e1aeSJan Lentfer 				  data->peap_version,
1213*6d49e1aeSJan Lentfer 				  data->phase2_method->name);
1214*6d49e1aeSJan Lentfer 		if (ret < 0 || (size_t) ret >= buflen - len)
1215*6d49e1aeSJan Lentfer 			return len;
1216*6d49e1aeSJan Lentfer 		len += ret;
1217*6d49e1aeSJan Lentfer 	}
1218*6d49e1aeSJan Lentfer 	return len;
1219*6d49e1aeSJan Lentfer }
1220*6d49e1aeSJan Lentfer 
1221*6d49e1aeSJan Lentfer 
1222*6d49e1aeSJan Lentfer static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
1223*6d49e1aeSJan Lentfer {
1224*6d49e1aeSJan Lentfer 	struct eap_peap_data *data = priv;
1225*6d49e1aeSJan Lentfer 	return data->key_data != NULL && data->phase2_success;
1226*6d49e1aeSJan Lentfer }
1227*6d49e1aeSJan Lentfer 
1228*6d49e1aeSJan Lentfer 
1229*6d49e1aeSJan Lentfer static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
1230*6d49e1aeSJan Lentfer {
1231*6d49e1aeSJan Lentfer 	struct eap_peap_data *data = priv;
1232*6d49e1aeSJan Lentfer 	u8 *key;
1233*6d49e1aeSJan Lentfer 
1234*6d49e1aeSJan Lentfer 	if (data->key_data == NULL || !data->phase2_success)
1235*6d49e1aeSJan Lentfer 		return NULL;
1236*6d49e1aeSJan Lentfer 
1237*6d49e1aeSJan Lentfer 	key = os_malloc(EAP_TLS_KEY_LEN);
1238*6d49e1aeSJan Lentfer 	if (key == NULL)
1239*6d49e1aeSJan Lentfer 		return NULL;
1240*6d49e1aeSJan Lentfer 
1241*6d49e1aeSJan Lentfer 	*len = EAP_TLS_KEY_LEN;
1242*6d49e1aeSJan Lentfer 
1243*6d49e1aeSJan Lentfer 	if (data->crypto_binding_used) {
1244*6d49e1aeSJan Lentfer 		u8 csk[128];
1245*6d49e1aeSJan Lentfer 		/*
1246*6d49e1aeSJan Lentfer 		 * Note: It looks like Microsoft implementation requires null
1247*6d49e1aeSJan Lentfer 		 * termination for this label while the one used for deriving
1248*6d49e1aeSJan Lentfer 		 * IPMK|CMK did not use null termination.
1249*6d49e1aeSJan Lentfer 		 */
1250*6d49e1aeSJan Lentfer 		peap_prfplus(data->peap_version, data->ipmk, 40,
1251*6d49e1aeSJan Lentfer 			     "Session Key Generating Function",
1252*6d49e1aeSJan Lentfer 			     (u8 *) "\00", 1, csk, sizeof(csk));
1253*6d49e1aeSJan Lentfer 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
1254*6d49e1aeSJan Lentfer 		os_memcpy(key, csk, EAP_TLS_KEY_LEN);
1255*6d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1256*6d49e1aeSJan Lentfer 			    key, EAP_TLS_KEY_LEN);
1257*6d49e1aeSJan Lentfer 	} else
1258*6d49e1aeSJan Lentfer 		os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
1259*6d49e1aeSJan Lentfer 
1260*6d49e1aeSJan Lentfer 	return key;
1261*6d49e1aeSJan Lentfer }
1262*6d49e1aeSJan Lentfer 
1263*6d49e1aeSJan Lentfer 
1264*6d49e1aeSJan Lentfer int eap_peer_peap_register(void)
1265*6d49e1aeSJan Lentfer {
1266*6d49e1aeSJan Lentfer 	struct eap_method *eap;
1267*6d49e1aeSJan Lentfer 	int ret;
1268*6d49e1aeSJan Lentfer 
1269*6d49e1aeSJan Lentfer 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1270*6d49e1aeSJan Lentfer 				    EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
1271*6d49e1aeSJan Lentfer 	if (eap == NULL)
1272*6d49e1aeSJan Lentfer 		return -1;
1273*6d49e1aeSJan Lentfer 
1274*6d49e1aeSJan Lentfer 	eap->init = eap_peap_init;
1275*6d49e1aeSJan Lentfer 	eap->deinit = eap_peap_deinit;
1276*6d49e1aeSJan Lentfer 	eap->process = eap_peap_process;
1277*6d49e1aeSJan Lentfer 	eap->isKeyAvailable = eap_peap_isKeyAvailable;
1278*6d49e1aeSJan Lentfer 	eap->getKey = eap_peap_getKey;
1279*6d49e1aeSJan Lentfer 	eap->get_status = eap_peap_get_status;
1280*6d49e1aeSJan Lentfer 	eap->has_reauth_data = eap_peap_has_reauth_data;
1281*6d49e1aeSJan Lentfer 	eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
1282*6d49e1aeSJan Lentfer 	eap->init_for_reauth = eap_peap_init_for_reauth;
1283*6d49e1aeSJan Lentfer 
1284*6d49e1aeSJan Lentfer 	ret = eap_peer_method_register(eap);
1285*6d49e1aeSJan Lentfer 	if (ret)
1286*6d49e1aeSJan Lentfer 		eap_peer_method_free(eap);
1287*6d49e1aeSJan Lentfer 	return ret;
1288*6d49e1aeSJan Lentfer }
1289