eap_server_mschapv2.c revision 346981
1226031Sstas/* 2226031Sstas * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server 3226031Sstas * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 4226031Sstas * 5226031Sstas * This software may be distributed under the terms of the BSD license. 6226031Sstas * See README for more details. 7226031Sstas */ 8226031Sstas 9226031Sstas#include "includes.h" 10226031Sstas 11226031Sstas#include "common.h" 12226031Sstas#include "crypto/ms_funcs.h" 13226031Sstas#include "crypto/random.h" 14226031Sstas#include "eap_i.h" 15226031Sstas 16226031Sstas 17226031Sstasstruct eap_mschapv2_hdr { 18226031Sstas u8 op_code; /* MSCHAPV2_OP_* */ 19226031Sstas u8 mschapv2_id; /* must be changed for challenges, but not for 20226031Sstas * success/failure */ 21226031Sstas u8 ms_length[2]; /* Note: misaligned; length - 5 */ 22226031Sstas /* followed by data */ 23226031Sstas} STRUCT_PACKED; 24226031Sstas 25226031Sstas#define MSCHAPV2_OP_CHALLENGE 1 26226031Sstas#define MSCHAPV2_OP_RESPONSE 2 27226031Sstas#define MSCHAPV2_OP_SUCCESS 3 28226031Sstas#define MSCHAPV2_OP_FAILURE 4 29226031Sstas#define MSCHAPV2_OP_CHANGE_PASSWORD 7 30226031Sstas 31226031Sstas#define MSCHAPV2_RESP_LEN 49 32226031Sstas 33226031Sstas#define ERROR_RESTRICTED_LOGON_HOURS 646 34226031Sstas#define ERROR_ACCT_DISABLED 647 35226031Sstas#define ERROR_PASSWD_EXPIRED 648 36226031Sstas#define ERROR_NO_DIALIN_PERMISSION 649 37226031Sstas#define ERROR_AUTHENTICATION_FAILURE 691 38226031Sstas#define ERROR_CHANGING_PASSWORD 709 39226031Sstas 40226031Sstas#define PASSWD_CHANGE_CHAL_LEN 16 41226031Sstas#define MSCHAPV2_KEY_LEN 16 42226031Sstas 43226031Sstas 44226031Sstas#define CHALLENGE_LEN 16 45226031Sstas 46226031Sstasstruct eap_mschapv2_data { 47226031Sstas u8 auth_challenge[CHALLENGE_LEN]; 48226031Sstas int auth_challenge_from_tls; 49226031Sstas u8 *peer_challenge; 50226031Sstas u8 auth_response[20]; 51226031Sstas enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state; 52226031Sstas u8 resp_mschapv2_id; 53226031Sstas u8 master_key[16]; 54226031Sstas int master_key_valid; 55226031Sstas}; 56226031Sstas 57226031Sstas 58226031Sstasstatic void * eap_mschapv2_init(struct eap_sm *sm) 59226031Sstas{ 60226031Sstas struct eap_mschapv2_data *data; 61226031Sstas 62226031Sstas data = os_zalloc(sizeof(*data)); 63226031Sstas if (data == NULL) 64226031Sstas return NULL; 65226031Sstas data->state = CHALLENGE; 66226031Sstas 67226031Sstas if (sm->auth_challenge) { 68226031Sstas os_memcpy(data->auth_challenge, sm->auth_challenge, 69226031Sstas CHALLENGE_LEN); 70226031Sstas data->auth_challenge_from_tls = 1; 71226031Sstas } 72226031Sstas 73226031Sstas if (sm->peer_challenge) { 74226031Sstas data->peer_challenge = os_memdup(sm->peer_challenge, 75226031Sstas CHALLENGE_LEN); 76226031Sstas if (data->peer_challenge == NULL) { 77226031Sstas os_free(data); 78226031Sstas return NULL; 79226031Sstas } 80226031Sstas } 81226031Sstas 82226031Sstas return data; 83226031Sstas} 84226031Sstas 85226031Sstas 86226031Sstasstatic void eap_mschapv2_reset(struct eap_sm *sm, void *priv) 87226031Sstas{ 88226031Sstas struct eap_mschapv2_data *data = priv; 89226031Sstas if (data == NULL) 90226031Sstas return; 91226031Sstas 92226031Sstas os_free(data->peer_challenge); 93226031Sstas bin_clear_free(data, sizeof(*data)); 94226031Sstas} 95226031Sstas 96226031Sstas 97226031Sstasstatic struct wpabuf * eap_mschapv2_build_challenge( 98226031Sstas struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) 99226031Sstas{ 100226031Sstas struct wpabuf *req; 101226031Sstas struct eap_mschapv2_hdr *ms; 102226031Sstas size_t ms_len; 103226031Sstas 104226031Sstas if (!data->auth_challenge_from_tls && 105226031Sstas random_get_bytes(data->auth_challenge, CHALLENGE_LEN)) { 106226031Sstas wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random " 107226031Sstas "data"); 108226031Sstas data->state = FAILURE; 109226031Sstas return NULL; 110226031Sstas } 111226031Sstas 112226031Sstas ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len; 113226031Sstas req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, 114226031Sstas EAP_CODE_REQUEST, id); 115226031Sstas if (req == NULL) { 116226031Sstas wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" 117226031Sstas " for request"); 118226031Sstas data->state = FAILURE; 119226031Sstas return NULL; 120226031Sstas } 121226031Sstas 122226031Sstas ms = wpabuf_put(req, sizeof(*ms)); 123226031Sstas ms->op_code = MSCHAPV2_OP_CHALLENGE; 124226031Sstas ms->mschapv2_id = id; 125226031Sstas WPA_PUT_BE16(ms->ms_length, ms_len); 126226031Sstas 127226031Sstas wpabuf_put_u8(req, CHALLENGE_LEN); 128226031Sstas if (!data->auth_challenge_from_tls) 129226031Sstas wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN); 130226031Sstas else 131226031Sstas wpabuf_put(req, CHALLENGE_LEN); 132226031Sstas wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", 133226031Sstas data->auth_challenge, CHALLENGE_LEN); 134226031Sstas wpabuf_put_data(req, sm->server_id, sm->server_id_len); 135226031Sstas 136226031Sstas return req; 137226031Sstas} 138226031Sstas 139226031Sstas 140226031Sstasstatic struct wpabuf * eap_mschapv2_build_success_req( 141226031Sstas struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) 142226031Sstas{ 143226031Sstas struct wpabuf *req; 144226031Sstas struct eap_mschapv2_hdr *ms; 145226031Sstas u8 *msg; 146226031Sstas char *message = "OK"; 147226031Sstas size_t ms_len; 148226031Sstas 149226031Sstas ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 + 150226031Sstas os_strlen(message); 151226031Sstas req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, 152226031Sstas EAP_CODE_REQUEST, id); 153226031Sstas if (req == NULL) { 154226031Sstas wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" 155226031Sstas " for request"); 156226031Sstas data->state = FAILURE; 157226031Sstas return NULL; 158226031Sstas } 159226031Sstas 160226031Sstas ms = wpabuf_put(req, sizeof(*ms)); 161226031Sstas ms->op_code = MSCHAPV2_OP_SUCCESS; 162226031Sstas ms->mschapv2_id = data->resp_mschapv2_id; 163226031Sstas WPA_PUT_BE16(ms->ms_length, ms_len); 164226031Sstas msg = (u8 *) (ms + 1); 165226031Sstas 166226031Sstas wpabuf_put_u8(req, 'S'); 167226031Sstas wpabuf_put_u8(req, '='); 168226031Sstas wpa_snprintf_hex_uppercase( 169226031Sstas wpabuf_put(req, sizeof(data->auth_response) * 2), 170226031Sstas sizeof(data->auth_response) * 2 + 1, 171226031Sstas data->auth_response, sizeof(data->auth_response)); 172226031Sstas wpabuf_put_u8(req, ' '); 173226031Sstas wpabuf_put_u8(req, 'M'); 174226031Sstas wpabuf_put_u8(req, '='); 175226031Sstas wpabuf_put_data(req, message, os_strlen(message)); 176226031Sstas 177226031Sstas wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message", 178226031Sstas msg, ms_len - sizeof(*ms)); 179226031Sstas 180226031Sstas return req; 181226031Sstas} 182226031Sstas 183226031Sstas 184226031Sstasstatic struct wpabuf * eap_mschapv2_build_failure_req( 185226031Sstas struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) 186226031Sstas{ 187226031Sstas struct wpabuf *req; 188226031Sstas struct eap_mschapv2_hdr *ms; 189226031Sstas char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 " 190226031Sstas "M=FAILED"; 191226031Sstas size_t ms_len; 192226031Sstas 193226031Sstas ms_len = sizeof(*ms) + os_strlen(message); 194226031Sstas req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, 195226031Sstas EAP_CODE_REQUEST, id); 196226031Sstas if (req == NULL) { 197226031Sstas wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" 198226031Sstas " for request"); 199226031Sstas data->state = FAILURE; 200226031Sstas return NULL; 201226031Sstas } 202226031Sstas 203226031Sstas ms = wpabuf_put(req, sizeof(*ms)); 204226031Sstas ms->op_code = MSCHAPV2_OP_FAILURE; 205226031Sstas ms->mschapv2_id = data->resp_mschapv2_id; 206226031Sstas WPA_PUT_BE16(ms->ms_length, ms_len); 207226031Sstas 208226031Sstas wpabuf_put_data(req, message, os_strlen(message)); 209226031Sstas 210226031Sstas wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message", 211226031Sstas (u8 *) message, os_strlen(message)); 212226031Sstas 213226031Sstas return req; 214226031Sstas} 215226031Sstas 216226031Sstas 217226031Sstasstatic struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv, 218226031Sstas u8 id) 219226031Sstas{ 220226031Sstas struct eap_mschapv2_data *data = priv; 221226031Sstas 222226031Sstas switch (data->state) { 223226031Sstas case CHALLENGE: 224226031Sstas return eap_mschapv2_build_challenge(sm, data, id); 225226031Sstas case SUCCESS_REQ: 226226031Sstas return eap_mschapv2_build_success_req(sm, data, id); 227226031Sstas case FAILURE_REQ: 228226031Sstas return eap_mschapv2_build_failure_req(sm, data, id); 229226031Sstas default: 230226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in " 231226031Sstas "buildReq", data->state); 232226031Sstas break; 233226031Sstas } 234226031Sstas return NULL; 235226031Sstas} 236226031Sstas 237226031Sstas 238226031Sstasstatic Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv, 239226031Sstas struct wpabuf *respData) 240226031Sstas{ 241226031Sstas struct eap_mschapv2_data *data = priv; 242226031Sstas struct eap_mschapv2_hdr *resp; 243226031Sstas const u8 *pos; 244226031Sstas size_t len; 245226031Sstas 246226031Sstas pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, 247226031Sstas &len); 248226031Sstas if (pos == NULL || len < 1) { 249226031Sstas wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame"); 250226031Sstas return TRUE; 251226031Sstas } 252226031Sstas 253226031Sstas resp = (struct eap_mschapv2_hdr *) pos; 254226031Sstas if (data->state == CHALLENGE && 255226031Sstas resp->op_code != MSCHAPV2_OP_RESPONSE) { 256226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - " 257226031Sstas "ignore op %d", resp->op_code); 258226031Sstas return TRUE; 259226031Sstas } 260226031Sstas 261226031Sstas if (data->state == SUCCESS_REQ && 262226031Sstas resp->op_code != MSCHAPV2_OP_SUCCESS && 263226031Sstas resp->op_code != MSCHAPV2_OP_FAILURE) { 264226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or " 265226031Sstas "Failure - ignore op %d", resp->op_code); 266226031Sstas return TRUE; 267226031Sstas } 268226031Sstas 269226031Sstas if (data->state == FAILURE_REQ && 270226031Sstas resp->op_code != MSCHAPV2_OP_FAILURE) { 271226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure " 272226031Sstas "- ignore op %d", resp->op_code); 273226031Sstas return TRUE; 274226031Sstas } 275226031Sstas 276226031Sstas return FALSE; 277226031Sstas} 278226031Sstas 279226031Sstas 280226031Sstasstatic void eap_mschapv2_process_response(struct eap_sm *sm, 281226031Sstas struct eap_mschapv2_data *data, 282226031Sstas struct wpabuf *respData) 283226031Sstas{ 284226031Sstas struct eap_mschapv2_hdr *resp; 285226031Sstas const u8 *pos, *end, *peer_challenge, *nt_response, *name; 286226031Sstas u8 flags; 287226031Sstas size_t len, name_len, i; 288226031Sstas u8 expected[24]; 289226031Sstas const u8 *username, *user; 290226031Sstas size_t username_len, user_len; 291226031Sstas int res; 292226031Sstas char *buf; 293226031Sstas 294226031Sstas pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, 295226031Sstas &len); 296226031Sstas if (pos == NULL || len < 1) 297226031Sstas return; /* Should not happen - frame already validated */ 298226031Sstas 299226031Sstas end = pos + len; 300226031Sstas resp = (struct eap_mschapv2_hdr *) pos; 301226031Sstas pos = (u8 *) (resp + 1); 302226031Sstas 303226031Sstas if (len < sizeof(*resp) + 1 + 49 || 304226031Sstas resp->op_code != MSCHAPV2_OP_RESPONSE || 305226031Sstas pos[0] != 49) { 306226031Sstas wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response", 307226031Sstas respData); 308226031Sstas data->state = FAILURE; 309226031Sstas return; 310226031Sstas } 311226031Sstas data->resp_mschapv2_id = resp->mschapv2_id; 312226031Sstas pos++; 313226031Sstas peer_challenge = pos; 314226031Sstas pos += 16 + 8; 315226031Sstas nt_response = pos; 316226031Sstas pos += 24; 317226031Sstas flags = *pos++; 318226031Sstas name = pos; 319226031Sstas name_len = end - name; 320226031Sstas 321226031Sstas if (data->peer_challenge) { 322226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured " 323226031Sstas "Peer-Challenge"); 324226031Sstas peer_challenge = data->peer_challenge; 325226031Sstas } 326226031Sstas wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge", 327226031Sstas peer_challenge, 16); 328226031Sstas wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24); 329226031Sstas wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags); 330226031Sstas wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len); 331226031Sstas 332226031Sstas buf = os_malloc(name_len * 4 + 1); 333226031Sstas if (buf) { 334226031Sstas printf_encode(buf, name_len * 4 + 1, name, name_len); 335226031Sstas eap_log_msg(sm, "EAP-MSCHAPV2 Name '%s'", buf); 336226031Sstas os_free(buf); 337226031Sstas } 338226031Sstas 339226031Sstas /* MSCHAPv2 does not include optional domain name in the 340226031Sstas * challenge-response calculation, so remove domain prefix 341226031Sstas * (if present). */ 342226031Sstas username = sm->identity; 343226031Sstas username_len = sm->identity_len; 344226031Sstas for (i = 0; i < username_len; i++) { 345226031Sstas if (username[i] == '\\') { 346226031Sstas username_len -= i + 1; 347226031Sstas username += i + 1; 348226031Sstas break; 349226031Sstas } 350226031Sstas } 351226031Sstas 352226031Sstas user = name; 353226031Sstas user_len = name_len; 354226031Sstas for (i = 0; i < user_len; i++) { 355226031Sstas if (user[i] == '\\') { 356226031Sstas user_len -= i + 1; 357226031Sstas user += i + 1; 358226031Sstas break; 359226031Sstas } 360226031Sstas } 361226031Sstas 362226031Sstas#ifdef CONFIG_TESTING_OPTIONS 363226031Sstas { 364226031Sstas u8 challenge[8]; 365226031Sstas 366226031Sstas if (challenge_hash(peer_challenge, data->auth_challenge, 367226031Sstas username, username_len, challenge) == 0) { 368226031Sstas eap_server_mschap_rx_callback(sm, "EAP-MSCHAPV2", 369226031Sstas username, username_len, 370226031Sstas challenge, nt_response); 371226031Sstas } 372226031Sstas } 373226031Sstas#endif /* CONFIG_TESTING_OPTIONS */ 374226031Sstas 375226031Sstas if (username_len != user_len || 376226031Sstas os_memcmp(username, user, username_len) != 0) { 377226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names"); 378226031Sstas wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user " 379226031Sstas "name", username, username_len); 380226031Sstas wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user " 381226031Sstas "name", user, user_len); 382226031Sstas data->state = FAILURE; 383226031Sstas return; 384226031Sstas } 385226031Sstas 386226031Sstas wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name", 387226031Sstas username, username_len); 388226031Sstas 389226031Sstas if (sm->user->password_hash) { 390226031Sstas res = generate_nt_response_pwhash(data->auth_challenge, 391226031Sstas peer_challenge, 392226031Sstas username, username_len, 393226031Sstas sm->user->password, 394226031Sstas expected); 395226031Sstas } else { 396226031Sstas res = generate_nt_response(data->auth_challenge, 397226031Sstas peer_challenge, 398226031Sstas username, username_len, 399226031Sstas sm->user->password, 400226031Sstas sm->user->password_len, 401226031Sstas expected); 402226031Sstas } 403226031Sstas if (res) { 404226031Sstas data->state = FAILURE; 405226031Sstas return; 406226031Sstas } 407226031Sstas 408226031Sstas if (os_memcmp_const(nt_response, expected, 24) == 0) { 409226031Sstas const u8 *pw_hash; 410226031Sstas u8 pw_hash_buf[16], pw_hash_hash[16]; 411226031Sstas 412226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response"); 413226031Sstas data->state = SUCCESS_REQ; 414226031Sstas 415226031Sstas /* Authenticator response is not really needed yet, but 416226031Sstas * calculate it here so that peer_challenge and username need 417226031Sstas * not be saved. */ 418226031Sstas if (sm->user->password_hash) { 419226031Sstas pw_hash = sm->user->password; 420226031Sstas } else { 421226031Sstas if (nt_password_hash(sm->user->password, 422226031Sstas sm->user->password_len, 423226031Sstas pw_hash_buf) < 0) { 424226031Sstas data->state = FAILURE; 425226031Sstas return; 426226031Sstas } 427226031Sstas pw_hash = pw_hash_buf; 428226031Sstas } 429226031Sstas if (generate_authenticator_response_pwhash( 430226031Sstas pw_hash, peer_challenge, data->auth_challenge, 431226031Sstas username, username_len, nt_response, 432226031Sstas data->auth_response) < 0 || 433226031Sstas hash_nt_password_hash(pw_hash, pw_hash_hash) < 0 || 434226031Sstas get_master_key(pw_hash_hash, nt_response, 435226031Sstas data->master_key)) { 436226031Sstas data->state = FAILURE; 437226031Sstas return; 438226031Sstas } 439226031Sstas data->master_key_valid = 1; 440226031Sstas wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key", 441226031Sstas data->master_key, MSCHAPV2_KEY_LEN); 442226031Sstas } else { 443226031Sstas wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response", 444226031Sstas expected, 24); 445226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response"); 446226031Sstas data->state = FAILURE_REQ; 447226031Sstas } 448226031Sstas} 449226031Sstas 450226031Sstas 451226031Sstasstatic void eap_mschapv2_process_success_resp(struct eap_sm *sm, 452226031Sstas struct eap_mschapv2_data *data, 453226031Sstas struct wpabuf *respData) 454226031Sstas{ 455226031Sstas struct eap_mschapv2_hdr *resp; 456226031Sstas const u8 *pos; 457226031Sstas size_t len; 458226031Sstas 459226031Sstas pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, 460226031Sstas &len); 461226031Sstas if (pos == NULL || len < 1) 462226031Sstas return; /* Should not happen - frame already validated */ 463226031Sstas 464226031Sstas resp = (struct eap_mschapv2_hdr *) pos; 465226031Sstas 466226031Sstas if (resp->op_code == MSCHAPV2_OP_SUCCESS) { 467226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response" 468226031Sstas " - authentication completed successfully"); 469226031Sstas data->state = SUCCESS; 470226031Sstas } else { 471226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success " 472226031Sstas "Response - peer rejected authentication"); 473226031Sstas data->state = FAILURE; 474226031Sstas } 475226031Sstas} 476226031Sstas 477226031Sstas 478226031Sstasstatic void eap_mschapv2_process_failure_resp(struct eap_sm *sm, 479226031Sstas struct eap_mschapv2_data *data, 480226031Sstas struct wpabuf *respData) 481226031Sstas{ 482226031Sstas struct eap_mschapv2_hdr *resp; 483226031Sstas const u8 *pos; 484226031Sstas size_t len; 485226031Sstas 486226031Sstas pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, 487226031Sstas &len); 488226031Sstas if (pos == NULL || len < 1) 489226031Sstas return; /* Should not happen - frame already validated */ 490226031Sstas 491226031Sstas resp = (struct eap_mschapv2_hdr *) pos; 492226031Sstas 493226031Sstas if (resp->op_code == MSCHAPV2_OP_FAILURE) { 494226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response" 495226031Sstas " - authentication failed"); 496226031Sstas } else { 497226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure " 498226031Sstas "Response - authentication failed"); 499226031Sstas } 500226031Sstas 501226031Sstas data->state = FAILURE; 502226031Sstas} 503226031Sstas 504226031Sstas 505226031Sstasstatic void eap_mschapv2_process(struct eap_sm *sm, void *priv, 506226031Sstas struct wpabuf *respData) 507226031Sstas{ 508226031Sstas struct eap_mschapv2_data *data = priv; 509226031Sstas 510226031Sstas if (sm->user == NULL || sm->user->password == NULL) { 511226031Sstas wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured"); 512226031Sstas data->state = FAILURE; 513226031Sstas return; 514226031Sstas } 515226031Sstas 516226031Sstas switch (data->state) { 517226031Sstas case CHALLENGE: 518226031Sstas eap_mschapv2_process_response(sm, data, respData); 519226031Sstas break; 520226031Sstas case SUCCESS_REQ: 521226031Sstas eap_mschapv2_process_success_resp(sm, data, respData); 522226031Sstas break; 523226031Sstas case FAILURE_REQ: 524226031Sstas eap_mschapv2_process_failure_resp(sm, data, respData); 525226031Sstas break; 526226031Sstas default: 527226031Sstas wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in " 528226031Sstas "process", data->state); 529226031Sstas break; 530226031Sstas } 531226031Sstas} 532226031Sstas 533226031Sstas 534226031Sstasstatic Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv) 535226031Sstas{ 536226031Sstas struct eap_mschapv2_data *data = priv; 537226031Sstas return data->state == SUCCESS || data->state == FAILURE; 538226031Sstas} 539226031Sstas 540226031Sstas 541226031Sstasstatic u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) 542226031Sstas{ 543226031Sstas struct eap_mschapv2_data *data = priv; 544226031Sstas u8 *key; 545226031Sstas 546226031Sstas if (data->state != SUCCESS || !data->master_key_valid) 547226031Sstas return NULL; 548226031Sstas 549226031Sstas *len = 2 * MSCHAPV2_KEY_LEN; 550226031Sstas key = os_malloc(*len); 551226031Sstas if (key == NULL) 552226031Sstas return NULL; 553226031Sstas /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */ 554226031Sstas if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 555226031Sstas 1) < 0 || 556226031Sstas get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, 557226031Sstas MSCHAPV2_KEY_LEN, 1, 1) < 0) { 558226031Sstas os_free(key); 559226031Sstas return NULL; 560226031Sstas } 561226031Sstas wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len); 562226031Sstas 563226031Sstas return key; 564226031Sstas} 565226031Sstas 566226031Sstas 567226031Sstasstatic Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv) 568226031Sstas{ 569226031Sstas struct eap_mschapv2_data *data = priv; 570226031Sstas return data->state == SUCCESS; 571226031Sstas} 572226031Sstas 573226031Sstas 574226031Sstasint eap_server_mschapv2_register(void) 575226031Sstas{ 576226031Sstas struct eap_method *eap; 577226031Sstas 578226031Sstas eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 579226031Sstas EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 580226031Sstas "MSCHAPV2"); 581226031Sstas if (eap == NULL) 582226031Sstas return -1; 583226031Sstas 584226031Sstas eap->init = eap_mschapv2_init; 585226031Sstas eap->reset = eap_mschapv2_reset; 586226031Sstas eap->buildReq = eap_mschapv2_buildReq; 587226031Sstas eap->check = eap_mschapv2_check; 588226031Sstas eap->process = eap_mschapv2_process; 589226031Sstas eap->isDone = eap_mschapv2_isDone; 590226031Sstas eap->getKey = eap_mschapv2_getKey; 591226031Sstas eap->isSuccess = eap_mschapv2_isSuccess; 592226031Sstas 593226031Sstas return eap_server_method_register(eap); 594226031Sstas} 595226031Sstas