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