1189251Ssam/* 2189251Ssam * EAP peer method: EAP-TTLS (RFC 5281) 3337817Scy * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/ms_funcs.h" 13214734Srpaulo#include "crypto/sha1.h" 14214734Srpaulo#include "crypto/tls.h" 15189251Ssam#include "eap_common/chap.h" 16214734Srpaulo#include "eap_common/eap_ttls.h" 17189251Ssam#include "mschapv2.h" 18214734Srpaulo#include "eap_i.h" 19214734Srpaulo#include "eap_tls_common.h" 20214734Srpaulo#include "eap_config.h" 21189251Ssam 22189251Ssam 23252726Srpaulo#define EAP_TTLS_VERSION 0 24189251Ssam 25189251Ssam 26189251Ssamstatic void eap_ttls_deinit(struct eap_sm *sm, void *priv); 27189251Ssam 28189251Ssam 29189251Ssamstruct eap_ttls_data { 30189251Ssam struct eap_ssl_data ssl; 31189251Ssam 32252726Srpaulo int ttls_version; 33189251Ssam 34189251Ssam const struct eap_method *phase2_method; 35189251Ssam void *phase2_priv; 36189251Ssam int phase2_success; 37189251Ssam int phase2_start; 38337817Scy EapDecision decision_succ; 39189251Ssam 40189251Ssam enum phase2_types { 41189251Ssam EAP_TTLS_PHASE2_EAP, 42189251Ssam EAP_TTLS_PHASE2_MSCHAPV2, 43189251Ssam EAP_TTLS_PHASE2_MSCHAP, 44189251Ssam EAP_TTLS_PHASE2_PAP, 45189251Ssam EAP_TTLS_PHASE2_CHAP 46189251Ssam } phase2_type; 47189251Ssam struct eap_method_type phase2_eap_type; 48189251Ssam struct eap_method_type *phase2_eap_types; 49189251Ssam size_t num_phase2_eap_types; 50189251Ssam 51189251Ssam u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; 52189251Ssam int auth_response_valid; 53189251Ssam u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ 54189251Ssam u8 ident; 55189251Ssam int resuming; /* starting a resumed session */ 56189251Ssam int reauth; /* reauthentication */ 57189251Ssam u8 *key_data; 58281806Srpaulo u8 *session_id; 59281806Srpaulo size_t id_len; 60189251Ssam 61189251Ssam struct wpabuf *pending_phase2_req; 62337817Scy struct wpabuf *pending_resp; 63189251Ssam 64189251Ssam#ifdef EAP_TNC 65189251Ssam int ready_for_tnc; 66189251Ssam int tnc_started; 67189251Ssam#endif /* EAP_TNC */ 68189251Ssam}; 69189251Ssam 70189251Ssam 71189251Ssamstatic void * eap_ttls_init(struct eap_sm *sm) 72189251Ssam{ 73189251Ssam struct eap_ttls_data *data; 74189251Ssam struct eap_peer_config *config = eap_get_config(sm); 75337817Scy int selected_non_eap; 76189251Ssam char *selected; 77189251Ssam 78189251Ssam data = os_zalloc(sizeof(*data)); 79189251Ssam if (data == NULL) 80189251Ssam return NULL; 81189251Ssam data->ttls_version = EAP_TTLS_VERSION; 82189251Ssam selected = "EAP"; 83337817Scy selected_non_eap = 0; 84189251Ssam data->phase2_type = EAP_TTLS_PHASE2_EAP; 85189251Ssam 86337817Scy /* 87337817Scy * Either one auth= type or one or more autheap= methods can be 88337817Scy * specified. 89337817Scy */ 90189251Ssam if (config && config->phase2) { 91337817Scy const char *token, *last = NULL; 92337817Scy 93337817Scy while ((token = cstr_token(config->phase2, " \t", &last))) { 94337817Scy if (os_strncmp(token, "auth=", 5) != 0) 95337817Scy continue; 96337817Scy token += 5; 97337817Scy 98337817Scy if (last - token == 8 && 99337817Scy os_strncmp(token, "MSCHAPV2", 8) == 0) { 100337817Scy selected = "MSCHAPV2"; 101337817Scy data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; 102337817Scy } else if (last - token == 6 && 103337817Scy os_strncmp(token, "MSCHAP", 6) == 0) { 104337817Scy selected = "MSCHAP"; 105337817Scy data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; 106337817Scy } else if (last - token == 3 && 107337817Scy os_strncmp(token, "PAP", 3) == 0) { 108337817Scy selected = "PAP"; 109337817Scy data->phase2_type = EAP_TTLS_PHASE2_PAP; 110337817Scy } else if (last - token == 4 && 111337817Scy os_strncmp(token, "CHAP", 4) == 0) { 112337817Scy selected = "CHAP"; 113337817Scy data->phase2_type = EAP_TTLS_PHASE2_CHAP; 114337817Scy } else { 115337817Scy wpa_printf(MSG_ERROR, 116337817Scy "EAP-TTLS: Unsupported Phase2 type '%s'", 117337817Scy token); 118337817Scy eap_ttls_deinit(sm, data); 119337817Scy return NULL; 120337817Scy } 121337817Scy 122337817Scy if (selected_non_eap) { 123337817Scy wpa_printf(MSG_ERROR, 124337817Scy "EAP-TTLS: Only one Phase2 type can be specified"); 125337817Scy eap_ttls_deinit(sm, data); 126337817Scy return NULL; 127337817Scy } 128337817Scy 129337817Scy selected_non_eap = 1; 130337817Scy } 131337817Scy 132189251Ssam if (os_strstr(config->phase2, "autheap=")) { 133337817Scy if (selected_non_eap) { 134337817Scy wpa_printf(MSG_ERROR, 135337817Scy "EAP-TTLS: Both auth= and autheap= params cannot be specified"); 136337817Scy eap_ttls_deinit(sm, data); 137337817Scy return NULL; 138337817Scy } 139189251Ssam selected = "EAP"; 140189251Ssam data->phase2_type = EAP_TTLS_PHASE2_EAP; 141189251Ssam } 142189251Ssam } 143337817Scy 144189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); 145189251Ssam 146189251Ssam if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { 147189251Ssam if (eap_peer_select_phase2_methods(config, "autheap=", 148189251Ssam &data->phase2_eap_types, 149189251Ssam &data->num_phase2_eap_types) 150189251Ssam < 0) { 151189251Ssam eap_ttls_deinit(sm, data); 152189251Ssam return NULL; 153189251Ssam } 154189251Ssam 155189251Ssam data->phase2_eap_type.vendor = EAP_VENDOR_IETF; 156189251Ssam data->phase2_eap_type.method = EAP_TYPE_NONE; 157189251Ssam } 158189251Ssam 159252726Srpaulo if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) { 160252726Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); 161252726Srpaulo eap_ttls_deinit(sm, data); 162252726Srpaulo return NULL; 163189251Ssam } 164189251Ssam 165189251Ssam return data; 166189251Ssam} 167189251Ssam 168189251Ssam 169189251Ssamstatic void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, 170189251Ssam struct eap_ttls_data *data) 171189251Ssam{ 172189251Ssam if (data->phase2_priv && data->phase2_method) { 173189251Ssam data->phase2_method->deinit(sm, data->phase2_priv); 174189251Ssam data->phase2_method = NULL; 175189251Ssam data->phase2_priv = NULL; 176189251Ssam } 177189251Ssam} 178189251Ssam 179189251Ssam 180281806Srpaulostatic void eap_ttls_free_key(struct eap_ttls_data *data) 181281806Srpaulo{ 182281806Srpaulo if (data->key_data) { 183281806Srpaulo bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 184281806Srpaulo data->key_data = NULL; 185281806Srpaulo } 186281806Srpaulo} 187281806Srpaulo 188281806Srpaulo 189189251Ssamstatic void eap_ttls_deinit(struct eap_sm *sm, void *priv) 190189251Ssam{ 191189251Ssam struct eap_ttls_data *data = priv; 192189251Ssam if (data == NULL) 193189251Ssam return; 194189251Ssam eap_ttls_phase2_eap_deinit(sm, data); 195189251Ssam os_free(data->phase2_eap_types); 196252726Srpaulo eap_peer_tls_ssl_deinit(sm, &data->ssl); 197281806Srpaulo eap_ttls_free_key(data); 198281806Srpaulo os_free(data->session_id); 199346981Scy wpabuf_clear_free(data->pending_phase2_req); 200346981Scy wpabuf_clear_free(data->pending_resp); 201189251Ssam os_free(data); 202189251Ssam} 203189251Ssam 204189251Ssam 205189251Ssamstatic u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, 206189251Ssam int mandatory, size_t len) 207189251Ssam{ 208189251Ssam struct ttls_avp_vendor *avp; 209189251Ssam u8 flags; 210189251Ssam size_t hdrlen; 211189251Ssam 212189251Ssam avp = (struct ttls_avp_vendor *) avphdr; 213189251Ssam flags = mandatory ? AVP_FLAGS_MANDATORY : 0; 214189251Ssam if (vendor_id) { 215189251Ssam flags |= AVP_FLAGS_VENDOR; 216189251Ssam hdrlen = sizeof(*avp); 217189251Ssam avp->vendor_id = host_to_be32(vendor_id); 218189251Ssam } else { 219189251Ssam hdrlen = sizeof(struct ttls_avp); 220189251Ssam } 221189251Ssam 222189251Ssam avp->avp_code = host_to_be32(avp_code); 223289549Srpaulo avp->avp_length = host_to_be32(((u32) flags << 24) | 224289549Srpaulo (u32) (hdrlen + len)); 225189251Ssam 226189251Ssam return avphdr + hdrlen; 227189251Ssam} 228189251Ssam 229189251Ssam 230189251Ssamstatic u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, 231189251Ssam u32 vendor_id, int mandatory, 232189251Ssam const u8 *data, size_t len) 233189251Ssam{ 234189251Ssam u8 *pos; 235189251Ssam pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); 236189251Ssam os_memcpy(pos, data, len); 237189251Ssam pos += len; 238189251Ssam AVP_PAD(start, pos); 239189251Ssam return pos; 240189251Ssam} 241189251Ssam 242189251Ssam 243189251Ssamstatic int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, 244189251Ssam int mandatory) 245189251Ssam{ 246189251Ssam struct wpabuf *msg; 247189251Ssam u8 *avp, *pos; 248189251Ssam 249189251Ssam msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); 250189251Ssam if (msg == NULL) { 251346981Scy wpabuf_clear_free(*resp); 252189251Ssam *resp = NULL; 253189251Ssam return -1; 254189251Ssam } 255189251Ssam 256189251Ssam avp = wpabuf_mhead(msg); 257189251Ssam pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); 258189251Ssam os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); 259189251Ssam pos += wpabuf_len(*resp); 260189251Ssam AVP_PAD(avp, pos); 261346981Scy wpabuf_clear_free(*resp); 262189251Ssam wpabuf_put(msg, pos - avp); 263189251Ssam *resp = msg; 264189251Ssam return 0; 265189251Ssam} 266189251Ssam 267189251Ssam 268189251Ssamstatic int eap_ttls_v0_derive_key(struct eap_sm *sm, 269189251Ssam struct eap_ttls_data *data) 270189251Ssam{ 271281806Srpaulo eap_ttls_free_key(data); 272189251Ssam data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, 273189251Ssam "ttls keying material", 274346981Scy NULL, 0, 275281806Srpaulo EAP_TLS_KEY_LEN + 276281806Srpaulo EAP_EMSK_LEN); 277189251Ssam if (!data->key_data) { 278189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); 279189251Ssam return -1; 280189251Ssam } 281189251Ssam 282189251Ssam wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", 283189251Ssam data->key_data, EAP_TLS_KEY_LEN); 284281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK", 285281806Srpaulo data->key_data + EAP_TLS_KEY_LEN, 286281806Srpaulo EAP_EMSK_LEN); 287189251Ssam 288281806Srpaulo os_free(data->session_id); 289281806Srpaulo data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, 290281806Srpaulo EAP_TYPE_TTLS, 291281806Srpaulo &data->id_len); 292281806Srpaulo if (data->session_id) { 293281806Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id", 294281806Srpaulo data->session_id, data->id_len); 295281806Srpaulo } else { 296281806Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id"); 297281806Srpaulo } 298281806Srpaulo 299189251Ssam return 0; 300189251Ssam} 301189251Ssam 302189251Ssam 303289549Srpaulo#ifndef CONFIG_FIPS 304189251Ssamstatic u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, 305189251Ssam struct eap_ttls_data *data, size_t len) 306189251Ssam{ 307346981Scy return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", 308346981Scy NULL, 0, len); 309189251Ssam} 310289549Srpaulo#endif /* CONFIG_FIPS */ 311189251Ssam 312189251Ssam 313189251Ssamstatic void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, 314189251Ssam u8 method) 315189251Ssam{ 316189251Ssam size_t i; 317189251Ssam for (i = 0; i < data->num_phase2_eap_types; i++) { 318189251Ssam if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || 319189251Ssam data->phase2_eap_types[i].method != method) 320189251Ssam continue; 321189251Ssam 322189251Ssam data->phase2_eap_type.vendor = 323189251Ssam data->phase2_eap_types[i].vendor; 324189251Ssam data->phase2_eap_type.method = 325189251Ssam data->phase2_eap_types[i].method; 326189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " 327189251Ssam "Phase 2 EAP vendor %d method %d", 328189251Ssam data->phase2_eap_type.vendor, 329189251Ssam data->phase2_eap_type.method); 330189251Ssam break; 331189251Ssam } 332189251Ssam} 333189251Ssam 334189251Ssam 335189251Ssamstatic int eap_ttls_phase2_eap_process(struct eap_sm *sm, 336189251Ssam struct eap_ttls_data *data, 337189251Ssam struct eap_method_ret *ret, 338189251Ssam struct eap_hdr *hdr, size_t len, 339189251Ssam struct wpabuf **resp) 340189251Ssam{ 341189251Ssam struct wpabuf msg; 342189251Ssam struct eap_method_ret iret; 343189251Ssam 344189251Ssam os_memset(&iret, 0, sizeof(iret)); 345189251Ssam wpabuf_set(&msg, hdr, len); 346189251Ssam *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, 347189251Ssam &msg); 348189251Ssam if ((iret.methodState == METHOD_DONE || 349189251Ssam iret.methodState == METHOD_MAY_CONT) && 350189251Ssam (iret.decision == DECISION_UNCOND_SUCC || 351189251Ssam iret.decision == DECISION_COND_SUCC || 352189251Ssam iret.decision == DECISION_FAIL)) { 353189251Ssam ret->methodState = iret.methodState; 354189251Ssam ret->decision = iret.decision; 355189251Ssam } 356189251Ssam 357189251Ssam return 0; 358189251Ssam} 359189251Ssam 360189251Ssam 361189251Ssamstatic int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, 362189251Ssam struct eap_ttls_data *data, 363189251Ssam struct eap_method_ret *ret, 364189251Ssam struct eap_hdr *hdr, size_t len, 365189251Ssam u8 method, struct wpabuf **resp) 366189251Ssam{ 367189251Ssam#ifdef EAP_TNC 368189251Ssam if (data->tnc_started && data->phase2_method && 369189251Ssam data->phase2_priv && method == EAP_TYPE_TNC && 370189251Ssam data->phase2_eap_type.method == EAP_TYPE_TNC) 371189251Ssam return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, 372189251Ssam resp); 373189251Ssam 374189251Ssam if (data->ready_for_tnc && !data->tnc_started && 375189251Ssam method == EAP_TYPE_TNC) { 376189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " 377189251Ssam "EAP method"); 378189251Ssam data->tnc_started = 1; 379189251Ssam } 380189251Ssam 381189251Ssam if (data->tnc_started) { 382189251Ssam if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || 383189251Ssam data->phase2_eap_type.method == EAP_TYPE_TNC) { 384189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP " 385189251Ssam "type %d for TNC", method); 386189251Ssam return -1; 387189251Ssam } 388189251Ssam 389189251Ssam data->phase2_eap_type.vendor = EAP_VENDOR_IETF; 390189251Ssam data->phase2_eap_type.method = method; 391189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " 392189251Ssam "Phase 2 EAP vendor %d method %d (TNC)", 393189251Ssam data->phase2_eap_type.vendor, 394189251Ssam data->phase2_eap_type.method); 395189251Ssam 396189251Ssam if (data->phase2_type == EAP_TTLS_PHASE2_EAP) 397189251Ssam eap_ttls_phase2_eap_deinit(sm, data); 398189251Ssam } 399189251Ssam#endif /* EAP_TNC */ 400189251Ssam 401189251Ssam if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && 402189251Ssam data->phase2_eap_type.method == EAP_TYPE_NONE) 403189251Ssam eap_ttls_phase2_select_eap_method(data, method); 404189251Ssam 405189251Ssam if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) 406189251Ssam { 407189251Ssam if (eap_peer_tls_phase2_nak(data->phase2_eap_types, 408189251Ssam data->num_phase2_eap_types, 409189251Ssam hdr, resp)) 410189251Ssam return -1; 411189251Ssam return 0; 412189251Ssam } 413189251Ssam 414189251Ssam if (data->phase2_priv == NULL) { 415189251Ssam data->phase2_method = eap_peer_get_eap_method( 416189251Ssam EAP_VENDOR_IETF, method); 417189251Ssam if (data->phase2_method) { 418189251Ssam sm->init_phase2 = 1; 419189251Ssam data->phase2_priv = data->phase2_method->init(sm); 420189251Ssam sm->init_phase2 = 0; 421189251Ssam } 422189251Ssam } 423189251Ssam if (data->phase2_priv == NULL || data->phase2_method == NULL) { 424189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " 425189251Ssam "Phase 2 EAP method %d", method); 426189251Ssam return -1; 427189251Ssam } 428189251Ssam 429189251Ssam return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); 430189251Ssam} 431189251Ssam 432189251Ssam 433189251Ssamstatic int eap_ttls_phase2_request_eap(struct eap_sm *sm, 434189251Ssam struct eap_ttls_data *data, 435189251Ssam struct eap_method_ret *ret, 436189251Ssam struct eap_hdr *hdr, 437189251Ssam struct wpabuf **resp) 438189251Ssam{ 439189251Ssam size_t len = be_to_host16(hdr->length); 440189251Ssam u8 *pos; 441189251Ssam struct eap_peer_config *config = eap_get_config(sm); 442189251Ssam 443189251Ssam if (len <= sizeof(struct eap_hdr)) { 444189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: too short " 445189251Ssam "Phase 2 request (len=%lu)", (unsigned long) len); 446189251Ssam return -1; 447189251Ssam } 448189251Ssam pos = (u8 *) (hdr + 1); 449189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); 450189251Ssam switch (*pos) { 451189251Ssam case EAP_TYPE_IDENTITY: 452189251Ssam *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); 453189251Ssam break; 454189251Ssam default: 455189251Ssam if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, 456189251Ssam *pos, resp) < 0) 457189251Ssam return -1; 458189251Ssam break; 459189251Ssam } 460189251Ssam 461189251Ssam if (*resp == NULL && 462189251Ssam (config->pending_req_identity || config->pending_req_password || 463346981Scy config->pending_req_otp || config->pending_req_sim)) { 464189251Ssam return 0; 465189251Ssam } 466189251Ssam 467189251Ssam if (*resp == NULL) 468189251Ssam return -1; 469189251Ssam 470189251Ssam wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", 471189251Ssam *resp); 472189251Ssam return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); 473189251Ssam} 474189251Ssam 475189251Ssam 476189251Ssamstatic int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, 477189251Ssam struct eap_ttls_data *data, 478189251Ssam struct eap_method_ret *ret, 479189251Ssam struct wpabuf **resp) 480189251Ssam{ 481289549Srpaulo#ifdef CONFIG_FIPS 482289549Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build"); 483289549Srpaulo return -1; 484289549Srpaulo#else /* CONFIG_FIPS */ 485252726Srpaulo#ifdef EAP_MSCHAPv2 486189251Ssam struct wpabuf *msg; 487189251Ssam u8 *buf, *pos, *challenge, *peer_challenge; 488189251Ssam const u8 *identity, *password; 489189251Ssam size_t identity_len, password_len; 490189251Ssam int pwhash; 491189251Ssam 492189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); 493189251Ssam 494189251Ssam identity = eap_get_config_identity(sm, &identity_len); 495189251Ssam password = eap_get_config_password2(sm, &password_len, &pwhash); 496189251Ssam if (identity == NULL || password == NULL) 497189251Ssam return -1; 498189251Ssam 499189251Ssam msg = wpabuf_alloc(identity_len + 1000); 500189251Ssam if (msg == NULL) { 501189251Ssam wpa_printf(MSG_ERROR, 502189251Ssam "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); 503189251Ssam return -1; 504189251Ssam } 505189251Ssam pos = buf = wpabuf_mhead(msg); 506189251Ssam 507189251Ssam /* User-Name */ 508189251Ssam pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 509189251Ssam identity, identity_len); 510189251Ssam 511189251Ssam /* MS-CHAP-Challenge */ 512189251Ssam challenge = eap_ttls_implicit_challenge( 513189251Ssam sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); 514189251Ssam if (challenge == NULL) { 515346981Scy wpabuf_clear_free(msg); 516189251Ssam wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " 517189251Ssam "implicit challenge"); 518189251Ssam return -1; 519189251Ssam } 520189251Ssam 521189251Ssam pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, 522189251Ssam RADIUS_VENDOR_ID_MICROSOFT, 1, 523189251Ssam challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); 524189251Ssam 525189251Ssam /* MS-CHAP2-Response */ 526189251Ssam pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, 527189251Ssam RADIUS_VENDOR_ID_MICROSOFT, 1, 528189251Ssam EAP_TTLS_MSCHAPV2_RESPONSE_LEN); 529189251Ssam data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; 530189251Ssam *pos++ = data->ident; 531189251Ssam *pos++ = 0; /* Flags */ 532252726Srpaulo if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) { 533252726Srpaulo os_free(challenge); 534346981Scy wpabuf_clear_free(msg); 535252726Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get " 536252726Srpaulo "random data for peer challenge"); 537252726Srpaulo return -1; 538252726Srpaulo } 539252726Srpaulo peer_challenge = pos; 540189251Ssam pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; 541189251Ssam os_memset(pos, 0, 8); /* Reserved, must be zero */ 542189251Ssam pos += 8; 543214734Srpaulo if (mschapv2_derive_response(identity, identity_len, password, 544214734Srpaulo password_len, pwhash, challenge, 545214734Srpaulo peer_challenge, pos, data->auth_response, 546214734Srpaulo data->master_key)) { 547252726Srpaulo os_free(challenge); 548346981Scy wpabuf_clear_free(msg); 549214734Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " 550214734Srpaulo "response"); 551214734Srpaulo return -1; 552214734Srpaulo } 553189251Ssam data->auth_response_valid = 1; 554189251Ssam 555189251Ssam pos += 24; 556189251Ssam os_free(challenge); 557189251Ssam AVP_PAD(buf, pos); 558189251Ssam 559189251Ssam wpabuf_put(msg, pos - buf); 560189251Ssam *resp = msg; 561189251Ssam 562189251Ssam return 0; 563252726Srpaulo#else /* EAP_MSCHAPv2 */ 564252726Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); 565252726Srpaulo return -1; 566252726Srpaulo#endif /* EAP_MSCHAPv2 */ 567289549Srpaulo#endif /* CONFIG_FIPS */ 568189251Ssam} 569189251Ssam 570189251Ssam 571189251Ssamstatic int eap_ttls_phase2_request_mschap(struct eap_sm *sm, 572189251Ssam struct eap_ttls_data *data, 573189251Ssam struct eap_method_ret *ret, 574189251Ssam struct wpabuf **resp) 575189251Ssam{ 576289549Srpaulo#ifdef CONFIG_FIPS 577289549Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build"); 578289549Srpaulo return -1; 579289549Srpaulo#else /* CONFIG_FIPS */ 580189251Ssam struct wpabuf *msg; 581189251Ssam u8 *buf, *pos, *challenge; 582189251Ssam const u8 *identity, *password; 583189251Ssam size_t identity_len, password_len; 584189251Ssam int pwhash; 585189251Ssam 586189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); 587189251Ssam 588189251Ssam identity = eap_get_config_identity(sm, &identity_len); 589189251Ssam password = eap_get_config_password2(sm, &password_len, &pwhash); 590189251Ssam if (identity == NULL || password == NULL) 591189251Ssam return -1; 592189251Ssam 593189251Ssam msg = wpabuf_alloc(identity_len + 1000); 594189251Ssam if (msg == NULL) { 595189251Ssam wpa_printf(MSG_ERROR, 596189251Ssam "EAP-TTLS/MSCHAP: Failed to allocate memory"); 597189251Ssam return -1; 598189251Ssam } 599189251Ssam pos = buf = wpabuf_mhead(msg); 600189251Ssam 601189251Ssam /* User-Name */ 602189251Ssam pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 603189251Ssam identity, identity_len); 604189251Ssam 605189251Ssam /* MS-CHAP-Challenge */ 606189251Ssam challenge = eap_ttls_implicit_challenge( 607189251Ssam sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); 608189251Ssam if (challenge == NULL) { 609346981Scy wpabuf_clear_free(msg); 610189251Ssam wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " 611189251Ssam "implicit challenge"); 612189251Ssam return -1; 613189251Ssam } 614189251Ssam 615189251Ssam pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, 616189251Ssam RADIUS_VENDOR_ID_MICROSOFT, 1, 617189251Ssam challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); 618189251Ssam 619189251Ssam /* MS-CHAP-Response */ 620189251Ssam pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, 621189251Ssam RADIUS_VENDOR_ID_MICROSOFT, 1, 622189251Ssam EAP_TTLS_MSCHAP_RESPONSE_LEN); 623189251Ssam data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; 624189251Ssam *pos++ = data->ident; 625189251Ssam *pos++ = 1; /* Flags: Use NT style passwords */ 626189251Ssam os_memset(pos, 0, 24); /* LM-Response */ 627189251Ssam pos += 24; 628189251Ssam if (pwhash) { 629346981Scy /* NT-Response */ 630346981Scy if (challenge_response(challenge, password, pos)) { 631346981Scy wpa_printf(MSG_ERROR, 632346981Scy "EAP-TTLS/MSCHAP: Failed derive password hash"); 633346981Scy wpabuf_clear_free(msg); 634346981Scy os_free(challenge); 635346981Scy return -1; 636346981Scy } 637346981Scy 638189251Ssam wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", 639189251Ssam password, 16); 640189251Ssam } else { 641346981Scy /* NT-Response */ 642346981Scy if (nt_challenge_response(challenge, password, password_len, 643346981Scy pos)) { 644346981Scy wpa_printf(MSG_ERROR, 645346981Scy "EAP-TTLS/MSCHAP: Failed derive password"); 646346981Scy wpabuf_clear_free(msg); 647346981Scy os_free(challenge); 648346981Scy return -1; 649346981Scy } 650346981Scy 651189251Ssam wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", 652189251Ssam password, password_len); 653189251Ssam } 654189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", 655189251Ssam challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); 656189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); 657189251Ssam pos += 24; 658189251Ssam os_free(challenge); 659189251Ssam AVP_PAD(buf, pos); 660189251Ssam 661189251Ssam wpabuf_put(msg, pos - buf); 662189251Ssam *resp = msg; 663189251Ssam 664252726Srpaulo /* EAP-TTLS/MSCHAP does not provide tunneled success 665252726Srpaulo * notification, so assume that Phase2 succeeds. */ 666252726Srpaulo ret->methodState = METHOD_DONE; 667252726Srpaulo ret->decision = DECISION_COND_SUCC; 668189251Ssam 669189251Ssam return 0; 670289549Srpaulo#endif /* CONFIG_FIPS */ 671189251Ssam} 672189251Ssam 673189251Ssam 674189251Ssamstatic int eap_ttls_phase2_request_pap(struct eap_sm *sm, 675189251Ssam struct eap_ttls_data *data, 676189251Ssam struct eap_method_ret *ret, 677189251Ssam struct wpabuf **resp) 678189251Ssam{ 679189251Ssam struct wpabuf *msg; 680189251Ssam u8 *buf, *pos; 681189251Ssam size_t pad; 682189251Ssam const u8 *identity, *password; 683189251Ssam size_t identity_len, password_len; 684189251Ssam 685189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); 686189251Ssam 687189251Ssam identity = eap_get_config_identity(sm, &identity_len); 688189251Ssam password = eap_get_config_password(sm, &password_len); 689189251Ssam if (identity == NULL || password == NULL) 690189251Ssam return -1; 691189251Ssam 692189251Ssam msg = wpabuf_alloc(identity_len + password_len + 100); 693189251Ssam if (msg == NULL) { 694189251Ssam wpa_printf(MSG_ERROR, 695189251Ssam "EAP-TTLS/PAP: Failed to allocate memory"); 696189251Ssam return -1; 697189251Ssam } 698189251Ssam pos = buf = wpabuf_mhead(msg); 699189251Ssam 700189251Ssam /* User-Name */ 701189251Ssam pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 702189251Ssam identity, identity_len); 703189251Ssam 704189251Ssam /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts 705189251Ssam * the data, so no separate encryption is used in the AVP itself. 706189251Ssam * However, the password is padded to obfuscate its length. */ 707209158Srpaulo pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; 708189251Ssam pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, 709189251Ssam password_len + pad); 710189251Ssam os_memcpy(pos, password, password_len); 711189251Ssam pos += password_len; 712189251Ssam os_memset(pos, 0, pad); 713189251Ssam pos += pad; 714189251Ssam AVP_PAD(buf, pos); 715189251Ssam 716189251Ssam wpabuf_put(msg, pos - buf); 717189251Ssam *resp = msg; 718189251Ssam 719252726Srpaulo /* EAP-TTLS/PAP does not provide tunneled success notification, 720252726Srpaulo * so assume that Phase2 succeeds. */ 721252726Srpaulo ret->methodState = METHOD_DONE; 722252726Srpaulo ret->decision = DECISION_COND_SUCC; 723189251Ssam 724189251Ssam return 0; 725189251Ssam} 726189251Ssam 727189251Ssam 728189251Ssamstatic int eap_ttls_phase2_request_chap(struct eap_sm *sm, 729189251Ssam struct eap_ttls_data *data, 730189251Ssam struct eap_method_ret *ret, 731189251Ssam struct wpabuf **resp) 732189251Ssam{ 733289549Srpaulo#ifdef CONFIG_FIPS 734289549Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build"); 735289549Srpaulo return -1; 736289549Srpaulo#else /* CONFIG_FIPS */ 737189251Ssam struct wpabuf *msg; 738189251Ssam u8 *buf, *pos, *challenge; 739189251Ssam const u8 *identity, *password; 740189251Ssam size_t identity_len, password_len; 741189251Ssam 742189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); 743189251Ssam 744189251Ssam identity = eap_get_config_identity(sm, &identity_len); 745189251Ssam password = eap_get_config_password(sm, &password_len); 746189251Ssam if (identity == NULL || password == NULL) 747189251Ssam return -1; 748189251Ssam 749189251Ssam msg = wpabuf_alloc(identity_len + 1000); 750189251Ssam if (msg == NULL) { 751189251Ssam wpa_printf(MSG_ERROR, 752189251Ssam "EAP-TTLS/CHAP: Failed to allocate memory"); 753189251Ssam return -1; 754189251Ssam } 755189251Ssam pos = buf = wpabuf_mhead(msg); 756189251Ssam 757189251Ssam /* User-Name */ 758189251Ssam pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, 759189251Ssam identity, identity_len); 760189251Ssam 761189251Ssam /* CHAP-Challenge */ 762189251Ssam challenge = eap_ttls_implicit_challenge( 763189251Ssam sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); 764189251Ssam if (challenge == NULL) { 765346981Scy wpabuf_clear_free(msg); 766189251Ssam wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " 767189251Ssam "implicit challenge"); 768189251Ssam return -1; 769189251Ssam } 770189251Ssam 771189251Ssam pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, 772189251Ssam challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); 773189251Ssam 774189251Ssam /* CHAP-Password */ 775189251Ssam pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, 776189251Ssam 1 + EAP_TTLS_CHAP_PASSWORD_LEN); 777189251Ssam data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; 778189251Ssam *pos++ = data->ident; 779189251Ssam 780189251Ssam /* MD5(Ident + Password + Challenge) */ 781189251Ssam chap_md5(data->ident, password, password_len, challenge, 782189251Ssam EAP_TTLS_CHAP_CHALLENGE_LEN, pos); 783189251Ssam 784189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", 785189251Ssam identity, identity_len); 786189251Ssam wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", 787189251Ssam password, password_len); 788189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", 789189251Ssam challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); 790189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", 791189251Ssam pos, EAP_TTLS_CHAP_PASSWORD_LEN); 792189251Ssam pos += EAP_TTLS_CHAP_PASSWORD_LEN; 793189251Ssam os_free(challenge); 794189251Ssam AVP_PAD(buf, pos); 795189251Ssam 796189251Ssam wpabuf_put(msg, pos - buf); 797189251Ssam *resp = msg; 798189251Ssam 799252726Srpaulo /* EAP-TTLS/CHAP does not provide tunneled success 800252726Srpaulo * notification, so assume that Phase2 succeeds. */ 801252726Srpaulo ret->methodState = METHOD_DONE; 802252726Srpaulo ret->decision = DECISION_COND_SUCC; 803189251Ssam 804189251Ssam return 0; 805289549Srpaulo#endif /* CONFIG_FIPS */ 806189251Ssam} 807189251Ssam 808189251Ssam 809189251Ssamstatic int eap_ttls_phase2_request(struct eap_sm *sm, 810189251Ssam struct eap_ttls_data *data, 811189251Ssam struct eap_method_ret *ret, 812189251Ssam struct eap_hdr *hdr, 813189251Ssam struct wpabuf **resp) 814189251Ssam{ 815189251Ssam int res = 0; 816189251Ssam size_t len; 817189251Ssam enum phase2_types phase2_type = data->phase2_type; 818189251Ssam 819189251Ssam#ifdef EAP_TNC 820189251Ssam if (data->tnc_started) { 821189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); 822189251Ssam phase2_type = EAP_TTLS_PHASE2_EAP; 823189251Ssam } 824189251Ssam#endif /* EAP_TNC */ 825189251Ssam 826189251Ssam if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || 827189251Ssam phase2_type == EAP_TTLS_PHASE2_MSCHAP || 828189251Ssam phase2_type == EAP_TTLS_PHASE2_PAP || 829189251Ssam phase2_type == EAP_TTLS_PHASE2_CHAP) { 830189251Ssam if (eap_get_config_identity(sm, &len) == NULL) { 831189251Ssam wpa_printf(MSG_INFO, 832189251Ssam "EAP-TTLS: Identity not configured"); 833189251Ssam eap_sm_request_identity(sm); 834189251Ssam if (eap_get_config_password(sm, &len) == NULL) 835189251Ssam eap_sm_request_password(sm); 836189251Ssam return 0; 837189251Ssam } 838189251Ssam 839189251Ssam if (eap_get_config_password(sm, &len) == NULL) { 840189251Ssam wpa_printf(MSG_INFO, 841189251Ssam "EAP-TTLS: Password not configured"); 842189251Ssam eap_sm_request_password(sm); 843189251Ssam return 0; 844189251Ssam } 845189251Ssam } 846189251Ssam 847189251Ssam switch (phase2_type) { 848189251Ssam case EAP_TTLS_PHASE2_EAP: 849189251Ssam res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); 850189251Ssam break; 851189251Ssam case EAP_TTLS_PHASE2_MSCHAPV2: 852189251Ssam res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); 853189251Ssam break; 854189251Ssam case EAP_TTLS_PHASE2_MSCHAP: 855189251Ssam res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); 856189251Ssam break; 857189251Ssam case EAP_TTLS_PHASE2_PAP: 858189251Ssam res = eap_ttls_phase2_request_pap(sm, data, ret, resp); 859189251Ssam break; 860189251Ssam case EAP_TTLS_PHASE2_CHAP: 861189251Ssam res = eap_ttls_phase2_request_chap(sm, data, ret, resp); 862189251Ssam break; 863189251Ssam default: 864189251Ssam wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); 865189251Ssam res = -1; 866189251Ssam break; 867189251Ssam } 868189251Ssam 869189251Ssam if (res < 0) { 870189251Ssam ret->methodState = METHOD_DONE; 871189251Ssam ret->decision = DECISION_FAIL; 872189251Ssam } 873189251Ssam 874189251Ssam return res; 875189251Ssam} 876189251Ssam 877189251Ssam 878189251Ssamstruct ttls_parse_avp { 879189251Ssam u8 *mschapv2; 880189251Ssam u8 *eapdata; 881189251Ssam size_t eap_len; 882189251Ssam int mschapv2_error; 883189251Ssam}; 884189251Ssam 885189251Ssam 886189251Ssamstatic int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, 887189251Ssam struct ttls_parse_avp *parse) 888189251Ssam{ 889189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); 890189251Ssam if (parse->eapdata == NULL) { 891346981Scy parse->eapdata = os_memdup(dpos, dlen); 892189251Ssam if (parse->eapdata == NULL) { 893189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " 894189251Ssam "memory for Phase 2 EAP data"); 895189251Ssam return -1; 896189251Ssam } 897189251Ssam parse->eap_len = dlen; 898189251Ssam } else { 899189251Ssam u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); 900189251Ssam if (neweap == NULL) { 901189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " 902189251Ssam "memory for Phase 2 EAP data"); 903189251Ssam return -1; 904189251Ssam } 905189251Ssam os_memcpy(neweap + parse->eap_len, dpos, dlen); 906189251Ssam parse->eapdata = neweap; 907189251Ssam parse->eap_len += dlen; 908189251Ssam } 909189251Ssam 910189251Ssam return 0; 911189251Ssam} 912189251Ssam 913189251Ssam 914189251Ssamstatic int eap_ttls_parse_avp(u8 *pos, size_t left, 915189251Ssam struct ttls_parse_avp *parse) 916189251Ssam{ 917189251Ssam struct ttls_avp *avp; 918189251Ssam u32 avp_code, avp_length, vendor_id = 0; 919189251Ssam u8 avp_flags, *dpos; 920189251Ssam size_t dlen; 921189251Ssam 922189251Ssam avp = (struct ttls_avp *) pos; 923189251Ssam avp_code = be_to_host32(avp->avp_code); 924189251Ssam avp_length = be_to_host32(avp->avp_length); 925189251Ssam avp_flags = (avp_length >> 24) & 0xff; 926189251Ssam avp_length &= 0xffffff; 927189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " 928189251Ssam "length=%d", (int) avp_code, avp_flags, 929189251Ssam (int) avp_length); 930189251Ssam 931189251Ssam if (avp_length > left) { 932189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " 933189251Ssam "(len=%d, left=%lu) - dropped", 934189251Ssam (int) avp_length, (unsigned long) left); 935189251Ssam return -1; 936189251Ssam } 937189251Ssam 938189251Ssam if (avp_length < sizeof(*avp)) { 939189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", 940189251Ssam avp_length); 941189251Ssam return -1; 942189251Ssam } 943189251Ssam 944189251Ssam dpos = (u8 *) (avp + 1); 945189251Ssam dlen = avp_length - sizeof(*avp); 946189251Ssam if (avp_flags & AVP_FLAGS_VENDOR) { 947189251Ssam if (dlen < 4) { 948189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP " 949189251Ssam "underflow"); 950189251Ssam return -1; 951189251Ssam } 952189251Ssam vendor_id = WPA_GET_BE32(dpos); 953189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", 954189251Ssam (int) vendor_id); 955189251Ssam dpos += 4; 956189251Ssam dlen -= 4; 957189251Ssam } 958189251Ssam 959189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); 960189251Ssam 961189251Ssam if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { 962189251Ssam if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) 963189251Ssam return -1; 964189251Ssam } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { 965189251Ssam /* This is an optional message that can be displayed to 966189251Ssam * the user. */ 967189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", 968189251Ssam dpos, dlen); 969189251Ssam } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 970189251Ssam avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { 971189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success", 972189251Ssam dpos, dlen); 973189251Ssam if (dlen != 43) { 974189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " 975189251Ssam "MS-CHAP2-Success length " 976189251Ssam "(len=%lu, expected 43)", 977189251Ssam (unsigned long) dlen); 978189251Ssam return -1; 979189251Ssam } 980189251Ssam parse->mschapv2 = dpos; 981189251Ssam } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 982189251Ssam avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { 983189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error", 984189251Ssam dpos, dlen); 985189251Ssam parse->mschapv2_error = 1; 986189251Ssam } else if (avp_flags & AVP_FLAGS_MANDATORY) { 987189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP " 988189251Ssam "code %d vendor_id %d - dropped", 989189251Ssam (int) avp_code, (int) vendor_id); 990189251Ssam return -1; 991189251Ssam } else { 992189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " 993189251Ssam "code %d vendor_id %d", 994189251Ssam (int) avp_code, (int) vendor_id); 995189251Ssam } 996189251Ssam 997189251Ssam return avp_length; 998189251Ssam} 999189251Ssam 1000189251Ssam 1001189251Ssamstatic int eap_ttls_parse_avps(struct wpabuf *in_decrypted, 1002189251Ssam struct ttls_parse_avp *parse) 1003189251Ssam{ 1004189251Ssam u8 *pos; 1005189251Ssam size_t left, pad; 1006189251Ssam int avp_length; 1007189251Ssam 1008189251Ssam pos = wpabuf_mhead(in_decrypted); 1009189251Ssam left = wpabuf_len(in_decrypted); 1010189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); 1011189251Ssam if (left < sizeof(struct ttls_avp)) { 1012189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" 1013189251Ssam " len=%lu expected %lu or more - dropped", 1014189251Ssam (unsigned long) left, 1015189251Ssam (unsigned long) sizeof(struct ttls_avp)); 1016189251Ssam return -1; 1017189251Ssam } 1018189251Ssam 1019189251Ssam /* Parse AVPs */ 1020189251Ssam os_memset(parse, 0, sizeof(*parse)); 1021189251Ssam 1022189251Ssam while (left > 0) { 1023189251Ssam avp_length = eap_ttls_parse_avp(pos, left, parse); 1024189251Ssam if (avp_length < 0) 1025189251Ssam return -1; 1026189251Ssam 1027189251Ssam pad = (4 - (avp_length & 3)) & 3; 1028189251Ssam pos += avp_length + pad; 1029189251Ssam if (left < avp_length + pad) 1030189251Ssam left = 0; 1031189251Ssam else 1032189251Ssam left -= avp_length + pad; 1033189251Ssam } 1034189251Ssam 1035189251Ssam return 0; 1036189251Ssam} 1037189251Ssam 1038189251Ssam 1039189251Ssamstatic u8 * eap_ttls_fake_identity_request(void) 1040189251Ssam{ 1041189251Ssam struct eap_hdr *hdr; 1042189251Ssam u8 *buf; 1043189251Ssam 1044189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " 1045189251Ssam "Phase 2 - use fake EAP-Request Identity"); 1046189251Ssam buf = os_malloc(sizeof(*hdr) + 1); 1047189251Ssam if (buf == NULL) { 1048189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " 1049189251Ssam "memory for fake EAP-Identity Request"); 1050189251Ssam return NULL; 1051189251Ssam } 1052189251Ssam 1053189251Ssam hdr = (struct eap_hdr *) buf; 1054189251Ssam hdr->code = EAP_CODE_REQUEST; 1055189251Ssam hdr->identifier = 0; 1056189251Ssam hdr->length = host_to_be16(sizeof(*hdr) + 1); 1057189251Ssam buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; 1058189251Ssam 1059189251Ssam return buf; 1060189251Ssam} 1061189251Ssam 1062189251Ssam 1063189251Ssamstatic int eap_ttls_encrypt_response(struct eap_sm *sm, 1064189251Ssam struct eap_ttls_data *data, 1065189251Ssam struct wpabuf *resp, u8 identifier, 1066189251Ssam struct wpabuf **out_data) 1067189251Ssam{ 1068189251Ssam if (resp == NULL) 1069189251Ssam return 0; 1070189251Ssam 1071189251Ssam wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", 1072189251Ssam resp); 1073189251Ssam if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, 1074189251Ssam data->ttls_version, identifier, 1075189251Ssam resp, out_data)) { 1076189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " 1077189251Ssam "frame"); 1078346981Scy wpabuf_clear_free(resp); 1079189251Ssam return -1; 1080189251Ssam } 1081346981Scy wpabuf_clear_free(resp); 1082189251Ssam 1083189251Ssam return 0; 1084189251Ssam} 1085189251Ssam 1086189251Ssam 1087189251Ssamstatic int eap_ttls_process_phase2_eap(struct eap_sm *sm, 1088189251Ssam struct eap_ttls_data *data, 1089189251Ssam struct eap_method_ret *ret, 1090189251Ssam struct ttls_parse_avp *parse, 1091189251Ssam struct wpabuf **resp) 1092189251Ssam{ 1093189251Ssam struct eap_hdr *hdr; 1094189251Ssam size_t len; 1095189251Ssam 1096189251Ssam if (parse->eapdata == NULL) { 1097189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " 1098189251Ssam "packet - dropped"); 1099189251Ssam return -1; 1100189251Ssam } 1101189251Ssam 1102189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", 1103189251Ssam parse->eapdata, parse->eap_len); 1104189251Ssam hdr = (struct eap_hdr *) parse->eapdata; 1105189251Ssam 1106189251Ssam if (parse->eap_len < sizeof(*hdr)) { 1107189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " 1108189251Ssam "frame (len=%lu, expected %lu or more) - dropped", 1109189251Ssam (unsigned long) parse->eap_len, 1110189251Ssam (unsigned long) sizeof(*hdr)); 1111189251Ssam return -1; 1112189251Ssam } 1113189251Ssam len = be_to_host16(hdr->length); 1114189251Ssam if (len > parse->eap_len) { 1115189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " 1116189251Ssam "EAP frame (EAP hdr len=%lu, EAP data len in " 1117189251Ssam "AVP=%lu)", 1118189251Ssam (unsigned long) len, 1119189251Ssam (unsigned long) parse->eap_len); 1120189251Ssam return -1; 1121189251Ssam } 1122189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " 1123189251Ssam "identifier=%d length=%lu", 1124189251Ssam hdr->code, hdr->identifier, (unsigned long) len); 1125189251Ssam switch (hdr->code) { 1126189251Ssam case EAP_CODE_REQUEST: 1127189251Ssam if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { 1128189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " 1129189251Ssam "processing failed"); 1130189251Ssam return -1; 1131189251Ssam } 1132189251Ssam break; 1133189251Ssam default: 1134189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " 1135189251Ssam "Phase 2 EAP header", hdr->code); 1136189251Ssam return -1; 1137189251Ssam } 1138189251Ssam 1139189251Ssam return 0; 1140189251Ssam} 1141189251Ssam 1142189251Ssam 1143189251Ssamstatic int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, 1144189251Ssam struct eap_ttls_data *data, 1145189251Ssam struct eap_method_ret *ret, 1146189251Ssam struct ttls_parse_avp *parse) 1147189251Ssam{ 1148252726Srpaulo#ifdef EAP_MSCHAPv2 1149189251Ssam if (parse->mschapv2_error) { 1150189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " 1151189251Ssam "MS-CHAP-Error - failed"); 1152189251Ssam ret->methodState = METHOD_DONE; 1153189251Ssam ret->decision = DECISION_FAIL; 1154189251Ssam /* Reply with empty data to ACK error */ 1155189251Ssam return 1; 1156189251Ssam } 1157189251Ssam 1158189251Ssam if (parse->mschapv2 == NULL) { 1159189251Ssam#ifdef EAP_TNC 1160189251Ssam if (data->phase2_success && parse->eapdata) { 1161189251Ssam /* 1162189251Ssam * Allow EAP-TNC to be started after successfully 1163189251Ssam * completed MSCHAPV2. 1164189251Ssam */ 1165189251Ssam return 1; 1166189251Ssam } 1167189251Ssam#endif /* EAP_TNC */ 1168189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " 1169189251Ssam "received for Phase2 MSCHAPV2"); 1170189251Ssam return -1; 1171189251Ssam } 1172189251Ssam if (parse->mschapv2[0] != data->ident) { 1173189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " 1174189251Ssam "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", 1175189251Ssam parse->mschapv2[0], data->ident); 1176189251Ssam return -1; 1177189251Ssam } 1178189251Ssam if (!data->auth_response_valid || 1179189251Ssam mschapv2_verify_auth_response(data->auth_response, 1180189251Ssam parse->mschapv2 + 1, 42)) { 1181189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " 1182189251Ssam "response in Phase 2 MSCHAPV2 success request"); 1183189251Ssam return -1; 1184189251Ssam } 1185189251Ssam 1186189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " 1187189251Ssam "authentication succeeded"); 1188252726Srpaulo ret->methodState = METHOD_DONE; 1189252726Srpaulo ret->decision = DECISION_UNCOND_SUCC; 1190252726Srpaulo data->phase2_success = 1; 1191189251Ssam 1192189251Ssam /* 1193189251Ssam * Reply with empty data; authentication server will reply 1194189251Ssam * with EAP-Success after this. 1195189251Ssam */ 1196189251Ssam return 1; 1197252726Srpaulo#else /* EAP_MSCHAPv2 */ 1198252726Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); 1199252726Srpaulo return -1; 1200252726Srpaulo#endif /* EAP_MSCHAPv2 */ 1201189251Ssam} 1202189251Ssam 1203189251Ssam 1204189251Ssam#ifdef EAP_TNC 1205189251Ssamstatic int eap_ttls_process_tnc_start(struct eap_sm *sm, 1206189251Ssam struct eap_ttls_data *data, 1207189251Ssam struct eap_method_ret *ret, 1208189251Ssam struct ttls_parse_avp *parse, 1209189251Ssam struct wpabuf **resp) 1210189251Ssam{ 1211189251Ssam /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ 1212189251Ssam if (parse->eapdata == NULL) { 1213189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " 1214189251Ssam "unexpected tunneled data (no EAP)"); 1215189251Ssam return -1; 1216189251Ssam } 1217189251Ssam 1218189251Ssam if (!data->ready_for_tnc) { 1219189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " 1220189251Ssam "EAP after non-EAP, but not ready for TNC"); 1221189251Ssam return -1; 1222189251Ssam } 1223189251Ssam 1224189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " 1225189251Ssam "non-EAP method"); 1226189251Ssam data->tnc_started = 1; 1227189251Ssam 1228189251Ssam if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) 1229189251Ssam return -1; 1230189251Ssam 1231189251Ssam return 0; 1232189251Ssam} 1233189251Ssam#endif /* EAP_TNC */ 1234189251Ssam 1235189251Ssam 1236189251Ssamstatic int eap_ttls_process_decrypted(struct eap_sm *sm, 1237189251Ssam struct eap_ttls_data *data, 1238189251Ssam struct eap_method_ret *ret, 1239189251Ssam u8 identifier, 1240189251Ssam struct ttls_parse_avp *parse, 1241189251Ssam struct wpabuf *in_decrypted, 1242189251Ssam struct wpabuf **out_data) 1243189251Ssam{ 1244189251Ssam struct wpabuf *resp = NULL; 1245189251Ssam struct eap_peer_config *config = eap_get_config(sm); 1246189251Ssam int res; 1247189251Ssam enum phase2_types phase2_type = data->phase2_type; 1248189251Ssam 1249189251Ssam#ifdef EAP_TNC 1250189251Ssam if (data->tnc_started) 1251189251Ssam phase2_type = EAP_TTLS_PHASE2_EAP; 1252189251Ssam#endif /* EAP_TNC */ 1253189251Ssam 1254189251Ssam switch (phase2_type) { 1255189251Ssam case EAP_TTLS_PHASE2_EAP: 1256189251Ssam if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < 1257189251Ssam 0) 1258189251Ssam return -1; 1259189251Ssam break; 1260189251Ssam case EAP_TTLS_PHASE2_MSCHAPV2: 1261189251Ssam res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); 1262189251Ssam#ifdef EAP_TNC 1263189251Ssam if (res == 1 && parse->eapdata && data->phase2_success) { 1264189251Ssam /* 1265189251Ssam * TNC may be required as the next 1266189251Ssam * authentication method within the tunnel. 1267189251Ssam */ 1268189251Ssam ret->methodState = METHOD_MAY_CONT; 1269189251Ssam data->ready_for_tnc = 1; 1270189251Ssam if (eap_ttls_process_tnc_start(sm, data, ret, parse, 1271189251Ssam &resp) == 0) 1272189251Ssam break; 1273189251Ssam } 1274189251Ssam#endif /* EAP_TNC */ 1275189251Ssam return res; 1276189251Ssam case EAP_TTLS_PHASE2_MSCHAP: 1277189251Ssam case EAP_TTLS_PHASE2_PAP: 1278189251Ssam case EAP_TTLS_PHASE2_CHAP: 1279189251Ssam#ifdef EAP_TNC 1280189251Ssam if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < 1281189251Ssam 0) 1282189251Ssam return -1; 1283189251Ssam break; 1284189251Ssam#else /* EAP_TNC */ 1285189251Ssam /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled 1286189251Ssam * requests to the supplicant */ 1287189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " 1288189251Ssam "tunneled data"); 1289189251Ssam return -1; 1290189251Ssam#endif /* EAP_TNC */ 1291189251Ssam } 1292189251Ssam 1293189251Ssam if (resp) { 1294189251Ssam if (eap_ttls_encrypt_response(sm, data, resp, identifier, 1295189251Ssam out_data) < 0) 1296189251Ssam return -1; 1297189251Ssam } else if (config->pending_req_identity || 1298189251Ssam config->pending_req_password || 1299189251Ssam config->pending_req_otp || 1300346981Scy config->pending_req_new_password || 1301346981Scy config->pending_req_sim) { 1302346981Scy wpabuf_clear_free(data->pending_phase2_req); 1303189251Ssam data->pending_phase2_req = wpabuf_dup(in_decrypted); 1304189251Ssam } 1305189251Ssam 1306189251Ssam return 0; 1307189251Ssam} 1308189251Ssam 1309189251Ssam 1310189251Ssamstatic int eap_ttls_implicit_identity_request(struct eap_sm *sm, 1311189251Ssam struct eap_ttls_data *data, 1312189251Ssam struct eap_method_ret *ret, 1313189251Ssam u8 identifier, 1314189251Ssam struct wpabuf **out_data) 1315189251Ssam{ 1316189251Ssam int retval = 0; 1317189251Ssam struct eap_hdr *hdr; 1318189251Ssam struct wpabuf *resp; 1319189251Ssam 1320189251Ssam hdr = (struct eap_hdr *) eap_ttls_fake_identity_request(); 1321189251Ssam if (hdr == NULL) { 1322189251Ssam ret->methodState = METHOD_DONE; 1323189251Ssam ret->decision = DECISION_FAIL; 1324189251Ssam return -1; 1325189251Ssam } 1326189251Ssam 1327189251Ssam resp = NULL; 1328189251Ssam if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) { 1329189251Ssam wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " 1330189251Ssam "processing failed"); 1331189251Ssam retval = -1; 1332189251Ssam } else { 1333252726Srpaulo struct eap_peer_config *config = eap_get_config(sm); 1334252726Srpaulo if (resp == NULL && 1335252726Srpaulo (config->pending_req_identity || 1336252726Srpaulo config->pending_req_password || 1337252726Srpaulo config->pending_req_otp || 1338346981Scy config->pending_req_new_password || 1339346981Scy config->pending_req_sim)) { 1340252726Srpaulo /* 1341252726Srpaulo * Use empty buffer to force implicit request 1342252726Srpaulo * processing when EAP request is re-processed after 1343252726Srpaulo * user input. 1344252726Srpaulo */ 1345346981Scy wpabuf_clear_free(data->pending_phase2_req); 1346252726Srpaulo data->pending_phase2_req = wpabuf_alloc(0); 1347252726Srpaulo } 1348252726Srpaulo 1349189251Ssam retval = eap_ttls_encrypt_response(sm, data, resp, identifier, 1350189251Ssam out_data); 1351189251Ssam } 1352189251Ssam 1353189251Ssam os_free(hdr); 1354189251Ssam 1355189251Ssam if (retval < 0) { 1356189251Ssam ret->methodState = METHOD_DONE; 1357189251Ssam ret->decision = DECISION_FAIL; 1358189251Ssam } 1359189251Ssam 1360189251Ssam return retval; 1361189251Ssam} 1362189251Ssam 1363189251Ssam 1364189251Ssamstatic int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data, 1365189251Ssam struct eap_method_ret *ret, u8 identifier, 1366189251Ssam struct wpabuf **out_data) 1367189251Ssam{ 1368189251Ssam data->phase2_start = 0; 1369189251Ssam 1370189251Ssam /* 1371189251Ssam * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only 1372189251Ssam * if TLS part was indeed resuming a previous session. Most 1373189251Ssam * Authentication Servers terminate EAP-TTLS before reaching this 1374189251Ssam * point, but some do not. Make wpa_supplicant stop phase 2 here, if 1375189251Ssam * needed. 1376189251Ssam */ 1377189251Ssam if (data->reauth && 1378189251Ssam tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { 1379189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " 1380189251Ssam "skip phase 2"); 1381189251Ssam *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS, 1382189251Ssam data->ttls_version); 1383189251Ssam ret->methodState = METHOD_DONE; 1384189251Ssam ret->decision = DECISION_UNCOND_SUCC; 1385189251Ssam data->phase2_success = 1; 1386189251Ssam return 0; 1387189251Ssam } 1388189251Ssam 1389189251Ssam return eap_ttls_implicit_identity_request(sm, data, ret, identifier, 1390189251Ssam out_data); 1391189251Ssam} 1392189251Ssam 1393189251Ssam 1394189251Ssamstatic int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, 1395189251Ssam struct eap_method_ret *ret, u8 identifier, 1396189251Ssam const struct wpabuf *in_data, 1397189251Ssam struct wpabuf **out_data) 1398189251Ssam{ 1399189251Ssam struct wpabuf *in_decrypted = NULL; 1400189251Ssam int retval = 0; 1401189251Ssam struct ttls_parse_avp parse; 1402189251Ssam 1403189251Ssam os_memset(&parse, 0, sizeof(parse)); 1404189251Ssam 1405189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" 1406189251Ssam " Phase 2", 1407189251Ssam in_data ? (unsigned long) wpabuf_len(in_data) : 0); 1408189251Ssam 1409189251Ssam if (data->pending_phase2_req) { 1410189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " 1411189251Ssam "skip decryption and use old data"); 1412189251Ssam /* Clear TLS reassembly state. */ 1413189251Ssam eap_peer_tls_reset_input(&data->ssl); 1414189251Ssam 1415189251Ssam in_decrypted = data->pending_phase2_req; 1416189251Ssam data->pending_phase2_req = NULL; 1417189251Ssam if (wpabuf_len(in_decrypted) == 0) { 1418346981Scy wpabuf_clear_free(in_decrypted); 1419189251Ssam return eap_ttls_implicit_identity_request( 1420189251Ssam sm, data, ret, identifier, out_data); 1421189251Ssam } 1422189251Ssam goto continue_req; 1423189251Ssam } 1424189251Ssam 1425189251Ssam if ((in_data == NULL || wpabuf_len(in_data) == 0) && 1426189251Ssam data->phase2_start) { 1427189251Ssam return eap_ttls_phase2_start(sm, data, ret, identifier, 1428189251Ssam out_data); 1429189251Ssam } 1430189251Ssam 1431189251Ssam if (in_data == NULL || wpabuf_len(in_data) == 0) { 1432189251Ssam /* Received TLS ACK - requesting more fragments */ 1433189251Ssam return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, 1434189251Ssam data->ttls_version, 1435189251Ssam identifier, NULL, out_data); 1436189251Ssam } 1437189251Ssam 1438189251Ssam retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); 1439189251Ssam if (retval) 1440189251Ssam goto done; 1441189251Ssam 1442189251Ssamcontinue_req: 1443189251Ssam data->phase2_start = 0; 1444189251Ssam 1445189251Ssam if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) { 1446189251Ssam retval = -1; 1447189251Ssam goto done; 1448189251Ssam } 1449189251Ssam 1450189251Ssam retval = eap_ttls_process_decrypted(sm, data, ret, identifier, 1451189251Ssam &parse, in_decrypted, out_data); 1452189251Ssam 1453189251Ssamdone: 1454346981Scy wpabuf_clear_free(in_decrypted); 1455189251Ssam os_free(parse.eapdata); 1456189251Ssam 1457189251Ssam if (retval < 0) { 1458189251Ssam ret->methodState = METHOD_DONE; 1459189251Ssam ret->decision = DECISION_FAIL; 1460189251Ssam } 1461189251Ssam 1462189251Ssam return retval; 1463189251Ssam} 1464189251Ssam 1465189251Ssam 1466189251Ssamstatic int eap_ttls_process_handshake(struct eap_sm *sm, 1467189251Ssam struct eap_ttls_data *data, 1468189251Ssam struct eap_method_ret *ret, 1469189251Ssam u8 identifier, 1470289549Srpaulo const struct wpabuf *in_data, 1471189251Ssam struct wpabuf **out_data) 1472189251Ssam{ 1473189251Ssam int res; 1474189251Ssam 1475337817Scy if (sm->waiting_ext_cert_check && data->pending_resp) { 1476337817Scy struct eap_peer_config *config = eap_get_config(sm); 1477337817Scy 1478337817Scy if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) { 1479337817Scy wpa_printf(MSG_DEBUG, 1480337817Scy "EAP-TTLS: External certificate check succeeded - continue handshake"); 1481337817Scy *out_data = data->pending_resp; 1482337817Scy data->pending_resp = NULL; 1483337817Scy sm->waiting_ext_cert_check = 0; 1484337817Scy return 0; 1485337817Scy } 1486337817Scy 1487337817Scy if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) { 1488337817Scy wpa_printf(MSG_DEBUG, 1489337817Scy "EAP-TTLS: External certificate check failed - force authentication failure"); 1490337817Scy ret->methodState = METHOD_DONE; 1491337817Scy ret->decision = DECISION_FAIL; 1492337817Scy sm->waiting_ext_cert_check = 0; 1493337817Scy return 0; 1494337817Scy } 1495337817Scy 1496337817Scy wpa_printf(MSG_DEBUG, 1497337817Scy "EAP-TTLS: Continuing to wait external server certificate validation"); 1498337817Scy return 0; 1499337817Scy } 1500337817Scy 1501189251Ssam res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, 1502189251Ssam data->ttls_version, identifier, 1503289549Srpaulo in_data, out_data); 1504289549Srpaulo if (res < 0) { 1505289549Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed"); 1506289549Srpaulo ret->methodState = METHOD_DONE; 1507289549Srpaulo ret->decision = DECISION_FAIL; 1508289549Srpaulo return -1; 1509289549Srpaulo } 1510189251Ssam 1511337817Scy if (sm->waiting_ext_cert_check) { 1512337817Scy wpa_printf(MSG_DEBUG, 1513337817Scy "EAP-TTLS: Waiting external server certificate validation"); 1514346981Scy wpabuf_clear_free(data->pending_resp); 1515337817Scy data->pending_resp = *out_data; 1516337817Scy *out_data = NULL; 1517337817Scy return 0; 1518337817Scy } 1519337817Scy 1520189251Ssam if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 1521189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " 1522189251Ssam "Phase 2"); 1523189251Ssam if (data->resuming) { 1524189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may " 1525189251Ssam "skip Phase 2"); 1526189251Ssam ret->decision = DECISION_COND_SUCC; 1527189251Ssam ret->methodState = METHOD_MAY_CONT; 1528189251Ssam } 1529189251Ssam data->phase2_start = 1; 1530252726Srpaulo eap_ttls_v0_derive_key(sm, data); 1531189251Ssam 1532189251Ssam if (*out_data == NULL || wpabuf_len(*out_data) == 0) { 1533189251Ssam if (eap_ttls_decrypt(sm, data, ret, identifier, 1534189251Ssam NULL, out_data)) { 1535189251Ssam wpa_printf(MSG_WARNING, "EAP-TTLS: " 1536189251Ssam "failed to process early " 1537189251Ssam "start for Phase 2"); 1538189251Ssam } 1539189251Ssam res = 0; 1540189251Ssam } 1541189251Ssam data->resuming = 0; 1542189251Ssam } 1543189251Ssam 1544189251Ssam if (res == 2) { 1545189251Ssam /* 1546189251Ssam * Application data included in the handshake message. 1547189251Ssam */ 1548346981Scy wpabuf_clear_free(data->pending_phase2_req); 1549189251Ssam data->pending_phase2_req = *out_data; 1550189251Ssam *out_data = NULL; 1551289549Srpaulo res = eap_ttls_decrypt(sm, data, ret, identifier, in_data, 1552189251Ssam out_data); 1553189251Ssam } 1554189251Ssam 1555189251Ssam return res; 1556189251Ssam} 1557189251Ssam 1558189251Ssam 1559346981Scystatic void eap_ttls_check_auth_status(struct eap_sm *sm, 1560189251Ssam struct eap_ttls_data *data, 1561189251Ssam struct eap_method_ret *ret) 1562189251Ssam{ 1563252726Srpaulo if (ret->methodState == METHOD_DONE) { 1564189251Ssam ret->allowNotifications = FALSE; 1565189251Ssam if (ret->decision == DECISION_UNCOND_SUCC || 1566189251Ssam ret->decision == DECISION_COND_SUCC) { 1567189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " 1568189251Ssam "completed successfully"); 1569189251Ssam data->phase2_success = 1; 1570337817Scy data->decision_succ = ret->decision; 1571189251Ssam#ifdef EAP_TNC 1572189251Ssam if (!data->ready_for_tnc && !data->tnc_started) { 1573189251Ssam /* 1574189251Ssam * TNC may be required as the next 1575189251Ssam * authentication method within the tunnel. 1576189251Ssam */ 1577189251Ssam ret->methodState = METHOD_MAY_CONT; 1578189251Ssam data->ready_for_tnc = 1; 1579189251Ssam } 1580189251Ssam#endif /* EAP_TNC */ 1581189251Ssam } 1582252726Srpaulo } else if (ret->methodState == METHOD_MAY_CONT && 1583189251Ssam (ret->decision == DECISION_UNCOND_SUCC || 1584189251Ssam ret->decision == DECISION_COND_SUCC)) { 1585189251Ssam wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " 1586189251Ssam "completed successfully (MAY_CONT)"); 1587189251Ssam data->phase2_success = 1; 1588337817Scy data->decision_succ = ret->decision; 1589337817Scy } else if (data->decision_succ != DECISION_FAIL && 1590337817Scy data->phase2_success && 1591337817Scy !data->ssl.tls_out) { 1592337817Scy /* 1593337817Scy * This is needed to cover the case where the final Phase 2 1594337817Scy * message gets fragmented since fragmentation clears 1595337817Scy * decision back to FAIL. 1596337817Scy */ 1597337817Scy wpa_printf(MSG_DEBUG, 1598337817Scy "EAP-TTLS: Restore success decision after fragmented frame sent completely"); 1599337817Scy ret->decision = data->decision_succ; 1600189251Ssam } 1601189251Ssam} 1602189251Ssam 1603189251Ssam 1604189251Ssamstatic struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, 1605189251Ssam struct eap_method_ret *ret, 1606189251Ssam const struct wpabuf *reqData) 1607189251Ssam{ 1608189251Ssam size_t left; 1609189251Ssam int res; 1610189251Ssam u8 flags, id; 1611189251Ssam struct wpabuf *resp; 1612189251Ssam const u8 *pos; 1613189251Ssam struct eap_ttls_data *data = priv; 1614289549Srpaulo struct wpabuf msg; 1615189251Ssam 1616189251Ssam pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, 1617189251Ssam reqData, &left, &flags); 1618189251Ssam if (pos == NULL) 1619189251Ssam return NULL; 1620189251Ssam id = eap_get_id(reqData); 1621189251Ssam 1622189251Ssam if (flags & EAP_TLS_FLAGS_START) { 1623252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own " 1624252726Srpaulo "ver=%d)", flags & EAP_TLS_VERSION_MASK, 1625252726Srpaulo data->ttls_version); 1626189251Ssam 1627189251Ssam /* RFC 5281, Ch. 9.2: 1628189251Ssam * "This packet MAY contain additional information in the form 1629189251Ssam * of AVPs, which may provide useful hints to the client" 1630189251Ssam * For now, ignore any potential extra data. 1631189251Ssam */ 1632189251Ssam left = 0; 1633189251Ssam } 1634189251Ssam 1635289549Srpaulo wpabuf_set(&msg, pos, left); 1636289549Srpaulo 1637189251Ssam resp = NULL; 1638189251Ssam if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 1639189251Ssam !data->resuming) { 1640189251Ssam res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); 1641189251Ssam } else { 1642189251Ssam res = eap_ttls_process_handshake(sm, data, ret, id, 1643289549Srpaulo &msg, &resp); 1644189251Ssam } 1645189251Ssam 1646189251Ssam eap_ttls_check_auth_status(sm, data, ret); 1647189251Ssam 1648189251Ssam /* FIX: what about res == -1? Could just move all error processing into 1649189251Ssam * the other functions and get rid of this res==1 case here. */ 1650189251Ssam if (res == 1) { 1651346981Scy wpabuf_clear_free(resp); 1652189251Ssam return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, 1653189251Ssam data->ttls_version); 1654189251Ssam } 1655189251Ssam return resp; 1656189251Ssam} 1657189251Ssam 1658189251Ssam 1659189251Ssamstatic Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) 1660189251Ssam{ 1661189251Ssam struct eap_ttls_data *data = priv; 1662189251Ssam return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 1663189251Ssam data->phase2_success; 1664189251Ssam} 1665189251Ssam 1666189251Ssam 1667189251Ssamstatic void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) 1668189251Ssam{ 1669189251Ssam struct eap_ttls_data *data = priv; 1670346981Scy 1671346981Scy if (data->phase2_priv && data->phase2_method && 1672346981Scy data->phase2_method->deinit_for_reauth) 1673346981Scy data->phase2_method->deinit_for_reauth(sm, data->phase2_priv); 1674346981Scy wpabuf_clear_free(data->pending_phase2_req); 1675189251Ssam data->pending_phase2_req = NULL; 1676346981Scy wpabuf_clear_free(data->pending_resp); 1677337817Scy data->pending_resp = NULL; 1678337817Scy data->decision_succ = DECISION_FAIL; 1679189251Ssam#ifdef EAP_TNC 1680189251Ssam data->ready_for_tnc = 0; 1681189251Ssam data->tnc_started = 0; 1682189251Ssam#endif /* EAP_TNC */ 1683189251Ssam} 1684189251Ssam 1685189251Ssam 1686189251Ssamstatic void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) 1687189251Ssam{ 1688189251Ssam struct eap_ttls_data *data = priv; 1689281806Srpaulo eap_ttls_free_key(data); 1690281806Srpaulo os_free(data->session_id); 1691281806Srpaulo data->session_id = NULL; 1692189251Ssam if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 1693189251Ssam os_free(data); 1694189251Ssam return NULL; 1695189251Ssam } 1696189251Ssam if (data->phase2_priv && data->phase2_method && 1697189251Ssam data->phase2_method->init_for_reauth) 1698189251Ssam data->phase2_method->init_for_reauth(sm, data->phase2_priv); 1699189251Ssam data->phase2_start = 0; 1700189251Ssam data->phase2_success = 0; 1701189251Ssam data->resuming = 1; 1702189251Ssam data->reauth = 1; 1703189251Ssam return priv; 1704189251Ssam} 1705189251Ssam 1706189251Ssam 1707189251Ssamstatic int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, 1708189251Ssam size_t buflen, int verbose) 1709189251Ssam{ 1710189251Ssam struct eap_ttls_data *data = priv; 1711189251Ssam int len, ret; 1712189251Ssam 1713189251Ssam len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 1714189251Ssam ret = os_snprintf(buf + len, buflen - len, 1715189251Ssam "EAP-TTLSv%d Phase2 method=", 1716189251Ssam data->ttls_version); 1717281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 1718189251Ssam return len; 1719189251Ssam len += ret; 1720189251Ssam switch (data->phase2_type) { 1721189251Ssam case EAP_TTLS_PHASE2_EAP: 1722189251Ssam ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", 1723189251Ssam data->phase2_method ? 1724189251Ssam data->phase2_method->name : "?"); 1725189251Ssam break; 1726189251Ssam case EAP_TTLS_PHASE2_MSCHAPV2: 1727189251Ssam ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); 1728189251Ssam break; 1729189251Ssam case EAP_TTLS_PHASE2_MSCHAP: 1730189251Ssam ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); 1731189251Ssam break; 1732189251Ssam case EAP_TTLS_PHASE2_PAP: 1733189251Ssam ret = os_snprintf(buf + len, buflen - len, "PAP\n"); 1734189251Ssam break; 1735189251Ssam case EAP_TTLS_PHASE2_CHAP: 1736189251Ssam ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); 1737189251Ssam break; 1738189251Ssam default: 1739189251Ssam ret = 0; 1740189251Ssam break; 1741189251Ssam } 1742281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 1743189251Ssam return len; 1744189251Ssam len += ret; 1745189251Ssam 1746189251Ssam return len; 1747189251Ssam} 1748189251Ssam 1749189251Ssam 1750189251Ssamstatic Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) 1751189251Ssam{ 1752189251Ssam struct eap_ttls_data *data = priv; 1753189251Ssam return data->key_data != NULL && data->phase2_success; 1754189251Ssam} 1755189251Ssam 1756189251Ssam 1757189251Ssamstatic u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) 1758189251Ssam{ 1759189251Ssam struct eap_ttls_data *data = priv; 1760189251Ssam u8 *key; 1761189251Ssam 1762189251Ssam if (data->key_data == NULL || !data->phase2_success) 1763189251Ssam return NULL; 1764189251Ssam 1765346981Scy key = os_memdup(data->key_data, EAP_TLS_KEY_LEN); 1766189251Ssam if (key == NULL) 1767189251Ssam return NULL; 1768189251Ssam 1769189251Ssam *len = EAP_TLS_KEY_LEN; 1770189251Ssam 1771189251Ssam return key; 1772189251Ssam} 1773189251Ssam 1774189251Ssam 1775281806Srpaulostatic u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 1776281806Srpaulo{ 1777281806Srpaulo struct eap_ttls_data *data = priv; 1778281806Srpaulo u8 *id; 1779281806Srpaulo 1780281806Srpaulo if (data->session_id == NULL || !data->phase2_success) 1781281806Srpaulo return NULL; 1782281806Srpaulo 1783346981Scy id = os_memdup(data->session_id, data->id_len); 1784281806Srpaulo if (id == NULL) 1785281806Srpaulo return NULL; 1786281806Srpaulo 1787281806Srpaulo *len = data->id_len; 1788281806Srpaulo 1789281806Srpaulo return id; 1790281806Srpaulo} 1791281806Srpaulo 1792281806Srpaulo 1793281806Srpaulostatic u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 1794281806Srpaulo{ 1795281806Srpaulo struct eap_ttls_data *data = priv; 1796281806Srpaulo u8 *key; 1797281806Srpaulo 1798281806Srpaulo if (data->key_data == NULL) 1799281806Srpaulo return NULL; 1800281806Srpaulo 1801346981Scy key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); 1802281806Srpaulo if (key == NULL) 1803281806Srpaulo return NULL; 1804281806Srpaulo 1805281806Srpaulo *len = EAP_EMSK_LEN; 1806281806Srpaulo 1807281806Srpaulo return key; 1808281806Srpaulo} 1809281806Srpaulo 1810281806Srpaulo 1811189251Ssamint eap_peer_ttls_register(void) 1812189251Ssam{ 1813189251Ssam struct eap_method *eap; 1814189251Ssam 1815189251Ssam eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 1816189251Ssam EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); 1817189251Ssam if (eap == NULL) 1818189251Ssam return -1; 1819189251Ssam 1820189251Ssam eap->init = eap_ttls_init; 1821189251Ssam eap->deinit = eap_ttls_deinit; 1822189251Ssam eap->process = eap_ttls_process; 1823189251Ssam eap->isKeyAvailable = eap_ttls_isKeyAvailable; 1824189251Ssam eap->getKey = eap_ttls_getKey; 1825281806Srpaulo eap->getSessionId = eap_ttls_get_session_id; 1826189251Ssam eap->get_status = eap_ttls_get_status; 1827189251Ssam eap->has_reauth_data = eap_ttls_has_reauth_data; 1828189251Ssam eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; 1829189251Ssam eap->init_for_reauth = eap_ttls_init_for_reauth; 1830281806Srpaulo eap->get_emsk = eap_ttls_get_emsk; 1831189251Ssam 1832337817Scy return eap_peer_method_register(eap); 1833189251Ssam} 1834