xref: /freebsd-src/contrib/wpa/src/eap_peer/eap_tls_common.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
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"
12e28a4053SRui Paulo #include "crypto/sha1.h"
13e28a4053SRui Paulo #include "crypto/tls.h"
1439beb93cSSam Leffler #include "eap_i.h"
1539beb93cSSam Leffler #include "eap_tls_common.h"
1639beb93cSSam Leffler #include "eap_config.h"
1739beb93cSSam Leffler 
1839beb93cSSam Leffler 
19c1d255d3SCy Schubert static struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
20f05cddf9SRui Paulo 					 u8 code, u8 identifier)
21f05cddf9SRui Paulo {
22f05cddf9SRui Paulo 	if (type == EAP_UNAUTH_TLS_TYPE)
23f05cddf9SRui Paulo 		return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
24f05cddf9SRui Paulo 				     EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
25f05cddf9SRui Paulo 				     code, identifier);
265b9c547cSRui Paulo 	if (type == EAP_WFA_UNAUTH_TLS_TYPE)
275b9c547cSRui Paulo 		return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
285b9c547cSRui Paulo 				     EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
295b9c547cSRui Paulo 				     code, identifier);
30f05cddf9SRui Paulo 	return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
31f05cddf9SRui Paulo 			     identifier);
32f05cddf9SRui Paulo }
33f05cddf9SRui Paulo 
34f05cddf9SRui Paulo 
3539beb93cSSam Leffler static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
3639beb93cSSam Leffler 			      const u8 **data, size_t *data_len)
3739beb93cSSam Leffler {
3839beb93cSSam Leffler 	const struct wpa_config_blob *blob;
3939beb93cSSam Leffler 
4039beb93cSSam Leffler 	if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
4139beb93cSSam Leffler 		return 0;
4239beb93cSSam Leffler 
4339beb93cSSam Leffler 	blob = eap_get_config_blob(sm, *name + 7);
4439beb93cSSam Leffler 	if (blob == NULL) {
4539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
4639beb93cSSam Leffler 			   "found", __func__, *name + 7);
4739beb93cSSam Leffler 		return -1;
4839beb93cSSam Leffler 	}
4939beb93cSSam Leffler 
5039beb93cSSam Leffler 	*name = NULL;
5139beb93cSSam Leffler 	*data = blob->data;
5239beb93cSSam Leffler 	*data_len = blob->len;
5339beb93cSSam Leffler 
5439beb93cSSam Leffler 	return 0;
5539beb93cSSam Leffler }
5639beb93cSSam Leffler 
5739beb93cSSam Leffler 
583157ba21SRui Paulo static void eap_tls_params_flags(struct tls_connection_params *params,
593157ba21SRui Paulo 				 const char *txt)
603157ba21SRui Paulo {
613157ba21SRui Paulo 	if (txt == NULL)
623157ba21SRui Paulo 		return;
633157ba21SRui Paulo 	if (os_strstr(txt, "tls_allow_md5=1"))
643157ba21SRui Paulo 		params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
653157ba21SRui Paulo 	if (os_strstr(txt, "tls_disable_time_checks=1"))
663157ba21SRui Paulo 		params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
67f05cddf9SRui Paulo 	if (os_strstr(txt, "tls_disable_session_ticket=1"))
68f05cddf9SRui Paulo 		params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
69f05cddf9SRui Paulo 	if (os_strstr(txt, "tls_disable_session_ticket=0"))
70f05cddf9SRui Paulo 		params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
71325151a3SRui Paulo 	if (os_strstr(txt, "tls_disable_tlsv1_0=1"))
72325151a3SRui Paulo 		params->flags |= TLS_CONN_DISABLE_TLSv1_0;
734bc52338SCy Schubert 	if (os_strstr(txt, "tls_disable_tlsv1_0=0")) {
74325151a3SRui Paulo 		params->flags &= ~TLS_CONN_DISABLE_TLSv1_0;
754bc52338SCy Schubert 		params->flags |= TLS_CONN_ENABLE_TLSv1_0;
764bc52338SCy Schubert 	}
775b9c547cSRui Paulo 	if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
785b9c547cSRui Paulo 		params->flags |= TLS_CONN_DISABLE_TLSv1_1;
794bc52338SCy Schubert 	if (os_strstr(txt, "tls_disable_tlsv1_1=0")) {
805b9c547cSRui Paulo 		params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
814bc52338SCy Schubert 		params->flags |= TLS_CONN_ENABLE_TLSv1_1;
824bc52338SCy Schubert 	}
835b9c547cSRui Paulo 	if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
845b9c547cSRui Paulo 		params->flags |= TLS_CONN_DISABLE_TLSv1_2;
854bc52338SCy Schubert 	if (os_strstr(txt, "tls_disable_tlsv1_2=0")) {
865b9c547cSRui Paulo 		params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
874bc52338SCy Schubert 		params->flags |= TLS_CONN_ENABLE_TLSv1_2;
884bc52338SCy Schubert 	}
8985732ac8SCy Schubert 	if (os_strstr(txt, "tls_disable_tlsv1_3=1"))
9085732ac8SCy Schubert 		params->flags |= TLS_CONN_DISABLE_TLSv1_3;
9185732ac8SCy Schubert 	if (os_strstr(txt, "tls_disable_tlsv1_3=0"))
9285732ac8SCy Schubert 		params->flags &= ~TLS_CONN_DISABLE_TLSv1_3;
93780fb4a2SCy Schubert 	if (os_strstr(txt, "tls_ext_cert_check=1"))
94780fb4a2SCy Schubert 		params->flags |= TLS_CONN_EXT_CERT_CHECK;
95780fb4a2SCy Schubert 	if (os_strstr(txt, "tls_ext_cert_check=0"))
96780fb4a2SCy Schubert 		params->flags &= ~TLS_CONN_EXT_CERT_CHECK;
9785732ac8SCy Schubert 	if (os_strstr(txt, "tls_suiteb=1"))
9885732ac8SCy Schubert 		params->flags |= TLS_CONN_SUITEB;
9985732ac8SCy Schubert 	if (os_strstr(txt, "tls_suiteb=0"))
10085732ac8SCy Schubert 		params->flags &= ~TLS_CONN_SUITEB;
10185732ac8SCy Schubert 	if (os_strstr(txt, "tls_suiteb_no_ecdh=1"))
10285732ac8SCy Schubert 		params->flags |= TLS_CONN_SUITEB_NO_ECDH;
10385732ac8SCy Schubert 	if (os_strstr(txt, "tls_suiteb_no_ecdh=0"))
10485732ac8SCy Schubert 		params->flags &= ~TLS_CONN_SUITEB_NO_ECDH;
105*a90b9d01SCy Schubert 	if (os_strstr(txt, "allow_unsafe_renegotiation=1"))
106*a90b9d01SCy Schubert 		params->flags |= TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION;
107*a90b9d01SCy Schubert 	if (os_strstr(txt, "allow_unsafe_renegotiation=0"))
108*a90b9d01SCy Schubert 		params->flags &= ~TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION;
1093157ba21SRui Paulo }
1103157ba21SRui Paulo 
1113157ba21SRui Paulo 
112c1d255d3SCy Schubert static void eap_tls_cert_params_from_conf(struct tls_connection_params *params,
113c1d255d3SCy Schubert 					  struct eap_peer_cert_config *config)
11439beb93cSSam Leffler {
1154bc52338SCy Schubert 	params->ca_cert = config->ca_cert;
1164bc52338SCy Schubert 	params->ca_path = config->ca_path;
1174bc52338SCy Schubert 	params->client_cert = config->client_cert;
1184bc52338SCy Schubert 	params->private_key = config->private_key;
1194bc52338SCy Schubert 	params->private_key_passwd = config->private_key_passwd;
1204bc52338SCy Schubert 	params->subject_match = config->subject_match;
1214bc52338SCy Schubert 	params->altsubject_match = config->altsubject_match;
1224bc52338SCy Schubert 	params->check_cert_subject = config->check_cert_subject;
1235b9c547cSRui Paulo 	params->suffix_match = config->domain_suffix_match;
1245b9c547cSRui Paulo 	params->domain_match = config->domain_match;
12539beb93cSSam Leffler 	params->engine = config->engine;
12639beb93cSSam Leffler 	params->engine_id = config->engine_id;
12739beb93cSSam Leffler 	params->pin = config->pin;
12839beb93cSSam Leffler 	params->key_id = config->key_id;
12939beb93cSSam Leffler 	params->cert_id = config->cert_id;
13039beb93cSSam Leffler 	params->ca_cert_id = config->ca_cert_id;
131c1d255d3SCy Schubert 	if (config->ocsp)
132c1d255d3SCy Schubert 		params->flags |= TLS_CONN_REQUEST_OCSP;
133c1d255d3SCy Schubert 	if (config->ocsp >= 2)
134c1d255d3SCy Schubert 		params->flags |= TLS_CONN_REQUIRE_OCSP;
135c1d255d3SCy Schubert 	if (config->ocsp == 3)
136c1d255d3SCy Schubert 		params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
137c1d255d3SCy Schubert }
138c1d255d3SCy Schubert 
139c1d255d3SCy Schubert 
140c1d255d3SCy Schubert static void eap_tls_params_from_conf1(struct tls_connection_params *params,
141c1d255d3SCy Schubert 				      struct eap_peer_config *config)
142c1d255d3SCy Schubert {
143c1d255d3SCy Schubert 	eap_tls_cert_params_from_conf(params, &config->cert);
1443157ba21SRui Paulo 	eap_tls_params_flags(params, config->phase1);
14539beb93cSSam Leffler }
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 
14839beb93cSSam Leffler static void eap_tls_params_from_conf2(struct tls_connection_params *params,
14939beb93cSSam Leffler 				      struct eap_peer_config *config)
15039beb93cSSam Leffler {
151c1d255d3SCy Schubert 	eap_tls_cert_params_from_conf(params, &config->phase2_cert);
1523157ba21SRui Paulo 	eap_tls_params_flags(params, config->phase2);
15339beb93cSSam Leffler }
15439beb93cSSam Leffler 
15539beb93cSSam Leffler 
156c1d255d3SCy Schubert static void eap_tls_params_from_conf2m(struct tls_connection_params *params,
157c1d255d3SCy Schubert 				       struct eap_peer_config *config)
158c1d255d3SCy Schubert {
159c1d255d3SCy Schubert 	eap_tls_cert_params_from_conf(params, &config->machine_cert);
160c1d255d3SCy Schubert 	eap_tls_params_flags(params, config->machine_phase2);
161c1d255d3SCy Schubert }
162c1d255d3SCy Schubert 
163c1d255d3SCy Schubert 
16439beb93cSSam Leffler static int eap_tls_params_from_conf(struct eap_sm *sm,
16539beb93cSSam Leffler 				    struct eap_ssl_data *data,
16639beb93cSSam Leffler 				    struct tls_connection_params *params,
16739beb93cSSam Leffler 				    struct eap_peer_config *config, int phase2)
16839beb93cSSam Leffler {
16939beb93cSSam Leffler 	os_memset(params, 0, sizeof(*params));
170206b73d0SCy Schubert 	if (sm->workaround && data->eap_type != EAP_TYPE_FAST &&
171206b73d0SCy Schubert 	    data->eap_type != EAP_TYPE_TEAP) {
172f05cddf9SRui Paulo 		/*
173f05cddf9SRui Paulo 		 * Some deployed authentication servers seem to be unable to
174f05cddf9SRui Paulo 		 * handle the TLS Session Ticket extension (they are supposed
175f05cddf9SRui Paulo 		 * to ignore unrecognized TLS extensions, but end up rejecting
176f05cddf9SRui Paulo 		 * the ClientHello instead). As a workaround, disable use of
177f05cddf9SRui Paulo 		 * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and
178f05cddf9SRui Paulo 		 * EAP-TTLS (EAP-FAST uses session ticket, so any server that
179f05cddf9SRui Paulo 		 * supports EAP-FAST does not need this workaround).
180f05cddf9SRui Paulo 		 */
181f05cddf9SRui Paulo 		params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
182f05cddf9SRui Paulo 	}
183206b73d0SCy Schubert 	if (data->eap_type == EAP_TYPE_TEAP) {
184206b73d0SCy Schubert 		/* RFC 7170 requires TLS v1.2 or newer to be used with TEAP */
185206b73d0SCy Schubert 		params->flags |= TLS_CONN_DISABLE_TLSv1_0 |
186206b73d0SCy Schubert 			TLS_CONN_DISABLE_TLSv1_1;
187206b73d0SCy Schubert 		if (config->teap_anon_dh)
188206b73d0SCy Schubert 			params->flags |= TLS_CONN_TEAP_ANON_DH;
189206b73d0SCy Schubert 	}
19085732ac8SCy Schubert 	if (data->eap_type == EAP_TYPE_FAST ||
191206b73d0SCy Schubert 	    data->eap_type == EAP_TYPE_TEAP ||
19285732ac8SCy Schubert 	    data->eap_type == EAP_TYPE_TTLS ||
19385732ac8SCy Schubert 	    data->eap_type == EAP_TYPE_PEAP) {
19485732ac8SCy Schubert 		/* The current EAP peer implementation is not yet ready for the
19585732ac8SCy Schubert 		 * TLS v1.3 changes, so disable this by default for now. */
19685732ac8SCy Schubert 		params->flags |= TLS_CONN_DISABLE_TLSv1_3;
19785732ac8SCy Schubert 	}
198*a90b9d01SCy Schubert #ifndef EAP_TLSV1_3
1994bc52338SCy Schubert 	if (data->eap_type == EAP_TYPE_TLS ||
2004bc52338SCy Schubert 	    data->eap_type == EAP_UNAUTH_TLS_TYPE ||
2014bc52338SCy Schubert 	    data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) {
20285732ac8SCy Schubert 		/* While the current EAP-TLS implementation is more or less
203*a90b9d01SCy Schubert 		 * complete for TLS v1.3, there has been only minimal
204*a90b9d01SCy Schubert 		 * interoperability testing with other implementations, so
205*a90b9d01SCy Schubert 		 * disable it by default for now until there has been chance to
206*a90b9d01SCy Schubert 		 * confirm that no significant interoperability issues show up
207*a90b9d01SCy Schubert 		 * with TLS version update.
20885732ac8SCy Schubert 		 */
20985732ac8SCy Schubert 		params->flags |= TLS_CONN_DISABLE_TLSv1_3;
21085732ac8SCy Schubert 	}
211*a90b9d01SCy Schubert #endif /* EAP_TLSV1_3 */
212c1d255d3SCy Schubert 	if (phase2 && sm->use_machine_cred) {
213c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "TLS: using machine config options");
214c1d255d3SCy Schubert 		eap_tls_params_from_conf2m(params, config);
215c1d255d3SCy Schubert 	} else if (phase2) {
21639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
21739beb93cSSam Leffler 		eap_tls_params_from_conf2(params, config);
21839beb93cSSam Leffler 	} else {
21939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
22039beb93cSSam Leffler 		eap_tls_params_from_conf1(params, config);
2215b9c547cSRui Paulo 		if (data->eap_type == EAP_TYPE_FAST)
2225b9c547cSRui Paulo 			params->flags |= TLS_CONN_EAP_FAST;
22339beb93cSSam Leffler 	}
22439beb93cSSam Leffler 
22539beb93cSSam Leffler 	/*
22639beb93cSSam Leffler 	 * Use blob data, if available. Otherwise, leave reference to external
22739beb93cSSam Leffler 	 * file as-is.
22839beb93cSSam Leffler 	 */
22939beb93cSSam Leffler 	if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,
23039beb93cSSam Leffler 			       &params->ca_cert_blob_len) ||
23139beb93cSSam Leffler 	    eap_tls_check_blob(sm, &params->client_cert,
23239beb93cSSam Leffler 			       &params->client_cert_blob,
23339beb93cSSam Leffler 			       &params->client_cert_blob_len) ||
23439beb93cSSam Leffler 	    eap_tls_check_blob(sm, &params->private_key,
23539beb93cSSam Leffler 			       &params->private_key_blob,
236*a90b9d01SCy Schubert 			       &params->private_key_blob_len)) {
23739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
23839beb93cSSam Leffler 		return -1;
23939beb93cSSam Leffler 	}
24039beb93cSSam Leffler 
2415b9c547cSRui Paulo 	params->openssl_ciphers = config->openssl_ciphers;
2425b9c547cSRui Paulo 
243780fb4a2SCy Schubert 	sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
244780fb4a2SCy Schubert 
245*a90b9d01SCy Schubert 	if (!phase2)
246*a90b9d01SCy Schubert 		data->client_cert_conf = params->client_cert ||
247*a90b9d01SCy Schubert 			params->client_cert_blob ||
248*a90b9d01SCy Schubert 			params->private_key ||
249*a90b9d01SCy Schubert 			params->private_key_blob;
250*a90b9d01SCy Schubert 
25139beb93cSSam Leffler 	return 0;
25239beb93cSSam Leffler }
25339beb93cSSam Leffler 
25439beb93cSSam Leffler 
25539beb93cSSam Leffler static int eap_tls_init_connection(struct eap_sm *sm,
25639beb93cSSam Leffler 				   struct eap_ssl_data *data,
25739beb93cSSam Leffler 				   struct eap_peer_config *config,
25839beb93cSSam Leffler 				   struct tls_connection_params *params)
25939beb93cSSam Leffler {
26039beb93cSSam Leffler 	int res;
26139beb93cSSam Leffler 
262f05cddf9SRui Paulo 	data->conn = tls_connection_init(data->ssl_ctx);
26339beb93cSSam Leffler 	if (data->conn == NULL) {
26439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
26539beb93cSSam Leffler 			   "connection");
26639beb93cSSam Leffler 		return -1;
26739beb93cSSam Leffler 	}
26839beb93cSSam Leffler 
269f05cddf9SRui Paulo 	res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
270325151a3SRui Paulo 	if (res == TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN) {
27139beb93cSSam Leffler 		/*
272325151a3SRui Paulo 		 * At this point with the pkcs11 engine the PIN is wrong. We
273325151a3SRui Paulo 		 * reset the PIN in the configuration to be sure to not use it
274325151a3SRui Paulo 		 * again and the calling function must request a new one.
27539beb93cSSam Leffler 		 */
276325151a3SRui Paulo 		wpa_printf(MSG_INFO,
277325151a3SRui Paulo 			   "TLS: Bad PIN provided, requesting a new one");
278c1d255d3SCy Schubert 		os_free(config->cert.pin);
279c1d255d3SCy Schubert 		config->cert.pin = NULL;
28039beb93cSSam Leffler 		eap_sm_request_pin(sm);
281c1d255d3SCy Schubert 		sm->ignore = true;
282325151a3SRui Paulo 	} else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
283325151a3SRui Paulo 		wpa_printf(MSG_INFO, "TLS: Failed to initialize engine");
284325151a3SRui Paulo 	} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
285325151a3SRui Paulo 		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
286c1d255d3SCy Schubert 		sm->ignore = true;
287325151a3SRui Paulo 	}
288325151a3SRui Paulo 	if (res) {
28939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
29039beb93cSSam Leffler 			   "parameters");
291f05cddf9SRui Paulo 		tls_connection_deinit(data->ssl_ctx, data->conn);
292e28a4053SRui Paulo 		data->conn = NULL;
29339beb93cSSam Leffler 		return -1;
29439beb93cSSam Leffler 	}
29539beb93cSSam Leffler 
29639beb93cSSam Leffler 	return 0;
29739beb93cSSam Leffler }
29839beb93cSSam Leffler 
29939beb93cSSam Leffler 
30039beb93cSSam Leffler /**
30139beb93cSSam Leffler  * eap_peer_tls_ssl_init - Initialize shared TLS functionality
30239beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
30339beb93cSSam Leffler  * @data: Data for TLS processing
30439beb93cSSam Leffler  * @config: Pointer to the network configuration
305f05cddf9SRui Paulo  * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
30639beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
30739beb93cSSam Leffler  *
30839beb93cSSam Leffler  * This function is used to initialize shared TLS functionality for EAP-TLS,
30939beb93cSSam Leffler  * EAP-PEAP, EAP-TTLS, and EAP-FAST.
31039beb93cSSam Leffler  */
31139beb93cSSam Leffler int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
312f05cddf9SRui Paulo 			  struct eap_peer_config *config, u8 eap_type)
31339beb93cSSam Leffler {
31439beb93cSSam Leffler 	struct tls_connection_params params;
31539beb93cSSam Leffler 
31639beb93cSSam Leffler 	if (config == NULL)
31739beb93cSSam Leffler 		return -1;
31839beb93cSSam Leffler 
31939beb93cSSam Leffler 	data->eap = sm;
320f05cddf9SRui Paulo 	data->eap_type = eap_type;
32139beb93cSSam Leffler 	data->phase2 = sm->init_phase2;
322f05cddf9SRui Paulo 	data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
323f05cddf9SRui Paulo 		sm->ssl_ctx;
32439beb93cSSam Leffler 	if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
32539beb93cSSam Leffler 	    0)
32639beb93cSSam Leffler 		return -1;
32739beb93cSSam Leffler 
32839beb93cSSam Leffler 	if (eap_tls_init_connection(sm, data, config, &params) < 0)
32939beb93cSSam Leffler 		return -1;
33039beb93cSSam Leffler 
33139beb93cSSam Leffler 	data->tls_out_limit = config->fragment_size;
33239beb93cSSam Leffler 	if (data->phase2) {
33339beb93cSSam Leffler 		/* Limit the fragment size in the inner TLS authentication
33439beb93cSSam Leffler 		 * since the outer authentication with EAP-PEAP does not yet
33539beb93cSSam Leffler 		 * support fragmentation */
33639beb93cSSam Leffler 		if (data->tls_out_limit > 100)
33739beb93cSSam Leffler 			data->tls_out_limit -= 100;
33839beb93cSSam Leffler 	}
33939beb93cSSam Leffler 
34039beb93cSSam Leffler 	if (config->phase1 &&
34139beb93cSSam Leffler 	    os_strstr(config->phase1, "include_tls_length=1")) {
34239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
34339beb93cSSam Leffler 			   "unfragmented packets");
34439beb93cSSam Leffler 		data->include_tls_length = 1;
34539beb93cSSam Leffler 	}
34639beb93cSSam Leffler 
34739beb93cSSam Leffler 	return 0;
34839beb93cSSam Leffler }
34939beb93cSSam Leffler 
35039beb93cSSam Leffler 
35139beb93cSSam Leffler /**
35239beb93cSSam Leffler  * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality
35339beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
35439beb93cSSam Leffler  * @data: Data for TLS processing
35539beb93cSSam Leffler  *
35639beb93cSSam Leffler  * This function deinitializes shared TLS functionality that was initialized
35739beb93cSSam Leffler  * with eap_peer_tls_ssl_init().
35839beb93cSSam Leffler  */
35939beb93cSSam Leffler void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
36039beb93cSSam Leffler {
361f05cddf9SRui Paulo 	tls_connection_deinit(data->ssl_ctx, data->conn);
36239beb93cSSam Leffler 	eap_peer_tls_reset_input(data);
36339beb93cSSam Leffler 	eap_peer_tls_reset_output(data);
36439beb93cSSam Leffler }
36539beb93cSSam Leffler 
36639beb93cSSam Leffler 
36739beb93cSSam Leffler /**
36839beb93cSSam Leffler  * eap_peer_tls_derive_key - Derive a key based on TLS session data
36939beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
37039beb93cSSam Leffler  * @data: Data for TLS processing
37139beb93cSSam Leffler  * @label: Label string for deriving the keys, e.g., "client EAP encryption"
3724bc52338SCy Schubert  * @context: Optional extra upper-layer context (max len 2^16)
3734bc52338SCy Schubert  * @context_len: The length of the context value
37439beb93cSSam Leffler  * @len: Length of the key material to generate (usually 64 for MSK)
37539beb93cSSam Leffler  * Returns: Pointer to allocated key on success or %NULL on failure
37639beb93cSSam Leffler  *
37739beb93cSSam Leffler  * This function uses TLS-PRF to generate pseudo-random data based on the TLS
37839beb93cSSam Leffler  * session data (client/server random and master key). Each key type may use a
37939beb93cSSam Leffler  * different label to bind the key usage into the generated material.
38039beb93cSSam Leffler  *
38139beb93cSSam Leffler  * The caller is responsible for freeing the returned buffer.
3824bc52338SCy Schubert  *
3834bc52338SCy Schubert  * Note: To provide the RFC 5705 context, the context variable must be non-NULL.
38439beb93cSSam Leffler  */
38539beb93cSSam Leffler u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
3864bc52338SCy Schubert 			     const char *label, const u8 *context,
3874bc52338SCy Schubert 			     size_t context_len, size_t len)
38839beb93cSSam Leffler {
389325151a3SRui Paulo 	u8 *out;
39039beb93cSSam Leffler 
39139beb93cSSam Leffler 	out = os_malloc(len);
39239beb93cSSam Leffler 	if (out == NULL)
39339beb93cSSam Leffler 		return NULL;
39439beb93cSSam Leffler 
3954bc52338SCy Schubert 	if (tls_connection_export_key(data->ssl_ctx, data->conn, label,
3964bc52338SCy Schubert 				      context, context_len, out, len)) {
39739beb93cSSam Leffler 		os_free(out);
39839beb93cSSam Leffler 		return NULL;
39939beb93cSSam Leffler 	}
40039beb93cSSam Leffler 
401325151a3SRui Paulo 	return out;
402325151a3SRui Paulo }
403325151a3SRui Paulo 
40439beb93cSSam Leffler 
40539beb93cSSam Leffler /**
4065b9c547cSRui Paulo  * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
4075b9c547cSRui Paulo  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
4085b9c547cSRui Paulo  * @data: Data for TLS processing
4095b9c547cSRui Paulo  * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
4105b9c547cSRui Paulo  * @len: Pointer to length of the session ID generated
4115b9c547cSRui Paulo  * Returns: Pointer to allocated Session-Id on success or %NULL on failure
4125b9c547cSRui Paulo  *
4135b9c547cSRui Paulo  * This function derive the Session-Id based on the TLS session data
4145b9c547cSRui Paulo  * (client/server random and method type).
4155b9c547cSRui Paulo  *
4165b9c547cSRui Paulo  * The caller is responsible for freeing the returned buffer.
4175b9c547cSRui Paulo  */
4185b9c547cSRui Paulo u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
4195b9c547cSRui Paulo 				    struct eap_ssl_data *data, u8 eap_type,
4205b9c547cSRui Paulo 				    size_t *len)
4215b9c547cSRui Paulo {
422325151a3SRui Paulo 	struct tls_random keys;
4235b9c547cSRui Paulo 	u8 *out;
4245b9c547cSRui Paulo 
425c1d255d3SCy Schubert 	if (data->tls_v13) {
4264bc52338SCy Schubert 		u8 *id, *method_id;
427c1d255d3SCy Schubert 		const u8 context[] = { eap_type };
4284bc52338SCy Schubert 
4294bc52338SCy Schubert 		/* Session-Id = <EAP-Type> || Method-Id
4304bc52338SCy Schubert 		 * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
431206b73d0SCy Schubert 		 *                          Type-Code, 64)
4324bc52338SCy Schubert 		 */
4334bc52338SCy Schubert 		*len = 1 + 64;
4344bc52338SCy Schubert 		id = os_malloc(*len);
4354bc52338SCy Schubert 		if (!id)
4364bc52338SCy Schubert 			return NULL;
4374bc52338SCy Schubert 		method_id = eap_peer_tls_derive_key(
438206b73d0SCy Schubert 			sm, data, "EXPORTER_EAP_TLS_Method-Id", context, 1, 64);
4394bc52338SCy Schubert 		if (!method_id) {
4404bc52338SCy Schubert 			os_free(id);
4414bc52338SCy Schubert 			return NULL;
4424bc52338SCy Schubert 		}
4434bc52338SCy Schubert 		id[0] = eap_type;
4444bc52338SCy Schubert 		os_memcpy(id + 1, method_id, 64);
4454bc52338SCy Schubert 		os_free(method_id);
4464bc52338SCy Schubert 		return id;
44785732ac8SCy Schubert 	}
44885732ac8SCy Schubert 
449780fb4a2SCy Schubert 	if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) ||
450780fb4a2SCy Schubert 	    keys.client_random == NULL || keys.server_random == NULL)
4515b9c547cSRui Paulo 		return NULL;
4525b9c547cSRui Paulo 
4535b9c547cSRui Paulo 	*len = 1 + keys.client_random_len + keys.server_random_len;
4545b9c547cSRui Paulo 	out = os_malloc(*len);
4555b9c547cSRui Paulo 	if (out == NULL)
4565b9c547cSRui Paulo 		return NULL;
4575b9c547cSRui Paulo 
4585b9c547cSRui Paulo 	/* Session-Id = EAP type || client.random || server.random */
4595b9c547cSRui Paulo 	out[0] = eap_type;
4605b9c547cSRui Paulo 	os_memcpy(out + 1, keys.client_random, keys.client_random_len);
4615b9c547cSRui Paulo 	os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
4625b9c547cSRui Paulo 		  keys.server_random_len);
4635b9c547cSRui Paulo 
4645b9c547cSRui Paulo 	return out;
4655b9c547cSRui Paulo }
4665b9c547cSRui Paulo 
4675b9c547cSRui Paulo 
4685b9c547cSRui Paulo /**
46939beb93cSSam Leffler  * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
47039beb93cSSam Leffler  * @data: Data for TLS processing
47139beb93cSSam Leffler  * @in_data: Next incoming TLS segment
47239beb93cSSam Leffler  * Returns: 0 on success, 1 if more data is needed for the full message, or
47339beb93cSSam Leffler  * -1 on error
47439beb93cSSam Leffler  */
47539beb93cSSam Leffler static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,
476e28a4053SRui Paulo 					    const struct wpabuf *in_data)
47739beb93cSSam Leffler {
478e28a4053SRui Paulo 	size_t tls_in_len, in_len;
47939beb93cSSam Leffler 
480e28a4053SRui Paulo 	tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0;
481e28a4053SRui Paulo 	in_len = in_data ? wpabuf_len(in_data) : 0;
482e28a4053SRui Paulo 
483e28a4053SRui Paulo 	if (tls_in_len + in_len == 0) {
48439beb93cSSam Leffler 		/* No message data received?! */
48539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: "
48639beb93cSSam Leffler 			   "tls_in_left=%lu tls_in_len=%lu in_len=%lu",
48739beb93cSSam Leffler 			   (unsigned long) data->tls_in_left,
488e28a4053SRui Paulo 			   (unsigned long) tls_in_len,
48939beb93cSSam Leffler 			   (unsigned long) in_len);
49039beb93cSSam Leffler 		eap_peer_tls_reset_input(data);
49139beb93cSSam Leffler 		return -1;
49239beb93cSSam Leffler 	}
49339beb93cSSam Leffler 
494e28a4053SRui Paulo 	if (tls_in_len + in_len > 65536) {
49539beb93cSSam Leffler 		/*
49639beb93cSSam Leffler 		 * Limit length to avoid rogue servers from causing large
49739beb93cSSam Leffler 		 * memory allocations.
49839beb93cSSam Leffler 		 */
49939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over "
50039beb93cSSam Leffler 			   "64 kB)");
50139beb93cSSam Leffler 		eap_peer_tls_reset_input(data);
50239beb93cSSam Leffler 		return -1;
50339beb93cSSam Leffler 	}
50439beb93cSSam Leffler 
50539beb93cSSam Leffler 	if (in_len > data->tls_in_left) {
50639beb93cSSam Leffler 		/* Sender is doing something odd - reject message */
50739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: more data than TLS message length "
50839beb93cSSam Leffler 			   "indicated");
50939beb93cSSam Leffler 		eap_peer_tls_reset_input(data);
51039beb93cSSam Leffler 		return -1;
51139beb93cSSam Leffler 	}
51239beb93cSSam Leffler 
513e28a4053SRui Paulo 	if (wpabuf_resize(&data->tls_in, in_len) < 0) {
51439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS "
51539beb93cSSam Leffler 			   "data");
51639beb93cSSam Leffler 		eap_peer_tls_reset_input(data);
51739beb93cSSam Leffler 		return -1;
51839beb93cSSam Leffler 	}
519f05cddf9SRui Paulo 	if (in_data)
520e28a4053SRui Paulo 		wpabuf_put_buf(data->tls_in, in_data);
52139beb93cSSam Leffler 	data->tls_in_left -= in_len;
52239beb93cSSam Leffler 
52339beb93cSSam Leffler 	if (data->tls_in_left > 0) {
52439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
52539beb93cSSam Leffler 			   "data", (unsigned long) data->tls_in_left);
52639beb93cSSam Leffler 		return 1;
52739beb93cSSam Leffler 	}
52839beb93cSSam Leffler 
52939beb93cSSam Leffler 	return 0;
53039beb93cSSam Leffler }
53139beb93cSSam Leffler 
53239beb93cSSam Leffler 
53339beb93cSSam Leffler /**
53439beb93cSSam Leffler  * eap_peer_tls_data_reassemble - Reassemble TLS data
53539beb93cSSam Leffler  * @data: Data for TLS processing
53639beb93cSSam Leffler  * @in_data: Next incoming TLS segment
53739beb93cSSam Leffler  * @need_more_input: Variable for returning whether more input data is needed
53839beb93cSSam Leffler  * to reassemble this TLS packet
53939beb93cSSam Leffler  * Returns: Pointer to output data, %NULL on error or when more data is needed
54039beb93cSSam Leffler  * for the full message (in which case, *need_more_input is also set to 1).
54139beb93cSSam Leffler  *
54239beb93cSSam Leffler  * This function reassembles TLS fragments. Caller must not free the returned
54339beb93cSSam Leffler  * data buffer since an internal pointer to it is maintained.
54439beb93cSSam Leffler  */
545e28a4053SRui Paulo static const struct wpabuf * eap_peer_tls_data_reassemble(
546e28a4053SRui Paulo 	struct eap_ssl_data *data, const struct wpabuf *in_data,
547e28a4053SRui Paulo 	int *need_more_input)
54839beb93cSSam Leffler {
54939beb93cSSam Leffler 	*need_more_input = 0;
55039beb93cSSam Leffler 
551e28a4053SRui Paulo 	if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) {
55239beb93cSSam Leffler 		/* Message has fragments */
553e28a4053SRui Paulo 		int res = eap_peer_tls_reassemble_fragment(data, in_data);
55439beb93cSSam Leffler 		if (res) {
55539beb93cSSam Leffler 			if (res == 1)
55639beb93cSSam Leffler 				*need_more_input = 1;
55739beb93cSSam Leffler 			return NULL;
55839beb93cSSam Leffler 		}
55939beb93cSSam Leffler 
56039beb93cSSam Leffler 		/* Message is now fully reassembled. */
56139beb93cSSam Leffler 	} else {
56239beb93cSSam Leffler 		/* No fragments in this message, so just make a copy of it. */
56339beb93cSSam Leffler 		data->tls_in_left = 0;
564e28a4053SRui Paulo 		data->tls_in = wpabuf_dup(in_data);
56539beb93cSSam Leffler 		if (data->tls_in == NULL)
56639beb93cSSam Leffler 			return NULL;
56739beb93cSSam Leffler 	}
56839beb93cSSam Leffler 
56939beb93cSSam Leffler 	return data->tls_in;
57039beb93cSSam Leffler }
57139beb93cSSam Leffler 
57239beb93cSSam Leffler 
57339beb93cSSam Leffler /**
57439beb93cSSam Leffler  * eap_tls_process_input - Process incoming TLS message
57539beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
57639beb93cSSam Leffler  * @data: Data for TLS processing
57739beb93cSSam Leffler  * @in_data: Message received from the server
57839beb93cSSam Leffler  * @out_data: Buffer for returning a pointer to application data (if available)
57939beb93cSSam Leffler  * Returns: 0 on success, 1 if more input data is needed, 2 if application data
58039beb93cSSam Leffler  * is available, -1 on failure
58139beb93cSSam Leffler  */
58239beb93cSSam Leffler static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
583325151a3SRui Paulo 				 const struct wpabuf *in_data,
58439beb93cSSam Leffler 				 struct wpabuf **out_data)
58539beb93cSSam Leffler {
586e28a4053SRui Paulo 	const struct wpabuf *msg;
58739beb93cSSam Leffler 	int need_more_input;
588e28a4053SRui Paulo 	struct wpabuf *appl_data;
58939beb93cSSam Leffler 
590325151a3SRui Paulo 	msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
59139beb93cSSam Leffler 	if (msg == NULL)
59239beb93cSSam Leffler 		return need_more_input ? 1 : -1;
59339beb93cSSam Leffler 
59439beb93cSSam Leffler 	/* Full TLS message reassembled - continue handshake processing */
59539beb93cSSam Leffler 	if (data->tls_out) {
59639beb93cSSam Leffler 		/* This should not happen.. */
59739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending "
59839beb93cSSam Leffler 			   "tls_out data even though tls_out_len = 0");
599e28a4053SRui Paulo 		wpabuf_free(data->tls_out);
60039beb93cSSam Leffler 		WPA_ASSERT(data->tls_out == NULL);
60139beb93cSSam Leffler 	}
60239beb93cSSam Leffler 	appl_data = NULL;
603f05cddf9SRui Paulo 	data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
604e28a4053SRui Paulo 						 msg, &appl_data);
60539beb93cSSam Leffler 
60639beb93cSSam Leffler 	eap_peer_tls_reset_input(data);
60739beb93cSSam Leffler 
60839beb93cSSam Leffler 	if (appl_data &&
609f05cddf9SRui Paulo 	    tls_connection_established(data->ssl_ctx, data->conn) &&
610f05cddf9SRui Paulo 	    !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
611e28a4053SRui Paulo 		wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
612e28a4053SRui Paulo 				    appl_data);
613e28a4053SRui Paulo 		*out_data = appl_data;
61439beb93cSSam Leffler 		return 2;
61539beb93cSSam Leffler 	}
61639beb93cSSam Leffler 
617e28a4053SRui Paulo 	wpabuf_free(appl_data);
61839beb93cSSam Leffler 
61939beb93cSSam Leffler 	return 0;
62039beb93cSSam Leffler }
62139beb93cSSam Leffler 
62239beb93cSSam Leffler 
62339beb93cSSam Leffler /**
62439beb93cSSam Leffler  * eap_tls_process_output - Process outgoing TLS message
62539beb93cSSam Leffler  * @data: Data for TLS processing
62639beb93cSSam Leffler  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
62739beb93cSSam Leffler  * @peap_version: Version number for EAP-PEAP/TTLS
62839beb93cSSam Leffler  * @id: EAP identifier for the response
62939beb93cSSam Leffler  * @ret: Return value to use on success
63039beb93cSSam Leffler  * @out_data: Buffer for returning the allocated output buffer
63139beb93cSSam Leffler  * Returns: ret (0 or 1) on success, -1 on failure
63239beb93cSSam Leffler  */
633c1d255d3SCy Schubert static int eap_tls_process_output(struct eap_ssl_data *data,
634c1d255d3SCy Schubert 				  enum eap_type eap_type,
63539beb93cSSam Leffler 				  int peap_version, u8 id, int ret,
63639beb93cSSam Leffler 				  struct wpabuf **out_data)
63739beb93cSSam Leffler {
63839beb93cSSam Leffler 	size_t len;
63939beb93cSSam Leffler 	u8 *flags;
64039beb93cSSam Leffler 	int more_fragments, length_included;
64139beb93cSSam Leffler 
642e28a4053SRui Paulo 	if (data->tls_out == NULL)
643e28a4053SRui Paulo 		return -1;
644e28a4053SRui Paulo 	len = wpabuf_len(data->tls_out) - data->tls_out_pos;
64539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
64639beb93cSSam Leffler 		   "%lu bytes)",
647e28a4053SRui Paulo 		   (unsigned long) len,
648e28a4053SRui Paulo 		   (unsigned long) wpabuf_len(data->tls_out));
64939beb93cSSam Leffler 
65039beb93cSSam Leffler 	/*
65139beb93cSSam Leffler 	 * Limit outgoing message to the configured maximum size. Fragment
65239beb93cSSam Leffler 	 * message if needed.
65339beb93cSSam Leffler 	 */
65439beb93cSSam Leffler 	if (len > data->tls_out_limit) {
65539beb93cSSam Leffler 		more_fragments = 1;
65639beb93cSSam Leffler 		len = data->tls_out_limit;
65739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
65839beb93cSSam Leffler 			   "will follow", (unsigned long) len);
65939beb93cSSam Leffler 	} else
66039beb93cSSam Leffler 		more_fragments = 0;
66139beb93cSSam Leffler 
66239beb93cSSam Leffler 	length_included = data->tls_out_pos == 0 &&
663e28a4053SRui Paulo 		(wpabuf_len(data->tls_out) > data->tls_out_limit ||
66439beb93cSSam Leffler 		 data->include_tls_length);
66539beb93cSSam Leffler 	if (!length_included &&
66639beb93cSSam Leffler 	    eap_type == EAP_TYPE_PEAP && peap_version == 0 &&
66739beb93cSSam Leffler 	    !tls_connection_established(data->eap->ssl_ctx, data->conn)) {
66839beb93cSSam Leffler 		/*
66939beb93cSSam Leffler 		 * Windows Server 2008 NPS really wants to have the TLS Message
67039beb93cSSam Leffler 		 * length included in phase 0 even for unfragmented frames or
67139beb93cSSam Leffler 		 * it will get very confused with Compound MAC calculation and
67239beb93cSSam Leffler 		 * Outer TLVs.
67339beb93cSSam Leffler 		 */
67439beb93cSSam Leffler 		length_included = 1;
67539beb93cSSam Leffler 	}
67639beb93cSSam Leffler 
677f05cddf9SRui Paulo 	*out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
67839beb93cSSam Leffler 				      EAP_CODE_RESPONSE, id);
67939beb93cSSam Leffler 	if (*out_data == NULL)
68039beb93cSSam Leffler 		return -1;
68139beb93cSSam Leffler 
68239beb93cSSam Leffler 	flags = wpabuf_put(*out_data, 1);
68339beb93cSSam Leffler 	*flags = peap_version;
68439beb93cSSam Leffler 	if (more_fragments)
68539beb93cSSam Leffler 		*flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
68639beb93cSSam Leffler 	if (length_included) {
68739beb93cSSam Leffler 		*flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
688e28a4053SRui Paulo 		wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out));
68939beb93cSSam Leffler 	}
69039beb93cSSam Leffler 
691e28a4053SRui Paulo 	wpabuf_put_data(*out_data,
692e28a4053SRui Paulo 			wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
693e28a4053SRui Paulo 			len);
69439beb93cSSam Leffler 	data->tls_out_pos += len;
69539beb93cSSam Leffler 
69639beb93cSSam Leffler 	if (!more_fragments)
69739beb93cSSam Leffler 		eap_peer_tls_reset_output(data);
69839beb93cSSam Leffler 
69939beb93cSSam Leffler 	return ret;
70039beb93cSSam Leffler }
70139beb93cSSam Leffler 
70239beb93cSSam Leffler 
70339beb93cSSam Leffler /**
70439beb93cSSam Leffler  * eap_peer_tls_process_helper - Process TLS handshake message
70539beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
70639beb93cSSam Leffler  * @data: Data for TLS processing
70739beb93cSSam Leffler  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
70839beb93cSSam Leffler  * @peap_version: Version number for EAP-PEAP/TTLS
70939beb93cSSam Leffler  * @id: EAP identifier for the response
71039beb93cSSam Leffler  * @in_data: Message received from the server
71139beb93cSSam Leffler  * @out_data: Buffer for returning a pointer to the response message
71239beb93cSSam Leffler  * Returns: 0 on success, 1 if more input data is needed, 2 if application data
71339beb93cSSam Leffler  * is available, or -1 on failure
71439beb93cSSam Leffler  *
71539beb93cSSam Leffler  * This function can be used to process TLS handshake messages. It reassembles
71639beb93cSSam Leffler  * the received fragments and uses a TLS library to process the messages. The
71739beb93cSSam Leffler  * response data from the TLS library is fragmented to suitable output messages
71839beb93cSSam Leffler  * that the caller can send out.
71939beb93cSSam Leffler  *
72039beb93cSSam Leffler  * out_data is used to return the response message if the return value of this
72139beb93cSSam Leffler  * function is 0, 2, or -1. In case of failure, the message is likely a TLS
72239beb93cSSam Leffler  * alarm message. The caller is responsible for freeing the allocated buffer if
72339beb93cSSam Leffler  * *out_data is not %NULL.
72439beb93cSSam Leffler  *
72539beb93cSSam Leffler  * This function is called for each received TLS message during the TLS
72639beb93cSSam Leffler  * handshake after eap_peer_tls_process_init() call and possible processing of
72739beb93cSSam Leffler  * TLS Flags field. Once the handshake has been completed, i.e., when
72839beb93cSSam Leffler  * tls_connection_established() returns 1, EAP method specific decrypting of
72939beb93cSSam Leffler  * the tunneled data is used.
73039beb93cSSam Leffler  */
73139beb93cSSam Leffler int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
732c1d255d3SCy Schubert 				enum eap_type eap_type, int peap_version,
733325151a3SRui Paulo 				u8 id, const struct wpabuf *in_data,
73439beb93cSSam Leffler 				struct wpabuf **out_data)
73539beb93cSSam Leffler {
73639beb93cSSam Leffler 	int ret = 0;
73739beb93cSSam Leffler 
73839beb93cSSam Leffler 	*out_data = NULL;
73939beb93cSSam Leffler 
740325151a3SRui Paulo 	if (data->tls_out && wpabuf_len(data->tls_out) > 0 &&
741325151a3SRui Paulo 	    wpabuf_len(in_data) > 0) {
74239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output "
74339beb93cSSam Leffler 			   "fragments are waiting to be sent out");
74439beb93cSSam Leffler 		return -1;
74539beb93cSSam Leffler 	}
74639beb93cSSam Leffler 
747e28a4053SRui Paulo 	if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
74839beb93cSSam Leffler 		/*
74939beb93cSSam Leffler 		 * No more data to send out - expect to receive more data from
75039beb93cSSam Leffler 		 * the AS.
75139beb93cSSam Leffler 		 */
752325151a3SRui Paulo 		int res = eap_tls_process_input(sm, data, in_data, out_data);
75385732ac8SCy Schubert 		char buf[20];
75485732ac8SCy Schubert 
75539beb93cSSam Leffler 		if (res) {
75639beb93cSSam Leffler 			/*
75739beb93cSSam Leffler 			 * Input processing failed (res = -1) or more data is
75839beb93cSSam Leffler 			 * needed (res = 1).
75939beb93cSSam Leffler 			 */
76039beb93cSSam Leffler 			return res;
76139beb93cSSam Leffler 		}
76239beb93cSSam Leffler 
76339beb93cSSam Leffler 		/*
76439beb93cSSam Leffler 		 * The incoming message has been reassembled and processed. The
76539beb93cSSam Leffler 		 * response was allocated into data->tls_out buffer.
76639beb93cSSam Leffler 		 */
76785732ac8SCy Schubert 
76885732ac8SCy Schubert 		if (tls_get_version(data->ssl_ctx, data->conn,
76985732ac8SCy Schubert 				    buf, sizeof(buf)) == 0) {
77085732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
77185732ac8SCy Schubert 			data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
77285732ac8SCy Schubert 		}
77339beb93cSSam Leffler 	}
77439beb93cSSam Leffler 
77539beb93cSSam Leffler 	if (data->tls_out == NULL) {
77639beb93cSSam Leffler 		/*
77739beb93cSSam Leffler 		 * No outgoing fragments remaining from the previous message
77839beb93cSSam Leffler 		 * and no new message generated. This indicates an error in TLS
77939beb93cSSam Leffler 		 * processing.
78039beb93cSSam Leffler 		 */
78139beb93cSSam Leffler 		eap_peer_tls_reset_output(data);
78239beb93cSSam Leffler 		return -1;
78339beb93cSSam Leffler 	}
78439beb93cSSam Leffler 
785f05cddf9SRui Paulo 	if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
78639beb93cSSam Leffler 		/* TLS processing has failed - return error */
78739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
788325151a3SRui Paulo 			   "report error (len=%u)",
789325151a3SRui Paulo 			   (unsigned int) wpabuf_len(data->tls_out));
79039beb93cSSam Leffler 		ret = -1;
79139beb93cSSam Leffler 		/* TODO: clean pin if engine used? */
792325151a3SRui Paulo 		if (wpabuf_len(data->tls_out) == 0) {
793325151a3SRui Paulo 			wpabuf_free(data->tls_out);
794325151a3SRui Paulo 			data->tls_out = NULL;
795325151a3SRui Paulo 			return -1;
796325151a3SRui Paulo 		}
79739beb93cSSam Leffler 	}
79839beb93cSSam Leffler 
799325151a3SRui Paulo 	if (wpabuf_len(data->tls_out) == 0) {
80039beb93cSSam Leffler 		/*
80139beb93cSSam Leffler 		 * TLS negotiation should now be complete since all other cases
80239beb93cSSam Leffler 		 * needing more data should have been caught above based on
80339beb93cSSam Leffler 		 * the TLS Message Length field.
80439beb93cSSam Leffler 		 */
80539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
806e28a4053SRui Paulo 		wpabuf_free(data->tls_out);
80739beb93cSSam Leffler 		data->tls_out = NULL;
80839beb93cSSam Leffler 		return 1;
80939beb93cSSam Leffler 	}
81039beb93cSSam Leffler 
81139beb93cSSam Leffler 	/* Send the pending message (in fragments, if needed). */
81239beb93cSSam Leffler 	return eap_tls_process_output(data, eap_type, peap_version, id, ret,
81339beb93cSSam Leffler 				      out_data);
81439beb93cSSam Leffler }
81539beb93cSSam Leffler 
81639beb93cSSam Leffler 
81739beb93cSSam Leffler /**
81839beb93cSSam Leffler  * eap_peer_tls_build_ack - Build a TLS ACK frame
81939beb93cSSam Leffler  * @id: EAP identifier for the response
82039beb93cSSam Leffler  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
82139beb93cSSam Leffler  * @peap_version: Version number for EAP-PEAP/TTLS
82239beb93cSSam Leffler  * Returns: Pointer to the allocated ACK frame or %NULL on failure
82339beb93cSSam Leffler  */
824c1d255d3SCy Schubert struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
82539beb93cSSam Leffler 				       int peap_version)
82639beb93cSSam Leffler {
82739beb93cSSam Leffler 	struct wpabuf *resp;
82839beb93cSSam Leffler 
829f05cddf9SRui Paulo 	resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id);
83039beb93cSSam Leffler 	if (resp == NULL)
83139beb93cSSam Leffler 		return NULL;
83239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)",
83339beb93cSSam Leffler 		   (int) eap_type, id, peap_version);
83439beb93cSSam Leffler 	wpabuf_put_u8(resp, peap_version); /* Flags */
83539beb93cSSam Leffler 	return resp;
83639beb93cSSam Leffler }
83739beb93cSSam Leffler 
83839beb93cSSam Leffler 
83939beb93cSSam Leffler /**
84039beb93cSSam Leffler  * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption
84139beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
84239beb93cSSam Leffler  * @data: Data for TLS processing
84339beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
84439beb93cSSam Leffler  */
84539beb93cSSam Leffler int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
84639beb93cSSam Leffler {
84739beb93cSSam Leffler 	eap_peer_tls_reset_input(data);
84839beb93cSSam Leffler 	eap_peer_tls_reset_output(data);
849f05cddf9SRui Paulo 	return tls_connection_shutdown(data->ssl_ctx, data->conn);
85039beb93cSSam Leffler }
85139beb93cSSam Leffler 
85239beb93cSSam Leffler 
85339beb93cSSam Leffler /**
85439beb93cSSam Leffler  * eap_peer_tls_status - Get TLS status
85539beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
85639beb93cSSam Leffler  * @data: Data for TLS processing
85739beb93cSSam Leffler  * @buf: Buffer for status information
85839beb93cSSam Leffler  * @buflen: Maximum buffer length
85939beb93cSSam Leffler  * @verbose: Whether to include verbose status information
86039beb93cSSam Leffler  * Returns: Number of bytes written to buf.
86139beb93cSSam Leffler  */
86239beb93cSSam Leffler int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
86339beb93cSSam Leffler 			char *buf, size_t buflen, int verbose)
86439beb93cSSam Leffler {
865325151a3SRui Paulo 	char version[20], name[128];
86639beb93cSSam Leffler 	int len = 0, ret;
86739beb93cSSam Leffler 
868325151a3SRui Paulo 	if (tls_get_version(data->ssl_ctx, data->conn, version,
869325151a3SRui Paulo 			    sizeof(version)) < 0)
870325151a3SRui Paulo 		version[0] = '\0';
871325151a3SRui Paulo 	if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) < 0)
872325151a3SRui Paulo 		name[0] = '\0';
873325151a3SRui Paulo 
87439beb93cSSam Leffler 	ret = os_snprintf(buf + len, buflen - len,
875325151a3SRui Paulo 			  "eap_tls_version=%s\n"
8765b9c547cSRui Paulo 			  "EAP TLS cipher=%s\n"
8775b9c547cSRui Paulo 			  "tls_session_reused=%d\n",
878325151a3SRui Paulo 			  version, name,
879325151a3SRui Paulo 			  tls_connection_resumed(data->ssl_ctx, data->conn));
8805b9c547cSRui Paulo 	if (os_snprintf_error(buflen - len, ret))
88139beb93cSSam Leffler 		return len;
88239beb93cSSam Leffler 	len += ret;
88339beb93cSSam Leffler 
88439beb93cSSam Leffler 	return len;
88539beb93cSSam Leffler }
88639beb93cSSam Leffler 
88739beb93cSSam Leffler 
88839beb93cSSam Leffler /**
88939beb93cSSam Leffler  * eap_peer_tls_process_init - Initial validation/processing of EAP requests
89039beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
89139beb93cSSam Leffler  * @data: Data for TLS processing
89239beb93cSSam Leffler  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
89339beb93cSSam Leffler  * @ret: Return values from EAP request validation and processing
89439beb93cSSam Leffler  * @reqData: EAP request to be processed (eapReqData)
89539beb93cSSam Leffler  * @len: Buffer for returning length of the remaining payload
89639beb93cSSam Leffler  * @flags: Buffer for returning TLS flags
89739beb93cSSam Leffler  * Returns: Pointer to payload after TLS flags and length or %NULL on failure
89839beb93cSSam Leffler  *
89939beb93cSSam Leffler  * This function validates the EAP header and processes the optional TLS
90039beb93cSSam Leffler  * Message Length field. If this is the first fragment of a TLS message, the
90139beb93cSSam Leffler  * TLS reassembly code is initialized to receive the indicated number of bytes.
90239beb93cSSam Leffler  *
90339beb93cSSam Leffler  * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this
90439beb93cSSam Leffler  * function as the first step in processing received messages. They will need
90539beb93cSSam Leffler  * to process the flags (apart from Message Length Included) that are returned
90639beb93cSSam Leffler  * through the flags pointer and the message payload that will be returned (and
90739beb93cSSam Leffler  * the length is returned through the len pointer). Return values (ret) are set
90839beb93cSSam Leffler  * for continuation of EAP method processing. The caller is responsible for
90939beb93cSSam Leffler  * setting these to indicate completion (either success or failure) based on
91039beb93cSSam Leffler  * the authentication result.
91139beb93cSSam Leffler  */
91239beb93cSSam Leffler const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
91339beb93cSSam Leffler 				     struct eap_ssl_data *data,
914c1d255d3SCy Schubert 				     enum eap_type eap_type,
91539beb93cSSam Leffler 				     struct eap_method_ret *ret,
91639beb93cSSam Leffler 				     const struct wpabuf *reqData,
91739beb93cSSam Leffler 				     size_t *len, u8 *flags)
91839beb93cSSam Leffler {
91939beb93cSSam Leffler 	const u8 *pos;
92039beb93cSSam Leffler 	size_t left;
92139beb93cSSam Leffler 	unsigned int tls_msg_len;
92239beb93cSSam Leffler 
923f05cddf9SRui Paulo 	if (tls_get_errors(data->ssl_ctx)) {
92439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: TLS errors detected");
925c1d255d3SCy Schubert 		ret->ignore = true;
92639beb93cSSam Leffler 		return NULL;
92739beb93cSSam Leffler 	}
92839beb93cSSam Leffler 
929f05cddf9SRui Paulo 	if (eap_type == EAP_UNAUTH_TLS_TYPE)
930f05cddf9SRui Paulo 		pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
931f05cddf9SRui Paulo 				       EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
932f05cddf9SRui Paulo 				       &left);
9335b9c547cSRui Paulo 	else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
9345b9c547cSRui Paulo 		pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
9355b9c547cSRui Paulo 				       EAP_VENDOR_WFA_UNAUTH_TLS, reqData,
9365b9c547cSRui Paulo 				       &left);
937f05cddf9SRui Paulo 	else
938f05cddf9SRui Paulo 		pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
939f05cddf9SRui Paulo 				       &left);
94039beb93cSSam Leffler 	if (pos == NULL) {
941c1d255d3SCy Schubert 		ret->ignore = true;
94239beb93cSSam Leffler 		return NULL;
94339beb93cSSam Leffler 	}
94439beb93cSSam Leffler 	if (left == 0) {
94539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
94639beb93cSSam Leffler 			   "octet included");
94739beb93cSSam Leffler 		if (!sm->workaround) {
948c1d255d3SCy Schubert 			ret->ignore = true;
94939beb93cSSam Leffler 			return NULL;
95039beb93cSSam Leffler 		}
95139beb93cSSam Leffler 
95239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags "
95339beb93cSSam Leffler 			   "indicates ACK frame");
95439beb93cSSam Leffler 		*flags = 0;
95539beb93cSSam Leffler 	} else {
95639beb93cSSam Leffler 		*flags = *pos++;
95739beb93cSSam Leffler 		left--;
95839beb93cSSam Leffler 	}
95939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
96039beb93cSSam Leffler 		   "Flags 0x%02x", (unsigned long) wpabuf_len(reqData),
96139beb93cSSam Leffler 		   *flags);
96239beb93cSSam Leffler 	if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
96339beb93cSSam Leffler 		if (left < 4) {
96439beb93cSSam Leffler 			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
96539beb93cSSam Leffler 				   "length");
966c1d255d3SCy Schubert 			ret->ignore = true;
96739beb93cSSam Leffler 			return NULL;
96839beb93cSSam Leffler 		}
96939beb93cSSam Leffler 		tls_msg_len = WPA_GET_BE32(pos);
97039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
97139beb93cSSam Leffler 			   tls_msg_len);
97239beb93cSSam Leffler 		if (data->tls_in_left == 0) {
97339beb93cSSam Leffler 			data->tls_in_total = tls_msg_len;
97439beb93cSSam Leffler 			data->tls_in_left = tls_msg_len;
975e28a4053SRui Paulo 			wpabuf_free(data->tls_in);
97639beb93cSSam Leffler 			data->tls_in = NULL;
97739beb93cSSam Leffler 		}
97839beb93cSSam Leffler 		pos += 4;
97939beb93cSSam Leffler 		left -= 4;
980f05cddf9SRui Paulo 
981f05cddf9SRui Paulo 		if (left > tls_msg_len) {
982f05cddf9SRui Paulo 			wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
983f05cddf9SRui Paulo 				   "bytes) smaller than this fragment (%d "
984f05cddf9SRui Paulo 				   "bytes)", (int) tls_msg_len, (int) left);
985c1d255d3SCy Schubert 			ret->ignore = true;
986f05cddf9SRui Paulo 			return NULL;
987f05cddf9SRui Paulo 		}
98839beb93cSSam Leffler 	}
98939beb93cSSam Leffler 
990c1d255d3SCy Schubert 	ret->ignore = false;
99139beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
99239beb93cSSam Leffler 	ret->decision = DECISION_FAIL;
993c1d255d3SCy Schubert 	ret->allowNotifications = true;
99439beb93cSSam Leffler 
99539beb93cSSam Leffler 	*len = left;
99639beb93cSSam Leffler 	return pos;
99739beb93cSSam Leffler }
99839beb93cSSam Leffler 
99939beb93cSSam Leffler 
100039beb93cSSam Leffler /**
100139beb93cSSam Leffler  * eap_peer_tls_reset_input - Reset input buffers
100239beb93cSSam Leffler  * @data: Data for TLS processing
100339beb93cSSam Leffler  *
100439beb93cSSam Leffler  * This function frees any allocated memory for input buffers and resets input
100539beb93cSSam Leffler  * state.
100639beb93cSSam Leffler  */
100739beb93cSSam Leffler void eap_peer_tls_reset_input(struct eap_ssl_data *data)
100839beb93cSSam Leffler {
1009e28a4053SRui Paulo 	data->tls_in_left = data->tls_in_total = 0;
1010e28a4053SRui Paulo 	wpabuf_free(data->tls_in);
101139beb93cSSam Leffler 	data->tls_in = NULL;
101239beb93cSSam Leffler }
101339beb93cSSam Leffler 
101439beb93cSSam Leffler 
101539beb93cSSam Leffler /**
101639beb93cSSam Leffler  * eap_peer_tls_reset_output - Reset output buffers
101739beb93cSSam Leffler  * @data: Data for TLS processing
101839beb93cSSam Leffler  *
101939beb93cSSam Leffler  * This function frees any allocated memory for output buffers and resets
102039beb93cSSam Leffler  * output state.
102139beb93cSSam Leffler  */
102239beb93cSSam Leffler void eap_peer_tls_reset_output(struct eap_ssl_data *data)
102339beb93cSSam Leffler {
102439beb93cSSam Leffler 	data->tls_out_pos = 0;
1025e28a4053SRui Paulo 	wpabuf_free(data->tls_out);
102639beb93cSSam Leffler 	data->tls_out = NULL;
102739beb93cSSam Leffler }
102839beb93cSSam Leffler 
102939beb93cSSam Leffler 
103039beb93cSSam Leffler /**
103139beb93cSSam Leffler  * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message
103239beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
103339beb93cSSam Leffler  * @data: Data for TLS processing
103439beb93cSSam Leffler  * @in_data: Message received from the server
103539beb93cSSam Leffler  * @in_decrypted: Buffer for returning a pointer to the decrypted message
103639beb93cSSam Leffler  * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
103739beb93cSSam Leffler  */
103839beb93cSSam Leffler int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
103939beb93cSSam Leffler 			 const struct wpabuf *in_data,
104039beb93cSSam Leffler 			 struct wpabuf **in_decrypted)
104139beb93cSSam Leffler {
1042e28a4053SRui Paulo 	const struct wpabuf *msg;
104339beb93cSSam Leffler 	int need_more_input;
104439beb93cSSam Leffler 
1045e28a4053SRui Paulo 	msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
104639beb93cSSam Leffler 	if (msg == NULL)
104739beb93cSSam Leffler 		return need_more_input ? 1 : -1;
104839beb93cSSam Leffler 
1049f05cddf9SRui Paulo 	*in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
1050e28a4053SRui Paulo 	eap_peer_tls_reset_input(data);
105139beb93cSSam Leffler 	if (*in_decrypted == NULL) {
105239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
105339beb93cSSam Leffler 		return -1;
105439beb93cSSam Leffler 	}
105539beb93cSSam Leffler 	return 0;
105639beb93cSSam Leffler }
105739beb93cSSam Leffler 
105839beb93cSSam Leffler 
105939beb93cSSam Leffler /**
106039beb93cSSam Leffler  * eap_peer_tls_encrypt - Encrypt phase 2 TLS message
106139beb93cSSam Leffler  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
106239beb93cSSam Leffler  * @data: Data for TLS processing
106339beb93cSSam Leffler  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
106439beb93cSSam Leffler  * @peap_version: Version number for EAP-PEAP/TTLS
106539beb93cSSam Leffler  * @id: EAP identifier for the response
106639beb93cSSam Leffler  * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments
106739beb93cSSam Leffler  * @out_data: Buffer for returning a pointer to the encrypted response message
106839beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
106939beb93cSSam Leffler  */
107039beb93cSSam Leffler int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
1071c1d255d3SCy Schubert 			 enum eap_type eap_type, int peap_version, u8 id,
107239beb93cSSam Leffler 			 const struct wpabuf *in_data,
107339beb93cSSam Leffler 			 struct wpabuf **out_data)
107439beb93cSSam Leffler {
107539beb93cSSam Leffler 	if (in_data) {
107639beb93cSSam Leffler 		eap_peer_tls_reset_output(data);
1077f05cddf9SRui Paulo 		data->tls_out = tls_connection_encrypt(data->ssl_ctx,
1078f05cddf9SRui Paulo 						       data->conn, in_data);
1079e28a4053SRui Paulo 		if (data->tls_out == NULL) {
108039beb93cSSam Leffler 			wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
108139beb93cSSam Leffler 				   "data (in_len=%lu)",
108239beb93cSSam Leffler 				   (unsigned long) wpabuf_len(in_data));
108339beb93cSSam Leffler 			eap_peer_tls_reset_output(data);
108439beb93cSSam Leffler 			return -1;
108539beb93cSSam Leffler 		}
108639beb93cSSam Leffler 	}
108739beb93cSSam Leffler 
108839beb93cSSam Leffler 	return eap_tls_process_output(data, eap_type, peap_version, id, 0,
108939beb93cSSam Leffler 				      out_data);
109039beb93cSSam Leffler }
109139beb93cSSam Leffler 
109239beb93cSSam Leffler 
109339beb93cSSam Leffler /**
109439beb93cSSam Leffler  * eap_peer_select_phase2_methods - Select phase 2 EAP method
109539beb93cSSam Leffler  * @config: Pointer to the network configuration
109639beb93cSSam Leffler  * @prefix: 'phase2' configuration prefix, e.g., "auth="
109739beb93cSSam Leffler  * @types: Buffer for returning allocated list of allowed EAP methods
109839beb93cSSam Leffler  * @num_types: Buffer for returning number of allocated EAP methods
109939beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
110039beb93cSSam Leffler  *
110139beb93cSSam Leffler  * This function is used to parse EAP method list and select allowed methods
110239beb93cSSam Leffler  * for Phase2 authentication.
110339beb93cSSam Leffler  */
110439beb93cSSam Leffler int eap_peer_select_phase2_methods(struct eap_peer_config *config,
110539beb93cSSam Leffler 				   const char *prefix,
110639beb93cSSam Leffler 				   struct eap_method_type **types,
1107c1d255d3SCy Schubert 				   size_t *num_types, int use_machine_cred)
110839beb93cSSam Leffler {
110939beb93cSSam Leffler 	char *start, *pos, *buf;
111039beb93cSSam Leffler 	struct eap_method_type *methods = NULL, *_methods;
1111325151a3SRui Paulo 	u32 method;
111239beb93cSSam Leffler 	size_t num_methods = 0, prefix_len;
1113c1d255d3SCy Schubert 	const char *phase2;
111439beb93cSSam Leffler 
1115c1d255d3SCy Schubert 	if (!config)
1116c1d255d3SCy Schubert 		goto get_defaults;
1117c1d255d3SCy Schubert 	phase2 = use_machine_cred ? config->machine_phase2 : config->phase2;
1118c1d255d3SCy Schubert 	if (!phase2)
111939beb93cSSam Leffler 		goto get_defaults;
112039beb93cSSam Leffler 
1121c1d255d3SCy Schubert 	start = buf = os_strdup(phase2);
112239beb93cSSam Leffler 	if (buf == NULL)
112339beb93cSSam Leffler 		return -1;
112439beb93cSSam Leffler 
112539beb93cSSam Leffler 	prefix_len = os_strlen(prefix);
112639beb93cSSam Leffler 
112739beb93cSSam Leffler 	while (start && *start != '\0') {
112839beb93cSSam Leffler 		int vendor;
112939beb93cSSam Leffler 		pos = os_strstr(start, prefix);
113039beb93cSSam Leffler 		if (pos == NULL)
113139beb93cSSam Leffler 			break;
113239beb93cSSam Leffler 		if (start != pos && *(pos - 1) != ' ') {
113339beb93cSSam Leffler 			start = pos + prefix_len;
113439beb93cSSam Leffler 			continue;
113539beb93cSSam Leffler 		}
113639beb93cSSam Leffler 
113739beb93cSSam Leffler 		start = pos + prefix_len;
113839beb93cSSam Leffler 		pos = os_strchr(start, ' ');
113939beb93cSSam Leffler 		if (pos)
114039beb93cSSam Leffler 			*pos++ = '\0';
114139beb93cSSam Leffler 		method = eap_get_phase2_type(start, &vendor);
114239beb93cSSam Leffler 		if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) {
114339beb93cSSam Leffler 			wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP "
114439beb93cSSam Leffler 				   "method '%s'", start);
1145780fb4a2SCy Schubert 			os_free(methods);
1146780fb4a2SCy Schubert 			os_free(buf);
1147780fb4a2SCy Schubert 			return -1;
114839beb93cSSam Leffler 		} else {
114939beb93cSSam Leffler 			num_methods++;
1150f05cddf9SRui Paulo 			_methods = os_realloc_array(methods, num_methods,
1151f05cddf9SRui Paulo 						    sizeof(*methods));
115239beb93cSSam Leffler 			if (_methods == NULL) {
115339beb93cSSam Leffler 				os_free(methods);
115439beb93cSSam Leffler 				os_free(buf);
115539beb93cSSam Leffler 				return -1;
115639beb93cSSam Leffler 			}
115739beb93cSSam Leffler 			methods = _methods;
115839beb93cSSam Leffler 			methods[num_methods - 1].vendor = vendor;
115939beb93cSSam Leffler 			methods[num_methods - 1].method = method;
116039beb93cSSam Leffler 		}
116139beb93cSSam Leffler 
116239beb93cSSam Leffler 		start = pos;
116339beb93cSSam Leffler 	}
116439beb93cSSam Leffler 
116539beb93cSSam Leffler 	os_free(buf);
116639beb93cSSam Leffler 
116739beb93cSSam Leffler get_defaults:
116839beb93cSSam Leffler 	if (methods == NULL)
116939beb93cSSam Leffler 		methods = eap_get_phase2_types(config, &num_methods);
117039beb93cSSam Leffler 
117139beb93cSSam Leffler 	if (methods == NULL) {
117239beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available");
117339beb93cSSam Leffler 		return -1;
117439beb93cSSam Leffler 	}
117539beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types",
117639beb93cSSam Leffler 		    (u8 *) methods,
117739beb93cSSam Leffler 		    num_methods * sizeof(struct eap_method_type));
117839beb93cSSam Leffler 
117939beb93cSSam Leffler 	*types = methods;
118039beb93cSSam Leffler 	*num_types = num_methods;
118139beb93cSSam Leffler 
118239beb93cSSam Leffler 	return 0;
118339beb93cSSam Leffler }
118439beb93cSSam Leffler 
118539beb93cSSam Leffler 
118639beb93cSSam Leffler /**
118739beb93cSSam Leffler  * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2
118839beb93cSSam Leffler  * @types: Buffer for returning allocated list of allowed EAP methods
118939beb93cSSam Leffler  * @num_types: Buffer for returning number of allocated EAP methods
119039beb93cSSam Leffler  * @hdr: EAP-Request header (and the following EAP type octet)
119139beb93cSSam Leffler  * @resp: Buffer for returning the EAP-Nak message
119239beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
119339beb93cSSam Leffler  */
119439beb93cSSam Leffler int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
119539beb93cSSam Leffler 			    struct eap_hdr *hdr, struct wpabuf **resp)
119639beb93cSSam Leffler {
119739beb93cSSam Leffler 	u8 *pos = (u8 *) (hdr + 1);
119839beb93cSSam Leffler 	size_t i;
119939beb93cSSam Leffler 
120039beb93cSSam Leffler 	/* TODO: add support for expanded Nak */
120139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos);
120239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types",
120339beb93cSSam Leffler 		    (u8 *) types, num_types * sizeof(struct eap_method_type));
120439beb93cSSam Leffler 	*resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types,
120539beb93cSSam Leffler 			      EAP_CODE_RESPONSE, hdr->identifier);
120639beb93cSSam Leffler 	if (*resp == NULL)
120739beb93cSSam Leffler 		return -1;
120839beb93cSSam Leffler 
120939beb93cSSam Leffler 	for (i = 0; i < num_types; i++) {
121039beb93cSSam Leffler 		if (types[i].vendor == EAP_VENDOR_IETF &&
121139beb93cSSam Leffler 		    types[i].method < 256)
121239beb93cSSam Leffler 			wpabuf_put_u8(*resp, types[i].method);
121339beb93cSSam Leffler 	}
121439beb93cSSam Leffler 
121539beb93cSSam Leffler 	eap_update_len(*resp);
121639beb93cSSam Leffler 
121739beb93cSSam Leffler 	return 0;
121839beb93cSSam Leffler }
1219