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