eap_server_mschapv2.c revision 281806
11556Srgrimes/*
21556Srgrimes * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server
31556Srgrimes * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
41556Srgrimes *
51556Srgrimes * This software may be distributed under the terms of the BSD license.
61556Srgrimes * See README for more details.
71556Srgrimes */
81556Srgrimes
91556Srgrimes#include "includes.h"
101556Srgrimes
111556Srgrimes#include "common.h"
121556Srgrimes#include "crypto/ms_funcs.h"
131556Srgrimes#include "crypto/random.h"
141556Srgrimes#include "eap_i.h"
151556Srgrimes
161556Srgrimes
171556Srgrimesstruct eap_mschapv2_hdr {
181556Srgrimes	u8 op_code; /* MSCHAPV2_OP_* */
191556Srgrimes	u8 mschapv2_id; /* must be changed for challenges, but not for
201556Srgrimes			 * success/failure */
211556Srgrimes	u8 ms_length[2]; /* Note: misaligned; length - 5 */
221556Srgrimes	/* followed by data */
231556Srgrimes} STRUCT_PACKED;
241556Srgrimes
251556Srgrimes#define MSCHAPV2_OP_CHALLENGE 1
261556Srgrimes#define MSCHAPV2_OP_RESPONSE 2
271556Srgrimes#define MSCHAPV2_OP_SUCCESS 3
281556Srgrimes#define MSCHAPV2_OP_FAILURE 4
291556Srgrimes#define MSCHAPV2_OP_CHANGE_PASSWORD 7
301556Srgrimes
311556Srgrimes#define MSCHAPV2_RESP_LEN 49
321556Srgrimes
331556Srgrimes#define ERROR_RESTRICTED_LOGON_HOURS 646
341556Srgrimes#define ERROR_ACCT_DISABLED 647
351556Srgrimes#define ERROR_PASSWD_EXPIRED 648
361556Srgrimes#define ERROR_NO_DIALIN_PERMISSION 649
371556Srgrimes#define ERROR_AUTHENTICATION_FAILURE 691
3820412Ssteve#define ERROR_CHANGING_PASSWORD 709
391556Srgrimes
401556Srgrimes#define PASSWD_CHANGE_CHAL_LEN 16
411556Srgrimes#define MSCHAPV2_KEY_LEN 16
421556Srgrimes
431556Srgrimes
4435772Scharnier#define CHALLENGE_LEN 16
4536000Scharnier
4635772Scharnierstruct eap_mschapv2_data {
4735772Scharnier	u8 auth_challenge[CHALLENGE_LEN];
4850471Speter	int auth_challenge_from_tls;
491556Srgrimes	u8 *peer_challenge;
501556Srgrimes	u8 auth_response[20];
511556Srgrimes	enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
521556Srgrimes	u8 resp_mschapv2_id;
5383482Sdillon	u8 master_key[16];
5483482Sdillon	int master_key_valid;
5583482Sdillon};
5683482Sdillon
5783482Sdillon
581556Srgrimesstatic void * eap_mschapv2_init(struct eap_sm *sm)
591556Srgrimes{
601556Srgrimes	struct eap_mschapv2_data *data;
611556Srgrimes
6218578Sache	data = os_zalloc(sizeof(*data));
631556Srgrimes	if (data == NULL)
641556Srgrimes		return NULL;
6578732Sdd	data->state = CHALLENGE;
661556Srgrimes
6783482Sdillon	if (sm->auth_challenge) {
681556Srgrimes		os_memcpy(data->auth_challenge, sm->auth_challenge,
691556Srgrimes			  CHALLENGE_LEN);
701556Srgrimes		data->auth_challenge_from_tls = 1;
7139065Simp	}
721556Srgrimes
7398216Sjmallett	if (sm->peer_challenge) {
7490106Simp		data->peer_challenge = os_malloc(CHALLENGE_LEN);
7590106Simp		if (data->peer_challenge == NULL) {
7690106Simp			os_free(data);
771556Srgrimes			return NULL;
7883482Sdillon		}
7990106Simp		os_memcpy(data->peer_challenge, sm->peer_challenge,
8083482Sdillon			  CHALLENGE_LEN);
8183482Sdillon	}
821556Srgrimes
8390106Simp	return data;
841556Srgrimes}
851556Srgrimes
861556Srgrimes
8718578Sachestatic void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
8818578Sache{
8924348Simp	struct eap_mschapv2_data *data = priv;
901556Srgrimes	if (data == NULL)
911556Srgrimes		return;
921556Srgrimes
931556Srgrimes	os_free(data->peer_challenge);
941556Srgrimes	bin_clear_free(data, sizeof(*data));
951556Srgrimes}
961556Srgrimes
971556Srgrimes
981556Srgrimesstatic struct wpabuf * eap_mschapv2_build_challenge(
991556Srgrimes	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
1001556Srgrimes{
1011556Srgrimes	struct wpabuf *req;
1021556Srgrimes	struct eap_mschapv2_hdr *ms;
1031556Srgrimes	size_t ms_len;
1041556Srgrimes
1051556Srgrimes	if (!data->auth_challenge_from_tls &&
1061556Srgrimes	    random_get_bytes(data->auth_challenge, CHALLENGE_LEN)) {
10759239Sasmodai		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
1081556Srgrimes			   "data");
1091556Srgrimes		data->state = FAILURE;
1101556Srgrimes		return NULL;
1111556Srgrimes	}
11218546Simp
11398216Sjmallett	ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
1141556Srgrimes	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
1151556Srgrimes			    EAP_CODE_REQUEST, id);
1161556Srgrimes	if (req == NULL) {
1171556Srgrimes		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
11883482Sdillon			   " for request");
1191556Srgrimes		data->state = FAILURE;
12083482Sdillon		return NULL;
1211556Srgrimes	}
1221556Srgrimes
1231556Srgrimes	ms = wpabuf_put(req, sizeof(*ms));
1241556Srgrimes	ms->op_code = MSCHAPV2_OP_CHALLENGE;
1251556Srgrimes	ms->mschapv2_id = id;
12698216Sjmallett	WPA_PUT_BE16(ms->ms_length, ms_len);
12798216Sjmallett
12898216Sjmallett	wpabuf_put_u8(req, CHALLENGE_LEN);
12998216Sjmallett	if (!data->auth_challenge_from_tls)
13098216Sjmallett		wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN);
13198216Sjmallett	else
13298216Sjmallett		wpabuf_put(req, CHALLENGE_LEN);
1331556Srgrimes	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
13490106Simp		    data->auth_challenge, CHALLENGE_LEN);
1351556Srgrimes	wpabuf_put_data(req, sm->server_id, sm->server_id_len);
13683482Sdillon
13783482Sdillon	return req;
13883961Sru}
1391556Srgrimes
14083482Sdillon
14183482Sdillonstatic struct wpabuf * eap_mschapv2_build_success_req(
14283482Sdillon	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
14383482Sdillon{
14483482Sdillon	struct wpabuf *req;
14583961Sru	struct eap_mschapv2_hdr *ms;
14683482Sdillon	u8 *msg;
14783482Sdillon	char *message = "OK";
14883482Sdillon	size_t ms_len;
14983482Sdillon
15083482Sdillon	ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 +
15183962Sru		os_strlen(message);
15283482Sdillon	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
1531556Srgrimes			    EAP_CODE_REQUEST, id);
15483482Sdillon	if (req == NULL) {
15583482Sdillon		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
15683482Sdillon			   " for request");
15783482Sdillon		data->state = FAILURE;
15883961Sru		return NULL;
15983961Sru	}
16083961Sru
16183961Sru	ms = wpabuf_put(req, sizeof(*ms));
16283961Sru	ms->op_code = MSCHAPV2_OP_SUCCESS;
16383961Sru	ms->mschapv2_id = data->resp_mschapv2_id;
16483961Sru	WPA_PUT_BE16(ms->ms_length, ms_len);
16583482Sdillon	msg = (u8 *) (ms + 1);
16683482Sdillon
16783961Sru	wpabuf_put_u8(req, 'S');
16883961Sru	wpabuf_put_u8(req, '=');
16983482Sdillon	wpa_snprintf_hex_uppercase(
17083482Sdillon		wpabuf_put(req, sizeof(data->auth_response) * 2),
17183482Sdillon		sizeof(data->auth_response) * 2 + 1,
17283482Sdillon		data->auth_response, sizeof(data->auth_response));
17383482Sdillon	wpabuf_put_u8(req, ' ');
1741556Srgrimes	wpabuf_put_u8(req, 'M');
1751556Srgrimes	wpabuf_put_u8(req, '=');
17683482Sdillon	wpabuf_put_data(req, message, os_strlen(message));
17790106Simp
1781556Srgrimes	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message",
17990106Simp			  msg, ms_len - sizeof(*ms));
1801556Srgrimes
18183961Sru	return req;
18283961Sru}
18383961Sru
18483961Sru
1851556Srgrimesstatic struct wpabuf * eap_mschapv2_build_failure_req(
1861556Srgrimes	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
1871556Srgrimes{
18898169Stjr	struct wpabuf *req;
18998169Stjr	struct eap_mschapv2_hdr *ms;
19098169Stjr	char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 "
19198169Stjr		"M=FAILED";
1921556Srgrimes	size_t ms_len;
19398169Stjr
19498169Stjr	ms_len = sizeof(*ms) + os_strlen(message);
19598169Stjr	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
19698169Stjr			    EAP_CODE_REQUEST, id);
19798169Stjr	if (req == NULL) {
1981556Srgrimes		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
1991556Srgrimes			   " for request");
2001556Srgrimes		data->state = FAILURE;
2011556Srgrimes		return NULL;
2021556Srgrimes	}
20398169Stjr
20498169Stjr	ms = wpabuf_put(req, sizeof(*ms));
2051556Srgrimes	ms->op_code = MSCHAPV2_OP_FAILURE;
2061556Srgrimes	ms->mschapv2_id = data->resp_mschapv2_id;
2071556Srgrimes	WPA_PUT_BE16(ms->ms_length, ms_len);
2081556Srgrimes
2091556Srgrimes	wpabuf_put_data(req, message, os_strlen(message));
2101556Srgrimes
2111556Srgrimes	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message",
21218578Sache			  (u8 *) message, os_strlen(message));
2131556Srgrimes
2141556Srgrimes	return req;
2151556Srgrimes}
2161556Srgrimes
2171556Srgrimes
2181556Srgrimesstatic struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv,
2191556Srgrimes					     u8 id)
2201556Srgrimes{
2211556Srgrimes	struct eap_mschapv2_data *data = priv;
2221556Srgrimes
2231556Srgrimes	switch (data->state) {
2241556Srgrimes	case CHALLENGE:
2251556Srgrimes		return eap_mschapv2_build_challenge(sm, data, id);
2261556Srgrimes	case SUCCESS_REQ:
2271556Srgrimes		return eap_mschapv2_build_success_req(sm, data, id);
2281556Srgrimes	case FAILURE_REQ:
2291556Srgrimes		return eap_mschapv2_build_failure_req(sm, data, id);
23011145Sbde	default:
2311556Srgrimes		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
2321556Srgrimes			   "buildReq", data->state);
2331556Srgrimes		break;
2341556Srgrimes	}
2351556Srgrimes	return NULL;
2361556Srgrimes}
23783482Sdillon
23890106Simp
2391556Srgrimesstatic Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
24090106Simp				  struct wpabuf *respData)
24139065Simp{
24239065Simp	struct eap_mschapv2_data *data = priv;
24391079Smarkm	struct eap_mschapv2_hdr *resp;
2441556Srgrimes	const u8 *pos;
2451556Srgrimes	size_t len;
2461556Srgrimes
2471556Srgrimes	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
2481556Srgrimes			       &len);
2491556Srgrimes	if (pos == NULL || len < 1) {
2501556Srgrimes		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
25139138Simp		return TRUE;
25259239Sasmodai	}
2531556Srgrimes
2541556Srgrimes	resp = (struct eap_mschapv2_hdr *) pos;
2551556Srgrimes	if (data->state == CHALLENGE &&
25639138Simp	    resp->op_code != MSCHAPV2_OP_RESPONSE) {
2571556Srgrimes		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
25811145Sbde			   "ignore op %d", resp->op_code);
2591556Srgrimes		return TRUE;
26011145Sbde	}
26111145Sbde
2621556Srgrimes	if (data->state == SUCCESS_REQ &&
26383482Sdillon	    resp->op_code != MSCHAPV2_OP_SUCCESS &&
26483482Sdillon	    resp->op_code != MSCHAPV2_OP_FAILURE) {
26583482Sdillon		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or "
26683482Sdillon			   "Failure - ignore op %d", resp->op_code);
26790106Simp		return TRUE;
26883482Sdillon	}
26983482Sdillon
27083482Sdillon	if (data->state == FAILURE_REQ &&
27191079Smarkm	    resp->op_code != MSCHAPV2_OP_FAILURE) {
27283482Sdillon		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure "
27383482Sdillon			   "- ignore op %d", resp->op_code);
27483482Sdillon		return TRUE;
27583482Sdillon	}
27683482Sdillon
27783482Sdillon	return FALSE;
27891079Smarkm}
27991079Smarkm
28083482Sdillon
28183482Sdillonstatic void eap_mschapv2_process_response(struct eap_sm *sm,
28283482Sdillon					  struct eap_mschapv2_data *data,
28383482Sdillon					  struct wpabuf *respData)
28483482Sdillon{
28583482Sdillon	struct eap_mschapv2_hdr *resp;
28683482Sdillon	const u8 *pos, *end, *peer_challenge, *nt_response, *name;
28783482Sdillon	u8 flags;
28883482Sdillon	size_t len, name_len, i;
28983482Sdillon	u8 expected[24];
29083482Sdillon	const u8 *username, *user;
29183482Sdillon	size_t username_len, user_len;
29283482Sdillon	int res;
29383482Sdillon	char *buf;
29483482Sdillon
29583482Sdillon	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
29683482Sdillon			       &len);
29791079Smarkm	if (pos == NULL || len < 1)
29891079Smarkm		return; /* Should not happen - frame already validated */
29983482Sdillon
30083482Sdillon	end = pos + len;
30191079Smarkm	resp = (struct eap_mschapv2_hdr *) pos;
30291079Smarkm	pos = (u8 *) (resp + 1);
30383482Sdillon
30483482Sdillon	if (len < sizeof(*resp) + 1 + 49 ||
30583482Sdillon	    resp->op_code != MSCHAPV2_OP_RESPONSE ||
30683482Sdillon	    pos[0] != 49) {
30783482Sdillon		wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response",
30883482Sdillon				respData);
30983482Sdillon		data->state = FAILURE;
31083482Sdillon		return;
31183482Sdillon	}
312	data->resp_mschapv2_id = resp->mschapv2_id;
313	pos++;
314	peer_challenge = pos;
315	pos += 16 + 8;
316	nt_response = pos;
317	pos += 24;
318	flags = *pos++;
319	name = pos;
320	name_len = end - name;
321
322	if (data->peer_challenge) {
323		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured "
324			   "Peer-Challenge");
325		peer_challenge = data->peer_challenge;
326	}
327	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
328		    peer_challenge, 16);
329	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24);
330	wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags);
331	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len);
332
333	buf = os_malloc(name_len * 4 + 1);
334	if (buf) {
335		printf_encode(buf, name_len * 4 + 1, name, name_len);
336		eap_log_msg(sm, "EAP-MSCHAPV2 Name '%s'", buf);
337		os_free(buf);
338	}
339
340	/* MSCHAPv2 does not include optional domain name in the
341	 * challenge-response calculation, so remove domain prefix
342	 * (if present). */
343	username = sm->identity;
344	username_len = sm->identity_len;
345	for (i = 0; i < username_len; i++) {
346		if (username[i] == '\\') {
347			username_len -= i + 1;
348			username += i + 1;
349			break;
350		}
351	}
352
353	user = name;
354	user_len = name_len;
355	for (i = 0; i < user_len; i++) {
356		if (user[i] == '\\') {
357			user_len -= i + 1;
358			user += i + 1;
359			break;
360		}
361	}
362
363	if (username_len != user_len ||
364	    os_memcmp(username, user, username_len) != 0) {
365		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names");
366		wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user "
367				  "name", username, username_len);
368		wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user "
369				  "name", user, user_len);
370		data->state = FAILURE;
371		return;
372	}
373
374	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name",
375			  username, username_len);
376
377	if (sm->user->password_hash) {
378		res = generate_nt_response_pwhash(data->auth_challenge,
379						  peer_challenge,
380						  username, username_len,
381						  sm->user->password,
382						  expected);
383	} else {
384		res = generate_nt_response(data->auth_challenge,
385					   peer_challenge,
386					   username, username_len,
387					   sm->user->password,
388					   sm->user->password_len,
389					   expected);
390	}
391	if (res) {
392		data->state = FAILURE;
393		return;
394	}
395
396	if (os_memcmp_const(nt_response, expected, 24) == 0) {
397		const u8 *pw_hash;
398		u8 pw_hash_buf[16], pw_hash_hash[16];
399
400		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response");
401		data->state = SUCCESS_REQ;
402
403		/* Authenticator response is not really needed yet, but
404		 * calculate it here so that peer_challenge and username need
405		 * not be saved. */
406		if (sm->user->password_hash) {
407			pw_hash = sm->user->password;
408		} else {
409			if (nt_password_hash(sm->user->password,
410					     sm->user->password_len,
411					     pw_hash_buf) < 0) {
412				data->state = FAILURE;
413				return;
414			}
415			pw_hash = pw_hash_buf;
416		}
417		if (generate_authenticator_response_pwhash(
418			    pw_hash, peer_challenge, data->auth_challenge,
419			    username, username_len, nt_response,
420			    data->auth_response) < 0 ||
421		    hash_nt_password_hash(pw_hash, pw_hash_hash) < 0 ||
422		    get_master_key(pw_hash_hash, nt_response,
423				   data->master_key)) {
424			data->state = FAILURE;
425			return;
426		}
427		data->master_key_valid = 1;
428		wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
429				data->master_key, MSCHAPV2_KEY_LEN);
430	} else {
431		wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response",
432			    expected, 24);
433		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response");
434		data->state = FAILURE_REQ;
435	}
436}
437
438
439static void eap_mschapv2_process_success_resp(struct eap_sm *sm,
440					      struct eap_mschapv2_data *data,
441					      struct wpabuf *respData)
442{
443	struct eap_mschapv2_hdr *resp;
444	const u8 *pos;
445	size_t len;
446
447	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
448			       &len);
449	if (pos == NULL || len < 1)
450		return; /* Should not happen - frame already validated */
451
452	resp = (struct eap_mschapv2_hdr *) pos;
453
454	if (resp->op_code == MSCHAPV2_OP_SUCCESS) {
455		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response"
456			   " - authentication completed successfully");
457		data->state = SUCCESS;
458	} else {
459		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success "
460			   "Response - peer rejected authentication");
461		data->state = FAILURE;
462	}
463}
464
465
466static void eap_mschapv2_process_failure_resp(struct eap_sm *sm,
467					      struct eap_mschapv2_data *data,
468					      struct wpabuf *respData)
469{
470	struct eap_mschapv2_hdr *resp;
471	const u8 *pos;
472	size_t len;
473
474	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
475			       &len);
476	if (pos == NULL || len < 1)
477		return; /* Should not happen - frame already validated */
478
479	resp = (struct eap_mschapv2_hdr *) pos;
480
481	if (resp->op_code == MSCHAPV2_OP_FAILURE) {
482		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response"
483			   " - authentication failed");
484	} else {
485		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure "
486			   "Response - authentication failed");
487	}
488
489	data->state = FAILURE;
490}
491
492
493static void eap_mschapv2_process(struct eap_sm *sm, void *priv,
494				 struct wpabuf *respData)
495{
496	struct eap_mschapv2_data *data = priv;
497
498	if (sm->user == NULL || sm->user->password == NULL) {
499		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
500		data->state = FAILURE;
501		return;
502	}
503
504	switch (data->state) {
505	case CHALLENGE:
506		eap_mschapv2_process_response(sm, data, respData);
507		break;
508	case SUCCESS_REQ:
509		eap_mschapv2_process_success_resp(sm, data, respData);
510		break;
511	case FAILURE_REQ:
512		eap_mschapv2_process_failure_resp(sm, data, respData);
513		break;
514	default:
515		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
516			   "process", data->state);
517		break;
518	}
519}
520
521
522static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
523{
524	struct eap_mschapv2_data *data = priv;
525	return data->state == SUCCESS || data->state == FAILURE;
526}
527
528
529static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
530{
531	struct eap_mschapv2_data *data = priv;
532	u8 *key;
533
534	if (data->state != SUCCESS || !data->master_key_valid)
535		return NULL;
536
537	*len = 2 * MSCHAPV2_KEY_LEN;
538	key = os_malloc(*len);
539	if (key == NULL)
540		return NULL;
541	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
542	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
543	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
544				MSCHAPV2_KEY_LEN, 1, 1);
545	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
546
547	return key;
548}
549
550
551static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
552{
553	struct eap_mschapv2_data *data = priv;
554	return data->state == SUCCESS;
555}
556
557
558int eap_server_mschapv2_register(void)
559{
560	struct eap_method *eap;
561	int ret;
562
563	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
564				      EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
565				      "MSCHAPV2");
566	if (eap == NULL)
567		return -1;
568
569	eap->init = eap_mschapv2_init;
570	eap->reset = eap_mschapv2_reset;
571	eap->buildReq = eap_mschapv2_buildReq;
572	eap->check = eap_mschapv2_check;
573	eap->process = eap_mschapv2_process;
574	eap->isDone = eap_mschapv2_isDone;
575	eap->getKey = eap_mschapv2_getKey;
576	eap->isSuccess = eap_mschapv2_isSuccess;
577
578	ret = eap_server_method_register(eap);
579	if (ret)
580		eap_server_method_free(eap);
581	return ret;
582}
583