xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_server/eap_server_peap.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3*a1157835SDaniel Fojt  * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino 
113ff40c12SJohn Marino #include "common.h"
123ff40c12SJohn Marino #include "crypto/sha1.h"
133ff40c12SJohn Marino #include "crypto/tls.h"
143ff40c12SJohn Marino #include "crypto/random.h"
153ff40c12SJohn Marino #include "eap_i.h"
163ff40c12SJohn Marino #include "eap_tls_common.h"
173ff40c12SJohn Marino #include "eap_common/eap_tlv_common.h"
183ff40c12SJohn Marino #include "eap_common/eap_peap_common.h"
193ff40c12SJohn Marino #include "tncs.h"
203ff40c12SJohn Marino 
213ff40c12SJohn Marino 
223ff40c12SJohn Marino /* Maximum supported PEAP version
233ff40c12SJohn Marino  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
243ff40c12SJohn Marino  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
253ff40c12SJohn Marino  */
263ff40c12SJohn Marino #define EAP_PEAP_VERSION 1
273ff40c12SJohn Marino 
283ff40c12SJohn Marino 
293ff40c12SJohn Marino static void eap_peap_reset(struct eap_sm *sm, void *priv);
303ff40c12SJohn Marino 
313ff40c12SJohn Marino 
323ff40c12SJohn Marino struct eap_peap_data {
333ff40c12SJohn Marino 	struct eap_ssl_data ssl;
343ff40c12SJohn Marino 	enum {
353ff40c12SJohn Marino 		START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
363ff40c12SJohn Marino 		PHASE2_METHOD, PHASE2_SOH,
373ff40c12SJohn Marino 		PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
383ff40c12SJohn Marino 	} state;
393ff40c12SJohn Marino 
403ff40c12SJohn Marino 	int peap_version;
413ff40c12SJohn Marino 	int recv_version;
423ff40c12SJohn Marino 	const struct eap_method *phase2_method;
433ff40c12SJohn Marino 	void *phase2_priv;
443ff40c12SJohn Marino 	int force_version;
453ff40c12SJohn Marino 	struct wpabuf *pending_phase2_resp;
463ff40c12SJohn Marino 	enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
473ff40c12SJohn Marino 	int crypto_binding_sent;
483ff40c12SJohn Marino 	int crypto_binding_used;
493ff40c12SJohn Marino 	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
503ff40c12SJohn Marino 	u8 binding_nonce[32];
513ff40c12SJohn Marino 	u8 ipmk[40];
523ff40c12SJohn Marino 	u8 cmk[20];
533ff40c12SJohn Marino 	u8 *phase2_key;
543ff40c12SJohn Marino 	size_t phase2_key_len;
553ff40c12SJohn Marino 	struct wpabuf *soh_response;
563ff40c12SJohn Marino };
573ff40c12SJohn Marino 
583ff40c12SJohn Marino 
eap_peap_state_txt(int state)593ff40c12SJohn Marino static const char * eap_peap_state_txt(int state)
603ff40c12SJohn Marino {
613ff40c12SJohn Marino 	switch (state) {
623ff40c12SJohn Marino 	case START:
633ff40c12SJohn Marino 		return "START";
643ff40c12SJohn Marino 	case PHASE1:
653ff40c12SJohn Marino 		return "PHASE1";
663ff40c12SJohn Marino 	case PHASE1_ID2:
673ff40c12SJohn Marino 		return "PHASE1_ID2";
683ff40c12SJohn Marino 	case PHASE2_START:
693ff40c12SJohn Marino 		return "PHASE2_START";
703ff40c12SJohn Marino 	case PHASE2_ID:
713ff40c12SJohn Marino 		return "PHASE2_ID";
723ff40c12SJohn Marino 	case PHASE2_METHOD:
733ff40c12SJohn Marino 		return "PHASE2_METHOD";
743ff40c12SJohn Marino 	case PHASE2_SOH:
753ff40c12SJohn Marino 		return "PHASE2_SOH";
763ff40c12SJohn Marino 	case PHASE2_TLV:
773ff40c12SJohn Marino 		return "PHASE2_TLV";
783ff40c12SJohn Marino 	case SUCCESS_REQ:
793ff40c12SJohn Marino 		return "SUCCESS_REQ";
803ff40c12SJohn Marino 	case FAILURE_REQ:
813ff40c12SJohn Marino 		return "FAILURE_REQ";
823ff40c12SJohn Marino 	case SUCCESS:
833ff40c12SJohn Marino 		return "SUCCESS";
843ff40c12SJohn Marino 	case FAILURE:
853ff40c12SJohn Marino 		return "FAILURE";
863ff40c12SJohn Marino 	default:
873ff40c12SJohn Marino 		return "Unknown?!";
883ff40c12SJohn Marino 	}
893ff40c12SJohn Marino }
903ff40c12SJohn Marino 
913ff40c12SJohn Marino 
eap_peap_state(struct eap_peap_data * data,int state)923ff40c12SJohn Marino static void eap_peap_state(struct eap_peap_data *data, int state)
933ff40c12SJohn Marino {
943ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
953ff40c12SJohn Marino 		   eap_peap_state_txt(data->state),
963ff40c12SJohn Marino 		   eap_peap_state_txt(state));
973ff40c12SJohn Marino 	data->state = state;
98*a1157835SDaniel Fojt 	if (state == FAILURE || state == FAILURE_REQ)
99*a1157835SDaniel Fojt 		tls_connection_remove_session(data->ssl.conn);
100*a1157835SDaniel Fojt }
101*a1157835SDaniel Fojt 
102*a1157835SDaniel Fojt 
eap_peap_valid_session(struct eap_sm * sm,struct eap_peap_data * data)103*a1157835SDaniel Fojt static void eap_peap_valid_session(struct eap_sm *sm,
104*a1157835SDaniel Fojt 				   struct eap_peap_data *data)
105*a1157835SDaniel Fojt {
106*a1157835SDaniel Fojt 	struct wpabuf *buf;
107*a1157835SDaniel Fojt 
108*a1157835SDaniel Fojt 	if (!sm->tls_session_lifetime ||
109*a1157835SDaniel Fojt 	    tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
110*a1157835SDaniel Fojt 		return;
111*a1157835SDaniel Fojt 
112*a1157835SDaniel Fojt 	buf = wpabuf_alloc(1 + 1 + sm->identity_len);
113*a1157835SDaniel Fojt 	if (!buf)
114*a1157835SDaniel Fojt 		return;
115*a1157835SDaniel Fojt 	wpabuf_put_u8(buf, EAP_TYPE_PEAP);
116*a1157835SDaniel Fojt 	if (sm->identity) {
117*a1157835SDaniel Fojt 		u8 id_len;
118*a1157835SDaniel Fojt 
119*a1157835SDaniel Fojt 		if (sm->identity_len <= 255)
120*a1157835SDaniel Fojt 			id_len = sm->identity_len;
121*a1157835SDaniel Fojt 		else
122*a1157835SDaniel Fojt 			id_len = 255;
123*a1157835SDaniel Fojt 		wpabuf_put_u8(buf, id_len);
124*a1157835SDaniel Fojt 		wpabuf_put_data(buf, sm->identity, id_len);
125*a1157835SDaniel Fojt 	} else {
126*a1157835SDaniel Fojt 		wpabuf_put_u8(buf, 0);
127*a1157835SDaniel Fojt 	}
128*a1157835SDaniel Fojt 	tls_connection_set_success_data(data->ssl.conn, buf);
1293ff40c12SJohn Marino }
1303ff40c12SJohn Marino 
1313ff40c12SJohn Marino 
eap_peap_req_success(struct eap_sm * sm,struct eap_peap_data * data)1323ff40c12SJohn Marino static void eap_peap_req_success(struct eap_sm *sm,
1333ff40c12SJohn Marino 				 struct eap_peap_data *data)
1343ff40c12SJohn Marino {
1353ff40c12SJohn Marino 	if (data->state == FAILURE || data->state == FAILURE_REQ) {
1363ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
1373ff40c12SJohn Marino 		return;
1383ff40c12SJohn Marino 	}
1393ff40c12SJohn Marino 
1403ff40c12SJohn Marino 	if (data->peap_version == 0) {
1413ff40c12SJohn Marino 		data->tlv_request = TLV_REQ_SUCCESS;
1423ff40c12SJohn Marino 		eap_peap_state(data, PHASE2_TLV);
1433ff40c12SJohn Marino 	} else {
1443ff40c12SJohn Marino 		eap_peap_state(data, SUCCESS_REQ);
1453ff40c12SJohn Marino 	}
1463ff40c12SJohn Marino }
1473ff40c12SJohn Marino 
1483ff40c12SJohn Marino 
eap_peap_req_failure(struct eap_sm * sm,struct eap_peap_data * data)1493ff40c12SJohn Marino static void eap_peap_req_failure(struct eap_sm *sm,
1503ff40c12SJohn Marino 				 struct eap_peap_data *data)
1513ff40c12SJohn Marino {
1523ff40c12SJohn Marino 	if (data->state == FAILURE || data->state == FAILURE_REQ ||
1533ff40c12SJohn Marino 	    data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
1543ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
1553ff40c12SJohn Marino 		return;
1563ff40c12SJohn Marino 	}
1573ff40c12SJohn Marino 
1583ff40c12SJohn Marino 	if (data->peap_version == 0) {
1593ff40c12SJohn Marino 		data->tlv_request = TLV_REQ_FAILURE;
1603ff40c12SJohn Marino 		eap_peap_state(data, PHASE2_TLV);
1613ff40c12SJohn Marino 	} else {
1623ff40c12SJohn Marino 		eap_peap_state(data, FAILURE_REQ);
1633ff40c12SJohn Marino 	}
1643ff40c12SJohn Marino }
1653ff40c12SJohn Marino 
1663ff40c12SJohn Marino 
eap_peap_init(struct eap_sm * sm)1673ff40c12SJohn Marino static void * eap_peap_init(struct eap_sm *sm)
1683ff40c12SJohn Marino {
1693ff40c12SJohn Marino 	struct eap_peap_data *data;
1703ff40c12SJohn Marino 
1713ff40c12SJohn Marino 	data = os_zalloc(sizeof(*data));
1723ff40c12SJohn Marino 	if (data == NULL)
1733ff40c12SJohn Marino 		return NULL;
1743ff40c12SJohn Marino 	data->peap_version = EAP_PEAP_VERSION;
1753ff40c12SJohn Marino 	data->force_version = -1;
1763ff40c12SJohn Marino 	if (sm->user && sm->user->force_version >= 0) {
1773ff40c12SJohn Marino 		data->force_version = sm->user->force_version;
1783ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
1793ff40c12SJohn Marino 			   data->force_version);
1803ff40c12SJohn Marino 		data->peap_version = data->force_version;
1813ff40c12SJohn Marino 	}
1823ff40c12SJohn Marino 	data->state = START;
1833ff40c12SJohn Marino 	data->crypto_binding = OPTIONAL_BINDING;
1843ff40c12SJohn Marino 
185*a1157835SDaniel Fojt 	if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_PEAP)) {
1863ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
1873ff40c12SJohn Marino 		eap_peap_reset(sm, data);
1883ff40c12SJohn Marino 		return NULL;
1893ff40c12SJohn Marino 	}
1903ff40c12SJohn Marino 
1913ff40c12SJohn Marino 	return data;
1923ff40c12SJohn Marino }
1933ff40c12SJohn Marino 
1943ff40c12SJohn Marino 
eap_peap_reset(struct eap_sm * sm,void * priv)1953ff40c12SJohn Marino static void eap_peap_reset(struct eap_sm *sm, void *priv)
1963ff40c12SJohn Marino {
1973ff40c12SJohn Marino 	struct eap_peap_data *data = priv;
1983ff40c12SJohn Marino 	if (data == NULL)
1993ff40c12SJohn Marino 		return;
2003ff40c12SJohn Marino 	if (data->phase2_priv && data->phase2_method)
2013ff40c12SJohn Marino 		data->phase2_method->reset(sm, data->phase2_priv);
2023ff40c12SJohn Marino 	eap_server_tls_ssl_deinit(sm, &data->ssl);
2033ff40c12SJohn Marino 	wpabuf_free(data->pending_phase2_resp);
2043ff40c12SJohn Marino 	os_free(data->phase2_key);
2053ff40c12SJohn Marino 	wpabuf_free(data->soh_response);
206*a1157835SDaniel Fojt 	bin_clear_free(data, sizeof(*data));
2073ff40c12SJohn Marino }
2083ff40c12SJohn Marino 
2093ff40c12SJohn Marino 
eap_peap_build_start(struct eap_sm * sm,struct eap_peap_data * data,u8 id)2103ff40c12SJohn Marino static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
2113ff40c12SJohn Marino 					    struct eap_peap_data *data, u8 id)
2123ff40c12SJohn Marino {
2133ff40c12SJohn Marino 	struct wpabuf *req;
2143ff40c12SJohn Marino 
2153ff40c12SJohn Marino 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
2163ff40c12SJohn Marino 			    EAP_CODE_REQUEST, id);
2173ff40c12SJohn Marino 	if (req == NULL) {
2183ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
2193ff40c12SJohn Marino 			   " request");
2203ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
2213ff40c12SJohn Marino 		return NULL;
2223ff40c12SJohn Marino 	}
2233ff40c12SJohn Marino 
2243ff40c12SJohn Marino 	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
2253ff40c12SJohn Marino 
2263ff40c12SJohn Marino 	eap_peap_state(data, PHASE1);
2273ff40c12SJohn Marino 
2283ff40c12SJohn Marino 	return req;
2293ff40c12SJohn Marino }
2303ff40c12SJohn Marino 
2313ff40c12SJohn Marino 
eap_peap_build_phase2_req(struct eap_sm * sm,struct eap_peap_data * data,u8 id)2323ff40c12SJohn Marino static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
2333ff40c12SJohn Marino 						 struct eap_peap_data *data,
2343ff40c12SJohn Marino 						 u8 id)
2353ff40c12SJohn Marino {
2363ff40c12SJohn Marino 	struct wpabuf *buf, *encr_req, msgbuf;
2373ff40c12SJohn Marino 	const u8 *req;
2383ff40c12SJohn Marino 	size_t req_len;
2393ff40c12SJohn Marino 
2403ff40c12SJohn Marino 	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
2413ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
2423ff40c12SJohn Marino 		return NULL;
2433ff40c12SJohn Marino 	}
2443ff40c12SJohn Marino 	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
2453ff40c12SJohn Marino 	if (buf == NULL)
2463ff40c12SJohn Marino 		return NULL;
2473ff40c12SJohn Marino 
2483ff40c12SJohn Marino 	req = wpabuf_head(buf);
2493ff40c12SJohn Marino 	req_len = wpabuf_len(buf);
2503ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
2513ff40c12SJohn Marino 			req, req_len);
2523ff40c12SJohn Marino 
2533ff40c12SJohn Marino 	if (data->peap_version == 0 &&
2543ff40c12SJohn Marino 	    data->phase2_method->method != EAP_TYPE_TLV) {
2553ff40c12SJohn Marino 		req += sizeof(struct eap_hdr);
2563ff40c12SJohn Marino 		req_len -= sizeof(struct eap_hdr);
2573ff40c12SJohn Marino 	}
2583ff40c12SJohn Marino 
2593ff40c12SJohn Marino 	wpabuf_set(&msgbuf, req, req_len);
2603ff40c12SJohn Marino 	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
2613ff40c12SJohn Marino 	wpabuf_free(buf);
2623ff40c12SJohn Marino 
2633ff40c12SJohn Marino 	return encr_req;
2643ff40c12SJohn Marino }
2653ff40c12SJohn Marino 
2663ff40c12SJohn Marino 
2673ff40c12SJohn Marino #ifdef EAP_SERVER_TNC
eap_peap_build_phase2_soh(struct eap_sm * sm,struct eap_peap_data * data,u8 id)2683ff40c12SJohn Marino static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
2693ff40c12SJohn Marino 						 struct eap_peap_data *data,
2703ff40c12SJohn Marino 						 u8 id)
2713ff40c12SJohn Marino {
2723ff40c12SJohn Marino 	struct wpabuf *buf1, *buf, *encr_req, msgbuf;
2733ff40c12SJohn Marino 	const u8 *req;
2743ff40c12SJohn Marino 	size_t req_len;
2753ff40c12SJohn Marino 
2763ff40c12SJohn Marino 	buf1 = tncs_build_soh_request();
2773ff40c12SJohn Marino 	if (buf1 == NULL)
2783ff40c12SJohn Marino 		return NULL;
2793ff40c12SJohn Marino 
2803ff40c12SJohn Marino 	buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
2813ff40c12SJohn Marino 			    EAP_CODE_REQUEST, id);
2823ff40c12SJohn Marino 	if (buf == NULL) {
2833ff40c12SJohn Marino 		wpabuf_free(buf1);
2843ff40c12SJohn Marino 		return NULL;
2853ff40c12SJohn Marino 	}
2863ff40c12SJohn Marino 	wpabuf_put_buf(buf, buf1);
2873ff40c12SJohn Marino 	wpabuf_free(buf1);
2883ff40c12SJohn Marino 
2893ff40c12SJohn Marino 	req = wpabuf_head(buf);
2903ff40c12SJohn Marino 	req_len = wpabuf_len(buf);
2913ff40c12SJohn Marino 
2923ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
2933ff40c12SJohn Marino 			req, req_len);
2943ff40c12SJohn Marino 
2953ff40c12SJohn Marino 	req += sizeof(struct eap_hdr);
2963ff40c12SJohn Marino 	req_len -= sizeof(struct eap_hdr);
2973ff40c12SJohn Marino 	wpabuf_set(&msgbuf, req, req_len);
2983ff40c12SJohn Marino 
2993ff40c12SJohn Marino 	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
3003ff40c12SJohn Marino 	wpabuf_free(buf);
3013ff40c12SJohn Marino 
3023ff40c12SJohn Marino 	return encr_req;
3033ff40c12SJohn Marino }
3043ff40c12SJohn Marino #endif /* EAP_SERVER_TNC */
3053ff40c12SJohn Marino 
3063ff40c12SJohn Marino 
eap_peap_get_isk(struct eap_peap_data * data,u8 * isk,size_t isk_len)3073ff40c12SJohn Marino static void eap_peap_get_isk(struct eap_peap_data *data,
3083ff40c12SJohn Marino 			     u8 *isk, size_t isk_len)
3093ff40c12SJohn Marino {
3103ff40c12SJohn Marino 	size_t key_len;
3113ff40c12SJohn Marino 
3123ff40c12SJohn Marino 	os_memset(isk, 0, isk_len);
3133ff40c12SJohn Marino 	if (data->phase2_key == NULL)
3143ff40c12SJohn Marino 		return;
3153ff40c12SJohn Marino 
3163ff40c12SJohn Marino 	key_len = data->phase2_key_len;
3173ff40c12SJohn Marino 	if (key_len > isk_len)
3183ff40c12SJohn Marino 		key_len = isk_len;
3193ff40c12SJohn Marino 	os_memcpy(isk, data->phase2_key, key_len);
3203ff40c12SJohn Marino }
3213ff40c12SJohn Marino 
3223ff40c12SJohn Marino 
eap_peap_derive_cmk(struct eap_sm * sm,struct eap_peap_data * data)3233ff40c12SJohn Marino static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
3243ff40c12SJohn Marino {
3253ff40c12SJohn Marino 	u8 *tk;
3263ff40c12SJohn Marino 	u8 isk[32], imck[60];
327*a1157835SDaniel Fojt 	int res;
3283ff40c12SJohn Marino 
3293ff40c12SJohn Marino 	/*
3303ff40c12SJohn Marino 	 * Tunnel key (TK) is the first 60 octets of the key generated by
3313ff40c12SJohn Marino 	 * phase 1 of PEAP (based on TLS).
3323ff40c12SJohn Marino 	 */
3333ff40c12SJohn Marino 	tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
334*a1157835SDaniel Fojt 				       NULL, 0, EAP_TLS_KEY_LEN);
3353ff40c12SJohn Marino 	if (tk == NULL)
3363ff40c12SJohn Marino 		return -1;
3373ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
3383ff40c12SJohn Marino 
339*a1157835SDaniel Fojt 	if (tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
340*a1157835SDaniel Fojt 		/* Fast-connect: IPMK|CMK = TK */
341*a1157835SDaniel Fojt 		os_memcpy(data->ipmk, tk, 40);
342*a1157835SDaniel Fojt 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
343*a1157835SDaniel Fojt 				data->ipmk, 40);
344*a1157835SDaniel Fojt 		os_memcpy(data->cmk, tk + 40, 20);
345*a1157835SDaniel Fojt 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
346*a1157835SDaniel Fojt 				data->cmk, 20);
347*a1157835SDaniel Fojt 		os_free(tk);
348*a1157835SDaniel Fojt 		return 0;
349*a1157835SDaniel Fojt 	}
350*a1157835SDaniel Fojt 
3513ff40c12SJohn Marino 	eap_peap_get_isk(data, isk, sizeof(isk));
3523ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
3533ff40c12SJohn Marino 
3543ff40c12SJohn Marino 	/*
3553ff40c12SJohn Marino 	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
3563ff40c12SJohn Marino 	 * TempKey = First 40 octets of TK
3573ff40c12SJohn Marino 	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
3583ff40c12SJohn Marino 	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
3593ff40c12SJohn Marino 	 * in the end of the label just before ISK; is that just a typo?)
3603ff40c12SJohn Marino 	 */
3613ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
362*a1157835SDaniel Fojt 	res = peap_prfplus(data->peap_version, tk, 40,
3633ff40c12SJohn Marino 			   "Inner Methods Compound Keys",
364*a1157835SDaniel Fojt 			   isk, sizeof(isk), imck, sizeof(imck));
365*a1157835SDaniel Fojt 	forced_memzero(isk, sizeof(isk));
366*a1157835SDaniel Fojt 	if (res < 0) {
3673ff40c12SJohn Marino 		os_free(tk);
3683ff40c12SJohn Marino 		return -1;
3693ff40c12SJohn Marino 	}
3703ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
3713ff40c12SJohn Marino 			imck, sizeof(imck));
3723ff40c12SJohn Marino 
3733ff40c12SJohn Marino 	os_free(tk);
3743ff40c12SJohn Marino 
3753ff40c12SJohn Marino 	os_memcpy(data->ipmk, imck, 40);
3763ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
3773ff40c12SJohn Marino 	os_memcpy(data->cmk, imck + 40, 20);
3783ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
379*a1157835SDaniel Fojt 	forced_memzero(imck, sizeof(imck));
3803ff40c12SJohn Marino 
3813ff40c12SJohn Marino 	return 0;
3823ff40c12SJohn Marino }
3833ff40c12SJohn Marino 
3843ff40c12SJohn Marino 
eap_peap_build_phase2_tlv(struct eap_sm * sm,struct eap_peap_data * data,u8 id)3853ff40c12SJohn Marino static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
3863ff40c12SJohn Marino 						 struct eap_peap_data *data,
3873ff40c12SJohn Marino 						 u8 id)
3883ff40c12SJohn Marino {
3893ff40c12SJohn Marino 	struct wpabuf *buf, *encr_req;
3903ff40c12SJohn Marino 	size_t mlen;
3913ff40c12SJohn Marino 
3923ff40c12SJohn Marino 	mlen = 6; /* Result TLV */
393*a1157835SDaniel Fojt 	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
394*a1157835SDaniel Fojt 	    data->crypto_binding != NO_BINDING) {
3953ff40c12SJohn Marino 		mlen += 60; /* Cryptobinding TLV */
3963ff40c12SJohn Marino #ifdef EAP_SERVER_TNC
3973ff40c12SJohn Marino 		if (data->soh_response)
3983ff40c12SJohn Marino 			mlen += wpabuf_len(data->soh_response);
3993ff40c12SJohn Marino #endif /* EAP_SERVER_TNC */
400*a1157835SDaniel Fojt 	}
4013ff40c12SJohn Marino 
4023ff40c12SJohn Marino 	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
4033ff40c12SJohn Marino 			    EAP_CODE_REQUEST, id);
4043ff40c12SJohn Marino 	if (buf == NULL)
4053ff40c12SJohn Marino 		return NULL;
4063ff40c12SJohn Marino 
4073ff40c12SJohn Marino 	wpabuf_put_u8(buf, 0x80); /* Mandatory */
4083ff40c12SJohn Marino 	wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
4093ff40c12SJohn Marino 	/* Length */
4103ff40c12SJohn Marino 	wpabuf_put_be16(buf, 2);
4113ff40c12SJohn Marino 	/* Status */
4123ff40c12SJohn Marino 	wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
4133ff40c12SJohn Marino 			EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
4143ff40c12SJohn Marino 
4153ff40c12SJohn Marino 	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
4163ff40c12SJohn Marino 	    data->crypto_binding != NO_BINDING) {
4173ff40c12SJohn Marino 		u8 *mac;
4183ff40c12SJohn Marino 		u8 eap_type = EAP_TYPE_PEAP;
4193ff40c12SJohn Marino 		const u8 *addr[2];
4203ff40c12SJohn Marino 		size_t len[2];
4213ff40c12SJohn Marino 		u16 tlv_type;
4223ff40c12SJohn Marino 
4233ff40c12SJohn Marino #ifdef EAP_SERVER_TNC
4243ff40c12SJohn Marino 		if (data->soh_response) {
4253ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
4263ff40c12SJohn Marino 				   "Response TLV");
4273ff40c12SJohn Marino 			wpabuf_put_buf(buf, data->soh_response);
4283ff40c12SJohn Marino 			wpabuf_free(data->soh_response);
4293ff40c12SJohn Marino 			data->soh_response = NULL;
4303ff40c12SJohn Marino 		}
4313ff40c12SJohn Marino #endif /* EAP_SERVER_TNC */
4323ff40c12SJohn Marino 
4333ff40c12SJohn Marino 		if (eap_peap_derive_cmk(sm, data) < 0 ||
4343ff40c12SJohn Marino 		    random_get_bytes(data->binding_nonce, 32)) {
4353ff40c12SJohn Marino 			wpabuf_free(buf);
4363ff40c12SJohn Marino 			return NULL;
4373ff40c12SJohn Marino 		}
4383ff40c12SJohn Marino 
4393ff40c12SJohn Marino 		/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
4403ff40c12SJohn Marino 		addr[0] = wpabuf_put(buf, 0);
4413ff40c12SJohn Marino 		len[0] = 60;
4423ff40c12SJohn Marino 		addr[1] = &eap_type;
4433ff40c12SJohn Marino 		len[1] = 1;
4443ff40c12SJohn Marino 
4453ff40c12SJohn Marino 		tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
4463ff40c12SJohn Marino 		wpabuf_put_be16(buf, tlv_type);
4473ff40c12SJohn Marino 		wpabuf_put_be16(buf, 56);
4483ff40c12SJohn Marino 
4493ff40c12SJohn Marino 		wpabuf_put_u8(buf, 0); /* Reserved */
4503ff40c12SJohn Marino 		wpabuf_put_u8(buf, data->peap_version); /* Version */
4513ff40c12SJohn Marino 		wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
4523ff40c12SJohn Marino 		wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
4533ff40c12SJohn Marino 		wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
4543ff40c12SJohn Marino 		mac = wpabuf_put(buf, 20); /* Compound_MAC */
4553ff40c12SJohn Marino 		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
4563ff40c12SJohn Marino 			    data->cmk, 20);
4573ff40c12SJohn Marino 		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
4583ff40c12SJohn Marino 			    addr[0], len[0]);
4593ff40c12SJohn Marino 		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
4603ff40c12SJohn Marino 			    addr[1], len[1]);
4613ff40c12SJohn Marino 		hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
4623ff40c12SJohn Marino 		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
4633ff40c12SJohn Marino 			    mac, SHA1_MAC_LEN);
4643ff40c12SJohn Marino 		data->crypto_binding_sent = 1;
4653ff40c12SJohn Marino 	}
4663ff40c12SJohn Marino 
4673ff40c12SJohn Marino 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
4683ff40c12SJohn Marino 			    buf);
4693ff40c12SJohn Marino 
4703ff40c12SJohn Marino 	encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
4713ff40c12SJohn Marino 	wpabuf_free(buf);
4723ff40c12SJohn Marino 
4733ff40c12SJohn Marino 	return encr_req;
4743ff40c12SJohn Marino }
4753ff40c12SJohn Marino 
4763ff40c12SJohn Marino 
eap_peap_build_phase2_term(struct eap_sm * sm,struct eap_peap_data * data,u8 id,int success)4773ff40c12SJohn Marino static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
4783ff40c12SJohn Marino 						  struct eap_peap_data *data,
4793ff40c12SJohn Marino 						  u8 id, int success)
4803ff40c12SJohn Marino {
4813ff40c12SJohn Marino 	struct wpabuf *encr_req, msgbuf;
4823ff40c12SJohn Marino 	size_t req_len;
4833ff40c12SJohn Marino 	struct eap_hdr *hdr;
4843ff40c12SJohn Marino 
4853ff40c12SJohn Marino 	req_len = sizeof(*hdr);
4863ff40c12SJohn Marino 	hdr = os_zalloc(req_len);
4873ff40c12SJohn Marino 	if (hdr == NULL)
4883ff40c12SJohn Marino 		return NULL;
4893ff40c12SJohn Marino 
4903ff40c12SJohn Marino 	hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
4913ff40c12SJohn Marino 	hdr->identifier = id;
4923ff40c12SJohn Marino 	hdr->length = host_to_be16(req_len);
4933ff40c12SJohn Marino 
4943ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
4953ff40c12SJohn Marino 			(u8 *) hdr, req_len);
4963ff40c12SJohn Marino 
4973ff40c12SJohn Marino 	wpabuf_set(&msgbuf, hdr, req_len);
4983ff40c12SJohn Marino 	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
4993ff40c12SJohn Marino 	os_free(hdr);
5003ff40c12SJohn Marino 
5013ff40c12SJohn Marino 	return encr_req;
5023ff40c12SJohn Marino }
5033ff40c12SJohn Marino 
5043ff40c12SJohn Marino 
eap_peap_buildReq(struct eap_sm * sm,void * priv,u8 id)5053ff40c12SJohn Marino static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
5063ff40c12SJohn Marino {
5073ff40c12SJohn Marino 	struct eap_peap_data *data = priv;
5083ff40c12SJohn Marino 
5093ff40c12SJohn Marino 	if (data->ssl.state == FRAG_ACK) {
5103ff40c12SJohn Marino 		return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
5113ff40c12SJohn Marino 						data->peap_version);
5123ff40c12SJohn Marino 	}
5133ff40c12SJohn Marino 
5143ff40c12SJohn Marino 	if (data->ssl.state == WAIT_FRAG_ACK) {
5153ff40c12SJohn Marino 		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
5163ff40c12SJohn Marino 						data->peap_version, id);
5173ff40c12SJohn Marino 	}
5183ff40c12SJohn Marino 
5193ff40c12SJohn Marino 	switch (data->state) {
5203ff40c12SJohn Marino 	case START:
5213ff40c12SJohn Marino 		return eap_peap_build_start(sm, data, id);
5223ff40c12SJohn Marino 	case PHASE1:
5233ff40c12SJohn Marino 	case PHASE1_ID2:
5243ff40c12SJohn Marino 		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
5253ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
5263ff40c12SJohn Marino 				   "starting Phase2");
5273ff40c12SJohn Marino 			eap_peap_state(data, PHASE2_START);
5283ff40c12SJohn Marino 		}
5293ff40c12SJohn Marino 		break;
5303ff40c12SJohn Marino 	case PHASE2_ID:
5313ff40c12SJohn Marino 	case PHASE2_METHOD:
5323ff40c12SJohn Marino 		wpabuf_free(data->ssl.tls_out);
5333ff40c12SJohn Marino 		data->ssl.tls_out_pos = 0;
5343ff40c12SJohn Marino 		data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
5353ff40c12SJohn Marino 		break;
5363ff40c12SJohn Marino #ifdef EAP_SERVER_TNC
5373ff40c12SJohn Marino 	case PHASE2_SOH:
5383ff40c12SJohn Marino 		wpabuf_free(data->ssl.tls_out);
5393ff40c12SJohn Marino 		data->ssl.tls_out_pos = 0;
5403ff40c12SJohn Marino 		data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id);
5413ff40c12SJohn Marino 		break;
5423ff40c12SJohn Marino #endif /* EAP_SERVER_TNC */
5433ff40c12SJohn Marino 	case PHASE2_TLV:
5443ff40c12SJohn Marino 		wpabuf_free(data->ssl.tls_out);
5453ff40c12SJohn Marino 		data->ssl.tls_out_pos = 0;
5463ff40c12SJohn Marino 		data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
5473ff40c12SJohn Marino 		break;
5483ff40c12SJohn Marino 	case SUCCESS_REQ:
5493ff40c12SJohn Marino 		wpabuf_free(data->ssl.tls_out);
5503ff40c12SJohn Marino 		data->ssl.tls_out_pos = 0;
5513ff40c12SJohn Marino 		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
5523ff40c12SJohn Marino 							       1);
5533ff40c12SJohn Marino 		break;
5543ff40c12SJohn Marino 	case FAILURE_REQ:
5553ff40c12SJohn Marino 		wpabuf_free(data->ssl.tls_out);
5563ff40c12SJohn Marino 		data->ssl.tls_out_pos = 0;
5573ff40c12SJohn Marino 		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
5583ff40c12SJohn Marino 							       0);
5593ff40c12SJohn Marino 		break;
5603ff40c12SJohn Marino 	default:
5613ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
5623ff40c12SJohn Marino 			   __func__, data->state);
5633ff40c12SJohn Marino 		return NULL;
5643ff40c12SJohn Marino 	}
5653ff40c12SJohn Marino 
5663ff40c12SJohn Marino 	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
5673ff40c12SJohn Marino 					data->peap_version, id);
5683ff40c12SJohn Marino }
5693ff40c12SJohn Marino 
5703ff40c12SJohn Marino 
eap_peap_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)5713ff40c12SJohn Marino static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
5723ff40c12SJohn Marino 			      struct wpabuf *respData)
5733ff40c12SJohn Marino {
5743ff40c12SJohn Marino 	const u8 *pos;
5753ff40c12SJohn Marino 	size_t len;
5763ff40c12SJohn Marino 
5773ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
5783ff40c12SJohn Marino 	if (pos == NULL || len < 1) {
5793ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
5803ff40c12SJohn Marino 		return TRUE;
5813ff40c12SJohn Marino 	}
5823ff40c12SJohn Marino 
5833ff40c12SJohn Marino 	return FALSE;
5843ff40c12SJohn Marino }
5853ff40c12SJohn Marino 
5863ff40c12SJohn Marino 
eap_peap_phase2_init(struct eap_sm * sm,struct eap_peap_data * data,int vendor,EapType eap_type)5873ff40c12SJohn Marino static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
588*a1157835SDaniel Fojt 				int vendor, EapType eap_type)
5893ff40c12SJohn Marino {
5903ff40c12SJohn Marino 	if (data->phase2_priv && data->phase2_method) {
5913ff40c12SJohn Marino 		data->phase2_method->reset(sm, data->phase2_priv);
5923ff40c12SJohn Marino 		data->phase2_method = NULL;
5933ff40c12SJohn Marino 		data->phase2_priv = NULL;
5943ff40c12SJohn Marino 	}
595*a1157835SDaniel Fojt 	data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
5963ff40c12SJohn Marino 	if (!data->phase2_method)
5973ff40c12SJohn Marino 		return -1;
5983ff40c12SJohn Marino 
5993ff40c12SJohn Marino 	sm->init_phase2 = 1;
6003ff40c12SJohn Marino 	data->phase2_priv = data->phase2_method->init(sm);
6013ff40c12SJohn Marino 	sm->init_phase2 = 0;
6023ff40c12SJohn Marino 	return 0;
6033ff40c12SJohn Marino }
6043ff40c12SJohn Marino 
6053ff40c12SJohn Marino 
eap_tlv_validate_cryptobinding(struct eap_sm * sm,struct eap_peap_data * data,const u8 * crypto_tlv,size_t crypto_tlv_len)6063ff40c12SJohn Marino static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
6073ff40c12SJohn Marino 					  struct eap_peap_data *data,
6083ff40c12SJohn Marino 					  const u8 *crypto_tlv,
6093ff40c12SJohn Marino 					  size_t crypto_tlv_len)
6103ff40c12SJohn Marino {
6113ff40c12SJohn Marino 	u8 buf[61], mac[SHA1_MAC_LEN];
6123ff40c12SJohn Marino 	const u8 *pos;
6133ff40c12SJohn Marino 
6143ff40c12SJohn Marino 	if (crypto_tlv_len != 4 + 56) {
6153ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
6163ff40c12SJohn Marino 			   "length %d", (int) crypto_tlv_len);
6173ff40c12SJohn Marino 		return -1;
6183ff40c12SJohn Marino 	}
6193ff40c12SJohn Marino 
6203ff40c12SJohn Marino 	pos = crypto_tlv;
6213ff40c12SJohn Marino 	pos += 4; /* TLV header */
6223ff40c12SJohn Marino 	if (pos[1] != data->peap_version) {
6233ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
6243ff40c12SJohn Marino 			   "mismatch (was %d; expected %d)",
6253ff40c12SJohn Marino 			   pos[1], data->peap_version);
6263ff40c12SJohn Marino 		return -1;
6273ff40c12SJohn Marino 	}
6283ff40c12SJohn Marino 
6293ff40c12SJohn Marino 	if (pos[3] != 1) {
6303ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
6313ff40c12SJohn Marino 			   "SubType %d", pos[3]);
6323ff40c12SJohn Marino 		return -1;
6333ff40c12SJohn Marino 	}
6343ff40c12SJohn Marino 	pos += 4;
6353ff40c12SJohn Marino 	pos += 32; /* Nonce */
6363ff40c12SJohn Marino 
6373ff40c12SJohn Marino 	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
6383ff40c12SJohn Marino 	os_memcpy(buf, crypto_tlv, 60);
6393ff40c12SJohn Marino 	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
6403ff40c12SJohn Marino 	buf[60] = EAP_TYPE_PEAP;
6413ff40c12SJohn Marino 	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
6423ff40c12SJohn Marino 
643*a1157835SDaniel Fojt 	if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
6443ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
6453ff40c12SJohn Marino 			   "cryptobinding TLV");
6463ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
6473ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
6483ff40c12SJohn Marino 			    buf, 61);
6493ff40c12SJohn Marino 		return -1;
6503ff40c12SJohn Marino 	}
6513ff40c12SJohn Marino 
6523ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
6533ff40c12SJohn Marino 
6543ff40c12SJohn Marino 	return 0;
6553ff40c12SJohn Marino }
6563ff40c12SJohn Marino 
6573ff40c12SJohn Marino 
eap_peap_process_phase2_tlv(struct eap_sm * sm,struct eap_peap_data * data,struct wpabuf * in_data)6583ff40c12SJohn Marino static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
6593ff40c12SJohn Marino 					struct eap_peap_data *data,
6603ff40c12SJohn Marino 					struct wpabuf *in_data)
6613ff40c12SJohn Marino {
6623ff40c12SJohn Marino 	const u8 *pos;
6633ff40c12SJohn Marino 	size_t left;
6643ff40c12SJohn Marino 	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
6653ff40c12SJohn Marino 	size_t result_tlv_len = 0, crypto_tlv_len = 0;
6663ff40c12SJohn Marino 	int tlv_type, mandatory, tlv_len;
6673ff40c12SJohn Marino 
6683ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
6693ff40c12SJohn Marino 	if (pos == NULL) {
6703ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
6713ff40c12SJohn Marino 		return;
6723ff40c12SJohn Marino 	}
6733ff40c12SJohn Marino 
6743ff40c12SJohn Marino 	/* Parse TLVs */
6753ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
6763ff40c12SJohn Marino 	while (left >= 4) {
6773ff40c12SJohn Marino 		mandatory = !!(pos[0] & 0x80);
6783ff40c12SJohn Marino 		tlv_type = pos[0] & 0x3f;
6793ff40c12SJohn Marino 		tlv_type = (tlv_type << 8) | pos[1];
6803ff40c12SJohn Marino 		tlv_len = ((int) pos[2] << 8) | pos[3];
6813ff40c12SJohn Marino 		pos += 4;
6823ff40c12SJohn Marino 		left -= 4;
6833ff40c12SJohn Marino 		if ((size_t) tlv_len > left) {
6843ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
6853ff40c12SJohn Marino 				   "(tlv_len=%d left=%lu)", tlv_len,
6863ff40c12SJohn Marino 				   (unsigned long) left);
6873ff40c12SJohn Marino 			eap_peap_state(data, FAILURE);
6883ff40c12SJohn Marino 			return;
6893ff40c12SJohn Marino 		}
6903ff40c12SJohn Marino 		switch (tlv_type) {
6913ff40c12SJohn Marino 		case EAP_TLV_RESULT_TLV:
6923ff40c12SJohn Marino 			result_tlv = pos;
6933ff40c12SJohn Marino 			result_tlv_len = tlv_len;
6943ff40c12SJohn Marino 			break;
6953ff40c12SJohn Marino 		case EAP_TLV_CRYPTO_BINDING_TLV:
6963ff40c12SJohn Marino 			crypto_tlv = pos;
6973ff40c12SJohn Marino 			crypto_tlv_len = tlv_len;
6983ff40c12SJohn Marino 			break;
6993ff40c12SJohn Marino 		default:
7003ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
7013ff40c12SJohn Marino 				   "%d%s", tlv_type,
7023ff40c12SJohn Marino 				   mandatory ? " (mandatory)" : "");
7033ff40c12SJohn Marino 			if (mandatory) {
7043ff40c12SJohn Marino 				eap_peap_state(data, FAILURE);
7053ff40c12SJohn Marino 				return;
7063ff40c12SJohn Marino 			}
7073ff40c12SJohn Marino 			/* Ignore this TLV, but process other TLVs */
7083ff40c12SJohn Marino 			break;
7093ff40c12SJohn Marino 		}
7103ff40c12SJohn Marino 
7113ff40c12SJohn Marino 		pos += tlv_len;
7123ff40c12SJohn Marino 		left -= tlv_len;
7133ff40c12SJohn Marino 	}
7143ff40c12SJohn Marino 	if (left) {
7153ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
7163ff40c12SJohn Marino 			   "Request (left=%lu)", (unsigned long) left);
7173ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
7183ff40c12SJohn Marino 		return;
7193ff40c12SJohn Marino 	}
7203ff40c12SJohn Marino 
7213ff40c12SJohn Marino 	/* Process supported TLVs */
7223ff40c12SJohn Marino 	if (crypto_tlv && data->crypto_binding_sent) {
7233ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
7243ff40c12SJohn Marino 			    crypto_tlv, crypto_tlv_len);
7253ff40c12SJohn Marino 		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
7263ff40c12SJohn Marino 						   crypto_tlv_len + 4) < 0) {
7273ff40c12SJohn Marino 			eap_peap_state(data, FAILURE);
7283ff40c12SJohn Marino 			return;
7293ff40c12SJohn Marino 		}
7303ff40c12SJohn Marino 		data->crypto_binding_used = 1;
7313ff40c12SJohn Marino 	} else if (!crypto_tlv && data->crypto_binding_sent &&
7323ff40c12SJohn Marino 		   data->crypto_binding == REQUIRE_BINDING) {
7333ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
7343ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
7353ff40c12SJohn Marino 		return;
7363ff40c12SJohn Marino 	}
7373ff40c12SJohn Marino 
7383ff40c12SJohn Marino 	if (result_tlv) {
7393ff40c12SJohn Marino 		int status;
7403ff40c12SJohn Marino 		const char *requested;
7413ff40c12SJohn Marino 
7423ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
7433ff40c12SJohn Marino 			    result_tlv, result_tlv_len);
7443ff40c12SJohn Marino 		if (result_tlv_len < 2) {
7453ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
7463ff40c12SJohn Marino 				   "(len=%lu)",
7473ff40c12SJohn Marino 				   (unsigned long) result_tlv_len);
7483ff40c12SJohn Marino 			eap_peap_state(data, FAILURE);
7493ff40c12SJohn Marino 			return;
7503ff40c12SJohn Marino 		}
7513ff40c12SJohn Marino 		requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
7523ff40c12SJohn Marino 			"Failure";
7533ff40c12SJohn Marino 		status = WPA_GET_BE16(result_tlv);
7543ff40c12SJohn Marino 		if (status == EAP_TLV_RESULT_SUCCESS) {
7553ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
7563ff40c12SJohn Marino 				   "- requested %s", requested);
757*a1157835SDaniel Fojt 			if (data->tlv_request == TLV_REQ_SUCCESS) {
7583ff40c12SJohn Marino 				eap_peap_state(data, SUCCESS);
759*a1157835SDaniel Fojt 				eap_peap_valid_session(sm, data);
760*a1157835SDaniel Fojt 			} else {
7613ff40c12SJohn Marino 				eap_peap_state(data, FAILURE);
762*a1157835SDaniel Fojt 			}
7633ff40c12SJohn Marino 
7643ff40c12SJohn Marino 		} else if (status == EAP_TLV_RESULT_FAILURE) {
7653ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
7663ff40c12SJohn Marino 				   "- requested %s", requested);
7673ff40c12SJohn Marino 			eap_peap_state(data, FAILURE);
7683ff40c12SJohn Marino 		} else {
7693ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
7703ff40c12SJohn Marino 				   "Status %d", status);
7713ff40c12SJohn Marino 			eap_peap_state(data, FAILURE);
7723ff40c12SJohn Marino 		}
7733ff40c12SJohn Marino 	}
7743ff40c12SJohn Marino }
7753ff40c12SJohn Marino 
7763ff40c12SJohn Marino 
7773ff40c12SJohn Marino #ifdef EAP_SERVER_TNC
eap_peap_process_phase2_soh(struct eap_sm * sm,struct eap_peap_data * data,struct wpabuf * in_data)7783ff40c12SJohn Marino static void eap_peap_process_phase2_soh(struct eap_sm *sm,
7793ff40c12SJohn Marino 					struct eap_peap_data *data,
7803ff40c12SJohn Marino 					struct wpabuf *in_data)
7813ff40c12SJohn Marino {
7823ff40c12SJohn Marino 	const u8 *pos, *vpos;
7833ff40c12SJohn Marino 	size_t left;
7843ff40c12SJohn Marino 	const u8 *soh_tlv = NULL;
7853ff40c12SJohn Marino 	size_t soh_tlv_len = 0;
7863ff40c12SJohn Marino 	int tlv_type, mandatory, tlv_len, vtlv_len;
787*a1157835SDaniel Fojt 	u32 next_type;
7883ff40c12SJohn Marino 	u32 vendor_id;
7893ff40c12SJohn Marino 
7903ff40c12SJohn Marino 	pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
7913ff40c12SJohn Marino 	if (pos == NULL) {
7923ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
7933ff40c12SJohn Marino 			   "Extensions Method header - skip TNC");
7943ff40c12SJohn Marino 		goto auth_method;
7953ff40c12SJohn Marino 	}
7963ff40c12SJohn Marino 
7973ff40c12SJohn Marino 	/* Parse TLVs */
7983ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
7993ff40c12SJohn Marino 	while (left >= 4) {
8003ff40c12SJohn Marino 		mandatory = !!(pos[0] & 0x80);
8013ff40c12SJohn Marino 		tlv_type = pos[0] & 0x3f;
8023ff40c12SJohn Marino 		tlv_type = (tlv_type << 8) | pos[1];
8033ff40c12SJohn Marino 		tlv_len = ((int) pos[2] << 8) | pos[3];
8043ff40c12SJohn Marino 		pos += 4;
8053ff40c12SJohn Marino 		left -= 4;
8063ff40c12SJohn Marino 		if ((size_t) tlv_len > left) {
8073ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
8083ff40c12SJohn Marino 				   "(tlv_len=%d left=%lu)", tlv_len,
8093ff40c12SJohn Marino 				   (unsigned long) left);
8103ff40c12SJohn Marino 			eap_peap_state(data, FAILURE);
8113ff40c12SJohn Marino 			return;
8123ff40c12SJohn Marino 		}
8133ff40c12SJohn Marino 		switch (tlv_type) {
8143ff40c12SJohn Marino 		case EAP_TLV_VENDOR_SPECIFIC_TLV:
8153ff40c12SJohn Marino 			if (tlv_len < 4) {
8163ff40c12SJohn Marino 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
8173ff40c12SJohn Marino 					   "vendor specific TLV (len=%d)",
8183ff40c12SJohn Marino 					   (int) tlv_len);
8193ff40c12SJohn Marino 				eap_peap_state(data, FAILURE);
8203ff40c12SJohn Marino 				return;
8213ff40c12SJohn Marino 			}
8223ff40c12SJohn Marino 
8233ff40c12SJohn Marino 			vendor_id = WPA_GET_BE32(pos);
8243ff40c12SJohn Marino 			if (vendor_id != EAP_VENDOR_MICROSOFT) {
8253ff40c12SJohn Marino 				if (mandatory) {
8263ff40c12SJohn Marino 					eap_peap_state(data, FAILURE);
8273ff40c12SJohn Marino 					return;
8283ff40c12SJohn Marino 				}
8293ff40c12SJohn Marino 				break;
8303ff40c12SJohn Marino 			}
8313ff40c12SJohn Marino 
8323ff40c12SJohn Marino 			vpos = pos + 4;
8333ff40c12SJohn Marino 			mandatory = !!(vpos[0] & 0x80);
8343ff40c12SJohn Marino 			tlv_type = vpos[0] & 0x3f;
8353ff40c12SJohn Marino 			tlv_type = (tlv_type << 8) | vpos[1];
8363ff40c12SJohn Marino 			vtlv_len = ((int) vpos[2] << 8) | vpos[3];
8373ff40c12SJohn Marino 			vpos += 4;
8383ff40c12SJohn Marino 			if (vpos + vtlv_len > pos + left) {
8393ff40c12SJohn Marino 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
8403ff40c12SJohn Marino 					   "underrun");
8413ff40c12SJohn Marino 				eap_peap_state(data, FAILURE);
8423ff40c12SJohn Marino 				return;
8433ff40c12SJohn Marino 			}
8443ff40c12SJohn Marino 
8453ff40c12SJohn Marino 			if (tlv_type == 1) {
8463ff40c12SJohn Marino 				soh_tlv = vpos;
8473ff40c12SJohn Marino 				soh_tlv_len = vtlv_len;
8483ff40c12SJohn Marino 				break;
8493ff40c12SJohn Marino 			}
8503ff40c12SJohn Marino 
8513ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
8523ff40c12SJohn Marino 				   "Type %d%s", tlv_type,
8533ff40c12SJohn Marino 				   mandatory ? " (mandatory)" : "");
8543ff40c12SJohn Marino 			if (mandatory) {
8553ff40c12SJohn Marino 				eap_peap_state(data, FAILURE);
8563ff40c12SJohn Marino 				return;
8573ff40c12SJohn Marino 			}
8583ff40c12SJohn Marino 			/* Ignore this TLV, but process other TLVs */
8593ff40c12SJohn Marino 			break;
8603ff40c12SJohn Marino 		default:
8613ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
8623ff40c12SJohn Marino 				   "%d%s", tlv_type,
8633ff40c12SJohn Marino 				   mandatory ? " (mandatory)" : "");
8643ff40c12SJohn Marino 			if (mandatory) {
8653ff40c12SJohn Marino 				eap_peap_state(data, FAILURE);
8663ff40c12SJohn Marino 				return;
8673ff40c12SJohn Marino 			}
8683ff40c12SJohn Marino 			/* Ignore this TLV, but process other TLVs */
8693ff40c12SJohn Marino 			break;
8703ff40c12SJohn Marino 		}
8713ff40c12SJohn Marino 
8723ff40c12SJohn Marino 		pos += tlv_len;
8733ff40c12SJohn Marino 		left -= tlv_len;
8743ff40c12SJohn Marino 	}
8753ff40c12SJohn Marino 	if (left) {
8763ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
8773ff40c12SJohn Marino 			   "Request (left=%lu)", (unsigned long) left);
8783ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
8793ff40c12SJohn Marino 		return;
8803ff40c12SJohn Marino 	}
8813ff40c12SJohn Marino 
8823ff40c12SJohn Marino 	/* Process supported TLVs */
8833ff40c12SJohn Marino 	if (soh_tlv) {
8843ff40c12SJohn Marino 		int failure = 0;
8853ff40c12SJohn Marino 		wpabuf_free(data->soh_response);
8863ff40c12SJohn Marino 		data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
8873ff40c12SJohn Marino 						      &failure);
8883ff40c12SJohn Marino 		if (failure) {
8893ff40c12SJohn Marino 			eap_peap_state(data, FAILURE);
8903ff40c12SJohn Marino 			return;
8913ff40c12SJohn Marino 		}
8923ff40c12SJohn Marino 	} else {
8933ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
8943ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
8953ff40c12SJohn Marino 		return;
8963ff40c12SJohn Marino 	}
8973ff40c12SJohn Marino 
8983ff40c12SJohn Marino auth_method:
8993ff40c12SJohn Marino 	eap_peap_state(data, PHASE2_METHOD);
9003ff40c12SJohn Marino 	next_type = sm->user->methods[0].method;
9013ff40c12SJohn Marino 	sm->user_eap_method_index = 1;
902*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type %d",
903*a1157835SDaniel Fojt 		   sm->user->methods[0].vendor, next_type);
904*a1157835SDaniel Fojt 	eap_peap_phase2_init(sm, data, sm->user->methods[0].vendor, next_type);
9053ff40c12SJohn Marino }
9063ff40c12SJohn Marino #endif /* EAP_SERVER_TNC */
9073ff40c12SJohn Marino 
9083ff40c12SJohn Marino 
eap_peap_process_phase2_response(struct eap_sm * sm,struct eap_peap_data * data,struct wpabuf * in_data)9093ff40c12SJohn Marino static void eap_peap_process_phase2_response(struct eap_sm *sm,
9103ff40c12SJohn Marino 					     struct eap_peap_data *data,
9113ff40c12SJohn Marino 					     struct wpabuf *in_data)
9123ff40c12SJohn Marino {
913*a1157835SDaniel Fojt 	int next_vendor = EAP_VENDOR_IETF;
914*a1157835SDaniel Fojt 	u32 next_type = EAP_TYPE_NONE;
9153ff40c12SJohn Marino 	const struct eap_hdr *hdr;
9163ff40c12SJohn Marino 	const u8 *pos;
9173ff40c12SJohn Marino 	size_t left;
9183ff40c12SJohn Marino 
9193ff40c12SJohn Marino 	if (data->state == PHASE2_TLV) {
9203ff40c12SJohn Marino 		eap_peap_process_phase2_tlv(sm, data, in_data);
9213ff40c12SJohn Marino 		return;
9223ff40c12SJohn Marino 	}
9233ff40c12SJohn Marino 
9243ff40c12SJohn Marino #ifdef EAP_SERVER_TNC
9253ff40c12SJohn Marino 	if (data->state == PHASE2_SOH) {
9263ff40c12SJohn Marino 		eap_peap_process_phase2_soh(sm, data, in_data);
9273ff40c12SJohn Marino 		return;
9283ff40c12SJohn Marino 	}
9293ff40c12SJohn Marino #endif /* EAP_SERVER_TNC */
9303ff40c12SJohn Marino 
9313ff40c12SJohn Marino 	if (data->phase2_priv == NULL) {
9323ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
9333ff40c12SJohn Marino 			   "initialized?!", __func__);
9343ff40c12SJohn Marino 		return;
9353ff40c12SJohn Marino 	}
9363ff40c12SJohn Marino 
9373ff40c12SJohn Marino 	hdr = wpabuf_head(in_data);
9383ff40c12SJohn Marino 	pos = (const u8 *) (hdr + 1);
9393ff40c12SJohn Marino 
9403ff40c12SJohn Marino 	if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
9413ff40c12SJohn Marino 		left = wpabuf_len(in_data) - sizeof(*hdr);
9423ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
9433ff40c12SJohn Marino 			    "allowed types", pos + 1, left - 1);
9443ff40c12SJohn Marino 		eap_sm_process_nak(sm, pos + 1, left - 1);
9453ff40c12SJohn Marino 		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
946*a1157835SDaniel Fojt 		    (sm->user->methods[sm->user_eap_method_index].vendor !=
947*a1157835SDaniel Fojt 		     EAP_VENDOR_IETF ||
9483ff40c12SJohn Marino 		     sm->user->methods[sm->user_eap_method_index].method !=
949*a1157835SDaniel Fojt 		     EAP_TYPE_NONE)) {
950*a1157835SDaniel Fojt 			next_vendor = sm->user->methods[
951*a1157835SDaniel Fojt 				sm->user_eap_method_index].vendor;
9523ff40c12SJohn Marino 			next_type = sm->user->methods[
9533ff40c12SJohn Marino 				sm->user_eap_method_index++].method;
954*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
955*a1157835SDaniel Fojt 				   "EAP-PEAP: try EAP vendor %d type 0x%x",
956*a1157835SDaniel Fojt 				   next_vendor, next_type);
9573ff40c12SJohn Marino 		} else {
9583ff40c12SJohn Marino 			eap_peap_req_failure(sm, data);
959*a1157835SDaniel Fojt 			next_vendor = EAP_VENDOR_IETF;
9603ff40c12SJohn Marino 			next_type = EAP_TYPE_NONE;
9613ff40c12SJohn Marino 		}
962*a1157835SDaniel Fojt 		eap_peap_phase2_init(sm, data, next_vendor, next_type);
9633ff40c12SJohn Marino 		return;
9643ff40c12SJohn Marino 	}
9653ff40c12SJohn Marino 
9663ff40c12SJohn Marino 	if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
9673ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
9683ff40c12SJohn Marino 			   "ignore the packet");
9693ff40c12SJohn Marino 		return;
9703ff40c12SJohn Marino 	}
9713ff40c12SJohn Marino 
9723ff40c12SJohn Marino 	data->phase2_method->process(sm, data->phase2_priv, in_data);
9733ff40c12SJohn Marino 
9743ff40c12SJohn Marino 	if (sm->method_pending == METHOD_PENDING_WAIT) {
9753ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
9763ff40c12SJohn Marino 			   "pending wait state - save decrypted response");
9773ff40c12SJohn Marino 		wpabuf_free(data->pending_phase2_resp);
9783ff40c12SJohn Marino 		data->pending_phase2_resp = wpabuf_dup(in_data);
9793ff40c12SJohn Marino 	}
9803ff40c12SJohn Marino 
9813ff40c12SJohn Marino 	if (!data->phase2_method->isDone(sm, data->phase2_priv))
9823ff40c12SJohn Marino 		return;
9833ff40c12SJohn Marino 
9843ff40c12SJohn Marino 	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
9853ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
9863ff40c12SJohn Marino 		eap_peap_req_failure(sm, data);
987*a1157835SDaniel Fojt 		next_vendor = EAP_VENDOR_IETF;
9883ff40c12SJohn Marino 		next_type = EAP_TYPE_NONE;
989*a1157835SDaniel Fojt 		eap_peap_phase2_init(sm, data, next_vendor, next_type);
9903ff40c12SJohn Marino 		return;
9913ff40c12SJohn Marino 	}
9923ff40c12SJohn Marino 
9933ff40c12SJohn Marino 	os_free(data->phase2_key);
9943ff40c12SJohn Marino 	if (data->phase2_method->getKey) {
9953ff40c12SJohn Marino 		data->phase2_key = data->phase2_method->getKey(
9963ff40c12SJohn Marino 			sm, data->phase2_priv, &data->phase2_key_len);
9973ff40c12SJohn Marino 		if (data->phase2_key == NULL) {
9983ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
9993ff40c12SJohn Marino 				   "failed");
10003ff40c12SJohn Marino 			eap_peap_req_failure(sm, data);
1001*a1157835SDaniel Fojt 			eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
1002*a1157835SDaniel Fojt 					     EAP_TYPE_NONE);
10033ff40c12SJohn Marino 			return;
10043ff40c12SJohn Marino 		}
10053ff40c12SJohn Marino 	}
10063ff40c12SJohn Marino 
10073ff40c12SJohn Marino 	switch (data->state) {
10083ff40c12SJohn Marino 	case PHASE1_ID2:
10093ff40c12SJohn Marino 	case PHASE2_ID:
10103ff40c12SJohn Marino 	case PHASE2_SOH:
10113ff40c12SJohn Marino 		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
10123ff40c12SJohn Marino 			wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
10133ff40c12SJohn Marino 					  "Identity not found in the user "
10143ff40c12SJohn Marino 					  "database",
10153ff40c12SJohn Marino 					  sm->identity, sm->identity_len);
10163ff40c12SJohn Marino 			eap_peap_req_failure(sm, data);
1017*a1157835SDaniel Fojt 			next_vendor = EAP_VENDOR_IETF;
10183ff40c12SJohn Marino 			next_type = EAP_TYPE_NONE;
10193ff40c12SJohn Marino 			break;
10203ff40c12SJohn Marino 		}
10213ff40c12SJohn Marino 
10223ff40c12SJohn Marino #ifdef EAP_SERVER_TNC
10233ff40c12SJohn Marino 		if (data->state != PHASE2_SOH && sm->tnc &&
10243ff40c12SJohn Marino 		    data->peap_version == 0) {
10253ff40c12SJohn Marino 			eap_peap_state(data, PHASE2_SOH);
10263ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
10273ff40c12SJohn Marino 				   "TNC (NAP SOH)");
1028*a1157835SDaniel Fojt 			next_vendor = EAP_VENDOR_IETF;
10293ff40c12SJohn Marino 			next_type = EAP_TYPE_NONE;
10303ff40c12SJohn Marino 			break;
10313ff40c12SJohn Marino 		}
10323ff40c12SJohn Marino #endif /* EAP_SERVER_TNC */
10333ff40c12SJohn Marino 
10343ff40c12SJohn Marino 		eap_peap_state(data, PHASE2_METHOD);
1035*a1157835SDaniel Fojt 		next_vendor = sm->user->methods[0].vendor;
10363ff40c12SJohn Marino 		next_type = sm->user->methods[0].method;
10373ff40c12SJohn Marino 		sm->user_eap_method_index = 1;
1038*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x",
1039*a1157835SDaniel Fojt 			   next_vendor, next_type);
10403ff40c12SJohn Marino 		break;
10413ff40c12SJohn Marino 	case PHASE2_METHOD:
10423ff40c12SJohn Marino 		eap_peap_req_success(sm, data);
1043*a1157835SDaniel Fojt 		next_vendor = EAP_VENDOR_IETF;
10443ff40c12SJohn Marino 		next_type = EAP_TYPE_NONE;
10453ff40c12SJohn Marino 		break;
10463ff40c12SJohn Marino 	case FAILURE:
10473ff40c12SJohn Marino 		break;
10483ff40c12SJohn Marino 	default:
10493ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
10503ff40c12SJohn Marino 			   __func__, data->state);
10513ff40c12SJohn Marino 		break;
10523ff40c12SJohn Marino 	}
10533ff40c12SJohn Marino 
1054*a1157835SDaniel Fojt 	eap_peap_phase2_init(sm, data, next_vendor, next_type);
10553ff40c12SJohn Marino }
10563ff40c12SJohn Marino 
10573ff40c12SJohn Marino 
eap_peap_process_phase2(struct eap_sm * sm,struct eap_peap_data * data,const struct wpabuf * respData,struct wpabuf * in_buf)10583ff40c12SJohn Marino static void eap_peap_process_phase2(struct eap_sm *sm,
10593ff40c12SJohn Marino 				    struct eap_peap_data *data,
10603ff40c12SJohn Marino 				    const struct wpabuf *respData,
10613ff40c12SJohn Marino 				    struct wpabuf *in_buf)
10623ff40c12SJohn Marino {
10633ff40c12SJohn Marino 	struct wpabuf *in_decrypted;
10643ff40c12SJohn Marino 	const struct eap_hdr *hdr;
10653ff40c12SJohn Marino 	size_t len;
10663ff40c12SJohn Marino 
10673ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
10683ff40c12SJohn Marino 		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
10693ff40c12SJohn Marino 
10703ff40c12SJohn Marino 	if (data->pending_phase2_resp) {
10713ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
10723ff40c12SJohn Marino 			   "skip decryption and use old data");
10733ff40c12SJohn Marino 		eap_peap_process_phase2_response(sm, data,
10743ff40c12SJohn Marino 						 data->pending_phase2_resp);
10753ff40c12SJohn Marino 		wpabuf_free(data->pending_phase2_resp);
10763ff40c12SJohn Marino 		data->pending_phase2_resp = NULL;
10773ff40c12SJohn Marino 		return;
10783ff40c12SJohn Marino 	}
10793ff40c12SJohn Marino 
10803ff40c12SJohn Marino 	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
10813ff40c12SJohn Marino 					      in_buf);
10823ff40c12SJohn Marino 	if (in_decrypted == NULL) {
10833ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
10843ff40c12SJohn Marino 			   "data");
10853ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
10863ff40c12SJohn Marino 		return;
10873ff40c12SJohn Marino 	}
10883ff40c12SJohn Marino 
10893ff40c12SJohn Marino 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
10903ff40c12SJohn Marino 			    in_decrypted);
10913ff40c12SJohn Marino 
10923ff40c12SJohn Marino 	if (data->peap_version == 0 && data->state != PHASE2_TLV) {
10933ff40c12SJohn Marino 		const struct eap_hdr *resp;
10943ff40c12SJohn Marino 		struct eap_hdr *nhdr;
10953ff40c12SJohn Marino 		struct wpabuf *nbuf =
10963ff40c12SJohn Marino 			wpabuf_alloc(sizeof(struct eap_hdr) +
10973ff40c12SJohn Marino 				     wpabuf_len(in_decrypted));
10983ff40c12SJohn Marino 		if (nbuf == NULL) {
10993ff40c12SJohn Marino 			wpabuf_free(in_decrypted);
11003ff40c12SJohn Marino 			return;
11013ff40c12SJohn Marino 		}
11023ff40c12SJohn Marino 
11033ff40c12SJohn Marino 		resp = wpabuf_head(respData);
11043ff40c12SJohn Marino 		nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
11053ff40c12SJohn Marino 		nhdr->code = resp->code;
11063ff40c12SJohn Marino 		nhdr->identifier = resp->identifier;
11073ff40c12SJohn Marino 		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
11083ff40c12SJohn Marino 					    wpabuf_len(in_decrypted));
11093ff40c12SJohn Marino 		wpabuf_put_buf(nbuf, in_decrypted);
11103ff40c12SJohn Marino 		wpabuf_free(in_decrypted);
11113ff40c12SJohn Marino 
11123ff40c12SJohn Marino 		in_decrypted = nbuf;
11133ff40c12SJohn Marino 	}
11143ff40c12SJohn Marino 
11153ff40c12SJohn Marino 	hdr = wpabuf_head(in_decrypted);
11163ff40c12SJohn Marino 	if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) {
11173ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
11183ff40c12SJohn Marino 			   "EAP frame (len=%lu)",
11193ff40c12SJohn Marino 			   (unsigned long) wpabuf_len(in_decrypted));
11203ff40c12SJohn Marino 		wpabuf_free(in_decrypted);
11213ff40c12SJohn Marino 		eap_peap_req_failure(sm, data);
11223ff40c12SJohn Marino 		return;
11233ff40c12SJohn Marino 	}
11243ff40c12SJohn Marino 	len = be_to_host16(hdr->length);
11253ff40c12SJohn Marino 	if (len > wpabuf_len(in_decrypted)) {
11263ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
11273ff40c12SJohn Marino 			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
11283ff40c12SJohn Marino 			   (unsigned long) wpabuf_len(in_decrypted),
11293ff40c12SJohn Marino 			   (unsigned long) len);
11303ff40c12SJohn Marino 		wpabuf_free(in_decrypted);
11313ff40c12SJohn Marino 		eap_peap_req_failure(sm, data);
11323ff40c12SJohn Marino 		return;
11333ff40c12SJohn Marino 	}
11343ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
11353ff40c12SJohn Marino 		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
11363ff40c12SJohn Marino 		   (unsigned long) len);
11373ff40c12SJohn Marino 	switch (hdr->code) {
11383ff40c12SJohn Marino 	case EAP_CODE_RESPONSE:
11393ff40c12SJohn Marino 		eap_peap_process_phase2_response(sm, data, in_decrypted);
11403ff40c12SJohn Marino 		break;
11413ff40c12SJohn Marino 	case EAP_CODE_SUCCESS:
11423ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
11433ff40c12SJohn Marino 		if (data->state == SUCCESS_REQ) {
11443ff40c12SJohn Marino 			eap_peap_state(data, SUCCESS);
1145*a1157835SDaniel Fojt 			eap_peap_valid_session(sm, data);
11463ff40c12SJohn Marino 		}
11473ff40c12SJohn Marino 		break;
11483ff40c12SJohn Marino 	case EAP_CODE_FAILURE:
11493ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
11503ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
11513ff40c12SJohn Marino 		break;
11523ff40c12SJohn Marino 	default:
11533ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
11543ff40c12SJohn Marino 			   "Phase 2 EAP header", hdr->code);
11553ff40c12SJohn Marino 		break;
11563ff40c12SJohn Marino 	}
11573ff40c12SJohn Marino 
11583ff40c12SJohn Marino 	wpabuf_free(in_decrypted);
11593ff40c12SJohn Marino }
11603ff40c12SJohn Marino 
11613ff40c12SJohn Marino 
eap_peap_process_version(struct eap_sm * sm,void * priv,int peer_version)11623ff40c12SJohn Marino static int eap_peap_process_version(struct eap_sm *sm, void *priv,
11633ff40c12SJohn Marino 				    int peer_version)
11643ff40c12SJohn Marino {
11653ff40c12SJohn Marino 	struct eap_peap_data *data = priv;
11663ff40c12SJohn Marino 
11673ff40c12SJohn Marino 	data->recv_version = peer_version;
11683ff40c12SJohn Marino 	if (data->force_version >= 0 && peer_version != data->force_version) {
11693ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
11703ff40c12SJohn Marino 			   " version (forced=%d peer=%d) - reject",
11713ff40c12SJohn Marino 			   data->force_version, peer_version);
11723ff40c12SJohn Marino 		return -1;
11733ff40c12SJohn Marino 	}
11743ff40c12SJohn Marino 	if (peer_version < data->peap_version) {
11753ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
11763ff40c12SJohn Marino 			   "use version %d",
11773ff40c12SJohn Marino 			   peer_version, data->peap_version, peer_version);
11783ff40c12SJohn Marino 		data->peap_version = peer_version;
11793ff40c12SJohn Marino 	}
11803ff40c12SJohn Marino 
11813ff40c12SJohn Marino 	return 0;
11823ff40c12SJohn Marino }
11833ff40c12SJohn Marino 
11843ff40c12SJohn Marino 
eap_peap_process_msg(struct eap_sm * sm,void * priv,const struct wpabuf * respData)11853ff40c12SJohn Marino static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
11863ff40c12SJohn Marino 				 const struct wpabuf *respData)
11873ff40c12SJohn Marino {
11883ff40c12SJohn Marino 	struct eap_peap_data *data = priv;
11893ff40c12SJohn Marino 
11903ff40c12SJohn Marino 	switch (data->state) {
11913ff40c12SJohn Marino 	case PHASE1:
11923ff40c12SJohn Marino 		if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
11933ff40c12SJohn Marino 			eap_peap_state(data, FAILURE);
11943ff40c12SJohn Marino 			break;
11953ff40c12SJohn Marino 		}
11963ff40c12SJohn Marino 		break;
11973ff40c12SJohn Marino 	case PHASE2_START:
11983ff40c12SJohn Marino 		eap_peap_state(data, PHASE2_ID);
1199*a1157835SDaniel Fojt 		eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
1200*a1157835SDaniel Fojt 				     EAP_TYPE_IDENTITY);
12013ff40c12SJohn Marino 		break;
12023ff40c12SJohn Marino 	case PHASE1_ID2:
12033ff40c12SJohn Marino 	case PHASE2_ID:
12043ff40c12SJohn Marino 	case PHASE2_METHOD:
12053ff40c12SJohn Marino 	case PHASE2_SOH:
12063ff40c12SJohn Marino 	case PHASE2_TLV:
12073ff40c12SJohn Marino 		eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
12083ff40c12SJohn Marino 		break;
12093ff40c12SJohn Marino 	case SUCCESS_REQ:
12103ff40c12SJohn Marino 		eap_peap_state(data, SUCCESS);
1211*a1157835SDaniel Fojt 		eap_peap_valid_session(sm, data);
12123ff40c12SJohn Marino 		break;
12133ff40c12SJohn Marino 	case FAILURE_REQ:
12143ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
12153ff40c12SJohn Marino 		break;
12163ff40c12SJohn Marino 	default:
12173ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
12183ff40c12SJohn Marino 			   data->state, __func__);
12193ff40c12SJohn Marino 		break;
12203ff40c12SJohn Marino 	}
12213ff40c12SJohn Marino }
12223ff40c12SJohn Marino 
12233ff40c12SJohn Marino 
eap_peap_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)12243ff40c12SJohn Marino static void eap_peap_process(struct eap_sm *sm, void *priv,
12253ff40c12SJohn Marino 			     struct wpabuf *respData)
12263ff40c12SJohn Marino {
12273ff40c12SJohn Marino 	struct eap_peap_data *data = priv;
1228*a1157835SDaniel Fojt 	const struct wpabuf *buf;
1229*a1157835SDaniel Fojt 	const u8 *pos;
1230*a1157835SDaniel Fojt 	u8 id_len;
1231*a1157835SDaniel Fojt 
12323ff40c12SJohn Marino 	if (eap_server_tls_process(sm, &data->ssl, respData, data,
12333ff40c12SJohn Marino 				   EAP_TYPE_PEAP, eap_peap_process_version,
1234*a1157835SDaniel Fojt 				   eap_peap_process_msg) < 0) {
12353ff40c12SJohn Marino 		eap_peap_state(data, FAILURE);
1236*a1157835SDaniel Fojt 		return;
1237*a1157835SDaniel Fojt 	}
1238*a1157835SDaniel Fojt 
1239*a1157835SDaniel Fojt 	if (data->state == SUCCESS ||
1240*a1157835SDaniel Fojt 	    !tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
1241*a1157835SDaniel Fojt 	    !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
1242*a1157835SDaniel Fojt 		return;
1243*a1157835SDaniel Fojt 
1244*a1157835SDaniel Fojt 	buf = tls_connection_get_success_data(data->ssl.conn);
1245*a1157835SDaniel Fojt 	if (!buf || wpabuf_len(buf) < 2) {
1246*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1247*a1157835SDaniel Fojt 			   "EAP-PEAP: No success data in resumed session - reject attempt");
1248*a1157835SDaniel Fojt 		eap_peap_state(data, FAILURE);
1249*a1157835SDaniel Fojt 		return;
1250*a1157835SDaniel Fojt 	}
1251*a1157835SDaniel Fojt 
1252*a1157835SDaniel Fojt 	pos = wpabuf_head(buf);
1253*a1157835SDaniel Fojt 	if (*pos != EAP_TYPE_PEAP) {
1254*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1255*a1157835SDaniel Fojt 			   "EAP-PEAP: Resumed session for another EAP type (%u) - reject attempt",
1256*a1157835SDaniel Fojt 			   *pos);
1257*a1157835SDaniel Fojt 		eap_peap_state(data, FAILURE);
1258*a1157835SDaniel Fojt 		return;
1259*a1157835SDaniel Fojt 	}
1260*a1157835SDaniel Fojt 
1261*a1157835SDaniel Fojt 	pos++;
1262*a1157835SDaniel Fojt 	id_len = *pos++;
1263*a1157835SDaniel Fojt 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PEAP: Identity from cached session",
1264*a1157835SDaniel Fojt 			  pos, id_len);
1265*a1157835SDaniel Fojt 	os_free(sm->identity);
1266*a1157835SDaniel Fojt 	sm->identity = os_malloc(id_len ? id_len : 1);
1267*a1157835SDaniel Fojt 	if (!sm->identity) {
1268*a1157835SDaniel Fojt 		sm->identity_len = 0;
1269*a1157835SDaniel Fojt 		eap_peap_state(data, FAILURE);
1270*a1157835SDaniel Fojt 		return;
1271*a1157835SDaniel Fojt 	}
1272*a1157835SDaniel Fojt 
1273*a1157835SDaniel Fojt 	os_memcpy(sm->identity, pos, id_len);
1274*a1157835SDaniel Fojt 	sm->identity_len = id_len;
1275*a1157835SDaniel Fojt 
1276*a1157835SDaniel Fojt 	if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
1277*a1157835SDaniel Fojt 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PEAP: Phase2 Identity not found in the user database",
1278*a1157835SDaniel Fojt 				  sm->identity, sm->identity_len);
1279*a1157835SDaniel Fojt 		eap_peap_state(data, FAILURE);
1280*a1157835SDaniel Fojt 		return;
1281*a1157835SDaniel Fojt 	}
1282*a1157835SDaniel Fojt 
1283*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
1284*a1157835SDaniel Fojt 		   "EAP-PEAP: Resuming previous session - skip Phase2");
1285*a1157835SDaniel Fojt 	eap_peap_req_success(sm, data);
1286*a1157835SDaniel Fojt 	if (data->state == SUCCESS_REQ)
1287*a1157835SDaniel Fojt 		tls_connection_set_success_data_resumed(data->ssl.conn);
12883ff40c12SJohn Marino }
12893ff40c12SJohn Marino 
12903ff40c12SJohn Marino 
eap_peap_isDone(struct eap_sm * sm,void * priv)12913ff40c12SJohn Marino static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
12923ff40c12SJohn Marino {
12933ff40c12SJohn Marino 	struct eap_peap_data *data = priv;
12943ff40c12SJohn Marino 	return data->state == SUCCESS || data->state == FAILURE;
12953ff40c12SJohn Marino }
12963ff40c12SJohn Marino 
12973ff40c12SJohn Marino 
eap_peap_getKey(struct eap_sm * sm,void * priv,size_t * len)12983ff40c12SJohn Marino static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
12993ff40c12SJohn Marino {
13003ff40c12SJohn Marino 	struct eap_peap_data *data = priv;
13013ff40c12SJohn Marino 	u8 *eapKeyData;
13023ff40c12SJohn Marino 
13033ff40c12SJohn Marino 	if (data->state != SUCCESS)
13043ff40c12SJohn Marino 		return NULL;
13053ff40c12SJohn Marino 
13063ff40c12SJohn Marino 	if (data->crypto_binding_used) {
13073ff40c12SJohn Marino 		u8 csk[128];
13083ff40c12SJohn Marino 		/*
13093ff40c12SJohn Marino 		 * Note: It looks like Microsoft implementation requires null
13103ff40c12SJohn Marino 		 * termination for this label while the one used for deriving
13113ff40c12SJohn Marino 		 * IPMK|CMK did not use null termination.
13123ff40c12SJohn Marino 		 */
13133ff40c12SJohn Marino 		if (peap_prfplus(data->peap_version, data->ipmk, 40,
13143ff40c12SJohn Marino 				 "Session Key Generating Function",
13153ff40c12SJohn Marino 				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
13163ff40c12SJohn Marino 			return NULL;
13173ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
13183ff40c12SJohn Marino 		eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
13193ff40c12SJohn Marino 		if (eapKeyData) {
13203ff40c12SJohn Marino 			os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
13213ff40c12SJohn Marino 			*len = EAP_TLS_KEY_LEN;
13223ff40c12SJohn Marino 			wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
13233ff40c12SJohn Marino 				    eapKeyData, EAP_TLS_KEY_LEN);
13243ff40c12SJohn Marino 		} else {
13253ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
13263ff40c12SJohn Marino 				   "key");
13273ff40c12SJohn Marino 		}
13283ff40c12SJohn Marino 
1329*a1157835SDaniel Fojt 		forced_memzero(csk, sizeof(csk));
1330*a1157835SDaniel Fojt 
13313ff40c12SJohn Marino 		return eapKeyData;
13323ff40c12SJohn Marino 	}
13333ff40c12SJohn Marino 
13343ff40c12SJohn Marino 	/* TODO: PEAPv1 - different label in some cases */
13353ff40c12SJohn Marino 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
1336*a1157835SDaniel Fojt 					       "client EAP encryption", NULL, 0,
1337*a1157835SDaniel Fojt 					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
13383ff40c12SJohn Marino 	if (eapKeyData) {
1339*a1157835SDaniel Fojt 		os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
13403ff40c12SJohn Marino 		*len = EAP_TLS_KEY_LEN;
13413ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
13423ff40c12SJohn Marino 			    eapKeyData, EAP_TLS_KEY_LEN);
13433ff40c12SJohn Marino 	} else {
13443ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
13453ff40c12SJohn Marino 	}
13463ff40c12SJohn Marino 
13473ff40c12SJohn Marino 	return eapKeyData;
13483ff40c12SJohn Marino }
13493ff40c12SJohn Marino 
13503ff40c12SJohn Marino 
eap_peap_get_emsk(struct eap_sm * sm,void * priv,size_t * len)1351*a1157835SDaniel Fojt static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1352*a1157835SDaniel Fojt {
1353*a1157835SDaniel Fojt 	struct eap_peap_data *data = priv;
1354*a1157835SDaniel Fojt 	u8 *eapKeyData, *emsk;
1355*a1157835SDaniel Fojt 
1356*a1157835SDaniel Fojt 	if (data->state != SUCCESS)
1357*a1157835SDaniel Fojt 		return NULL;
1358*a1157835SDaniel Fojt 
1359*a1157835SDaniel Fojt 	if (data->crypto_binding_used) {
1360*a1157835SDaniel Fojt 		/* [MS-PEAP] does not define EMSK derivation */
1361*a1157835SDaniel Fojt 		return NULL;
1362*a1157835SDaniel Fojt 	}
1363*a1157835SDaniel Fojt 
1364*a1157835SDaniel Fojt 	/* TODO: PEAPv1 - different label in some cases */
1365*a1157835SDaniel Fojt 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
1366*a1157835SDaniel Fojt 					       "client EAP encryption", NULL, 0,
1367*a1157835SDaniel Fojt 					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
1368*a1157835SDaniel Fojt 	if (eapKeyData) {
1369*a1157835SDaniel Fojt 		emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
1370*a1157835SDaniel Fojt 		bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
1371*a1157835SDaniel Fojt 		if (!emsk)
1372*a1157835SDaniel Fojt 			return NULL;
1373*a1157835SDaniel Fojt 		*len = EAP_EMSK_LEN;
1374*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived EMSK",
1375*a1157835SDaniel Fojt 			    emsk, EAP_EMSK_LEN);
1376*a1157835SDaniel Fojt 	} else {
1377*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive EMSK");
1378*a1157835SDaniel Fojt 		emsk = NULL;
1379*a1157835SDaniel Fojt 	}
1380*a1157835SDaniel Fojt 
1381*a1157835SDaniel Fojt 	return emsk;
1382*a1157835SDaniel Fojt }
1383*a1157835SDaniel Fojt 
1384*a1157835SDaniel Fojt 
eap_peap_isSuccess(struct eap_sm * sm,void * priv)13853ff40c12SJohn Marino static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
13863ff40c12SJohn Marino {
13873ff40c12SJohn Marino 	struct eap_peap_data *data = priv;
13883ff40c12SJohn Marino 	return data->state == SUCCESS;
13893ff40c12SJohn Marino }
13903ff40c12SJohn Marino 
13913ff40c12SJohn Marino 
eap_peap_get_session_id(struct eap_sm * sm,void * priv,size_t * len)1392*a1157835SDaniel Fojt static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1393*a1157835SDaniel Fojt {
1394*a1157835SDaniel Fojt 	struct eap_peap_data *data = priv;
1395*a1157835SDaniel Fojt 
1396*a1157835SDaniel Fojt 	if (data->state != SUCCESS)
1397*a1157835SDaniel Fojt 		return NULL;
1398*a1157835SDaniel Fojt 
1399*a1157835SDaniel Fojt 	return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
1400*a1157835SDaniel Fojt 						len);
1401*a1157835SDaniel Fojt }
1402*a1157835SDaniel Fojt 
1403*a1157835SDaniel Fojt 
eap_server_peap_register(void)14043ff40c12SJohn Marino int eap_server_peap_register(void)
14053ff40c12SJohn Marino {
14063ff40c12SJohn Marino 	struct eap_method *eap;
14073ff40c12SJohn Marino 
14083ff40c12SJohn Marino 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
14093ff40c12SJohn Marino 				      EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
14103ff40c12SJohn Marino 	if (eap == NULL)
14113ff40c12SJohn Marino 		return -1;
14123ff40c12SJohn Marino 
14133ff40c12SJohn Marino 	eap->init = eap_peap_init;
14143ff40c12SJohn Marino 	eap->reset = eap_peap_reset;
14153ff40c12SJohn Marino 	eap->buildReq = eap_peap_buildReq;
14163ff40c12SJohn Marino 	eap->check = eap_peap_check;
14173ff40c12SJohn Marino 	eap->process = eap_peap_process;
14183ff40c12SJohn Marino 	eap->isDone = eap_peap_isDone;
14193ff40c12SJohn Marino 	eap->getKey = eap_peap_getKey;
1420*a1157835SDaniel Fojt 	eap->get_emsk = eap_peap_get_emsk;
14213ff40c12SJohn Marino 	eap->isSuccess = eap_peap_isSuccess;
1422*a1157835SDaniel Fojt 	eap->getSessionId = eap_peap_get_session_id;
14233ff40c12SJohn Marino 
1424*a1157835SDaniel Fojt 	return eap_server_method_register(eap);
14253ff40c12SJohn Marino }
1426