139beb93cSSam Leffler /* 239beb93cSSam Leffler * EAP peer method: EAP-TTLS (RFC 5281) 3780fb4a2SCy Schubert * Copyright (c) 2004-2015, 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/ms_funcs.h" 13e28a4053SRui Paulo #include "crypto/sha1.h" 14e28a4053SRui Paulo #include "crypto/tls.h" 1539beb93cSSam Leffler #include "eap_common/chap.h" 1639beb93cSSam Leffler #include "eap_common/eap_ttls.h" 17e28a4053SRui Paulo #include "mschapv2.h" 18e28a4053SRui Paulo #include "eap_i.h" 19e28a4053SRui Paulo #include "eap_tls_common.h" 20e28a4053SRui Paulo #include "eap_config.h" 2139beb93cSSam Leffler 2239beb93cSSam Leffler 23f05cddf9SRui Paulo #define EAP_TTLS_VERSION 0 2439beb93cSSam Leffler 2539beb93cSSam Leffler 2639beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv); 2739beb93cSSam Leffler 2839beb93cSSam Leffler 2939beb93cSSam Leffler struct eap_ttls_data { 3039beb93cSSam Leffler struct eap_ssl_data ssl; 3139beb93cSSam Leffler 32f05cddf9SRui Paulo int ttls_version; 3339beb93cSSam Leffler 3439beb93cSSam Leffler const struct eap_method *phase2_method; 3539beb93cSSam Leffler void *phase2_priv; 3639beb93cSSam Leffler int phase2_success; 3739beb93cSSam Leffler int phase2_start; 38780fb4a2SCy Schubert EapDecision decision_succ; 3939beb93cSSam Leffler 4039beb93cSSam Leffler enum phase2_types { 4139beb93cSSam Leffler EAP_TTLS_PHASE2_EAP, 4239beb93cSSam Leffler EAP_TTLS_PHASE2_MSCHAPV2, 4339beb93cSSam Leffler EAP_TTLS_PHASE2_MSCHAP, 4439beb93cSSam Leffler EAP_TTLS_PHASE2_PAP, 4539beb93cSSam Leffler EAP_TTLS_PHASE2_CHAP 4639beb93cSSam Leffler } phase2_type; 4739beb93cSSam Leffler struct eap_method_type phase2_eap_type; 4839beb93cSSam Leffler struct eap_method_type *phase2_eap_types; 4939beb93cSSam Leffler size_t num_phase2_eap_types; 5039beb93cSSam Leffler 5139beb93cSSam Leffler u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; 5239beb93cSSam Leffler int auth_response_valid; 5339beb93cSSam Leffler u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ 5439beb93cSSam Leffler u8 ident; 5539beb93cSSam Leffler int resuming; /* starting a resumed session */ 5639beb93cSSam Leffler int reauth; /* reauthentication */ 5739beb93cSSam Leffler u8 *key_data; 585b9c547cSRui Paulo u8 *session_id; 595b9c547cSRui Paulo size_t id_len; 6039beb93cSSam Leffler 6139beb93cSSam Leffler struct wpabuf *pending_phase2_req; 62780fb4a2SCy Schubert struct wpabuf *pending_resp; 6339beb93cSSam Leffler 6439beb93cSSam Leffler #ifdef EAP_TNC 6539beb93cSSam Leffler int ready_for_tnc; 6639beb93cSSam Leffler int tnc_started; 6739beb93cSSam Leffler #endif /* EAP_TNC */ 68*a90b9d01SCy Schubert 69*a90b9d01SCy Schubert enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth; 7039beb93cSSam Leffler }; 7139beb93cSSam Leffler 7239beb93cSSam Leffler 73*a90b9d01SCy Schubert static void eap_ttls_parse_phase1(struct eap_ttls_data *data, 74*a90b9d01SCy Schubert const char *phase1) 75*a90b9d01SCy Schubert { 76*a90b9d01SCy Schubert if (os_strstr(phase1, "phase2_auth=0")) { 77*a90b9d01SCy Schubert data->phase2_auth = NO_AUTH; 78*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 79*a90b9d01SCy Schubert "EAP-TTLS: Do not require Phase 2 authentication"); 80*a90b9d01SCy Schubert } else if (os_strstr(phase1, "phase2_auth=1")) { 81*a90b9d01SCy Schubert data->phase2_auth = FOR_INITIAL; 82*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 83*a90b9d01SCy Schubert "EAP-TTLS: Require Phase 2 authentication for initial connection"); 84*a90b9d01SCy Schubert } else if (os_strstr(phase1, "phase2_auth=2")) { 85*a90b9d01SCy Schubert data->phase2_auth = ALWAYS; 86*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 87*a90b9d01SCy Schubert "EAP-TTLS: Require Phase 2 authentication for all cases"); 88*a90b9d01SCy Schubert } 89*a90b9d01SCy Schubert } 90*a90b9d01SCy Schubert 91*a90b9d01SCy Schubert 9239beb93cSSam Leffler static void * eap_ttls_init(struct eap_sm *sm) 9339beb93cSSam Leffler { 9439beb93cSSam Leffler struct eap_ttls_data *data; 9539beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 96780fb4a2SCy Schubert int selected_non_eap; 9739beb93cSSam Leffler char *selected; 9839beb93cSSam Leffler 9939beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 10039beb93cSSam Leffler if (data == NULL) 10139beb93cSSam Leffler return NULL; 10239beb93cSSam Leffler data->ttls_version = EAP_TTLS_VERSION; 10339beb93cSSam Leffler selected = "EAP"; 104780fb4a2SCy Schubert selected_non_eap = 0; 10539beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_EAP; 106*a90b9d01SCy Schubert data->phase2_auth = FOR_INITIAL; 107*a90b9d01SCy Schubert 108*a90b9d01SCy Schubert if (config && config->phase1) 109*a90b9d01SCy Schubert eap_ttls_parse_phase1(data, config->phase1); 11039beb93cSSam Leffler 111780fb4a2SCy Schubert /* 112780fb4a2SCy Schubert * Either one auth= type or one or more autheap= methods can be 113780fb4a2SCy Schubert * specified. 114780fb4a2SCy Schubert */ 11539beb93cSSam Leffler if (config && config->phase2) { 116780fb4a2SCy Schubert const char *token, *last = NULL; 117780fb4a2SCy Schubert 118780fb4a2SCy Schubert while ((token = cstr_token(config->phase2, " \t", &last))) { 119780fb4a2SCy Schubert if (os_strncmp(token, "auth=", 5) != 0) 120780fb4a2SCy Schubert continue; 121780fb4a2SCy Schubert token += 5; 122780fb4a2SCy Schubert 123780fb4a2SCy Schubert if (last - token == 8 && 124780fb4a2SCy Schubert os_strncmp(token, "MSCHAPV2", 8) == 0) { 12539beb93cSSam Leffler selected = "MSCHAPV2"; 12639beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; 127780fb4a2SCy Schubert } else if (last - token == 6 && 128780fb4a2SCy Schubert os_strncmp(token, "MSCHAP", 6) == 0) { 12939beb93cSSam Leffler selected = "MSCHAP"; 13039beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; 131780fb4a2SCy Schubert } else if (last - token == 3 && 132780fb4a2SCy Schubert os_strncmp(token, "PAP", 3) == 0) { 13339beb93cSSam Leffler selected = "PAP"; 13439beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_PAP; 135780fb4a2SCy Schubert } else if (last - token == 4 && 136780fb4a2SCy Schubert os_strncmp(token, "CHAP", 4) == 0) { 13739beb93cSSam Leffler selected = "CHAP"; 13839beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_CHAP; 139780fb4a2SCy Schubert } else { 140780fb4a2SCy Schubert wpa_printf(MSG_ERROR, 141780fb4a2SCy Schubert "EAP-TTLS: Unsupported Phase2 type '%s'", 142780fb4a2SCy Schubert token); 143780fb4a2SCy Schubert eap_ttls_deinit(sm, data); 144780fb4a2SCy Schubert return NULL; 145780fb4a2SCy Schubert } 146780fb4a2SCy Schubert 147780fb4a2SCy Schubert if (selected_non_eap) { 148780fb4a2SCy Schubert wpa_printf(MSG_ERROR, 149780fb4a2SCy Schubert "EAP-TTLS: Only one Phase2 type can be specified"); 150780fb4a2SCy Schubert eap_ttls_deinit(sm, data); 151780fb4a2SCy Schubert return NULL; 152780fb4a2SCy Schubert } 153780fb4a2SCy Schubert 154780fb4a2SCy Schubert selected_non_eap = 1; 155780fb4a2SCy Schubert } 156780fb4a2SCy Schubert 157780fb4a2SCy Schubert if (os_strstr(config->phase2, "autheap=")) { 158780fb4a2SCy Schubert if (selected_non_eap) { 159780fb4a2SCy Schubert wpa_printf(MSG_ERROR, 160780fb4a2SCy Schubert "EAP-TTLS: Both auth= and autheap= params cannot be specified"); 161780fb4a2SCy Schubert eap_ttls_deinit(sm, data); 162780fb4a2SCy Schubert return NULL; 163780fb4a2SCy Schubert } 164780fb4a2SCy Schubert selected = "EAP"; 165780fb4a2SCy Schubert data->phase2_type = EAP_TTLS_PHASE2_EAP; 16639beb93cSSam Leffler } 16739beb93cSSam Leffler } 168780fb4a2SCy Schubert 16939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); 17039beb93cSSam Leffler 17139beb93cSSam Leffler if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { 17239beb93cSSam Leffler if (eap_peer_select_phase2_methods(config, "autheap=", 17339beb93cSSam Leffler &data->phase2_eap_types, 174c1d255d3SCy Schubert &data->num_phase2_eap_types, 175c1d255d3SCy Schubert 0) < 0) { 17639beb93cSSam Leffler eap_ttls_deinit(sm, data); 17739beb93cSSam Leffler return NULL; 17839beb93cSSam Leffler } 17939beb93cSSam Leffler 18039beb93cSSam Leffler data->phase2_eap_type.vendor = EAP_VENDOR_IETF; 18139beb93cSSam Leffler data->phase2_eap_type.method = EAP_TYPE_NONE; 18239beb93cSSam Leffler } 18339beb93cSSam Leffler 184f05cddf9SRui Paulo if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) { 185f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); 18639beb93cSSam Leffler eap_ttls_deinit(sm, data); 18739beb93cSSam Leffler return NULL; 18839beb93cSSam Leffler } 18939beb93cSSam Leffler 19039beb93cSSam Leffler return data; 19139beb93cSSam Leffler } 19239beb93cSSam Leffler 19339beb93cSSam Leffler 19439beb93cSSam Leffler static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, 19539beb93cSSam Leffler struct eap_ttls_data *data) 19639beb93cSSam Leffler { 19739beb93cSSam Leffler if (data->phase2_priv && data->phase2_method) { 19839beb93cSSam Leffler data->phase2_method->deinit(sm, data->phase2_priv); 19939beb93cSSam Leffler data->phase2_method = NULL; 20039beb93cSSam Leffler data->phase2_priv = NULL; 20139beb93cSSam Leffler } 20239beb93cSSam Leffler } 20339beb93cSSam Leffler 20439beb93cSSam Leffler 2055b9c547cSRui Paulo static void eap_ttls_free_key(struct eap_ttls_data *data) 2065b9c547cSRui Paulo { 2075b9c547cSRui Paulo if (data->key_data) { 2085b9c547cSRui Paulo bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 2095b9c547cSRui Paulo data->key_data = NULL; 2105b9c547cSRui Paulo } 2115b9c547cSRui Paulo } 2125b9c547cSRui Paulo 2135b9c547cSRui Paulo 21439beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv) 21539beb93cSSam Leffler { 21639beb93cSSam Leffler struct eap_ttls_data *data = priv; 21739beb93cSSam Leffler if (data == NULL) 21839beb93cSSam Leffler return; 21939beb93cSSam Leffler eap_ttls_phase2_eap_deinit(sm, data); 22039beb93cSSam Leffler os_free(data->phase2_eap_types); 22139beb93cSSam Leffler eap_peer_tls_ssl_deinit(sm, &data->ssl); 2225b9c547cSRui Paulo eap_ttls_free_key(data); 2235b9c547cSRui Paulo os_free(data->session_id); 2244bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 2254bc52338SCy Schubert wpabuf_clear_free(data->pending_resp); 22639beb93cSSam Leffler os_free(data); 22739beb93cSSam Leffler } 22839beb93cSSam Leffler 22939beb93cSSam Leffler 23039beb93cSSam Leffler static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, 23139beb93cSSam Leffler int mandatory, size_t len) 23239beb93cSSam Leffler { 23339beb93cSSam Leffler struct ttls_avp_vendor *avp; 23439beb93cSSam Leffler u8 flags; 23539beb93cSSam Leffler size_t hdrlen; 23639beb93cSSam Leffler 23739beb93cSSam Leffler avp = (struct ttls_avp_vendor *) avphdr; 23839beb93cSSam Leffler flags = mandatory ? AVP_FLAGS_MANDATORY : 0; 23939beb93cSSam Leffler if (vendor_id) { 24039beb93cSSam Leffler flags |= AVP_FLAGS_VENDOR; 24139beb93cSSam Leffler hdrlen = sizeof(*avp); 24239beb93cSSam Leffler avp->vendor_id = host_to_be32(vendor_id); 24339beb93cSSam Leffler } else { 24439beb93cSSam Leffler hdrlen = sizeof(struct ttls_avp); 24539beb93cSSam Leffler } 24639beb93cSSam Leffler 24739beb93cSSam Leffler avp->avp_code = host_to_be32(avp_code); 248325151a3SRui Paulo avp->avp_length = host_to_be32(((u32) flags << 24) | 249325151a3SRui Paulo (u32) (hdrlen + len)); 25039beb93cSSam Leffler 25139beb93cSSam Leffler return avphdr + hdrlen; 25239beb93cSSam Leffler } 25339beb93cSSam Leffler 25439beb93cSSam Leffler 25539beb93cSSam Leffler static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, 25639beb93cSSam Leffler u32 vendor_id, int mandatory, 25739beb93cSSam Leffler const u8 *data, size_t len) 25839beb93cSSam Leffler { 25939beb93cSSam Leffler u8 *pos; 26039beb93cSSam Leffler pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); 26139beb93cSSam Leffler os_memcpy(pos, data, len); 26239beb93cSSam Leffler pos += len; 26339beb93cSSam Leffler AVP_PAD(start, pos); 26439beb93cSSam Leffler return pos; 26539beb93cSSam Leffler } 26639beb93cSSam Leffler 26739beb93cSSam Leffler 26839beb93cSSam Leffler static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, 26939beb93cSSam Leffler int mandatory) 27039beb93cSSam Leffler { 27139beb93cSSam Leffler struct wpabuf *msg; 27239beb93cSSam Leffler u8 *avp, *pos; 27339beb93cSSam Leffler 27439beb93cSSam Leffler msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); 27539beb93cSSam Leffler if (msg == NULL) { 2764bc52338SCy Schubert wpabuf_clear_free(*resp); 27739beb93cSSam Leffler *resp = NULL; 27839beb93cSSam Leffler return -1; 27939beb93cSSam Leffler } 28039beb93cSSam Leffler 28139beb93cSSam Leffler avp = wpabuf_mhead(msg); 28239beb93cSSam Leffler pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); 28339beb93cSSam Leffler os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); 28439beb93cSSam Leffler pos += wpabuf_len(*resp); 28539beb93cSSam Leffler AVP_PAD(avp, pos); 2864bc52338SCy Schubert wpabuf_clear_free(*resp); 28739beb93cSSam Leffler wpabuf_put(msg, pos - avp); 28839beb93cSSam Leffler *resp = msg; 28939beb93cSSam Leffler return 0; 29039beb93cSSam Leffler } 29139beb93cSSam Leffler 29239beb93cSSam Leffler 29339beb93cSSam Leffler static int eap_ttls_v0_derive_key(struct eap_sm *sm, 29439beb93cSSam Leffler struct eap_ttls_data *data) 29539beb93cSSam Leffler { 296c1d255d3SCy Schubert const char *label; 297c1d255d3SCy Schubert const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS }; 298c1d255d3SCy Schubert const u8 *context = NULL; 299c1d255d3SCy Schubert size_t context_len = 0; 300c1d255d3SCy Schubert 301c1d255d3SCy Schubert if (data->ssl.tls_v13) { 302c1d255d3SCy Schubert label = "EXPORTER_EAP_TLS_Key_Material"; 303c1d255d3SCy Schubert context = eap_tls13_context; 304c1d255d3SCy Schubert context_len = sizeof(eap_tls13_context); 305c1d255d3SCy Schubert } else { 306c1d255d3SCy Schubert label = "ttls keying material"; 307c1d255d3SCy Schubert } 308c1d255d3SCy Schubert 3095b9c547cSRui Paulo eap_ttls_free_key(data); 310c1d255d3SCy Schubert data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label, 311c1d255d3SCy Schubert context, context_len, 3125b9c547cSRui Paulo EAP_TLS_KEY_LEN + 3135b9c547cSRui Paulo EAP_EMSK_LEN); 31439beb93cSSam Leffler if (!data->key_data) { 31539beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); 31639beb93cSSam Leffler return -1; 31739beb93cSSam Leffler } 31839beb93cSSam Leffler 31939beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", 32039beb93cSSam Leffler data->key_data, EAP_TLS_KEY_LEN); 3215b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK", 3225b9c547cSRui Paulo data->key_data + EAP_TLS_KEY_LEN, 3235b9c547cSRui Paulo EAP_EMSK_LEN); 3245b9c547cSRui Paulo 3255b9c547cSRui Paulo os_free(data->session_id); 3265b9c547cSRui Paulo data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, 3275b9c547cSRui Paulo EAP_TYPE_TTLS, 3285b9c547cSRui Paulo &data->id_len); 3295b9c547cSRui Paulo if (data->session_id) { 3305b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id", 3315b9c547cSRui Paulo data->session_id, data->id_len); 3325b9c547cSRui Paulo } else { 3335b9c547cSRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id"); 3345b9c547cSRui Paulo } 33539beb93cSSam Leffler 33639beb93cSSam Leffler return 0; 33739beb93cSSam Leffler } 33839beb93cSSam Leffler 33939beb93cSSam Leffler 340325151a3SRui Paulo #ifndef CONFIG_FIPS 34139beb93cSSam Leffler static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, 34239beb93cSSam Leffler struct eap_ttls_data *data, size_t len) 34339beb93cSSam Leffler { 3444bc52338SCy Schubert return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", 3454bc52338SCy Schubert NULL, 0, len); 34639beb93cSSam Leffler } 347325151a3SRui Paulo #endif /* CONFIG_FIPS */ 34839beb93cSSam Leffler 34939beb93cSSam Leffler 35039beb93cSSam Leffler static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, 351c1d255d3SCy Schubert int vendor, enum eap_type method) 35239beb93cSSam Leffler { 35339beb93cSSam Leffler size_t i; 35439beb93cSSam Leffler for (i = 0; i < data->num_phase2_eap_types; i++) { 355c1d255d3SCy Schubert if (data->phase2_eap_types[i].vendor != vendor || 35639beb93cSSam Leffler data->phase2_eap_types[i].method != method) 35739beb93cSSam Leffler continue; 35839beb93cSSam Leffler 35939beb93cSSam Leffler data->phase2_eap_type.vendor = 36039beb93cSSam Leffler data->phase2_eap_types[i].vendor; 36139beb93cSSam Leffler data->phase2_eap_type.method = 36239beb93cSSam Leffler data->phase2_eap_types[i].method; 36339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " 36439beb93cSSam Leffler "Phase 2 EAP vendor %d method %d", 36539beb93cSSam Leffler data->phase2_eap_type.vendor, 36639beb93cSSam Leffler data->phase2_eap_type.method); 36739beb93cSSam Leffler break; 36839beb93cSSam Leffler } 36939beb93cSSam Leffler } 37039beb93cSSam Leffler 37139beb93cSSam Leffler 37239beb93cSSam Leffler static int eap_ttls_phase2_eap_process(struct eap_sm *sm, 37339beb93cSSam Leffler struct eap_ttls_data *data, 37439beb93cSSam Leffler struct eap_method_ret *ret, 37539beb93cSSam Leffler struct eap_hdr *hdr, size_t len, 37639beb93cSSam Leffler struct wpabuf **resp) 37739beb93cSSam Leffler { 37839beb93cSSam Leffler struct wpabuf msg; 37939beb93cSSam Leffler struct eap_method_ret iret; 38039beb93cSSam Leffler 38139beb93cSSam Leffler os_memset(&iret, 0, sizeof(iret)); 38239beb93cSSam Leffler wpabuf_set(&msg, hdr, len); 38339beb93cSSam Leffler *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, 38439beb93cSSam Leffler &msg); 38539beb93cSSam Leffler if ((iret.methodState == METHOD_DONE || 38639beb93cSSam Leffler iret.methodState == METHOD_MAY_CONT) && 38739beb93cSSam Leffler (iret.decision == DECISION_UNCOND_SUCC || 38839beb93cSSam Leffler iret.decision == DECISION_COND_SUCC || 38939beb93cSSam Leffler iret.decision == DECISION_FAIL)) { 39039beb93cSSam Leffler ret->methodState = iret.methodState; 39139beb93cSSam Leffler ret->decision = iret.decision; 39239beb93cSSam Leffler } 39339beb93cSSam Leffler 39439beb93cSSam Leffler return 0; 39539beb93cSSam Leffler } 39639beb93cSSam Leffler 39739beb93cSSam Leffler 39839beb93cSSam Leffler static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, 39939beb93cSSam Leffler struct eap_ttls_data *data, 40039beb93cSSam Leffler struct eap_method_ret *ret, 40139beb93cSSam Leffler struct eap_hdr *hdr, size_t len, 402c1d255d3SCy Schubert int vendor, enum eap_type method, 403c1d255d3SCy Schubert struct wpabuf **resp) 40439beb93cSSam Leffler { 40539beb93cSSam Leffler #ifdef EAP_TNC 40639beb93cSSam Leffler if (data->tnc_started && data->phase2_method && 407c1d255d3SCy Schubert data->phase2_priv && 408c1d255d3SCy Schubert vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC && 40939beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_TNC) 41039beb93cSSam Leffler return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, 41139beb93cSSam Leffler resp); 41239beb93cSSam Leffler 41339beb93cSSam Leffler if (data->ready_for_tnc && !data->tnc_started && 414c1d255d3SCy Schubert vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC) { 41539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " 41639beb93cSSam Leffler "EAP method"); 41739beb93cSSam Leffler data->tnc_started = 1; 41839beb93cSSam Leffler } 41939beb93cSSam Leffler 42039beb93cSSam Leffler if (data->tnc_started) { 42139beb93cSSam Leffler if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || 42239beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_TNC) { 42339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP " 42439beb93cSSam Leffler "type %d for TNC", method); 42539beb93cSSam Leffler return -1; 42639beb93cSSam Leffler } 42739beb93cSSam Leffler 428c1d255d3SCy Schubert data->phase2_eap_type.vendor = vendor; 42939beb93cSSam Leffler data->phase2_eap_type.method = method; 43039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " 43139beb93cSSam Leffler "Phase 2 EAP vendor %d method %d (TNC)", 43239beb93cSSam Leffler data->phase2_eap_type.vendor, 43339beb93cSSam Leffler data->phase2_eap_type.method); 43439beb93cSSam Leffler 43539beb93cSSam Leffler if (data->phase2_type == EAP_TTLS_PHASE2_EAP) 43639beb93cSSam Leffler eap_ttls_phase2_eap_deinit(sm, data); 43739beb93cSSam Leffler } 43839beb93cSSam Leffler #endif /* EAP_TNC */ 43939beb93cSSam Leffler 44039beb93cSSam Leffler if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && 44139beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_NONE) 442c1d255d3SCy Schubert eap_ttls_phase2_select_eap_method(data, vendor, method); 44339beb93cSSam Leffler 444c1d255d3SCy Schubert if (vendor != data->phase2_eap_type.vendor || 445c1d255d3SCy Schubert method != data->phase2_eap_type.method || 446c1d255d3SCy Schubert (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) { 44739beb93cSSam Leffler if (eap_peer_tls_phase2_nak(data->phase2_eap_types, 44839beb93cSSam Leffler data->num_phase2_eap_types, 44939beb93cSSam Leffler hdr, resp)) 45039beb93cSSam Leffler return -1; 45139beb93cSSam Leffler return 0; 45239beb93cSSam Leffler } 45339beb93cSSam Leffler 45439beb93cSSam Leffler if (data->phase2_priv == NULL) { 455c1d255d3SCy Schubert data->phase2_method = eap_peer_get_eap_method(vendor, method); 45639beb93cSSam Leffler if (data->phase2_method) { 45739beb93cSSam Leffler sm->init_phase2 = 1; 45839beb93cSSam Leffler data->phase2_priv = data->phase2_method->init(sm); 45939beb93cSSam Leffler sm->init_phase2 = 0; 46039beb93cSSam Leffler } 46139beb93cSSam Leffler } 46239beb93cSSam Leffler if (data->phase2_priv == NULL || data->phase2_method == NULL) { 463c1d255d3SCy Schubert wpa_printf(MSG_INFO, 464c1d255d3SCy Schubert "EAP-TTLS: failed to initialize Phase 2 EAP method %u:%u", 465c1d255d3SCy Schubert vendor, method); 46639beb93cSSam Leffler return -1; 46739beb93cSSam Leffler } 46839beb93cSSam Leffler 46939beb93cSSam Leffler return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); 47039beb93cSSam Leffler } 47139beb93cSSam Leffler 47239beb93cSSam Leffler 47339beb93cSSam Leffler static int eap_ttls_phase2_request_eap(struct eap_sm *sm, 47439beb93cSSam Leffler struct eap_ttls_data *data, 47539beb93cSSam Leffler struct eap_method_ret *ret, 47639beb93cSSam Leffler struct eap_hdr *hdr, 47739beb93cSSam Leffler struct wpabuf **resp) 47839beb93cSSam Leffler { 47939beb93cSSam Leffler size_t len = be_to_host16(hdr->length); 48039beb93cSSam Leffler u8 *pos; 48139beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 48239beb93cSSam Leffler 48339beb93cSSam Leffler if (len <= sizeof(struct eap_hdr)) { 48439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: too short " 48539beb93cSSam Leffler "Phase 2 request (len=%lu)", (unsigned long) len); 48639beb93cSSam Leffler return -1; 48739beb93cSSam Leffler } 48839beb93cSSam Leffler pos = (u8 *) (hdr + 1); 48939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); 49039beb93cSSam Leffler switch (*pos) { 49139beb93cSSam Leffler case EAP_TYPE_IDENTITY: 49239beb93cSSam Leffler *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); 49339beb93cSSam Leffler break; 494c1d255d3SCy Schubert case EAP_TYPE_EXPANDED: 495c1d255d3SCy Schubert if (len < sizeof(struct eap_hdr) + 8) { 496c1d255d3SCy Schubert wpa_printf(MSG_INFO, 497c1d255d3SCy Schubert "EAP-TTLS: Too short Phase 2 request (expanded header) (len=%lu)", 498c1d255d3SCy Schubert (unsigned long) len); 499c1d255d3SCy Schubert return -1; 500c1d255d3SCy Schubert } 501c1d255d3SCy Schubert if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, 502c1d255d3SCy Schubert WPA_GET_BE24(pos + 1), 503c1d255d3SCy Schubert WPA_GET_BE32(pos + 4), 504c1d255d3SCy Schubert resp) < 0) 505c1d255d3SCy Schubert return -1; 506c1d255d3SCy Schubert break; 50739beb93cSSam Leffler default: 50839beb93cSSam Leffler if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, 509c1d255d3SCy Schubert EAP_VENDOR_IETF, *pos, 510c1d255d3SCy Schubert resp) < 0) 51139beb93cSSam Leffler return -1; 51239beb93cSSam Leffler break; 51339beb93cSSam Leffler } 51439beb93cSSam Leffler 51539beb93cSSam Leffler if (*resp == NULL && 51639beb93cSSam Leffler (config->pending_req_identity || config->pending_req_password || 51785732ac8SCy Schubert config->pending_req_otp || config->pending_req_sim)) { 51839beb93cSSam Leffler return 0; 51939beb93cSSam Leffler } 52039beb93cSSam Leffler 52139beb93cSSam Leffler if (*resp == NULL) 52239beb93cSSam Leffler return -1; 52339beb93cSSam Leffler 52439beb93cSSam Leffler wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", 52539beb93cSSam Leffler *resp); 52639beb93cSSam Leffler return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); 52739beb93cSSam Leffler } 52839beb93cSSam Leffler 52939beb93cSSam Leffler 53039beb93cSSam Leffler static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, 53139beb93cSSam Leffler struct eap_ttls_data *data, 53239beb93cSSam Leffler struct eap_method_ret *ret, 53339beb93cSSam Leffler struct wpabuf **resp) 53439beb93cSSam Leffler { 535325151a3SRui Paulo #ifdef CONFIG_FIPS 536325151a3SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build"); 537325151a3SRui Paulo return -1; 538325151a3SRui Paulo #else /* CONFIG_FIPS */ 539f05cddf9SRui Paulo #ifdef EAP_MSCHAPv2 54039beb93cSSam Leffler struct wpabuf *msg; 54139beb93cSSam Leffler u8 *buf, *pos, *challenge, *peer_challenge; 54239beb93cSSam Leffler const u8 *identity, *password; 54339beb93cSSam Leffler size_t identity_len, password_len; 54439beb93cSSam Leffler int pwhash; 54539beb93cSSam Leffler 54639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); 54739beb93cSSam Leffler 54839beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 54939beb93cSSam Leffler password = eap_get_config_password2(sm, &password_len, &pwhash); 55039beb93cSSam Leffler if (identity == NULL || password == NULL) 55139beb93cSSam Leffler return -1; 55239beb93cSSam Leffler 55339beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 55439beb93cSSam Leffler if (msg == NULL) { 55539beb93cSSam Leffler wpa_printf(MSG_ERROR, 55639beb93cSSam Leffler "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); 55739beb93cSSam Leffler return -1; 55839beb93cSSam Leffler } 55939beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 56039beb93cSSam Leffler 56139beb93cSSam Leffler /* User-Name */ 56239beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 56339beb93cSSam Leffler identity, identity_len); 56439beb93cSSam Leffler 56539beb93cSSam Leffler /* MS-CHAP-Challenge */ 56639beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 56739beb93cSSam Leffler sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); 56839beb93cSSam Leffler if (challenge == NULL) { 5694bc52338SCy Schubert wpabuf_clear_free(msg); 57039beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " 57139beb93cSSam Leffler "implicit challenge"); 57239beb93cSSam Leffler return -1; 57339beb93cSSam Leffler } 57439beb93cSSam Leffler 57539beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, 57639beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 57739beb93cSSam Leffler challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); 57839beb93cSSam Leffler 57939beb93cSSam Leffler /* MS-CHAP2-Response */ 58039beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, 58139beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 58239beb93cSSam Leffler EAP_TTLS_MSCHAPV2_RESPONSE_LEN); 58339beb93cSSam Leffler data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; 58439beb93cSSam Leffler *pos++ = data->ident; 58539beb93cSSam Leffler *pos++ = 0; /* Flags */ 586f05cddf9SRui Paulo if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) { 587f05cddf9SRui Paulo os_free(challenge); 5884bc52338SCy Schubert wpabuf_clear_free(msg); 589f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get " 590f05cddf9SRui Paulo "random data for peer challenge"); 591f05cddf9SRui Paulo return -1; 592f05cddf9SRui Paulo } 593f05cddf9SRui Paulo peer_challenge = pos; 59439beb93cSSam Leffler pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; 59539beb93cSSam Leffler os_memset(pos, 0, 8); /* Reserved, must be zero */ 59639beb93cSSam Leffler pos += 8; 597e28a4053SRui Paulo if (mschapv2_derive_response(identity, identity_len, password, 59839beb93cSSam Leffler password_len, pwhash, challenge, 59939beb93cSSam Leffler peer_challenge, pos, data->auth_response, 600e28a4053SRui Paulo data->master_key)) { 601f05cddf9SRui Paulo os_free(challenge); 6024bc52338SCy Schubert wpabuf_clear_free(msg); 603e28a4053SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " 604e28a4053SRui Paulo "response"); 605e28a4053SRui Paulo return -1; 606e28a4053SRui Paulo } 60739beb93cSSam Leffler data->auth_response_valid = 1; 60839beb93cSSam Leffler 60939beb93cSSam Leffler pos += 24; 61039beb93cSSam Leffler os_free(challenge); 61139beb93cSSam Leffler AVP_PAD(buf, pos); 61239beb93cSSam Leffler 61339beb93cSSam Leffler wpabuf_put(msg, pos - buf); 61439beb93cSSam Leffler *resp = msg; 61539beb93cSSam Leffler 61639beb93cSSam Leffler return 0; 617f05cddf9SRui Paulo #else /* EAP_MSCHAPv2 */ 618f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); 619f05cddf9SRui Paulo return -1; 620f05cddf9SRui Paulo #endif /* EAP_MSCHAPv2 */ 621325151a3SRui Paulo #endif /* CONFIG_FIPS */ 62239beb93cSSam Leffler } 62339beb93cSSam Leffler 62439beb93cSSam Leffler 62539beb93cSSam Leffler static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, 62639beb93cSSam Leffler struct eap_ttls_data *data, 62739beb93cSSam Leffler struct eap_method_ret *ret, 62839beb93cSSam Leffler struct wpabuf **resp) 62939beb93cSSam Leffler { 630325151a3SRui Paulo #ifdef CONFIG_FIPS 631325151a3SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build"); 632325151a3SRui Paulo return -1; 633325151a3SRui Paulo #else /* CONFIG_FIPS */ 63439beb93cSSam Leffler struct wpabuf *msg; 63539beb93cSSam Leffler u8 *buf, *pos, *challenge; 63639beb93cSSam Leffler const u8 *identity, *password; 63739beb93cSSam Leffler size_t identity_len, password_len; 63839beb93cSSam Leffler int pwhash; 63939beb93cSSam Leffler 64039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); 64139beb93cSSam Leffler 64239beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 64339beb93cSSam Leffler password = eap_get_config_password2(sm, &password_len, &pwhash); 64439beb93cSSam Leffler if (identity == NULL || password == NULL) 64539beb93cSSam Leffler return -1; 64639beb93cSSam Leffler 64739beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 64839beb93cSSam Leffler if (msg == NULL) { 64939beb93cSSam Leffler wpa_printf(MSG_ERROR, 65039beb93cSSam Leffler "EAP-TTLS/MSCHAP: Failed to allocate memory"); 65139beb93cSSam Leffler return -1; 65239beb93cSSam Leffler } 65339beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 65439beb93cSSam Leffler 65539beb93cSSam Leffler /* User-Name */ 65639beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 65739beb93cSSam Leffler identity, identity_len); 65839beb93cSSam Leffler 65939beb93cSSam Leffler /* MS-CHAP-Challenge */ 66039beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 66139beb93cSSam Leffler sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); 66239beb93cSSam Leffler if (challenge == NULL) { 6634bc52338SCy Schubert wpabuf_clear_free(msg); 66439beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " 66539beb93cSSam Leffler "implicit challenge"); 66639beb93cSSam Leffler return -1; 66739beb93cSSam Leffler } 66839beb93cSSam Leffler 66939beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, 67039beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 67139beb93cSSam Leffler challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); 67239beb93cSSam Leffler 67339beb93cSSam Leffler /* MS-CHAP-Response */ 67439beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, 67539beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 67639beb93cSSam Leffler EAP_TTLS_MSCHAP_RESPONSE_LEN); 67739beb93cSSam Leffler data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; 67839beb93cSSam Leffler *pos++ = data->ident; 67939beb93cSSam Leffler *pos++ = 1; /* Flags: Use NT style passwords */ 68039beb93cSSam Leffler os_memset(pos, 0, 24); /* LM-Response */ 68139beb93cSSam Leffler pos += 24; 68239beb93cSSam Leffler if (pwhash) { 68385732ac8SCy Schubert /* NT-Response */ 68485732ac8SCy Schubert if (challenge_response(challenge, password, pos)) { 68585732ac8SCy Schubert wpa_printf(MSG_ERROR, 68685732ac8SCy Schubert "EAP-TTLS/MSCHAP: Failed derive password hash"); 6874bc52338SCy Schubert wpabuf_clear_free(msg); 68885732ac8SCy Schubert os_free(challenge); 68985732ac8SCy Schubert return -1; 69085732ac8SCy Schubert } 69185732ac8SCy Schubert 69239beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", 69339beb93cSSam Leffler password, 16); 69439beb93cSSam Leffler } else { 69585732ac8SCy Schubert /* NT-Response */ 69685732ac8SCy Schubert if (nt_challenge_response(challenge, password, password_len, 69785732ac8SCy Schubert pos)) { 69885732ac8SCy Schubert wpa_printf(MSG_ERROR, 69985732ac8SCy Schubert "EAP-TTLS/MSCHAP: Failed derive password"); 7004bc52338SCy Schubert wpabuf_clear_free(msg); 70185732ac8SCy Schubert os_free(challenge); 70285732ac8SCy Schubert return -1; 70385732ac8SCy Schubert } 70485732ac8SCy Schubert 70539beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", 70639beb93cSSam Leffler password, password_len); 70739beb93cSSam Leffler } 70839beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", 70939beb93cSSam Leffler challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); 71039beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); 71139beb93cSSam Leffler pos += 24; 71239beb93cSSam Leffler os_free(challenge); 71339beb93cSSam Leffler AVP_PAD(buf, pos); 71439beb93cSSam Leffler 71539beb93cSSam Leffler wpabuf_put(msg, pos - buf); 71639beb93cSSam Leffler *resp = msg; 71739beb93cSSam Leffler 71839beb93cSSam Leffler /* EAP-TTLS/MSCHAP does not provide tunneled success 71939beb93cSSam Leffler * notification, so assume that Phase2 succeeds. */ 72039beb93cSSam Leffler ret->methodState = METHOD_DONE; 72139beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 72239beb93cSSam Leffler 72339beb93cSSam Leffler return 0; 724325151a3SRui Paulo #endif /* CONFIG_FIPS */ 72539beb93cSSam Leffler } 72639beb93cSSam Leffler 72739beb93cSSam Leffler 72839beb93cSSam Leffler static int eap_ttls_phase2_request_pap(struct eap_sm *sm, 72939beb93cSSam Leffler struct eap_ttls_data *data, 73039beb93cSSam Leffler struct eap_method_ret *ret, 73139beb93cSSam Leffler struct wpabuf **resp) 73239beb93cSSam Leffler { 73339beb93cSSam Leffler struct wpabuf *msg; 73439beb93cSSam Leffler u8 *buf, *pos; 73539beb93cSSam Leffler size_t pad; 73639beb93cSSam Leffler const u8 *identity, *password; 73739beb93cSSam Leffler size_t identity_len, password_len; 73839beb93cSSam Leffler 73939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); 74039beb93cSSam Leffler 74139beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 74239beb93cSSam Leffler password = eap_get_config_password(sm, &password_len); 74339beb93cSSam Leffler if (identity == NULL || password == NULL) 74439beb93cSSam Leffler return -1; 74539beb93cSSam Leffler 74639beb93cSSam Leffler msg = wpabuf_alloc(identity_len + password_len + 100); 74739beb93cSSam Leffler if (msg == NULL) { 74839beb93cSSam Leffler wpa_printf(MSG_ERROR, 74939beb93cSSam Leffler "EAP-TTLS/PAP: Failed to allocate memory"); 75039beb93cSSam Leffler return -1; 75139beb93cSSam Leffler } 75239beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 75339beb93cSSam Leffler 75439beb93cSSam Leffler /* User-Name */ 75539beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 75639beb93cSSam Leffler identity, identity_len); 75739beb93cSSam Leffler 75839beb93cSSam Leffler /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts 75939beb93cSSam Leffler * the data, so no separate encryption is used in the AVP itself. 76039beb93cSSam Leffler * However, the password is padded to obfuscate its length. */ 7613157ba21SRui Paulo pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; 76239beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, 76339beb93cSSam Leffler password_len + pad); 76439beb93cSSam Leffler os_memcpy(pos, password, password_len); 76539beb93cSSam Leffler pos += password_len; 76639beb93cSSam Leffler os_memset(pos, 0, pad); 76739beb93cSSam Leffler pos += pad; 76839beb93cSSam Leffler AVP_PAD(buf, pos); 76939beb93cSSam Leffler 77039beb93cSSam Leffler wpabuf_put(msg, pos - buf); 77139beb93cSSam Leffler *resp = msg; 77239beb93cSSam Leffler 77339beb93cSSam Leffler /* EAP-TTLS/PAP does not provide tunneled success notification, 77439beb93cSSam Leffler * so assume that Phase2 succeeds. */ 77539beb93cSSam Leffler ret->methodState = METHOD_DONE; 77639beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 77739beb93cSSam Leffler 77839beb93cSSam Leffler return 0; 77939beb93cSSam Leffler } 78039beb93cSSam Leffler 78139beb93cSSam Leffler 78239beb93cSSam Leffler static int eap_ttls_phase2_request_chap(struct eap_sm *sm, 78339beb93cSSam Leffler struct eap_ttls_data *data, 78439beb93cSSam Leffler struct eap_method_ret *ret, 78539beb93cSSam Leffler struct wpabuf **resp) 78639beb93cSSam Leffler { 787325151a3SRui Paulo #ifdef CONFIG_FIPS 788325151a3SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build"); 789325151a3SRui Paulo return -1; 790325151a3SRui Paulo #else /* CONFIG_FIPS */ 79139beb93cSSam Leffler struct wpabuf *msg; 79239beb93cSSam Leffler u8 *buf, *pos, *challenge; 79339beb93cSSam Leffler const u8 *identity, *password; 79439beb93cSSam Leffler size_t identity_len, password_len; 79539beb93cSSam Leffler 79639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); 79739beb93cSSam Leffler 79839beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 79939beb93cSSam Leffler password = eap_get_config_password(sm, &password_len); 80039beb93cSSam Leffler if (identity == NULL || password == NULL) 80139beb93cSSam Leffler return -1; 80239beb93cSSam Leffler 80339beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 80439beb93cSSam Leffler if (msg == NULL) { 80539beb93cSSam Leffler wpa_printf(MSG_ERROR, 80639beb93cSSam Leffler "EAP-TTLS/CHAP: Failed to allocate memory"); 80739beb93cSSam Leffler return -1; 80839beb93cSSam Leffler } 80939beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 81039beb93cSSam Leffler 81139beb93cSSam Leffler /* User-Name */ 81239beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 81339beb93cSSam Leffler identity, identity_len); 81439beb93cSSam Leffler 81539beb93cSSam Leffler /* CHAP-Challenge */ 81639beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 81739beb93cSSam Leffler sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); 81839beb93cSSam Leffler if (challenge == NULL) { 8194bc52338SCy Schubert wpabuf_clear_free(msg); 82039beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " 82139beb93cSSam Leffler "implicit challenge"); 82239beb93cSSam Leffler return -1; 82339beb93cSSam Leffler } 82439beb93cSSam Leffler 82539beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, 82639beb93cSSam Leffler challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); 82739beb93cSSam Leffler 82839beb93cSSam Leffler /* CHAP-Password */ 82939beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, 83039beb93cSSam Leffler 1 + EAP_TTLS_CHAP_PASSWORD_LEN); 83139beb93cSSam Leffler data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; 83239beb93cSSam Leffler *pos++ = data->ident; 83339beb93cSSam Leffler 83439beb93cSSam Leffler /* MD5(Ident + Password + Challenge) */ 83539beb93cSSam Leffler chap_md5(data->ident, password, password_len, challenge, 83639beb93cSSam Leffler EAP_TTLS_CHAP_CHALLENGE_LEN, pos); 83739beb93cSSam Leffler 83839beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", 83939beb93cSSam Leffler identity, identity_len); 84039beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", 84139beb93cSSam Leffler password, password_len); 84239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", 84339beb93cSSam Leffler challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); 84439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", 84539beb93cSSam Leffler pos, EAP_TTLS_CHAP_PASSWORD_LEN); 84639beb93cSSam Leffler pos += EAP_TTLS_CHAP_PASSWORD_LEN; 84739beb93cSSam Leffler os_free(challenge); 84839beb93cSSam Leffler AVP_PAD(buf, pos); 84939beb93cSSam Leffler 85039beb93cSSam Leffler wpabuf_put(msg, pos - buf); 85139beb93cSSam Leffler *resp = msg; 85239beb93cSSam Leffler 85339beb93cSSam Leffler /* EAP-TTLS/CHAP does not provide tunneled success 85439beb93cSSam Leffler * notification, so assume that Phase2 succeeds. */ 85539beb93cSSam Leffler ret->methodState = METHOD_DONE; 85639beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 85739beb93cSSam Leffler 85839beb93cSSam Leffler return 0; 859325151a3SRui Paulo #endif /* CONFIG_FIPS */ 86039beb93cSSam Leffler } 86139beb93cSSam Leffler 86239beb93cSSam Leffler 86339beb93cSSam Leffler static int eap_ttls_phase2_request(struct eap_sm *sm, 86439beb93cSSam Leffler struct eap_ttls_data *data, 86539beb93cSSam Leffler struct eap_method_ret *ret, 86639beb93cSSam Leffler struct eap_hdr *hdr, 86739beb93cSSam Leffler struct wpabuf **resp) 86839beb93cSSam Leffler { 86939beb93cSSam Leffler int res = 0; 87039beb93cSSam Leffler size_t len; 87139beb93cSSam Leffler enum phase2_types phase2_type = data->phase2_type; 87239beb93cSSam Leffler 87339beb93cSSam Leffler #ifdef EAP_TNC 87439beb93cSSam Leffler if (data->tnc_started) { 87539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); 87639beb93cSSam Leffler phase2_type = EAP_TTLS_PHASE2_EAP; 87739beb93cSSam Leffler } 87839beb93cSSam Leffler #endif /* EAP_TNC */ 87939beb93cSSam Leffler 88039beb93cSSam Leffler if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || 88139beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_MSCHAP || 88239beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_PAP || 88339beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_CHAP) { 88439beb93cSSam Leffler if (eap_get_config_identity(sm, &len) == NULL) { 88539beb93cSSam Leffler wpa_printf(MSG_INFO, 88639beb93cSSam Leffler "EAP-TTLS: Identity not configured"); 88739beb93cSSam Leffler eap_sm_request_identity(sm); 88839beb93cSSam Leffler if (eap_get_config_password(sm, &len) == NULL) 88939beb93cSSam Leffler eap_sm_request_password(sm); 89039beb93cSSam Leffler return 0; 89139beb93cSSam Leffler } 89239beb93cSSam Leffler 89339beb93cSSam Leffler if (eap_get_config_password(sm, &len) == NULL) { 89439beb93cSSam Leffler wpa_printf(MSG_INFO, 89539beb93cSSam Leffler "EAP-TTLS: Password not configured"); 89639beb93cSSam Leffler eap_sm_request_password(sm); 89739beb93cSSam Leffler return 0; 89839beb93cSSam Leffler } 89939beb93cSSam Leffler } 90039beb93cSSam Leffler 90139beb93cSSam Leffler switch (phase2_type) { 90239beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 90339beb93cSSam Leffler res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); 90439beb93cSSam Leffler break; 90539beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 90639beb93cSSam Leffler res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); 90739beb93cSSam Leffler break; 90839beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 90939beb93cSSam Leffler res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); 91039beb93cSSam Leffler break; 91139beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 91239beb93cSSam Leffler res = eap_ttls_phase2_request_pap(sm, data, ret, resp); 91339beb93cSSam Leffler break; 91439beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 91539beb93cSSam Leffler res = eap_ttls_phase2_request_chap(sm, data, ret, resp); 91639beb93cSSam Leffler break; 91739beb93cSSam Leffler default: 91839beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); 91939beb93cSSam Leffler res = -1; 92039beb93cSSam Leffler break; 92139beb93cSSam Leffler } 92239beb93cSSam Leffler 92339beb93cSSam Leffler if (res < 0) { 92439beb93cSSam Leffler ret->methodState = METHOD_DONE; 92539beb93cSSam Leffler ret->decision = DECISION_FAIL; 92639beb93cSSam Leffler } 92739beb93cSSam Leffler 92839beb93cSSam Leffler return res; 92939beb93cSSam Leffler } 93039beb93cSSam Leffler 93139beb93cSSam Leffler 93239beb93cSSam Leffler struct ttls_parse_avp { 93339beb93cSSam Leffler u8 *mschapv2; 93439beb93cSSam Leffler u8 *eapdata; 93539beb93cSSam Leffler size_t eap_len; 93639beb93cSSam Leffler int mschapv2_error; 93739beb93cSSam Leffler }; 93839beb93cSSam Leffler 93939beb93cSSam Leffler 94039beb93cSSam Leffler static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, 94139beb93cSSam Leffler struct ttls_parse_avp *parse) 94239beb93cSSam Leffler { 94339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); 94439beb93cSSam Leffler if (parse->eapdata == NULL) { 94585732ac8SCy Schubert parse->eapdata = os_memdup(dpos, dlen); 94639beb93cSSam Leffler if (parse->eapdata == NULL) { 94739beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " 94839beb93cSSam Leffler "memory for Phase 2 EAP data"); 94939beb93cSSam Leffler return -1; 95039beb93cSSam Leffler } 95139beb93cSSam Leffler parse->eap_len = dlen; 95239beb93cSSam Leffler } else { 95339beb93cSSam Leffler u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); 95439beb93cSSam Leffler if (neweap == NULL) { 95539beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " 95639beb93cSSam Leffler "memory for Phase 2 EAP data"); 95739beb93cSSam Leffler return -1; 95839beb93cSSam Leffler } 95939beb93cSSam Leffler os_memcpy(neweap + parse->eap_len, dpos, dlen); 96039beb93cSSam Leffler parse->eapdata = neweap; 96139beb93cSSam Leffler parse->eap_len += dlen; 96239beb93cSSam Leffler } 96339beb93cSSam Leffler 96439beb93cSSam Leffler return 0; 96539beb93cSSam Leffler } 96639beb93cSSam Leffler 96739beb93cSSam Leffler 96839beb93cSSam Leffler static int eap_ttls_parse_avp(u8 *pos, size_t left, 96939beb93cSSam Leffler struct ttls_parse_avp *parse) 97039beb93cSSam Leffler { 97139beb93cSSam Leffler struct ttls_avp *avp; 97239beb93cSSam Leffler u32 avp_code, avp_length, vendor_id = 0; 97339beb93cSSam Leffler u8 avp_flags, *dpos; 97439beb93cSSam Leffler size_t dlen; 97539beb93cSSam Leffler 97639beb93cSSam Leffler avp = (struct ttls_avp *) pos; 97739beb93cSSam Leffler avp_code = be_to_host32(avp->avp_code); 97839beb93cSSam Leffler avp_length = be_to_host32(avp->avp_length); 97939beb93cSSam Leffler avp_flags = (avp_length >> 24) & 0xff; 98039beb93cSSam Leffler avp_length &= 0xffffff; 98139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " 98239beb93cSSam Leffler "length=%d", (int) avp_code, avp_flags, 98339beb93cSSam Leffler (int) avp_length); 98439beb93cSSam Leffler 98539beb93cSSam Leffler if (avp_length > left) { 98639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " 98739beb93cSSam Leffler "(len=%d, left=%lu) - dropped", 98839beb93cSSam Leffler (int) avp_length, (unsigned long) left); 98939beb93cSSam Leffler return -1; 99039beb93cSSam Leffler } 99139beb93cSSam Leffler 99239beb93cSSam Leffler if (avp_length < sizeof(*avp)) { 99339beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", 99439beb93cSSam Leffler avp_length); 99539beb93cSSam Leffler return -1; 99639beb93cSSam Leffler } 99739beb93cSSam Leffler 99839beb93cSSam Leffler dpos = (u8 *) (avp + 1); 99939beb93cSSam Leffler dlen = avp_length - sizeof(*avp); 100039beb93cSSam Leffler if (avp_flags & AVP_FLAGS_VENDOR) { 100139beb93cSSam Leffler if (dlen < 4) { 100239beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP " 100339beb93cSSam Leffler "underflow"); 100439beb93cSSam Leffler return -1; 100539beb93cSSam Leffler } 100639beb93cSSam Leffler vendor_id = WPA_GET_BE32(dpos); 100739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", 100839beb93cSSam Leffler (int) vendor_id); 100939beb93cSSam Leffler dpos += 4; 101039beb93cSSam Leffler dlen -= 4; 101139beb93cSSam Leffler } 101239beb93cSSam Leffler 101339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); 101439beb93cSSam Leffler 101539beb93cSSam Leffler if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { 101639beb93cSSam Leffler if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) 101739beb93cSSam Leffler return -1; 101839beb93cSSam Leffler } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { 101939beb93cSSam Leffler /* This is an optional message that can be displayed to 102039beb93cSSam Leffler * the user. */ 102139beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", 102239beb93cSSam Leffler dpos, dlen); 102339beb93cSSam Leffler } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 102439beb93cSSam Leffler avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { 102539beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success", 102639beb93cSSam Leffler dpos, dlen); 102739beb93cSSam Leffler if (dlen != 43) { 102839beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " 102939beb93cSSam Leffler "MS-CHAP2-Success length " 103039beb93cSSam Leffler "(len=%lu, expected 43)", 103139beb93cSSam Leffler (unsigned long) dlen); 103239beb93cSSam Leffler return -1; 103339beb93cSSam Leffler } 103439beb93cSSam Leffler parse->mschapv2 = dpos; 103539beb93cSSam Leffler } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 103639beb93cSSam Leffler avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { 103739beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error", 103839beb93cSSam Leffler dpos, dlen); 103939beb93cSSam Leffler parse->mschapv2_error = 1; 104039beb93cSSam Leffler } else if (avp_flags & AVP_FLAGS_MANDATORY) { 104139beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP " 104239beb93cSSam Leffler "code %d vendor_id %d - dropped", 104339beb93cSSam Leffler (int) avp_code, (int) vendor_id); 104439beb93cSSam Leffler return -1; 104539beb93cSSam Leffler } else { 104639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " 104739beb93cSSam Leffler "code %d vendor_id %d", 104839beb93cSSam Leffler (int) avp_code, (int) vendor_id); 104939beb93cSSam Leffler } 105039beb93cSSam Leffler 105139beb93cSSam Leffler return avp_length; 105239beb93cSSam Leffler } 105339beb93cSSam Leffler 105439beb93cSSam Leffler 105539beb93cSSam Leffler static int eap_ttls_parse_avps(struct wpabuf *in_decrypted, 105639beb93cSSam Leffler struct ttls_parse_avp *parse) 105739beb93cSSam Leffler { 105839beb93cSSam Leffler u8 *pos; 105939beb93cSSam Leffler size_t left, pad; 106039beb93cSSam Leffler int avp_length; 106139beb93cSSam Leffler 106239beb93cSSam Leffler pos = wpabuf_mhead(in_decrypted); 106339beb93cSSam Leffler left = wpabuf_len(in_decrypted); 106439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); 106539beb93cSSam Leffler if (left < sizeof(struct ttls_avp)) { 106639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" 106739beb93cSSam Leffler " len=%lu expected %lu or more - dropped", 106839beb93cSSam Leffler (unsigned long) left, 106939beb93cSSam Leffler (unsigned long) sizeof(struct ttls_avp)); 107039beb93cSSam Leffler return -1; 107139beb93cSSam Leffler } 107239beb93cSSam Leffler 107339beb93cSSam Leffler /* Parse AVPs */ 107439beb93cSSam Leffler os_memset(parse, 0, sizeof(*parse)); 107539beb93cSSam Leffler 107639beb93cSSam Leffler while (left > 0) { 107739beb93cSSam Leffler avp_length = eap_ttls_parse_avp(pos, left, parse); 107839beb93cSSam Leffler if (avp_length < 0) 107939beb93cSSam Leffler return -1; 108039beb93cSSam Leffler 108139beb93cSSam Leffler pad = (4 - (avp_length & 3)) & 3; 108239beb93cSSam Leffler pos += avp_length + pad; 108339beb93cSSam Leffler if (left < avp_length + pad) 108439beb93cSSam Leffler left = 0; 108539beb93cSSam Leffler else 108639beb93cSSam Leffler left -= avp_length + pad; 108739beb93cSSam Leffler } 108839beb93cSSam Leffler 108939beb93cSSam Leffler return 0; 109039beb93cSSam Leffler } 109139beb93cSSam Leffler 109239beb93cSSam Leffler 109339beb93cSSam Leffler static u8 * eap_ttls_fake_identity_request(void) 109439beb93cSSam Leffler { 109539beb93cSSam Leffler struct eap_hdr *hdr; 109639beb93cSSam Leffler u8 *buf; 109739beb93cSSam Leffler 109839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " 109939beb93cSSam Leffler "Phase 2 - use fake EAP-Request Identity"); 110039beb93cSSam Leffler buf = os_malloc(sizeof(*hdr) + 1); 110139beb93cSSam Leffler if (buf == NULL) { 110239beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " 110339beb93cSSam Leffler "memory for fake EAP-Identity Request"); 110439beb93cSSam Leffler return NULL; 110539beb93cSSam Leffler } 110639beb93cSSam Leffler 110739beb93cSSam Leffler hdr = (struct eap_hdr *) buf; 110839beb93cSSam Leffler hdr->code = EAP_CODE_REQUEST; 110939beb93cSSam Leffler hdr->identifier = 0; 111039beb93cSSam Leffler hdr->length = host_to_be16(sizeof(*hdr) + 1); 111139beb93cSSam Leffler buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; 111239beb93cSSam Leffler 111339beb93cSSam Leffler return buf; 111439beb93cSSam Leffler } 111539beb93cSSam Leffler 111639beb93cSSam Leffler 111739beb93cSSam Leffler static int eap_ttls_encrypt_response(struct eap_sm *sm, 111839beb93cSSam Leffler struct eap_ttls_data *data, 111939beb93cSSam Leffler struct wpabuf *resp, u8 identifier, 112039beb93cSSam Leffler struct wpabuf **out_data) 112139beb93cSSam Leffler { 112239beb93cSSam Leffler if (resp == NULL) 112339beb93cSSam Leffler return 0; 112439beb93cSSam Leffler 112539beb93cSSam Leffler wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", 112639beb93cSSam Leffler resp); 112739beb93cSSam Leffler if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, 112839beb93cSSam Leffler data->ttls_version, identifier, 112939beb93cSSam Leffler resp, out_data)) { 113039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " 113139beb93cSSam Leffler "frame"); 11324bc52338SCy Schubert wpabuf_clear_free(resp); 113339beb93cSSam Leffler return -1; 113439beb93cSSam Leffler } 11354bc52338SCy Schubert wpabuf_clear_free(resp); 113639beb93cSSam Leffler 113739beb93cSSam Leffler return 0; 113839beb93cSSam Leffler } 113939beb93cSSam Leffler 114039beb93cSSam Leffler 114139beb93cSSam Leffler static int eap_ttls_process_phase2_eap(struct eap_sm *sm, 114239beb93cSSam Leffler struct eap_ttls_data *data, 114339beb93cSSam Leffler struct eap_method_ret *ret, 114439beb93cSSam Leffler struct ttls_parse_avp *parse, 114539beb93cSSam Leffler struct wpabuf **resp) 114639beb93cSSam Leffler { 114739beb93cSSam Leffler struct eap_hdr *hdr; 114839beb93cSSam Leffler size_t len; 114939beb93cSSam Leffler 115039beb93cSSam Leffler if (parse->eapdata == NULL) { 115139beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " 115239beb93cSSam Leffler "packet - dropped"); 115339beb93cSSam Leffler return -1; 115439beb93cSSam Leffler } 115539beb93cSSam Leffler 115639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", 115739beb93cSSam Leffler parse->eapdata, parse->eap_len); 115839beb93cSSam Leffler hdr = (struct eap_hdr *) parse->eapdata; 115939beb93cSSam Leffler 116039beb93cSSam Leffler if (parse->eap_len < sizeof(*hdr)) { 116139beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " 116239beb93cSSam Leffler "frame (len=%lu, expected %lu or more) - dropped", 116339beb93cSSam Leffler (unsigned long) parse->eap_len, 116439beb93cSSam Leffler (unsigned long) sizeof(*hdr)); 116539beb93cSSam Leffler return -1; 116639beb93cSSam Leffler } 116739beb93cSSam Leffler len = be_to_host16(hdr->length); 116839beb93cSSam Leffler if (len > parse->eap_len) { 116939beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " 117039beb93cSSam Leffler "EAP frame (EAP hdr len=%lu, EAP data len in " 117139beb93cSSam Leffler "AVP=%lu)", 117239beb93cSSam Leffler (unsigned long) len, 117339beb93cSSam Leffler (unsigned long) parse->eap_len); 117439beb93cSSam Leffler return -1; 117539beb93cSSam Leffler } 117639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " 117739beb93cSSam Leffler "identifier=%d length=%lu", 117839beb93cSSam Leffler hdr->code, hdr->identifier, (unsigned long) len); 117939beb93cSSam Leffler switch (hdr->code) { 118039beb93cSSam Leffler case EAP_CODE_REQUEST: 118139beb93cSSam Leffler if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { 118239beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " 118339beb93cSSam Leffler "processing failed"); 118439beb93cSSam Leffler return -1; 118539beb93cSSam Leffler } 118639beb93cSSam Leffler break; 118739beb93cSSam Leffler default: 118839beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " 118939beb93cSSam Leffler "Phase 2 EAP header", hdr->code); 119039beb93cSSam Leffler return -1; 119139beb93cSSam Leffler } 119239beb93cSSam Leffler 119339beb93cSSam Leffler return 0; 119439beb93cSSam Leffler } 119539beb93cSSam Leffler 119639beb93cSSam Leffler 119739beb93cSSam Leffler static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, 119839beb93cSSam Leffler struct eap_ttls_data *data, 119939beb93cSSam Leffler struct eap_method_ret *ret, 120039beb93cSSam Leffler struct ttls_parse_avp *parse) 120139beb93cSSam Leffler { 1202f05cddf9SRui Paulo #ifdef EAP_MSCHAPv2 120339beb93cSSam Leffler if (parse->mschapv2_error) { 120439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " 120539beb93cSSam Leffler "MS-CHAP-Error - failed"); 120639beb93cSSam Leffler ret->methodState = METHOD_DONE; 120739beb93cSSam Leffler ret->decision = DECISION_FAIL; 120839beb93cSSam Leffler /* Reply with empty data to ACK error */ 120939beb93cSSam Leffler return 1; 121039beb93cSSam Leffler } 121139beb93cSSam Leffler 121239beb93cSSam Leffler if (parse->mschapv2 == NULL) { 121339beb93cSSam Leffler #ifdef EAP_TNC 121439beb93cSSam Leffler if (data->phase2_success && parse->eapdata) { 121539beb93cSSam Leffler /* 121639beb93cSSam Leffler * Allow EAP-TNC to be started after successfully 121739beb93cSSam Leffler * completed MSCHAPV2. 121839beb93cSSam Leffler */ 121939beb93cSSam Leffler return 1; 122039beb93cSSam Leffler } 122139beb93cSSam Leffler #endif /* EAP_TNC */ 122239beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " 122339beb93cSSam Leffler "received for Phase2 MSCHAPV2"); 122439beb93cSSam Leffler return -1; 122539beb93cSSam Leffler } 122639beb93cSSam Leffler if (parse->mschapv2[0] != data->ident) { 122739beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " 122839beb93cSSam Leffler "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", 122939beb93cSSam Leffler parse->mschapv2[0], data->ident); 123039beb93cSSam Leffler return -1; 123139beb93cSSam Leffler } 123239beb93cSSam Leffler if (!data->auth_response_valid || 123339beb93cSSam Leffler mschapv2_verify_auth_response(data->auth_response, 123439beb93cSSam Leffler parse->mschapv2 + 1, 42)) { 123539beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " 123639beb93cSSam Leffler "response in Phase 2 MSCHAPV2 success request"); 123739beb93cSSam Leffler return -1; 123839beb93cSSam Leffler } 123939beb93cSSam Leffler 124039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " 124139beb93cSSam Leffler "authentication succeeded"); 124239beb93cSSam Leffler ret->methodState = METHOD_DONE; 124339beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 124439beb93cSSam Leffler data->phase2_success = 1; 124539beb93cSSam Leffler 124639beb93cSSam Leffler /* 124739beb93cSSam Leffler * Reply with empty data; authentication server will reply 124839beb93cSSam Leffler * with EAP-Success after this. 124939beb93cSSam Leffler */ 125039beb93cSSam Leffler return 1; 1251f05cddf9SRui Paulo #else /* EAP_MSCHAPv2 */ 1252f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); 1253f05cddf9SRui Paulo return -1; 1254f05cddf9SRui Paulo #endif /* EAP_MSCHAPv2 */ 125539beb93cSSam Leffler } 125639beb93cSSam Leffler 125739beb93cSSam Leffler 125839beb93cSSam Leffler #ifdef EAP_TNC 125939beb93cSSam Leffler static int eap_ttls_process_tnc_start(struct eap_sm *sm, 126039beb93cSSam Leffler struct eap_ttls_data *data, 126139beb93cSSam Leffler struct eap_method_ret *ret, 126239beb93cSSam Leffler struct ttls_parse_avp *parse, 126339beb93cSSam Leffler struct wpabuf **resp) 126439beb93cSSam Leffler { 126539beb93cSSam Leffler /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ 126639beb93cSSam Leffler if (parse->eapdata == NULL) { 126739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " 126839beb93cSSam Leffler "unexpected tunneled data (no EAP)"); 126939beb93cSSam Leffler return -1; 127039beb93cSSam Leffler } 127139beb93cSSam Leffler 127239beb93cSSam Leffler if (!data->ready_for_tnc) { 127339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " 127439beb93cSSam Leffler "EAP after non-EAP, but not ready for TNC"); 127539beb93cSSam Leffler return -1; 127639beb93cSSam Leffler } 127739beb93cSSam Leffler 127839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " 127939beb93cSSam Leffler "non-EAP method"); 128039beb93cSSam Leffler data->tnc_started = 1; 128139beb93cSSam Leffler 128239beb93cSSam Leffler if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) 128339beb93cSSam Leffler return -1; 128439beb93cSSam Leffler 128539beb93cSSam Leffler return 0; 128639beb93cSSam Leffler } 128739beb93cSSam Leffler #endif /* EAP_TNC */ 128839beb93cSSam Leffler 128939beb93cSSam Leffler 129039beb93cSSam Leffler static int eap_ttls_process_decrypted(struct eap_sm *sm, 129139beb93cSSam Leffler struct eap_ttls_data *data, 129239beb93cSSam Leffler struct eap_method_ret *ret, 129339beb93cSSam Leffler u8 identifier, 129439beb93cSSam Leffler struct ttls_parse_avp *parse, 129539beb93cSSam Leffler struct wpabuf *in_decrypted, 129639beb93cSSam Leffler struct wpabuf **out_data) 129739beb93cSSam Leffler { 129839beb93cSSam Leffler struct wpabuf *resp = NULL; 129939beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 130039beb93cSSam Leffler int res; 130139beb93cSSam Leffler enum phase2_types phase2_type = data->phase2_type; 130239beb93cSSam Leffler 130339beb93cSSam Leffler #ifdef EAP_TNC 130439beb93cSSam Leffler if (data->tnc_started) 130539beb93cSSam Leffler phase2_type = EAP_TTLS_PHASE2_EAP; 130639beb93cSSam Leffler #endif /* EAP_TNC */ 130739beb93cSSam Leffler 130839beb93cSSam Leffler switch (phase2_type) { 130939beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 131039beb93cSSam Leffler if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < 131139beb93cSSam Leffler 0) 131239beb93cSSam Leffler return -1; 131339beb93cSSam Leffler break; 131439beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 131539beb93cSSam Leffler res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); 131639beb93cSSam Leffler #ifdef EAP_TNC 131739beb93cSSam Leffler if (res == 1 && parse->eapdata && data->phase2_success) { 131839beb93cSSam Leffler /* 131939beb93cSSam Leffler * TNC may be required as the next 132039beb93cSSam Leffler * authentication method within the tunnel. 132139beb93cSSam Leffler */ 132239beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 132339beb93cSSam Leffler data->ready_for_tnc = 1; 132439beb93cSSam Leffler if (eap_ttls_process_tnc_start(sm, data, ret, parse, 132539beb93cSSam Leffler &resp) == 0) 132639beb93cSSam Leffler break; 132739beb93cSSam Leffler } 132839beb93cSSam Leffler #endif /* EAP_TNC */ 132939beb93cSSam Leffler return res; 133039beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 133139beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 133239beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 133339beb93cSSam Leffler #ifdef EAP_TNC 133439beb93cSSam Leffler if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < 133539beb93cSSam Leffler 0) 133639beb93cSSam Leffler return -1; 133739beb93cSSam Leffler break; 133839beb93cSSam Leffler #else /* EAP_TNC */ 133939beb93cSSam Leffler /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled 134039beb93cSSam Leffler * requests to the supplicant */ 134139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " 134239beb93cSSam Leffler "tunneled data"); 134339beb93cSSam Leffler return -1; 134439beb93cSSam Leffler #endif /* EAP_TNC */ 134539beb93cSSam Leffler } 134639beb93cSSam Leffler 134739beb93cSSam Leffler if (resp) { 134839beb93cSSam Leffler if (eap_ttls_encrypt_response(sm, data, resp, identifier, 134939beb93cSSam Leffler out_data) < 0) 135039beb93cSSam Leffler return -1; 135139beb93cSSam Leffler } else if (config->pending_req_identity || 135239beb93cSSam Leffler config->pending_req_password || 135339beb93cSSam Leffler config->pending_req_otp || 135485732ac8SCy Schubert config->pending_req_new_password || 135585732ac8SCy Schubert config->pending_req_sim) { 13564bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 135739beb93cSSam Leffler data->pending_phase2_req = wpabuf_dup(in_decrypted); 135839beb93cSSam Leffler } 135939beb93cSSam Leffler 136039beb93cSSam Leffler return 0; 136139beb93cSSam Leffler } 136239beb93cSSam Leffler 136339beb93cSSam Leffler 136439beb93cSSam Leffler static int eap_ttls_implicit_identity_request(struct eap_sm *sm, 136539beb93cSSam Leffler struct eap_ttls_data *data, 136639beb93cSSam Leffler struct eap_method_ret *ret, 136739beb93cSSam Leffler u8 identifier, 136839beb93cSSam Leffler struct wpabuf **out_data) 136939beb93cSSam Leffler { 137039beb93cSSam Leffler int retval = 0; 137139beb93cSSam Leffler struct eap_hdr *hdr; 137239beb93cSSam Leffler struct wpabuf *resp; 137339beb93cSSam Leffler 137439beb93cSSam Leffler hdr = (struct eap_hdr *) eap_ttls_fake_identity_request(); 137539beb93cSSam Leffler if (hdr == NULL) { 137639beb93cSSam Leffler ret->methodState = METHOD_DONE; 137739beb93cSSam Leffler ret->decision = DECISION_FAIL; 137839beb93cSSam Leffler return -1; 137939beb93cSSam Leffler } 138039beb93cSSam Leffler 138139beb93cSSam Leffler resp = NULL; 138239beb93cSSam Leffler if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) { 138339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " 138439beb93cSSam Leffler "processing failed"); 138539beb93cSSam Leffler retval = -1; 138639beb93cSSam Leffler } else { 1387f05cddf9SRui Paulo struct eap_peer_config *config = eap_get_config(sm); 1388f05cddf9SRui Paulo if (resp == NULL && 1389f05cddf9SRui Paulo (config->pending_req_identity || 1390f05cddf9SRui Paulo config->pending_req_password || 1391f05cddf9SRui Paulo config->pending_req_otp || 139285732ac8SCy Schubert config->pending_req_new_password || 139385732ac8SCy Schubert config->pending_req_sim)) { 1394f05cddf9SRui Paulo /* 1395f05cddf9SRui Paulo * Use empty buffer to force implicit request 1396f05cddf9SRui Paulo * processing when EAP request is re-processed after 1397f05cddf9SRui Paulo * user input. 1398f05cddf9SRui Paulo */ 13994bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 1400f05cddf9SRui Paulo data->pending_phase2_req = wpabuf_alloc(0); 1401f05cddf9SRui Paulo } 1402f05cddf9SRui Paulo 140339beb93cSSam Leffler retval = eap_ttls_encrypt_response(sm, data, resp, identifier, 140439beb93cSSam Leffler out_data); 140539beb93cSSam Leffler } 140639beb93cSSam Leffler 140739beb93cSSam Leffler os_free(hdr); 140839beb93cSSam Leffler 140939beb93cSSam Leffler if (retval < 0) { 141039beb93cSSam Leffler ret->methodState = METHOD_DONE; 141139beb93cSSam Leffler ret->decision = DECISION_FAIL; 141239beb93cSSam Leffler } 141339beb93cSSam Leffler 141439beb93cSSam Leffler return retval; 141539beb93cSSam Leffler } 141639beb93cSSam Leffler 141739beb93cSSam Leffler 141839beb93cSSam Leffler static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data, 141939beb93cSSam Leffler struct eap_method_ret *ret, u8 identifier, 142039beb93cSSam Leffler struct wpabuf **out_data) 142139beb93cSSam Leffler { 142239beb93cSSam Leffler data->phase2_start = 0; 142339beb93cSSam Leffler 142439beb93cSSam Leffler /* 142539beb93cSSam Leffler * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only 142639beb93cSSam Leffler * if TLS part was indeed resuming a previous session. Most 142739beb93cSSam Leffler * Authentication Servers terminate EAP-TTLS before reaching this 142839beb93cSSam Leffler * point, but some do not. Make wpa_supplicant stop phase 2 here, if 142939beb93cSSam Leffler * needed. 143039beb93cSSam Leffler */ 143139beb93cSSam Leffler if (data->reauth && 143239beb93cSSam Leffler tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { 143339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " 143439beb93cSSam Leffler "skip phase 2"); 143539beb93cSSam Leffler *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS, 143639beb93cSSam Leffler data->ttls_version); 143739beb93cSSam Leffler ret->methodState = METHOD_DONE; 143839beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 143939beb93cSSam Leffler data->phase2_success = 1; 144039beb93cSSam Leffler return 0; 144139beb93cSSam Leffler } 144239beb93cSSam Leffler 144339beb93cSSam Leffler return eap_ttls_implicit_identity_request(sm, data, ret, identifier, 144439beb93cSSam Leffler out_data); 144539beb93cSSam Leffler } 144639beb93cSSam Leffler 144739beb93cSSam Leffler 144839beb93cSSam Leffler static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, 144939beb93cSSam Leffler struct eap_method_ret *ret, u8 identifier, 145039beb93cSSam Leffler const struct wpabuf *in_data, 145139beb93cSSam Leffler struct wpabuf **out_data) 145239beb93cSSam Leffler { 145339beb93cSSam Leffler struct wpabuf *in_decrypted = NULL; 145439beb93cSSam Leffler int retval = 0; 145539beb93cSSam Leffler struct ttls_parse_avp parse; 145639beb93cSSam Leffler 145739beb93cSSam Leffler os_memset(&parse, 0, sizeof(parse)); 145839beb93cSSam Leffler 145939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" 146039beb93cSSam Leffler " Phase 2", 146139beb93cSSam Leffler in_data ? (unsigned long) wpabuf_len(in_data) : 0); 146239beb93cSSam Leffler 146339beb93cSSam Leffler if (data->pending_phase2_req) { 146439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " 146539beb93cSSam Leffler "skip decryption and use old data"); 146639beb93cSSam Leffler /* Clear TLS reassembly state. */ 146739beb93cSSam Leffler eap_peer_tls_reset_input(&data->ssl); 146839beb93cSSam Leffler 146939beb93cSSam Leffler in_decrypted = data->pending_phase2_req; 147039beb93cSSam Leffler data->pending_phase2_req = NULL; 147139beb93cSSam Leffler if (wpabuf_len(in_decrypted) == 0) { 14724bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 147339beb93cSSam Leffler return eap_ttls_implicit_identity_request( 147439beb93cSSam Leffler sm, data, ret, identifier, out_data); 147539beb93cSSam Leffler } 147639beb93cSSam Leffler goto continue_req; 147739beb93cSSam Leffler } 147839beb93cSSam Leffler 147939beb93cSSam Leffler if ((in_data == NULL || wpabuf_len(in_data) == 0) && 148039beb93cSSam Leffler data->phase2_start) { 1481c1d255d3SCy Schubert start: 148239beb93cSSam Leffler return eap_ttls_phase2_start(sm, data, ret, identifier, 148339beb93cSSam Leffler out_data); 148439beb93cSSam Leffler } 148539beb93cSSam Leffler 148639beb93cSSam Leffler if (in_data == NULL || wpabuf_len(in_data) == 0) { 148739beb93cSSam Leffler /* Received TLS ACK - requesting more fragments */ 148839beb93cSSam Leffler return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, 148939beb93cSSam Leffler data->ttls_version, 149039beb93cSSam Leffler identifier, NULL, out_data); 149139beb93cSSam Leffler } 149239beb93cSSam Leffler 149339beb93cSSam Leffler retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); 149439beb93cSSam Leffler if (retval) 149539beb93cSSam Leffler goto done; 1496c1d255d3SCy Schubert if (wpabuf_len(in_decrypted) == 0) { 1497c1d255d3SCy Schubert wpabuf_free(in_decrypted); 1498c1d255d3SCy Schubert goto start; 1499c1d255d3SCy Schubert } 1500c1d255d3SCy Schubert 1501*a90b9d01SCy Schubert /* RFC 9190 Section 2.5 */ 1502c1d255d3SCy Schubert if (data->ssl.tls_v13 && wpabuf_len(in_decrypted) == 1 && 1503c1d255d3SCy Schubert *wpabuf_head_u8(in_decrypted) == 0) { 1504c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1505*a90b9d01SCy Schubert "EAP-TLS: ACKing protected success indication (appl data 0x00)"); 1506c1d255d3SCy Schubert eap_peer_tls_reset_output(&data->ssl); 1507c1d255d3SCy Schubert wpabuf_free(in_decrypted); 1508c1d255d3SCy Schubert return 1; 1509c1d255d3SCy Schubert } 151039beb93cSSam Leffler 151139beb93cSSam Leffler continue_req: 151239beb93cSSam Leffler data->phase2_start = 0; 151339beb93cSSam Leffler 151439beb93cSSam Leffler if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) { 151539beb93cSSam Leffler retval = -1; 151639beb93cSSam Leffler goto done; 151739beb93cSSam Leffler } 151839beb93cSSam Leffler 151939beb93cSSam Leffler retval = eap_ttls_process_decrypted(sm, data, ret, identifier, 152039beb93cSSam Leffler &parse, in_decrypted, out_data); 152139beb93cSSam Leffler 152239beb93cSSam Leffler done: 15234bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 152439beb93cSSam Leffler os_free(parse.eapdata); 152539beb93cSSam Leffler 152639beb93cSSam Leffler if (retval < 0) { 152739beb93cSSam Leffler ret->methodState = METHOD_DONE; 152839beb93cSSam Leffler ret->decision = DECISION_FAIL; 152939beb93cSSam Leffler } 153039beb93cSSam Leffler 153139beb93cSSam Leffler return retval; 153239beb93cSSam Leffler } 153339beb93cSSam Leffler 153439beb93cSSam Leffler 153539beb93cSSam Leffler static int eap_ttls_process_handshake(struct eap_sm *sm, 153639beb93cSSam Leffler struct eap_ttls_data *data, 153739beb93cSSam Leffler struct eap_method_ret *ret, 153839beb93cSSam Leffler u8 identifier, 1539325151a3SRui Paulo const struct wpabuf *in_data, 154039beb93cSSam Leffler struct wpabuf **out_data) 154139beb93cSSam Leffler { 154239beb93cSSam Leffler int res; 154339beb93cSSam Leffler 1544780fb4a2SCy Schubert if (sm->waiting_ext_cert_check && data->pending_resp) { 1545780fb4a2SCy Schubert struct eap_peer_config *config = eap_get_config(sm); 1546780fb4a2SCy Schubert 1547780fb4a2SCy Schubert if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) { 1548780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1549780fb4a2SCy Schubert "EAP-TTLS: External certificate check succeeded - continue handshake"); 1550780fb4a2SCy Schubert *out_data = data->pending_resp; 1551780fb4a2SCy Schubert data->pending_resp = NULL; 1552780fb4a2SCy Schubert sm->waiting_ext_cert_check = 0; 1553780fb4a2SCy Schubert return 0; 1554780fb4a2SCy Schubert } 1555780fb4a2SCy Schubert 1556780fb4a2SCy Schubert if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) { 1557780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1558780fb4a2SCy Schubert "EAP-TTLS: External certificate check failed - force authentication failure"); 1559780fb4a2SCy Schubert ret->methodState = METHOD_DONE; 1560780fb4a2SCy Schubert ret->decision = DECISION_FAIL; 1561780fb4a2SCy Schubert sm->waiting_ext_cert_check = 0; 1562780fb4a2SCy Schubert return 0; 1563780fb4a2SCy Schubert } 1564780fb4a2SCy Schubert 1565780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1566780fb4a2SCy Schubert "EAP-TTLS: Continuing to wait external server certificate validation"); 1567780fb4a2SCy Schubert return 0; 1568780fb4a2SCy Schubert } 1569780fb4a2SCy Schubert 157039beb93cSSam Leffler res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, 157139beb93cSSam Leffler data->ttls_version, identifier, 1572325151a3SRui Paulo in_data, out_data); 1573325151a3SRui Paulo if (res < 0) { 1574325151a3SRui Paulo wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed"); 1575325151a3SRui Paulo ret->methodState = METHOD_DONE; 1576325151a3SRui Paulo ret->decision = DECISION_FAIL; 1577325151a3SRui Paulo return -1; 1578325151a3SRui Paulo } 157939beb93cSSam Leffler 1580780fb4a2SCy Schubert if (sm->waiting_ext_cert_check) { 1581780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1582780fb4a2SCy Schubert "EAP-TTLS: Waiting external server certificate validation"); 15834bc52338SCy Schubert wpabuf_clear_free(data->pending_resp); 1584780fb4a2SCy Schubert data->pending_resp = *out_data; 1585780fb4a2SCy Schubert *out_data = NULL; 1586780fb4a2SCy Schubert return 0; 1587780fb4a2SCy Schubert } 1588780fb4a2SCy Schubert 158939beb93cSSam Leffler if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 159039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " 159139beb93cSSam Leffler "Phase 2"); 159239beb93cSSam Leffler if (data->resuming) { 159339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may " 159439beb93cSSam Leffler "skip Phase 2"); 159539beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 159639beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 159739beb93cSSam Leffler } 159839beb93cSSam Leffler data->phase2_start = 1; 159939beb93cSSam Leffler eap_ttls_v0_derive_key(sm, data); 160039beb93cSSam Leffler 160139beb93cSSam Leffler if (*out_data == NULL || wpabuf_len(*out_data) == 0) { 160239beb93cSSam Leffler if (eap_ttls_decrypt(sm, data, ret, identifier, 160339beb93cSSam Leffler NULL, out_data)) { 160439beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: " 160539beb93cSSam Leffler "failed to process early " 160639beb93cSSam Leffler "start for Phase 2"); 160739beb93cSSam Leffler } 160839beb93cSSam Leffler res = 0; 160939beb93cSSam Leffler } 161039beb93cSSam Leffler data->resuming = 0; 161139beb93cSSam Leffler } 161239beb93cSSam Leffler 161339beb93cSSam Leffler if (res == 2) { 161439beb93cSSam Leffler /* 161539beb93cSSam Leffler * Application data included in the handshake message. 161639beb93cSSam Leffler */ 16174bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 161839beb93cSSam Leffler data->pending_phase2_req = *out_data; 161939beb93cSSam Leffler *out_data = NULL; 1620325151a3SRui Paulo res = eap_ttls_decrypt(sm, data, ret, identifier, in_data, 162139beb93cSSam Leffler out_data); 162239beb93cSSam Leffler } 162339beb93cSSam Leffler 162439beb93cSSam Leffler return res; 162539beb93cSSam Leffler } 162639beb93cSSam Leffler 162739beb93cSSam Leffler 162839beb93cSSam Leffler static void eap_ttls_check_auth_status(struct eap_sm *sm, 162939beb93cSSam Leffler struct eap_ttls_data *data, 163039beb93cSSam Leffler struct eap_method_ret *ret) 163139beb93cSSam Leffler { 1632f05cddf9SRui Paulo if (ret->methodState == METHOD_DONE) { 1633c1d255d3SCy Schubert ret->allowNotifications = false; 163439beb93cSSam Leffler if (ret->decision == DECISION_UNCOND_SUCC || 163539beb93cSSam Leffler ret->decision == DECISION_COND_SUCC) { 163639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " 163739beb93cSSam Leffler "completed successfully"); 163839beb93cSSam Leffler data->phase2_success = 1; 1639780fb4a2SCy Schubert data->decision_succ = ret->decision; 164039beb93cSSam Leffler #ifdef EAP_TNC 164139beb93cSSam Leffler if (!data->ready_for_tnc && !data->tnc_started) { 164239beb93cSSam Leffler /* 164339beb93cSSam Leffler * TNC may be required as the next 164439beb93cSSam Leffler * authentication method within the tunnel. 164539beb93cSSam Leffler */ 164639beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 164739beb93cSSam Leffler data->ready_for_tnc = 1; 164839beb93cSSam Leffler } 164939beb93cSSam Leffler #endif /* EAP_TNC */ 165039beb93cSSam Leffler } 1651f05cddf9SRui Paulo } else if (ret->methodState == METHOD_MAY_CONT && 165239beb93cSSam Leffler (ret->decision == DECISION_UNCOND_SUCC || 165339beb93cSSam Leffler ret->decision == DECISION_COND_SUCC)) { 165439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " 165539beb93cSSam Leffler "completed successfully (MAY_CONT)"); 165639beb93cSSam Leffler data->phase2_success = 1; 1657780fb4a2SCy Schubert data->decision_succ = ret->decision; 1658780fb4a2SCy Schubert } else if (data->decision_succ != DECISION_FAIL && 1659780fb4a2SCy Schubert data->phase2_success && 1660780fb4a2SCy Schubert !data->ssl.tls_out) { 1661780fb4a2SCy Schubert /* 1662780fb4a2SCy Schubert * This is needed to cover the case where the final Phase 2 1663780fb4a2SCy Schubert * message gets fragmented since fragmentation clears 1664780fb4a2SCy Schubert * decision back to FAIL. 1665780fb4a2SCy Schubert */ 1666780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1667780fb4a2SCy Schubert "EAP-TTLS: Restore success decision after fragmented frame sent completely"); 1668780fb4a2SCy Schubert ret->decision = data->decision_succ; 166939beb93cSSam Leffler } 167039beb93cSSam Leffler } 167139beb93cSSam Leffler 167239beb93cSSam Leffler 167339beb93cSSam Leffler static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, 167439beb93cSSam Leffler struct eap_method_ret *ret, 167539beb93cSSam Leffler const struct wpabuf *reqData) 167639beb93cSSam Leffler { 167739beb93cSSam Leffler size_t left; 167839beb93cSSam Leffler int res; 167939beb93cSSam Leffler u8 flags, id; 168039beb93cSSam Leffler struct wpabuf *resp; 168139beb93cSSam Leffler const u8 *pos; 168239beb93cSSam Leffler struct eap_ttls_data *data = priv; 1683325151a3SRui Paulo struct wpabuf msg; 168439beb93cSSam Leffler 168539beb93cSSam Leffler pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, 168639beb93cSSam Leffler reqData, &left, &flags); 168739beb93cSSam Leffler if (pos == NULL) 168839beb93cSSam Leffler return NULL; 168939beb93cSSam Leffler id = eap_get_id(reqData); 169039beb93cSSam Leffler 169139beb93cSSam Leffler if (flags & EAP_TLS_FLAGS_START) { 1692f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own " 1693f05cddf9SRui Paulo "ver=%d)", flags & EAP_TLS_VERSION_MASK, 1694f05cddf9SRui Paulo data->ttls_version); 169539beb93cSSam Leffler 169639beb93cSSam Leffler /* RFC 5281, Ch. 9.2: 169739beb93cSSam Leffler * "This packet MAY contain additional information in the form 169839beb93cSSam Leffler * of AVPs, which may provide useful hints to the client" 169939beb93cSSam Leffler * For now, ignore any potential extra data. 170039beb93cSSam Leffler */ 170139beb93cSSam Leffler left = 0; 170239beb93cSSam Leffler } 170339beb93cSSam Leffler 1704325151a3SRui Paulo wpabuf_set(&msg, pos, left); 1705325151a3SRui Paulo 170639beb93cSSam Leffler resp = NULL; 170739beb93cSSam Leffler if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 170839beb93cSSam Leffler !data->resuming) { 170939beb93cSSam Leffler res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); 171039beb93cSSam Leffler } else { 171139beb93cSSam Leffler res = eap_ttls_process_handshake(sm, data, ret, id, 1712325151a3SRui Paulo &msg, &resp); 171339beb93cSSam Leffler } 171439beb93cSSam Leffler 171539beb93cSSam Leffler eap_ttls_check_auth_status(sm, data, ret); 171639beb93cSSam Leffler 171739beb93cSSam Leffler /* FIX: what about res == -1? Could just move all error processing into 171839beb93cSSam Leffler * the other functions and get rid of this res==1 case here. */ 171939beb93cSSam Leffler if (res == 1) { 17204bc52338SCy Schubert wpabuf_clear_free(resp); 172139beb93cSSam Leffler return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, 172239beb93cSSam Leffler data->ttls_version); 172339beb93cSSam Leffler } 172439beb93cSSam Leffler return resp; 172539beb93cSSam Leffler } 172639beb93cSSam Leffler 172739beb93cSSam Leffler 1728c1d255d3SCy Schubert static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) 172939beb93cSSam Leffler { 173039beb93cSSam Leffler struct eap_ttls_data *data = priv; 1731*a90b9d01SCy Schubert 173239beb93cSSam Leffler return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 1733*a90b9d01SCy Schubert data->phase2_success && data->phase2_auth != ALWAYS; 173439beb93cSSam Leffler } 173539beb93cSSam Leffler 173639beb93cSSam Leffler 173739beb93cSSam Leffler static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) 173839beb93cSSam Leffler { 173939beb93cSSam Leffler struct eap_ttls_data *data = priv; 174085732ac8SCy Schubert 174185732ac8SCy Schubert if (data->phase2_priv && data->phase2_method && 174285732ac8SCy Schubert data->phase2_method->deinit_for_reauth) 174385732ac8SCy Schubert data->phase2_method->deinit_for_reauth(sm, data->phase2_priv); 17444bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 174539beb93cSSam Leffler data->pending_phase2_req = NULL; 17464bc52338SCy Schubert wpabuf_clear_free(data->pending_resp); 1747780fb4a2SCy Schubert data->pending_resp = NULL; 1748780fb4a2SCy Schubert data->decision_succ = DECISION_FAIL; 174939beb93cSSam Leffler #ifdef EAP_TNC 175039beb93cSSam Leffler data->ready_for_tnc = 0; 175139beb93cSSam Leffler data->tnc_started = 0; 175239beb93cSSam Leffler #endif /* EAP_TNC */ 175339beb93cSSam Leffler } 175439beb93cSSam Leffler 175539beb93cSSam Leffler 175639beb93cSSam Leffler static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) 175739beb93cSSam Leffler { 175839beb93cSSam Leffler struct eap_ttls_data *data = priv; 17595b9c547cSRui Paulo eap_ttls_free_key(data); 17605b9c547cSRui Paulo os_free(data->session_id); 17615b9c547cSRui Paulo data->session_id = NULL; 176239beb93cSSam Leffler if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 176339beb93cSSam Leffler os_free(data); 176439beb93cSSam Leffler return NULL; 176539beb93cSSam Leffler } 176639beb93cSSam Leffler if (data->phase2_priv && data->phase2_method && 176739beb93cSSam Leffler data->phase2_method->init_for_reauth) 176839beb93cSSam Leffler data->phase2_method->init_for_reauth(sm, data->phase2_priv); 176939beb93cSSam Leffler data->phase2_start = 0; 177039beb93cSSam Leffler data->phase2_success = 0; 177139beb93cSSam Leffler data->resuming = 1; 177239beb93cSSam Leffler data->reauth = 1; 177339beb93cSSam Leffler return priv; 177439beb93cSSam Leffler } 177539beb93cSSam Leffler 177639beb93cSSam Leffler 177739beb93cSSam Leffler static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, 177839beb93cSSam Leffler size_t buflen, int verbose) 177939beb93cSSam Leffler { 178039beb93cSSam Leffler struct eap_ttls_data *data = priv; 178139beb93cSSam Leffler int len, ret; 178239beb93cSSam Leffler 178339beb93cSSam Leffler len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 178439beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, 178539beb93cSSam Leffler "EAP-TTLSv%d Phase2 method=", 178639beb93cSSam Leffler data->ttls_version); 17875b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 178839beb93cSSam Leffler return len; 178939beb93cSSam Leffler len += ret; 179039beb93cSSam Leffler switch (data->phase2_type) { 179139beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 179239beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", 179339beb93cSSam Leffler data->phase2_method ? 179439beb93cSSam Leffler data->phase2_method->name : "?"); 179539beb93cSSam Leffler break; 179639beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 179739beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); 179839beb93cSSam Leffler break; 179939beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 180039beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); 180139beb93cSSam Leffler break; 180239beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 180339beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "PAP\n"); 180439beb93cSSam Leffler break; 180539beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 180639beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); 180739beb93cSSam Leffler break; 180839beb93cSSam Leffler default: 180939beb93cSSam Leffler ret = 0; 181039beb93cSSam Leffler break; 181139beb93cSSam Leffler } 18125b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 181339beb93cSSam Leffler return len; 181439beb93cSSam Leffler len += ret; 181539beb93cSSam Leffler 181639beb93cSSam Leffler return len; 181739beb93cSSam Leffler } 181839beb93cSSam Leffler 181939beb93cSSam Leffler 1820c1d255d3SCy Schubert static bool eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) 182139beb93cSSam Leffler { 182239beb93cSSam Leffler struct eap_ttls_data *data = priv; 182339beb93cSSam Leffler return data->key_data != NULL && data->phase2_success; 182439beb93cSSam Leffler } 182539beb93cSSam Leffler 182639beb93cSSam Leffler 182739beb93cSSam Leffler static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) 182839beb93cSSam Leffler { 182939beb93cSSam Leffler struct eap_ttls_data *data = priv; 183039beb93cSSam Leffler u8 *key; 183139beb93cSSam Leffler 183239beb93cSSam Leffler if (data->key_data == NULL || !data->phase2_success) 183339beb93cSSam Leffler return NULL; 183439beb93cSSam Leffler 183585732ac8SCy Schubert key = os_memdup(data->key_data, EAP_TLS_KEY_LEN); 183639beb93cSSam Leffler if (key == NULL) 183739beb93cSSam Leffler return NULL; 183839beb93cSSam Leffler 183939beb93cSSam Leffler *len = EAP_TLS_KEY_LEN; 184039beb93cSSam Leffler 184139beb93cSSam Leffler return key; 184239beb93cSSam Leffler } 184339beb93cSSam Leffler 184439beb93cSSam Leffler 18455b9c547cSRui Paulo static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 18465b9c547cSRui Paulo { 18475b9c547cSRui Paulo struct eap_ttls_data *data = priv; 18485b9c547cSRui Paulo u8 *id; 18495b9c547cSRui Paulo 18505b9c547cSRui Paulo if (data->session_id == NULL || !data->phase2_success) 18515b9c547cSRui Paulo return NULL; 18525b9c547cSRui Paulo 185385732ac8SCy Schubert id = os_memdup(data->session_id, data->id_len); 18545b9c547cSRui Paulo if (id == NULL) 18555b9c547cSRui Paulo return NULL; 18565b9c547cSRui Paulo 18575b9c547cSRui Paulo *len = data->id_len; 18585b9c547cSRui Paulo 18595b9c547cSRui Paulo return id; 18605b9c547cSRui Paulo } 18615b9c547cSRui Paulo 18625b9c547cSRui Paulo 18635b9c547cSRui Paulo static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 18645b9c547cSRui Paulo { 18655b9c547cSRui Paulo struct eap_ttls_data *data = priv; 18665b9c547cSRui Paulo u8 *key; 18675b9c547cSRui Paulo 18685b9c547cSRui Paulo if (data->key_data == NULL) 18695b9c547cSRui Paulo return NULL; 18705b9c547cSRui Paulo 187185732ac8SCy Schubert key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); 18725b9c547cSRui Paulo if (key == NULL) 18735b9c547cSRui Paulo return NULL; 18745b9c547cSRui Paulo 18755b9c547cSRui Paulo *len = EAP_EMSK_LEN; 18765b9c547cSRui Paulo 18775b9c547cSRui Paulo return key; 18785b9c547cSRui Paulo } 18795b9c547cSRui Paulo 18805b9c547cSRui Paulo 188139beb93cSSam Leffler int eap_peer_ttls_register(void) 188239beb93cSSam Leffler { 188339beb93cSSam Leffler struct eap_method *eap; 188439beb93cSSam Leffler 188539beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 188639beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); 188739beb93cSSam Leffler if (eap == NULL) 188839beb93cSSam Leffler return -1; 188939beb93cSSam Leffler 189039beb93cSSam Leffler eap->init = eap_ttls_init; 189139beb93cSSam Leffler eap->deinit = eap_ttls_deinit; 189239beb93cSSam Leffler eap->process = eap_ttls_process; 189339beb93cSSam Leffler eap->isKeyAvailable = eap_ttls_isKeyAvailable; 189439beb93cSSam Leffler eap->getKey = eap_ttls_getKey; 18955b9c547cSRui Paulo eap->getSessionId = eap_ttls_get_session_id; 189639beb93cSSam Leffler eap->get_status = eap_ttls_get_status; 189739beb93cSSam Leffler eap->has_reauth_data = eap_ttls_has_reauth_data; 189839beb93cSSam Leffler eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; 189939beb93cSSam Leffler eap->init_for_reauth = eap_ttls_init_for_reauth; 19005b9c547cSRui Paulo eap->get_emsk = eap_ttls_get_emsk; 190139beb93cSSam Leffler 1902780fb4a2SCy Schubert return eap_peer_method_register(eap); 190339beb93cSSam Leffler } 1904