139beb93cSSam Leffler /* 239beb93cSSam Leffler * EAP peer method: EAP-TTLS (RFC 5281) 339beb93cSSam Leffler * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "includes.h" 1639beb93cSSam Leffler 1739beb93cSSam Leffler #include "common.h" 1839beb93cSSam Leffler #include "eap_peer/eap_i.h" 1939beb93cSSam Leffler #include "eap_peer/eap_tls_common.h" 2039beb93cSSam Leffler #include "eap_peer/eap_config.h" 2139beb93cSSam Leffler #include "ms_funcs.h" 2239beb93cSSam Leffler #include "sha1.h" 2339beb93cSSam Leffler #include "eap_common/chap.h" 2439beb93cSSam Leffler #include "tls.h" 2539beb93cSSam Leffler #include "mschapv2.h" 2639beb93cSSam Leffler #include "eap_common/eap_ttls.h" 2739beb93cSSam Leffler 2839beb93cSSam Leffler 2939beb93cSSam Leffler /* Maximum supported TTLS version 3039beb93cSSam Leffler * 0 = RFC 5281 3139beb93cSSam Leffler * 1 = draft-funk-eap-ttls-v1-00.txt 3239beb93cSSam Leffler */ 3339beb93cSSam Leffler #ifndef EAP_TTLS_VERSION 3439beb93cSSam Leffler #define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */ 3539beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 3639beb93cSSam Leffler 3739beb93cSSam Leffler 3839beb93cSSam Leffler #define MSCHAPV2_KEY_LEN 16 3939beb93cSSam Leffler #define MSCHAPV2_NT_RESPONSE_LEN 24 4039beb93cSSam Leffler 4139beb93cSSam Leffler 4239beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv); 4339beb93cSSam Leffler 4439beb93cSSam Leffler 4539beb93cSSam Leffler struct eap_ttls_data { 4639beb93cSSam Leffler struct eap_ssl_data ssl; 4739beb93cSSam Leffler int ssl_initialized; 4839beb93cSSam Leffler 4939beb93cSSam Leffler int ttls_version, force_ttls_version; 5039beb93cSSam Leffler 5139beb93cSSam Leffler const struct eap_method *phase2_method; 5239beb93cSSam Leffler void *phase2_priv; 5339beb93cSSam Leffler int phase2_success; 5439beb93cSSam Leffler int phase2_start; 5539beb93cSSam Leffler 5639beb93cSSam Leffler enum phase2_types { 5739beb93cSSam Leffler EAP_TTLS_PHASE2_EAP, 5839beb93cSSam Leffler EAP_TTLS_PHASE2_MSCHAPV2, 5939beb93cSSam Leffler EAP_TTLS_PHASE2_MSCHAP, 6039beb93cSSam Leffler EAP_TTLS_PHASE2_PAP, 6139beb93cSSam Leffler EAP_TTLS_PHASE2_CHAP 6239beb93cSSam Leffler } phase2_type; 6339beb93cSSam Leffler struct eap_method_type phase2_eap_type; 6439beb93cSSam Leffler struct eap_method_type *phase2_eap_types; 6539beb93cSSam Leffler size_t num_phase2_eap_types; 6639beb93cSSam Leffler 6739beb93cSSam Leffler u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; 6839beb93cSSam Leffler int auth_response_valid; 6939beb93cSSam Leffler u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ 7039beb93cSSam Leffler u8 ident; 7139beb93cSSam Leffler int resuming; /* starting a resumed session */ 7239beb93cSSam Leffler int reauth; /* reauthentication */ 7339beb93cSSam Leffler u8 *key_data; 7439beb93cSSam Leffler 7539beb93cSSam Leffler struct wpabuf *pending_phase2_req; 7639beb93cSSam Leffler 7739beb93cSSam Leffler #ifdef EAP_TNC 7839beb93cSSam Leffler int ready_for_tnc; 7939beb93cSSam Leffler int tnc_started; 8039beb93cSSam Leffler #endif /* EAP_TNC */ 8139beb93cSSam Leffler }; 8239beb93cSSam Leffler 8339beb93cSSam Leffler 8439beb93cSSam Leffler static void * eap_ttls_init(struct eap_sm *sm) 8539beb93cSSam Leffler { 8639beb93cSSam Leffler struct eap_ttls_data *data; 8739beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 8839beb93cSSam Leffler char *selected; 8939beb93cSSam Leffler 9039beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 9139beb93cSSam Leffler if (data == NULL) 9239beb93cSSam Leffler return NULL; 9339beb93cSSam Leffler data->ttls_version = EAP_TTLS_VERSION; 9439beb93cSSam Leffler data->force_ttls_version = -1; 9539beb93cSSam Leffler selected = "EAP"; 9639beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_EAP; 9739beb93cSSam Leffler 9839beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 9939beb93cSSam Leffler if (config && config->phase1) { 10039beb93cSSam Leffler const char *pos = os_strstr(config->phase1, "ttlsver="); 10139beb93cSSam Leffler if (pos) { 10239beb93cSSam Leffler data->force_ttls_version = atoi(pos + 8); 10339beb93cSSam Leffler data->ttls_version = data->force_ttls_version; 10439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version " 10539beb93cSSam Leffler "%d", data->force_ttls_version); 10639beb93cSSam Leffler } 10739beb93cSSam Leffler } 10839beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 10939beb93cSSam Leffler 11039beb93cSSam Leffler if (config && config->phase2) { 11139beb93cSSam Leffler if (os_strstr(config->phase2, "autheap=")) { 11239beb93cSSam Leffler selected = "EAP"; 11339beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_EAP; 11439beb93cSSam Leffler } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { 11539beb93cSSam Leffler selected = "MSCHAPV2"; 11639beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; 11739beb93cSSam Leffler } else if (os_strstr(config->phase2, "auth=MSCHAP")) { 11839beb93cSSam Leffler selected = "MSCHAP"; 11939beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; 12039beb93cSSam Leffler } else if (os_strstr(config->phase2, "auth=PAP")) { 12139beb93cSSam Leffler selected = "PAP"; 12239beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_PAP; 12339beb93cSSam Leffler } else if (os_strstr(config->phase2, "auth=CHAP")) { 12439beb93cSSam Leffler selected = "CHAP"; 12539beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_CHAP; 12639beb93cSSam Leffler } 12739beb93cSSam Leffler } 12839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); 12939beb93cSSam Leffler 13039beb93cSSam Leffler if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { 13139beb93cSSam Leffler if (eap_peer_select_phase2_methods(config, "autheap=", 13239beb93cSSam Leffler &data->phase2_eap_types, 13339beb93cSSam Leffler &data->num_phase2_eap_types) 13439beb93cSSam Leffler < 0) { 13539beb93cSSam Leffler eap_ttls_deinit(sm, data); 13639beb93cSSam Leffler return NULL; 13739beb93cSSam Leffler } 13839beb93cSSam Leffler 13939beb93cSSam Leffler data->phase2_eap_type.vendor = EAP_VENDOR_IETF; 14039beb93cSSam Leffler data->phase2_eap_type.method = EAP_TYPE_NONE; 14139beb93cSSam Leffler } 14239beb93cSSam Leffler 14339beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 14439beb93cSSam Leffler if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && 14539beb93cSSam Leffler data->ttls_version > 0) { 14639beb93cSSam Leffler if (data->force_ttls_version > 0) { 14739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " 14839beb93cSSam Leffler "TLS library does not support TLS/IA.", 14939beb93cSSam Leffler data->force_ttls_version); 15039beb93cSSam Leffler eap_ttls_deinit(sm, data); 15139beb93cSSam Leffler return NULL; 15239beb93cSSam Leffler } 15339beb93cSSam Leffler data->ttls_version = 0; 15439beb93cSSam Leffler } 15539beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 15639beb93cSSam Leffler 15739beb93cSSam Leffler return data; 15839beb93cSSam Leffler } 15939beb93cSSam Leffler 16039beb93cSSam Leffler 16139beb93cSSam Leffler static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, 16239beb93cSSam Leffler struct eap_ttls_data *data) 16339beb93cSSam Leffler { 16439beb93cSSam Leffler if (data->phase2_priv && data->phase2_method) { 16539beb93cSSam Leffler data->phase2_method->deinit(sm, data->phase2_priv); 16639beb93cSSam Leffler data->phase2_method = NULL; 16739beb93cSSam Leffler data->phase2_priv = NULL; 16839beb93cSSam Leffler } 16939beb93cSSam Leffler } 17039beb93cSSam Leffler 17139beb93cSSam Leffler 17239beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv) 17339beb93cSSam Leffler { 17439beb93cSSam Leffler struct eap_ttls_data *data = priv; 17539beb93cSSam Leffler if (data == NULL) 17639beb93cSSam Leffler return; 17739beb93cSSam Leffler eap_ttls_phase2_eap_deinit(sm, data); 17839beb93cSSam Leffler os_free(data->phase2_eap_types); 17939beb93cSSam Leffler if (data->ssl_initialized) 18039beb93cSSam Leffler eap_peer_tls_ssl_deinit(sm, &data->ssl); 18139beb93cSSam Leffler os_free(data->key_data); 18239beb93cSSam Leffler wpabuf_free(data->pending_phase2_req); 18339beb93cSSam Leffler os_free(data); 18439beb93cSSam Leffler } 18539beb93cSSam Leffler 18639beb93cSSam Leffler 18739beb93cSSam Leffler static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, 18839beb93cSSam Leffler int mandatory, size_t len) 18939beb93cSSam Leffler { 19039beb93cSSam Leffler struct ttls_avp_vendor *avp; 19139beb93cSSam Leffler u8 flags; 19239beb93cSSam Leffler size_t hdrlen; 19339beb93cSSam Leffler 19439beb93cSSam Leffler avp = (struct ttls_avp_vendor *) avphdr; 19539beb93cSSam Leffler flags = mandatory ? AVP_FLAGS_MANDATORY : 0; 19639beb93cSSam Leffler if (vendor_id) { 19739beb93cSSam Leffler flags |= AVP_FLAGS_VENDOR; 19839beb93cSSam Leffler hdrlen = sizeof(*avp); 19939beb93cSSam Leffler avp->vendor_id = host_to_be32(vendor_id); 20039beb93cSSam Leffler } else { 20139beb93cSSam Leffler hdrlen = sizeof(struct ttls_avp); 20239beb93cSSam Leffler } 20339beb93cSSam Leffler 20439beb93cSSam Leffler avp->avp_code = host_to_be32(avp_code); 20539beb93cSSam Leffler avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len)); 20639beb93cSSam Leffler 20739beb93cSSam Leffler return avphdr + hdrlen; 20839beb93cSSam Leffler } 20939beb93cSSam Leffler 21039beb93cSSam Leffler 21139beb93cSSam Leffler static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, 21239beb93cSSam Leffler u32 vendor_id, int mandatory, 21339beb93cSSam Leffler const u8 *data, size_t len) 21439beb93cSSam Leffler { 21539beb93cSSam Leffler u8 *pos; 21639beb93cSSam Leffler pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); 21739beb93cSSam Leffler os_memcpy(pos, data, len); 21839beb93cSSam Leffler pos += len; 21939beb93cSSam Leffler AVP_PAD(start, pos); 22039beb93cSSam Leffler return pos; 22139beb93cSSam Leffler } 22239beb93cSSam Leffler 22339beb93cSSam Leffler 22439beb93cSSam Leffler static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, 22539beb93cSSam Leffler int mandatory) 22639beb93cSSam Leffler { 22739beb93cSSam Leffler struct wpabuf *msg; 22839beb93cSSam Leffler u8 *avp, *pos; 22939beb93cSSam Leffler 23039beb93cSSam Leffler msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); 23139beb93cSSam Leffler if (msg == NULL) { 23239beb93cSSam Leffler wpabuf_free(*resp); 23339beb93cSSam Leffler *resp = NULL; 23439beb93cSSam Leffler return -1; 23539beb93cSSam Leffler } 23639beb93cSSam Leffler 23739beb93cSSam Leffler avp = wpabuf_mhead(msg); 23839beb93cSSam Leffler pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); 23939beb93cSSam Leffler os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); 24039beb93cSSam Leffler pos += wpabuf_len(*resp); 24139beb93cSSam Leffler AVP_PAD(avp, pos); 24239beb93cSSam Leffler wpabuf_free(*resp); 24339beb93cSSam Leffler wpabuf_put(msg, pos - avp); 24439beb93cSSam Leffler *resp = msg; 24539beb93cSSam Leffler return 0; 24639beb93cSSam Leffler } 24739beb93cSSam Leffler 24839beb93cSSam Leffler 24939beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 25039beb93cSSam Leffler static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, 25139beb93cSSam Leffler struct eap_ttls_data *data, 25239beb93cSSam Leffler const u8 *key, size_t key_len) 25339beb93cSSam Leffler { 25439beb93cSSam Leffler u8 *buf; 25539beb93cSSam Leffler size_t buf_len; 25639beb93cSSam Leffler int ret; 25739beb93cSSam Leffler 25839beb93cSSam Leffler if (key) { 25939beb93cSSam Leffler buf_len = 2 + key_len; 26039beb93cSSam Leffler buf = os_malloc(buf_len); 26139beb93cSSam Leffler if (buf == NULL) 26239beb93cSSam Leffler return -1; 26339beb93cSSam Leffler WPA_PUT_BE16(buf, key_len); 26439beb93cSSam Leffler os_memcpy(buf + 2, key, key_len); 26539beb93cSSam Leffler } else { 26639beb93cSSam Leffler buf = NULL; 26739beb93cSSam Leffler buf_len = 0; 26839beb93cSSam Leffler } 26939beb93cSSam Leffler 27039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner " 27139beb93cSSam Leffler "secret permutation", buf, buf_len); 27239beb93cSSam Leffler ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx, 27339beb93cSSam Leffler data->ssl.conn, 27439beb93cSSam Leffler buf, buf_len); 27539beb93cSSam Leffler os_free(buf); 27639beb93cSSam Leffler 27739beb93cSSam Leffler return ret; 27839beb93cSSam Leffler } 27939beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 28039beb93cSSam Leffler 28139beb93cSSam Leffler 28239beb93cSSam Leffler static int eap_ttls_v0_derive_key(struct eap_sm *sm, 28339beb93cSSam Leffler struct eap_ttls_data *data) 28439beb93cSSam Leffler { 28539beb93cSSam Leffler os_free(data->key_data); 28639beb93cSSam Leffler data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, 28739beb93cSSam Leffler "ttls keying material", 28839beb93cSSam Leffler EAP_TLS_KEY_LEN); 28939beb93cSSam Leffler if (!data->key_data) { 29039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); 29139beb93cSSam Leffler return -1; 29239beb93cSSam Leffler } 29339beb93cSSam Leffler 29439beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", 29539beb93cSSam Leffler data->key_data, EAP_TLS_KEY_LEN); 29639beb93cSSam Leffler 29739beb93cSSam Leffler return 0; 29839beb93cSSam Leffler } 29939beb93cSSam Leffler 30039beb93cSSam Leffler 30139beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 30239beb93cSSam Leffler static int eap_ttls_v1_derive_key(struct eap_sm *sm, 30339beb93cSSam Leffler struct eap_ttls_data *data) 30439beb93cSSam Leffler { 30539beb93cSSam Leffler struct tls_keys keys; 30639beb93cSSam Leffler u8 *rnd; 30739beb93cSSam Leffler 30839beb93cSSam Leffler os_free(data->key_data); 30939beb93cSSam Leffler data->key_data = NULL; 31039beb93cSSam Leffler 31139beb93cSSam Leffler os_memset(&keys, 0, sizeof(keys)); 31239beb93cSSam Leffler if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || 31339beb93cSSam Leffler keys.client_random == NULL || keys.server_random == NULL || 31439beb93cSSam Leffler keys.inner_secret == NULL) { 31539beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " 31639beb93cSSam Leffler "client random, or server random to derive keying " 31739beb93cSSam Leffler "material"); 31839beb93cSSam Leffler return -1; 31939beb93cSSam Leffler } 32039beb93cSSam Leffler 32139beb93cSSam Leffler rnd = os_malloc(keys.client_random_len + keys.server_random_len); 32239beb93cSSam Leffler data->key_data = os_malloc(EAP_TLS_KEY_LEN); 32339beb93cSSam Leffler if (rnd == NULL || data->key_data == NULL) { 32439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); 32539beb93cSSam Leffler os_free(rnd); 32639beb93cSSam Leffler os_free(data->key_data); 32739beb93cSSam Leffler data->key_data = NULL; 32839beb93cSSam Leffler return -1; 32939beb93cSSam Leffler } 33039beb93cSSam Leffler os_memcpy(rnd, keys.client_random, keys.client_random_len); 33139beb93cSSam Leffler os_memcpy(rnd + keys.client_random_len, keys.server_random, 33239beb93cSSam Leffler keys.server_random_len); 33339beb93cSSam Leffler 33439beb93cSSam Leffler if (tls_prf(keys.inner_secret, keys.inner_secret_len, 33539beb93cSSam Leffler "ttls v1 keying material", rnd, keys.client_random_len + 33639beb93cSSam Leffler keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) { 33739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); 33839beb93cSSam Leffler os_free(rnd); 33939beb93cSSam Leffler os_free(data->key_data); 34039beb93cSSam Leffler data->key_data = NULL; 34139beb93cSSam Leffler return -1; 34239beb93cSSam Leffler } 34339beb93cSSam Leffler 34439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", 34539beb93cSSam Leffler rnd, keys.client_random_len + keys.server_random_len); 34639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", 34739beb93cSSam Leffler keys.inner_secret, keys.inner_secret_len); 34839beb93cSSam Leffler 34939beb93cSSam Leffler os_free(rnd); 35039beb93cSSam Leffler 35139beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", 35239beb93cSSam Leffler data->key_data, EAP_TLS_KEY_LEN); 35339beb93cSSam Leffler 35439beb93cSSam Leffler return 0; 35539beb93cSSam Leffler } 35639beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 35739beb93cSSam Leffler 35839beb93cSSam Leffler 35939beb93cSSam Leffler static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, 36039beb93cSSam Leffler struct eap_ttls_data *data, size_t len) 36139beb93cSSam Leffler { 36239beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 36339beb93cSSam Leffler struct tls_keys keys; 36439beb93cSSam Leffler u8 *challenge, *rnd; 36539beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 36639beb93cSSam Leffler 36739beb93cSSam Leffler if (data->ttls_version == 0) { 36839beb93cSSam Leffler return eap_peer_tls_derive_key(sm, &data->ssl, 36939beb93cSSam Leffler "ttls challenge", len); 37039beb93cSSam Leffler } 37139beb93cSSam Leffler 37239beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 37339beb93cSSam Leffler 37439beb93cSSam Leffler os_memset(&keys, 0, sizeof(keys)); 37539beb93cSSam Leffler if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || 37639beb93cSSam Leffler keys.client_random == NULL || keys.server_random == NULL || 37739beb93cSSam Leffler keys.inner_secret == NULL) { 37839beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " 37939beb93cSSam Leffler "client random, or server random to derive " 38039beb93cSSam Leffler "implicit challenge"); 38139beb93cSSam Leffler return NULL; 38239beb93cSSam Leffler } 38339beb93cSSam Leffler 38439beb93cSSam Leffler rnd = os_malloc(keys.client_random_len + keys.server_random_len); 38539beb93cSSam Leffler challenge = os_malloc(len); 38639beb93cSSam Leffler if (rnd == NULL || challenge == NULL) { 38739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " 38839beb93cSSam Leffler "challenge derivation"); 38939beb93cSSam Leffler os_free(rnd); 39039beb93cSSam Leffler os_free(challenge); 39139beb93cSSam Leffler return NULL; 39239beb93cSSam Leffler } 39339beb93cSSam Leffler os_memcpy(rnd, keys.server_random, keys.server_random_len); 39439beb93cSSam Leffler os_memcpy(rnd + keys.server_random_len, keys.client_random, 39539beb93cSSam Leffler keys.client_random_len); 39639beb93cSSam Leffler 39739beb93cSSam Leffler if (tls_prf(keys.inner_secret, keys.inner_secret_len, 39839beb93cSSam Leffler "inner application challenge", rnd, 39939beb93cSSam Leffler keys.client_random_len + keys.server_random_len, 40039beb93cSSam Leffler challenge, len)) { 40139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " 40239beb93cSSam Leffler "challenge"); 40339beb93cSSam Leffler os_free(rnd); 40439beb93cSSam Leffler os_free(challenge); 40539beb93cSSam Leffler return NULL; 40639beb93cSSam Leffler } 40739beb93cSSam Leffler 40839beb93cSSam Leffler os_free(rnd); 40939beb93cSSam Leffler 41039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", 41139beb93cSSam Leffler challenge, len); 41239beb93cSSam Leffler 41339beb93cSSam Leffler return challenge; 41439beb93cSSam Leffler 41539beb93cSSam Leffler #else /* EAP_TTLS_VERSION */ 41639beb93cSSam Leffler 41739beb93cSSam Leffler return NULL; 41839beb93cSSam Leffler 41939beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 42039beb93cSSam Leffler } 42139beb93cSSam Leffler 42239beb93cSSam Leffler 42339beb93cSSam Leffler static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm, 42439beb93cSSam Leffler struct eap_ttls_data *data, 42539beb93cSSam Leffler struct eap_method_ret *ret) 42639beb93cSSam Leffler { 42739beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 42839beb93cSSam Leffler if (data->ttls_version > 0) { 42939beb93cSSam Leffler const struct eap_method *m = data->phase2_method; 43039beb93cSSam Leffler void *priv = data->phase2_priv; 43139beb93cSSam Leffler 43239beb93cSSam Leffler /* TTLSv1 requires TLS/IA FinalPhaseFinished */ 43339beb93cSSam Leffler if (ret->decision == DECISION_UNCOND_SUCC) 43439beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 43539beb93cSSam Leffler ret->methodState = METHOD_CONT; 43639beb93cSSam Leffler 43739beb93cSSam Leffler if (ret->decision == DECISION_COND_SUCC && 43839beb93cSSam Leffler m->isKeyAvailable && m->getKey && 43939beb93cSSam Leffler m->isKeyAvailable(sm, priv)) { 44039beb93cSSam Leffler u8 *key; 44139beb93cSSam Leffler size_t key_len; 44239beb93cSSam Leffler key = m->getKey(sm, priv, &key_len); 44339beb93cSSam Leffler if (key) { 44439beb93cSSam Leffler eap_ttls_ia_permute_inner_secret( 44539beb93cSSam Leffler sm, data, key, key_len); 44639beb93cSSam Leffler os_free(key); 44739beb93cSSam Leffler } 44839beb93cSSam Leffler } 44939beb93cSSam Leffler } 45039beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 45139beb93cSSam Leffler } 45239beb93cSSam Leffler 45339beb93cSSam Leffler 45439beb93cSSam Leffler static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, 45539beb93cSSam Leffler u8 method) 45639beb93cSSam Leffler { 45739beb93cSSam Leffler size_t i; 45839beb93cSSam Leffler for (i = 0; i < data->num_phase2_eap_types; i++) { 45939beb93cSSam Leffler if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || 46039beb93cSSam Leffler data->phase2_eap_types[i].method != method) 46139beb93cSSam Leffler continue; 46239beb93cSSam Leffler 46339beb93cSSam Leffler data->phase2_eap_type.vendor = 46439beb93cSSam Leffler data->phase2_eap_types[i].vendor; 46539beb93cSSam Leffler data->phase2_eap_type.method = 46639beb93cSSam Leffler data->phase2_eap_types[i].method; 46739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " 46839beb93cSSam Leffler "Phase 2 EAP vendor %d method %d", 46939beb93cSSam Leffler data->phase2_eap_type.vendor, 47039beb93cSSam Leffler data->phase2_eap_type.method); 47139beb93cSSam Leffler break; 47239beb93cSSam Leffler } 47339beb93cSSam Leffler } 47439beb93cSSam Leffler 47539beb93cSSam Leffler 47639beb93cSSam Leffler static int eap_ttls_phase2_eap_process(struct eap_sm *sm, 47739beb93cSSam Leffler struct eap_ttls_data *data, 47839beb93cSSam Leffler struct eap_method_ret *ret, 47939beb93cSSam Leffler struct eap_hdr *hdr, size_t len, 48039beb93cSSam Leffler struct wpabuf **resp) 48139beb93cSSam Leffler { 48239beb93cSSam Leffler struct wpabuf msg; 48339beb93cSSam Leffler struct eap_method_ret iret; 48439beb93cSSam Leffler 48539beb93cSSam Leffler os_memset(&iret, 0, sizeof(iret)); 48639beb93cSSam Leffler wpabuf_set(&msg, hdr, len); 48739beb93cSSam Leffler *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, 48839beb93cSSam Leffler &msg); 48939beb93cSSam Leffler if ((iret.methodState == METHOD_DONE || 49039beb93cSSam Leffler iret.methodState == METHOD_MAY_CONT) && 49139beb93cSSam Leffler (iret.decision == DECISION_UNCOND_SUCC || 49239beb93cSSam Leffler iret.decision == DECISION_COND_SUCC || 49339beb93cSSam Leffler iret.decision == DECISION_FAIL)) { 49439beb93cSSam Leffler ret->methodState = iret.methodState; 49539beb93cSSam Leffler ret->decision = iret.decision; 49639beb93cSSam Leffler } 49739beb93cSSam Leffler eap_ttlsv1_phase2_eap_finish(sm, data, ret); 49839beb93cSSam Leffler 49939beb93cSSam Leffler return 0; 50039beb93cSSam Leffler } 50139beb93cSSam Leffler 50239beb93cSSam Leffler 50339beb93cSSam Leffler static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, 50439beb93cSSam Leffler struct eap_ttls_data *data, 50539beb93cSSam Leffler struct eap_method_ret *ret, 50639beb93cSSam Leffler struct eap_hdr *hdr, size_t len, 50739beb93cSSam Leffler u8 method, struct wpabuf **resp) 50839beb93cSSam Leffler { 50939beb93cSSam Leffler #ifdef EAP_TNC 51039beb93cSSam Leffler if (data->tnc_started && data->phase2_method && 51139beb93cSSam Leffler data->phase2_priv && method == EAP_TYPE_TNC && 51239beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_TNC) 51339beb93cSSam Leffler return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, 51439beb93cSSam Leffler resp); 51539beb93cSSam Leffler 51639beb93cSSam Leffler if (data->ready_for_tnc && !data->tnc_started && 51739beb93cSSam Leffler method == EAP_TYPE_TNC) { 51839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " 51939beb93cSSam Leffler "EAP method"); 52039beb93cSSam Leffler data->tnc_started = 1; 52139beb93cSSam Leffler } 52239beb93cSSam Leffler 52339beb93cSSam Leffler if (data->tnc_started) { 52439beb93cSSam Leffler if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || 52539beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_TNC) { 52639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP " 52739beb93cSSam Leffler "type %d for TNC", method); 52839beb93cSSam Leffler return -1; 52939beb93cSSam Leffler } 53039beb93cSSam Leffler 53139beb93cSSam Leffler data->phase2_eap_type.vendor = EAP_VENDOR_IETF; 53239beb93cSSam Leffler data->phase2_eap_type.method = method; 53339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " 53439beb93cSSam Leffler "Phase 2 EAP vendor %d method %d (TNC)", 53539beb93cSSam Leffler data->phase2_eap_type.vendor, 53639beb93cSSam Leffler data->phase2_eap_type.method); 53739beb93cSSam Leffler 53839beb93cSSam Leffler if (data->phase2_type == EAP_TTLS_PHASE2_EAP) 53939beb93cSSam Leffler eap_ttls_phase2_eap_deinit(sm, data); 54039beb93cSSam Leffler } 54139beb93cSSam Leffler #endif /* EAP_TNC */ 54239beb93cSSam Leffler 54339beb93cSSam Leffler if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && 54439beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_NONE) 54539beb93cSSam Leffler eap_ttls_phase2_select_eap_method(data, method); 54639beb93cSSam Leffler 54739beb93cSSam Leffler if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) 54839beb93cSSam Leffler { 54939beb93cSSam Leffler if (eap_peer_tls_phase2_nak(data->phase2_eap_types, 55039beb93cSSam Leffler data->num_phase2_eap_types, 55139beb93cSSam Leffler hdr, resp)) 55239beb93cSSam Leffler return -1; 55339beb93cSSam Leffler return 0; 55439beb93cSSam Leffler } 55539beb93cSSam Leffler 55639beb93cSSam Leffler if (data->phase2_priv == NULL) { 55739beb93cSSam Leffler data->phase2_method = eap_peer_get_eap_method( 55839beb93cSSam Leffler EAP_VENDOR_IETF, method); 55939beb93cSSam Leffler if (data->phase2_method) { 56039beb93cSSam Leffler sm->init_phase2 = 1; 56139beb93cSSam Leffler data->phase2_priv = data->phase2_method->init(sm); 56239beb93cSSam Leffler sm->init_phase2 = 0; 56339beb93cSSam Leffler } 56439beb93cSSam Leffler } 56539beb93cSSam Leffler if (data->phase2_priv == NULL || data->phase2_method == NULL) { 56639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " 56739beb93cSSam Leffler "Phase 2 EAP method %d", method); 56839beb93cSSam Leffler return -1; 56939beb93cSSam Leffler } 57039beb93cSSam Leffler 57139beb93cSSam Leffler return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); 57239beb93cSSam Leffler } 57339beb93cSSam Leffler 57439beb93cSSam Leffler 57539beb93cSSam Leffler static int eap_ttls_phase2_request_eap(struct eap_sm *sm, 57639beb93cSSam Leffler struct eap_ttls_data *data, 57739beb93cSSam Leffler struct eap_method_ret *ret, 57839beb93cSSam Leffler struct eap_hdr *hdr, 57939beb93cSSam Leffler struct wpabuf **resp) 58039beb93cSSam Leffler { 58139beb93cSSam Leffler size_t len = be_to_host16(hdr->length); 58239beb93cSSam Leffler u8 *pos; 58339beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 58439beb93cSSam Leffler 58539beb93cSSam Leffler if (len <= sizeof(struct eap_hdr)) { 58639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: too short " 58739beb93cSSam Leffler "Phase 2 request (len=%lu)", (unsigned long) len); 58839beb93cSSam Leffler return -1; 58939beb93cSSam Leffler } 59039beb93cSSam Leffler pos = (u8 *) (hdr + 1); 59139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); 59239beb93cSSam Leffler switch (*pos) { 59339beb93cSSam Leffler case EAP_TYPE_IDENTITY: 59439beb93cSSam Leffler *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); 59539beb93cSSam Leffler break; 59639beb93cSSam Leffler default: 59739beb93cSSam Leffler if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, 59839beb93cSSam Leffler *pos, resp) < 0) 59939beb93cSSam Leffler return -1; 60039beb93cSSam Leffler break; 60139beb93cSSam Leffler } 60239beb93cSSam Leffler 60339beb93cSSam Leffler if (*resp == NULL && 60439beb93cSSam Leffler (config->pending_req_identity || config->pending_req_password || 60539beb93cSSam Leffler config->pending_req_otp)) { 60639beb93cSSam Leffler return 0; 60739beb93cSSam Leffler } 60839beb93cSSam Leffler 60939beb93cSSam Leffler if (*resp == NULL) 61039beb93cSSam Leffler return -1; 61139beb93cSSam Leffler 61239beb93cSSam Leffler wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", 61339beb93cSSam Leffler *resp); 61439beb93cSSam Leffler return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); 61539beb93cSSam Leffler } 61639beb93cSSam Leffler 61739beb93cSSam Leffler 61839beb93cSSam Leffler static void eap_ttlsv1_permute_inner(struct eap_sm *sm, 61939beb93cSSam Leffler struct eap_ttls_data *data) 62039beb93cSSam Leffler { 62139beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 62239beb93cSSam Leffler u8 session_key[2 * MSCHAPV2_KEY_LEN]; 62339beb93cSSam Leffler 62439beb93cSSam Leffler if (data->ttls_version == 0) 62539beb93cSSam Leffler return; 62639beb93cSSam Leffler 62739beb93cSSam Leffler get_asymetric_start_key(data->master_key, session_key, 62839beb93cSSam Leffler MSCHAPV2_KEY_LEN, 0, 0); 62939beb93cSSam Leffler get_asymetric_start_key(data->master_key, 63039beb93cSSam Leffler session_key + MSCHAPV2_KEY_LEN, 63139beb93cSSam Leffler MSCHAPV2_KEY_LEN, 1, 0); 63239beb93cSSam Leffler eap_ttls_ia_permute_inner_secret(sm, data, session_key, 63339beb93cSSam Leffler sizeof(session_key)); 63439beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 63539beb93cSSam Leffler } 63639beb93cSSam Leffler 63739beb93cSSam Leffler 63839beb93cSSam Leffler static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, 63939beb93cSSam Leffler struct eap_ttls_data *data, 64039beb93cSSam Leffler struct eap_method_ret *ret, 64139beb93cSSam Leffler struct wpabuf **resp) 64239beb93cSSam Leffler { 64339beb93cSSam Leffler struct wpabuf *msg; 64439beb93cSSam Leffler u8 *buf, *pos, *challenge, *peer_challenge; 64539beb93cSSam Leffler const u8 *identity, *password; 64639beb93cSSam Leffler size_t identity_len, password_len; 64739beb93cSSam Leffler int pwhash; 64839beb93cSSam Leffler 64939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); 65039beb93cSSam Leffler 65139beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 65239beb93cSSam Leffler password = eap_get_config_password2(sm, &password_len, &pwhash); 65339beb93cSSam Leffler if (identity == NULL || password == NULL) 65439beb93cSSam Leffler return -1; 65539beb93cSSam Leffler 65639beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 65739beb93cSSam Leffler if (msg == NULL) { 65839beb93cSSam Leffler wpa_printf(MSG_ERROR, 65939beb93cSSam Leffler "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); 66039beb93cSSam Leffler return -1; 66139beb93cSSam Leffler } 66239beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 66339beb93cSSam Leffler 66439beb93cSSam Leffler /* User-Name */ 66539beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 66639beb93cSSam Leffler identity, identity_len); 66739beb93cSSam Leffler 66839beb93cSSam Leffler /* MS-CHAP-Challenge */ 66939beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 67039beb93cSSam Leffler sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); 67139beb93cSSam Leffler if (challenge == NULL) { 67239beb93cSSam Leffler wpabuf_free(msg); 67339beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " 67439beb93cSSam Leffler "implicit challenge"); 67539beb93cSSam Leffler return -1; 67639beb93cSSam Leffler } 67739beb93cSSam Leffler peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; 67839beb93cSSam Leffler 67939beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, 68039beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 68139beb93cSSam Leffler challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); 68239beb93cSSam Leffler 68339beb93cSSam Leffler /* MS-CHAP2-Response */ 68439beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, 68539beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 68639beb93cSSam Leffler EAP_TTLS_MSCHAPV2_RESPONSE_LEN); 68739beb93cSSam Leffler data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; 68839beb93cSSam Leffler *pos++ = data->ident; 68939beb93cSSam Leffler *pos++ = 0; /* Flags */ 69039beb93cSSam Leffler os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); 69139beb93cSSam Leffler pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; 69239beb93cSSam Leffler os_memset(pos, 0, 8); /* Reserved, must be zero */ 69339beb93cSSam Leffler pos += 8; 69439beb93cSSam Leffler mschapv2_derive_response(identity, identity_len, password, 69539beb93cSSam Leffler password_len, pwhash, challenge, 69639beb93cSSam Leffler peer_challenge, pos, data->auth_response, 69739beb93cSSam Leffler data->master_key); 69839beb93cSSam Leffler data->auth_response_valid = 1; 69939beb93cSSam Leffler 70039beb93cSSam Leffler eap_ttlsv1_permute_inner(sm, data); 70139beb93cSSam Leffler 70239beb93cSSam Leffler pos += 24; 70339beb93cSSam Leffler os_free(challenge); 70439beb93cSSam Leffler AVP_PAD(buf, pos); 70539beb93cSSam Leffler 70639beb93cSSam Leffler wpabuf_put(msg, pos - buf); 70739beb93cSSam Leffler *resp = msg; 70839beb93cSSam Leffler 70939beb93cSSam Leffler if (sm->workaround && data->ttls_version == 0) { 71039beb93cSSam Leffler /* At least FreeRADIUS seems to be terminating 71139beb93cSSam Leffler * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success 71239beb93cSSam Leffler * packet. */ 71339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - " 71439beb93cSSam Leffler "allow success without tunneled response"); 71539beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 71639beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 71739beb93cSSam Leffler } 71839beb93cSSam Leffler 71939beb93cSSam Leffler return 0; 72039beb93cSSam Leffler } 72139beb93cSSam Leffler 72239beb93cSSam Leffler 72339beb93cSSam Leffler static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, 72439beb93cSSam Leffler struct eap_ttls_data *data, 72539beb93cSSam Leffler struct eap_method_ret *ret, 72639beb93cSSam Leffler struct wpabuf **resp) 72739beb93cSSam Leffler { 72839beb93cSSam Leffler struct wpabuf *msg; 72939beb93cSSam Leffler u8 *buf, *pos, *challenge; 73039beb93cSSam Leffler const u8 *identity, *password; 73139beb93cSSam Leffler size_t identity_len, password_len; 73239beb93cSSam Leffler int pwhash; 73339beb93cSSam Leffler 73439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); 73539beb93cSSam Leffler 73639beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 73739beb93cSSam Leffler password = eap_get_config_password2(sm, &password_len, &pwhash); 73839beb93cSSam Leffler if (identity == NULL || password == NULL) 73939beb93cSSam Leffler return -1; 74039beb93cSSam Leffler 74139beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 74239beb93cSSam Leffler if (msg == NULL) { 74339beb93cSSam Leffler wpa_printf(MSG_ERROR, 74439beb93cSSam Leffler "EAP-TTLS/MSCHAP: Failed to allocate memory"); 74539beb93cSSam Leffler return -1; 74639beb93cSSam Leffler } 74739beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 74839beb93cSSam Leffler 74939beb93cSSam Leffler /* User-Name */ 75039beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 75139beb93cSSam Leffler identity, identity_len); 75239beb93cSSam Leffler 75339beb93cSSam Leffler /* MS-CHAP-Challenge */ 75439beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 75539beb93cSSam Leffler sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); 75639beb93cSSam Leffler if (challenge == NULL) { 75739beb93cSSam Leffler wpabuf_free(msg); 75839beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " 75939beb93cSSam Leffler "implicit challenge"); 76039beb93cSSam Leffler return -1; 76139beb93cSSam Leffler } 76239beb93cSSam Leffler 76339beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, 76439beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 76539beb93cSSam Leffler challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); 76639beb93cSSam Leffler 76739beb93cSSam Leffler /* MS-CHAP-Response */ 76839beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, 76939beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 77039beb93cSSam Leffler EAP_TTLS_MSCHAP_RESPONSE_LEN); 77139beb93cSSam Leffler data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; 77239beb93cSSam Leffler *pos++ = data->ident; 77339beb93cSSam Leffler *pos++ = 1; /* Flags: Use NT style passwords */ 77439beb93cSSam Leffler os_memset(pos, 0, 24); /* LM-Response */ 77539beb93cSSam Leffler pos += 24; 77639beb93cSSam Leffler if (pwhash) { 77739beb93cSSam Leffler challenge_response(challenge, password, pos); /* NT-Response */ 77839beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", 77939beb93cSSam Leffler password, 16); 78039beb93cSSam Leffler } else { 78139beb93cSSam Leffler nt_challenge_response(challenge, password, password_len, 78239beb93cSSam Leffler pos); /* NT-Response */ 78339beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", 78439beb93cSSam Leffler password, password_len); 78539beb93cSSam Leffler } 78639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", 78739beb93cSSam Leffler challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); 78839beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); 78939beb93cSSam Leffler pos += 24; 79039beb93cSSam Leffler os_free(challenge); 79139beb93cSSam Leffler AVP_PAD(buf, pos); 79239beb93cSSam Leffler 79339beb93cSSam Leffler wpabuf_put(msg, pos - buf); 79439beb93cSSam Leffler *resp = msg; 79539beb93cSSam Leffler 79639beb93cSSam Leffler if (data->ttls_version > 0) { 79739beb93cSSam Leffler /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, 79839beb93cSSam Leffler * so do not allow connection to be terminated yet. */ 79939beb93cSSam Leffler ret->methodState = METHOD_CONT; 80039beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 80139beb93cSSam Leffler } else { 80239beb93cSSam Leffler /* EAP-TTLS/MSCHAP does not provide tunneled success 80339beb93cSSam Leffler * notification, so assume that Phase2 succeeds. */ 80439beb93cSSam Leffler ret->methodState = METHOD_DONE; 80539beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 80639beb93cSSam Leffler } 80739beb93cSSam Leffler 80839beb93cSSam Leffler return 0; 80939beb93cSSam Leffler } 81039beb93cSSam Leffler 81139beb93cSSam Leffler 81239beb93cSSam Leffler static int eap_ttls_phase2_request_pap(struct eap_sm *sm, 81339beb93cSSam Leffler struct eap_ttls_data *data, 81439beb93cSSam Leffler struct eap_method_ret *ret, 81539beb93cSSam Leffler struct wpabuf **resp) 81639beb93cSSam Leffler { 81739beb93cSSam Leffler struct wpabuf *msg; 81839beb93cSSam Leffler u8 *buf, *pos; 81939beb93cSSam Leffler size_t pad; 82039beb93cSSam Leffler const u8 *identity, *password; 82139beb93cSSam Leffler size_t identity_len, password_len; 82239beb93cSSam Leffler 82339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); 82439beb93cSSam Leffler 82539beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 82639beb93cSSam Leffler password = eap_get_config_password(sm, &password_len); 82739beb93cSSam Leffler if (identity == NULL || password == NULL) 82839beb93cSSam Leffler return -1; 82939beb93cSSam Leffler 83039beb93cSSam Leffler msg = wpabuf_alloc(identity_len + password_len + 100); 83139beb93cSSam Leffler if (msg == NULL) { 83239beb93cSSam Leffler wpa_printf(MSG_ERROR, 83339beb93cSSam Leffler "EAP-TTLS/PAP: Failed to allocate memory"); 83439beb93cSSam Leffler return -1; 83539beb93cSSam Leffler } 83639beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 83739beb93cSSam Leffler 83839beb93cSSam Leffler /* User-Name */ 83939beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 84039beb93cSSam Leffler identity, identity_len); 84139beb93cSSam Leffler 84239beb93cSSam Leffler /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts 84339beb93cSSam Leffler * the data, so no separate encryption is used in the AVP itself. 84439beb93cSSam Leffler * However, the password is padded to obfuscate its length. */ 84539beb93cSSam Leffler pad = (16 - (password_len & 15)) & 15; 84639beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, 84739beb93cSSam Leffler password_len + pad); 84839beb93cSSam Leffler os_memcpy(pos, password, password_len); 84939beb93cSSam Leffler pos += password_len; 85039beb93cSSam Leffler os_memset(pos, 0, pad); 85139beb93cSSam Leffler pos += pad; 85239beb93cSSam Leffler AVP_PAD(buf, pos); 85339beb93cSSam Leffler 85439beb93cSSam Leffler wpabuf_put(msg, pos - buf); 85539beb93cSSam Leffler *resp = msg; 85639beb93cSSam Leffler 85739beb93cSSam Leffler if (data->ttls_version > 0) { 85839beb93cSSam Leffler /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, 85939beb93cSSam Leffler * so do not allow connection to be terminated yet. */ 86039beb93cSSam Leffler ret->methodState = METHOD_CONT; 86139beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 86239beb93cSSam Leffler } else { 86339beb93cSSam Leffler /* EAP-TTLS/PAP does not provide tunneled success notification, 86439beb93cSSam Leffler * so assume that Phase2 succeeds. */ 86539beb93cSSam Leffler ret->methodState = METHOD_DONE; 86639beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 86739beb93cSSam Leffler } 86839beb93cSSam Leffler 86939beb93cSSam Leffler return 0; 87039beb93cSSam Leffler } 87139beb93cSSam Leffler 87239beb93cSSam Leffler 87339beb93cSSam Leffler static int eap_ttls_phase2_request_chap(struct eap_sm *sm, 87439beb93cSSam Leffler struct eap_ttls_data *data, 87539beb93cSSam Leffler struct eap_method_ret *ret, 87639beb93cSSam Leffler struct wpabuf **resp) 87739beb93cSSam Leffler { 87839beb93cSSam Leffler struct wpabuf *msg; 87939beb93cSSam Leffler u8 *buf, *pos, *challenge; 88039beb93cSSam Leffler const u8 *identity, *password; 88139beb93cSSam Leffler size_t identity_len, password_len; 88239beb93cSSam Leffler 88339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); 88439beb93cSSam Leffler 88539beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 88639beb93cSSam Leffler password = eap_get_config_password(sm, &password_len); 88739beb93cSSam Leffler if (identity == NULL || password == NULL) 88839beb93cSSam Leffler return -1; 88939beb93cSSam Leffler 89039beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 89139beb93cSSam Leffler if (msg == NULL) { 89239beb93cSSam Leffler wpa_printf(MSG_ERROR, 89339beb93cSSam Leffler "EAP-TTLS/CHAP: Failed to allocate memory"); 89439beb93cSSam Leffler return -1; 89539beb93cSSam Leffler } 89639beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 89739beb93cSSam Leffler 89839beb93cSSam Leffler /* User-Name */ 89939beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 90039beb93cSSam Leffler identity, identity_len); 90139beb93cSSam Leffler 90239beb93cSSam Leffler /* CHAP-Challenge */ 90339beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 90439beb93cSSam Leffler sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); 90539beb93cSSam Leffler if (challenge == NULL) { 90639beb93cSSam Leffler wpabuf_free(msg); 90739beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " 90839beb93cSSam Leffler "implicit challenge"); 90939beb93cSSam Leffler return -1; 91039beb93cSSam Leffler } 91139beb93cSSam Leffler 91239beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, 91339beb93cSSam Leffler challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); 91439beb93cSSam Leffler 91539beb93cSSam Leffler /* CHAP-Password */ 91639beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, 91739beb93cSSam Leffler 1 + EAP_TTLS_CHAP_PASSWORD_LEN); 91839beb93cSSam Leffler data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; 91939beb93cSSam Leffler *pos++ = data->ident; 92039beb93cSSam Leffler 92139beb93cSSam Leffler /* MD5(Ident + Password + Challenge) */ 92239beb93cSSam Leffler chap_md5(data->ident, password, password_len, challenge, 92339beb93cSSam Leffler EAP_TTLS_CHAP_CHALLENGE_LEN, pos); 92439beb93cSSam Leffler 92539beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", 92639beb93cSSam Leffler identity, identity_len); 92739beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", 92839beb93cSSam Leffler password, password_len); 92939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", 93039beb93cSSam Leffler challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); 93139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", 93239beb93cSSam Leffler pos, EAP_TTLS_CHAP_PASSWORD_LEN); 93339beb93cSSam Leffler pos += EAP_TTLS_CHAP_PASSWORD_LEN; 93439beb93cSSam Leffler os_free(challenge); 93539beb93cSSam Leffler AVP_PAD(buf, pos); 93639beb93cSSam Leffler 93739beb93cSSam Leffler wpabuf_put(msg, pos - buf); 93839beb93cSSam Leffler *resp = msg; 93939beb93cSSam Leffler 94039beb93cSSam Leffler if (data->ttls_version > 0) { 94139beb93cSSam Leffler /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, 94239beb93cSSam Leffler * so do not allow connection to be terminated yet. */ 94339beb93cSSam Leffler ret->methodState = METHOD_CONT; 94439beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 94539beb93cSSam Leffler } else { 94639beb93cSSam Leffler /* EAP-TTLS/CHAP does not provide tunneled success 94739beb93cSSam Leffler * notification, so assume that Phase2 succeeds. */ 94839beb93cSSam Leffler ret->methodState = METHOD_DONE; 94939beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 95039beb93cSSam Leffler } 95139beb93cSSam Leffler 95239beb93cSSam Leffler return 0; 95339beb93cSSam Leffler } 95439beb93cSSam Leffler 95539beb93cSSam Leffler 95639beb93cSSam Leffler static int eap_ttls_phase2_request(struct eap_sm *sm, 95739beb93cSSam Leffler struct eap_ttls_data *data, 95839beb93cSSam Leffler struct eap_method_ret *ret, 95939beb93cSSam Leffler struct eap_hdr *hdr, 96039beb93cSSam Leffler struct wpabuf **resp) 96139beb93cSSam Leffler { 96239beb93cSSam Leffler int res = 0; 96339beb93cSSam Leffler size_t len; 96439beb93cSSam Leffler enum phase2_types phase2_type = data->phase2_type; 96539beb93cSSam Leffler 96639beb93cSSam Leffler #ifdef EAP_TNC 96739beb93cSSam Leffler if (data->tnc_started) { 96839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); 96939beb93cSSam Leffler phase2_type = EAP_TTLS_PHASE2_EAP; 97039beb93cSSam Leffler } 97139beb93cSSam Leffler #endif /* EAP_TNC */ 97239beb93cSSam Leffler 97339beb93cSSam Leffler if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || 97439beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_MSCHAP || 97539beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_PAP || 97639beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_CHAP) { 97739beb93cSSam Leffler if (eap_get_config_identity(sm, &len) == NULL) { 97839beb93cSSam Leffler wpa_printf(MSG_INFO, 97939beb93cSSam Leffler "EAP-TTLS: Identity not configured"); 98039beb93cSSam Leffler eap_sm_request_identity(sm); 98139beb93cSSam Leffler if (eap_get_config_password(sm, &len) == NULL) 98239beb93cSSam Leffler eap_sm_request_password(sm); 98339beb93cSSam Leffler return 0; 98439beb93cSSam Leffler } 98539beb93cSSam Leffler 98639beb93cSSam Leffler if (eap_get_config_password(sm, &len) == NULL) { 98739beb93cSSam Leffler wpa_printf(MSG_INFO, 98839beb93cSSam Leffler "EAP-TTLS: Password not configured"); 98939beb93cSSam Leffler eap_sm_request_password(sm); 99039beb93cSSam Leffler return 0; 99139beb93cSSam Leffler } 99239beb93cSSam Leffler } 99339beb93cSSam Leffler 99439beb93cSSam Leffler switch (phase2_type) { 99539beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 99639beb93cSSam Leffler res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); 99739beb93cSSam Leffler break; 99839beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 99939beb93cSSam Leffler res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); 100039beb93cSSam Leffler break; 100139beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 100239beb93cSSam Leffler res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); 100339beb93cSSam Leffler break; 100439beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 100539beb93cSSam Leffler res = eap_ttls_phase2_request_pap(sm, data, ret, resp); 100639beb93cSSam Leffler break; 100739beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 100839beb93cSSam Leffler res = eap_ttls_phase2_request_chap(sm, data, ret, resp); 100939beb93cSSam Leffler break; 101039beb93cSSam Leffler default: 101139beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); 101239beb93cSSam Leffler res = -1; 101339beb93cSSam Leffler break; 101439beb93cSSam Leffler } 101539beb93cSSam Leffler 101639beb93cSSam Leffler if (res < 0) { 101739beb93cSSam Leffler ret->methodState = METHOD_DONE; 101839beb93cSSam Leffler ret->decision = DECISION_FAIL; 101939beb93cSSam Leffler } 102039beb93cSSam Leffler 102139beb93cSSam Leffler return res; 102239beb93cSSam Leffler } 102339beb93cSSam Leffler 102439beb93cSSam Leffler 102539beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 102639beb93cSSam Leffler static struct wpabuf * eap_ttls_build_phase_finished( 102739beb93cSSam Leffler struct eap_sm *sm, struct eap_ttls_data *data, int id, int final) 102839beb93cSSam Leffler { 102939beb93cSSam Leffler int len; 103039beb93cSSam Leffler struct wpabuf *req; 103139beb93cSSam Leffler u8 *pos; 103239beb93cSSam Leffler const int max_len = 300; 103339beb93cSSam Leffler 103439beb93cSSam Leffler req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1 + max_len, 103539beb93cSSam Leffler EAP_CODE_RESPONSE, id); 103639beb93cSSam Leffler if (req == NULL) 103739beb93cSSam Leffler return NULL; 103839beb93cSSam Leffler 103939beb93cSSam Leffler wpabuf_put_u8(req, data->ttls_version); 104039beb93cSSam Leffler 104139beb93cSSam Leffler pos = wpabuf_put(req, 0); 104239beb93cSSam Leffler len = tls_connection_ia_send_phase_finished(sm->ssl_ctx, 104339beb93cSSam Leffler data->ssl.conn, 104439beb93cSSam Leffler final, pos, max_len); 104539beb93cSSam Leffler if (len < 0) { 104639beb93cSSam Leffler wpabuf_free(req); 104739beb93cSSam Leffler return NULL; 104839beb93cSSam Leffler } 104939beb93cSSam Leffler wpabuf_put(req, len); 105039beb93cSSam Leffler eap_update_len(req); 105139beb93cSSam Leffler 105239beb93cSSam Leffler return req; 105339beb93cSSam Leffler } 105439beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 105539beb93cSSam Leffler 105639beb93cSSam Leffler 105739beb93cSSam Leffler struct ttls_parse_avp { 105839beb93cSSam Leffler u8 *mschapv2; 105939beb93cSSam Leffler u8 *eapdata; 106039beb93cSSam Leffler size_t eap_len; 106139beb93cSSam Leffler int mschapv2_error; 106239beb93cSSam Leffler }; 106339beb93cSSam Leffler 106439beb93cSSam Leffler 106539beb93cSSam Leffler static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, 106639beb93cSSam Leffler struct ttls_parse_avp *parse) 106739beb93cSSam Leffler { 106839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); 106939beb93cSSam Leffler if (parse->eapdata == NULL) { 107039beb93cSSam Leffler parse->eapdata = os_malloc(dlen); 107139beb93cSSam Leffler if (parse->eapdata == NULL) { 107239beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " 107339beb93cSSam Leffler "memory for Phase 2 EAP data"); 107439beb93cSSam Leffler return -1; 107539beb93cSSam Leffler } 107639beb93cSSam Leffler os_memcpy(parse->eapdata, dpos, dlen); 107739beb93cSSam Leffler parse->eap_len = dlen; 107839beb93cSSam Leffler } else { 107939beb93cSSam Leffler u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); 108039beb93cSSam Leffler if (neweap == NULL) { 108139beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " 108239beb93cSSam Leffler "memory for Phase 2 EAP data"); 108339beb93cSSam Leffler return -1; 108439beb93cSSam Leffler } 108539beb93cSSam Leffler os_memcpy(neweap + parse->eap_len, dpos, dlen); 108639beb93cSSam Leffler parse->eapdata = neweap; 108739beb93cSSam Leffler parse->eap_len += dlen; 108839beb93cSSam Leffler } 108939beb93cSSam Leffler 109039beb93cSSam Leffler return 0; 109139beb93cSSam Leffler } 109239beb93cSSam Leffler 109339beb93cSSam Leffler 109439beb93cSSam Leffler static int eap_ttls_parse_avp(u8 *pos, size_t left, 109539beb93cSSam Leffler struct ttls_parse_avp *parse) 109639beb93cSSam Leffler { 109739beb93cSSam Leffler struct ttls_avp *avp; 109839beb93cSSam Leffler u32 avp_code, avp_length, vendor_id = 0; 109939beb93cSSam Leffler u8 avp_flags, *dpos; 110039beb93cSSam Leffler size_t dlen; 110139beb93cSSam Leffler 110239beb93cSSam Leffler avp = (struct ttls_avp *) pos; 110339beb93cSSam Leffler avp_code = be_to_host32(avp->avp_code); 110439beb93cSSam Leffler avp_length = be_to_host32(avp->avp_length); 110539beb93cSSam Leffler avp_flags = (avp_length >> 24) & 0xff; 110639beb93cSSam Leffler avp_length &= 0xffffff; 110739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " 110839beb93cSSam Leffler "length=%d", (int) avp_code, avp_flags, 110939beb93cSSam Leffler (int) avp_length); 111039beb93cSSam Leffler 111139beb93cSSam Leffler if (avp_length > left) { 111239beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " 111339beb93cSSam Leffler "(len=%d, left=%lu) - dropped", 111439beb93cSSam Leffler (int) avp_length, (unsigned long) left); 111539beb93cSSam Leffler return -1; 111639beb93cSSam Leffler } 111739beb93cSSam Leffler 111839beb93cSSam Leffler if (avp_length < sizeof(*avp)) { 111939beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", 112039beb93cSSam Leffler avp_length); 112139beb93cSSam Leffler return -1; 112239beb93cSSam Leffler } 112339beb93cSSam Leffler 112439beb93cSSam Leffler dpos = (u8 *) (avp + 1); 112539beb93cSSam Leffler dlen = avp_length - sizeof(*avp); 112639beb93cSSam Leffler if (avp_flags & AVP_FLAGS_VENDOR) { 112739beb93cSSam Leffler if (dlen < 4) { 112839beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP " 112939beb93cSSam Leffler "underflow"); 113039beb93cSSam Leffler return -1; 113139beb93cSSam Leffler } 113239beb93cSSam Leffler vendor_id = WPA_GET_BE32(dpos); 113339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", 113439beb93cSSam Leffler (int) vendor_id); 113539beb93cSSam Leffler dpos += 4; 113639beb93cSSam Leffler dlen -= 4; 113739beb93cSSam Leffler } 113839beb93cSSam Leffler 113939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); 114039beb93cSSam Leffler 114139beb93cSSam Leffler if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { 114239beb93cSSam Leffler if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) 114339beb93cSSam Leffler return -1; 114439beb93cSSam Leffler } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { 114539beb93cSSam Leffler /* This is an optional message that can be displayed to 114639beb93cSSam Leffler * the user. */ 114739beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", 114839beb93cSSam Leffler dpos, dlen); 114939beb93cSSam Leffler } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 115039beb93cSSam Leffler avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { 115139beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success", 115239beb93cSSam Leffler dpos, dlen); 115339beb93cSSam Leffler if (dlen != 43) { 115439beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " 115539beb93cSSam Leffler "MS-CHAP2-Success length " 115639beb93cSSam Leffler "(len=%lu, expected 43)", 115739beb93cSSam Leffler (unsigned long) dlen); 115839beb93cSSam Leffler return -1; 115939beb93cSSam Leffler } 116039beb93cSSam Leffler parse->mschapv2 = dpos; 116139beb93cSSam Leffler } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 116239beb93cSSam Leffler avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { 116339beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error", 116439beb93cSSam Leffler dpos, dlen); 116539beb93cSSam Leffler parse->mschapv2_error = 1; 116639beb93cSSam Leffler } else if (avp_flags & AVP_FLAGS_MANDATORY) { 116739beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP " 116839beb93cSSam Leffler "code %d vendor_id %d - dropped", 116939beb93cSSam Leffler (int) avp_code, (int) vendor_id); 117039beb93cSSam Leffler return -1; 117139beb93cSSam Leffler } else { 117239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " 117339beb93cSSam Leffler "code %d vendor_id %d", 117439beb93cSSam Leffler (int) avp_code, (int) vendor_id); 117539beb93cSSam Leffler } 117639beb93cSSam Leffler 117739beb93cSSam Leffler return avp_length; 117839beb93cSSam Leffler } 117939beb93cSSam Leffler 118039beb93cSSam Leffler 118139beb93cSSam Leffler static int eap_ttls_parse_avps(struct wpabuf *in_decrypted, 118239beb93cSSam Leffler struct ttls_parse_avp *parse) 118339beb93cSSam Leffler { 118439beb93cSSam Leffler u8 *pos; 118539beb93cSSam Leffler size_t left, pad; 118639beb93cSSam Leffler int avp_length; 118739beb93cSSam Leffler 118839beb93cSSam Leffler pos = wpabuf_mhead(in_decrypted); 118939beb93cSSam Leffler left = wpabuf_len(in_decrypted); 119039beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); 119139beb93cSSam Leffler if (left < sizeof(struct ttls_avp)) { 119239beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" 119339beb93cSSam Leffler " len=%lu expected %lu or more - dropped", 119439beb93cSSam Leffler (unsigned long) left, 119539beb93cSSam Leffler (unsigned long) sizeof(struct ttls_avp)); 119639beb93cSSam Leffler return -1; 119739beb93cSSam Leffler } 119839beb93cSSam Leffler 119939beb93cSSam Leffler /* Parse AVPs */ 120039beb93cSSam Leffler os_memset(parse, 0, sizeof(*parse)); 120139beb93cSSam Leffler 120239beb93cSSam Leffler while (left > 0) { 120339beb93cSSam Leffler avp_length = eap_ttls_parse_avp(pos, left, parse); 120439beb93cSSam Leffler if (avp_length < 0) 120539beb93cSSam Leffler return -1; 120639beb93cSSam Leffler 120739beb93cSSam Leffler pad = (4 - (avp_length & 3)) & 3; 120839beb93cSSam Leffler pos += avp_length + pad; 120939beb93cSSam Leffler if (left < avp_length + pad) 121039beb93cSSam Leffler left = 0; 121139beb93cSSam Leffler else 121239beb93cSSam Leffler left -= avp_length + pad; 121339beb93cSSam Leffler } 121439beb93cSSam Leffler 121539beb93cSSam Leffler return 0; 121639beb93cSSam Leffler } 121739beb93cSSam Leffler 121839beb93cSSam Leffler 121939beb93cSSam Leffler static u8 * eap_ttls_fake_identity_request(void) 122039beb93cSSam Leffler { 122139beb93cSSam Leffler struct eap_hdr *hdr; 122239beb93cSSam Leffler u8 *buf; 122339beb93cSSam Leffler 122439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " 122539beb93cSSam Leffler "Phase 2 - use fake EAP-Request Identity"); 122639beb93cSSam Leffler buf = os_malloc(sizeof(*hdr) + 1); 122739beb93cSSam Leffler if (buf == NULL) { 122839beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " 122939beb93cSSam Leffler "memory for fake EAP-Identity Request"); 123039beb93cSSam Leffler return NULL; 123139beb93cSSam Leffler } 123239beb93cSSam Leffler 123339beb93cSSam Leffler hdr = (struct eap_hdr *) buf; 123439beb93cSSam Leffler hdr->code = EAP_CODE_REQUEST; 123539beb93cSSam Leffler hdr->identifier = 0; 123639beb93cSSam Leffler hdr->length = host_to_be16(sizeof(*hdr) + 1); 123739beb93cSSam Leffler buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; 123839beb93cSSam Leffler 123939beb93cSSam Leffler return buf; 124039beb93cSSam Leffler } 124139beb93cSSam Leffler 124239beb93cSSam Leffler 124339beb93cSSam Leffler static int eap_ttls_encrypt_response(struct eap_sm *sm, 124439beb93cSSam Leffler struct eap_ttls_data *data, 124539beb93cSSam Leffler struct wpabuf *resp, u8 identifier, 124639beb93cSSam Leffler struct wpabuf **out_data) 124739beb93cSSam Leffler { 124839beb93cSSam Leffler if (resp == NULL) 124939beb93cSSam Leffler return 0; 125039beb93cSSam Leffler 125139beb93cSSam Leffler wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", 125239beb93cSSam Leffler resp); 125339beb93cSSam Leffler if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, 125439beb93cSSam Leffler data->ttls_version, identifier, 125539beb93cSSam Leffler resp, out_data)) { 125639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " 125739beb93cSSam Leffler "frame"); 125839beb93cSSam Leffler return -1; 125939beb93cSSam Leffler } 126039beb93cSSam Leffler wpabuf_free(resp); 126139beb93cSSam Leffler 126239beb93cSSam Leffler return 0; 126339beb93cSSam Leffler } 126439beb93cSSam Leffler 126539beb93cSSam Leffler 126639beb93cSSam Leffler static int eap_ttls_process_phase2_eap(struct eap_sm *sm, 126739beb93cSSam Leffler struct eap_ttls_data *data, 126839beb93cSSam Leffler struct eap_method_ret *ret, 126939beb93cSSam Leffler struct ttls_parse_avp *parse, 127039beb93cSSam Leffler struct wpabuf **resp) 127139beb93cSSam Leffler { 127239beb93cSSam Leffler struct eap_hdr *hdr; 127339beb93cSSam Leffler size_t len; 127439beb93cSSam Leffler 127539beb93cSSam Leffler if (parse->eapdata == NULL) { 127639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " 127739beb93cSSam Leffler "packet - dropped"); 127839beb93cSSam Leffler return -1; 127939beb93cSSam Leffler } 128039beb93cSSam Leffler 128139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", 128239beb93cSSam Leffler parse->eapdata, parse->eap_len); 128339beb93cSSam Leffler hdr = (struct eap_hdr *) parse->eapdata; 128439beb93cSSam Leffler 128539beb93cSSam Leffler if (parse->eap_len < sizeof(*hdr)) { 128639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " 128739beb93cSSam Leffler "frame (len=%lu, expected %lu or more) - dropped", 128839beb93cSSam Leffler (unsigned long) parse->eap_len, 128939beb93cSSam Leffler (unsigned long) sizeof(*hdr)); 129039beb93cSSam Leffler return -1; 129139beb93cSSam Leffler } 129239beb93cSSam Leffler len = be_to_host16(hdr->length); 129339beb93cSSam Leffler if (len > parse->eap_len) { 129439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " 129539beb93cSSam Leffler "EAP frame (EAP hdr len=%lu, EAP data len in " 129639beb93cSSam Leffler "AVP=%lu)", 129739beb93cSSam Leffler (unsigned long) len, 129839beb93cSSam Leffler (unsigned long) parse->eap_len); 129939beb93cSSam Leffler return -1; 130039beb93cSSam Leffler } 130139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " 130239beb93cSSam Leffler "identifier=%d length=%lu", 130339beb93cSSam Leffler hdr->code, hdr->identifier, (unsigned long) len); 130439beb93cSSam Leffler switch (hdr->code) { 130539beb93cSSam Leffler case EAP_CODE_REQUEST: 130639beb93cSSam Leffler if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { 130739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " 130839beb93cSSam Leffler "processing failed"); 130939beb93cSSam Leffler return -1; 131039beb93cSSam Leffler } 131139beb93cSSam Leffler break; 131239beb93cSSam Leffler default: 131339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " 131439beb93cSSam Leffler "Phase 2 EAP header", hdr->code); 131539beb93cSSam Leffler return -1; 131639beb93cSSam Leffler } 131739beb93cSSam Leffler 131839beb93cSSam Leffler return 0; 131939beb93cSSam Leffler } 132039beb93cSSam Leffler 132139beb93cSSam Leffler 132239beb93cSSam Leffler static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, 132339beb93cSSam Leffler struct eap_ttls_data *data, 132439beb93cSSam Leffler struct eap_method_ret *ret, 132539beb93cSSam Leffler struct ttls_parse_avp *parse) 132639beb93cSSam Leffler { 132739beb93cSSam Leffler if (parse->mschapv2_error) { 132839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " 132939beb93cSSam Leffler "MS-CHAP-Error - failed"); 133039beb93cSSam Leffler ret->methodState = METHOD_DONE; 133139beb93cSSam Leffler ret->decision = DECISION_FAIL; 133239beb93cSSam Leffler /* Reply with empty data to ACK error */ 133339beb93cSSam Leffler return 1; 133439beb93cSSam Leffler } 133539beb93cSSam Leffler 133639beb93cSSam Leffler if (parse->mschapv2 == NULL) { 133739beb93cSSam Leffler #ifdef EAP_TNC 133839beb93cSSam Leffler if (data->phase2_success && parse->eapdata) { 133939beb93cSSam Leffler /* 134039beb93cSSam Leffler * Allow EAP-TNC to be started after successfully 134139beb93cSSam Leffler * completed MSCHAPV2. 134239beb93cSSam Leffler */ 134339beb93cSSam Leffler return 1; 134439beb93cSSam Leffler } 134539beb93cSSam Leffler #endif /* EAP_TNC */ 134639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " 134739beb93cSSam Leffler "received for Phase2 MSCHAPV2"); 134839beb93cSSam Leffler return -1; 134939beb93cSSam Leffler } 135039beb93cSSam Leffler if (parse->mschapv2[0] != data->ident) { 135139beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " 135239beb93cSSam Leffler "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", 135339beb93cSSam Leffler parse->mschapv2[0], data->ident); 135439beb93cSSam Leffler return -1; 135539beb93cSSam Leffler } 135639beb93cSSam Leffler if (!data->auth_response_valid || 135739beb93cSSam Leffler mschapv2_verify_auth_response(data->auth_response, 135839beb93cSSam Leffler parse->mschapv2 + 1, 42)) { 135939beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " 136039beb93cSSam Leffler "response in Phase 2 MSCHAPV2 success request"); 136139beb93cSSam Leffler return -1; 136239beb93cSSam Leffler } 136339beb93cSSam Leffler 136439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " 136539beb93cSSam Leffler "authentication succeeded"); 136639beb93cSSam Leffler if (data->ttls_version > 0) { 136739beb93cSSam Leffler /* 136839beb93cSSam Leffler * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report 136939beb93cSSam Leffler * success, so do not allow connection to be terminated 137039beb93cSSam Leffler * yet. 137139beb93cSSam Leffler */ 137239beb93cSSam Leffler ret->methodState = METHOD_CONT; 137339beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 137439beb93cSSam Leffler } else { 137539beb93cSSam Leffler ret->methodState = METHOD_DONE; 137639beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 137739beb93cSSam Leffler data->phase2_success = 1; 137839beb93cSSam Leffler } 137939beb93cSSam Leffler 138039beb93cSSam Leffler /* 138139beb93cSSam Leffler * Reply with empty data; authentication server will reply 138239beb93cSSam Leffler * with EAP-Success after this. 138339beb93cSSam Leffler */ 138439beb93cSSam Leffler return 1; 138539beb93cSSam Leffler } 138639beb93cSSam Leffler 138739beb93cSSam Leffler 138839beb93cSSam Leffler #ifdef EAP_TNC 138939beb93cSSam Leffler static int eap_ttls_process_tnc_start(struct eap_sm *sm, 139039beb93cSSam Leffler struct eap_ttls_data *data, 139139beb93cSSam Leffler struct eap_method_ret *ret, 139239beb93cSSam Leffler struct ttls_parse_avp *parse, 139339beb93cSSam Leffler struct wpabuf **resp) 139439beb93cSSam Leffler { 139539beb93cSSam Leffler /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ 139639beb93cSSam Leffler if (parse->eapdata == NULL) { 139739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " 139839beb93cSSam Leffler "unexpected tunneled data (no EAP)"); 139939beb93cSSam Leffler return -1; 140039beb93cSSam Leffler } 140139beb93cSSam Leffler 140239beb93cSSam Leffler if (!data->ready_for_tnc) { 140339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " 140439beb93cSSam Leffler "EAP after non-EAP, but not ready for TNC"); 140539beb93cSSam Leffler return -1; 140639beb93cSSam Leffler } 140739beb93cSSam Leffler 140839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " 140939beb93cSSam Leffler "non-EAP method"); 141039beb93cSSam Leffler data->tnc_started = 1; 141139beb93cSSam Leffler 141239beb93cSSam Leffler if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) 141339beb93cSSam Leffler return -1; 141439beb93cSSam Leffler 141539beb93cSSam Leffler return 0; 141639beb93cSSam Leffler } 141739beb93cSSam Leffler #endif /* EAP_TNC */ 141839beb93cSSam Leffler 141939beb93cSSam Leffler 142039beb93cSSam Leffler static int eap_ttls_process_decrypted(struct eap_sm *sm, 142139beb93cSSam Leffler struct eap_ttls_data *data, 142239beb93cSSam Leffler struct eap_method_ret *ret, 142339beb93cSSam Leffler u8 identifier, 142439beb93cSSam Leffler struct ttls_parse_avp *parse, 142539beb93cSSam Leffler struct wpabuf *in_decrypted, 142639beb93cSSam Leffler struct wpabuf **out_data) 142739beb93cSSam Leffler { 142839beb93cSSam Leffler struct wpabuf *resp = NULL; 142939beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 143039beb93cSSam Leffler int res; 143139beb93cSSam Leffler enum phase2_types phase2_type = data->phase2_type; 143239beb93cSSam Leffler 143339beb93cSSam Leffler #ifdef EAP_TNC 143439beb93cSSam Leffler if (data->tnc_started) 143539beb93cSSam Leffler phase2_type = EAP_TTLS_PHASE2_EAP; 143639beb93cSSam Leffler #endif /* EAP_TNC */ 143739beb93cSSam Leffler 143839beb93cSSam Leffler switch (phase2_type) { 143939beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 144039beb93cSSam Leffler if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < 144139beb93cSSam Leffler 0) 144239beb93cSSam Leffler return -1; 144339beb93cSSam Leffler break; 144439beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 144539beb93cSSam Leffler res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); 144639beb93cSSam Leffler #ifdef EAP_TNC 144739beb93cSSam Leffler if (res == 1 && parse->eapdata && data->phase2_success) { 144839beb93cSSam Leffler /* 144939beb93cSSam Leffler * TNC may be required as the next 145039beb93cSSam Leffler * authentication method within the tunnel. 145139beb93cSSam Leffler */ 145239beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 145339beb93cSSam Leffler data->ready_for_tnc = 1; 145439beb93cSSam Leffler if (eap_ttls_process_tnc_start(sm, data, ret, parse, 145539beb93cSSam Leffler &resp) == 0) 145639beb93cSSam Leffler break; 145739beb93cSSam Leffler } 145839beb93cSSam Leffler #endif /* EAP_TNC */ 145939beb93cSSam Leffler return res; 146039beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 146139beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 146239beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 146339beb93cSSam Leffler #ifdef EAP_TNC 146439beb93cSSam Leffler if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < 146539beb93cSSam Leffler 0) 146639beb93cSSam Leffler return -1; 146739beb93cSSam Leffler break; 146839beb93cSSam Leffler #else /* EAP_TNC */ 146939beb93cSSam Leffler /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled 147039beb93cSSam Leffler * requests to the supplicant */ 147139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " 147239beb93cSSam Leffler "tunneled data"); 147339beb93cSSam Leffler return -1; 147439beb93cSSam Leffler #endif /* EAP_TNC */ 147539beb93cSSam Leffler } 147639beb93cSSam Leffler 147739beb93cSSam Leffler if (resp) { 147839beb93cSSam Leffler if (eap_ttls_encrypt_response(sm, data, resp, identifier, 147939beb93cSSam Leffler out_data) < 0) 148039beb93cSSam Leffler return -1; 148139beb93cSSam Leffler } else if (config->pending_req_identity || 148239beb93cSSam Leffler config->pending_req_password || 148339beb93cSSam Leffler config->pending_req_otp || 148439beb93cSSam Leffler config->pending_req_new_password) { 148539beb93cSSam Leffler wpabuf_free(data->pending_phase2_req); 148639beb93cSSam Leffler data->pending_phase2_req = wpabuf_dup(in_decrypted); 148739beb93cSSam Leffler } 148839beb93cSSam Leffler 148939beb93cSSam Leffler return 0; 149039beb93cSSam Leffler } 149139beb93cSSam Leffler 149239beb93cSSam Leffler 149339beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 149439beb93cSSam Leffler static void eap_ttls_final_phase_finished(struct eap_sm *sm, 149539beb93cSSam Leffler struct eap_ttls_data *data, 149639beb93cSSam Leffler struct eap_method_ret *ret, 149739beb93cSSam Leffler u8 identifier, 149839beb93cSSam Leffler struct wpabuf **out_data) 149939beb93cSSam Leffler { 150039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received"); 150139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded"); 150239beb93cSSam Leffler ret->methodState = METHOD_DONE; 150339beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 150439beb93cSSam Leffler data->phase2_success = 1; 150539beb93cSSam Leffler *out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1); 150639beb93cSSam Leffler eap_ttls_v1_derive_key(sm, data); 150739beb93cSSam Leffler } 150839beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 150939beb93cSSam Leffler 151039beb93cSSam Leffler 151139beb93cSSam Leffler static int eap_ttls_implicit_identity_request(struct eap_sm *sm, 151239beb93cSSam Leffler struct eap_ttls_data *data, 151339beb93cSSam Leffler struct eap_method_ret *ret, 151439beb93cSSam Leffler u8 identifier, 151539beb93cSSam Leffler struct wpabuf **out_data) 151639beb93cSSam Leffler { 151739beb93cSSam Leffler int retval = 0; 151839beb93cSSam Leffler struct eap_hdr *hdr; 151939beb93cSSam Leffler struct wpabuf *resp; 152039beb93cSSam Leffler 152139beb93cSSam Leffler hdr = (struct eap_hdr *) eap_ttls_fake_identity_request(); 152239beb93cSSam Leffler if (hdr == NULL) { 152339beb93cSSam Leffler ret->methodState = METHOD_DONE; 152439beb93cSSam Leffler ret->decision = DECISION_FAIL; 152539beb93cSSam Leffler return -1; 152639beb93cSSam Leffler } 152739beb93cSSam Leffler 152839beb93cSSam Leffler resp = NULL; 152939beb93cSSam Leffler if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) { 153039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " 153139beb93cSSam Leffler "processing failed"); 153239beb93cSSam Leffler retval = -1; 153339beb93cSSam Leffler } else { 153439beb93cSSam Leffler retval = eap_ttls_encrypt_response(sm, data, resp, identifier, 153539beb93cSSam Leffler out_data); 153639beb93cSSam Leffler } 153739beb93cSSam Leffler 153839beb93cSSam Leffler os_free(hdr); 153939beb93cSSam Leffler 154039beb93cSSam Leffler if (retval < 0) { 154139beb93cSSam Leffler ret->methodState = METHOD_DONE; 154239beb93cSSam Leffler ret->decision = DECISION_FAIL; 154339beb93cSSam Leffler } 154439beb93cSSam Leffler 154539beb93cSSam Leffler return retval; 154639beb93cSSam Leffler } 154739beb93cSSam Leffler 154839beb93cSSam Leffler 154939beb93cSSam Leffler static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data, 155039beb93cSSam Leffler struct eap_method_ret *ret, u8 identifier, 155139beb93cSSam Leffler struct wpabuf **out_data) 155239beb93cSSam Leffler { 155339beb93cSSam Leffler data->phase2_start = 0; 155439beb93cSSam Leffler 155539beb93cSSam Leffler /* 155639beb93cSSam Leffler * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only 155739beb93cSSam Leffler * if TLS part was indeed resuming a previous session. Most 155839beb93cSSam Leffler * Authentication Servers terminate EAP-TTLS before reaching this 155939beb93cSSam Leffler * point, but some do not. Make wpa_supplicant stop phase 2 here, if 156039beb93cSSam Leffler * needed. 156139beb93cSSam Leffler */ 156239beb93cSSam Leffler if (data->reauth && 156339beb93cSSam Leffler tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { 156439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " 156539beb93cSSam Leffler "skip phase 2"); 156639beb93cSSam Leffler *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS, 156739beb93cSSam Leffler data->ttls_version); 156839beb93cSSam Leffler ret->methodState = METHOD_DONE; 156939beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 157039beb93cSSam Leffler data->phase2_success = 1; 157139beb93cSSam Leffler return 0; 157239beb93cSSam Leffler } 157339beb93cSSam Leffler 157439beb93cSSam Leffler return eap_ttls_implicit_identity_request(sm, data, ret, identifier, 157539beb93cSSam Leffler out_data); 157639beb93cSSam Leffler } 157739beb93cSSam Leffler 157839beb93cSSam Leffler 157939beb93cSSam Leffler static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, 158039beb93cSSam Leffler struct eap_method_ret *ret, u8 identifier, 158139beb93cSSam Leffler const struct wpabuf *in_data, 158239beb93cSSam Leffler struct wpabuf **out_data) 158339beb93cSSam Leffler { 158439beb93cSSam Leffler struct wpabuf *in_decrypted = NULL; 158539beb93cSSam Leffler int retval = 0; 158639beb93cSSam Leffler struct ttls_parse_avp parse; 158739beb93cSSam Leffler 158839beb93cSSam Leffler os_memset(&parse, 0, sizeof(parse)); 158939beb93cSSam Leffler 159039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" 159139beb93cSSam Leffler " Phase 2", 159239beb93cSSam Leffler in_data ? (unsigned long) wpabuf_len(in_data) : 0); 159339beb93cSSam Leffler 159439beb93cSSam Leffler if (data->pending_phase2_req) { 159539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " 159639beb93cSSam Leffler "skip decryption and use old data"); 159739beb93cSSam Leffler /* Clear TLS reassembly state. */ 159839beb93cSSam Leffler eap_peer_tls_reset_input(&data->ssl); 159939beb93cSSam Leffler 160039beb93cSSam Leffler in_decrypted = data->pending_phase2_req; 160139beb93cSSam Leffler data->pending_phase2_req = NULL; 160239beb93cSSam Leffler if (wpabuf_len(in_decrypted) == 0) { 160339beb93cSSam Leffler wpabuf_free(in_decrypted); 160439beb93cSSam Leffler return eap_ttls_implicit_identity_request( 160539beb93cSSam Leffler sm, data, ret, identifier, out_data); 160639beb93cSSam Leffler } 160739beb93cSSam Leffler goto continue_req; 160839beb93cSSam Leffler } 160939beb93cSSam Leffler 161039beb93cSSam Leffler if ((in_data == NULL || wpabuf_len(in_data) == 0) && 161139beb93cSSam Leffler data->phase2_start) { 161239beb93cSSam Leffler return eap_ttls_phase2_start(sm, data, ret, identifier, 161339beb93cSSam Leffler out_data); 161439beb93cSSam Leffler } 161539beb93cSSam Leffler 161639beb93cSSam Leffler if (in_data == NULL || wpabuf_len(in_data) == 0) { 161739beb93cSSam Leffler /* Received TLS ACK - requesting more fragments */ 161839beb93cSSam Leffler return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, 161939beb93cSSam Leffler data->ttls_version, 162039beb93cSSam Leffler identifier, NULL, out_data); 162139beb93cSSam Leffler } 162239beb93cSSam Leffler 162339beb93cSSam Leffler retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); 162439beb93cSSam Leffler if (retval) 162539beb93cSSam Leffler goto done; 162639beb93cSSam Leffler 162739beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 162839beb93cSSam Leffler if (data->ttls_version > 0 && 162939beb93cSSam Leffler (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) && 163039beb93cSSam Leffler tls_connection_ia_final_phase_finished(sm->ssl_ctx, 163139beb93cSSam Leffler data->ssl.conn)) { 163239beb93cSSam Leffler eap_ttls_final_phase_finished(sm, data, ret, identifier, 163339beb93cSSam Leffler out_data); 163439beb93cSSam Leffler goto done; 163539beb93cSSam Leffler } 163639beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 163739beb93cSSam Leffler 163839beb93cSSam Leffler continue_req: 163939beb93cSSam Leffler data->phase2_start = 0; 164039beb93cSSam Leffler 164139beb93cSSam Leffler if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) { 164239beb93cSSam Leffler retval = -1; 164339beb93cSSam Leffler goto done; 164439beb93cSSam Leffler } 164539beb93cSSam Leffler 164639beb93cSSam Leffler retval = eap_ttls_process_decrypted(sm, data, ret, identifier, 164739beb93cSSam Leffler &parse, in_decrypted, out_data); 164839beb93cSSam Leffler 164939beb93cSSam Leffler done: 165039beb93cSSam Leffler wpabuf_free(in_decrypted); 165139beb93cSSam Leffler os_free(parse.eapdata); 165239beb93cSSam Leffler 165339beb93cSSam Leffler if (retval < 0) { 165439beb93cSSam Leffler ret->methodState = METHOD_DONE; 165539beb93cSSam Leffler ret->decision = DECISION_FAIL; 165639beb93cSSam Leffler } 165739beb93cSSam Leffler 165839beb93cSSam Leffler return retval; 165939beb93cSSam Leffler } 166039beb93cSSam Leffler 166139beb93cSSam Leffler 166239beb93cSSam Leffler static int eap_ttls_process_start(struct eap_sm *sm, 166339beb93cSSam Leffler struct eap_ttls_data *data, u8 flags, 166439beb93cSSam Leffler struct eap_method_ret *ret) 166539beb93cSSam Leffler { 166639beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 166739beb93cSSam Leffler 166839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)", 166939beb93cSSam Leffler flags & EAP_PEAP_VERSION_MASK, data->ttls_version); 167039beb93cSSam Leffler #if EAP_TTLS_VERSION > 0 167139beb93cSSam Leffler if ((flags & EAP_PEAP_VERSION_MASK) < data->ttls_version) 167239beb93cSSam Leffler data->ttls_version = flags & EAP_PEAP_VERSION_MASK; 167339beb93cSSam Leffler if (data->force_ttls_version >= 0 && 167439beb93cSSam Leffler data->force_ttls_version != data->ttls_version) { 167539beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select " 167639beb93cSSam Leffler "forced TTLS version %d", 167739beb93cSSam Leffler data->force_ttls_version); 167839beb93cSSam Leffler ret->methodState = METHOD_DONE; 167939beb93cSSam Leffler ret->decision = DECISION_FAIL; 168039beb93cSSam Leffler ret->allowNotifications = FALSE; 168139beb93cSSam Leffler return -1; 168239beb93cSSam Leffler } 168339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d", 168439beb93cSSam Leffler data->ttls_version); 168539beb93cSSam Leffler 168639beb93cSSam Leffler if (data->ttls_version > 0) 168739beb93cSSam Leffler data->ssl.tls_ia = 1; 168839beb93cSSam Leffler #endif /* EAP_TTLS_VERSION */ 168939beb93cSSam Leffler if (!data->ssl_initialized && 169039beb93cSSam Leffler eap_peer_tls_ssl_init(sm, &data->ssl, config)) { 169139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); 169239beb93cSSam Leffler return -1; 169339beb93cSSam Leffler } 169439beb93cSSam Leffler data->ssl_initialized = 1; 169539beb93cSSam Leffler 169639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Start"); 169739beb93cSSam Leffler 169839beb93cSSam Leffler return 0; 169939beb93cSSam Leffler } 170039beb93cSSam Leffler 170139beb93cSSam Leffler 170239beb93cSSam Leffler static int eap_ttls_process_handshake(struct eap_sm *sm, 170339beb93cSSam Leffler struct eap_ttls_data *data, 170439beb93cSSam Leffler struct eap_method_ret *ret, 170539beb93cSSam Leffler u8 identifier, 170639beb93cSSam Leffler const u8 *in_data, size_t in_len, 170739beb93cSSam Leffler struct wpabuf **out_data) 170839beb93cSSam Leffler { 170939beb93cSSam Leffler int res; 171039beb93cSSam Leffler 171139beb93cSSam Leffler res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, 171239beb93cSSam Leffler data->ttls_version, identifier, 171339beb93cSSam Leffler in_data, in_len, out_data); 171439beb93cSSam Leffler 171539beb93cSSam Leffler if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 171639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " 171739beb93cSSam Leffler "Phase 2"); 171839beb93cSSam Leffler if (data->resuming) { 171939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may " 172039beb93cSSam Leffler "skip Phase 2"); 172139beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 172239beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 172339beb93cSSam Leffler } 172439beb93cSSam Leffler data->phase2_start = 1; 172539beb93cSSam Leffler if (data->ttls_version == 0) 172639beb93cSSam Leffler eap_ttls_v0_derive_key(sm, data); 172739beb93cSSam Leffler 172839beb93cSSam Leffler if (*out_data == NULL || wpabuf_len(*out_data) == 0) { 172939beb93cSSam Leffler if (eap_ttls_decrypt(sm, data, ret, identifier, 173039beb93cSSam Leffler NULL, out_data)) { 173139beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: " 173239beb93cSSam Leffler "failed to process early " 173339beb93cSSam Leffler "start for Phase 2"); 173439beb93cSSam Leffler } 173539beb93cSSam Leffler res = 0; 173639beb93cSSam Leffler } 173739beb93cSSam Leffler data->resuming = 0; 173839beb93cSSam Leffler } 173939beb93cSSam Leffler 174039beb93cSSam Leffler if (res == 2) { 174139beb93cSSam Leffler struct wpabuf msg; 174239beb93cSSam Leffler /* 174339beb93cSSam Leffler * Application data included in the handshake message. 174439beb93cSSam Leffler */ 174539beb93cSSam Leffler wpabuf_free(data->pending_phase2_req); 174639beb93cSSam Leffler data->pending_phase2_req = *out_data; 174739beb93cSSam Leffler *out_data = NULL; 174839beb93cSSam Leffler wpabuf_set(&msg, in_data, in_len); 174939beb93cSSam Leffler res = eap_ttls_decrypt(sm, data, ret, identifier, &msg, 175039beb93cSSam Leffler out_data); 175139beb93cSSam Leffler } 175239beb93cSSam Leffler 175339beb93cSSam Leffler return res; 175439beb93cSSam Leffler } 175539beb93cSSam Leffler 175639beb93cSSam Leffler 175739beb93cSSam Leffler static void eap_ttls_check_auth_status(struct eap_sm *sm, 175839beb93cSSam Leffler struct eap_ttls_data *data, 175939beb93cSSam Leffler struct eap_method_ret *ret) 176039beb93cSSam Leffler { 176139beb93cSSam Leffler if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) { 176239beb93cSSam Leffler ret->allowNotifications = FALSE; 176339beb93cSSam Leffler if (ret->decision == DECISION_UNCOND_SUCC || 176439beb93cSSam Leffler ret->decision == DECISION_COND_SUCC) { 176539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " 176639beb93cSSam Leffler "completed successfully"); 176739beb93cSSam Leffler data->phase2_success = 1; 176839beb93cSSam Leffler #ifdef EAP_TNC 176939beb93cSSam Leffler if (!data->ready_for_tnc && !data->tnc_started) { 177039beb93cSSam Leffler /* 177139beb93cSSam Leffler * TNC may be required as the next 177239beb93cSSam Leffler * authentication method within the tunnel. 177339beb93cSSam Leffler */ 177439beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 177539beb93cSSam Leffler data->ready_for_tnc = 1; 177639beb93cSSam Leffler } 177739beb93cSSam Leffler #endif /* EAP_TNC */ 177839beb93cSSam Leffler } 177939beb93cSSam Leffler } else if (data->ttls_version == 0 && 178039beb93cSSam Leffler ret->methodState == METHOD_MAY_CONT && 178139beb93cSSam Leffler (ret->decision == DECISION_UNCOND_SUCC || 178239beb93cSSam Leffler ret->decision == DECISION_COND_SUCC)) { 178339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " 178439beb93cSSam Leffler "completed successfully (MAY_CONT)"); 178539beb93cSSam Leffler data->phase2_success = 1; 178639beb93cSSam Leffler } 178739beb93cSSam Leffler } 178839beb93cSSam Leffler 178939beb93cSSam Leffler 179039beb93cSSam Leffler static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, 179139beb93cSSam Leffler struct eap_method_ret *ret, 179239beb93cSSam Leffler const struct wpabuf *reqData) 179339beb93cSSam Leffler { 179439beb93cSSam Leffler size_t left; 179539beb93cSSam Leffler int res; 179639beb93cSSam Leffler u8 flags, id; 179739beb93cSSam Leffler struct wpabuf *resp; 179839beb93cSSam Leffler const u8 *pos; 179939beb93cSSam Leffler struct eap_ttls_data *data = priv; 180039beb93cSSam Leffler 180139beb93cSSam Leffler pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, 180239beb93cSSam Leffler reqData, &left, &flags); 180339beb93cSSam Leffler if (pos == NULL) 180439beb93cSSam Leffler return NULL; 180539beb93cSSam Leffler id = eap_get_id(reqData); 180639beb93cSSam Leffler 180739beb93cSSam Leffler if (flags & EAP_TLS_FLAGS_START) { 180839beb93cSSam Leffler if (eap_ttls_process_start(sm, data, flags, ret) < 0) 180939beb93cSSam Leffler return NULL; 181039beb93cSSam Leffler 181139beb93cSSam Leffler /* RFC 5281, Ch. 9.2: 181239beb93cSSam Leffler * "This packet MAY contain additional information in the form 181339beb93cSSam Leffler * of AVPs, which may provide useful hints to the client" 181439beb93cSSam Leffler * For now, ignore any potential extra data. 181539beb93cSSam Leffler */ 181639beb93cSSam Leffler left = 0; 181739beb93cSSam Leffler } else if (!data->ssl_initialized) { 181839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not " 181939beb93cSSam Leffler "include Start flag"); 182039beb93cSSam Leffler ret->methodState = METHOD_DONE; 182139beb93cSSam Leffler ret->decision = DECISION_FAIL; 182239beb93cSSam Leffler ret->allowNotifications = FALSE; 182339beb93cSSam Leffler return NULL; 182439beb93cSSam Leffler } 182539beb93cSSam Leffler 182639beb93cSSam Leffler resp = NULL; 182739beb93cSSam Leffler if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 182839beb93cSSam Leffler !data->resuming) { 182939beb93cSSam Leffler struct wpabuf msg; 183039beb93cSSam Leffler wpabuf_set(&msg, pos, left); 183139beb93cSSam Leffler res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); 183239beb93cSSam Leffler } else { 183339beb93cSSam Leffler res = eap_ttls_process_handshake(sm, data, ret, id, 183439beb93cSSam Leffler pos, left, &resp); 183539beb93cSSam Leffler } 183639beb93cSSam Leffler 183739beb93cSSam Leffler eap_ttls_check_auth_status(sm, data, ret); 183839beb93cSSam Leffler 183939beb93cSSam Leffler /* FIX: what about res == -1? Could just move all error processing into 184039beb93cSSam Leffler * the other functions and get rid of this res==1 case here. */ 184139beb93cSSam Leffler if (res == 1) { 184239beb93cSSam Leffler wpabuf_free(resp); 184339beb93cSSam Leffler return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, 184439beb93cSSam Leffler data->ttls_version); 184539beb93cSSam Leffler } 184639beb93cSSam Leffler return resp; 184739beb93cSSam Leffler } 184839beb93cSSam Leffler 184939beb93cSSam Leffler 185039beb93cSSam Leffler static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) 185139beb93cSSam Leffler { 185239beb93cSSam Leffler struct eap_ttls_data *data = priv; 185339beb93cSSam Leffler return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 185439beb93cSSam Leffler data->phase2_success; 185539beb93cSSam Leffler } 185639beb93cSSam Leffler 185739beb93cSSam Leffler 185839beb93cSSam Leffler static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) 185939beb93cSSam Leffler { 186039beb93cSSam Leffler struct eap_ttls_data *data = priv; 186139beb93cSSam Leffler wpabuf_free(data->pending_phase2_req); 186239beb93cSSam Leffler data->pending_phase2_req = NULL; 186339beb93cSSam Leffler #ifdef EAP_TNC 186439beb93cSSam Leffler data->ready_for_tnc = 0; 186539beb93cSSam Leffler data->tnc_started = 0; 186639beb93cSSam Leffler #endif /* EAP_TNC */ 186739beb93cSSam Leffler } 186839beb93cSSam Leffler 186939beb93cSSam Leffler 187039beb93cSSam Leffler static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) 187139beb93cSSam Leffler { 187239beb93cSSam Leffler struct eap_ttls_data *data = priv; 187339beb93cSSam Leffler os_free(data->key_data); 187439beb93cSSam Leffler data->key_data = NULL; 187539beb93cSSam Leffler if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 187639beb93cSSam Leffler os_free(data); 187739beb93cSSam Leffler return NULL; 187839beb93cSSam Leffler } 187939beb93cSSam Leffler if (data->phase2_priv && data->phase2_method && 188039beb93cSSam Leffler data->phase2_method->init_for_reauth) 188139beb93cSSam Leffler data->phase2_method->init_for_reauth(sm, data->phase2_priv); 188239beb93cSSam Leffler data->phase2_start = 0; 188339beb93cSSam Leffler data->phase2_success = 0; 188439beb93cSSam Leffler data->resuming = 1; 188539beb93cSSam Leffler data->reauth = 1; 188639beb93cSSam Leffler return priv; 188739beb93cSSam Leffler } 188839beb93cSSam Leffler 188939beb93cSSam Leffler 189039beb93cSSam Leffler static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, 189139beb93cSSam Leffler size_t buflen, int verbose) 189239beb93cSSam Leffler { 189339beb93cSSam Leffler struct eap_ttls_data *data = priv; 189439beb93cSSam Leffler int len, ret; 189539beb93cSSam Leffler 189639beb93cSSam Leffler len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 189739beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, 189839beb93cSSam Leffler "EAP-TTLSv%d Phase2 method=", 189939beb93cSSam Leffler data->ttls_version); 190039beb93cSSam Leffler if (ret < 0 || (size_t) ret >= buflen - len) 190139beb93cSSam Leffler return len; 190239beb93cSSam Leffler len += ret; 190339beb93cSSam Leffler switch (data->phase2_type) { 190439beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 190539beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", 190639beb93cSSam Leffler data->phase2_method ? 190739beb93cSSam Leffler data->phase2_method->name : "?"); 190839beb93cSSam Leffler break; 190939beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 191039beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); 191139beb93cSSam Leffler break; 191239beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 191339beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); 191439beb93cSSam Leffler break; 191539beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 191639beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "PAP\n"); 191739beb93cSSam Leffler break; 191839beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 191939beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); 192039beb93cSSam Leffler break; 192139beb93cSSam Leffler default: 192239beb93cSSam Leffler ret = 0; 192339beb93cSSam Leffler break; 192439beb93cSSam Leffler } 192539beb93cSSam Leffler if (ret < 0 || (size_t) ret >= buflen - len) 192639beb93cSSam Leffler return len; 192739beb93cSSam Leffler len += ret; 192839beb93cSSam Leffler 192939beb93cSSam Leffler return len; 193039beb93cSSam Leffler } 193139beb93cSSam Leffler 193239beb93cSSam Leffler 193339beb93cSSam Leffler static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) 193439beb93cSSam Leffler { 193539beb93cSSam Leffler struct eap_ttls_data *data = priv; 193639beb93cSSam Leffler return data->key_data != NULL && data->phase2_success; 193739beb93cSSam Leffler } 193839beb93cSSam Leffler 193939beb93cSSam Leffler 194039beb93cSSam Leffler static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) 194139beb93cSSam Leffler { 194239beb93cSSam Leffler struct eap_ttls_data *data = priv; 194339beb93cSSam Leffler u8 *key; 194439beb93cSSam Leffler 194539beb93cSSam Leffler if (data->key_data == NULL || !data->phase2_success) 194639beb93cSSam Leffler return NULL; 194739beb93cSSam Leffler 194839beb93cSSam Leffler key = os_malloc(EAP_TLS_KEY_LEN); 194939beb93cSSam Leffler if (key == NULL) 195039beb93cSSam Leffler return NULL; 195139beb93cSSam Leffler 195239beb93cSSam Leffler *len = EAP_TLS_KEY_LEN; 195339beb93cSSam Leffler os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); 195439beb93cSSam Leffler 195539beb93cSSam Leffler return key; 195639beb93cSSam Leffler } 195739beb93cSSam Leffler 195839beb93cSSam Leffler 195939beb93cSSam Leffler int eap_peer_ttls_register(void) 196039beb93cSSam Leffler { 196139beb93cSSam Leffler struct eap_method *eap; 196239beb93cSSam Leffler int ret; 196339beb93cSSam Leffler 196439beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 196539beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); 196639beb93cSSam Leffler if (eap == NULL) 196739beb93cSSam Leffler return -1; 196839beb93cSSam Leffler 196939beb93cSSam Leffler eap->init = eap_ttls_init; 197039beb93cSSam Leffler eap->deinit = eap_ttls_deinit; 197139beb93cSSam Leffler eap->process = eap_ttls_process; 197239beb93cSSam Leffler eap->isKeyAvailable = eap_ttls_isKeyAvailable; 197339beb93cSSam Leffler eap->getKey = eap_ttls_getKey; 197439beb93cSSam Leffler eap->get_status = eap_ttls_get_status; 197539beb93cSSam Leffler eap->has_reauth_data = eap_ttls_has_reauth_data; 197639beb93cSSam Leffler eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; 197739beb93cSSam Leffler eap->init_for_reauth = eap_ttls_init_for_reauth; 197839beb93cSSam Leffler 197939beb93cSSam Leffler ret = eap_peer_method_register(eap); 198039beb93cSSam Leffler if (ret) 198139beb93cSSam Leffler eap_peer_method_free(eap); 198239beb93cSSam Leffler return ret; 198339beb93cSSam Leffler } 1984