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