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, ¶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 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, ¶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 */ 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