139beb93cSSam Leffler /* 239beb93cSSam Leffler * EAP peer method: EAP-TTLS (RFC 5281) 3f05cddf9SRui Paulo * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 12e28a4053SRui Paulo #include "crypto/ms_funcs.h" 13e28a4053SRui Paulo #include "crypto/sha1.h" 14e28a4053SRui Paulo #include "crypto/tls.h" 1539beb93cSSam Leffler #include "eap_common/chap.h" 1639beb93cSSam Leffler #include "eap_common/eap_ttls.h" 17e28a4053SRui Paulo #include "mschapv2.h" 18e28a4053SRui Paulo #include "eap_i.h" 19e28a4053SRui Paulo #include "eap_tls_common.h" 20e28a4053SRui Paulo #include "eap_config.h" 2139beb93cSSam Leffler 2239beb93cSSam Leffler 23f05cddf9SRui Paulo #define EAP_TTLS_VERSION 0 2439beb93cSSam Leffler 2539beb93cSSam Leffler 2639beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv); 2739beb93cSSam Leffler 2839beb93cSSam Leffler 2939beb93cSSam Leffler struct eap_ttls_data { 3039beb93cSSam Leffler struct eap_ssl_data ssl; 3139beb93cSSam Leffler 32f05cddf9SRui Paulo int ttls_version; 3339beb93cSSam Leffler 3439beb93cSSam Leffler const struct eap_method *phase2_method; 3539beb93cSSam Leffler void *phase2_priv; 3639beb93cSSam Leffler int phase2_success; 3739beb93cSSam Leffler int phase2_start; 3839beb93cSSam Leffler 3939beb93cSSam Leffler enum phase2_types { 4039beb93cSSam Leffler EAP_TTLS_PHASE2_EAP, 4139beb93cSSam Leffler EAP_TTLS_PHASE2_MSCHAPV2, 4239beb93cSSam Leffler EAP_TTLS_PHASE2_MSCHAP, 4339beb93cSSam Leffler EAP_TTLS_PHASE2_PAP, 4439beb93cSSam Leffler EAP_TTLS_PHASE2_CHAP 4539beb93cSSam Leffler } phase2_type; 4639beb93cSSam Leffler struct eap_method_type phase2_eap_type; 4739beb93cSSam Leffler struct eap_method_type *phase2_eap_types; 4839beb93cSSam Leffler size_t num_phase2_eap_types; 4939beb93cSSam Leffler 5039beb93cSSam Leffler u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; 5139beb93cSSam Leffler int auth_response_valid; 5239beb93cSSam Leffler u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ 5339beb93cSSam Leffler u8 ident; 5439beb93cSSam Leffler int resuming; /* starting a resumed session */ 5539beb93cSSam Leffler int reauth; /* reauthentication */ 5639beb93cSSam Leffler u8 *key_data; 575b9c547cSRui Paulo u8 *session_id; 585b9c547cSRui Paulo size_t id_len; 5939beb93cSSam Leffler 6039beb93cSSam Leffler struct wpabuf *pending_phase2_req; 6139beb93cSSam Leffler 6239beb93cSSam Leffler #ifdef EAP_TNC 6339beb93cSSam Leffler int ready_for_tnc; 6439beb93cSSam Leffler int tnc_started; 6539beb93cSSam Leffler #endif /* EAP_TNC */ 6639beb93cSSam Leffler }; 6739beb93cSSam Leffler 6839beb93cSSam Leffler 6939beb93cSSam Leffler static void * eap_ttls_init(struct eap_sm *sm) 7039beb93cSSam Leffler { 7139beb93cSSam Leffler struct eap_ttls_data *data; 7239beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 7339beb93cSSam Leffler char *selected; 7439beb93cSSam Leffler 7539beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 7639beb93cSSam Leffler if (data == NULL) 7739beb93cSSam Leffler return NULL; 7839beb93cSSam Leffler data->ttls_version = EAP_TTLS_VERSION; 7939beb93cSSam Leffler selected = "EAP"; 8039beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_EAP; 8139beb93cSSam Leffler 8239beb93cSSam Leffler if (config && config->phase2) { 8339beb93cSSam Leffler if (os_strstr(config->phase2, "autheap=")) { 8439beb93cSSam Leffler selected = "EAP"; 8539beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_EAP; 8639beb93cSSam Leffler } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { 8739beb93cSSam Leffler selected = "MSCHAPV2"; 8839beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; 8939beb93cSSam Leffler } else if (os_strstr(config->phase2, "auth=MSCHAP")) { 9039beb93cSSam Leffler selected = "MSCHAP"; 9139beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; 9239beb93cSSam Leffler } else if (os_strstr(config->phase2, "auth=PAP")) { 9339beb93cSSam Leffler selected = "PAP"; 9439beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_PAP; 9539beb93cSSam Leffler } else if (os_strstr(config->phase2, "auth=CHAP")) { 9639beb93cSSam Leffler selected = "CHAP"; 9739beb93cSSam Leffler data->phase2_type = EAP_TTLS_PHASE2_CHAP; 9839beb93cSSam Leffler } 9939beb93cSSam Leffler } 10039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); 10139beb93cSSam Leffler 10239beb93cSSam Leffler if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { 10339beb93cSSam Leffler if (eap_peer_select_phase2_methods(config, "autheap=", 10439beb93cSSam Leffler &data->phase2_eap_types, 10539beb93cSSam Leffler &data->num_phase2_eap_types) 10639beb93cSSam Leffler < 0) { 10739beb93cSSam Leffler eap_ttls_deinit(sm, data); 10839beb93cSSam Leffler return NULL; 10939beb93cSSam Leffler } 11039beb93cSSam Leffler 11139beb93cSSam Leffler data->phase2_eap_type.vendor = EAP_VENDOR_IETF; 11239beb93cSSam Leffler data->phase2_eap_type.method = EAP_TYPE_NONE; 11339beb93cSSam Leffler } 11439beb93cSSam Leffler 115f05cddf9SRui Paulo if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) { 116f05cddf9SRui Paulo wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); 11739beb93cSSam Leffler eap_ttls_deinit(sm, data); 11839beb93cSSam Leffler return NULL; 11939beb93cSSam Leffler } 12039beb93cSSam Leffler 12139beb93cSSam Leffler return data; 12239beb93cSSam Leffler } 12339beb93cSSam Leffler 12439beb93cSSam Leffler 12539beb93cSSam Leffler static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, 12639beb93cSSam Leffler struct eap_ttls_data *data) 12739beb93cSSam Leffler { 12839beb93cSSam Leffler if (data->phase2_priv && data->phase2_method) { 12939beb93cSSam Leffler data->phase2_method->deinit(sm, data->phase2_priv); 13039beb93cSSam Leffler data->phase2_method = NULL; 13139beb93cSSam Leffler data->phase2_priv = NULL; 13239beb93cSSam Leffler } 13339beb93cSSam Leffler } 13439beb93cSSam Leffler 13539beb93cSSam Leffler 1365b9c547cSRui Paulo static void eap_ttls_free_key(struct eap_ttls_data *data) 1375b9c547cSRui Paulo { 1385b9c547cSRui Paulo if (data->key_data) { 1395b9c547cSRui Paulo bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 1405b9c547cSRui Paulo data->key_data = NULL; 1415b9c547cSRui Paulo } 1425b9c547cSRui Paulo } 1435b9c547cSRui Paulo 1445b9c547cSRui Paulo 14539beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv) 14639beb93cSSam Leffler { 14739beb93cSSam Leffler struct eap_ttls_data *data = priv; 14839beb93cSSam Leffler if (data == NULL) 14939beb93cSSam Leffler return; 15039beb93cSSam Leffler eap_ttls_phase2_eap_deinit(sm, data); 15139beb93cSSam Leffler os_free(data->phase2_eap_types); 15239beb93cSSam Leffler eap_peer_tls_ssl_deinit(sm, &data->ssl); 1535b9c547cSRui Paulo eap_ttls_free_key(data); 1545b9c547cSRui Paulo os_free(data->session_id); 15539beb93cSSam Leffler wpabuf_free(data->pending_phase2_req); 15639beb93cSSam Leffler os_free(data); 15739beb93cSSam Leffler } 15839beb93cSSam Leffler 15939beb93cSSam Leffler 16039beb93cSSam Leffler static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, 16139beb93cSSam Leffler int mandatory, size_t len) 16239beb93cSSam Leffler { 16339beb93cSSam Leffler struct ttls_avp_vendor *avp; 16439beb93cSSam Leffler u8 flags; 16539beb93cSSam Leffler size_t hdrlen; 16639beb93cSSam Leffler 16739beb93cSSam Leffler avp = (struct ttls_avp_vendor *) avphdr; 16839beb93cSSam Leffler flags = mandatory ? AVP_FLAGS_MANDATORY : 0; 16939beb93cSSam Leffler if (vendor_id) { 17039beb93cSSam Leffler flags |= AVP_FLAGS_VENDOR; 17139beb93cSSam Leffler hdrlen = sizeof(*avp); 17239beb93cSSam Leffler avp->vendor_id = host_to_be32(vendor_id); 17339beb93cSSam Leffler } else { 17439beb93cSSam Leffler hdrlen = sizeof(struct ttls_avp); 17539beb93cSSam Leffler } 17639beb93cSSam Leffler 17739beb93cSSam Leffler avp->avp_code = host_to_be32(avp_code); 178*325151a3SRui Paulo avp->avp_length = host_to_be32(((u32) flags << 24) | 179*325151a3SRui Paulo (u32) (hdrlen + len)); 18039beb93cSSam Leffler 18139beb93cSSam Leffler return avphdr + hdrlen; 18239beb93cSSam Leffler } 18339beb93cSSam Leffler 18439beb93cSSam Leffler 18539beb93cSSam Leffler static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, 18639beb93cSSam Leffler u32 vendor_id, int mandatory, 18739beb93cSSam Leffler const u8 *data, size_t len) 18839beb93cSSam Leffler { 18939beb93cSSam Leffler u8 *pos; 19039beb93cSSam Leffler pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); 19139beb93cSSam Leffler os_memcpy(pos, data, len); 19239beb93cSSam Leffler pos += len; 19339beb93cSSam Leffler AVP_PAD(start, pos); 19439beb93cSSam Leffler return pos; 19539beb93cSSam Leffler } 19639beb93cSSam Leffler 19739beb93cSSam Leffler 19839beb93cSSam Leffler static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, 19939beb93cSSam Leffler int mandatory) 20039beb93cSSam Leffler { 20139beb93cSSam Leffler struct wpabuf *msg; 20239beb93cSSam Leffler u8 *avp, *pos; 20339beb93cSSam Leffler 20439beb93cSSam Leffler msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); 20539beb93cSSam Leffler if (msg == NULL) { 20639beb93cSSam Leffler wpabuf_free(*resp); 20739beb93cSSam Leffler *resp = NULL; 20839beb93cSSam Leffler return -1; 20939beb93cSSam Leffler } 21039beb93cSSam Leffler 21139beb93cSSam Leffler avp = wpabuf_mhead(msg); 21239beb93cSSam Leffler pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); 21339beb93cSSam Leffler os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); 21439beb93cSSam Leffler pos += wpabuf_len(*resp); 21539beb93cSSam Leffler AVP_PAD(avp, pos); 21639beb93cSSam Leffler wpabuf_free(*resp); 21739beb93cSSam Leffler wpabuf_put(msg, pos - avp); 21839beb93cSSam Leffler *resp = msg; 21939beb93cSSam Leffler return 0; 22039beb93cSSam Leffler } 22139beb93cSSam Leffler 22239beb93cSSam Leffler 22339beb93cSSam Leffler static int eap_ttls_v0_derive_key(struct eap_sm *sm, 22439beb93cSSam Leffler struct eap_ttls_data *data) 22539beb93cSSam Leffler { 2265b9c547cSRui Paulo eap_ttls_free_key(data); 22739beb93cSSam Leffler data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, 22839beb93cSSam Leffler "ttls keying material", 2295b9c547cSRui Paulo EAP_TLS_KEY_LEN + 2305b9c547cSRui Paulo EAP_EMSK_LEN); 23139beb93cSSam Leffler if (!data->key_data) { 23239beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); 23339beb93cSSam Leffler return -1; 23439beb93cSSam Leffler } 23539beb93cSSam Leffler 23639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", 23739beb93cSSam Leffler data->key_data, EAP_TLS_KEY_LEN); 2385b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK", 2395b9c547cSRui Paulo data->key_data + EAP_TLS_KEY_LEN, 2405b9c547cSRui Paulo EAP_EMSK_LEN); 2415b9c547cSRui Paulo 2425b9c547cSRui Paulo os_free(data->session_id); 2435b9c547cSRui Paulo data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, 2445b9c547cSRui Paulo EAP_TYPE_TTLS, 2455b9c547cSRui Paulo &data->id_len); 2465b9c547cSRui Paulo if (data->session_id) { 2475b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id", 2485b9c547cSRui Paulo data->session_id, data->id_len); 2495b9c547cSRui Paulo } else { 2505b9c547cSRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id"); 2515b9c547cSRui Paulo } 25239beb93cSSam Leffler 25339beb93cSSam Leffler return 0; 25439beb93cSSam Leffler } 25539beb93cSSam Leffler 25639beb93cSSam Leffler 257*325151a3SRui Paulo #ifndef CONFIG_FIPS 25839beb93cSSam Leffler static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, 25939beb93cSSam Leffler struct eap_ttls_data *data, size_t len) 26039beb93cSSam Leffler { 261f05cddf9SRui Paulo return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); 26239beb93cSSam Leffler } 263*325151a3SRui Paulo #endif /* CONFIG_FIPS */ 26439beb93cSSam Leffler 26539beb93cSSam Leffler 26639beb93cSSam Leffler static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, 26739beb93cSSam Leffler u8 method) 26839beb93cSSam Leffler { 26939beb93cSSam Leffler size_t i; 27039beb93cSSam Leffler for (i = 0; i < data->num_phase2_eap_types; i++) { 27139beb93cSSam Leffler if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || 27239beb93cSSam Leffler data->phase2_eap_types[i].method != method) 27339beb93cSSam Leffler continue; 27439beb93cSSam Leffler 27539beb93cSSam Leffler data->phase2_eap_type.vendor = 27639beb93cSSam Leffler data->phase2_eap_types[i].vendor; 27739beb93cSSam Leffler data->phase2_eap_type.method = 27839beb93cSSam Leffler data->phase2_eap_types[i].method; 27939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " 28039beb93cSSam Leffler "Phase 2 EAP vendor %d method %d", 28139beb93cSSam Leffler data->phase2_eap_type.vendor, 28239beb93cSSam Leffler data->phase2_eap_type.method); 28339beb93cSSam Leffler break; 28439beb93cSSam Leffler } 28539beb93cSSam Leffler } 28639beb93cSSam Leffler 28739beb93cSSam Leffler 28839beb93cSSam Leffler static int eap_ttls_phase2_eap_process(struct eap_sm *sm, 28939beb93cSSam Leffler struct eap_ttls_data *data, 29039beb93cSSam Leffler struct eap_method_ret *ret, 29139beb93cSSam Leffler struct eap_hdr *hdr, size_t len, 29239beb93cSSam Leffler struct wpabuf **resp) 29339beb93cSSam Leffler { 29439beb93cSSam Leffler struct wpabuf msg; 29539beb93cSSam Leffler struct eap_method_ret iret; 29639beb93cSSam Leffler 29739beb93cSSam Leffler os_memset(&iret, 0, sizeof(iret)); 29839beb93cSSam Leffler wpabuf_set(&msg, hdr, len); 29939beb93cSSam Leffler *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, 30039beb93cSSam Leffler &msg); 30139beb93cSSam Leffler if ((iret.methodState == METHOD_DONE || 30239beb93cSSam Leffler iret.methodState == METHOD_MAY_CONT) && 30339beb93cSSam Leffler (iret.decision == DECISION_UNCOND_SUCC || 30439beb93cSSam Leffler iret.decision == DECISION_COND_SUCC || 30539beb93cSSam Leffler iret.decision == DECISION_FAIL)) { 30639beb93cSSam Leffler ret->methodState = iret.methodState; 30739beb93cSSam Leffler ret->decision = iret.decision; 30839beb93cSSam Leffler } 30939beb93cSSam Leffler 31039beb93cSSam Leffler return 0; 31139beb93cSSam Leffler } 31239beb93cSSam Leffler 31339beb93cSSam Leffler 31439beb93cSSam Leffler static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, 31539beb93cSSam Leffler struct eap_ttls_data *data, 31639beb93cSSam Leffler struct eap_method_ret *ret, 31739beb93cSSam Leffler struct eap_hdr *hdr, size_t len, 31839beb93cSSam Leffler u8 method, struct wpabuf **resp) 31939beb93cSSam Leffler { 32039beb93cSSam Leffler #ifdef EAP_TNC 32139beb93cSSam Leffler if (data->tnc_started && data->phase2_method && 32239beb93cSSam Leffler data->phase2_priv && method == EAP_TYPE_TNC && 32339beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_TNC) 32439beb93cSSam Leffler return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, 32539beb93cSSam Leffler resp); 32639beb93cSSam Leffler 32739beb93cSSam Leffler if (data->ready_for_tnc && !data->tnc_started && 32839beb93cSSam Leffler method == EAP_TYPE_TNC) { 32939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " 33039beb93cSSam Leffler "EAP method"); 33139beb93cSSam Leffler data->tnc_started = 1; 33239beb93cSSam Leffler } 33339beb93cSSam Leffler 33439beb93cSSam Leffler if (data->tnc_started) { 33539beb93cSSam Leffler if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || 33639beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_TNC) { 33739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP " 33839beb93cSSam Leffler "type %d for TNC", method); 33939beb93cSSam Leffler return -1; 34039beb93cSSam Leffler } 34139beb93cSSam Leffler 34239beb93cSSam Leffler data->phase2_eap_type.vendor = EAP_VENDOR_IETF; 34339beb93cSSam Leffler data->phase2_eap_type.method = method; 34439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " 34539beb93cSSam Leffler "Phase 2 EAP vendor %d method %d (TNC)", 34639beb93cSSam Leffler data->phase2_eap_type.vendor, 34739beb93cSSam Leffler data->phase2_eap_type.method); 34839beb93cSSam Leffler 34939beb93cSSam Leffler if (data->phase2_type == EAP_TTLS_PHASE2_EAP) 35039beb93cSSam Leffler eap_ttls_phase2_eap_deinit(sm, data); 35139beb93cSSam Leffler } 35239beb93cSSam Leffler #endif /* EAP_TNC */ 35339beb93cSSam Leffler 35439beb93cSSam Leffler if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && 35539beb93cSSam Leffler data->phase2_eap_type.method == EAP_TYPE_NONE) 35639beb93cSSam Leffler eap_ttls_phase2_select_eap_method(data, method); 35739beb93cSSam Leffler 35839beb93cSSam Leffler if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) 35939beb93cSSam Leffler { 36039beb93cSSam Leffler if (eap_peer_tls_phase2_nak(data->phase2_eap_types, 36139beb93cSSam Leffler data->num_phase2_eap_types, 36239beb93cSSam Leffler hdr, resp)) 36339beb93cSSam Leffler return -1; 36439beb93cSSam Leffler return 0; 36539beb93cSSam Leffler } 36639beb93cSSam Leffler 36739beb93cSSam Leffler if (data->phase2_priv == NULL) { 36839beb93cSSam Leffler data->phase2_method = eap_peer_get_eap_method( 36939beb93cSSam Leffler EAP_VENDOR_IETF, method); 37039beb93cSSam Leffler if (data->phase2_method) { 37139beb93cSSam Leffler sm->init_phase2 = 1; 37239beb93cSSam Leffler data->phase2_priv = data->phase2_method->init(sm); 37339beb93cSSam Leffler sm->init_phase2 = 0; 37439beb93cSSam Leffler } 37539beb93cSSam Leffler } 37639beb93cSSam Leffler if (data->phase2_priv == NULL || data->phase2_method == NULL) { 37739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " 37839beb93cSSam Leffler "Phase 2 EAP method %d", method); 37939beb93cSSam Leffler return -1; 38039beb93cSSam Leffler } 38139beb93cSSam Leffler 38239beb93cSSam Leffler return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); 38339beb93cSSam Leffler } 38439beb93cSSam Leffler 38539beb93cSSam Leffler 38639beb93cSSam Leffler static int eap_ttls_phase2_request_eap(struct eap_sm *sm, 38739beb93cSSam Leffler struct eap_ttls_data *data, 38839beb93cSSam Leffler struct eap_method_ret *ret, 38939beb93cSSam Leffler struct eap_hdr *hdr, 39039beb93cSSam Leffler struct wpabuf **resp) 39139beb93cSSam Leffler { 39239beb93cSSam Leffler size_t len = be_to_host16(hdr->length); 39339beb93cSSam Leffler u8 *pos; 39439beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 39539beb93cSSam Leffler 39639beb93cSSam Leffler if (len <= sizeof(struct eap_hdr)) { 39739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: too short " 39839beb93cSSam Leffler "Phase 2 request (len=%lu)", (unsigned long) len); 39939beb93cSSam Leffler return -1; 40039beb93cSSam Leffler } 40139beb93cSSam Leffler pos = (u8 *) (hdr + 1); 40239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); 40339beb93cSSam Leffler switch (*pos) { 40439beb93cSSam Leffler case EAP_TYPE_IDENTITY: 40539beb93cSSam Leffler *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); 40639beb93cSSam Leffler break; 40739beb93cSSam Leffler default: 40839beb93cSSam Leffler if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, 40939beb93cSSam Leffler *pos, resp) < 0) 41039beb93cSSam Leffler return -1; 41139beb93cSSam Leffler break; 41239beb93cSSam Leffler } 41339beb93cSSam Leffler 41439beb93cSSam Leffler if (*resp == NULL && 41539beb93cSSam Leffler (config->pending_req_identity || config->pending_req_password || 41639beb93cSSam Leffler config->pending_req_otp)) { 41739beb93cSSam Leffler return 0; 41839beb93cSSam Leffler } 41939beb93cSSam Leffler 42039beb93cSSam Leffler if (*resp == NULL) 42139beb93cSSam Leffler return -1; 42239beb93cSSam Leffler 42339beb93cSSam Leffler wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", 42439beb93cSSam Leffler *resp); 42539beb93cSSam Leffler return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); 42639beb93cSSam Leffler } 42739beb93cSSam Leffler 42839beb93cSSam Leffler 42939beb93cSSam Leffler static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, 43039beb93cSSam Leffler struct eap_ttls_data *data, 43139beb93cSSam Leffler struct eap_method_ret *ret, 43239beb93cSSam Leffler struct wpabuf **resp) 43339beb93cSSam Leffler { 434*325151a3SRui Paulo #ifdef CONFIG_FIPS 435*325151a3SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build"); 436*325151a3SRui Paulo return -1; 437*325151a3SRui Paulo #else /* CONFIG_FIPS */ 438f05cddf9SRui Paulo #ifdef EAP_MSCHAPv2 43939beb93cSSam Leffler struct wpabuf *msg; 44039beb93cSSam Leffler u8 *buf, *pos, *challenge, *peer_challenge; 44139beb93cSSam Leffler const u8 *identity, *password; 44239beb93cSSam Leffler size_t identity_len, password_len; 44339beb93cSSam Leffler int pwhash; 44439beb93cSSam Leffler 44539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); 44639beb93cSSam Leffler 44739beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 44839beb93cSSam Leffler password = eap_get_config_password2(sm, &password_len, &pwhash); 44939beb93cSSam Leffler if (identity == NULL || password == NULL) 45039beb93cSSam Leffler return -1; 45139beb93cSSam Leffler 45239beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 45339beb93cSSam Leffler if (msg == NULL) { 45439beb93cSSam Leffler wpa_printf(MSG_ERROR, 45539beb93cSSam Leffler "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); 45639beb93cSSam Leffler return -1; 45739beb93cSSam Leffler } 45839beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 45939beb93cSSam Leffler 46039beb93cSSam Leffler /* User-Name */ 46139beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 46239beb93cSSam Leffler identity, identity_len); 46339beb93cSSam Leffler 46439beb93cSSam Leffler /* MS-CHAP-Challenge */ 46539beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 46639beb93cSSam Leffler sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); 46739beb93cSSam Leffler if (challenge == NULL) { 46839beb93cSSam Leffler wpabuf_free(msg); 46939beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " 47039beb93cSSam Leffler "implicit challenge"); 47139beb93cSSam Leffler return -1; 47239beb93cSSam Leffler } 47339beb93cSSam Leffler 47439beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, 47539beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 47639beb93cSSam Leffler challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); 47739beb93cSSam Leffler 47839beb93cSSam Leffler /* MS-CHAP2-Response */ 47939beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, 48039beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 48139beb93cSSam Leffler EAP_TTLS_MSCHAPV2_RESPONSE_LEN); 48239beb93cSSam Leffler data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; 48339beb93cSSam Leffler *pos++ = data->ident; 48439beb93cSSam Leffler *pos++ = 0; /* Flags */ 485f05cddf9SRui Paulo if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) { 486f05cddf9SRui Paulo os_free(challenge); 487f05cddf9SRui Paulo wpabuf_free(msg); 488f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get " 489f05cddf9SRui Paulo "random data for peer challenge"); 490f05cddf9SRui Paulo return -1; 491f05cddf9SRui Paulo } 492f05cddf9SRui Paulo peer_challenge = pos; 49339beb93cSSam Leffler pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; 49439beb93cSSam Leffler os_memset(pos, 0, 8); /* Reserved, must be zero */ 49539beb93cSSam Leffler pos += 8; 496e28a4053SRui Paulo if (mschapv2_derive_response(identity, identity_len, password, 49739beb93cSSam Leffler password_len, pwhash, challenge, 49839beb93cSSam Leffler peer_challenge, pos, data->auth_response, 499e28a4053SRui Paulo data->master_key)) { 500f05cddf9SRui Paulo os_free(challenge); 501e28a4053SRui Paulo wpabuf_free(msg); 502e28a4053SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " 503e28a4053SRui Paulo "response"); 504e28a4053SRui Paulo return -1; 505e28a4053SRui Paulo } 50639beb93cSSam Leffler data->auth_response_valid = 1; 50739beb93cSSam Leffler 50839beb93cSSam Leffler pos += 24; 50939beb93cSSam Leffler os_free(challenge); 51039beb93cSSam Leffler AVP_PAD(buf, pos); 51139beb93cSSam Leffler 51239beb93cSSam Leffler wpabuf_put(msg, pos - buf); 51339beb93cSSam Leffler *resp = msg; 51439beb93cSSam Leffler 51539beb93cSSam Leffler return 0; 516f05cddf9SRui Paulo #else /* EAP_MSCHAPv2 */ 517f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); 518f05cddf9SRui Paulo return -1; 519f05cddf9SRui Paulo #endif /* EAP_MSCHAPv2 */ 520*325151a3SRui Paulo #endif /* CONFIG_FIPS */ 52139beb93cSSam Leffler } 52239beb93cSSam Leffler 52339beb93cSSam Leffler 52439beb93cSSam Leffler static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, 52539beb93cSSam Leffler struct eap_ttls_data *data, 52639beb93cSSam Leffler struct eap_method_ret *ret, 52739beb93cSSam Leffler struct wpabuf **resp) 52839beb93cSSam Leffler { 529*325151a3SRui Paulo #ifdef CONFIG_FIPS 530*325151a3SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build"); 531*325151a3SRui Paulo return -1; 532*325151a3SRui Paulo #else /* CONFIG_FIPS */ 53339beb93cSSam Leffler struct wpabuf *msg; 53439beb93cSSam Leffler u8 *buf, *pos, *challenge; 53539beb93cSSam Leffler const u8 *identity, *password; 53639beb93cSSam Leffler size_t identity_len, password_len; 53739beb93cSSam Leffler int pwhash; 53839beb93cSSam Leffler 53939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); 54039beb93cSSam Leffler 54139beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 54239beb93cSSam Leffler password = eap_get_config_password2(sm, &password_len, &pwhash); 54339beb93cSSam Leffler if (identity == NULL || password == NULL) 54439beb93cSSam Leffler return -1; 54539beb93cSSam Leffler 54639beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 54739beb93cSSam Leffler if (msg == NULL) { 54839beb93cSSam Leffler wpa_printf(MSG_ERROR, 54939beb93cSSam Leffler "EAP-TTLS/MSCHAP: Failed to allocate memory"); 55039beb93cSSam Leffler return -1; 55139beb93cSSam Leffler } 55239beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 55339beb93cSSam Leffler 55439beb93cSSam Leffler /* User-Name */ 55539beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 55639beb93cSSam Leffler identity, identity_len); 55739beb93cSSam Leffler 55839beb93cSSam Leffler /* MS-CHAP-Challenge */ 55939beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 56039beb93cSSam Leffler sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); 56139beb93cSSam Leffler if (challenge == NULL) { 56239beb93cSSam Leffler wpabuf_free(msg); 56339beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " 56439beb93cSSam Leffler "implicit challenge"); 56539beb93cSSam Leffler return -1; 56639beb93cSSam Leffler } 56739beb93cSSam Leffler 56839beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, 56939beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 57039beb93cSSam Leffler challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); 57139beb93cSSam Leffler 57239beb93cSSam Leffler /* MS-CHAP-Response */ 57339beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, 57439beb93cSSam Leffler RADIUS_VENDOR_ID_MICROSOFT, 1, 57539beb93cSSam Leffler EAP_TTLS_MSCHAP_RESPONSE_LEN); 57639beb93cSSam Leffler data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; 57739beb93cSSam Leffler *pos++ = data->ident; 57839beb93cSSam Leffler *pos++ = 1; /* Flags: Use NT style passwords */ 57939beb93cSSam Leffler os_memset(pos, 0, 24); /* LM-Response */ 58039beb93cSSam Leffler pos += 24; 58139beb93cSSam Leffler if (pwhash) { 58239beb93cSSam Leffler challenge_response(challenge, password, pos); /* NT-Response */ 58339beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", 58439beb93cSSam Leffler password, 16); 58539beb93cSSam Leffler } else { 58639beb93cSSam Leffler nt_challenge_response(challenge, password, password_len, 58739beb93cSSam Leffler pos); /* NT-Response */ 58839beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", 58939beb93cSSam Leffler password, password_len); 59039beb93cSSam Leffler } 59139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", 59239beb93cSSam Leffler challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); 59339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); 59439beb93cSSam Leffler pos += 24; 59539beb93cSSam Leffler os_free(challenge); 59639beb93cSSam Leffler AVP_PAD(buf, pos); 59739beb93cSSam Leffler 59839beb93cSSam Leffler wpabuf_put(msg, pos - buf); 59939beb93cSSam Leffler *resp = msg; 60039beb93cSSam Leffler 60139beb93cSSam Leffler /* EAP-TTLS/MSCHAP does not provide tunneled success 60239beb93cSSam Leffler * notification, so assume that Phase2 succeeds. */ 60339beb93cSSam Leffler ret->methodState = METHOD_DONE; 60439beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 60539beb93cSSam Leffler 60639beb93cSSam Leffler return 0; 607*325151a3SRui Paulo #endif /* CONFIG_FIPS */ 60839beb93cSSam Leffler } 60939beb93cSSam Leffler 61039beb93cSSam Leffler 61139beb93cSSam Leffler static int eap_ttls_phase2_request_pap(struct eap_sm *sm, 61239beb93cSSam Leffler struct eap_ttls_data *data, 61339beb93cSSam Leffler struct eap_method_ret *ret, 61439beb93cSSam Leffler struct wpabuf **resp) 61539beb93cSSam Leffler { 61639beb93cSSam Leffler struct wpabuf *msg; 61739beb93cSSam Leffler u8 *buf, *pos; 61839beb93cSSam Leffler size_t pad; 61939beb93cSSam Leffler const u8 *identity, *password; 62039beb93cSSam Leffler size_t identity_len, password_len; 62139beb93cSSam Leffler 62239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); 62339beb93cSSam Leffler 62439beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 62539beb93cSSam Leffler password = eap_get_config_password(sm, &password_len); 62639beb93cSSam Leffler if (identity == NULL || password == NULL) 62739beb93cSSam Leffler return -1; 62839beb93cSSam Leffler 62939beb93cSSam Leffler msg = wpabuf_alloc(identity_len + password_len + 100); 63039beb93cSSam Leffler if (msg == NULL) { 63139beb93cSSam Leffler wpa_printf(MSG_ERROR, 63239beb93cSSam Leffler "EAP-TTLS/PAP: Failed to allocate memory"); 63339beb93cSSam Leffler return -1; 63439beb93cSSam Leffler } 63539beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 63639beb93cSSam Leffler 63739beb93cSSam Leffler /* User-Name */ 63839beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 63939beb93cSSam Leffler identity, identity_len); 64039beb93cSSam Leffler 64139beb93cSSam Leffler /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts 64239beb93cSSam Leffler * the data, so no separate encryption is used in the AVP itself. 64339beb93cSSam Leffler * However, the password is padded to obfuscate its length. */ 6443157ba21SRui Paulo pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; 64539beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, 64639beb93cSSam Leffler password_len + pad); 64739beb93cSSam Leffler os_memcpy(pos, password, password_len); 64839beb93cSSam Leffler pos += password_len; 64939beb93cSSam Leffler os_memset(pos, 0, pad); 65039beb93cSSam Leffler pos += pad; 65139beb93cSSam Leffler AVP_PAD(buf, pos); 65239beb93cSSam Leffler 65339beb93cSSam Leffler wpabuf_put(msg, pos - buf); 65439beb93cSSam Leffler *resp = msg; 65539beb93cSSam Leffler 65639beb93cSSam Leffler /* EAP-TTLS/PAP does not provide tunneled success notification, 65739beb93cSSam Leffler * so assume that Phase2 succeeds. */ 65839beb93cSSam Leffler ret->methodState = METHOD_DONE; 65939beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 66039beb93cSSam Leffler 66139beb93cSSam Leffler return 0; 66239beb93cSSam Leffler } 66339beb93cSSam Leffler 66439beb93cSSam Leffler 66539beb93cSSam Leffler static int eap_ttls_phase2_request_chap(struct eap_sm *sm, 66639beb93cSSam Leffler struct eap_ttls_data *data, 66739beb93cSSam Leffler struct eap_method_ret *ret, 66839beb93cSSam Leffler struct wpabuf **resp) 66939beb93cSSam Leffler { 670*325151a3SRui Paulo #ifdef CONFIG_FIPS 671*325151a3SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build"); 672*325151a3SRui Paulo return -1; 673*325151a3SRui Paulo #else /* CONFIG_FIPS */ 67439beb93cSSam Leffler struct wpabuf *msg; 67539beb93cSSam Leffler u8 *buf, *pos, *challenge; 67639beb93cSSam Leffler const u8 *identity, *password; 67739beb93cSSam Leffler size_t identity_len, password_len; 67839beb93cSSam Leffler 67939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); 68039beb93cSSam Leffler 68139beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 68239beb93cSSam Leffler password = eap_get_config_password(sm, &password_len); 68339beb93cSSam Leffler if (identity == NULL || password == NULL) 68439beb93cSSam Leffler return -1; 68539beb93cSSam Leffler 68639beb93cSSam Leffler msg = wpabuf_alloc(identity_len + 1000); 68739beb93cSSam Leffler if (msg == NULL) { 68839beb93cSSam Leffler wpa_printf(MSG_ERROR, 68939beb93cSSam Leffler "EAP-TTLS/CHAP: Failed to allocate memory"); 69039beb93cSSam Leffler return -1; 69139beb93cSSam Leffler } 69239beb93cSSam Leffler pos = buf = wpabuf_mhead(msg); 69339beb93cSSam Leffler 69439beb93cSSam Leffler /* User-Name */ 69539beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 69639beb93cSSam Leffler identity, identity_len); 69739beb93cSSam Leffler 69839beb93cSSam Leffler /* CHAP-Challenge */ 69939beb93cSSam Leffler challenge = eap_ttls_implicit_challenge( 70039beb93cSSam Leffler sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); 70139beb93cSSam Leffler if (challenge == NULL) { 70239beb93cSSam Leffler wpabuf_free(msg); 70339beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " 70439beb93cSSam Leffler "implicit challenge"); 70539beb93cSSam Leffler return -1; 70639beb93cSSam Leffler } 70739beb93cSSam Leffler 70839beb93cSSam Leffler pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, 70939beb93cSSam Leffler challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); 71039beb93cSSam Leffler 71139beb93cSSam Leffler /* CHAP-Password */ 71239beb93cSSam Leffler pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, 71339beb93cSSam Leffler 1 + EAP_TTLS_CHAP_PASSWORD_LEN); 71439beb93cSSam Leffler data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; 71539beb93cSSam Leffler *pos++ = data->ident; 71639beb93cSSam Leffler 71739beb93cSSam Leffler /* MD5(Ident + Password + Challenge) */ 71839beb93cSSam Leffler chap_md5(data->ident, password, password_len, challenge, 71939beb93cSSam Leffler EAP_TTLS_CHAP_CHALLENGE_LEN, pos); 72039beb93cSSam Leffler 72139beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", 72239beb93cSSam Leffler identity, identity_len); 72339beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", 72439beb93cSSam Leffler password, password_len); 72539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", 72639beb93cSSam Leffler challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); 72739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", 72839beb93cSSam Leffler pos, EAP_TTLS_CHAP_PASSWORD_LEN); 72939beb93cSSam Leffler pos += EAP_TTLS_CHAP_PASSWORD_LEN; 73039beb93cSSam Leffler os_free(challenge); 73139beb93cSSam Leffler AVP_PAD(buf, pos); 73239beb93cSSam Leffler 73339beb93cSSam Leffler wpabuf_put(msg, pos - buf); 73439beb93cSSam Leffler *resp = msg; 73539beb93cSSam Leffler 73639beb93cSSam Leffler /* EAP-TTLS/CHAP does not provide tunneled success 73739beb93cSSam Leffler * notification, so assume that Phase2 succeeds. */ 73839beb93cSSam Leffler ret->methodState = METHOD_DONE; 73939beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 74039beb93cSSam Leffler 74139beb93cSSam Leffler return 0; 742*325151a3SRui Paulo #endif /* CONFIG_FIPS */ 74339beb93cSSam Leffler } 74439beb93cSSam Leffler 74539beb93cSSam Leffler 74639beb93cSSam Leffler static int eap_ttls_phase2_request(struct eap_sm *sm, 74739beb93cSSam Leffler struct eap_ttls_data *data, 74839beb93cSSam Leffler struct eap_method_ret *ret, 74939beb93cSSam Leffler struct eap_hdr *hdr, 75039beb93cSSam Leffler struct wpabuf **resp) 75139beb93cSSam Leffler { 75239beb93cSSam Leffler int res = 0; 75339beb93cSSam Leffler size_t len; 75439beb93cSSam Leffler enum phase2_types phase2_type = data->phase2_type; 75539beb93cSSam Leffler 75639beb93cSSam Leffler #ifdef EAP_TNC 75739beb93cSSam Leffler if (data->tnc_started) { 75839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); 75939beb93cSSam Leffler phase2_type = EAP_TTLS_PHASE2_EAP; 76039beb93cSSam Leffler } 76139beb93cSSam Leffler #endif /* EAP_TNC */ 76239beb93cSSam Leffler 76339beb93cSSam Leffler if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || 76439beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_MSCHAP || 76539beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_PAP || 76639beb93cSSam Leffler phase2_type == EAP_TTLS_PHASE2_CHAP) { 76739beb93cSSam Leffler if (eap_get_config_identity(sm, &len) == NULL) { 76839beb93cSSam Leffler wpa_printf(MSG_INFO, 76939beb93cSSam Leffler "EAP-TTLS: Identity not configured"); 77039beb93cSSam Leffler eap_sm_request_identity(sm); 77139beb93cSSam Leffler if (eap_get_config_password(sm, &len) == NULL) 77239beb93cSSam Leffler eap_sm_request_password(sm); 77339beb93cSSam Leffler return 0; 77439beb93cSSam Leffler } 77539beb93cSSam Leffler 77639beb93cSSam Leffler if (eap_get_config_password(sm, &len) == NULL) { 77739beb93cSSam Leffler wpa_printf(MSG_INFO, 77839beb93cSSam Leffler "EAP-TTLS: Password not configured"); 77939beb93cSSam Leffler eap_sm_request_password(sm); 78039beb93cSSam Leffler return 0; 78139beb93cSSam Leffler } 78239beb93cSSam Leffler } 78339beb93cSSam Leffler 78439beb93cSSam Leffler switch (phase2_type) { 78539beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 78639beb93cSSam Leffler res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); 78739beb93cSSam Leffler break; 78839beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 78939beb93cSSam Leffler res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); 79039beb93cSSam Leffler break; 79139beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 79239beb93cSSam Leffler res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); 79339beb93cSSam Leffler break; 79439beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 79539beb93cSSam Leffler res = eap_ttls_phase2_request_pap(sm, data, ret, resp); 79639beb93cSSam Leffler break; 79739beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 79839beb93cSSam Leffler res = eap_ttls_phase2_request_chap(sm, data, ret, resp); 79939beb93cSSam Leffler break; 80039beb93cSSam Leffler default: 80139beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); 80239beb93cSSam Leffler res = -1; 80339beb93cSSam Leffler break; 80439beb93cSSam Leffler } 80539beb93cSSam Leffler 80639beb93cSSam Leffler if (res < 0) { 80739beb93cSSam Leffler ret->methodState = METHOD_DONE; 80839beb93cSSam Leffler ret->decision = DECISION_FAIL; 80939beb93cSSam Leffler } 81039beb93cSSam Leffler 81139beb93cSSam Leffler return res; 81239beb93cSSam Leffler } 81339beb93cSSam Leffler 81439beb93cSSam Leffler 81539beb93cSSam Leffler struct ttls_parse_avp { 81639beb93cSSam Leffler u8 *mschapv2; 81739beb93cSSam Leffler u8 *eapdata; 81839beb93cSSam Leffler size_t eap_len; 81939beb93cSSam Leffler int mschapv2_error; 82039beb93cSSam Leffler }; 82139beb93cSSam Leffler 82239beb93cSSam Leffler 82339beb93cSSam Leffler static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, 82439beb93cSSam Leffler struct ttls_parse_avp *parse) 82539beb93cSSam Leffler { 82639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); 82739beb93cSSam Leffler if (parse->eapdata == NULL) { 82839beb93cSSam Leffler parse->eapdata = os_malloc(dlen); 82939beb93cSSam Leffler if (parse->eapdata == NULL) { 83039beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " 83139beb93cSSam Leffler "memory for Phase 2 EAP data"); 83239beb93cSSam Leffler return -1; 83339beb93cSSam Leffler } 83439beb93cSSam Leffler os_memcpy(parse->eapdata, dpos, dlen); 83539beb93cSSam Leffler parse->eap_len = dlen; 83639beb93cSSam Leffler } else { 83739beb93cSSam Leffler u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); 83839beb93cSSam Leffler if (neweap == NULL) { 83939beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " 84039beb93cSSam Leffler "memory for Phase 2 EAP data"); 84139beb93cSSam Leffler return -1; 84239beb93cSSam Leffler } 84339beb93cSSam Leffler os_memcpy(neweap + parse->eap_len, dpos, dlen); 84439beb93cSSam Leffler parse->eapdata = neweap; 84539beb93cSSam Leffler parse->eap_len += dlen; 84639beb93cSSam Leffler } 84739beb93cSSam Leffler 84839beb93cSSam Leffler return 0; 84939beb93cSSam Leffler } 85039beb93cSSam Leffler 85139beb93cSSam Leffler 85239beb93cSSam Leffler static int eap_ttls_parse_avp(u8 *pos, size_t left, 85339beb93cSSam Leffler struct ttls_parse_avp *parse) 85439beb93cSSam Leffler { 85539beb93cSSam Leffler struct ttls_avp *avp; 85639beb93cSSam Leffler u32 avp_code, avp_length, vendor_id = 0; 85739beb93cSSam Leffler u8 avp_flags, *dpos; 85839beb93cSSam Leffler size_t dlen; 85939beb93cSSam Leffler 86039beb93cSSam Leffler avp = (struct ttls_avp *) pos; 86139beb93cSSam Leffler avp_code = be_to_host32(avp->avp_code); 86239beb93cSSam Leffler avp_length = be_to_host32(avp->avp_length); 86339beb93cSSam Leffler avp_flags = (avp_length >> 24) & 0xff; 86439beb93cSSam Leffler avp_length &= 0xffffff; 86539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " 86639beb93cSSam Leffler "length=%d", (int) avp_code, avp_flags, 86739beb93cSSam Leffler (int) avp_length); 86839beb93cSSam Leffler 86939beb93cSSam Leffler if (avp_length > left) { 87039beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " 87139beb93cSSam Leffler "(len=%d, left=%lu) - dropped", 87239beb93cSSam Leffler (int) avp_length, (unsigned long) left); 87339beb93cSSam Leffler return -1; 87439beb93cSSam Leffler } 87539beb93cSSam Leffler 87639beb93cSSam Leffler if (avp_length < sizeof(*avp)) { 87739beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", 87839beb93cSSam Leffler avp_length); 87939beb93cSSam Leffler return -1; 88039beb93cSSam Leffler } 88139beb93cSSam Leffler 88239beb93cSSam Leffler dpos = (u8 *) (avp + 1); 88339beb93cSSam Leffler dlen = avp_length - sizeof(*avp); 88439beb93cSSam Leffler if (avp_flags & AVP_FLAGS_VENDOR) { 88539beb93cSSam Leffler if (dlen < 4) { 88639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP " 88739beb93cSSam Leffler "underflow"); 88839beb93cSSam Leffler return -1; 88939beb93cSSam Leffler } 89039beb93cSSam Leffler vendor_id = WPA_GET_BE32(dpos); 89139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", 89239beb93cSSam Leffler (int) vendor_id); 89339beb93cSSam Leffler dpos += 4; 89439beb93cSSam Leffler dlen -= 4; 89539beb93cSSam Leffler } 89639beb93cSSam Leffler 89739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); 89839beb93cSSam Leffler 89939beb93cSSam Leffler if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { 90039beb93cSSam Leffler if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) 90139beb93cSSam Leffler return -1; 90239beb93cSSam Leffler } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { 90339beb93cSSam Leffler /* This is an optional message that can be displayed to 90439beb93cSSam Leffler * the user. */ 90539beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", 90639beb93cSSam Leffler dpos, dlen); 90739beb93cSSam Leffler } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 90839beb93cSSam Leffler avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { 90939beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success", 91039beb93cSSam Leffler dpos, dlen); 91139beb93cSSam Leffler if (dlen != 43) { 91239beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " 91339beb93cSSam Leffler "MS-CHAP2-Success length " 91439beb93cSSam Leffler "(len=%lu, expected 43)", 91539beb93cSSam Leffler (unsigned long) dlen); 91639beb93cSSam Leffler return -1; 91739beb93cSSam Leffler } 91839beb93cSSam Leffler parse->mschapv2 = dpos; 91939beb93cSSam Leffler } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 92039beb93cSSam Leffler avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { 92139beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error", 92239beb93cSSam Leffler dpos, dlen); 92339beb93cSSam Leffler parse->mschapv2_error = 1; 92439beb93cSSam Leffler } else if (avp_flags & AVP_FLAGS_MANDATORY) { 92539beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP " 92639beb93cSSam Leffler "code %d vendor_id %d - dropped", 92739beb93cSSam Leffler (int) avp_code, (int) vendor_id); 92839beb93cSSam Leffler return -1; 92939beb93cSSam Leffler } else { 93039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " 93139beb93cSSam Leffler "code %d vendor_id %d", 93239beb93cSSam Leffler (int) avp_code, (int) vendor_id); 93339beb93cSSam Leffler } 93439beb93cSSam Leffler 93539beb93cSSam Leffler return avp_length; 93639beb93cSSam Leffler } 93739beb93cSSam Leffler 93839beb93cSSam Leffler 93939beb93cSSam Leffler static int eap_ttls_parse_avps(struct wpabuf *in_decrypted, 94039beb93cSSam Leffler struct ttls_parse_avp *parse) 94139beb93cSSam Leffler { 94239beb93cSSam Leffler u8 *pos; 94339beb93cSSam Leffler size_t left, pad; 94439beb93cSSam Leffler int avp_length; 94539beb93cSSam Leffler 94639beb93cSSam Leffler pos = wpabuf_mhead(in_decrypted); 94739beb93cSSam Leffler left = wpabuf_len(in_decrypted); 94839beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); 94939beb93cSSam Leffler if (left < sizeof(struct ttls_avp)) { 95039beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" 95139beb93cSSam Leffler " len=%lu expected %lu or more - dropped", 95239beb93cSSam Leffler (unsigned long) left, 95339beb93cSSam Leffler (unsigned long) sizeof(struct ttls_avp)); 95439beb93cSSam Leffler return -1; 95539beb93cSSam Leffler } 95639beb93cSSam Leffler 95739beb93cSSam Leffler /* Parse AVPs */ 95839beb93cSSam Leffler os_memset(parse, 0, sizeof(*parse)); 95939beb93cSSam Leffler 96039beb93cSSam Leffler while (left > 0) { 96139beb93cSSam Leffler avp_length = eap_ttls_parse_avp(pos, left, parse); 96239beb93cSSam Leffler if (avp_length < 0) 96339beb93cSSam Leffler return -1; 96439beb93cSSam Leffler 96539beb93cSSam Leffler pad = (4 - (avp_length & 3)) & 3; 96639beb93cSSam Leffler pos += avp_length + pad; 96739beb93cSSam Leffler if (left < avp_length + pad) 96839beb93cSSam Leffler left = 0; 96939beb93cSSam Leffler else 97039beb93cSSam Leffler left -= avp_length + pad; 97139beb93cSSam Leffler } 97239beb93cSSam Leffler 97339beb93cSSam Leffler return 0; 97439beb93cSSam Leffler } 97539beb93cSSam Leffler 97639beb93cSSam Leffler 97739beb93cSSam Leffler static u8 * eap_ttls_fake_identity_request(void) 97839beb93cSSam Leffler { 97939beb93cSSam Leffler struct eap_hdr *hdr; 98039beb93cSSam Leffler u8 *buf; 98139beb93cSSam Leffler 98239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " 98339beb93cSSam Leffler "Phase 2 - use fake EAP-Request Identity"); 98439beb93cSSam Leffler buf = os_malloc(sizeof(*hdr) + 1); 98539beb93cSSam Leffler if (buf == NULL) { 98639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " 98739beb93cSSam Leffler "memory for fake EAP-Identity Request"); 98839beb93cSSam Leffler return NULL; 98939beb93cSSam Leffler } 99039beb93cSSam Leffler 99139beb93cSSam Leffler hdr = (struct eap_hdr *) buf; 99239beb93cSSam Leffler hdr->code = EAP_CODE_REQUEST; 99339beb93cSSam Leffler hdr->identifier = 0; 99439beb93cSSam Leffler hdr->length = host_to_be16(sizeof(*hdr) + 1); 99539beb93cSSam Leffler buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; 99639beb93cSSam Leffler 99739beb93cSSam Leffler return buf; 99839beb93cSSam Leffler } 99939beb93cSSam Leffler 100039beb93cSSam Leffler 100139beb93cSSam Leffler static int eap_ttls_encrypt_response(struct eap_sm *sm, 100239beb93cSSam Leffler struct eap_ttls_data *data, 100339beb93cSSam Leffler struct wpabuf *resp, u8 identifier, 100439beb93cSSam Leffler struct wpabuf **out_data) 100539beb93cSSam Leffler { 100639beb93cSSam Leffler if (resp == NULL) 100739beb93cSSam Leffler return 0; 100839beb93cSSam Leffler 100939beb93cSSam Leffler wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", 101039beb93cSSam Leffler resp); 101139beb93cSSam Leffler if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, 101239beb93cSSam Leffler data->ttls_version, identifier, 101339beb93cSSam Leffler resp, out_data)) { 101439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " 101539beb93cSSam Leffler "frame"); 10165b9c547cSRui Paulo wpabuf_free(resp); 101739beb93cSSam Leffler return -1; 101839beb93cSSam Leffler } 101939beb93cSSam Leffler wpabuf_free(resp); 102039beb93cSSam Leffler 102139beb93cSSam Leffler return 0; 102239beb93cSSam Leffler } 102339beb93cSSam Leffler 102439beb93cSSam Leffler 102539beb93cSSam Leffler static int eap_ttls_process_phase2_eap(struct eap_sm *sm, 102639beb93cSSam Leffler struct eap_ttls_data *data, 102739beb93cSSam Leffler struct eap_method_ret *ret, 102839beb93cSSam Leffler struct ttls_parse_avp *parse, 102939beb93cSSam Leffler struct wpabuf **resp) 103039beb93cSSam Leffler { 103139beb93cSSam Leffler struct eap_hdr *hdr; 103239beb93cSSam Leffler size_t len; 103339beb93cSSam Leffler 103439beb93cSSam Leffler if (parse->eapdata == NULL) { 103539beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " 103639beb93cSSam Leffler "packet - dropped"); 103739beb93cSSam Leffler return -1; 103839beb93cSSam Leffler } 103939beb93cSSam Leffler 104039beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", 104139beb93cSSam Leffler parse->eapdata, parse->eap_len); 104239beb93cSSam Leffler hdr = (struct eap_hdr *) parse->eapdata; 104339beb93cSSam Leffler 104439beb93cSSam Leffler if (parse->eap_len < sizeof(*hdr)) { 104539beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " 104639beb93cSSam Leffler "frame (len=%lu, expected %lu or more) - dropped", 104739beb93cSSam Leffler (unsigned long) parse->eap_len, 104839beb93cSSam Leffler (unsigned long) sizeof(*hdr)); 104939beb93cSSam Leffler return -1; 105039beb93cSSam Leffler } 105139beb93cSSam Leffler len = be_to_host16(hdr->length); 105239beb93cSSam Leffler if (len > parse->eap_len) { 105339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " 105439beb93cSSam Leffler "EAP frame (EAP hdr len=%lu, EAP data len in " 105539beb93cSSam Leffler "AVP=%lu)", 105639beb93cSSam Leffler (unsigned long) len, 105739beb93cSSam Leffler (unsigned long) parse->eap_len); 105839beb93cSSam Leffler return -1; 105939beb93cSSam Leffler } 106039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " 106139beb93cSSam Leffler "identifier=%d length=%lu", 106239beb93cSSam Leffler hdr->code, hdr->identifier, (unsigned long) len); 106339beb93cSSam Leffler switch (hdr->code) { 106439beb93cSSam Leffler case EAP_CODE_REQUEST: 106539beb93cSSam Leffler if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { 106639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " 106739beb93cSSam Leffler "processing failed"); 106839beb93cSSam Leffler return -1; 106939beb93cSSam Leffler } 107039beb93cSSam Leffler break; 107139beb93cSSam Leffler default: 107239beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " 107339beb93cSSam Leffler "Phase 2 EAP header", hdr->code); 107439beb93cSSam Leffler return -1; 107539beb93cSSam Leffler } 107639beb93cSSam Leffler 107739beb93cSSam Leffler return 0; 107839beb93cSSam Leffler } 107939beb93cSSam Leffler 108039beb93cSSam Leffler 108139beb93cSSam Leffler static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, 108239beb93cSSam Leffler struct eap_ttls_data *data, 108339beb93cSSam Leffler struct eap_method_ret *ret, 108439beb93cSSam Leffler struct ttls_parse_avp *parse) 108539beb93cSSam Leffler { 1086f05cddf9SRui Paulo #ifdef EAP_MSCHAPv2 108739beb93cSSam Leffler if (parse->mschapv2_error) { 108839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " 108939beb93cSSam Leffler "MS-CHAP-Error - failed"); 109039beb93cSSam Leffler ret->methodState = METHOD_DONE; 109139beb93cSSam Leffler ret->decision = DECISION_FAIL; 109239beb93cSSam Leffler /* Reply with empty data to ACK error */ 109339beb93cSSam Leffler return 1; 109439beb93cSSam Leffler } 109539beb93cSSam Leffler 109639beb93cSSam Leffler if (parse->mschapv2 == NULL) { 109739beb93cSSam Leffler #ifdef EAP_TNC 109839beb93cSSam Leffler if (data->phase2_success && parse->eapdata) { 109939beb93cSSam Leffler /* 110039beb93cSSam Leffler * Allow EAP-TNC to be started after successfully 110139beb93cSSam Leffler * completed MSCHAPV2. 110239beb93cSSam Leffler */ 110339beb93cSSam Leffler return 1; 110439beb93cSSam Leffler } 110539beb93cSSam Leffler #endif /* EAP_TNC */ 110639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " 110739beb93cSSam Leffler "received for Phase2 MSCHAPV2"); 110839beb93cSSam Leffler return -1; 110939beb93cSSam Leffler } 111039beb93cSSam Leffler if (parse->mschapv2[0] != data->ident) { 111139beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " 111239beb93cSSam Leffler "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", 111339beb93cSSam Leffler parse->mschapv2[0], data->ident); 111439beb93cSSam Leffler return -1; 111539beb93cSSam Leffler } 111639beb93cSSam Leffler if (!data->auth_response_valid || 111739beb93cSSam Leffler mschapv2_verify_auth_response(data->auth_response, 111839beb93cSSam Leffler parse->mschapv2 + 1, 42)) { 111939beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " 112039beb93cSSam Leffler "response in Phase 2 MSCHAPV2 success request"); 112139beb93cSSam Leffler return -1; 112239beb93cSSam Leffler } 112339beb93cSSam Leffler 112439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " 112539beb93cSSam Leffler "authentication succeeded"); 112639beb93cSSam Leffler ret->methodState = METHOD_DONE; 112739beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 112839beb93cSSam Leffler data->phase2_success = 1; 112939beb93cSSam Leffler 113039beb93cSSam Leffler /* 113139beb93cSSam Leffler * Reply with empty data; authentication server will reply 113239beb93cSSam Leffler * with EAP-Success after this. 113339beb93cSSam Leffler */ 113439beb93cSSam Leffler return 1; 1135f05cddf9SRui Paulo #else /* EAP_MSCHAPv2 */ 1136f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); 1137f05cddf9SRui Paulo return -1; 1138f05cddf9SRui Paulo #endif /* EAP_MSCHAPv2 */ 113939beb93cSSam Leffler } 114039beb93cSSam Leffler 114139beb93cSSam Leffler 114239beb93cSSam Leffler #ifdef EAP_TNC 114339beb93cSSam Leffler static int eap_ttls_process_tnc_start(struct eap_sm *sm, 114439beb93cSSam Leffler struct eap_ttls_data *data, 114539beb93cSSam Leffler struct eap_method_ret *ret, 114639beb93cSSam Leffler struct ttls_parse_avp *parse, 114739beb93cSSam Leffler struct wpabuf **resp) 114839beb93cSSam Leffler { 114939beb93cSSam Leffler /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ 115039beb93cSSam Leffler if (parse->eapdata == NULL) { 115139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " 115239beb93cSSam Leffler "unexpected tunneled data (no EAP)"); 115339beb93cSSam Leffler return -1; 115439beb93cSSam Leffler } 115539beb93cSSam Leffler 115639beb93cSSam Leffler if (!data->ready_for_tnc) { 115739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " 115839beb93cSSam Leffler "EAP after non-EAP, but not ready for TNC"); 115939beb93cSSam Leffler return -1; 116039beb93cSSam Leffler } 116139beb93cSSam Leffler 116239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " 116339beb93cSSam Leffler "non-EAP method"); 116439beb93cSSam Leffler data->tnc_started = 1; 116539beb93cSSam Leffler 116639beb93cSSam Leffler if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) 116739beb93cSSam Leffler return -1; 116839beb93cSSam Leffler 116939beb93cSSam Leffler return 0; 117039beb93cSSam Leffler } 117139beb93cSSam Leffler #endif /* EAP_TNC */ 117239beb93cSSam Leffler 117339beb93cSSam Leffler 117439beb93cSSam Leffler static int eap_ttls_process_decrypted(struct eap_sm *sm, 117539beb93cSSam Leffler struct eap_ttls_data *data, 117639beb93cSSam Leffler struct eap_method_ret *ret, 117739beb93cSSam Leffler u8 identifier, 117839beb93cSSam Leffler struct ttls_parse_avp *parse, 117939beb93cSSam Leffler struct wpabuf *in_decrypted, 118039beb93cSSam Leffler struct wpabuf **out_data) 118139beb93cSSam Leffler { 118239beb93cSSam Leffler struct wpabuf *resp = NULL; 118339beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 118439beb93cSSam Leffler int res; 118539beb93cSSam Leffler enum phase2_types phase2_type = data->phase2_type; 118639beb93cSSam Leffler 118739beb93cSSam Leffler #ifdef EAP_TNC 118839beb93cSSam Leffler if (data->tnc_started) 118939beb93cSSam Leffler phase2_type = EAP_TTLS_PHASE2_EAP; 119039beb93cSSam Leffler #endif /* EAP_TNC */ 119139beb93cSSam Leffler 119239beb93cSSam Leffler switch (phase2_type) { 119339beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 119439beb93cSSam Leffler if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < 119539beb93cSSam Leffler 0) 119639beb93cSSam Leffler return -1; 119739beb93cSSam Leffler break; 119839beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 119939beb93cSSam Leffler res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); 120039beb93cSSam Leffler #ifdef EAP_TNC 120139beb93cSSam Leffler if (res == 1 && parse->eapdata && data->phase2_success) { 120239beb93cSSam Leffler /* 120339beb93cSSam Leffler * TNC may be required as the next 120439beb93cSSam Leffler * authentication method within the tunnel. 120539beb93cSSam Leffler */ 120639beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 120739beb93cSSam Leffler data->ready_for_tnc = 1; 120839beb93cSSam Leffler if (eap_ttls_process_tnc_start(sm, data, ret, parse, 120939beb93cSSam Leffler &resp) == 0) 121039beb93cSSam Leffler break; 121139beb93cSSam Leffler } 121239beb93cSSam Leffler #endif /* EAP_TNC */ 121339beb93cSSam Leffler return res; 121439beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 121539beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 121639beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 121739beb93cSSam Leffler #ifdef EAP_TNC 121839beb93cSSam Leffler if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < 121939beb93cSSam Leffler 0) 122039beb93cSSam Leffler return -1; 122139beb93cSSam Leffler break; 122239beb93cSSam Leffler #else /* EAP_TNC */ 122339beb93cSSam Leffler /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled 122439beb93cSSam Leffler * requests to the supplicant */ 122539beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " 122639beb93cSSam Leffler "tunneled data"); 122739beb93cSSam Leffler return -1; 122839beb93cSSam Leffler #endif /* EAP_TNC */ 122939beb93cSSam Leffler } 123039beb93cSSam Leffler 123139beb93cSSam Leffler if (resp) { 123239beb93cSSam Leffler if (eap_ttls_encrypt_response(sm, data, resp, identifier, 123339beb93cSSam Leffler out_data) < 0) 123439beb93cSSam Leffler return -1; 123539beb93cSSam Leffler } else if (config->pending_req_identity || 123639beb93cSSam Leffler config->pending_req_password || 123739beb93cSSam Leffler config->pending_req_otp || 123839beb93cSSam Leffler config->pending_req_new_password) { 123939beb93cSSam Leffler wpabuf_free(data->pending_phase2_req); 124039beb93cSSam Leffler data->pending_phase2_req = wpabuf_dup(in_decrypted); 124139beb93cSSam Leffler } 124239beb93cSSam Leffler 124339beb93cSSam Leffler return 0; 124439beb93cSSam Leffler } 124539beb93cSSam Leffler 124639beb93cSSam Leffler 124739beb93cSSam Leffler static int eap_ttls_implicit_identity_request(struct eap_sm *sm, 124839beb93cSSam Leffler struct eap_ttls_data *data, 124939beb93cSSam Leffler struct eap_method_ret *ret, 125039beb93cSSam Leffler u8 identifier, 125139beb93cSSam Leffler struct wpabuf **out_data) 125239beb93cSSam Leffler { 125339beb93cSSam Leffler int retval = 0; 125439beb93cSSam Leffler struct eap_hdr *hdr; 125539beb93cSSam Leffler struct wpabuf *resp; 125639beb93cSSam Leffler 125739beb93cSSam Leffler hdr = (struct eap_hdr *) eap_ttls_fake_identity_request(); 125839beb93cSSam Leffler if (hdr == NULL) { 125939beb93cSSam Leffler ret->methodState = METHOD_DONE; 126039beb93cSSam Leffler ret->decision = DECISION_FAIL; 126139beb93cSSam Leffler return -1; 126239beb93cSSam Leffler } 126339beb93cSSam Leffler 126439beb93cSSam Leffler resp = NULL; 126539beb93cSSam Leffler if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) { 126639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " 126739beb93cSSam Leffler "processing failed"); 126839beb93cSSam Leffler retval = -1; 126939beb93cSSam Leffler } else { 1270f05cddf9SRui Paulo struct eap_peer_config *config = eap_get_config(sm); 1271f05cddf9SRui Paulo if (resp == NULL && 1272f05cddf9SRui Paulo (config->pending_req_identity || 1273f05cddf9SRui Paulo config->pending_req_password || 1274f05cddf9SRui Paulo config->pending_req_otp || 1275f05cddf9SRui Paulo config->pending_req_new_password)) { 1276f05cddf9SRui Paulo /* 1277f05cddf9SRui Paulo * Use empty buffer to force implicit request 1278f05cddf9SRui Paulo * processing when EAP request is re-processed after 1279f05cddf9SRui Paulo * user input. 1280f05cddf9SRui Paulo */ 1281f05cddf9SRui Paulo wpabuf_free(data->pending_phase2_req); 1282f05cddf9SRui Paulo data->pending_phase2_req = wpabuf_alloc(0); 1283f05cddf9SRui Paulo } 1284f05cddf9SRui Paulo 128539beb93cSSam Leffler retval = eap_ttls_encrypt_response(sm, data, resp, identifier, 128639beb93cSSam Leffler out_data); 128739beb93cSSam Leffler } 128839beb93cSSam Leffler 128939beb93cSSam Leffler os_free(hdr); 129039beb93cSSam Leffler 129139beb93cSSam Leffler if (retval < 0) { 129239beb93cSSam Leffler ret->methodState = METHOD_DONE; 129339beb93cSSam Leffler ret->decision = DECISION_FAIL; 129439beb93cSSam Leffler } 129539beb93cSSam Leffler 129639beb93cSSam Leffler return retval; 129739beb93cSSam Leffler } 129839beb93cSSam Leffler 129939beb93cSSam Leffler 130039beb93cSSam Leffler static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data, 130139beb93cSSam Leffler struct eap_method_ret *ret, u8 identifier, 130239beb93cSSam Leffler struct wpabuf **out_data) 130339beb93cSSam Leffler { 130439beb93cSSam Leffler data->phase2_start = 0; 130539beb93cSSam Leffler 130639beb93cSSam Leffler /* 130739beb93cSSam Leffler * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only 130839beb93cSSam Leffler * if TLS part was indeed resuming a previous session. Most 130939beb93cSSam Leffler * Authentication Servers terminate EAP-TTLS before reaching this 131039beb93cSSam Leffler * point, but some do not. Make wpa_supplicant stop phase 2 here, if 131139beb93cSSam Leffler * needed. 131239beb93cSSam Leffler */ 131339beb93cSSam Leffler if (data->reauth && 131439beb93cSSam Leffler tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { 131539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " 131639beb93cSSam Leffler "skip phase 2"); 131739beb93cSSam Leffler *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS, 131839beb93cSSam Leffler data->ttls_version); 131939beb93cSSam Leffler ret->methodState = METHOD_DONE; 132039beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 132139beb93cSSam Leffler data->phase2_success = 1; 132239beb93cSSam Leffler return 0; 132339beb93cSSam Leffler } 132439beb93cSSam Leffler 132539beb93cSSam Leffler return eap_ttls_implicit_identity_request(sm, data, ret, identifier, 132639beb93cSSam Leffler out_data); 132739beb93cSSam Leffler } 132839beb93cSSam Leffler 132939beb93cSSam Leffler 133039beb93cSSam Leffler static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, 133139beb93cSSam Leffler struct eap_method_ret *ret, u8 identifier, 133239beb93cSSam Leffler const struct wpabuf *in_data, 133339beb93cSSam Leffler struct wpabuf **out_data) 133439beb93cSSam Leffler { 133539beb93cSSam Leffler struct wpabuf *in_decrypted = NULL; 133639beb93cSSam Leffler int retval = 0; 133739beb93cSSam Leffler struct ttls_parse_avp parse; 133839beb93cSSam Leffler 133939beb93cSSam Leffler os_memset(&parse, 0, sizeof(parse)); 134039beb93cSSam Leffler 134139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" 134239beb93cSSam Leffler " Phase 2", 134339beb93cSSam Leffler in_data ? (unsigned long) wpabuf_len(in_data) : 0); 134439beb93cSSam Leffler 134539beb93cSSam Leffler if (data->pending_phase2_req) { 134639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " 134739beb93cSSam Leffler "skip decryption and use old data"); 134839beb93cSSam Leffler /* Clear TLS reassembly state. */ 134939beb93cSSam Leffler eap_peer_tls_reset_input(&data->ssl); 135039beb93cSSam Leffler 135139beb93cSSam Leffler in_decrypted = data->pending_phase2_req; 135239beb93cSSam Leffler data->pending_phase2_req = NULL; 135339beb93cSSam Leffler if (wpabuf_len(in_decrypted) == 0) { 135439beb93cSSam Leffler wpabuf_free(in_decrypted); 135539beb93cSSam Leffler return eap_ttls_implicit_identity_request( 135639beb93cSSam Leffler sm, data, ret, identifier, out_data); 135739beb93cSSam Leffler } 135839beb93cSSam Leffler goto continue_req; 135939beb93cSSam Leffler } 136039beb93cSSam Leffler 136139beb93cSSam Leffler if ((in_data == NULL || wpabuf_len(in_data) == 0) && 136239beb93cSSam Leffler data->phase2_start) { 136339beb93cSSam Leffler return eap_ttls_phase2_start(sm, data, ret, identifier, 136439beb93cSSam Leffler out_data); 136539beb93cSSam Leffler } 136639beb93cSSam Leffler 136739beb93cSSam Leffler if (in_data == NULL || wpabuf_len(in_data) == 0) { 136839beb93cSSam Leffler /* Received TLS ACK - requesting more fragments */ 136939beb93cSSam Leffler return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, 137039beb93cSSam Leffler data->ttls_version, 137139beb93cSSam Leffler identifier, NULL, out_data); 137239beb93cSSam Leffler } 137339beb93cSSam Leffler 137439beb93cSSam Leffler retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); 137539beb93cSSam Leffler if (retval) 137639beb93cSSam Leffler goto done; 137739beb93cSSam Leffler 137839beb93cSSam Leffler continue_req: 137939beb93cSSam Leffler data->phase2_start = 0; 138039beb93cSSam Leffler 138139beb93cSSam Leffler if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) { 138239beb93cSSam Leffler retval = -1; 138339beb93cSSam Leffler goto done; 138439beb93cSSam Leffler } 138539beb93cSSam Leffler 138639beb93cSSam Leffler retval = eap_ttls_process_decrypted(sm, data, ret, identifier, 138739beb93cSSam Leffler &parse, in_decrypted, out_data); 138839beb93cSSam Leffler 138939beb93cSSam Leffler done: 139039beb93cSSam Leffler wpabuf_free(in_decrypted); 139139beb93cSSam Leffler os_free(parse.eapdata); 139239beb93cSSam Leffler 139339beb93cSSam Leffler if (retval < 0) { 139439beb93cSSam Leffler ret->methodState = METHOD_DONE; 139539beb93cSSam Leffler ret->decision = DECISION_FAIL; 139639beb93cSSam Leffler } 139739beb93cSSam Leffler 139839beb93cSSam Leffler return retval; 139939beb93cSSam Leffler } 140039beb93cSSam Leffler 140139beb93cSSam Leffler 140239beb93cSSam Leffler static int eap_ttls_process_handshake(struct eap_sm *sm, 140339beb93cSSam Leffler struct eap_ttls_data *data, 140439beb93cSSam Leffler struct eap_method_ret *ret, 140539beb93cSSam Leffler u8 identifier, 1406*325151a3SRui Paulo const struct wpabuf *in_data, 140739beb93cSSam Leffler struct wpabuf **out_data) 140839beb93cSSam Leffler { 140939beb93cSSam Leffler int res; 141039beb93cSSam Leffler 141139beb93cSSam Leffler res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, 141239beb93cSSam Leffler data->ttls_version, identifier, 1413*325151a3SRui Paulo in_data, out_data); 1414*325151a3SRui Paulo if (res < 0) { 1415*325151a3SRui Paulo wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed"); 1416*325151a3SRui Paulo ret->methodState = METHOD_DONE; 1417*325151a3SRui Paulo ret->decision = DECISION_FAIL; 1418*325151a3SRui Paulo return -1; 1419*325151a3SRui Paulo } 142039beb93cSSam Leffler 142139beb93cSSam Leffler if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 142239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " 142339beb93cSSam Leffler "Phase 2"); 142439beb93cSSam Leffler if (data->resuming) { 142539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may " 142639beb93cSSam Leffler "skip Phase 2"); 142739beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 142839beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 142939beb93cSSam Leffler } 143039beb93cSSam Leffler data->phase2_start = 1; 143139beb93cSSam Leffler eap_ttls_v0_derive_key(sm, data); 143239beb93cSSam Leffler 143339beb93cSSam Leffler if (*out_data == NULL || wpabuf_len(*out_data) == 0) { 143439beb93cSSam Leffler if (eap_ttls_decrypt(sm, data, ret, identifier, 143539beb93cSSam Leffler NULL, out_data)) { 143639beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-TTLS: " 143739beb93cSSam Leffler "failed to process early " 143839beb93cSSam Leffler "start for Phase 2"); 143939beb93cSSam Leffler } 144039beb93cSSam Leffler res = 0; 144139beb93cSSam Leffler } 144239beb93cSSam Leffler data->resuming = 0; 144339beb93cSSam Leffler } 144439beb93cSSam Leffler 144539beb93cSSam Leffler if (res == 2) { 144639beb93cSSam Leffler /* 144739beb93cSSam Leffler * Application data included in the handshake message. 144839beb93cSSam Leffler */ 144939beb93cSSam Leffler wpabuf_free(data->pending_phase2_req); 145039beb93cSSam Leffler data->pending_phase2_req = *out_data; 145139beb93cSSam Leffler *out_data = NULL; 1452*325151a3SRui Paulo res = eap_ttls_decrypt(sm, data, ret, identifier, in_data, 145339beb93cSSam Leffler out_data); 145439beb93cSSam Leffler } 145539beb93cSSam Leffler 145639beb93cSSam Leffler return res; 145739beb93cSSam Leffler } 145839beb93cSSam Leffler 145939beb93cSSam Leffler 146039beb93cSSam Leffler static void eap_ttls_check_auth_status(struct eap_sm *sm, 146139beb93cSSam Leffler struct eap_ttls_data *data, 146239beb93cSSam Leffler struct eap_method_ret *ret) 146339beb93cSSam Leffler { 1464f05cddf9SRui Paulo if (ret->methodState == METHOD_DONE) { 146539beb93cSSam Leffler ret->allowNotifications = FALSE; 146639beb93cSSam Leffler if (ret->decision == DECISION_UNCOND_SUCC || 146739beb93cSSam Leffler ret->decision == DECISION_COND_SUCC) { 146839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " 146939beb93cSSam Leffler "completed successfully"); 147039beb93cSSam Leffler data->phase2_success = 1; 147139beb93cSSam Leffler #ifdef EAP_TNC 147239beb93cSSam Leffler if (!data->ready_for_tnc && !data->tnc_started) { 147339beb93cSSam Leffler /* 147439beb93cSSam Leffler * TNC may be required as the next 147539beb93cSSam Leffler * authentication method within the tunnel. 147639beb93cSSam Leffler */ 147739beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 147839beb93cSSam Leffler data->ready_for_tnc = 1; 147939beb93cSSam Leffler } 148039beb93cSSam Leffler #endif /* EAP_TNC */ 148139beb93cSSam Leffler } 1482f05cddf9SRui Paulo } else if (ret->methodState == METHOD_MAY_CONT && 148339beb93cSSam Leffler (ret->decision == DECISION_UNCOND_SUCC || 148439beb93cSSam Leffler ret->decision == DECISION_COND_SUCC)) { 148539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " 148639beb93cSSam Leffler "completed successfully (MAY_CONT)"); 148739beb93cSSam Leffler data->phase2_success = 1; 148839beb93cSSam Leffler } 148939beb93cSSam Leffler } 149039beb93cSSam Leffler 149139beb93cSSam Leffler 149239beb93cSSam Leffler static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, 149339beb93cSSam Leffler struct eap_method_ret *ret, 149439beb93cSSam Leffler const struct wpabuf *reqData) 149539beb93cSSam Leffler { 149639beb93cSSam Leffler size_t left; 149739beb93cSSam Leffler int res; 149839beb93cSSam Leffler u8 flags, id; 149939beb93cSSam Leffler struct wpabuf *resp; 150039beb93cSSam Leffler const u8 *pos; 150139beb93cSSam Leffler struct eap_ttls_data *data = priv; 1502*325151a3SRui Paulo struct wpabuf msg; 150339beb93cSSam Leffler 150439beb93cSSam Leffler pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, 150539beb93cSSam Leffler reqData, &left, &flags); 150639beb93cSSam Leffler if (pos == NULL) 150739beb93cSSam Leffler return NULL; 150839beb93cSSam Leffler id = eap_get_id(reqData); 150939beb93cSSam Leffler 151039beb93cSSam Leffler if (flags & EAP_TLS_FLAGS_START) { 1511f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own " 1512f05cddf9SRui Paulo "ver=%d)", flags & EAP_TLS_VERSION_MASK, 1513f05cddf9SRui Paulo data->ttls_version); 151439beb93cSSam Leffler 151539beb93cSSam Leffler /* RFC 5281, Ch. 9.2: 151639beb93cSSam Leffler * "This packet MAY contain additional information in the form 151739beb93cSSam Leffler * of AVPs, which may provide useful hints to the client" 151839beb93cSSam Leffler * For now, ignore any potential extra data. 151939beb93cSSam Leffler */ 152039beb93cSSam Leffler left = 0; 152139beb93cSSam Leffler } 152239beb93cSSam Leffler 1523*325151a3SRui Paulo wpabuf_set(&msg, pos, left); 1524*325151a3SRui Paulo 152539beb93cSSam Leffler resp = NULL; 152639beb93cSSam Leffler if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 152739beb93cSSam Leffler !data->resuming) { 152839beb93cSSam Leffler res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); 152939beb93cSSam Leffler } else { 153039beb93cSSam Leffler res = eap_ttls_process_handshake(sm, data, ret, id, 1531*325151a3SRui Paulo &msg, &resp); 153239beb93cSSam Leffler } 153339beb93cSSam Leffler 153439beb93cSSam Leffler eap_ttls_check_auth_status(sm, data, ret); 153539beb93cSSam Leffler 153639beb93cSSam Leffler /* FIX: what about res == -1? Could just move all error processing into 153739beb93cSSam Leffler * the other functions and get rid of this res==1 case here. */ 153839beb93cSSam Leffler if (res == 1) { 153939beb93cSSam Leffler wpabuf_free(resp); 154039beb93cSSam Leffler return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, 154139beb93cSSam Leffler data->ttls_version); 154239beb93cSSam Leffler } 154339beb93cSSam Leffler return resp; 154439beb93cSSam Leffler } 154539beb93cSSam Leffler 154639beb93cSSam Leffler 154739beb93cSSam Leffler static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) 154839beb93cSSam Leffler { 154939beb93cSSam Leffler struct eap_ttls_data *data = priv; 155039beb93cSSam Leffler return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 155139beb93cSSam Leffler data->phase2_success; 155239beb93cSSam Leffler } 155339beb93cSSam Leffler 155439beb93cSSam Leffler 155539beb93cSSam Leffler static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) 155639beb93cSSam Leffler { 155739beb93cSSam Leffler struct eap_ttls_data *data = priv; 155839beb93cSSam Leffler wpabuf_free(data->pending_phase2_req); 155939beb93cSSam Leffler data->pending_phase2_req = NULL; 156039beb93cSSam Leffler #ifdef EAP_TNC 156139beb93cSSam Leffler data->ready_for_tnc = 0; 156239beb93cSSam Leffler data->tnc_started = 0; 156339beb93cSSam Leffler #endif /* EAP_TNC */ 156439beb93cSSam Leffler } 156539beb93cSSam Leffler 156639beb93cSSam Leffler 156739beb93cSSam Leffler static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) 156839beb93cSSam Leffler { 156939beb93cSSam Leffler struct eap_ttls_data *data = priv; 15705b9c547cSRui Paulo eap_ttls_free_key(data); 15715b9c547cSRui Paulo os_free(data->session_id); 15725b9c547cSRui Paulo data->session_id = NULL; 157339beb93cSSam Leffler if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 157439beb93cSSam Leffler os_free(data); 157539beb93cSSam Leffler return NULL; 157639beb93cSSam Leffler } 157739beb93cSSam Leffler if (data->phase2_priv && data->phase2_method && 157839beb93cSSam Leffler data->phase2_method->init_for_reauth) 157939beb93cSSam Leffler data->phase2_method->init_for_reauth(sm, data->phase2_priv); 158039beb93cSSam Leffler data->phase2_start = 0; 158139beb93cSSam Leffler data->phase2_success = 0; 158239beb93cSSam Leffler data->resuming = 1; 158339beb93cSSam Leffler data->reauth = 1; 158439beb93cSSam Leffler return priv; 158539beb93cSSam Leffler } 158639beb93cSSam Leffler 158739beb93cSSam Leffler 158839beb93cSSam Leffler static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, 158939beb93cSSam Leffler size_t buflen, int verbose) 159039beb93cSSam Leffler { 159139beb93cSSam Leffler struct eap_ttls_data *data = priv; 159239beb93cSSam Leffler int len, ret; 159339beb93cSSam Leffler 159439beb93cSSam Leffler len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 159539beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, 159639beb93cSSam Leffler "EAP-TTLSv%d Phase2 method=", 159739beb93cSSam Leffler data->ttls_version); 15985b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 159939beb93cSSam Leffler return len; 160039beb93cSSam Leffler len += ret; 160139beb93cSSam Leffler switch (data->phase2_type) { 160239beb93cSSam Leffler case EAP_TTLS_PHASE2_EAP: 160339beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", 160439beb93cSSam Leffler data->phase2_method ? 160539beb93cSSam Leffler data->phase2_method->name : "?"); 160639beb93cSSam Leffler break; 160739beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAPV2: 160839beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); 160939beb93cSSam Leffler break; 161039beb93cSSam Leffler case EAP_TTLS_PHASE2_MSCHAP: 161139beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); 161239beb93cSSam Leffler break; 161339beb93cSSam Leffler case EAP_TTLS_PHASE2_PAP: 161439beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "PAP\n"); 161539beb93cSSam Leffler break; 161639beb93cSSam Leffler case EAP_TTLS_PHASE2_CHAP: 161739beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); 161839beb93cSSam Leffler break; 161939beb93cSSam Leffler default: 162039beb93cSSam Leffler ret = 0; 162139beb93cSSam Leffler break; 162239beb93cSSam Leffler } 16235b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 162439beb93cSSam Leffler return len; 162539beb93cSSam Leffler len += ret; 162639beb93cSSam Leffler 162739beb93cSSam Leffler return len; 162839beb93cSSam Leffler } 162939beb93cSSam Leffler 163039beb93cSSam Leffler 163139beb93cSSam Leffler static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) 163239beb93cSSam Leffler { 163339beb93cSSam Leffler struct eap_ttls_data *data = priv; 163439beb93cSSam Leffler return data->key_data != NULL && data->phase2_success; 163539beb93cSSam Leffler } 163639beb93cSSam Leffler 163739beb93cSSam Leffler 163839beb93cSSam Leffler static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) 163939beb93cSSam Leffler { 164039beb93cSSam Leffler struct eap_ttls_data *data = priv; 164139beb93cSSam Leffler u8 *key; 164239beb93cSSam Leffler 164339beb93cSSam Leffler if (data->key_data == NULL || !data->phase2_success) 164439beb93cSSam Leffler return NULL; 164539beb93cSSam Leffler 164639beb93cSSam Leffler key = os_malloc(EAP_TLS_KEY_LEN); 164739beb93cSSam Leffler if (key == NULL) 164839beb93cSSam Leffler return NULL; 164939beb93cSSam Leffler 165039beb93cSSam Leffler *len = EAP_TLS_KEY_LEN; 165139beb93cSSam Leffler os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); 165239beb93cSSam Leffler 165339beb93cSSam Leffler return key; 165439beb93cSSam Leffler } 165539beb93cSSam Leffler 165639beb93cSSam Leffler 16575b9c547cSRui Paulo static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 16585b9c547cSRui Paulo { 16595b9c547cSRui Paulo struct eap_ttls_data *data = priv; 16605b9c547cSRui Paulo u8 *id; 16615b9c547cSRui Paulo 16625b9c547cSRui Paulo if (data->session_id == NULL || !data->phase2_success) 16635b9c547cSRui Paulo return NULL; 16645b9c547cSRui Paulo 16655b9c547cSRui Paulo id = os_malloc(data->id_len); 16665b9c547cSRui Paulo if (id == NULL) 16675b9c547cSRui Paulo return NULL; 16685b9c547cSRui Paulo 16695b9c547cSRui Paulo *len = data->id_len; 16705b9c547cSRui Paulo os_memcpy(id, data->session_id, data->id_len); 16715b9c547cSRui Paulo 16725b9c547cSRui Paulo return id; 16735b9c547cSRui Paulo } 16745b9c547cSRui Paulo 16755b9c547cSRui Paulo 16765b9c547cSRui Paulo static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 16775b9c547cSRui Paulo { 16785b9c547cSRui Paulo struct eap_ttls_data *data = priv; 16795b9c547cSRui Paulo u8 *key; 16805b9c547cSRui Paulo 16815b9c547cSRui Paulo if (data->key_data == NULL) 16825b9c547cSRui Paulo return NULL; 16835b9c547cSRui Paulo 16845b9c547cSRui Paulo key = os_malloc(EAP_EMSK_LEN); 16855b9c547cSRui Paulo if (key == NULL) 16865b9c547cSRui Paulo return NULL; 16875b9c547cSRui Paulo 16885b9c547cSRui Paulo *len = EAP_EMSK_LEN; 16895b9c547cSRui Paulo os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); 16905b9c547cSRui Paulo 16915b9c547cSRui Paulo return key; 16925b9c547cSRui Paulo } 16935b9c547cSRui Paulo 16945b9c547cSRui Paulo 169539beb93cSSam Leffler int eap_peer_ttls_register(void) 169639beb93cSSam Leffler { 169739beb93cSSam Leffler struct eap_method *eap; 169839beb93cSSam Leffler int ret; 169939beb93cSSam Leffler 170039beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 170139beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); 170239beb93cSSam Leffler if (eap == NULL) 170339beb93cSSam Leffler return -1; 170439beb93cSSam Leffler 170539beb93cSSam Leffler eap->init = eap_ttls_init; 170639beb93cSSam Leffler eap->deinit = eap_ttls_deinit; 170739beb93cSSam Leffler eap->process = eap_ttls_process; 170839beb93cSSam Leffler eap->isKeyAvailable = eap_ttls_isKeyAvailable; 170939beb93cSSam Leffler eap->getKey = eap_ttls_getKey; 17105b9c547cSRui Paulo eap->getSessionId = eap_ttls_get_session_id; 171139beb93cSSam Leffler eap->get_status = eap_ttls_get_status; 171239beb93cSSam Leffler eap->has_reauth_data = eap_ttls_has_reauth_data; 171339beb93cSSam Leffler eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; 171439beb93cSSam Leffler eap->init_for_reauth = eap_ttls_init_for_reauth; 17155b9c547cSRui Paulo eap->get_emsk = eap_ttls_get_emsk; 171639beb93cSSam Leffler 171739beb93cSSam Leffler ret = eap_peer_method_register(eap); 171839beb93cSSam Leffler if (ret) 171939beb93cSSam Leffler eap_peer_method_free(eap); 172039beb93cSSam Leffler return ret; 172139beb93cSSam Leffler } 1722