1214501Srpaulo/* 2214501Srpaulo * hostapd / EAP-TTLS (RFC 5281) 3214501Srpaulo * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5214501Srpaulo * This program is free software; you can redistribute it and/or modify 6214501Srpaulo * it under the terms of the GNU General Public License version 2 as 7214501Srpaulo * published by the Free Software Foundation. 8214501Srpaulo * 9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214501Srpaulo * license. 11214501Srpaulo * 12214501Srpaulo * See README and COPYING for more details. 13214501Srpaulo */ 14214501Srpaulo 15214501Srpaulo#include "includes.h" 16214501Srpaulo 17214501Srpaulo#include "common.h" 18214501Srpaulo#include "crypto/ms_funcs.h" 19214501Srpaulo#include "crypto/sha1.h" 20214501Srpaulo#include "crypto/tls.h" 21214501Srpaulo#include "eap_server/eap_i.h" 22214501Srpaulo#include "eap_server/eap_tls_common.h" 23214501Srpaulo#include "eap_common/chap.h" 24214501Srpaulo#include "eap_common/eap_ttls.h" 25214501Srpaulo 26214501Srpaulo 27214501Srpaulo/* Maximum supported TTLS version 28214501Srpaulo * 0 = RFC 5281 29214501Srpaulo * 1 = draft-funk-eap-ttls-v1-00.txt 30214501Srpaulo */ 31214501Srpaulo#ifndef EAP_TTLS_VERSION 32214501Srpaulo#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */ 33214501Srpaulo#endif /* EAP_TTLS_VERSION */ 34214501Srpaulo 35214501Srpaulo 36214501Srpaulo#define MSCHAPV2_KEY_LEN 16 37214501Srpaulo 38214501Srpaulo 39214501Srpaulostatic void eap_ttls_reset(struct eap_sm *sm, void *priv); 40214501Srpaulo 41214501Srpaulo 42214501Srpaulostruct eap_ttls_data { 43214501Srpaulo struct eap_ssl_data ssl; 44214501Srpaulo enum { 45214501Srpaulo START, PHASE1, PHASE2_START, PHASE2_METHOD, 46214501Srpaulo PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE 47214501Srpaulo } state; 48214501Srpaulo 49214501Srpaulo int ttls_version; 50214501Srpaulo int force_version; 51214501Srpaulo const struct eap_method *phase2_method; 52214501Srpaulo void *phase2_priv; 53214501Srpaulo int mschapv2_resp_ok; 54214501Srpaulo u8 mschapv2_auth_response[20]; 55214501Srpaulo u8 mschapv2_ident; 56214501Srpaulo int tls_ia_configured; 57214501Srpaulo struct wpabuf *pending_phase2_eap_resp; 58214501Srpaulo int tnc_started; 59214501Srpaulo}; 60214501Srpaulo 61214501Srpaulo 62214501Srpaulostatic const char * eap_ttls_state_txt(int state) 63214501Srpaulo{ 64214501Srpaulo switch (state) { 65214501Srpaulo case START: 66214501Srpaulo return "START"; 67214501Srpaulo case PHASE1: 68214501Srpaulo return "PHASE1"; 69214501Srpaulo case PHASE2_START: 70214501Srpaulo return "PHASE2_START"; 71214501Srpaulo case PHASE2_METHOD: 72214501Srpaulo return "PHASE2_METHOD"; 73214501Srpaulo case PHASE2_MSCHAPV2_RESP: 74214501Srpaulo return "PHASE2_MSCHAPV2_RESP"; 75214501Srpaulo case PHASE_FINISHED: 76214501Srpaulo return "PHASE_FINISHED"; 77214501Srpaulo case SUCCESS: 78214501Srpaulo return "SUCCESS"; 79214501Srpaulo case FAILURE: 80214501Srpaulo return "FAILURE"; 81214501Srpaulo default: 82214501Srpaulo return "Unknown?!"; 83214501Srpaulo } 84214501Srpaulo} 85214501Srpaulo 86214501Srpaulo 87214501Srpaulostatic void eap_ttls_state(struct eap_ttls_data *data, int state) 88214501Srpaulo{ 89214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: %s -> %s", 90214501Srpaulo eap_ttls_state_txt(data->state), 91214501Srpaulo eap_ttls_state_txt(state)); 92214501Srpaulo data->state = state; 93214501Srpaulo} 94214501Srpaulo 95214501Srpaulo 96214501Srpaulostatic u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, 97214501Srpaulo int mandatory, size_t len) 98214501Srpaulo{ 99214501Srpaulo struct ttls_avp_vendor *avp; 100214501Srpaulo u8 flags; 101214501Srpaulo size_t hdrlen; 102214501Srpaulo 103214501Srpaulo avp = (struct ttls_avp_vendor *) avphdr; 104214501Srpaulo flags = mandatory ? AVP_FLAGS_MANDATORY : 0; 105214501Srpaulo if (vendor_id) { 106214501Srpaulo flags |= AVP_FLAGS_VENDOR; 107214501Srpaulo hdrlen = sizeof(*avp); 108214501Srpaulo avp->vendor_id = host_to_be32(vendor_id); 109214501Srpaulo } else { 110214501Srpaulo hdrlen = sizeof(struct ttls_avp); 111214501Srpaulo } 112214501Srpaulo 113214501Srpaulo avp->avp_code = host_to_be32(avp_code); 114214501Srpaulo avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len)); 115214501Srpaulo 116214501Srpaulo return avphdr + hdrlen; 117214501Srpaulo} 118214501Srpaulo 119214501Srpaulo 120214501Srpaulostatic struct wpabuf * eap_ttls_avp_encapsulate(struct wpabuf *resp, 121214501Srpaulo u32 avp_code, int mandatory) 122214501Srpaulo{ 123214501Srpaulo struct wpabuf *avp; 124214501Srpaulo u8 *pos; 125214501Srpaulo 126214501Srpaulo avp = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(resp) + 4); 127214501Srpaulo if (avp == NULL) { 128214501Srpaulo wpabuf_free(resp); 129214501Srpaulo return NULL; 130214501Srpaulo } 131214501Srpaulo 132214501Srpaulo pos = eap_ttls_avp_hdr(wpabuf_mhead(avp), avp_code, 0, mandatory, 133214501Srpaulo wpabuf_len(resp)); 134214501Srpaulo os_memcpy(pos, wpabuf_head(resp), wpabuf_len(resp)); 135214501Srpaulo pos += wpabuf_len(resp); 136214501Srpaulo AVP_PAD((const u8 *) wpabuf_head(avp), pos); 137214501Srpaulo wpabuf_free(resp); 138214501Srpaulo wpabuf_put(avp, pos - (u8 *) wpabuf_head(avp)); 139214501Srpaulo return avp; 140214501Srpaulo} 141214501Srpaulo 142214501Srpaulo 143214501Srpaulostruct eap_ttls_avp { 144214501Srpaulo /* Note: eap is allocated memory; caller is responsible for freeing 145214501Srpaulo * it. All the other pointers are pointing to the packet data, i.e., 146214501Srpaulo * they must not be freed separately. */ 147214501Srpaulo u8 *eap; 148214501Srpaulo size_t eap_len; 149214501Srpaulo u8 *user_name; 150214501Srpaulo size_t user_name_len; 151214501Srpaulo u8 *user_password; 152214501Srpaulo size_t user_password_len; 153214501Srpaulo u8 *chap_challenge; 154214501Srpaulo size_t chap_challenge_len; 155214501Srpaulo u8 *chap_password; 156214501Srpaulo size_t chap_password_len; 157214501Srpaulo u8 *mschap_challenge; 158214501Srpaulo size_t mschap_challenge_len; 159214501Srpaulo u8 *mschap_response; 160214501Srpaulo size_t mschap_response_len; 161214501Srpaulo u8 *mschap2_response; 162214501Srpaulo size_t mschap2_response_len; 163214501Srpaulo}; 164214501Srpaulo 165214501Srpaulo 166214501Srpaulostatic int eap_ttls_avp_parse(struct wpabuf *buf, struct eap_ttls_avp *parse) 167214501Srpaulo{ 168214501Srpaulo struct ttls_avp *avp; 169214501Srpaulo u8 *pos; 170214501Srpaulo int left; 171214501Srpaulo 172214501Srpaulo pos = wpabuf_mhead(buf); 173214501Srpaulo left = wpabuf_len(buf); 174214501Srpaulo os_memset(parse, 0, sizeof(*parse)); 175214501Srpaulo 176214501Srpaulo while (left > 0) { 177214501Srpaulo u32 avp_code, avp_length, vendor_id = 0; 178214501Srpaulo u8 avp_flags, *dpos; 179214501Srpaulo size_t pad, dlen; 180214501Srpaulo avp = (struct ttls_avp *) pos; 181214501Srpaulo avp_code = be_to_host32(avp->avp_code); 182214501Srpaulo avp_length = be_to_host32(avp->avp_length); 183214501Srpaulo avp_flags = (avp_length >> 24) & 0xff; 184214501Srpaulo avp_length &= 0xffffff; 185214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " 186214501Srpaulo "length=%d", (int) avp_code, avp_flags, 187214501Srpaulo (int) avp_length); 188214501Srpaulo if ((int) avp_length > left) { 189214501Srpaulo wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " 190214501Srpaulo "(len=%d, left=%d) - dropped", 191214501Srpaulo (int) avp_length, left); 192214501Srpaulo goto fail; 193214501Srpaulo } 194214501Srpaulo if (avp_length < sizeof(*avp)) { 195214501Srpaulo wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length " 196214501Srpaulo "%d", avp_length); 197214501Srpaulo goto fail; 198214501Srpaulo } 199214501Srpaulo dpos = (u8 *) (avp + 1); 200214501Srpaulo dlen = avp_length - sizeof(*avp); 201214501Srpaulo if (avp_flags & AVP_FLAGS_VENDOR) { 202214501Srpaulo if (dlen < 4) { 203214501Srpaulo wpa_printf(MSG_WARNING, "EAP-TTLS: vendor AVP " 204214501Srpaulo "underflow"); 205214501Srpaulo goto fail; 206214501Srpaulo } 207214501Srpaulo vendor_id = be_to_host32(* (be32 *) dpos); 208214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", 209214501Srpaulo (int) vendor_id); 210214501Srpaulo dpos += 4; 211214501Srpaulo dlen -= 4; 212214501Srpaulo } 213214501Srpaulo 214214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); 215214501Srpaulo 216214501Srpaulo if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { 217214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); 218214501Srpaulo if (parse->eap == NULL) { 219214501Srpaulo parse->eap = os_malloc(dlen); 220214501Srpaulo if (parse->eap == NULL) { 221214501Srpaulo wpa_printf(MSG_WARNING, "EAP-TTLS: " 222214501Srpaulo "failed to allocate memory " 223214501Srpaulo "for Phase 2 EAP data"); 224214501Srpaulo goto fail; 225214501Srpaulo } 226214501Srpaulo os_memcpy(parse->eap, dpos, dlen); 227214501Srpaulo parse->eap_len = dlen; 228214501Srpaulo } else { 229214501Srpaulo u8 *neweap = os_realloc(parse->eap, 230214501Srpaulo parse->eap_len + dlen); 231214501Srpaulo if (neweap == NULL) { 232214501Srpaulo wpa_printf(MSG_WARNING, "EAP-TTLS: " 233214501Srpaulo "failed to allocate memory " 234214501Srpaulo "for Phase 2 EAP data"); 235214501Srpaulo goto fail; 236214501Srpaulo } 237214501Srpaulo os_memcpy(neweap + parse->eap_len, dpos, dlen); 238214501Srpaulo parse->eap = neweap; 239214501Srpaulo parse->eap_len += dlen; 240214501Srpaulo } 241214501Srpaulo } else if (vendor_id == 0 && 242214501Srpaulo avp_code == RADIUS_ATTR_USER_NAME) { 243214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: User-Name", 244214501Srpaulo dpos, dlen); 245214501Srpaulo parse->user_name = dpos; 246214501Srpaulo parse->user_name_len = dlen; 247214501Srpaulo } else if (vendor_id == 0 && 248214501Srpaulo avp_code == RADIUS_ATTR_USER_PASSWORD) { 249214501Srpaulo u8 *password = dpos; 250214501Srpaulo size_t password_len = dlen; 251214501Srpaulo while (password_len > 0 && 252214501Srpaulo password[password_len - 1] == '\0') { 253214501Srpaulo password_len--; 254214501Srpaulo } 255214501Srpaulo wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: " 256214501Srpaulo "User-Password (PAP)", 257214501Srpaulo password, password_len); 258214501Srpaulo parse->user_password = password; 259214501Srpaulo parse->user_password_len = password_len; 260214501Srpaulo } else if (vendor_id == 0 && 261214501Srpaulo avp_code == RADIUS_ATTR_CHAP_CHALLENGE) { 262214501Srpaulo wpa_hexdump(MSG_DEBUG, 263214501Srpaulo "EAP-TTLS: CHAP-Challenge (CHAP)", 264214501Srpaulo dpos, dlen); 265214501Srpaulo parse->chap_challenge = dpos; 266214501Srpaulo parse->chap_challenge_len = dlen; 267214501Srpaulo } else if (vendor_id == 0 && 268214501Srpaulo avp_code == RADIUS_ATTR_CHAP_PASSWORD) { 269214501Srpaulo wpa_hexdump(MSG_DEBUG, 270214501Srpaulo "EAP-TTLS: CHAP-Password (CHAP)", 271214501Srpaulo dpos, dlen); 272214501Srpaulo parse->chap_password = dpos; 273214501Srpaulo parse->chap_password_len = dlen; 274214501Srpaulo } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 275214501Srpaulo avp_code == RADIUS_ATTR_MS_CHAP_CHALLENGE) { 276214501Srpaulo wpa_hexdump(MSG_DEBUG, 277214501Srpaulo "EAP-TTLS: MS-CHAP-Challenge", 278214501Srpaulo dpos, dlen); 279214501Srpaulo parse->mschap_challenge = dpos; 280214501Srpaulo parse->mschap_challenge_len = dlen; 281214501Srpaulo } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 282214501Srpaulo avp_code == RADIUS_ATTR_MS_CHAP_RESPONSE) { 283214501Srpaulo wpa_hexdump(MSG_DEBUG, 284214501Srpaulo "EAP-TTLS: MS-CHAP-Response (MSCHAP)", 285214501Srpaulo dpos, dlen); 286214501Srpaulo parse->mschap_response = dpos; 287214501Srpaulo parse->mschap_response_len = dlen; 288214501Srpaulo } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && 289214501Srpaulo avp_code == RADIUS_ATTR_MS_CHAP2_RESPONSE) { 290214501Srpaulo wpa_hexdump(MSG_DEBUG, 291214501Srpaulo "EAP-TTLS: MS-CHAP2-Response (MSCHAPV2)", 292214501Srpaulo dpos, dlen); 293214501Srpaulo parse->mschap2_response = dpos; 294214501Srpaulo parse->mschap2_response_len = dlen; 295214501Srpaulo } else if (avp_flags & AVP_FLAGS_MANDATORY) { 296214501Srpaulo wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported " 297214501Srpaulo "mandatory AVP code %d vendor_id %d - " 298214501Srpaulo "dropped", (int) avp_code, (int) vendor_id); 299214501Srpaulo goto fail; 300214501Srpaulo } else { 301214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported " 302214501Srpaulo "AVP code %d vendor_id %d", 303214501Srpaulo (int) avp_code, (int) vendor_id); 304214501Srpaulo } 305214501Srpaulo 306214501Srpaulo pad = (4 - (avp_length & 3)) & 3; 307214501Srpaulo pos += avp_length + pad; 308214501Srpaulo left -= avp_length + pad; 309214501Srpaulo } 310214501Srpaulo 311214501Srpaulo return 0; 312214501Srpaulo 313214501Srpaulofail: 314214501Srpaulo os_free(parse->eap); 315214501Srpaulo parse->eap = NULL; 316214501Srpaulo return -1; 317214501Srpaulo} 318214501Srpaulo 319214501Srpaulo 320214501Srpaulostatic u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, 321214501Srpaulo struct eap_ttls_data *data, size_t len) 322214501Srpaulo{ 323214501Srpaulo struct tls_keys keys; 324214501Srpaulo u8 *challenge, *rnd; 325214501Srpaulo 326214501Srpaulo if (data->ttls_version == 0) { 327214501Srpaulo return eap_server_tls_derive_key(sm, &data->ssl, 328214501Srpaulo "ttls challenge", len); 329214501Srpaulo } 330214501Srpaulo 331214501Srpaulo os_memset(&keys, 0, sizeof(keys)); 332214501Srpaulo if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || 333214501Srpaulo keys.client_random == NULL || keys.server_random == NULL || 334214501Srpaulo keys.inner_secret == NULL) { 335214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " 336214501Srpaulo "client random, or server random to derive " 337214501Srpaulo "implicit challenge"); 338214501Srpaulo return NULL; 339214501Srpaulo } 340214501Srpaulo 341214501Srpaulo rnd = os_malloc(keys.client_random_len + keys.server_random_len); 342214501Srpaulo challenge = os_malloc(len); 343214501Srpaulo if (rnd == NULL || challenge == NULL) { 344214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " 345214501Srpaulo "challenge derivation"); 346214501Srpaulo os_free(rnd); 347214501Srpaulo os_free(challenge); 348214501Srpaulo return NULL; 349214501Srpaulo } 350214501Srpaulo os_memcpy(rnd, keys.server_random, keys.server_random_len); 351214501Srpaulo os_memcpy(rnd + keys.server_random_len, keys.client_random, 352214501Srpaulo keys.client_random_len); 353214501Srpaulo 354214501Srpaulo if (tls_prf(keys.inner_secret, keys.inner_secret_len, 355214501Srpaulo "inner application challenge", rnd, 356214501Srpaulo keys.client_random_len + keys.server_random_len, 357214501Srpaulo challenge, len)) { 358214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " 359214501Srpaulo "challenge"); 360214501Srpaulo os_free(rnd); 361214501Srpaulo os_free(challenge); 362214501Srpaulo return NULL; 363214501Srpaulo } 364214501Srpaulo 365214501Srpaulo os_free(rnd); 366214501Srpaulo 367214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", 368214501Srpaulo challenge, len); 369214501Srpaulo 370214501Srpaulo return challenge; 371214501Srpaulo} 372214501Srpaulo 373214501Srpaulo 374214501Srpaulostatic void * eap_ttls_init(struct eap_sm *sm) 375214501Srpaulo{ 376214501Srpaulo struct eap_ttls_data *data; 377214501Srpaulo 378214501Srpaulo data = os_zalloc(sizeof(*data)); 379214501Srpaulo if (data == NULL) 380214501Srpaulo return NULL; 381214501Srpaulo data->ttls_version = EAP_TTLS_VERSION; 382214501Srpaulo data->force_version = -1; 383214501Srpaulo if (sm->user && sm->user->force_version >= 0) { 384214501Srpaulo data->force_version = sm->user->force_version; 385214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d", 386214501Srpaulo data->force_version); 387214501Srpaulo data->ttls_version = data->force_version; 388214501Srpaulo } 389214501Srpaulo data->state = START; 390214501Srpaulo 391214501Srpaulo if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && 392214501Srpaulo data->ttls_version > 0) { 393214501Srpaulo if (data->force_version > 0) { 394214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " 395214501Srpaulo "TLS library does not support TLS/IA.", 396214501Srpaulo data->force_version); 397214501Srpaulo eap_ttls_reset(sm, data); 398214501Srpaulo return NULL; 399214501Srpaulo } 400214501Srpaulo data->ttls_version = 0; 401214501Srpaulo } 402214501Srpaulo 403214501Srpaulo if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { 404214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); 405214501Srpaulo eap_ttls_reset(sm, data); 406214501Srpaulo return NULL; 407214501Srpaulo } 408214501Srpaulo 409214501Srpaulo return data; 410214501Srpaulo} 411214501Srpaulo 412214501Srpaulo 413214501Srpaulostatic void eap_ttls_reset(struct eap_sm *sm, void *priv) 414214501Srpaulo{ 415214501Srpaulo struct eap_ttls_data *data = priv; 416214501Srpaulo if (data == NULL) 417214501Srpaulo return; 418214501Srpaulo if (data->phase2_priv && data->phase2_method) 419214501Srpaulo data->phase2_method->reset(sm, data->phase2_priv); 420214501Srpaulo eap_server_tls_ssl_deinit(sm, &data->ssl); 421214501Srpaulo wpabuf_free(data->pending_phase2_eap_resp); 422214501Srpaulo os_free(data); 423214501Srpaulo} 424214501Srpaulo 425214501Srpaulo 426214501Srpaulostatic struct wpabuf * eap_ttls_build_start(struct eap_sm *sm, 427214501Srpaulo struct eap_ttls_data *data, u8 id) 428214501Srpaulo{ 429214501Srpaulo struct wpabuf *req; 430214501Srpaulo 431214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1, 432214501Srpaulo EAP_CODE_REQUEST, id); 433214501Srpaulo if (req == NULL) { 434214501Srpaulo wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to allocate memory for" 435214501Srpaulo " request"); 436214501Srpaulo eap_ttls_state(data, FAILURE); 437214501Srpaulo return NULL; 438214501Srpaulo } 439214501Srpaulo 440214501Srpaulo wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->ttls_version); 441214501Srpaulo 442214501Srpaulo eap_ttls_state(data, PHASE1); 443214501Srpaulo 444214501Srpaulo return req; 445214501Srpaulo} 446214501Srpaulo 447214501Srpaulo 448214501Srpaulostatic struct wpabuf * eap_ttls_build_phase2_eap_req( 449214501Srpaulo struct eap_sm *sm, struct eap_ttls_data *data, u8 id) 450214501Srpaulo{ 451214501Srpaulo struct wpabuf *buf, *encr_req; 452214501Srpaulo 453214501Srpaulo 454214501Srpaulo buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); 455214501Srpaulo if (buf == NULL) 456214501Srpaulo return NULL; 457214501Srpaulo 458214501Srpaulo wpa_hexdump_buf_key(MSG_DEBUG, 459214501Srpaulo "EAP-TTLS/EAP: Encapsulate Phase 2 data", buf); 460214501Srpaulo 461214501Srpaulo buf = eap_ttls_avp_encapsulate(buf, RADIUS_ATTR_EAP_MESSAGE, 1); 462214501Srpaulo if (buf == NULL) { 463214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Failed to encapsulate " 464214501Srpaulo "packet"); 465214501Srpaulo return NULL; 466214501Srpaulo } 467214501Srpaulo 468214501Srpaulo wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated " 469214501Srpaulo "Phase 2 data", buf); 470214501Srpaulo 471214501Srpaulo encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); 472214501Srpaulo wpabuf_free(buf); 473214501Srpaulo 474214501Srpaulo return encr_req; 475214501Srpaulo} 476214501Srpaulo 477214501Srpaulo 478214501Srpaulostatic struct wpabuf * eap_ttls_build_phase2_mschapv2( 479214501Srpaulo struct eap_sm *sm, struct eap_ttls_data *data) 480214501Srpaulo{ 481214501Srpaulo struct wpabuf *encr_req, msgbuf; 482214501Srpaulo u8 *req, *pos, *end; 483214501Srpaulo int ret; 484214501Srpaulo 485214501Srpaulo pos = req = os_malloc(100); 486214501Srpaulo if (req == NULL) 487214501Srpaulo return NULL; 488214501Srpaulo end = req + 100; 489214501Srpaulo 490214501Srpaulo if (data->mschapv2_resp_ok) { 491214501Srpaulo pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_SUCCESS, 492214501Srpaulo RADIUS_VENDOR_ID_MICROSOFT, 1, 43); 493214501Srpaulo *pos++ = data->mschapv2_ident; 494214501Srpaulo ret = os_snprintf((char *) pos, end - pos, "S="); 495214501Srpaulo if (ret >= 0 && ret < end - pos) 496214501Srpaulo pos += ret; 497214501Srpaulo pos += wpa_snprintf_hex_uppercase( 498214501Srpaulo (char *) pos, end - pos, data->mschapv2_auth_response, 499214501Srpaulo sizeof(data->mschapv2_auth_response)); 500214501Srpaulo } else { 501214501Srpaulo pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR, 502214501Srpaulo RADIUS_VENDOR_ID_MICROSOFT, 1, 6); 503214501Srpaulo os_memcpy(pos, "Failed", 6); 504214501Srpaulo pos += 6; 505214501Srpaulo AVP_PAD(req, pos); 506214501Srpaulo } 507214501Srpaulo 508214501Srpaulo wpabuf_set(&msgbuf, req, pos - req); 509214501Srpaulo wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 " 510214501Srpaulo "data", &msgbuf); 511214501Srpaulo 512214501Srpaulo encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); 513214501Srpaulo os_free(req); 514214501Srpaulo 515214501Srpaulo return encr_req; 516214501Srpaulo} 517214501Srpaulo 518214501Srpaulo 519214501Srpaulostatic struct wpabuf * eap_ttls_build_phase_finished( 520214501Srpaulo struct eap_sm *sm, struct eap_ttls_data *data, int final) 521214501Srpaulo{ 522214501Srpaulo return tls_connection_ia_send_phase_finished(sm->ssl_ctx, 523214501Srpaulo data->ssl.conn, final); 524214501Srpaulo} 525214501Srpaulo 526214501Srpaulo 527214501Srpaulostatic struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id) 528214501Srpaulo{ 529214501Srpaulo struct eap_ttls_data *data = priv; 530214501Srpaulo 531214501Srpaulo if (data->ssl.state == FRAG_ACK) { 532214501Srpaulo return eap_server_tls_build_ack(id, EAP_TYPE_TTLS, 533214501Srpaulo data->ttls_version); 534214501Srpaulo } 535214501Srpaulo 536214501Srpaulo if (data->ssl.state == WAIT_FRAG_ACK) { 537214501Srpaulo return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS, 538214501Srpaulo data->ttls_version, id); 539214501Srpaulo } 540214501Srpaulo 541214501Srpaulo switch (data->state) { 542214501Srpaulo case START: 543214501Srpaulo return eap_ttls_build_start(sm, data, id); 544214501Srpaulo case PHASE1: 545214501Srpaulo if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 546214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, " 547214501Srpaulo "starting Phase2"); 548214501Srpaulo eap_ttls_state(data, PHASE2_START); 549214501Srpaulo } 550214501Srpaulo break; 551214501Srpaulo case PHASE2_METHOD: 552214501Srpaulo wpabuf_free(data->ssl.tls_out); 553214501Srpaulo data->ssl.tls_out_pos = 0; 554214501Srpaulo data->ssl.tls_out = eap_ttls_build_phase2_eap_req(sm, data, 555214501Srpaulo id); 556214501Srpaulo break; 557214501Srpaulo case PHASE2_MSCHAPV2_RESP: 558214501Srpaulo wpabuf_free(data->ssl.tls_out); 559214501Srpaulo data->ssl.tls_out_pos = 0; 560214501Srpaulo data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data); 561214501Srpaulo break; 562214501Srpaulo case PHASE_FINISHED: 563214501Srpaulo wpabuf_free(data->ssl.tls_out); 564214501Srpaulo data->ssl.tls_out_pos = 0; 565214501Srpaulo data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1); 566214501Srpaulo break; 567214501Srpaulo default: 568214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", 569214501Srpaulo __func__, data->state); 570214501Srpaulo return NULL; 571214501Srpaulo } 572214501Srpaulo 573214501Srpaulo return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS, 574214501Srpaulo data->ttls_version, id); 575214501Srpaulo} 576214501Srpaulo 577214501Srpaulo 578214501Srpaulostatic Boolean eap_ttls_check(struct eap_sm *sm, void *priv, 579214501Srpaulo struct wpabuf *respData) 580214501Srpaulo{ 581214501Srpaulo const u8 *pos; 582214501Srpaulo size_t len; 583214501Srpaulo 584214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData, &len); 585214501Srpaulo if (pos == NULL || len < 1) { 586214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame"); 587214501Srpaulo return TRUE; 588214501Srpaulo } 589214501Srpaulo 590214501Srpaulo return FALSE; 591214501Srpaulo} 592214501Srpaulo 593214501Srpaulo 594214501Srpaulostatic int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, 595214501Srpaulo struct eap_ttls_data *data, 596214501Srpaulo const u8 *key, size_t key_len) 597214501Srpaulo{ 598214501Srpaulo u8 *buf; 599214501Srpaulo size_t buf_len; 600214501Srpaulo int ret; 601214501Srpaulo 602214501Srpaulo if (key) { 603214501Srpaulo buf_len = 2 + key_len; 604214501Srpaulo buf = os_malloc(buf_len); 605214501Srpaulo if (buf == NULL) 606214501Srpaulo return -1; 607214501Srpaulo WPA_PUT_BE16(buf, key_len); 608214501Srpaulo os_memcpy(buf + 2, key, key_len); 609214501Srpaulo } else { 610214501Srpaulo buf = NULL; 611214501Srpaulo buf_len = 0; 612214501Srpaulo } 613214501Srpaulo 614214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner " 615214501Srpaulo "secret permutation", buf, buf_len); 616214501Srpaulo ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx, 617214501Srpaulo data->ssl.conn, 618214501Srpaulo buf, buf_len); 619214501Srpaulo os_free(buf); 620214501Srpaulo 621214501Srpaulo return ret; 622214501Srpaulo} 623214501Srpaulo 624214501Srpaulo 625214501Srpaulostatic void eap_ttls_process_phase2_pap(struct eap_sm *sm, 626214501Srpaulo struct eap_ttls_data *data, 627214501Srpaulo const u8 *user_password, 628214501Srpaulo size_t user_password_len) 629214501Srpaulo{ 630214501Srpaulo if (!sm->user || !sm->user->password || sm->user->password_hash || 631214501Srpaulo !(sm->user->ttls_auth & EAP_TTLS_AUTH_PAP)) { 632214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No plaintext user " 633214501Srpaulo "password configured"); 634214501Srpaulo eap_ttls_state(data, FAILURE); 635214501Srpaulo return; 636214501Srpaulo } 637214501Srpaulo 638214501Srpaulo if (sm->user->password_len != user_password_len || 639214501Srpaulo os_memcmp(sm->user->password, user_password, user_password_len) != 640214501Srpaulo 0) { 641214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password"); 642214501Srpaulo eap_ttls_state(data, FAILURE); 643214501Srpaulo return; 644214501Srpaulo } 645214501Srpaulo 646214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password"); 647214501Srpaulo eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : 648214501Srpaulo SUCCESS); 649214501Srpaulo} 650214501Srpaulo 651214501Srpaulo 652214501Srpaulostatic void eap_ttls_process_phase2_chap(struct eap_sm *sm, 653214501Srpaulo struct eap_ttls_data *data, 654214501Srpaulo const u8 *challenge, 655214501Srpaulo size_t challenge_len, 656214501Srpaulo const u8 *password, 657214501Srpaulo size_t password_len) 658214501Srpaulo{ 659214501Srpaulo u8 *chal, hash[CHAP_MD5_LEN]; 660214501Srpaulo 661214501Srpaulo if (challenge == NULL || password == NULL || 662214501Srpaulo challenge_len != EAP_TTLS_CHAP_CHALLENGE_LEN || 663214501Srpaulo password_len != 1 + EAP_TTLS_CHAP_PASSWORD_LEN) { 664214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid CHAP attributes " 665214501Srpaulo "(challenge len %lu password len %lu)", 666214501Srpaulo (unsigned long) challenge_len, 667214501Srpaulo (unsigned long) password_len); 668214501Srpaulo eap_ttls_state(data, FAILURE); 669214501Srpaulo return; 670214501Srpaulo } 671214501Srpaulo 672214501Srpaulo if (!sm->user || !sm->user->password || sm->user->password_hash || 673214501Srpaulo !(sm->user->ttls_auth & EAP_TTLS_AUTH_CHAP)) { 674214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No plaintext user " 675214501Srpaulo "password configured"); 676214501Srpaulo eap_ttls_state(data, FAILURE); 677214501Srpaulo return; 678214501Srpaulo } 679214501Srpaulo 680214501Srpaulo chal = eap_ttls_implicit_challenge(sm, data, 681214501Srpaulo EAP_TTLS_CHAP_CHALLENGE_LEN + 1); 682214501Srpaulo if (chal == NULL) { 683214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Failed to generate " 684214501Srpaulo "challenge from TLS data"); 685214501Srpaulo eap_ttls_state(data, FAILURE); 686214501Srpaulo return; 687214501Srpaulo } 688214501Srpaulo 689214501Srpaulo if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 || 690214501Srpaulo password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) { 691214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch"); 692214501Srpaulo os_free(chal); 693214501Srpaulo eap_ttls_state(data, FAILURE); 694214501Srpaulo return; 695214501Srpaulo } 696214501Srpaulo os_free(chal); 697214501Srpaulo 698214501Srpaulo /* MD5(Ident + Password + Challenge) */ 699214501Srpaulo chap_md5(password[0], sm->user->password, sm->user->password_len, 700214501Srpaulo challenge, challenge_len, hash); 701214501Srpaulo 702214501Srpaulo if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) { 703214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password"); 704214501Srpaulo eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : 705214501Srpaulo SUCCESS); 706214501Srpaulo } else { 707214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password"); 708214501Srpaulo eap_ttls_state(data, FAILURE); 709214501Srpaulo } 710214501Srpaulo} 711214501Srpaulo 712214501Srpaulo 713214501Srpaulostatic void eap_ttls_process_phase2_mschap(struct eap_sm *sm, 714214501Srpaulo struct eap_ttls_data *data, 715214501Srpaulo u8 *challenge, size_t challenge_len, 716214501Srpaulo u8 *response, size_t response_len) 717214501Srpaulo{ 718214501Srpaulo u8 *chal, nt_response[24]; 719214501Srpaulo 720214501Srpaulo if (challenge == NULL || response == NULL || 721214501Srpaulo challenge_len != EAP_TTLS_MSCHAP_CHALLENGE_LEN || 722214501Srpaulo response_len != EAP_TTLS_MSCHAP_RESPONSE_LEN) { 723214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid MS-CHAP " 724214501Srpaulo "attributes (challenge len %lu response len %lu)", 725214501Srpaulo (unsigned long) challenge_len, 726214501Srpaulo (unsigned long) response_len); 727214501Srpaulo eap_ttls_state(data, FAILURE); 728214501Srpaulo return; 729214501Srpaulo } 730214501Srpaulo 731214501Srpaulo if (!sm->user || !sm->user->password || 732214501Srpaulo !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAP)) { 733214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: No user password " 734214501Srpaulo "configured"); 735214501Srpaulo eap_ttls_state(data, FAILURE); 736214501Srpaulo return; 737214501Srpaulo } 738214501Srpaulo 739214501Srpaulo chal = eap_ttls_implicit_challenge(sm, data, 740214501Srpaulo EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); 741214501Srpaulo if (chal == NULL) { 742214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Failed to generate " 743214501Srpaulo "challenge from TLS data"); 744214501Srpaulo eap_ttls_state(data, FAILURE); 745214501Srpaulo return; 746214501Srpaulo } 747214501Srpaulo 748214501Srpaulo if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 || 749214501Srpaulo response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) { 750214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch"); 751214501Srpaulo os_free(chal); 752214501Srpaulo eap_ttls_state(data, FAILURE); 753214501Srpaulo return; 754214501Srpaulo } 755214501Srpaulo os_free(chal); 756214501Srpaulo 757214501Srpaulo if (sm->user->password_hash) 758214501Srpaulo challenge_response(challenge, sm->user->password, nt_response); 759214501Srpaulo else 760214501Srpaulo nt_challenge_response(challenge, sm->user->password, 761214501Srpaulo sm->user->password_len, nt_response); 762214501Srpaulo 763214501Srpaulo if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) { 764214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response"); 765214501Srpaulo eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : 766214501Srpaulo SUCCESS); 767214501Srpaulo } else { 768214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response"); 769214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received", 770214501Srpaulo response + 2 + 24, 24); 771214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Expected", 772214501Srpaulo nt_response, 24); 773214501Srpaulo eap_ttls_state(data, FAILURE); 774214501Srpaulo } 775214501Srpaulo} 776214501Srpaulo 777214501Srpaulo 778214501Srpaulostatic void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, 779214501Srpaulo struct eap_ttls_data *data, 780214501Srpaulo u8 *challenge, 781214501Srpaulo size_t challenge_len, 782214501Srpaulo u8 *response, size_t response_len) 783214501Srpaulo{ 784214501Srpaulo u8 *chal, *username, nt_response[24], *rx_resp, *peer_challenge, 785214501Srpaulo *auth_challenge; 786214501Srpaulo size_t username_len, i; 787214501Srpaulo 788214501Srpaulo if (challenge == NULL || response == NULL || 789214501Srpaulo challenge_len != EAP_TTLS_MSCHAPV2_CHALLENGE_LEN || 790214501Srpaulo response_len != EAP_TTLS_MSCHAPV2_RESPONSE_LEN) { 791214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid MS-CHAP2 " 792214501Srpaulo "attributes (challenge len %lu response len %lu)", 793214501Srpaulo (unsigned long) challenge_len, 794214501Srpaulo (unsigned long) response_len); 795214501Srpaulo eap_ttls_state(data, FAILURE); 796214501Srpaulo return; 797214501Srpaulo } 798214501Srpaulo 799214501Srpaulo if (!sm->user || !sm->user->password || 800214501Srpaulo !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAPV2)) { 801214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user password " 802214501Srpaulo "configured"); 803214501Srpaulo eap_ttls_state(data, FAILURE); 804214501Srpaulo return; 805214501Srpaulo } 806214501Srpaulo 807214501Srpaulo /* MSCHAPv2 does not include optional domain name in the 808214501Srpaulo * challenge-response calculation, so remove domain prefix 809214501Srpaulo * (if present). */ 810214501Srpaulo username = sm->identity; 811214501Srpaulo username_len = sm->identity_len; 812214501Srpaulo for (i = 0; i < username_len; i++) { 813214501Srpaulo if (username[i] == '\\') { 814214501Srpaulo username_len -= i + 1; 815214501Srpaulo username += i + 1; 816214501Srpaulo break; 817214501Srpaulo } 818214501Srpaulo } 819214501Srpaulo 820214501Srpaulo chal = eap_ttls_implicit_challenge( 821214501Srpaulo sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); 822214501Srpaulo if (chal == NULL) { 823214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Failed to generate " 824214501Srpaulo "challenge from TLS data"); 825214501Srpaulo eap_ttls_state(data, FAILURE); 826214501Srpaulo return; 827214501Srpaulo } 828214501Srpaulo 829214501Srpaulo if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 || 830214501Srpaulo response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) { 831214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch"); 832214501Srpaulo os_free(chal); 833214501Srpaulo eap_ttls_state(data, FAILURE); 834214501Srpaulo return; 835214501Srpaulo } 836214501Srpaulo os_free(chal); 837214501Srpaulo 838214501Srpaulo auth_challenge = challenge; 839214501Srpaulo peer_challenge = response + 2; 840214501Srpaulo 841214501Srpaulo wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: User", 842214501Srpaulo username, username_len); 843214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: auth_challenge", 844214501Srpaulo auth_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); 845214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: peer_challenge", 846214501Srpaulo peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); 847214501Srpaulo 848214501Srpaulo if (sm->user->password_hash) { 849214501Srpaulo generate_nt_response_pwhash(auth_challenge, peer_challenge, 850214501Srpaulo username, username_len, 851214501Srpaulo sm->user->password, 852214501Srpaulo nt_response); 853214501Srpaulo } else { 854214501Srpaulo generate_nt_response(auth_challenge, peer_challenge, 855214501Srpaulo username, username_len, 856214501Srpaulo sm->user->password, 857214501Srpaulo sm->user->password_len, 858214501Srpaulo nt_response); 859214501Srpaulo } 860214501Srpaulo 861214501Srpaulo rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8; 862214501Srpaulo if (os_memcmp(nt_response, rx_resp, 24) == 0) { 863214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct " 864214501Srpaulo "NT-Response"); 865214501Srpaulo data->mschapv2_resp_ok = 1; 866214501Srpaulo if (data->ttls_version > 0) { 867214501Srpaulo const u8 *pw_hash; 868214501Srpaulo u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16]; 869214501Srpaulo u8 session_key[2 * MSCHAPV2_KEY_LEN]; 870214501Srpaulo 871214501Srpaulo if (sm->user->password_hash) 872214501Srpaulo pw_hash = sm->user->password; 873214501Srpaulo else { 874214501Srpaulo nt_password_hash(sm->user->password, 875214501Srpaulo sm->user->password_len, 876214501Srpaulo pw_hash_buf); 877214501Srpaulo pw_hash = pw_hash_buf; 878214501Srpaulo } 879214501Srpaulo hash_nt_password_hash(pw_hash, pw_hash_hash); 880214501Srpaulo get_master_key(pw_hash_hash, nt_response, master_key); 881214501Srpaulo get_asymetric_start_key(master_key, session_key, 882214501Srpaulo MSCHAPV2_KEY_LEN, 0, 0); 883214501Srpaulo get_asymetric_start_key(master_key, 884214501Srpaulo session_key + MSCHAPV2_KEY_LEN, 885214501Srpaulo MSCHAPV2_KEY_LEN, 1, 0); 886214501Srpaulo eap_ttls_ia_permute_inner_secret(sm, data, 887214501Srpaulo session_key, 888214501Srpaulo sizeof(session_key)); 889214501Srpaulo } 890214501Srpaulo 891214501Srpaulo if (sm->user->password_hash) { 892214501Srpaulo generate_authenticator_response_pwhash( 893214501Srpaulo sm->user->password, 894214501Srpaulo peer_challenge, auth_challenge, 895214501Srpaulo username, username_len, nt_response, 896214501Srpaulo data->mschapv2_auth_response); 897214501Srpaulo } else { 898214501Srpaulo generate_authenticator_response( 899214501Srpaulo sm->user->password, sm->user->password_len, 900214501Srpaulo peer_challenge, auth_challenge, 901214501Srpaulo username, username_len, nt_response, 902214501Srpaulo data->mschapv2_auth_response); 903214501Srpaulo } 904214501Srpaulo } else { 905214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid " 906214501Srpaulo "NT-Response"); 907214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Received", 908214501Srpaulo rx_resp, 24); 909214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Expected", 910214501Srpaulo nt_response, 24); 911214501Srpaulo data->mschapv2_resp_ok = 0; 912214501Srpaulo } 913214501Srpaulo eap_ttls_state(data, PHASE2_MSCHAPV2_RESP); 914214501Srpaulo data->mschapv2_ident = response[0]; 915214501Srpaulo} 916214501Srpaulo 917214501Srpaulo 918214501Srpaulostatic int eap_ttls_phase2_eap_init(struct eap_sm *sm, 919214501Srpaulo struct eap_ttls_data *data, 920214501Srpaulo EapType eap_type) 921214501Srpaulo{ 922214501Srpaulo if (data->phase2_priv && data->phase2_method) { 923214501Srpaulo data->phase2_method->reset(sm, data->phase2_priv); 924214501Srpaulo data->phase2_method = NULL; 925214501Srpaulo data->phase2_priv = NULL; 926214501Srpaulo } 927214501Srpaulo data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, 928214501Srpaulo eap_type); 929214501Srpaulo if (!data->phase2_method) 930214501Srpaulo return -1; 931214501Srpaulo 932214501Srpaulo sm->init_phase2 = 1; 933214501Srpaulo data->phase2_priv = data->phase2_method->init(sm); 934214501Srpaulo sm->init_phase2 = 0; 935214501Srpaulo return data->phase2_priv == NULL ? -1 : 0; 936214501Srpaulo} 937214501Srpaulo 938214501Srpaulo 939214501Srpaulostatic void eap_ttls_process_phase2_eap_response(struct eap_sm *sm, 940214501Srpaulo struct eap_ttls_data *data, 941214501Srpaulo u8 *in_data, size_t in_len) 942214501Srpaulo{ 943214501Srpaulo u8 next_type = EAP_TYPE_NONE; 944214501Srpaulo struct eap_hdr *hdr; 945214501Srpaulo u8 *pos; 946214501Srpaulo size_t left; 947214501Srpaulo struct wpabuf buf; 948214501Srpaulo const struct eap_method *m = data->phase2_method; 949214501Srpaulo void *priv = data->phase2_priv; 950214501Srpaulo 951214501Srpaulo if (priv == NULL) { 952214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: %s - Phase2 not " 953214501Srpaulo "initialized?!", __func__); 954214501Srpaulo return; 955214501Srpaulo } 956214501Srpaulo 957214501Srpaulo hdr = (struct eap_hdr *) in_data; 958214501Srpaulo pos = (u8 *) (hdr + 1); 959214501Srpaulo 960214501Srpaulo if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { 961214501Srpaulo left = in_len - sizeof(*hdr); 962214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 type Nak'ed; " 963214501Srpaulo "allowed types", pos + 1, left - 1); 964214501Srpaulo eap_sm_process_nak(sm, pos + 1, left - 1); 965214501Srpaulo if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 966214501Srpaulo sm->user->methods[sm->user_eap_method_index].method != 967214501Srpaulo EAP_TYPE_NONE) { 968214501Srpaulo next_type = sm->user->methods[ 969214501Srpaulo sm->user_eap_method_index++].method; 970214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", 971214501Srpaulo next_type); 972214501Srpaulo if (eap_ttls_phase2_eap_init(sm, data, next_type)) { 973214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to " 974214501Srpaulo "initialize EAP type %d", 975214501Srpaulo next_type); 976214501Srpaulo eap_ttls_state(data, FAILURE); 977214501Srpaulo return; 978214501Srpaulo } 979214501Srpaulo } else { 980214501Srpaulo eap_ttls_state(data, FAILURE); 981214501Srpaulo } 982214501Srpaulo return; 983214501Srpaulo } 984214501Srpaulo 985214501Srpaulo wpabuf_set(&buf, in_data, in_len); 986214501Srpaulo 987214501Srpaulo if (m->check(sm, priv, &buf)) { 988214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 check() asked to " 989214501Srpaulo "ignore the packet"); 990214501Srpaulo return; 991214501Srpaulo } 992214501Srpaulo 993214501Srpaulo m->process(sm, priv, &buf); 994214501Srpaulo 995214501Srpaulo if (sm->method_pending == METHOD_PENDING_WAIT) { 996214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method is in " 997214501Srpaulo "pending wait state - save decrypted response"); 998214501Srpaulo wpabuf_free(data->pending_phase2_eap_resp); 999214501Srpaulo data->pending_phase2_eap_resp = wpabuf_dup(&buf); 1000214501Srpaulo } 1001214501Srpaulo 1002214501Srpaulo if (!m->isDone(sm, priv)) 1003214501Srpaulo return; 1004214501Srpaulo 1005214501Srpaulo if (!m->isSuccess(sm, priv)) { 1006214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method failed"); 1007214501Srpaulo eap_ttls_state(data, FAILURE); 1008214501Srpaulo return; 1009214501Srpaulo } 1010214501Srpaulo 1011214501Srpaulo switch (data->state) { 1012214501Srpaulo case PHASE2_START: 1013214501Srpaulo if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 1014214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP_TTLS: Phase2 " 1015214501Srpaulo "Identity not found in the user " 1016214501Srpaulo "database", 1017214501Srpaulo sm->identity, sm->identity_len); 1018214501Srpaulo eap_ttls_state(data, FAILURE); 1019214501Srpaulo break; 1020214501Srpaulo } 1021214501Srpaulo 1022214501Srpaulo eap_ttls_state(data, PHASE2_METHOD); 1023214501Srpaulo next_type = sm->user->methods[0].method; 1024214501Srpaulo sm->user_eap_method_index = 1; 1025214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type); 1026214501Srpaulo if (eap_ttls_phase2_eap_init(sm, data, next_type)) { 1027214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize " 1028214501Srpaulo "EAP type %d", next_type); 1029214501Srpaulo eap_ttls_state(data, FAILURE); 1030214501Srpaulo } 1031214501Srpaulo break; 1032214501Srpaulo case PHASE2_METHOD: 1033214501Srpaulo if (data->ttls_version > 0) { 1034214501Srpaulo if (m->getKey) { 1035214501Srpaulo u8 *key; 1036214501Srpaulo size_t key_len; 1037214501Srpaulo key = m->getKey(sm, priv, &key_len); 1038214501Srpaulo eap_ttls_ia_permute_inner_secret(sm, data, 1039214501Srpaulo key, key_len); 1040214501Srpaulo } 1041214501Srpaulo eap_ttls_state(data, PHASE_FINISHED); 1042214501Srpaulo } else 1043214501Srpaulo eap_ttls_state(data, SUCCESS); 1044214501Srpaulo break; 1045214501Srpaulo case FAILURE: 1046214501Srpaulo break; 1047214501Srpaulo default: 1048214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", 1049214501Srpaulo __func__, data->state); 1050214501Srpaulo break; 1051214501Srpaulo } 1052214501Srpaulo} 1053214501Srpaulo 1054214501Srpaulo 1055214501Srpaulostatic void eap_ttls_process_phase2_eap(struct eap_sm *sm, 1056214501Srpaulo struct eap_ttls_data *data, 1057214501Srpaulo const u8 *eap, size_t eap_len) 1058214501Srpaulo{ 1059214501Srpaulo struct eap_hdr *hdr; 1060214501Srpaulo size_t len; 1061214501Srpaulo 1062214501Srpaulo if (data->state == PHASE2_START) { 1063214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2"); 1064214501Srpaulo if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0) 1065214501Srpaulo { 1066214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to " 1067214501Srpaulo "initialize EAP-Identity"); 1068214501Srpaulo return; 1069214501Srpaulo } 1070214501Srpaulo } 1071214501Srpaulo 1072214501Srpaulo if (eap_len < sizeof(*hdr)) { 1073214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: too short Phase 2 EAP " 1074214501Srpaulo "packet (len=%lu)", (unsigned long) eap_len); 1075214501Srpaulo return; 1076214501Srpaulo } 1077214501Srpaulo 1078214501Srpaulo hdr = (struct eap_hdr *) eap; 1079214501Srpaulo len = be_to_host16(hdr->length); 1080214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: received Phase 2 EAP: code=%d " 1081214501Srpaulo "identifier=%d length=%lu", hdr->code, hdr->identifier, 1082214501Srpaulo (unsigned long) len); 1083214501Srpaulo if (len > eap_len) { 1084214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Length mismatch in Phase 2" 1085214501Srpaulo " EAP frame (hdr len=%lu, data len in AVP=%lu)", 1086214501Srpaulo (unsigned long) len, (unsigned long) eap_len); 1087214501Srpaulo return; 1088214501Srpaulo } 1089214501Srpaulo 1090214501Srpaulo switch (hdr->code) { 1091214501Srpaulo case EAP_CODE_RESPONSE: 1092214501Srpaulo eap_ttls_process_phase2_eap_response(sm, data, (u8 *) hdr, 1093214501Srpaulo len); 1094214501Srpaulo break; 1095214501Srpaulo default: 1096214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Unexpected code=%d in " 1097214501Srpaulo "Phase 2 EAP header", hdr->code); 1098214501Srpaulo break; 1099214501Srpaulo } 1100214501Srpaulo} 1101214501Srpaulo 1102214501Srpaulo 1103214501Srpaulostatic void eap_ttls_process_phase2(struct eap_sm *sm, 1104214501Srpaulo struct eap_ttls_data *data, 1105214501Srpaulo struct wpabuf *in_buf) 1106214501Srpaulo{ 1107214501Srpaulo struct wpabuf *in_decrypted; 1108214501Srpaulo struct eap_ttls_avp parse; 1109214501Srpaulo 1110214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" 1111214501Srpaulo " Phase 2", (unsigned long) wpabuf_len(in_buf)); 1112214501Srpaulo 1113214501Srpaulo if (data->pending_phase2_eap_resp) { 1114214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 EAP response " 1115214501Srpaulo "- skip decryption and use old data"); 1116214501Srpaulo eap_ttls_process_phase2_eap( 1117214501Srpaulo sm, data, wpabuf_head(data->pending_phase2_eap_resp), 1118214501Srpaulo wpabuf_len(data->pending_phase2_eap_resp)); 1119214501Srpaulo wpabuf_free(data->pending_phase2_eap_resp); 1120214501Srpaulo data->pending_phase2_eap_resp = NULL; 1121214501Srpaulo return; 1122214501Srpaulo } 1123214501Srpaulo 1124214501Srpaulo in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, 1125214501Srpaulo in_buf); 1126214501Srpaulo if (in_decrypted == NULL) { 1127214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 " 1128214501Srpaulo "data"); 1129214501Srpaulo eap_ttls_state(data, FAILURE); 1130214501Srpaulo return; 1131214501Srpaulo } 1132214501Srpaulo 1133214501Srpaulo if (data->state == PHASE_FINISHED) { 1134214501Srpaulo if (wpabuf_len(in_decrypted) == 0 && 1135214501Srpaulo tls_connection_ia_final_phase_finished(sm->ssl_ctx, 1136214501Srpaulo data->ssl.conn)) { 1137214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished " 1138214501Srpaulo "received"); 1139214501Srpaulo eap_ttls_state(data, SUCCESS); 1140214501Srpaulo } else { 1141214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid " 1142214501Srpaulo "FinalPhaseFinished"); 1143214501Srpaulo eap_ttls_state(data, FAILURE); 1144214501Srpaulo } 1145214501Srpaulo 1146214501Srpaulo wpabuf_free(in_decrypted); 1147214501Srpaulo return; 1148214501Srpaulo } 1149214501Srpaulo 1150214501Srpaulo wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", 1151214501Srpaulo in_decrypted); 1152214501Srpaulo 1153214501Srpaulo if (eap_ttls_avp_parse(in_decrypted, &parse) < 0) { 1154214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs"); 1155214501Srpaulo wpabuf_free(in_decrypted); 1156214501Srpaulo eap_ttls_state(data, FAILURE); 1157214501Srpaulo return; 1158214501Srpaulo } 1159214501Srpaulo 1160214501Srpaulo if (parse.user_name) { 1161214501Srpaulo os_free(sm->identity); 1162214501Srpaulo sm->identity = os_malloc(parse.user_name_len); 1163214501Srpaulo if (sm->identity) { 1164214501Srpaulo os_memcpy(sm->identity, parse.user_name, 1165214501Srpaulo parse.user_name_len); 1166214501Srpaulo sm->identity_len = parse.user_name_len; 1167214501Srpaulo } 1168214501Srpaulo if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1) 1169214501Srpaulo != 0) { 1170214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not " 1171214501Srpaulo "found in the user database"); 1172214501Srpaulo eap_ttls_state(data, FAILURE); 1173214501Srpaulo goto done; 1174214501Srpaulo } 1175214501Srpaulo } 1176214501Srpaulo 1177214501Srpaulo#ifdef EAP_SERVER_TNC 1178214501Srpaulo if (data->tnc_started && parse.eap == NULL) { 1179214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP " 1180214501Srpaulo "response from peer"); 1181214501Srpaulo eap_ttls_state(data, FAILURE); 1182214501Srpaulo goto done; 1183214501Srpaulo } 1184214501Srpaulo#endif /* EAP_SERVER_TNC */ 1185214501Srpaulo 1186214501Srpaulo if (parse.eap) { 1187214501Srpaulo eap_ttls_process_phase2_eap(sm, data, parse.eap, 1188214501Srpaulo parse.eap_len); 1189214501Srpaulo } else if (parse.user_password) { 1190214501Srpaulo eap_ttls_process_phase2_pap(sm, data, parse.user_password, 1191214501Srpaulo parse.user_password_len); 1192214501Srpaulo } else if (parse.chap_password) { 1193214501Srpaulo eap_ttls_process_phase2_chap(sm, data, 1194214501Srpaulo parse.chap_challenge, 1195214501Srpaulo parse.chap_challenge_len, 1196214501Srpaulo parse.chap_password, 1197214501Srpaulo parse.chap_password_len); 1198214501Srpaulo } else if (parse.mschap_response) { 1199214501Srpaulo eap_ttls_process_phase2_mschap(sm, data, 1200214501Srpaulo parse.mschap_challenge, 1201214501Srpaulo parse.mschap_challenge_len, 1202214501Srpaulo parse.mschap_response, 1203214501Srpaulo parse.mschap_response_len); 1204214501Srpaulo } else if (parse.mschap2_response) { 1205214501Srpaulo eap_ttls_process_phase2_mschapv2(sm, data, 1206214501Srpaulo parse.mschap_challenge, 1207214501Srpaulo parse.mschap_challenge_len, 1208214501Srpaulo parse.mschap2_response, 1209214501Srpaulo parse.mschap2_response_len); 1210214501Srpaulo } 1211214501Srpaulo 1212214501Srpaulodone: 1213214501Srpaulo wpabuf_free(in_decrypted); 1214214501Srpaulo os_free(parse.eap); 1215214501Srpaulo} 1216214501Srpaulo 1217214501Srpaulo 1218214501Srpaulostatic void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data) 1219214501Srpaulo{ 1220214501Srpaulo#ifdef EAP_SERVER_TNC 1221214501Srpaulo if (!sm->tnc || data->state != SUCCESS || data->tnc_started) 1222214501Srpaulo return; 1223214501Srpaulo 1224214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC"); 1225214501Srpaulo if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) { 1226214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC"); 1227214501Srpaulo eap_ttls_state(data, FAILURE); 1228214501Srpaulo return; 1229214501Srpaulo } 1230214501Srpaulo 1231214501Srpaulo data->tnc_started = 1; 1232214501Srpaulo eap_ttls_state(data, PHASE2_METHOD); 1233214501Srpaulo#endif /* EAP_SERVER_TNC */ 1234214501Srpaulo} 1235214501Srpaulo 1236214501Srpaulo 1237214501Srpaulostatic int eap_ttls_process_version(struct eap_sm *sm, void *priv, 1238214501Srpaulo int peer_version) 1239214501Srpaulo{ 1240214501Srpaulo struct eap_ttls_data *data = priv; 1241214501Srpaulo if (peer_version < data->ttls_version) { 1242214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; " 1243214501Srpaulo "use version %d", 1244214501Srpaulo peer_version, data->ttls_version, peer_version); 1245214501Srpaulo data->ttls_version = peer_version; 1246214501Srpaulo } 1247214501Srpaulo 1248214501Srpaulo if (data->ttls_version > 0 && !data->tls_ia_configured) { 1249214501Srpaulo if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) { 1250214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable " 1251214501Srpaulo "TLS/IA"); 1252214501Srpaulo return -1; 1253214501Srpaulo } 1254214501Srpaulo data->tls_ia_configured = 1; 1255214501Srpaulo } 1256214501Srpaulo 1257214501Srpaulo return 0; 1258214501Srpaulo} 1259214501Srpaulo 1260214501Srpaulo 1261214501Srpaulostatic void eap_ttls_process_msg(struct eap_sm *sm, void *priv, 1262214501Srpaulo const struct wpabuf *respData) 1263214501Srpaulo{ 1264214501Srpaulo struct eap_ttls_data *data = priv; 1265214501Srpaulo 1266214501Srpaulo switch (data->state) { 1267214501Srpaulo case PHASE1: 1268214501Srpaulo if (eap_server_tls_phase1(sm, &data->ssl) < 0) 1269214501Srpaulo eap_ttls_state(data, FAILURE); 1270214501Srpaulo break; 1271214501Srpaulo case PHASE2_START: 1272214501Srpaulo case PHASE2_METHOD: 1273214501Srpaulo case PHASE_FINISHED: 1274214501Srpaulo eap_ttls_process_phase2(sm, data, data->ssl.tls_in); 1275214501Srpaulo eap_ttls_start_tnc(sm, data); 1276214501Srpaulo break; 1277214501Srpaulo case PHASE2_MSCHAPV2_RESP: 1278214501Srpaulo if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.tls_in) == 1279214501Srpaulo 0) { 1280214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " 1281214501Srpaulo "acknowledged response"); 1282214501Srpaulo eap_ttls_state(data, data->ttls_version > 0 ? 1283214501Srpaulo PHASE_FINISHED : SUCCESS); 1284214501Srpaulo } else if (!data->mschapv2_resp_ok) { 1285214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " 1286214501Srpaulo "acknowledged error"); 1287214501Srpaulo eap_ttls_state(data, FAILURE); 1288214501Srpaulo } else { 1289214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected " 1290214501Srpaulo "frame from peer (payload len %lu, " 1291214501Srpaulo "expected empty frame)", 1292214501Srpaulo (unsigned long) 1293214501Srpaulo wpabuf_len(data->ssl.tls_in)); 1294214501Srpaulo eap_ttls_state(data, FAILURE); 1295214501Srpaulo } 1296214501Srpaulo eap_ttls_start_tnc(sm, data); 1297214501Srpaulo break; 1298214501Srpaulo default: 1299214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected state %d in %s", 1300214501Srpaulo data->state, __func__); 1301214501Srpaulo break; 1302214501Srpaulo } 1303214501Srpaulo} 1304214501Srpaulo 1305214501Srpaulo 1306214501Srpaulostatic void eap_ttls_process(struct eap_sm *sm, void *priv, 1307214501Srpaulo struct wpabuf *respData) 1308214501Srpaulo{ 1309214501Srpaulo struct eap_ttls_data *data = priv; 1310214501Srpaulo if (eap_server_tls_process(sm, &data->ssl, respData, data, 1311214501Srpaulo EAP_TYPE_TTLS, eap_ttls_process_version, 1312214501Srpaulo eap_ttls_process_msg) < 0) 1313214501Srpaulo eap_ttls_state(data, FAILURE); 1314214501Srpaulo} 1315214501Srpaulo 1316214501Srpaulo 1317214501Srpaulostatic Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv) 1318214501Srpaulo{ 1319214501Srpaulo struct eap_ttls_data *data = priv; 1320214501Srpaulo return data->state == SUCCESS || data->state == FAILURE; 1321214501Srpaulo} 1322214501Srpaulo 1323214501Srpaulo 1324214501Srpaulostatic u8 * eap_ttls_v1_derive_key(struct eap_sm *sm, 1325214501Srpaulo struct eap_ttls_data *data) 1326214501Srpaulo{ 1327214501Srpaulo struct tls_keys keys; 1328214501Srpaulo u8 *rnd, *key; 1329214501Srpaulo 1330214501Srpaulo os_memset(&keys, 0, sizeof(keys)); 1331214501Srpaulo if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || 1332214501Srpaulo keys.client_random == NULL || keys.server_random == NULL || 1333214501Srpaulo keys.inner_secret == NULL) { 1334214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " 1335214501Srpaulo "client random, or server random to derive keying " 1336214501Srpaulo "material"); 1337214501Srpaulo return NULL; 1338214501Srpaulo } 1339214501Srpaulo 1340214501Srpaulo rnd = os_malloc(keys.client_random_len + keys.server_random_len); 1341214501Srpaulo key = os_malloc(EAP_TLS_KEY_LEN); 1342214501Srpaulo if (rnd == NULL || key == NULL) { 1343214501Srpaulo wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); 1344214501Srpaulo os_free(rnd); 1345214501Srpaulo os_free(key); 1346214501Srpaulo return NULL; 1347214501Srpaulo } 1348214501Srpaulo os_memcpy(rnd, keys.client_random, keys.client_random_len); 1349214501Srpaulo os_memcpy(rnd + keys.client_random_len, keys.server_random, 1350214501Srpaulo keys.server_random_len); 1351214501Srpaulo 1352214501Srpaulo if (tls_prf(keys.inner_secret, keys.inner_secret_len, 1353214501Srpaulo "ttls v1 keying material", rnd, keys.client_random_len + 1354214501Srpaulo keys.server_random_len, key, EAP_TLS_KEY_LEN)) { 1355214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); 1356214501Srpaulo os_free(rnd); 1357214501Srpaulo os_free(key); 1358214501Srpaulo return NULL; 1359214501Srpaulo } 1360214501Srpaulo 1361214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", 1362214501Srpaulo rnd, keys.client_random_len + keys.server_random_len); 1363214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", 1364214501Srpaulo keys.inner_secret, keys.inner_secret_len); 1365214501Srpaulo 1366214501Srpaulo os_free(rnd); 1367214501Srpaulo 1368214501Srpaulo return key; 1369214501Srpaulo} 1370214501Srpaulo 1371214501Srpaulo 1372214501Srpaulostatic u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) 1373214501Srpaulo{ 1374214501Srpaulo struct eap_ttls_data *data = priv; 1375214501Srpaulo u8 *eapKeyData; 1376214501Srpaulo 1377214501Srpaulo if (data->state != SUCCESS) 1378214501Srpaulo return NULL; 1379214501Srpaulo 1380214501Srpaulo if (data->ttls_version == 0) { 1381214501Srpaulo eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 1382214501Srpaulo "ttls keying material", 1383214501Srpaulo EAP_TLS_KEY_LEN); 1384214501Srpaulo } else { 1385214501Srpaulo eapKeyData = eap_ttls_v1_derive_key(sm, data); 1386214501Srpaulo } 1387214501Srpaulo 1388214501Srpaulo if (eapKeyData) { 1389214501Srpaulo *len = EAP_TLS_KEY_LEN; 1390214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", 1391214501Srpaulo eapKeyData, EAP_TLS_KEY_LEN); 1392214501Srpaulo } else { 1393214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); 1394214501Srpaulo } 1395214501Srpaulo 1396214501Srpaulo return eapKeyData; 1397214501Srpaulo} 1398214501Srpaulo 1399214501Srpaulo 1400214501Srpaulostatic Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv) 1401214501Srpaulo{ 1402214501Srpaulo struct eap_ttls_data *data = priv; 1403214501Srpaulo return data->state == SUCCESS; 1404214501Srpaulo} 1405214501Srpaulo 1406214501Srpaulo 1407214501Srpauloint eap_server_ttls_register(void) 1408214501Srpaulo{ 1409214501Srpaulo struct eap_method *eap; 1410214501Srpaulo int ret; 1411214501Srpaulo 1412214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1413214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); 1414214501Srpaulo if (eap == NULL) 1415214501Srpaulo return -1; 1416214501Srpaulo 1417214501Srpaulo eap->init = eap_ttls_init; 1418214501Srpaulo eap->reset = eap_ttls_reset; 1419214501Srpaulo eap->buildReq = eap_ttls_buildReq; 1420214501Srpaulo eap->check = eap_ttls_check; 1421214501Srpaulo eap->process = eap_ttls_process; 1422214501Srpaulo eap->isDone = eap_ttls_isDone; 1423214501Srpaulo eap->getKey = eap_ttls_getKey; 1424214501Srpaulo eap->isSuccess = eap_ttls_isSuccess; 1425214501Srpaulo 1426214501Srpaulo ret = eap_server_method_register(eap); 1427214501Srpaulo if (ret) 1428214501Srpaulo eap_server_method_free(eap); 1429214501Srpaulo return ret; 1430214501Srpaulo} 1431