xref: /freebsd/contrib/wpa/src/eap_peer/eap_peap.c (revision c1d255d3)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
34bc52338SCy Schubert  * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
1239beb93cSSam Leffler #include "crypto/sha1.h"
13e28a4053SRui Paulo #include "crypto/tls.h"
14e28a4053SRui Paulo #include "eap_common/eap_tlv_common.h"
15e28a4053SRui Paulo #include "eap_common/eap_peap_common.h"
1639beb93cSSam Leffler #include "eap_i.h"
1739beb93cSSam Leffler #include "eap_tls_common.h"
1839beb93cSSam Leffler #include "eap_config.h"
1939beb93cSSam Leffler #include "tncc.h"
2039beb93cSSam Leffler 
2139beb93cSSam Leffler 
2239beb93cSSam Leffler /* Maximum supported PEAP version
2339beb93cSSam Leffler  * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
2439beb93cSSam Leffler  * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
2539beb93cSSam Leffler  */
2639beb93cSSam Leffler #define EAP_PEAP_VERSION 1
2739beb93cSSam Leffler 
2839beb93cSSam Leffler 
2939beb93cSSam Leffler static void eap_peap_deinit(struct eap_sm *sm, void *priv);
3039beb93cSSam Leffler 
3139beb93cSSam Leffler 
3239beb93cSSam Leffler struct eap_peap_data {
3339beb93cSSam Leffler 	struct eap_ssl_data ssl;
3439beb93cSSam Leffler 
3539beb93cSSam Leffler 	int peap_version, force_peap_version, force_new_label;
3639beb93cSSam Leffler 
3739beb93cSSam Leffler 	const struct eap_method *phase2_method;
3839beb93cSSam Leffler 	void *phase2_priv;
3939beb93cSSam Leffler 	int phase2_success;
4039beb93cSSam Leffler 	int phase2_eap_success;
4139beb93cSSam Leffler 	int phase2_eap_started;
4239beb93cSSam Leffler 
4339beb93cSSam Leffler 	struct eap_method_type phase2_type;
4439beb93cSSam Leffler 	struct eap_method_type *phase2_types;
4539beb93cSSam Leffler 	size_t num_phase2_types;
4639beb93cSSam Leffler 
4739beb93cSSam Leffler 	int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
4839beb93cSSam Leffler 				 * EAP-Success
4939beb93cSSam Leffler 				 * 1 = reply with tunneled EAP-Success to inner
5039beb93cSSam Leffler 				 * EAP-Success and expect AS to send outer
5139beb93cSSam Leffler 				 * (unencrypted) EAP-Success after this
5239beb93cSSam Leffler 				 * 2 = reply with PEAP/TLS ACK to inner
5339beb93cSSam Leffler 				 * EAP-Success and expect AS to send outer
5439beb93cSSam Leffler 				 * (unencrypted) EAP-Success after this */
5539beb93cSSam Leffler 	int resuming; /* starting a resumed session */
5639beb93cSSam Leffler 	int reauth; /* reauthentication */
5739beb93cSSam Leffler 	u8 *key_data;
585b9c547cSRui Paulo 	u8 *session_id;
595b9c547cSRui Paulo 	size_t id_len;
6039beb93cSSam Leffler 
6139beb93cSSam Leffler 	struct wpabuf *pending_phase2_req;
62780fb4a2SCy Schubert 	struct wpabuf *pending_resp;
6339beb93cSSam Leffler 	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
6439beb93cSSam Leffler 	int crypto_binding_used;
6539beb93cSSam Leffler 	u8 binding_nonce[32];
6639beb93cSSam Leffler 	u8 ipmk[40];
6739beb93cSSam Leffler 	u8 cmk[20];
6839beb93cSSam Leffler 	int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
6939beb93cSSam Leffler 		  * is enabled. */
7039beb93cSSam Leffler };
7139beb93cSSam Leffler 
7239beb93cSSam Leffler 
eap_peap_parse_phase1(struct eap_peap_data * data,const char * phase1)73780fb4a2SCy Schubert static void eap_peap_parse_phase1(struct eap_peap_data *data,
7439beb93cSSam Leffler 				  const char *phase1)
7539beb93cSSam Leffler {
7639beb93cSSam Leffler 	const char *pos;
7739beb93cSSam Leffler 
7839beb93cSSam Leffler 	pos = os_strstr(phase1, "peapver=");
7939beb93cSSam Leffler 	if (pos) {
8039beb93cSSam Leffler 		data->force_peap_version = atoi(pos + 8);
8139beb93cSSam Leffler 		data->peap_version = data->force_peap_version;
8239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d",
8339beb93cSSam Leffler 			   data->force_peap_version);
8439beb93cSSam Leffler 	}
8539beb93cSSam Leffler 
8639beb93cSSam Leffler 	if (os_strstr(phase1, "peaplabel=1")) {
8739beb93cSSam Leffler 		data->force_new_label = 1;
8839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key "
8939beb93cSSam Leffler 			   "derivation");
9039beb93cSSam Leffler 	}
9139beb93cSSam Leffler 
9239beb93cSSam Leffler 	if (os_strstr(phase1, "peap_outer_success=0")) {
9339beb93cSSam Leffler 		data->peap_outer_success = 0;
9439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on "
9539beb93cSSam Leffler 			   "tunneled EAP-Success");
9639beb93cSSam Leffler 	} else if (os_strstr(phase1, "peap_outer_success=1")) {
9739beb93cSSam Leffler 		data->peap_outer_success = 1;
9839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success "
9939beb93cSSam Leffler 			   "after receiving tunneled EAP-Success");
10039beb93cSSam Leffler 	} else if (os_strstr(phase1, "peap_outer_success=2")) {
10139beb93cSSam Leffler 		data->peap_outer_success = 2;
10239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after "
10339beb93cSSam Leffler 			   "receiving tunneled EAP-Success");
10439beb93cSSam Leffler 	}
10539beb93cSSam Leffler 
10639beb93cSSam Leffler 	if (os_strstr(phase1, "crypto_binding=0")) {
10739beb93cSSam Leffler 		data->crypto_binding = NO_BINDING;
10839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
10939beb93cSSam Leffler 	} else if (os_strstr(phase1, "crypto_binding=1")) {
11039beb93cSSam Leffler 		data->crypto_binding = OPTIONAL_BINDING;
11139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
11239beb93cSSam Leffler 	} else if (os_strstr(phase1, "crypto_binding=2")) {
11339beb93cSSam Leffler 		data->crypto_binding = REQUIRE_BINDING;
11439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
11539beb93cSSam Leffler 	}
11639beb93cSSam Leffler 
11739beb93cSSam Leffler #ifdef EAP_TNC
11839beb93cSSam Leffler 	if (os_strstr(phase1, "tnc=soh2")) {
11939beb93cSSam Leffler 		data->soh = 2;
12039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
12139beb93cSSam Leffler 	} else if (os_strstr(phase1, "tnc=soh1")) {
12239beb93cSSam Leffler 		data->soh = 1;
12339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled");
12439beb93cSSam Leffler 	} else if (os_strstr(phase1, "tnc=soh")) {
12539beb93cSSam Leffler 		data->soh = 2;
12639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
12739beb93cSSam Leffler 	}
12839beb93cSSam Leffler #endif /* EAP_TNC */
12939beb93cSSam Leffler }
13039beb93cSSam Leffler 
13139beb93cSSam Leffler 
eap_peap_init(struct eap_sm * sm)13239beb93cSSam Leffler static void * eap_peap_init(struct eap_sm *sm)
13339beb93cSSam Leffler {
13439beb93cSSam Leffler 	struct eap_peap_data *data;
13539beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
13639beb93cSSam Leffler 
13739beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
13839beb93cSSam Leffler 	if (data == NULL)
13939beb93cSSam Leffler 		return NULL;
140*c1d255d3SCy Schubert 	sm->peap_done = false;
14139beb93cSSam Leffler 	data->peap_version = EAP_PEAP_VERSION;
14239beb93cSSam Leffler 	data->force_peap_version = -1;
14339beb93cSSam Leffler 	data->peap_outer_success = 2;
14439beb93cSSam Leffler 	data->crypto_binding = OPTIONAL_BINDING;
14539beb93cSSam Leffler 
146780fb4a2SCy Schubert 	if (config && config->phase1)
147780fb4a2SCy Schubert 		eap_peap_parse_phase1(data, config->phase1);
14839beb93cSSam Leffler 
14939beb93cSSam Leffler 	if (eap_peer_select_phase2_methods(config, "auth=",
15039beb93cSSam Leffler 					   &data->phase2_types,
151*c1d255d3SCy Schubert 					   &data->num_phase2_types, 0) < 0) {
15239beb93cSSam Leffler 		eap_peap_deinit(sm, data);
15339beb93cSSam Leffler 		return NULL;
15439beb93cSSam Leffler 	}
15539beb93cSSam Leffler 
15639beb93cSSam Leffler 	data->phase2_type.vendor = EAP_VENDOR_IETF;
15739beb93cSSam Leffler 	data->phase2_type.method = EAP_TYPE_NONE;
15839beb93cSSam Leffler 
159f05cddf9SRui Paulo 	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) {
16039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
16139beb93cSSam Leffler 		eap_peap_deinit(sm, data);
16239beb93cSSam Leffler 		return NULL;
16339beb93cSSam Leffler 	}
16439beb93cSSam Leffler 
16539beb93cSSam Leffler 	return data;
16639beb93cSSam Leffler }
16739beb93cSSam Leffler 
16839beb93cSSam Leffler 
eap_peap_free_key(struct eap_peap_data * data)1695b9c547cSRui Paulo static void eap_peap_free_key(struct eap_peap_data *data)
1705b9c547cSRui Paulo {
1715b9c547cSRui Paulo 	if (data->key_data) {
1724bc52338SCy Schubert 		bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
1735b9c547cSRui Paulo 		data->key_data = NULL;
1745b9c547cSRui Paulo 	}
1755b9c547cSRui Paulo }
1765b9c547cSRui Paulo 
1775b9c547cSRui Paulo 
eap_peap_deinit(struct eap_sm * sm,void * priv)17839beb93cSSam Leffler static void eap_peap_deinit(struct eap_sm *sm, void *priv)
17939beb93cSSam Leffler {
18039beb93cSSam Leffler 	struct eap_peap_data *data = priv;
18139beb93cSSam Leffler 	if (data == NULL)
18239beb93cSSam Leffler 		return;
18339beb93cSSam Leffler 	if (data->phase2_priv && data->phase2_method)
18439beb93cSSam Leffler 		data->phase2_method->deinit(sm, data->phase2_priv);
18539beb93cSSam Leffler 	os_free(data->phase2_types);
18639beb93cSSam Leffler 	eap_peer_tls_ssl_deinit(sm, &data->ssl);
1875b9c547cSRui Paulo 	eap_peap_free_key(data);
1885b9c547cSRui Paulo 	os_free(data->session_id);
1894bc52338SCy Schubert 	wpabuf_clear_free(data->pending_phase2_req);
1904bc52338SCy Schubert 	wpabuf_clear_free(data->pending_resp);
1914bc52338SCy Schubert 	bin_clear_free(data, sizeof(*data));
19239beb93cSSam Leffler }
19339beb93cSSam Leffler 
19439beb93cSSam Leffler 
19539beb93cSSam Leffler /**
19639beb93cSSam Leffler  * eap_tlv_build_nak - Build EAP-TLV NAK message
19739beb93cSSam Leffler  * @id: EAP identifier for the header
19839beb93cSSam Leffler  * @nak_type: TLV type (EAP_TLV_*)
19939beb93cSSam Leffler  * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
20039beb93cSSam Leffler  *
201f05cddf9SRui Paulo  * This function builds an EAP-TLV NAK message. The caller is responsible for
20239beb93cSSam Leffler  * freeing the returned buffer.
20339beb93cSSam Leffler  */
eap_tlv_build_nak(int id,u16 nak_type)20439beb93cSSam Leffler static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
20539beb93cSSam Leffler {
20639beb93cSSam Leffler 	struct wpabuf *msg;
20739beb93cSSam Leffler 
20839beb93cSSam Leffler 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
20939beb93cSSam Leffler 			    EAP_CODE_RESPONSE, id);
21039beb93cSSam Leffler 	if (msg == NULL)
21139beb93cSSam Leffler 		return NULL;
21239beb93cSSam Leffler 
21339beb93cSSam Leffler 	wpabuf_put_u8(msg, 0x80); /* Mandatory */
21439beb93cSSam Leffler 	wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
21539beb93cSSam Leffler 	wpabuf_put_be16(msg, 6); /* Length */
21639beb93cSSam Leffler 	wpabuf_put_be32(msg, 0); /* Vendor-Id */
21739beb93cSSam Leffler 	wpabuf_put_be16(msg, nak_type); /* NAK-Type */
21839beb93cSSam Leffler 
21939beb93cSSam Leffler 	return msg;
22039beb93cSSam Leffler }
22139beb93cSSam Leffler 
22239beb93cSSam Leffler 
eap_peap_get_isk(struct eap_sm * sm,struct eap_peap_data * data,u8 * isk,size_t isk_len)22339beb93cSSam Leffler static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
22439beb93cSSam Leffler 			    u8 *isk, size_t isk_len)
22539beb93cSSam Leffler {
22639beb93cSSam Leffler 	u8 *key;
22739beb93cSSam Leffler 	size_t key_len;
22839beb93cSSam Leffler 
22939beb93cSSam Leffler 	os_memset(isk, 0, isk_len);
23039beb93cSSam Leffler 	if (data->phase2_method == NULL || data->phase2_priv == NULL ||
23139beb93cSSam Leffler 	    data->phase2_method->isKeyAvailable == NULL ||
23239beb93cSSam Leffler 	    data->phase2_method->getKey == NULL)
23339beb93cSSam Leffler 		return 0;
23439beb93cSSam Leffler 
23539beb93cSSam Leffler 	if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
23639beb93cSSam Leffler 	    (key = data->phase2_method->getKey(sm, data->phase2_priv,
23739beb93cSSam Leffler 					       &key_len)) == NULL) {
23839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
23939beb93cSSam Leffler 			   "from Phase 2");
24039beb93cSSam Leffler 		return -1;
24139beb93cSSam Leffler 	}
24239beb93cSSam Leffler 
24339beb93cSSam Leffler 	if (key_len > isk_len)
24439beb93cSSam Leffler 		key_len = isk_len;
24539beb93cSSam Leffler 	os_memcpy(isk, key, key_len);
24639beb93cSSam Leffler 	os_free(key);
24739beb93cSSam Leffler 
24839beb93cSSam Leffler 	return 0;
24939beb93cSSam Leffler }
25039beb93cSSam Leffler 
25139beb93cSSam Leffler 
eap_peap_derive_cmk(struct eap_sm * sm,struct eap_peap_data * data)25239beb93cSSam Leffler static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
25339beb93cSSam Leffler {
25439beb93cSSam Leffler 	u8 *tk;
25539beb93cSSam Leffler 	u8 isk[32], imck[60];
2564bc52338SCy Schubert 	int resumed, res;
25739beb93cSSam Leffler 
25839beb93cSSam Leffler 	/*
25939beb93cSSam Leffler 	 * Tunnel key (TK) is the first 60 octets of the key generated by
26039beb93cSSam Leffler 	 * phase 1 of PEAP (based on TLS).
26139beb93cSSam Leffler 	 */
26239beb93cSSam Leffler 	tk = data->key_data;
26339beb93cSSam Leffler 	if (tk == NULL)
26439beb93cSSam Leffler 		return -1;
26539beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
26639beb93cSSam Leffler 
267780fb4a2SCy Schubert 	resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn);
268780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG,
269780fb4a2SCy Schubert 		   "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d",
270780fb4a2SCy Schubert 		   data->reauth, resumed, data->phase2_eap_started,
271780fb4a2SCy Schubert 		   data->phase2_success);
272780fb4a2SCy Schubert 	if (data->reauth && !data->phase2_eap_started && resumed) {
27339beb93cSSam Leffler 		/* Fast-connect: IPMK|CMK = TK */
27439beb93cSSam Leffler 		os_memcpy(data->ipmk, tk, 40);
27539beb93cSSam Leffler 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
27639beb93cSSam Leffler 				data->ipmk, 40);
27739beb93cSSam Leffler 		os_memcpy(data->cmk, tk + 40, 20);
27839beb93cSSam Leffler 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
27939beb93cSSam Leffler 				data->cmk, 20);
28039beb93cSSam Leffler 		return 0;
28139beb93cSSam Leffler 	}
28239beb93cSSam Leffler 
28339beb93cSSam Leffler 	if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
28439beb93cSSam Leffler 		return -1;
28539beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
28639beb93cSSam Leffler 
28739beb93cSSam Leffler 	/*
28839beb93cSSam Leffler 	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
28939beb93cSSam Leffler 	 * TempKey = First 40 octets of TK
29039beb93cSSam Leffler 	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
29139beb93cSSam Leffler 	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
29239beb93cSSam Leffler 	 * in the end of the label just before ISK; is that just a typo?)
29339beb93cSSam Leffler 	 */
29439beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
2954bc52338SCy Schubert 	res = peap_prfplus(data->peap_version, tk, 40,
296f05cddf9SRui Paulo 			   "Inner Methods Compound Keys",
2974bc52338SCy Schubert 			   isk, sizeof(isk), imck, sizeof(imck));
298206b73d0SCy Schubert 	forced_memzero(isk, sizeof(isk));
2994bc52338SCy Schubert 	if (res < 0)
300f05cddf9SRui Paulo 		return -1;
30139beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
30239beb93cSSam Leffler 			imck, sizeof(imck));
30339beb93cSSam Leffler 
30439beb93cSSam Leffler 	os_memcpy(data->ipmk, imck, 40);
30539beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
30639beb93cSSam Leffler 	os_memcpy(data->cmk, imck + 40, 20);
30739beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
308206b73d0SCy Schubert 	forced_memzero(imck, sizeof(imck));
30939beb93cSSam Leffler 
31039beb93cSSam Leffler 	return 0;
31139beb93cSSam Leffler }
31239beb93cSSam Leffler 
31339beb93cSSam Leffler 
eap_tlv_add_cryptobinding(struct eap_sm * sm,struct eap_peap_data * data,struct wpabuf * buf)31439beb93cSSam Leffler static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
31539beb93cSSam Leffler 				     struct eap_peap_data *data,
31639beb93cSSam Leffler 				     struct wpabuf *buf)
31739beb93cSSam Leffler {
31839beb93cSSam Leffler 	u8 *mac;
31939beb93cSSam Leffler 	u8 eap_type = EAP_TYPE_PEAP;
32039beb93cSSam Leffler 	const u8 *addr[2];
32139beb93cSSam Leffler 	size_t len[2];
32239beb93cSSam Leffler 	u16 tlv_type;
32339beb93cSSam Leffler 
32439beb93cSSam Leffler 	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
32539beb93cSSam Leffler 	addr[0] = wpabuf_put(buf, 0);
32639beb93cSSam Leffler 	len[0] = 60;
32739beb93cSSam Leffler 	addr[1] = &eap_type;
32839beb93cSSam Leffler 	len[1] = 1;
32939beb93cSSam Leffler 
33039beb93cSSam Leffler 	tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
33139beb93cSSam Leffler 	wpabuf_put_be16(buf, tlv_type);
33239beb93cSSam Leffler 	wpabuf_put_be16(buf, 56);
33339beb93cSSam Leffler 
33439beb93cSSam Leffler 	wpabuf_put_u8(buf, 0); /* Reserved */
33539beb93cSSam Leffler 	wpabuf_put_u8(buf, data->peap_version); /* Version */
33639beb93cSSam Leffler 	wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
33739beb93cSSam Leffler 	wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
33839beb93cSSam Leffler 	wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
33939beb93cSSam Leffler 	mac = wpabuf_put(buf, 20); /* Compound_MAC */
34039beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
34139beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
34239beb93cSSam Leffler 		    addr[0], len[0]);
34339beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
34439beb93cSSam Leffler 		    addr[1], len[1]);
345780fb4a2SCy Schubert 	if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0)
346780fb4a2SCy Schubert 		return -1;
34739beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
34839beb93cSSam Leffler 	data->crypto_binding_used = 1;
34939beb93cSSam Leffler 
35039beb93cSSam Leffler 	return 0;
35139beb93cSSam Leffler }
35239beb93cSSam Leffler 
35339beb93cSSam Leffler 
35439beb93cSSam Leffler /**
35539beb93cSSam Leffler  * eap_tlv_build_result - Build EAP-TLV Result message
35639beb93cSSam Leffler  * @id: EAP identifier for the header
35739beb93cSSam Leffler  * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
35839beb93cSSam Leffler  * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
35939beb93cSSam Leffler  *
360f05cddf9SRui Paulo  * This function builds an EAP-TLV Result message. The caller is responsible
361f05cddf9SRui Paulo  * for freeing the returned buffer.
36239beb93cSSam Leffler  */
eap_tlv_build_result(struct eap_sm * sm,struct eap_peap_data * data,int crypto_tlv_used,int id,u16 status)36339beb93cSSam Leffler static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
36439beb93cSSam Leffler 					    struct eap_peap_data *data,
36539beb93cSSam Leffler 					    int crypto_tlv_used,
36639beb93cSSam Leffler 					    int id, u16 status)
36739beb93cSSam Leffler {
36839beb93cSSam Leffler 	struct wpabuf *msg;
36939beb93cSSam Leffler 	size_t len;
37039beb93cSSam Leffler 
37139beb93cSSam Leffler 	if (data->crypto_binding == NO_BINDING)
37239beb93cSSam Leffler 		crypto_tlv_used = 0;
37339beb93cSSam Leffler 
37439beb93cSSam Leffler 	len = 6;
37539beb93cSSam Leffler 	if (crypto_tlv_used)
37639beb93cSSam Leffler 		len += 60; /* Cryptobinding TLV */
37739beb93cSSam Leffler 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
37839beb93cSSam Leffler 			    EAP_CODE_RESPONSE, id);
37939beb93cSSam Leffler 	if (msg == NULL)
38039beb93cSSam Leffler 		return NULL;
38139beb93cSSam Leffler 
38239beb93cSSam Leffler 	wpabuf_put_u8(msg, 0x80); /* Mandatory */
38339beb93cSSam Leffler 	wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
38439beb93cSSam Leffler 	wpabuf_put_be16(msg, 2); /* Length */
38539beb93cSSam Leffler 	wpabuf_put_be16(msg, status); /* Status */
38639beb93cSSam Leffler 
38739beb93cSSam Leffler 	if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
3884bc52338SCy Schubert 		wpabuf_clear_free(msg);
38939beb93cSSam Leffler 		return NULL;
39039beb93cSSam Leffler 	}
39139beb93cSSam Leffler 
39239beb93cSSam Leffler 	return msg;
39339beb93cSSam Leffler }
39439beb93cSSam Leffler 
39539beb93cSSam Leffler 
eap_tlv_validate_cryptobinding(struct eap_sm * sm,struct eap_peap_data * data,const u8 * crypto_tlv,size_t crypto_tlv_len)39639beb93cSSam Leffler static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
39739beb93cSSam Leffler 					  struct eap_peap_data *data,
39839beb93cSSam Leffler 					  const u8 *crypto_tlv,
39939beb93cSSam Leffler 					  size_t crypto_tlv_len)
40039beb93cSSam Leffler {
40139beb93cSSam Leffler 	u8 buf[61], mac[SHA1_MAC_LEN];
40239beb93cSSam Leffler 	const u8 *pos;
40339beb93cSSam Leffler 
40439beb93cSSam Leffler 	if (eap_peap_derive_cmk(sm, data) < 0) {
40539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
40639beb93cSSam Leffler 		return -1;
40739beb93cSSam Leffler 	}
40839beb93cSSam Leffler 
40939beb93cSSam Leffler 	if (crypto_tlv_len != 4 + 56) {
41039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
41139beb93cSSam Leffler 			   "length %d", (int) crypto_tlv_len);
41239beb93cSSam Leffler 		return -1;
41339beb93cSSam Leffler 	}
41439beb93cSSam Leffler 
41539beb93cSSam Leffler 	pos = crypto_tlv;
41639beb93cSSam Leffler 	pos += 4; /* TLV header */
41739beb93cSSam Leffler 	if (pos[1] != data->peap_version) {
41839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
41939beb93cSSam Leffler 			   "mismatch (was %d; expected %d)",
42039beb93cSSam Leffler 			   pos[1], data->peap_version);
42139beb93cSSam Leffler 		return -1;
42239beb93cSSam Leffler 	}
42339beb93cSSam Leffler 
42439beb93cSSam Leffler 	if (pos[3] != 0) {
42539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
42639beb93cSSam Leffler 			   "SubType %d", pos[3]);
42739beb93cSSam Leffler 		return -1;
42839beb93cSSam Leffler 	}
42939beb93cSSam Leffler 	pos += 4;
43039beb93cSSam Leffler 	os_memcpy(data->binding_nonce, pos, 32);
43139beb93cSSam Leffler 	pos += 32; /* Nonce */
43239beb93cSSam Leffler 
43339beb93cSSam Leffler 	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
43439beb93cSSam Leffler 	os_memcpy(buf, crypto_tlv, 60);
43539beb93cSSam Leffler 	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
43639beb93cSSam Leffler 	buf[60] = EAP_TYPE_PEAP;
43739beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
43839beb93cSSam Leffler 		    buf, sizeof(buf));
43939beb93cSSam Leffler 	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
44039beb93cSSam Leffler 
4415b9c547cSRui Paulo 	if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
44239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
44339beb93cSSam Leffler 			   "cryptobinding TLV");
44439beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
44539beb93cSSam Leffler 			    pos, SHA1_MAC_LEN);
44639beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
44739beb93cSSam Leffler 			    mac, SHA1_MAC_LEN);
44839beb93cSSam Leffler 		return -1;
44939beb93cSSam Leffler 	}
45039beb93cSSam Leffler 
45139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
45239beb93cSSam Leffler 
45339beb93cSSam Leffler 	return 0;
45439beb93cSSam Leffler }
45539beb93cSSam Leffler 
45639beb93cSSam Leffler 
45739beb93cSSam Leffler /**
45839beb93cSSam Leffler  * eap_tlv_process - Process a received EAP-TLV message and generate a response
45939beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
46039beb93cSSam Leffler  * @ret: Return values from EAP request validation and processing
46139beb93cSSam Leffler  * @req: EAP-TLV request to be processed. The caller must have validated that
46239beb93cSSam Leffler  * the buffer is large enough to contain full request (hdr->length bytes) and
46339beb93cSSam Leffler  * that the EAP type is EAP_TYPE_TLV.
46439beb93cSSam Leffler  * @resp: Buffer to return a pointer to the allocated response message. This
46539beb93cSSam Leffler  * field should be initialized to %NULL before the call. The value will be
46639beb93cSSam Leffler  * updated if a response message is generated. The caller is responsible for
46739beb93cSSam Leffler  * freeing the allocated message.
46839beb93cSSam Leffler  * @force_failure: Force negotiation to fail
46939beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
47039beb93cSSam Leffler  */
eap_tlv_process(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,const struct wpabuf * req,struct wpabuf ** resp,int force_failure)47139beb93cSSam Leffler static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
47239beb93cSSam Leffler 			   struct eap_method_ret *ret,
47339beb93cSSam Leffler 			   const struct wpabuf *req, struct wpabuf **resp,
47439beb93cSSam Leffler 			   int force_failure)
47539beb93cSSam Leffler {
47639beb93cSSam Leffler 	size_t left, tlv_len;
47739beb93cSSam Leffler 	const u8 *pos;
47839beb93cSSam Leffler 	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
47939beb93cSSam Leffler 	size_t result_tlv_len = 0, crypto_tlv_len = 0;
48039beb93cSSam Leffler 	int tlv_type, mandatory;
48139beb93cSSam Leffler 
48239beb93cSSam Leffler 	/* Parse TLVs */
48339beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
48439beb93cSSam Leffler 	if (pos == NULL)
48539beb93cSSam Leffler 		return -1;
48639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
48739beb93cSSam Leffler 	while (left >= 4) {
48839beb93cSSam Leffler 		mandatory = !!(pos[0] & 0x80);
48939beb93cSSam Leffler 		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
49039beb93cSSam Leffler 		pos += 2;
49139beb93cSSam Leffler 		tlv_len = WPA_GET_BE16(pos);
49239beb93cSSam Leffler 		pos += 2;
49339beb93cSSam Leffler 		left -= 4;
49439beb93cSSam Leffler 		if (tlv_len > left) {
49539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
49639beb93cSSam Leffler 				   "(tlv_len=%lu left=%lu)",
49739beb93cSSam Leffler 				   (unsigned long) tlv_len,
49839beb93cSSam Leffler 				   (unsigned long) left);
49939beb93cSSam Leffler 			return -1;
50039beb93cSSam Leffler 		}
50139beb93cSSam Leffler 		switch (tlv_type) {
50239beb93cSSam Leffler 		case EAP_TLV_RESULT_TLV:
50339beb93cSSam Leffler 			result_tlv = pos;
50439beb93cSSam Leffler 			result_tlv_len = tlv_len;
50539beb93cSSam Leffler 			break;
50639beb93cSSam Leffler 		case EAP_TLV_CRYPTO_BINDING_TLV:
50739beb93cSSam Leffler 			crypto_tlv = pos;
50839beb93cSSam Leffler 			crypto_tlv_len = tlv_len;
50939beb93cSSam Leffler 			break;
51039beb93cSSam Leffler 		default:
51139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
51239beb93cSSam Leffler 				   "%d%s", tlv_type,
51339beb93cSSam Leffler 				   mandatory ? " (mandatory)" : "");
51439beb93cSSam Leffler 			if (mandatory) {
51539beb93cSSam Leffler 				/* NAK TLV and ignore all TLVs in this packet.
51639beb93cSSam Leffler 				 */
51739beb93cSSam Leffler 				*resp = eap_tlv_build_nak(eap_get_id(req),
51839beb93cSSam Leffler 							  tlv_type);
51939beb93cSSam Leffler 				return *resp == NULL ? -1 : 0;
52039beb93cSSam Leffler 			}
52139beb93cSSam Leffler 			/* Ignore this TLV, but process other TLVs */
52239beb93cSSam Leffler 			break;
52339beb93cSSam Leffler 		}
52439beb93cSSam Leffler 
52539beb93cSSam Leffler 		pos += tlv_len;
52639beb93cSSam Leffler 		left -= tlv_len;
52739beb93cSSam Leffler 	}
52839beb93cSSam Leffler 	if (left) {
52939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
53039beb93cSSam Leffler 			   "Request (left=%lu)", (unsigned long) left);
53139beb93cSSam Leffler 		return -1;
53239beb93cSSam Leffler 	}
53339beb93cSSam Leffler 
53439beb93cSSam Leffler 	/* Process supported TLVs */
53539beb93cSSam Leffler 	if (crypto_tlv && data->crypto_binding != NO_BINDING) {
53639beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
53739beb93cSSam Leffler 			    crypto_tlv, crypto_tlv_len);
53839beb93cSSam Leffler 		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
53939beb93cSSam Leffler 						   crypto_tlv_len + 4) < 0) {
54039beb93cSSam Leffler 			if (result_tlv == NULL)
54139beb93cSSam Leffler 				return -1;
54239beb93cSSam Leffler 			force_failure = 1;
54339beb93cSSam Leffler 			crypto_tlv = NULL; /* do not include Cryptobinding TLV
54439beb93cSSam Leffler 					    * in response, if the received
54539beb93cSSam Leffler 					    * cryptobinding was invalid. */
54639beb93cSSam Leffler 		}
54739beb93cSSam Leffler 	} else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
54839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
54939beb93cSSam Leffler 		return -1;
55039beb93cSSam Leffler 	}
55139beb93cSSam Leffler 
55239beb93cSSam Leffler 	if (result_tlv) {
55339beb93cSSam Leffler 		int status, resp_status;
55439beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
55539beb93cSSam Leffler 			    result_tlv, result_tlv_len);
55639beb93cSSam Leffler 		if (result_tlv_len < 2) {
55739beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
55839beb93cSSam Leffler 				   "(len=%lu)",
55939beb93cSSam Leffler 				   (unsigned long) result_tlv_len);
56039beb93cSSam Leffler 			return -1;
56139beb93cSSam Leffler 		}
56239beb93cSSam Leffler 		status = WPA_GET_BE16(result_tlv);
56339beb93cSSam Leffler 		if (status == EAP_TLV_RESULT_SUCCESS) {
56439beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
56539beb93cSSam Leffler 				   "- EAP-TLV/Phase2 Completed");
56639beb93cSSam Leffler 			if (force_failure) {
56739beb93cSSam Leffler 				wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
56839beb93cSSam Leffler 					   " - force failed Phase 2");
56939beb93cSSam Leffler 				resp_status = EAP_TLV_RESULT_FAILURE;
57039beb93cSSam Leffler 				ret->decision = DECISION_FAIL;
57139beb93cSSam Leffler 			} else {
57239beb93cSSam Leffler 				resp_status = EAP_TLV_RESULT_SUCCESS;
57339beb93cSSam Leffler 				ret->decision = DECISION_UNCOND_SUCC;
57439beb93cSSam Leffler 			}
57539beb93cSSam Leffler 		} else if (status == EAP_TLV_RESULT_FAILURE) {
57639beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
57739beb93cSSam Leffler 			resp_status = EAP_TLV_RESULT_FAILURE;
57839beb93cSSam Leffler 			ret->decision = DECISION_FAIL;
57939beb93cSSam Leffler 		} else {
58039beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
58139beb93cSSam Leffler 				   "Status %d", status);
58239beb93cSSam Leffler 			resp_status = EAP_TLV_RESULT_FAILURE;
58339beb93cSSam Leffler 			ret->decision = DECISION_FAIL;
58439beb93cSSam Leffler 		}
58539beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
58639beb93cSSam Leffler 
58739beb93cSSam Leffler 		*resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
58839beb93cSSam Leffler 					     eap_get_id(req), resp_status);
58939beb93cSSam Leffler 	}
59039beb93cSSam Leffler 
59139beb93cSSam Leffler 	return 0;
59239beb93cSSam Leffler }
59339beb93cSSam Leffler 
59439beb93cSSam Leffler 
eap_peap_phase2_request(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,struct wpabuf * req,struct wpabuf ** resp)59539beb93cSSam Leffler static int eap_peap_phase2_request(struct eap_sm *sm,
59639beb93cSSam Leffler 				   struct eap_peap_data *data,
59739beb93cSSam Leffler 				   struct eap_method_ret *ret,
59839beb93cSSam Leffler 				   struct wpabuf *req,
59939beb93cSSam Leffler 				   struct wpabuf **resp)
60039beb93cSSam Leffler {
60139beb93cSSam Leffler 	struct eap_hdr *hdr = wpabuf_mhead(req);
60239beb93cSSam Leffler 	size_t len = be_to_host16(hdr->length);
60339beb93cSSam Leffler 	u8 *pos;
60439beb93cSSam Leffler 	struct eap_method_ret iret;
60539beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
606*c1d255d3SCy Schubert 	int vendor;
607*c1d255d3SCy Schubert 	enum eap_type method;
60839beb93cSSam Leffler 
60939beb93cSSam Leffler 	if (len <= sizeof(struct eap_hdr)) {
61039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
61139beb93cSSam Leffler 			   "Phase 2 request (len=%lu)", (unsigned long) len);
61239beb93cSSam Leffler 		return -1;
61339beb93cSSam Leffler 	}
61439beb93cSSam Leffler 	pos = (u8 *) (hdr + 1);
61539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
61639beb93cSSam Leffler 	switch (*pos) {
61739beb93cSSam Leffler 	case EAP_TYPE_IDENTITY:
61839beb93cSSam Leffler 		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
61939beb93cSSam Leffler 		break;
62039beb93cSSam Leffler 	case EAP_TYPE_TLV:
62139beb93cSSam Leffler 		os_memset(&iret, 0, sizeof(iret));
62239beb93cSSam Leffler 		if (eap_tlv_process(sm, data, &iret, req, resp,
62339beb93cSSam Leffler 				    data->phase2_eap_started &&
62439beb93cSSam Leffler 				    !data->phase2_eap_success)) {
62539beb93cSSam Leffler 			ret->methodState = METHOD_DONE;
62639beb93cSSam Leffler 			ret->decision = DECISION_FAIL;
62739beb93cSSam Leffler 			return -1;
62839beb93cSSam Leffler 		}
62939beb93cSSam Leffler 		if (iret.methodState == METHOD_DONE ||
63039beb93cSSam Leffler 		    iret.methodState == METHOD_MAY_CONT) {
63139beb93cSSam Leffler 			ret->methodState = iret.methodState;
63239beb93cSSam Leffler 			ret->decision = iret.decision;
63339beb93cSSam Leffler 			data->phase2_success = 1;
63439beb93cSSam Leffler 		}
63539beb93cSSam Leffler 		break;
63639beb93cSSam Leffler 	case EAP_TYPE_EXPANDED:
63739beb93cSSam Leffler #ifdef EAP_TNC
63839beb93cSSam Leffler 		if (data->soh) {
63939beb93cSSam Leffler 			const u8 *epos;
64039beb93cSSam Leffler 			size_t eleft;
64139beb93cSSam Leffler 
64239beb93cSSam Leffler 			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
64339beb93cSSam Leffler 						req, &eleft);
64439beb93cSSam Leffler 			if (epos) {
64539beb93cSSam Leffler 				struct wpabuf *buf;
64639beb93cSSam Leffler 				wpa_printf(MSG_DEBUG,
64739beb93cSSam Leffler 					   "EAP-PEAP: SoH EAP Extensions");
64839beb93cSSam Leffler 				buf = tncc_process_soh_request(data->soh,
64939beb93cSSam Leffler 							       epos, eleft);
65039beb93cSSam Leffler 				if (buf) {
65139beb93cSSam Leffler 					*resp = eap_msg_alloc(
65239beb93cSSam Leffler 						EAP_VENDOR_MICROSOFT, 0x21,
65339beb93cSSam Leffler 						wpabuf_len(buf),
65439beb93cSSam Leffler 						EAP_CODE_RESPONSE,
65539beb93cSSam Leffler 						hdr->identifier);
65639beb93cSSam Leffler 					if (*resp == NULL) {
65739beb93cSSam Leffler 						ret->methodState = METHOD_DONE;
65839beb93cSSam Leffler 						ret->decision = DECISION_FAIL;
6594bc52338SCy Schubert 						wpabuf_clear_free(buf);
66039beb93cSSam Leffler 						return -1;
66139beb93cSSam Leffler 					}
66239beb93cSSam Leffler 					wpabuf_put_buf(*resp, buf);
6634bc52338SCy Schubert 					wpabuf_clear_free(buf);
66439beb93cSSam Leffler 					break;
66539beb93cSSam Leffler 				}
66639beb93cSSam Leffler 			}
66739beb93cSSam Leffler 		}
66839beb93cSSam Leffler #endif /* EAP_TNC */
66939beb93cSSam Leffler 		/* fall through */
67039beb93cSSam Leffler 	default:
671*c1d255d3SCy Schubert 		vendor = EAP_VENDOR_IETF;
672*c1d255d3SCy Schubert 		method = *pos;
673*c1d255d3SCy Schubert 
674*c1d255d3SCy Schubert 		if (method == EAP_TYPE_EXPANDED) {
675*c1d255d3SCy Schubert 			if (len < sizeof(struct eap_hdr) + 8) {
676*c1d255d3SCy Schubert 				wpa_printf(MSG_INFO,
677*c1d255d3SCy Schubert 					   "EAP-PEAP: Too short Phase 2 request (expanded header) (len=%lu)",
678*c1d255d3SCy Schubert 					   (unsigned long) len);
679*c1d255d3SCy Schubert 				return -1;
680*c1d255d3SCy Schubert 			}
681*c1d255d3SCy Schubert 			vendor = WPA_GET_BE24(pos + 1);
682*c1d255d3SCy Schubert 			method = WPA_GET_BE32(pos + 4);
683*c1d255d3SCy Schubert 		}
684*c1d255d3SCy Schubert 
68539beb93cSSam Leffler 		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
68639beb93cSSam Leffler 		    data->phase2_type.method == EAP_TYPE_NONE) {
68739beb93cSSam Leffler 			size_t i;
68839beb93cSSam Leffler 			for (i = 0; i < data->num_phase2_types; i++) {
689*c1d255d3SCy Schubert 				if (data->phase2_types[i].vendor != vendor ||
690*c1d255d3SCy Schubert 				    data->phase2_types[i].method != method)
69139beb93cSSam Leffler 					continue;
69239beb93cSSam Leffler 
69339beb93cSSam Leffler 				data->phase2_type.vendor =
69439beb93cSSam Leffler 					data->phase2_types[i].vendor;
69539beb93cSSam Leffler 				data->phase2_type.method =
69639beb93cSSam Leffler 					data->phase2_types[i].method;
69739beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
69839beb93cSSam Leffler 					   "Phase 2 EAP vendor %d method %d",
69939beb93cSSam Leffler 					   data->phase2_type.vendor,
70039beb93cSSam Leffler 					   data->phase2_type.method);
70139beb93cSSam Leffler 				break;
70239beb93cSSam Leffler 			}
70339beb93cSSam Leffler 		}
704*c1d255d3SCy Schubert 		if (vendor != data->phase2_type.vendor ||
705*c1d255d3SCy Schubert 		    method != data->phase2_type.method ||
706*c1d255d3SCy Schubert 		    (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
70739beb93cSSam Leffler 			if (eap_peer_tls_phase2_nak(data->phase2_types,
70839beb93cSSam Leffler 						    data->num_phase2_types,
70939beb93cSSam Leffler 						    hdr, resp))
71039beb93cSSam Leffler 				return -1;
71139beb93cSSam Leffler 			return 0;
71239beb93cSSam Leffler 		}
71339beb93cSSam Leffler 
71439beb93cSSam Leffler 		if (data->phase2_priv == NULL) {
71539beb93cSSam Leffler 			data->phase2_method = eap_peer_get_eap_method(
71639beb93cSSam Leffler 				data->phase2_type.vendor,
71739beb93cSSam Leffler 				data->phase2_type.method);
71839beb93cSSam Leffler 			if (data->phase2_method) {
71939beb93cSSam Leffler 				sm->init_phase2 = 1;
72039beb93cSSam Leffler 				data->phase2_priv =
72139beb93cSSam Leffler 					data->phase2_method->init(sm);
72239beb93cSSam Leffler 				sm->init_phase2 = 0;
72339beb93cSSam Leffler 			}
72439beb93cSSam Leffler 		}
72539beb93cSSam Leffler 		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
72639beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
72739beb93cSSam Leffler 				   "Phase 2 EAP method %d", *pos);
72839beb93cSSam Leffler 			ret->methodState = METHOD_DONE;
72939beb93cSSam Leffler 			ret->decision = DECISION_FAIL;
73039beb93cSSam Leffler 			return -1;
73139beb93cSSam Leffler 		}
73239beb93cSSam Leffler 		data->phase2_eap_started = 1;
73339beb93cSSam Leffler 		os_memset(&iret, 0, sizeof(iret));
73439beb93cSSam Leffler 		*resp = data->phase2_method->process(sm, data->phase2_priv,
73539beb93cSSam Leffler 						     &iret, req);
73639beb93cSSam Leffler 		if ((iret.methodState == METHOD_DONE ||
73739beb93cSSam Leffler 		     iret.methodState == METHOD_MAY_CONT) &&
73839beb93cSSam Leffler 		    (iret.decision == DECISION_UNCOND_SUCC ||
73939beb93cSSam Leffler 		     iret.decision == DECISION_COND_SUCC)) {
74039beb93cSSam Leffler 			data->phase2_eap_success = 1;
74139beb93cSSam Leffler 			data->phase2_success = 1;
74239beb93cSSam Leffler 		}
74339beb93cSSam Leffler 		break;
74439beb93cSSam Leffler 	}
74539beb93cSSam Leffler 
74639beb93cSSam Leffler 	if (*resp == NULL &&
74739beb93cSSam Leffler 	    (config->pending_req_identity || config->pending_req_password ||
74885732ac8SCy Schubert 	     config->pending_req_otp || config->pending_req_new_password ||
74985732ac8SCy Schubert 	     config->pending_req_sim)) {
7504bc52338SCy Schubert 		wpabuf_clear_free(data->pending_phase2_req);
75139beb93cSSam Leffler 		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
75239beb93cSSam Leffler 	}
75339beb93cSSam Leffler 
75439beb93cSSam Leffler 	return 0;
75539beb93cSSam Leffler }
75639beb93cSSam Leffler 
75739beb93cSSam Leffler 
eap_peap_decrypt(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,const struct eap_hdr * req,const struct wpabuf * in_data,struct wpabuf ** out_data)75839beb93cSSam Leffler static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
75939beb93cSSam Leffler 			    struct eap_method_ret *ret,
76039beb93cSSam Leffler 			    const struct eap_hdr *req,
76139beb93cSSam Leffler 			    const struct wpabuf *in_data,
76239beb93cSSam Leffler 			    struct wpabuf **out_data)
76339beb93cSSam Leffler {
76439beb93cSSam Leffler 	struct wpabuf *in_decrypted = NULL;
76539beb93cSSam Leffler 	int res, skip_change = 0;
76639beb93cSSam Leffler 	struct eap_hdr *hdr, *rhdr;
76739beb93cSSam Leffler 	struct wpabuf *resp = NULL;
76839beb93cSSam Leffler 	size_t len;
76939beb93cSSam Leffler 
77039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
77139beb93cSSam Leffler 		   " Phase 2", (unsigned long) wpabuf_len(in_data));
77239beb93cSSam Leffler 
77339beb93cSSam Leffler 	if (data->pending_phase2_req) {
77439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
77539beb93cSSam Leffler 			   "skip decryption and use old data");
77639beb93cSSam Leffler 		/* Clear TLS reassembly state. */
77739beb93cSSam Leffler 		eap_peer_tls_reset_input(&data->ssl);
77839beb93cSSam Leffler 		in_decrypted = data->pending_phase2_req;
77939beb93cSSam Leffler 		data->pending_phase2_req = NULL;
78039beb93cSSam Leffler 		skip_change = 1;
78139beb93cSSam Leffler 		goto continue_req;
78239beb93cSSam Leffler 	}
78339beb93cSSam Leffler 
78439beb93cSSam Leffler 	if (wpabuf_len(in_data) == 0 && sm->workaround &&
78539beb93cSSam Leffler 	    data->phase2_success) {
78639beb93cSSam Leffler 		/*
78739beb93cSSam Leffler 		 * Cisco ACS seems to be using TLS ACK to terminate
78839beb93cSSam Leffler 		 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
78939beb93cSSam Leffler 		 */
79039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
79139beb93cSSam Leffler 			   "expected data - acknowledge with TLS ACK since "
79239beb93cSSam Leffler 			   "Phase 2 has been completed");
79339beb93cSSam Leffler 		ret->decision = DECISION_COND_SUCC;
79439beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
79539beb93cSSam Leffler 		return 1;
79639beb93cSSam Leffler 	} else if (wpabuf_len(in_data) == 0) {
79739beb93cSSam Leffler 		/* Received TLS ACK - requesting more fragments */
79839beb93cSSam Leffler 		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
79939beb93cSSam Leffler 					    data->peap_version,
80039beb93cSSam Leffler 					    req->identifier, NULL, out_data);
80139beb93cSSam Leffler 	}
80239beb93cSSam Leffler 
80339beb93cSSam Leffler 	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
80439beb93cSSam Leffler 	if (res)
80539beb93cSSam Leffler 		return res;
806*c1d255d3SCy Schubert 	if (wpabuf_len(in_decrypted) == 0) {
807*c1d255d3SCy Schubert 		wpabuf_free(in_decrypted);
808*c1d255d3SCy Schubert 		return 1;
809*c1d255d3SCy Schubert 	}
81039beb93cSSam Leffler 
81139beb93cSSam Leffler continue_req:
81239beb93cSSam Leffler 	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
81339beb93cSSam Leffler 			in_decrypted);
81439beb93cSSam Leffler 
81539beb93cSSam Leffler 	hdr = wpabuf_mhead(in_decrypted);
81639beb93cSSam Leffler 	if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
81739beb93cSSam Leffler 	    be_to_host16(hdr->length) == 5 &&
81839beb93cSSam Leffler 	    eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
81939beb93cSSam Leffler 		/* At least FreeRADIUS seems to send full EAP header with
82039beb93cSSam Leffler 		 * EAP Request Identity */
82139beb93cSSam Leffler 		skip_change = 1;
82239beb93cSSam Leffler 	}
82339beb93cSSam Leffler 	if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
82439beb93cSSam Leffler 	    eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
82539beb93cSSam Leffler 		skip_change = 1;
82639beb93cSSam Leffler 	}
82739beb93cSSam Leffler 
82839beb93cSSam Leffler 	if (data->peap_version == 0 && !skip_change) {
82939beb93cSSam Leffler 		struct eap_hdr *nhdr;
83039beb93cSSam Leffler 		struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
83139beb93cSSam Leffler 						   wpabuf_len(in_decrypted));
83239beb93cSSam Leffler 		if (nmsg == NULL) {
8334bc52338SCy Schubert 			wpabuf_clear_free(in_decrypted);
83439beb93cSSam Leffler 			return 0;
83539beb93cSSam Leffler 		}
83639beb93cSSam Leffler 		nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
83739beb93cSSam Leffler 		wpabuf_put_buf(nmsg, in_decrypted);
83839beb93cSSam Leffler 		nhdr->code = req->code;
83939beb93cSSam Leffler 		nhdr->identifier = req->identifier;
84039beb93cSSam Leffler 		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
84139beb93cSSam Leffler 					    wpabuf_len(in_decrypted));
84239beb93cSSam Leffler 
8434bc52338SCy Schubert 		wpabuf_clear_free(in_decrypted);
84439beb93cSSam Leffler 		in_decrypted = nmsg;
84539beb93cSSam Leffler 	}
84639beb93cSSam Leffler 
84739beb93cSSam Leffler 	hdr = wpabuf_mhead(in_decrypted);
84839beb93cSSam Leffler 	if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
84939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
85039beb93cSSam Leffler 			   "EAP frame (len=%lu)",
85139beb93cSSam Leffler 			   (unsigned long) wpabuf_len(in_decrypted));
8524bc52338SCy Schubert 		wpabuf_clear_free(in_decrypted);
85339beb93cSSam Leffler 		return 0;
85439beb93cSSam Leffler 	}
85539beb93cSSam Leffler 	len = be_to_host16(hdr->length);
85639beb93cSSam Leffler 	if (len > wpabuf_len(in_decrypted)) {
85739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
85839beb93cSSam Leffler 			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
85939beb93cSSam Leffler 			   (unsigned long) wpabuf_len(in_decrypted),
86039beb93cSSam Leffler 			   (unsigned long) len);
8614bc52338SCy Schubert 		wpabuf_clear_free(in_decrypted);
86239beb93cSSam Leffler 		return 0;
86339beb93cSSam Leffler 	}
86439beb93cSSam Leffler 	if (len < wpabuf_len(in_decrypted)) {
86539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
86639beb93cSSam Leffler 			   "shorter length than full decrypted data "
86739beb93cSSam Leffler 			   "(%lu < %lu)",
86839beb93cSSam Leffler 			   (unsigned long) len,
86939beb93cSSam Leffler 			   (unsigned long) wpabuf_len(in_decrypted));
87039beb93cSSam Leffler 	}
87139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
87239beb93cSSam Leffler 		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
87339beb93cSSam Leffler 		   (unsigned long) len);
87439beb93cSSam Leffler 	switch (hdr->code) {
87539beb93cSSam Leffler 	case EAP_CODE_REQUEST:
87639beb93cSSam Leffler 		if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
87739beb93cSSam Leffler 					    &resp)) {
8784bc52338SCy Schubert 			wpabuf_clear_free(in_decrypted);
87939beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
88039beb93cSSam Leffler 				   "processing failed");
88139beb93cSSam Leffler 			return 0;
88239beb93cSSam Leffler 		}
88339beb93cSSam Leffler 		break;
88439beb93cSSam Leffler 	case EAP_CODE_SUCCESS:
88539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
88639beb93cSSam Leffler 		if (data->peap_version == 1) {
88739beb93cSSam Leffler 			/* EAP-Success within TLS tunnel is used to indicate
88839beb93cSSam Leffler 			 * shutdown of the TLS channel. The authentication has
88939beb93cSSam Leffler 			 * been completed. */
89039beb93cSSam Leffler 			if (data->phase2_eap_started &&
89139beb93cSSam Leffler 			    !data->phase2_eap_success) {
89239beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
89339beb93cSSam Leffler 					   "Success used to indicate success, "
89439beb93cSSam Leffler 					   "but Phase 2 EAP was not yet "
89539beb93cSSam Leffler 					   "completed successfully");
89639beb93cSSam Leffler 				ret->methodState = METHOD_DONE;
89739beb93cSSam Leffler 				ret->decision = DECISION_FAIL;
8984bc52338SCy Schubert 				wpabuf_clear_free(in_decrypted);
89939beb93cSSam Leffler 				return 0;
90039beb93cSSam Leffler 			}
90139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
90239beb93cSSam Leffler 				   "EAP-Success within TLS tunnel - "
90339beb93cSSam Leffler 				   "authentication completed");
90439beb93cSSam Leffler 			ret->decision = DECISION_UNCOND_SUCC;
90539beb93cSSam Leffler 			ret->methodState = METHOD_DONE;
90639beb93cSSam Leffler 			data->phase2_success = 1;
90739beb93cSSam Leffler 			if (data->peap_outer_success == 2) {
9084bc52338SCy Schubert 				wpabuf_clear_free(in_decrypted);
90939beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
91039beb93cSSam Leffler 					   "to finish authentication");
91139beb93cSSam Leffler 				return 1;
91239beb93cSSam Leffler 			} else if (data->peap_outer_success == 1) {
91339beb93cSSam Leffler 				/* Reply with EAP-Success within the TLS
91439beb93cSSam Leffler 				 * channel to complete the authentication. */
91539beb93cSSam Leffler 				resp = wpabuf_alloc(sizeof(struct eap_hdr));
91639beb93cSSam Leffler 				if (resp) {
91739beb93cSSam Leffler 					rhdr = wpabuf_put(resp, sizeof(*rhdr));
91839beb93cSSam Leffler 					rhdr->code = EAP_CODE_SUCCESS;
91939beb93cSSam Leffler 					rhdr->identifier = hdr->identifier;
92039beb93cSSam Leffler 					rhdr->length =
92139beb93cSSam Leffler 						host_to_be16(sizeof(*rhdr));
92239beb93cSSam Leffler 				}
92339beb93cSSam Leffler 			} else {
92439beb93cSSam Leffler 				/* No EAP-Success expected for Phase 1 (outer,
92539beb93cSSam Leffler 				 * unencrypted auth), so force EAP state
92639beb93cSSam Leffler 				 * machine to SUCCESS state. */
927*c1d255d3SCy Schubert 				sm->peap_done = true;
92839beb93cSSam Leffler 			}
92939beb93cSSam Leffler 		} else {
93039beb93cSSam Leffler 			/* FIX: ? */
93139beb93cSSam Leffler 		}
93239beb93cSSam Leffler 		break;
93339beb93cSSam Leffler 	case EAP_CODE_FAILURE:
93439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
93539beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
93639beb93cSSam Leffler 		ret->methodState = METHOD_MAY_CONT;
937*c1d255d3SCy Schubert 		ret->allowNotifications = false;
93839beb93cSSam Leffler 		/* Reply with EAP-Failure within the TLS channel to complete
93939beb93cSSam Leffler 		 * failure reporting. */
94039beb93cSSam Leffler 		resp = wpabuf_alloc(sizeof(struct eap_hdr));
94139beb93cSSam Leffler 		if (resp) {
94239beb93cSSam Leffler 			rhdr = wpabuf_put(resp, sizeof(*rhdr));
94339beb93cSSam Leffler 			rhdr->code = EAP_CODE_FAILURE;
94439beb93cSSam Leffler 			rhdr->identifier = hdr->identifier;
94539beb93cSSam Leffler 			rhdr->length = host_to_be16(sizeof(*rhdr));
94639beb93cSSam Leffler 		}
94739beb93cSSam Leffler 		break;
94839beb93cSSam Leffler 	default:
94939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
95039beb93cSSam Leffler 			   "Phase 2 EAP header", hdr->code);
95139beb93cSSam Leffler 		break;
95239beb93cSSam Leffler 	}
95339beb93cSSam Leffler 
9544bc52338SCy Schubert 	wpabuf_clear_free(in_decrypted);
95539beb93cSSam Leffler 
95639beb93cSSam Leffler 	if (resp) {
95739beb93cSSam Leffler 		int skip_change2 = 0;
95839beb93cSSam Leffler 		struct wpabuf *rmsg, buf;
95939beb93cSSam Leffler 
96039beb93cSSam Leffler 		wpa_hexdump_buf_key(MSG_DEBUG,
96139beb93cSSam Leffler 				    "EAP-PEAP: Encrypting Phase 2 data", resp);
96239beb93cSSam Leffler 		/* PEAP version changes */
96339beb93cSSam Leffler 		if (wpabuf_len(resp) >= 5 &&
96439beb93cSSam Leffler 		    wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
96539beb93cSSam Leffler 		    eap_get_type(resp) == EAP_TYPE_TLV)
96639beb93cSSam Leffler 			skip_change2 = 1;
96739beb93cSSam Leffler 		rmsg = resp;
96839beb93cSSam Leffler 		if (data->peap_version == 0 && !skip_change2) {
96939beb93cSSam Leffler 			wpabuf_set(&buf, wpabuf_head_u8(resp) +
97039beb93cSSam Leffler 				   sizeof(struct eap_hdr),
97139beb93cSSam Leffler 				   wpabuf_len(resp) - sizeof(struct eap_hdr));
97239beb93cSSam Leffler 			rmsg = &buf;
97339beb93cSSam Leffler 		}
97439beb93cSSam Leffler 
97539beb93cSSam Leffler 		if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
97639beb93cSSam Leffler 					 data->peap_version, req->identifier,
97739beb93cSSam Leffler 					 rmsg, out_data)) {
97839beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
97939beb93cSSam Leffler 				   "a Phase 2 frame");
98039beb93cSSam Leffler 		}
9814bc52338SCy Schubert 		wpabuf_clear_free(resp);
98239beb93cSSam Leffler 	}
98339beb93cSSam Leffler 
98439beb93cSSam Leffler 	return 0;
98539beb93cSSam Leffler }
98639beb93cSSam Leffler 
98739beb93cSSam Leffler 
eap_peap_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)98839beb93cSSam Leffler static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
98939beb93cSSam Leffler 					struct eap_method_ret *ret,
99039beb93cSSam Leffler 					const struct wpabuf *reqData)
99139beb93cSSam Leffler {
99239beb93cSSam Leffler 	const struct eap_hdr *req;
99339beb93cSSam Leffler 	size_t left;
99439beb93cSSam Leffler 	int res;
99539beb93cSSam Leffler 	u8 flags, id;
99639beb93cSSam Leffler 	struct wpabuf *resp;
99739beb93cSSam Leffler 	const u8 *pos;
99839beb93cSSam Leffler 	struct eap_peap_data *data = priv;
999325151a3SRui Paulo 	struct wpabuf msg;
100039beb93cSSam Leffler 
100139beb93cSSam Leffler 	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
100239beb93cSSam Leffler 					reqData, &left, &flags);
100339beb93cSSam Leffler 	if (pos == NULL)
100439beb93cSSam Leffler 		return NULL;
100539beb93cSSam Leffler 	req = wpabuf_head(reqData);
100639beb93cSSam Leffler 	id = req->identifier;
100739beb93cSSam Leffler 
100839beb93cSSam Leffler 	if (flags & EAP_TLS_FLAGS_START) {
100939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
1010e28a4053SRui Paulo 			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
101139beb93cSSam Leffler 			data->peap_version);
1012e28a4053SRui Paulo 		if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version)
1013e28a4053SRui Paulo 			data->peap_version = flags & EAP_TLS_VERSION_MASK;
101439beb93cSSam Leffler 		if (data->force_peap_version >= 0 &&
101539beb93cSSam Leffler 		    data->force_peap_version != data->peap_version) {
101639beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
101739beb93cSSam Leffler 				   "forced PEAP version %d",
101839beb93cSSam Leffler 				   data->force_peap_version);
101939beb93cSSam Leffler 			ret->methodState = METHOD_DONE;
102039beb93cSSam Leffler 			ret->decision = DECISION_FAIL;
1021*c1d255d3SCy Schubert 			ret->allowNotifications = false;
102239beb93cSSam Leffler 			return NULL;
102339beb93cSSam Leffler 		}
102439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
102539beb93cSSam Leffler 			   data->peap_version);
102639beb93cSSam Leffler 		left = 0; /* make sure that this frame is empty, even though it
102739beb93cSSam Leffler 			   * should always be, anyway */
102839beb93cSSam Leffler 	}
102939beb93cSSam Leffler 
1030325151a3SRui Paulo 	wpabuf_set(&msg, pos, left);
1031325151a3SRui Paulo 
103239beb93cSSam Leffler 	resp = NULL;
103339beb93cSSam Leffler 	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
103439beb93cSSam Leffler 	    !data->resuming) {
103539beb93cSSam Leffler 		res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
103639beb93cSSam Leffler 	} else {
1037780fb4a2SCy Schubert 		if (sm->waiting_ext_cert_check && data->pending_resp) {
1038780fb4a2SCy Schubert 			struct eap_peer_config *config = eap_get_config(sm);
1039780fb4a2SCy Schubert 
1040780fb4a2SCy Schubert 			if (config->pending_ext_cert_check ==
1041780fb4a2SCy Schubert 			    EXT_CERT_CHECK_GOOD) {
1042780fb4a2SCy Schubert 				wpa_printf(MSG_DEBUG,
1043780fb4a2SCy Schubert 					   "EAP-PEAP: External certificate check succeeded - continue handshake");
1044780fb4a2SCy Schubert 				resp = data->pending_resp;
1045780fb4a2SCy Schubert 				data->pending_resp = NULL;
1046780fb4a2SCy Schubert 				sm->waiting_ext_cert_check = 0;
1047780fb4a2SCy Schubert 				return resp;
1048780fb4a2SCy Schubert 			}
1049780fb4a2SCy Schubert 
1050780fb4a2SCy Schubert 			if (config->pending_ext_cert_check ==
1051780fb4a2SCy Schubert 			    EXT_CERT_CHECK_BAD) {
1052780fb4a2SCy Schubert 				wpa_printf(MSG_DEBUG,
1053780fb4a2SCy Schubert 					   "EAP-PEAP: External certificate check failed - force authentication failure");
1054780fb4a2SCy Schubert 				ret->methodState = METHOD_DONE;
1055780fb4a2SCy Schubert 				ret->decision = DECISION_FAIL;
1056780fb4a2SCy Schubert 				sm->waiting_ext_cert_check = 0;
1057780fb4a2SCy Schubert 				return NULL;
1058780fb4a2SCy Schubert 			}
1059780fb4a2SCy Schubert 
1060780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG,
1061780fb4a2SCy Schubert 				   "EAP-PEAP: Continuing to wait external server certificate validation");
1062780fb4a2SCy Schubert 			return NULL;
1063780fb4a2SCy Schubert 		}
1064780fb4a2SCy Schubert 
106539beb93cSSam Leffler 		res = eap_peer_tls_process_helper(sm, &data->ssl,
106639beb93cSSam Leffler 						  EAP_TYPE_PEAP,
1067325151a3SRui Paulo 						  data->peap_version, id, &msg,
1068325151a3SRui Paulo 						  &resp);
106939beb93cSSam Leffler 
1070325151a3SRui Paulo 		if (res < 0) {
1071325151a3SRui Paulo 			wpa_printf(MSG_DEBUG,
1072325151a3SRui Paulo 				   "EAP-PEAP: TLS processing failed");
1073325151a3SRui Paulo 			ret->methodState = METHOD_DONE;
1074325151a3SRui Paulo 			ret->decision = DECISION_FAIL;
1075325151a3SRui Paulo 			return resp;
1076325151a3SRui Paulo 		}
1077780fb4a2SCy Schubert 
1078780fb4a2SCy Schubert 
1079780fb4a2SCy Schubert 		if (sm->waiting_ext_cert_check) {
1080780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG,
1081780fb4a2SCy Schubert 				   "EAP-PEAP: Waiting external server certificate validation");
10824bc52338SCy Schubert 			wpabuf_clear_free(data->pending_resp);
1083780fb4a2SCy Schubert 			data->pending_resp = resp;
1084780fb4a2SCy Schubert 			return NULL;
1085780fb4a2SCy Schubert 		}
1086780fb4a2SCy Schubert 
108739beb93cSSam Leffler 		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
1088*c1d255d3SCy Schubert 			const char *label;
1089*c1d255d3SCy Schubert 			const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
1090*c1d255d3SCy Schubert 			const u8 *context = NULL;
1091*c1d255d3SCy Schubert 			size_t context_len = 0;
1092*c1d255d3SCy Schubert 
109339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG,
109439beb93cSSam Leffler 				   "EAP-PEAP: TLS done, proceed to Phase 2");
10955b9c547cSRui Paulo 			eap_peap_free_key(data);
109639beb93cSSam Leffler 			/* draft-josefsson-ppext-eap-tls-eap-05.txt
109739beb93cSSam Leffler 			 * specifies that PEAPv1 would use "client PEAP
109839beb93cSSam Leffler 			 * encryption" as the label. However, most existing
109939beb93cSSam Leffler 			 * PEAPv1 implementations seem to be using the old
110039beb93cSSam Leffler 			 * label, "client EAP encryption", instead. Use the old
110139beb93cSSam Leffler 			 * label by default, but allow it to be configured with
1102*c1d255d3SCy Schubert 			 * phase1 parameter peaplabel=1.
1103*c1d255d3SCy Schubert 			 *
1104*c1d255d3SCy Schubert 			 * When using TLS 1.3, draft-ietf-emu-tls-eap-types
1105*c1d255d3SCy Schubert 			 * defines a new set of label and context parameters.
1106*c1d255d3SCy Schubert 			 */
1107*c1d255d3SCy Schubert 			if (data->ssl.tls_v13) {
1108*c1d255d3SCy Schubert 				label = "EXPORTER_EAP_TLS_Key_Material";
1109*c1d255d3SCy Schubert 				context = eap_tls13_context;
1110*c1d255d3SCy Schubert 				context_len = sizeof(eap_tls13_context);
1111*c1d255d3SCy Schubert 			} else if (data->force_new_label) {
111239beb93cSSam Leffler 				label = "client PEAP encryption";
1113*c1d255d3SCy Schubert 			} else {
111439beb93cSSam Leffler 				label = "client EAP encryption";
1115*c1d255d3SCy Schubert 			}
111639beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
111739beb93cSSam Leffler 				   "key derivation", label);
111839beb93cSSam Leffler 			data->key_data =
111939beb93cSSam Leffler 				eap_peer_tls_derive_key(sm, &data->ssl, label,
1120*c1d255d3SCy Schubert 							context, context_len,
11214bc52338SCy Schubert 							EAP_TLS_KEY_LEN +
11224bc52338SCy Schubert 							EAP_EMSK_LEN);
112339beb93cSSam Leffler 			if (data->key_data) {
112439beb93cSSam Leffler 				wpa_hexdump_key(MSG_DEBUG,
112539beb93cSSam Leffler 						"EAP-PEAP: Derived key",
112639beb93cSSam Leffler 						data->key_data,
112739beb93cSSam Leffler 						EAP_TLS_KEY_LEN);
11284bc52338SCy Schubert 				wpa_hexdump_key(MSG_DEBUG,
11294bc52338SCy Schubert 						"EAP-PEAP: Derived EMSK",
11304bc52338SCy Schubert 						data->key_data +
11314bc52338SCy Schubert 						EAP_TLS_KEY_LEN,
11324bc52338SCy Schubert 						EAP_EMSK_LEN);
113339beb93cSSam Leffler 			} else {
113439beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
113539beb93cSSam Leffler 					   "derive key");
113639beb93cSSam Leffler 			}
113739beb93cSSam Leffler 
11385b9c547cSRui Paulo 			os_free(data->session_id);
11395b9c547cSRui Paulo 			data->session_id =
11405b9c547cSRui Paulo 				eap_peer_tls_derive_session_id(sm, &data->ssl,
11415b9c547cSRui Paulo 							       EAP_TYPE_PEAP,
11425b9c547cSRui Paulo 							       &data->id_len);
11435b9c547cSRui Paulo 			if (data->session_id) {
11445b9c547cSRui Paulo 				wpa_hexdump(MSG_DEBUG,
11455b9c547cSRui Paulo 					    "EAP-PEAP: Derived Session-Id",
11465b9c547cSRui Paulo 					    data->session_id, data->id_len);
11475b9c547cSRui Paulo 			} else {
11485b9c547cSRui Paulo 				wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
11495b9c547cSRui Paulo 					   "derive Session-Id");
11505b9c547cSRui Paulo 			}
11515b9c547cSRui Paulo 
115239beb93cSSam Leffler 			if (sm->workaround && data->resuming) {
115339beb93cSSam Leffler 				/*
115439beb93cSSam Leffler 				 * At least few RADIUS servers (Aegis v1.1.6;
115539beb93cSSam Leffler 				 * but not v1.1.4; and Cisco ACS) seem to be
115639beb93cSSam Leffler 				 * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
115739beb93cSSam Leffler 				 * ACS) session resumption with outer
115839beb93cSSam Leffler 				 * EAP-Success. This does not seem to follow
115939beb93cSSam Leffler 				 * draft-josefsson-pppext-eap-tls-eap-05.txt
116039beb93cSSam Leffler 				 * section 4.2, so only allow this if EAP
116139beb93cSSam Leffler 				 * workarounds are enabled.
116239beb93cSSam Leffler 				 */
116339beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
116439beb93cSSam Leffler 					   "allow outer EAP-Success to "
116539beb93cSSam Leffler 					   "terminate PEAP resumption");
116639beb93cSSam Leffler 				ret->decision = DECISION_COND_SUCC;
116739beb93cSSam Leffler 				data->phase2_success = 1;
116839beb93cSSam Leffler 			}
116939beb93cSSam Leffler 
117039beb93cSSam Leffler 			data->resuming = 0;
117139beb93cSSam Leffler 		}
117239beb93cSSam Leffler 
117339beb93cSSam Leffler 		if (res == 2) {
117439beb93cSSam Leffler 			/*
117539beb93cSSam Leffler 			 * Application data included in the handshake message.
117639beb93cSSam Leffler 			 */
11774bc52338SCy Schubert 			wpabuf_clear_free(data->pending_phase2_req);
117839beb93cSSam Leffler 			data->pending_phase2_req = resp;
117939beb93cSSam Leffler 			resp = NULL;
118039beb93cSSam Leffler 			res = eap_peap_decrypt(sm, data, ret, req, &msg,
118139beb93cSSam Leffler 					       &resp);
118239beb93cSSam Leffler 		}
118339beb93cSSam Leffler 	}
118439beb93cSSam Leffler 
118539beb93cSSam Leffler 	if (ret->methodState == METHOD_DONE) {
1186*c1d255d3SCy Schubert 		ret->allowNotifications = false;
118739beb93cSSam Leffler 	}
118839beb93cSSam Leffler 
118939beb93cSSam Leffler 	if (res == 1) {
11904bc52338SCy Schubert 		wpabuf_clear_free(resp);
119139beb93cSSam Leffler 		return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
119239beb93cSSam Leffler 					      data->peap_version);
119339beb93cSSam Leffler 	}
119439beb93cSSam Leffler 
119539beb93cSSam Leffler 	return resp;
119639beb93cSSam Leffler }
119739beb93cSSam Leffler 
119839beb93cSSam Leffler 
eap_peap_has_reauth_data(struct eap_sm * sm,void * priv)1199*c1d255d3SCy Schubert static bool eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
120039beb93cSSam Leffler {
120139beb93cSSam Leffler 	struct eap_peap_data *data = priv;
120239beb93cSSam Leffler 	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
120339beb93cSSam Leffler 		data->phase2_success;
120439beb93cSSam Leffler }
120539beb93cSSam Leffler 
120639beb93cSSam Leffler 
eap_peap_deinit_for_reauth(struct eap_sm * sm,void * priv)120739beb93cSSam Leffler static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
120839beb93cSSam Leffler {
120939beb93cSSam Leffler 	struct eap_peap_data *data = priv;
121085732ac8SCy Schubert 
121185732ac8SCy Schubert 	if (data->phase2_priv && data->phase2_method &&
121285732ac8SCy Schubert 	    data->phase2_method->deinit_for_reauth)
121385732ac8SCy Schubert 		data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
12144bc52338SCy Schubert 	wpabuf_clear_free(data->pending_phase2_req);
121539beb93cSSam Leffler 	data->pending_phase2_req = NULL;
12164bc52338SCy Schubert 	wpabuf_clear_free(data->pending_resp);
1217780fb4a2SCy Schubert 	data->pending_resp = NULL;
121839beb93cSSam Leffler 	data->crypto_binding_used = 0;
121939beb93cSSam Leffler }
122039beb93cSSam Leffler 
122139beb93cSSam Leffler 
eap_peap_init_for_reauth(struct eap_sm * sm,void * priv)122239beb93cSSam Leffler static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
122339beb93cSSam Leffler {
122439beb93cSSam Leffler 	struct eap_peap_data *data = priv;
12255b9c547cSRui Paulo 	eap_peap_free_key(data);
12265b9c547cSRui Paulo 	os_free(data->session_id);
12275b9c547cSRui Paulo 	data->session_id = NULL;
122839beb93cSSam Leffler 	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
122939beb93cSSam Leffler 		os_free(data);
123039beb93cSSam Leffler 		return NULL;
123139beb93cSSam Leffler 	}
123239beb93cSSam Leffler 	if (data->phase2_priv && data->phase2_method &&
123339beb93cSSam Leffler 	    data->phase2_method->init_for_reauth)
123439beb93cSSam Leffler 		data->phase2_method->init_for_reauth(sm, data->phase2_priv);
123539beb93cSSam Leffler 	data->phase2_success = 0;
123639beb93cSSam Leffler 	data->phase2_eap_success = 0;
123739beb93cSSam Leffler 	data->phase2_eap_started = 0;
123839beb93cSSam Leffler 	data->resuming = 1;
123939beb93cSSam Leffler 	data->reauth = 1;
1240*c1d255d3SCy Schubert 	sm->peap_done = false;
124139beb93cSSam Leffler 	return priv;
124239beb93cSSam Leffler }
124339beb93cSSam Leffler 
124439beb93cSSam Leffler 
eap_peap_get_status(struct eap_sm * sm,void * priv,char * buf,size_t buflen,int verbose)124539beb93cSSam Leffler static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
124639beb93cSSam Leffler 			       size_t buflen, int verbose)
124739beb93cSSam Leffler {
124839beb93cSSam Leffler 	struct eap_peap_data *data = priv;
124939beb93cSSam Leffler 	int len, ret;
125039beb93cSSam Leffler 
125139beb93cSSam Leffler 	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
125239beb93cSSam Leffler 	if (data->phase2_method) {
125339beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len,
125439beb93cSSam Leffler 				  "EAP-PEAPv%d Phase2 method=%s\n",
125539beb93cSSam Leffler 				  data->peap_version,
125639beb93cSSam Leffler 				  data->phase2_method->name);
12575b9c547cSRui Paulo 		if (os_snprintf_error(buflen - len, ret))
125839beb93cSSam Leffler 			return len;
125939beb93cSSam Leffler 		len += ret;
126039beb93cSSam Leffler 	}
126139beb93cSSam Leffler 	return len;
126239beb93cSSam Leffler }
126339beb93cSSam Leffler 
126439beb93cSSam Leffler 
eap_peap_isKeyAvailable(struct eap_sm * sm,void * priv)1265*c1d255d3SCy Schubert static bool eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
126639beb93cSSam Leffler {
126739beb93cSSam Leffler 	struct eap_peap_data *data = priv;
126839beb93cSSam Leffler 	return data->key_data != NULL && data->phase2_success;
126939beb93cSSam Leffler }
127039beb93cSSam Leffler 
127139beb93cSSam Leffler 
eap_peap_getKey(struct eap_sm * sm,void * priv,size_t * len)127239beb93cSSam Leffler static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
127339beb93cSSam Leffler {
127439beb93cSSam Leffler 	struct eap_peap_data *data = priv;
127539beb93cSSam Leffler 	u8 *key;
127639beb93cSSam Leffler 
127739beb93cSSam Leffler 	if (data->key_data == NULL || !data->phase2_success)
127839beb93cSSam Leffler 		return NULL;
127939beb93cSSam Leffler 
128039beb93cSSam Leffler 	key = os_malloc(EAP_TLS_KEY_LEN);
128139beb93cSSam Leffler 	if (key == NULL)
128239beb93cSSam Leffler 		return NULL;
128339beb93cSSam Leffler 
128439beb93cSSam Leffler 	*len = EAP_TLS_KEY_LEN;
128539beb93cSSam Leffler 
128639beb93cSSam Leffler 	if (data->crypto_binding_used) {
128739beb93cSSam Leffler 		u8 csk[128];
128839beb93cSSam Leffler 		/*
128939beb93cSSam Leffler 		 * Note: It looks like Microsoft implementation requires null
129039beb93cSSam Leffler 		 * termination for this label while the one used for deriving
129139beb93cSSam Leffler 		 * IPMK|CMK did not use null termination.
129239beb93cSSam Leffler 		 */
1293f05cddf9SRui Paulo 		if (peap_prfplus(data->peap_version, data->ipmk, 40,
129439beb93cSSam Leffler 				 "Session Key Generating Function",
1295f05cddf9SRui Paulo 				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
1296f05cddf9SRui Paulo 			os_free(key);
1297f05cddf9SRui Paulo 			return NULL;
1298f05cddf9SRui Paulo 		}
129939beb93cSSam Leffler 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
130039beb93cSSam Leffler 		os_memcpy(key, csk, EAP_TLS_KEY_LEN);
130139beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
130239beb93cSSam Leffler 			    key, EAP_TLS_KEY_LEN);
1303206b73d0SCy Schubert 		forced_memzero(csk, sizeof(csk));
130439beb93cSSam Leffler 	} else
130539beb93cSSam Leffler 		os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
130639beb93cSSam Leffler 
130739beb93cSSam Leffler 	return key;
130839beb93cSSam Leffler }
130939beb93cSSam Leffler 
131039beb93cSSam Leffler 
eap_peap_get_emsk(struct eap_sm * sm,void * priv,size_t * len)13114bc52338SCy Schubert static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
13124bc52338SCy Schubert {
13134bc52338SCy Schubert 	struct eap_peap_data *data = priv;
13144bc52338SCy Schubert 	u8 *key;
13154bc52338SCy Schubert 
13164bc52338SCy Schubert 	if (!data->key_data || !data->phase2_success)
13174bc52338SCy Schubert 		return NULL;
13184bc52338SCy Schubert 
13194bc52338SCy Schubert 	if (data->crypto_binding_used) {
13204bc52338SCy Schubert 		/* [MS-PEAP] does not define EMSK derivation */
13214bc52338SCy Schubert 		return NULL;
13224bc52338SCy Schubert 	}
13234bc52338SCy Schubert 
13244bc52338SCy Schubert 	key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
13254bc52338SCy Schubert 	if (!key)
13264bc52338SCy Schubert 		return NULL;
13274bc52338SCy Schubert 
13284bc52338SCy Schubert 	*len = EAP_EMSK_LEN;
13294bc52338SCy Schubert 
13304bc52338SCy Schubert 	return key;
13314bc52338SCy Schubert }
13324bc52338SCy Schubert 
13334bc52338SCy Schubert 
eap_peap_get_session_id(struct eap_sm * sm,void * priv,size_t * len)13345b9c547cSRui Paulo static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
13355b9c547cSRui Paulo {
13365b9c547cSRui Paulo 	struct eap_peap_data *data = priv;
13375b9c547cSRui Paulo 	u8 *id;
13385b9c547cSRui Paulo 
13395b9c547cSRui Paulo 	if (data->session_id == NULL || !data->phase2_success)
13405b9c547cSRui Paulo 		return NULL;
13415b9c547cSRui Paulo 
134285732ac8SCy Schubert 	id = os_memdup(data->session_id, data->id_len);
13435b9c547cSRui Paulo 	if (id == NULL)
13445b9c547cSRui Paulo 		return NULL;
13455b9c547cSRui Paulo 
13465b9c547cSRui Paulo 	*len = data->id_len;
13475b9c547cSRui Paulo 
13485b9c547cSRui Paulo 	return id;
13495b9c547cSRui Paulo }
13505b9c547cSRui Paulo 
13515b9c547cSRui Paulo 
eap_peer_peap_register(void)135239beb93cSSam Leffler int eap_peer_peap_register(void)
135339beb93cSSam Leffler {
135439beb93cSSam Leffler 	struct eap_method *eap;
135539beb93cSSam Leffler 
135639beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
135739beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
135839beb93cSSam Leffler 	if (eap == NULL)
135939beb93cSSam Leffler 		return -1;
136039beb93cSSam Leffler 
136139beb93cSSam Leffler 	eap->init = eap_peap_init;
136239beb93cSSam Leffler 	eap->deinit = eap_peap_deinit;
136339beb93cSSam Leffler 	eap->process = eap_peap_process;
136439beb93cSSam Leffler 	eap->isKeyAvailable = eap_peap_isKeyAvailable;
136539beb93cSSam Leffler 	eap->getKey = eap_peap_getKey;
13664bc52338SCy Schubert 	eap->get_emsk = eap_peap_get_emsk;
136739beb93cSSam Leffler 	eap->get_status = eap_peap_get_status;
136839beb93cSSam Leffler 	eap->has_reauth_data = eap_peap_has_reauth_data;
136939beb93cSSam Leffler 	eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
137039beb93cSSam Leffler 	eap->init_for_reauth = eap_peap_init_for_reauth;
13715b9c547cSRui Paulo 	eap->getSessionId = eap_peap_get_session_id;
137239beb93cSSam Leffler 
1373780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
137439beb93cSSam Leffler }
1375