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
eap_tls_msg_alloc(enum eap_type type,size_t payload_len,u8 code,u8 identifier)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
eap_tls_check_blob(struct eap_sm * sm,const char ** name,const u8 ** data,size_t * data_len)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
eap_tls_params_flags(struct tls_connection_params * params,const char * txt)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
eap_tls_cert_params_from_conf(struct tls_connection_params * params,struct eap_peer_cert_config * config)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
eap_tls_params_from_conf1(struct tls_connection_params * params,struct eap_peer_config * config)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
eap_tls_params_from_conf2(struct tls_connection_params * params,struct eap_peer_config * config)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
eap_tls_params_from_conf2m(struct tls_connection_params * params,struct eap_peer_config * config)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
eap_tls_params_from_conf(struct eap_sm * sm,struct eap_ssl_data * data,struct tls_connection_params * params,struct eap_peer_config * config,int phase2)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, ¶ms->ca_cert, ¶ms->ca_cert_blob,
23039beb93cSSam Leffler ¶ms->ca_cert_blob_len) ||
23139beb93cSSam Leffler eap_tls_check_blob(sm, ¶ms->client_cert,
23239beb93cSSam Leffler ¶ms->client_cert_blob,
23339beb93cSSam Leffler ¶ms->client_cert_blob_len) ||
23439beb93cSSam Leffler eap_tls_check_blob(sm, ¶ms->private_key,
23539beb93cSSam Leffler ¶ms->private_key_blob,
236*a90b9d01SCy Schubert ¶ms->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
eap_tls_init_connection(struct eap_sm * sm,struct eap_ssl_data * data,struct eap_peer_config * config,struct tls_connection_params * params)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 */
eap_peer_tls_ssl_init(struct eap_sm * sm,struct eap_ssl_data * data,struct eap_peer_config * config,u8 eap_type)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, ¶ms, config, data->phase2) <
32539beb93cSSam Leffler 0)
32639beb93cSSam Leffler return -1;
32739beb93cSSam Leffler
32839beb93cSSam Leffler if (eap_tls_init_connection(sm, data, config, ¶ms) < 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 */
eap_peer_tls_ssl_deinit(struct eap_sm * sm,struct eap_ssl_data * data)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 */
eap_peer_tls_derive_key(struct eap_sm * sm,struct eap_ssl_data * data,const char * label,const u8 * context,size_t context_len,size_t len)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 */
eap_peer_tls_derive_session_id(struct eap_sm * sm,struct eap_ssl_data * data,u8 eap_type,size_t * len)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 */
eap_peer_tls_reassemble_fragment(struct eap_ssl_data * data,const struct wpabuf * in_data)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 */
eap_peer_tls_data_reassemble(struct eap_ssl_data * data,const struct wpabuf * in_data,int * need_more_input)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 */
eap_tls_process_input(struct eap_sm * sm,struct eap_ssl_data * data,const struct wpabuf * in_data,struct wpabuf ** out_data)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 */
eap_tls_process_output(struct eap_ssl_data * data,enum eap_type eap_type,int peap_version,u8 id,int ret,struct wpabuf ** out_data)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 */
eap_peer_tls_process_helper(struct eap_sm * sm,struct eap_ssl_data * data,enum eap_type eap_type,int peap_version,u8 id,const struct wpabuf * in_data,struct wpabuf ** out_data)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 */
eap_peer_tls_build_ack(u8 id,enum eap_type eap_type,int peap_version)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 */
eap_peer_tls_reauth_init(struct eap_sm * sm,struct eap_ssl_data * data)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 */
eap_peer_tls_status(struct eap_sm * sm,struct eap_ssl_data * data,char * buf,size_t buflen,int verbose)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 */
eap_peer_tls_process_init(struct eap_sm * sm,struct eap_ssl_data * data,enum eap_type eap_type,struct eap_method_ret * ret,const struct wpabuf * reqData,size_t * len,u8 * flags)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 */
eap_peer_tls_reset_input(struct eap_ssl_data * data)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 */
eap_peer_tls_reset_output(struct eap_ssl_data * data)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 */
eap_peer_tls_decrypt(struct eap_sm * sm,struct eap_ssl_data * data,const struct wpabuf * in_data,struct wpabuf ** in_decrypted)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 */
eap_peer_tls_encrypt(struct eap_sm * sm,struct eap_ssl_data * data,enum eap_type eap_type,int peap_version,u8 id,const struct wpabuf * in_data,struct wpabuf ** out_data)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 */
eap_peer_select_phase2_methods(struct eap_peer_config * config,const char * prefix,struct eap_method_type ** types,size_t * num_types,int use_machine_cred)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 */
eap_peer_tls_phase2_nak(struct eap_method_type * types,size_t num_types,struct eap_hdr * hdr,struct wpabuf ** resp)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