1/*
2 * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "crypto/sha1.h"
13#include "crypto/tls.h"
14#include "crypto/random.h"
15#include "eap_i.h"
16#include "eap_tls_common.h"
17#include "eap_common/eap_tlv_common.h"
18#include "eap_common/eap_peap_common.h"
19#include "tncs.h"
20
21
22/* Maximum supported PEAP version
23 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
24 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
25 */
26#define EAP_PEAP_VERSION 1
27
28
29static void eap_peap_reset(struct eap_sm *sm, void *priv);
30
31
32struct eap_peap_data {
33	struct eap_ssl_data ssl;
34	enum {
35		START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
36		PHASE2_METHOD, PHASE2_SOH,
37		PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
38	} state;
39
40	int peap_version;
41	int recv_version;
42	const struct eap_method *phase2_method;
43	void *phase2_priv;
44	int force_version;
45	struct wpabuf *pending_phase2_resp;
46	enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
47	int crypto_binding_sent;
48	int crypto_binding_used;
49	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
50	u8 binding_nonce[32];
51	u8 ipmk[40];
52	u8 cmk[20];
53	u8 *phase2_key;
54	size_t phase2_key_len;
55	struct wpabuf *soh_response;
56};
57
58
59static const char * eap_peap_state_txt(int state)
60{
61	switch (state) {
62	case START:
63		return "START";
64	case PHASE1:
65		return "PHASE1";
66	case PHASE1_ID2:
67		return "PHASE1_ID2";
68	case PHASE2_START:
69		return "PHASE2_START";
70	case PHASE2_ID:
71		return "PHASE2_ID";
72	case PHASE2_METHOD:
73		return "PHASE2_METHOD";
74	case PHASE2_SOH:
75		return "PHASE2_SOH";
76	case PHASE2_TLV:
77		return "PHASE2_TLV";
78	case SUCCESS_REQ:
79		return "SUCCESS_REQ";
80	case FAILURE_REQ:
81		return "FAILURE_REQ";
82	case SUCCESS:
83		return "SUCCESS";
84	case FAILURE:
85		return "FAILURE";
86	default:
87		return "Unknown?!";
88	}
89}
90
91
92static void eap_peap_state(struct eap_peap_data *data, int state)
93{
94	wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
95		   eap_peap_state_txt(data->state),
96		   eap_peap_state_txt(state));
97	data->state = state;
98	if (state == FAILURE || state == FAILURE_REQ)
99		tls_connection_remove_session(data->ssl.conn);
100}
101
102
103static void eap_peap_valid_session(struct eap_sm *sm,
104				   struct eap_peap_data *data)
105{
106	struct wpabuf *buf;
107
108	if (!sm->tls_session_lifetime ||
109	    tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
110		return;
111
112	buf = wpabuf_alloc(1 + 1 + sm->identity_len);
113	if (!buf)
114		return;
115	wpabuf_put_u8(buf, EAP_TYPE_PEAP);
116	if (sm->identity) {
117		u8 id_len;
118
119		if (sm->identity_len <= 255)
120			id_len = sm->identity_len;
121		else
122			id_len = 255;
123		wpabuf_put_u8(buf, id_len);
124		wpabuf_put_data(buf, sm->identity, id_len);
125	} else {
126		wpabuf_put_u8(buf, 0);
127	}
128	tls_connection_set_success_data(data->ssl.conn, buf);
129}
130
131
132static void eap_peap_req_success(struct eap_sm *sm,
133				 struct eap_peap_data *data)
134{
135	if (data->state == FAILURE || data->state == FAILURE_REQ) {
136		eap_peap_state(data, FAILURE);
137		return;
138	}
139
140	if (data->peap_version == 0) {
141		data->tlv_request = TLV_REQ_SUCCESS;
142		eap_peap_state(data, PHASE2_TLV);
143	} else {
144		eap_peap_state(data, SUCCESS_REQ);
145	}
146}
147
148
149static void eap_peap_req_failure(struct eap_sm *sm,
150				 struct eap_peap_data *data)
151{
152	if (data->state == FAILURE || data->state == FAILURE_REQ ||
153	    data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
154		eap_peap_state(data, FAILURE);
155		return;
156	}
157
158	if (data->peap_version == 0) {
159		data->tlv_request = TLV_REQ_FAILURE;
160		eap_peap_state(data, PHASE2_TLV);
161	} else {
162		eap_peap_state(data, FAILURE_REQ);
163	}
164}
165
166
167static void * eap_peap_init(struct eap_sm *sm)
168{
169	struct eap_peap_data *data;
170
171	data = os_zalloc(sizeof(*data));
172	if (data == NULL)
173		return NULL;
174	data->peap_version = EAP_PEAP_VERSION;
175	data->force_version = -1;
176	if (sm->user && sm->user->force_version >= 0) {
177		data->force_version = sm->user->force_version;
178		wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
179			   data->force_version);
180		data->peap_version = data->force_version;
181	}
182	data->state = START;
183	data->crypto_binding = OPTIONAL_BINDING;
184
185	if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_PEAP)) {
186		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
187		eap_peap_reset(sm, data);
188		return NULL;
189	}
190
191	return data;
192}
193
194
195static void eap_peap_reset(struct eap_sm *sm, void *priv)
196{
197	struct eap_peap_data *data = priv;
198	if (data == NULL)
199		return;
200	if (data->phase2_priv && data->phase2_method)
201		data->phase2_method->reset(sm, data->phase2_priv);
202	eap_server_tls_ssl_deinit(sm, &data->ssl);
203	wpabuf_free(data->pending_phase2_resp);
204	os_free(data->phase2_key);
205	wpabuf_free(data->soh_response);
206	bin_clear_free(data, sizeof(*data));
207}
208
209
210static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
211					    struct eap_peap_data *data, u8 id)
212{
213	struct wpabuf *req;
214
215	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
216			    EAP_CODE_REQUEST, id);
217	if (req == NULL) {
218		wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
219			   " request");
220		eap_peap_state(data, FAILURE);
221		return NULL;
222	}
223
224	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
225
226	eap_peap_state(data, PHASE1);
227
228	return req;
229}
230
231
232static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
233						 struct eap_peap_data *data,
234						 u8 id)
235{
236	struct wpabuf *buf, *encr_req, msgbuf;
237	const u8 *req;
238	size_t req_len;
239
240	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
241		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
242		return NULL;
243	}
244	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
245	if (buf == NULL)
246		return NULL;
247
248	req = wpabuf_head(buf);
249	req_len = wpabuf_len(buf);
250	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
251			req, req_len);
252
253	if (data->peap_version == 0 &&
254	    data->phase2_method->method != EAP_TYPE_TLV) {
255		req += sizeof(struct eap_hdr);
256		req_len -= sizeof(struct eap_hdr);
257	}
258
259	wpabuf_set(&msgbuf, req, req_len);
260	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
261	wpabuf_free(buf);
262
263	return encr_req;
264}
265
266
267#ifdef EAP_SERVER_TNC
268static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
269						 struct eap_peap_data *data,
270						 u8 id)
271{
272	struct wpabuf *buf1, *buf, *encr_req, msgbuf;
273	const u8 *req;
274	size_t req_len;
275
276	buf1 = tncs_build_soh_request();
277	if (buf1 == NULL)
278		return NULL;
279
280	buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
281			    EAP_CODE_REQUEST, id);
282	if (buf == NULL) {
283		wpabuf_free(buf1);
284		return NULL;
285	}
286	wpabuf_put_buf(buf, buf1);
287	wpabuf_free(buf1);
288
289	req = wpabuf_head(buf);
290	req_len = wpabuf_len(buf);
291
292	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
293			req, req_len);
294
295	req += sizeof(struct eap_hdr);
296	req_len -= sizeof(struct eap_hdr);
297	wpabuf_set(&msgbuf, req, req_len);
298
299	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
300	wpabuf_free(buf);
301
302	return encr_req;
303}
304#endif /* EAP_SERVER_TNC */
305
306
307static void eap_peap_get_isk(struct eap_peap_data *data,
308			     u8 *isk, size_t isk_len)
309{
310	size_t key_len;
311
312	os_memset(isk, 0, isk_len);
313	if (data->phase2_key == NULL)
314		return;
315
316	key_len = data->phase2_key_len;
317	if (key_len > isk_len)
318		key_len = isk_len;
319	os_memcpy(isk, data->phase2_key, key_len);
320}
321
322
323static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
324{
325	u8 *tk;
326	u8 isk[32], imck[60];
327
328	/*
329	 * Tunnel key (TK) is the first 60 octets of the key generated by
330	 * phase 1 of PEAP (based on TLS).
331	 */
332	tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
333				       EAP_TLS_KEY_LEN);
334	if (tk == NULL)
335		return -1;
336	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
337
338	if (tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
339		/* Fast-connect: IPMK|CMK = TK */
340		os_memcpy(data->ipmk, tk, 40);
341		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
342				data->ipmk, 40);
343		os_memcpy(data->cmk, tk + 40, 20);
344		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
345				data->cmk, 20);
346		os_free(tk);
347		return 0;
348	}
349
350	eap_peap_get_isk(data, isk, sizeof(isk));
351	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
352
353	/*
354	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
355	 * TempKey = First 40 octets of TK
356	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
357	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
358	 * in the end of the label just before ISK; is that just a typo?)
359	 */
360	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
361	if (peap_prfplus(data->peap_version, tk, 40,
362			 "Inner Methods Compound Keys",
363			 isk, sizeof(isk), imck, sizeof(imck)) < 0) {
364		os_free(tk);
365		return -1;
366	}
367	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
368			imck, sizeof(imck));
369
370	os_free(tk);
371
372	os_memcpy(data->ipmk, imck, 40);
373	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
374	os_memcpy(data->cmk, imck + 40, 20);
375	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
376
377	return 0;
378}
379
380
381static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
382						 struct eap_peap_data *data,
383						 u8 id)
384{
385	struct wpabuf *buf, *encr_req;
386	size_t mlen;
387
388	mlen = 6; /* Result TLV */
389	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
390	    data->crypto_binding != NO_BINDING) {
391		mlen += 60; /* Cryptobinding TLV */
392#ifdef EAP_SERVER_TNC
393		if (data->soh_response)
394			mlen += wpabuf_len(data->soh_response);
395#endif /* EAP_SERVER_TNC */
396	}
397
398	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
399			    EAP_CODE_REQUEST, id);
400	if (buf == NULL)
401		return NULL;
402
403	wpabuf_put_u8(buf, 0x80); /* Mandatory */
404	wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
405	/* Length */
406	wpabuf_put_be16(buf, 2);
407	/* Status */
408	wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
409			EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
410
411	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
412	    data->crypto_binding != NO_BINDING) {
413		u8 *mac;
414		u8 eap_type = EAP_TYPE_PEAP;
415		const u8 *addr[2];
416		size_t len[2];
417		u16 tlv_type;
418
419#ifdef EAP_SERVER_TNC
420		if (data->soh_response) {
421			wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
422				   "Response TLV");
423			wpabuf_put_buf(buf, data->soh_response);
424			wpabuf_free(data->soh_response);
425			data->soh_response = NULL;
426		}
427#endif /* EAP_SERVER_TNC */
428
429		if (eap_peap_derive_cmk(sm, data) < 0 ||
430		    random_get_bytes(data->binding_nonce, 32)) {
431			wpabuf_free(buf);
432			return NULL;
433		}
434
435		/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
436		addr[0] = wpabuf_put(buf, 0);
437		len[0] = 60;
438		addr[1] = &eap_type;
439		len[1] = 1;
440
441		tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
442		wpabuf_put_be16(buf, tlv_type);
443		wpabuf_put_be16(buf, 56);
444
445		wpabuf_put_u8(buf, 0); /* Reserved */
446		wpabuf_put_u8(buf, data->peap_version); /* Version */
447		wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
448		wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
449		wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
450		mac = wpabuf_put(buf, 20); /* Compound_MAC */
451		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
452			    data->cmk, 20);
453		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
454			    addr[0], len[0]);
455		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
456			    addr[1], len[1]);
457		hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
458		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
459			    mac, SHA1_MAC_LEN);
460		data->crypto_binding_sent = 1;
461	}
462
463	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
464			    buf);
465
466	encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
467	wpabuf_free(buf);
468
469	return encr_req;
470}
471
472
473static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
474						  struct eap_peap_data *data,
475						  u8 id, int success)
476{
477	struct wpabuf *encr_req, msgbuf;
478	size_t req_len;
479	struct eap_hdr *hdr;
480
481	req_len = sizeof(*hdr);
482	hdr = os_zalloc(req_len);
483	if (hdr == NULL)
484		return NULL;
485
486	hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
487	hdr->identifier = id;
488	hdr->length = host_to_be16(req_len);
489
490	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
491			(u8 *) hdr, req_len);
492
493	wpabuf_set(&msgbuf, hdr, req_len);
494	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
495	os_free(hdr);
496
497	return encr_req;
498}
499
500
501static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
502{
503	struct eap_peap_data *data = priv;
504
505	if (data->ssl.state == FRAG_ACK) {
506		return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
507						data->peap_version);
508	}
509
510	if (data->ssl.state == WAIT_FRAG_ACK) {
511		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
512						data->peap_version, id);
513	}
514
515	switch (data->state) {
516	case START:
517		return eap_peap_build_start(sm, data, id);
518	case PHASE1:
519	case PHASE1_ID2:
520		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
521			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
522				   "starting Phase2");
523			eap_peap_state(data, PHASE2_START);
524		}
525		break;
526	case PHASE2_ID:
527	case PHASE2_METHOD:
528		wpabuf_free(data->ssl.tls_out);
529		data->ssl.tls_out_pos = 0;
530		data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
531		break;
532#ifdef EAP_SERVER_TNC
533	case PHASE2_SOH:
534		wpabuf_free(data->ssl.tls_out);
535		data->ssl.tls_out_pos = 0;
536		data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id);
537		break;
538#endif /* EAP_SERVER_TNC */
539	case PHASE2_TLV:
540		wpabuf_free(data->ssl.tls_out);
541		data->ssl.tls_out_pos = 0;
542		data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
543		break;
544	case SUCCESS_REQ:
545		wpabuf_free(data->ssl.tls_out);
546		data->ssl.tls_out_pos = 0;
547		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
548							       1);
549		break;
550	case FAILURE_REQ:
551		wpabuf_free(data->ssl.tls_out);
552		data->ssl.tls_out_pos = 0;
553		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
554							       0);
555		break;
556	default:
557		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
558			   __func__, data->state);
559		return NULL;
560	}
561
562	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
563					data->peap_version, id);
564}
565
566
567static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
568			      struct wpabuf *respData)
569{
570	const u8 *pos;
571	size_t len;
572
573	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
574	if (pos == NULL || len < 1) {
575		wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
576		return TRUE;
577	}
578
579	return FALSE;
580}
581
582
583static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
584				int vendor, EapType eap_type)
585{
586	if (data->phase2_priv && data->phase2_method) {
587		data->phase2_method->reset(sm, data->phase2_priv);
588		data->phase2_method = NULL;
589		data->phase2_priv = NULL;
590	}
591	data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
592	if (!data->phase2_method)
593		return -1;
594
595	sm->init_phase2 = 1;
596	data->phase2_priv = data->phase2_method->init(sm);
597	sm->init_phase2 = 0;
598	return 0;
599}
600
601
602static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
603					  struct eap_peap_data *data,
604					  const u8 *crypto_tlv,
605					  size_t crypto_tlv_len)
606{
607	u8 buf[61], mac[SHA1_MAC_LEN];
608	const u8 *pos;
609
610	if (crypto_tlv_len != 4 + 56) {
611		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
612			   "length %d", (int) crypto_tlv_len);
613		return -1;
614	}
615
616	pos = crypto_tlv;
617	pos += 4; /* TLV header */
618	if (pos[1] != data->peap_version) {
619		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
620			   "mismatch (was %d; expected %d)",
621			   pos[1], data->peap_version);
622		return -1;
623	}
624
625	if (pos[3] != 1) {
626		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
627			   "SubType %d", pos[3]);
628		return -1;
629	}
630	pos += 4;
631	pos += 32; /* Nonce */
632
633	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
634	os_memcpy(buf, crypto_tlv, 60);
635	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
636	buf[60] = EAP_TYPE_PEAP;
637	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
638
639	if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
640		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
641			   "cryptobinding TLV");
642		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
643		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
644			    buf, 61);
645		return -1;
646	}
647
648	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
649
650	return 0;
651}
652
653
654static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
655					struct eap_peap_data *data,
656					struct wpabuf *in_data)
657{
658	const u8 *pos;
659	size_t left;
660	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
661	size_t result_tlv_len = 0, crypto_tlv_len = 0;
662	int tlv_type, mandatory, tlv_len;
663
664	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
665	if (pos == NULL) {
666		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
667		return;
668	}
669
670	/* Parse TLVs */
671	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
672	while (left >= 4) {
673		mandatory = !!(pos[0] & 0x80);
674		tlv_type = pos[0] & 0x3f;
675		tlv_type = (tlv_type << 8) | pos[1];
676		tlv_len = ((int) pos[2] << 8) | pos[3];
677		pos += 4;
678		left -= 4;
679		if ((size_t) tlv_len > left) {
680			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
681				   "(tlv_len=%d left=%lu)", tlv_len,
682				   (unsigned long) left);
683			eap_peap_state(data, FAILURE);
684			return;
685		}
686		switch (tlv_type) {
687		case EAP_TLV_RESULT_TLV:
688			result_tlv = pos;
689			result_tlv_len = tlv_len;
690			break;
691		case EAP_TLV_CRYPTO_BINDING_TLV:
692			crypto_tlv = pos;
693			crypto_tlv_len = tlv_len;
694			break;
695		default:
696			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
697				   "%d%s", tlv_type,
698				   mandatory ? " (mandatory)" : "");
699			if (mandatory) {
700				eap_peap_state(data, FAILURE);
701				return;
702			}
703			/* Ignore this TLV, but process other TLVs */
704			break;
705		}
706
707		pos += tlv_len;
708		left -= tlv_len;
709	}
710	if (left) {
711		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
712			   "Request (left=%lu)", (unsigned long) left);
713		eap_peap_state(data, FAILURE);
714		return;
715	}
716
717	/* Process supported TLVs */
718	if (crypto_tlv && data->crypto_binding_sent) {
719		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
720			    crypto_tlv, crypto_tlv_len);
721		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
722						   crypto_tlv_len + 4) < 0) {
723			eap_peap_state(data, FAILURE);
724			return;
725		}
726		data->crypto_binding_used = 1;
727	} else if (!crypto_tlv && data->crypto_binding_sent &&
728		   data->crypto_binding == REQUIRE_BINDING) {
729		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
730		eap_peap_state(data, FAILURE);
731		return;
732	}
733
734	if (result_tlv) {
735		int status;
736		const char *requested;
737
738		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
739			    result_tlv, result_tlv_len);
740		if (result_tlv_len < 2) {
741			wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
742				   "(len=%lu)",
743				   (unsigned long) result_tlv_len);
744			eap_peap_state(data, FAILURE);
745			return;
746		}
747		requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
748			"Failure";
749		status = WPA_GET_BE16(result_tlv);
750		if (status == EAP_TLV_RESULT_SUCCESS) {
751			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
752				   "- requested %s", requested);
753			if (data->tlv_request == TLV_REQ_SUCCESS) {
754				eap_peap_state(data, SUCCESS);
755				eap_peap_valid_session(sm, data);
756			} else {
757				eap_peap_state(data, FAILURE);
758			}
759
760		} else if (status == EAP_TLV_RESULT_FAILURE) {
761			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
762				   "- requested %s", requested);
763			eap_peap_state(data, FAILURE);
764		} else {
765			wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
766				   "Status %d", status);
767			eap_peap_state(data, FAILURE);
768		}
769	}
770}
771
772
773#ifdef EAP_SERVER_TNC
774static void eap_peap_process_phase2_soh(struct eap_sm *sm,
775					struct eap_peap_data *data,
776					struct wpabuf *in_data)
777{
778	const u8 *pos, *vpos;
779	size_t left;
780	const u8 *soh_tlv = NULL;
781	size_t soh_tlv_len = 0;
782	int tlv_type, mandatory, tlv_len, vtlv_len;
783	u32 next_type;
784	u32 vendor_id;
785
786	pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
787	if (pos == NULL) {
788		wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
789			   "Extensions Method header - skip TNC");
790		goto auth_method;
791	}
792
793	/* Parse TLVs */
794	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
795	while (left >= 4) {
796		mandatory = !!(pos[0] & 0x80);
797		tlv_type = pos[0] & 0x3f;
798		tlv_type = (tlv_type << 8) | pos[1];
799		tlv_len = ((int) pos[2] << 8) | pos[3];
800		pos += 4;
801		left -= 4;
802		if ((size_t) tlv_len > left) {
803			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
804				   "(tlv_len=%d left=%lu)", tlv_len,
805				   (unsigned long) left);
806			eap_peap_state(data, FAILURE);
807			return;
808		}
809		switch (tlv_type) {
810		case EAP_TLV_VENDOR_SPECIFIC_TLV:
811			if (tlv_len < 4) {
812				wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
813					   "vendor specific TLV (len=%d)",
814					   (int) tlv_len);
815				eap_peap_state(data, FAILURE);
816				return;
817			}
818
819			vendor_id = WPA_GET_BE32(pos);
820			if (vendor_id != EAP_VENDOR_MICROSOFT) {
821				if (mandatory) {
822					eap_peap_state(data, FAILURE);
823					return;
824				}
825				break;
826			}
827
828			vpos = pos + 4;
829			mandatory = !!(vpos[0] & 0x80);
830			tlv_type = vpos[0] & 0x3f;
831			tlv_type = (tlv_type << 8) | vpos[1];
832			vtlv_len = ((int) vpos[2] << 8) | vpos[3];
833			vpos += 4;
834			if (vpos + vtlv_len > pos + left) {
835				wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
836					   "underrun");
837				eap_peap_state(data, FAILURE);
838				return;
839			}
840
841			if (tlv_type == 1) {
842				soh_tlv = vpos;
843				soh_tlv_len = vtlv_len;
844				break;
845			}
846
847			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
848				   "Type %d%s", tlv_type,
849				   mandatory ? " (mandatory)" : "");
850			if (mandatory) {
851				eap_peap_state(data, FAILURE);
852				return;
853			}
854			/* Ignore this TLV, but process other TLVs */
855			break;
856		default:
857			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
858				   "%d%s", tlv_type,
859				   mandatory ? " (mandatory)" : "");
860			if (mandatory) {
861				eap_peap_state(data, FAILURE);
862				return;
863			}
864			/* Ignore this TLV, but process other TLVs */
865			break;
866		}
867
868		pos += tlv_len;
869		left -= tlv_len;
870	}
871	if (left) {
872		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
873			   "Request (left=%lu)", (unsigned long) left);
874		eap_peap_state(data, FAILURE);
875		return;
876	}
877
878	/* Process supported TLVs */
879	if (soh_tlv) {
880		int failure = 0;
881		wpabuf_free(data->soh_response);
882		data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
883						      &failure);
884		if (failure) {
885			eap_peap_state(data, FAILURE);
886			return;
887		}
888	} else {
889		wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
890		eap_peap_state(data, FAILURE);
891		return;
892	}
893
894auth_method:
895	eap_peap_state(data, PHASE2_METHOD);
896	next_type = sm->user->methods[0].method;
897	sm->user_eap_method_index = 1;
898	wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type %d",
899		   sm->user->methods[0].vendor, next_type);
900	eap_peap_phase2_init(sm, data, sm->user->methods[0].vendor, next_type);
901}
902#endif /* EAP_SERVER_TNC */
903
904
905static void eap_peap_process_phase2_response(struct eap_sm *sm,
906					     struct eap_peap_data *data,
907					     struct wpabuf *in_data)
908{
909	int next_vendor = EAP_VENDOR_IETF;
910	u32 next_type = EAP_TYPE_NONE;
911	const struct eap_hdr *hdr;
912	const u8 *pos;
913	size_t left;
914
915	if (data->state == PHASE2_TLV) {
916		eap_peap_process_phase2_tlv(sm, data, in_data);
917		return;
918	}
919
920#ifdef EAP_SERVER_TNC
921	if (data->state == PHASE2_SOH) {
922		eap_peap_process_phase2_soh(sm, data, in_data);
923		return;
924	}
925#endif /* EAP_SERVER_TNC */
926
927	if (data->phase2_priv == NULL) {
928		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
929			   "initialized?!", __func__);
930		return;
931	}
932
933	hdr = wpabuf_head(in_data);
934	pos = (const u8 *) (hdr + 1);
935
936	if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
937		left = wpabuf_len(in_data) - sizeof(*hdr);
938		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
939			    "allowed types", pos + 1, left - 1);
940		eap_sm_process_nak(sm, pos + 1, left - 1);
941		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
942		    (sm->user->methods[sm->user_eap_method_index].vendor !=
943		     EAP_VENDOR_IETF ||
944		     sm->user->methods[sm->user_eap_method_index].method !=
945		     EAP_TYPE_NONE)) {
946			next_vendor = sm->user->methods[
947				sm->user_eap_method_index].vendor;
948			next_type = sm->user->methods[
949				sm->user_eap_method_index++].method;
950			wpa_printf(MSG_DEBUG,
951				   "EAP-PEAP: try EAP vendor %d type 0x%x",
952				   next_vendor, next_type);
953		} else {
954			eap_peap_req_failure(sm, data);
955			next_vendor = EAP_VENDOR_IETF;
956			next_type = EAP_TYPE_NONE;
957		}
958		eap_peap_phase2_init(sm, data, next_vendor, next_type);
959		return;
960	}
961
962	if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
963		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
964			   "ignore the packet");
965		return;
966	}
967
968	data->phase2_method->process(sm, data->phase2_priv, in_data);
969
970	if (sm->method_pending == METHOD_PENDING_WAIT) {
971		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
972			   "pending wait state - save decrypted response");
973		wpabuf_free(data->pending_phase2_resp);
974		data->pending_phase2_resp = wpabuf_dup(in_data);
975	}
976
977	if (!data->phase2_method->isDone(sm, data->phase2_priv))
978		return;
979
980	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
981		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
982		eap_peap_req_failure(sm, data);
983		next_vendor = EAP_VENDOR_IETF;
984		next_type = EAP_TYPE_NONE;
985		eap_peap_phase2_init(sm, data, next_vendor, next_type);
986		return;
987	}
988
989	os_free(data->phase2_key);
990	if (data->phase2_method->getKey) {
991		data->phase2_key = data->phase2_method->getKey(
992			sm, data->phase2_priv, &data->phase2_key_len);
993		if (data->phase2_key == NULL) {
994			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
995				   "failed");
996			eap_peap_req_failure(sm, data);
997			eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
998					     EAP_TYPE_NONE);
999			return;
1000		}
1001	}
1002
1003	switch (data->state) {
1004	case PHASE1_ID2:
1005	case PHASE2_ID:
1006	case PHASE2_SOH:
1007		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
1008			wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
1009					  "Identity not found in the user "
1010					  "database",
1011					  sm->identity, sm->identity_len);
1012			eap_peap_req_failure(sm, data);
1013			next_vendor = EAP_VENDOR_IETF;
1014			next_type = EAP_TYPE_NONE;
1015			break;
1016		}
1017
1018#ifdef EAP_SERVER_TNC
1019		if (data->state != PHASE2_SOH && sm->tnc &&
1020		    data->peap_version == 0) {
1021			eap_peap_state(data, PHASE2_SOH);
1022			wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
1023				   "TNC (NAP SOH)");
1024			next_vendor = EAP_VENDOR_IETF;
1025			next_type = EAP_TYPE_NONE;
1026			break;
1027		}
1028#endif /* EAP_SERVER_TNC */
1029
1030		eap_peap_state(data, PHASE2_METHOD);
1031		next_vendor = sm->user->methods[0].vendor;
1032		next_type = sm->user->methods[0].method;
1033		sm->user_eap_method_index = 1;
1034		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x",
1035			   next_vendor, next_type);
1036		break;
1037	case PHASE2_METHOD:
1038		eap_peap_req_success(sm, data);
1039		next_vendor = EAP_VENDOR_IETF;
1040		next_type = EAP_TYPE_NONE;
1041		break;
1042	case FAILURE:
1043		break;
1044	default:
1045		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
1046			   __func__, data->state);
1047		break;
1048	}
1049
1050	eap_peap_phase2_init(sm, data, next_vendor, next_type);
1051}
1052
1053
1054static void eap_peap_process_phase2(struct eap_sm *sm,
1055				    struct eap_peap_data *data,
1056				    const struct wpabuf *respData,
1057				    struct wpabuf *in_buf)
1058{
1059	struct wpabuf *in_decrypted;
1060	const struct eap_hdr *hdr;
1061	size_t len;
1062
1063	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
1064		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
1065
1066	if (data->pending_phase2_resp) {
1067		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
1068			   "skip decryption and use old data");
1069		eap_peap_process_phase2_response(sm, data,
1070						 data->pending_phase2_resp);
1071		wpabuf_free(data->pending_phase2_resp);
1072		data->pending_phase2_resp = NULL;
1073		return;
1074	}
1075
1076	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
1077					      in_buf);
1078	if (in_decrypted == NULL) {
1079		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
1080			   "data");
1081		eap_peap_state(data, FAILURE);
1082		return;
1083	}
1084
1085	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
1086			    in_decrypted);
1087
1088	if (data->peap_version == 0 && data->state != PHASE2_TLV) {
1089		const struct eap_hdr *resp;
1090		struct eap_hdr *nhdr;
1091		struct wpabuf *nbuf =
1092			wpabuf_alloc(sizeof(struct eap_hdr) +
1093				     wpabuf_len(in_decrypted));
1094		if (nbuf == NULL) {
1095			wpabuf_free(in_decrypted);
1096			return;
1097		}
1098
1099		resp = wpabuf_head(respData);
1100		nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
1101		nhdr->code = resp->code;
1102		nhdr->identifier = resp->identifier;
1103		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
1104					    wpabuf_len(in_decrypted));
1105		wpabuf_put_buf(nbuf, in_decrypted);
1106		wpabuf_free(in_decrypted);
1107
1108		in_decrypted = nbuf;
1109	}
1110
1111	hdr = wpabuf_head(in_decrypted);
1112	if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) {
1113		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
1114			   "EAP frame (len=%lu)",
1115			   (unsigned long) wpabuf_len(in_decrypted));
1116		wpabuf_free(in_decrypted);
1117		eap_peap_req_failure(sm, data);
1118		return;
1119	}
1120	len = be_to_host16(hdr->length);
1121	if (len > wpabuf_len(in_decrypted)) {
1122		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
1123			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
1124			   (unsigned long) wpabuf_len(in_decrypted),
1125			   (unsigned long) len);
1126		wpabuf_free(in_decrypted);
1127		eap_peap_req_failure(sm, data);
1128		return;
1129	}
1130	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
1131		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
1132		   (unsigned long) len);
1133	switch (hdr->code) {
1134	case EAP_CODE_RESPONSE:
1135		eap_peap_process_phase2_response(sm, data, in_decrypted);
1136		break;
1137	case EAP_CODE_SUCCESS:
1138		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
1139		if (data->state == SUCCESS_REQ) {
1140			eap_peap_state(data, SUCCESS);
1141			eap_peap_valid_session(sm, data);
1142		}
1143		break;
1144	case EAP_CODE_FAILURE:
1145		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
1146		eap_peap_state(data, FAILURE);
1147		break;
1148	default:
1149		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
1150			   "Phase 2 EAP header", hdr->code);
1151		break;
1152	}
1153
1154	wpabuf_free(in_decrypted);
1155}
1156
1157
1158static int eap_peap_process_version(struct eap_sm *sm, void *priv,
1159				    int peer_version)
1160{
1161	struct eap_peap_data *data = priv;
1162
1163	data->recv_version = peer_version;
1164	if (data->force_version >= 0 && peer_version != data->force_version) {
1165		wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
1166			   " version (forced=%d peer=%d) - reject",
1167			   data->force_version, peer_version);
1168		return -1;
1169	}
1170	if (peer_version < data->peap_version) {
1171		wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
1172			   "use version %d",
1173			   peer_version, data->peap_version, peer_version);
1174		data->peap_version = peer_version;
1175	}
1176
1177	return 0;
1178}
1179
1180
1181static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
1182				 const struct wpabuf *respData)
1183{
1184	struct eap_peap_data *data = priv;
1185
1186	switch (data->state) {
1187	case PHASE1:
1188		if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
1189			eap_peap_state(data, FAILURE);
1190			break;
1191		}
1192		break;
1193	case PHASE2_START:
1194		eap_peap_state(data, PHASE2_ID);
1195		eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
1196				     EAP_TYPE_IDENTITY);
1197		break;
1198	case PHASE1_ID2:
1199	case PHASE2_ID:
1200	case PHASE2_METHOD:
1201	case PHASE2_SOH:
1202	case PHASE2_TLV:
1203		eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
1204		break;
1205	case SUCCESS_REQ:
1206		eap_peap_state(data, SUCCESS);
1207		eap_peap_valid_session(sm, data);
1208		break;
1209	case FAILURE_REQ:
1210		eap_peap_state(data, FAILURE);
1211		break;
1212	default:
1213		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
1214			   data->state, __func__);
1215		break;
1216	}
1217}
1218
1219
1220static void eap_peap_process(struct eap_sm *sm, void *priv,
1221			     struct wpabuf *respData)
1222{
1223	struct eap_peap_data *data = priv;
1224	const struct wpabuf *buf;
1225	const u8 *pos;
1226	u8 id_len;
1227
1228	if (eap_server_tls_process(sm, &data->ssl, respData, data,
1229				   EAP_TYPE_PEAP, eap_peap_process_version,
1230				   eap_peap_process_msg) < 0) {
1231		eap_peap_state(data, FAILURE);
1232		return;
1233	}
1234
1235	if (data->state == SUCCESS ||
1236	    !tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
1237	    !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
1238		return;
1239
1240	buf = tls_connection_get_success_data(data->ssl.conn);
1241	if (!buf || wpabuf_len(buf) < 2) {
1242		wpa_printf(MSG_DEBUG,
1243			   "EAP-PEAP: No success data in resumed session - reject attempt");
1244		eap_peap_state(data, FAILURE);
1245		return;
1246	}
1247
1248	pos = wpabuf_head(buf);
1249	if (*pos != EAP_TYPE_PEAP) {
1250		wpa_printf(MSG_DEBUG,
1251			   "EAP-PEAP: Resumed session for another EAP type (%u) - reject attempt",
1252			   *pos);
1253		eap_peap_state(data, FAILURE);
1254		return;
1255	}
1256
1257	pos++;
1258	id_len = *pos++;
1259	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PEAP: Identity from cached session",
1260			  pos, id_len);
1261	os_free(sm->identity);
1262	sm->identity = os_malloc(id_len ? id_len : 1);
1263	if (!sm->identity) {
1264		sm->identity_len = 0;
1265		eap_peap_state(data, FAILURE);
1266		return;
1267	}
1268
1269	os_memcpy(sm->identity, pos, id_len);
1270	sm->identity_len = id_len;
1271
1272	if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
1273		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PEAP: Phase2 Identity not found in the user database",
1274				  sm->identity, sm->identity_len);
1275		eap_peap_state(data, FAILURE);
1276		return;
1277	}
1278
1279	wpa_printf(MSG_DEBUG,
1280		   "EAP-PEAP: Resuming previous session - skip Phase2");
1281	eap_peap_req_success(sm, data);
1282	if (data->state == SUCCESS_REQ)
1283		tls_connection_set_success_data_resumed(data->ssl.conn);
1284}
1285
1286
1287static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
1288{
1289	struct eap_peap_data *data = priv;
1290	return data->state == SUCCESS || data->state == FAILURE;
1291}
1292
1293
1294static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
1295{
1296	struct eap_peap_data *data = priv;
1297	u8 *eapKeyData;
1298
1299	if (data->state != SUCCESS)
1300		return NULL;
1301
1302	if (data->crypto_binding_used) {
1303		u8 csk[128];
1304		/*
1305		 * Note: It looks like Microsoft implementation requires null
1306		 * termination for this label while the one used for deriving
1307		 * IPMK|CMK did not use null termination.
1308		 */
1309		if (peap_prfplus(data->peap_version, data->ipmk, 40,
1310				 "Session Key Generating Function",
1311				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
1312			return NULL;
1313		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
1314		eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
1315		if (eapKeyData) {
1316			os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
1317			*len = EAP_TLS_KEY_LEN;
1318			wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1319				    eapKeyData, EAP_TLS_KEY_LEN);
1320		} else {
1321			wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
1322				   "key");
1323		}
1324
1325		return eapKeyData;
1326	}
1327
1328	/* TODO: PEAPv1 - different label in some cases */
1329	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
1330					       "client EAP encryption",
1331					       EAP_TLS_KEY_LEN);
1332	if (eapKeyData) {
1333		*len = EAP_TLS_KEY_LEN;
1334		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1335			    eapKeyData, EAP_TLS_KEY_LEN);
1336	} else {
1337		wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
1338	}
1339
1340	return eapKeyData;
1341}
1342
1343
1344static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
1345{
1346	struct eap_peap_data *data = priv;
1347	return data->state == SUCCESS;
1348}
1349
1350
1351static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1352{
1353	struct eap_peap_data *data = priv;
1354
1355	if (data->state != SUCCESS)
1356		return NULL;
1357
1358	return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
1359						len);
1360}
1361
1362
1363int eap_server_peap_register(void)
1364{
1365	struct eap_method *eap;
1366
1367	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1368				      EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
1369	if (eap == NULL)
1370		return -1;
1371
1372	eap->init = eap_peap_init;
1373	eap->reset = eap_peap_reset;
1374	eap->buildReq = eap_peap_buildReq;
1375	eap->check = eap_peap_check;
1376	eap->process = eap_peap_process;
1377	eap->isDone = eap_peap_isDone;
1378	eap->getKey = eap_peap_getKey;
1379	eap->isSuccess = eap_peap_isSuccess;
1380	eap->getSessionId = eap_peap_get_session_id;
1381
1382	return eap_server_method_register(eap);
1383}
1384