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