1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify
6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as
7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation.
8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license.
11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details.
13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This file implements EAP peer part of EAP-MSCHAPV2 method (EAP type 26).
15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * draft-kamath-pppext-eap-mschapv2-00.txt defines the Microsoft EAP CHAP
16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Extensions Protocol, Version 2, for mutual authentication and key
17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * derivation. This encapsulates MS-CHAP-v2 protocol which is defined in
18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * RFC 2759. Use of EAP-MSCHAPV2 derived keys with MPPE cipher is described in
19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * RFC 3079.
20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h"
23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h"
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_i.h"
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_config.h"
27b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/ms_funcs.h"
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "wpa_ctrl.h"
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "mschapv2.h"
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef _MSC_VER
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#pragma pack(push, 1)
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* _MSC_VER */
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct eap_mschapv2_hdr {
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 op_code; /* MSCHAPV2_OP_* */
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 mschapv2_id; /* usually same as EAP identifier; must be changed
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 * for challenges, but not for success/failure */
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 ms_length[2]; /* Note: misaligned; length - 5 */
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* followed by data */
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} STRUCT_PACKED;
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* Response Data field */
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct ms_response {
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 peer_challenge[MSCHAPV2_CHAL_LEN];
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 reserved[8];
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 flags;
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} STRUCT_PACKED;
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* Change-Password Data field */
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct ms_change_password {
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 encr_password[516];
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 encr_hash[16];
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 peer_challenge[MSCHAPV2_CHAL_LEN];
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 reserved[8];
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 flags[2];
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} STRUCT_PACKED;
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef _MSC_VER
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#pragma pack(pop)
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* _MSC_VER */
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define MSCHAPV2_OP_CHALLENGE 1
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define MSCHAPV2_OP_RESPONSE 2
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define MSCHAPV2_OP_SUCCESS 3
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define MSCHAPV2_OP_FAILURE 4
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define MSCHAPV2_OP_CHANGE_PASSWORD 7
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define ERROR_RESTRICTED_LOGON_HOURS 646
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define ERROR_ACCT_DISABLED 647
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define ERROR_PASSWD_EXPIRED 648
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define ERROR_NO_DIALIN_PERMISSION 649
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define ERROR_AUTHENTICATION_FAILURE 691
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define ERROR_CHANGING_PASSWORD 709
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define PASSWD_CHANGE_CHAL_LEN 16
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define MSCHAPV2_KEY_LEN 16
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct eap_mschapv2_data {
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int auth_response_valid;
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int prev_error;
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int passwd_change_challenge_valid;
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int passwd_change_version;
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Optional challenge values generated in EAP-FAST Phase 1 negotiation
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *peer_challenge;
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *auth_challenge;
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int phase2;
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int master_key_valid;
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int success;
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *prev_challenge;
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_mschapv2_deinit(struct eap_sm *sm, void *priv);
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void * eap_mschapv2_init(struct eap_sm *sm)
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_mschapv2_data *data;
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data = os_zalloc(sizeof(*data));
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sm->peer_challenge) {
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->peer_challenge == NULL) {
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			eap_mschapv2_deinit(sm, data);
120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data->peer_challenge, sm->peer_challenge,
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  MSCHAPV2_CHAL_LEN);
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sm->auth_challenge) {
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->auth_challenge == NULL) {
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			eap_mschapv2_deinit(sm, data);
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data->auth_challenge, sm->auth_challenge,
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  MSCHAPV2_CHAL_LEN);
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->phase2 = sm->init_phase2;
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data;
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_mschapv2_data *data = priv;
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->peer_challenge);
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->auth_challenge);
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->prev_challenge);
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data);
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_mschapv2_challenge_reply(
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id,
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 mschapv2_id, const u8 *auth_challenge)
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *resp;
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_mschapv2_hdr *ms;
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *peer_challenge;
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ms_len;
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ms_response *r;
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t identity_len, password_len;
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *identity, *password;
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int pwhash;
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	identity = eap_get_config_identity(sm, &identity_len);
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	password = eap_get_config_password2(sm, &password_len, &pwhash);
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (identity == NULL || password == NULL)
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len;
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     EAP_CODE_RESPONSE, id);
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (resp == NULL)
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms = wpabuf_put(resp, sizeof(*ms));
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms->op_code = MSCHAPV2_OP_RESPONSE;
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms->mschapv2_id = mschapv2_id;
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->prev_error) {
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/*
183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * TODO: this does not seem to be enough when processing two
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * or more failure messages. IAS did not increment mschapv2_id
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * in its own packets, but it seemed to expect the peer to
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * increment this for all packets(?).
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 */
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ms->mschapv2_id++;
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(ms->ms_length, ms_len);
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(resp, sizeof(*r)); /* Value-Size */
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Response */
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	r = wpabuf_put(resp, sizeof(*r));
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	peer_challenge = r->peer_challenge;
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->peer_challenge) {
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "in Phase 1");
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		peer_challenge = data->peer_challenge;
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (os_get_random(peer_challenge, MSCHAPV2_CHAL_LEN)) {
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(resp);
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(r->reserved, 0, 8);
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->auth_challenge) {
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "in Phase 1");
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		auth_challenge = data->auth_challenge;
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	mschapv2_derive_response(identity, identity_len, password,
213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 password_len, pwhash, auth_challenge,
214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 peer_challenge, r->nt_response,
215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 data->auth_response, data->master_key);
216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->auth_response_valid = 1;
217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->master_key_valid = 1;
218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	r->flags = 0; /* reserved, must be zero */
220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_data(resp, identity, identity_len);
222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "(response)", id, ms->mschapv2_id);
224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return resp;
225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message
230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @data: Pointer to private EAP method data from eap_mschapv2_init()
232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ret: Return values from EAP request validation and processing
233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @req: Pointer to EAP-MSCHAPv2 header from the request
234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @req_len: Length of the EAP-MSCHAPv2 data
235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @id: EAP identifier used in the request
236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * no reply available
238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_mschapv2_challenge(
240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sm *sm, struct eap_mschapv2_data *data,
241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t req_len, u8 id)
243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len, challenge_len;
245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos, *challenge;
246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_get_config_identity(sm, &len) == NULL ||
248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    eap_get_config_password(sm, &len) == NULL)
249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (req_len < sizeof(*req) + 1) {
253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "(len %lu)", (unsigned long) req_len);
255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = (const u8 *) (req + 1);
259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	challenge_len = *pos++;
260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len = req_len - sizeof(*req) - 1;
261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (challenge_len != MSCHAPV2_CHAL_LEN) {
262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "%lu", (unsigned long) challenge_len);
264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (len < challenge_len) {
269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   " packet: len=%lu challenge_len=%lu",
271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) len, (unsigned long) challenge_len);
272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->passwd_change_challenge_valid) {
277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "failure message");
279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		challenge = data->passwd_change_challenge;
280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else
281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		challenge = pos;
282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += challenge_len;
283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len -= challenge_len;
284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    pos, len);
286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->ignore = FALSE;
288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->decision = DECISION_FAIL;
290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->allowNotifications = TRUE;
291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    challenge);
294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_mschapv2_password_changed(struct eap_sm *sm,
298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  struct eap_mschapv2_data *data)
299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_peer_config *config = eap_get_config(sm);
301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (config && config->new_password) {
302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_msg(sm->msg_ctx, MSG_INFO,
303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			WPA_EVENT_PASSWORD_CHANGED
304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			"EAP-MSCHAPV2: Password changed successfully");
305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->prev_error = 0;
306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(config->password);
307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			config->password = os_malloc(16);
309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			config->password_len = 16;
310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (config->password) {
311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				nt_password_hash(config->new_password,
312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 config->new_password_len,
313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 config->password);
314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_free(config->new_password);
316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else {
317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			config->password = config->new_password;
318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			config->password_len = config->new_password_len;
319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		config->new_password = NULL;
321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		config->new_password_len = 0;
322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * eap_mschapv2_process - Process an EAP-MSCHAPv2 success message
328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @data: Pointer to private EAP method data from eap_mschapv2_init()
330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ret: Return values from EAP request validation and processing
331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @req: Pointer to EAP-MSCHAPv2 header from the request
332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @req_len: Length of the EAP-MSCHAPv2 data
333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @id: EAP identifier used in th erequest
334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * no reply available
336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_mschapv2_success(struct eap_sm *sm,
338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    struct eap_mschapv2_data *data,
339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    struct eap_method_ret *ret,
340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    const struct eap_mschapv2_hdr *req,
341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    size_t req_len, u8 id)
342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *resp;
344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos;
345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len;
346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len = req_len - sizeof(*req);
349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = (const u8 *) (req + 1);
350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (!data->auth_response_valid ||
351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    mschapv2_verify_auth_response(data->auth_response, pos, len)) {
352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "response in success request");
354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->methodState = METHOD_DONE;
355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->decision = DECISION_FAIL;
356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len -= 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (len > 0 && *pos == ' ') {
361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos++;
362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		len--;
363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  pos, len);
366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Note: Only op_code of the EAP-MSCHAPV2 header is included in success
369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * message. */
370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     EAP_CODE_RESPONSE, id);
372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (resp == NULL) {
373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "buffer for success response");
375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS); /* op_code */
380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->methodState = METHOD_DONE;
382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->decision = DECISION_UNCOND_SUCC;
383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->allowNotifications = FALSE;
384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->success = 1;
385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->prev_error == ERROR_PASSWD_EXPIRED)
387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_mschapv2_password_changed(sm, data);
388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return resp;
390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_mschapv2_failure_txt(struct eap_sm *sm,
394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    struct eap_mschapv2_data *data, char *txt)
395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char *pos, *msg = "";
397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int retry = 1;
398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_peer_config *config = eap_get_config(sm);
399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* For example:
401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure
402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = txt;
405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos && os_strncmp(pos, "E=", 2) == 0) {
407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->prev_error = atoi(pos);
409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   data->prev_error);
411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos = os_strchr(pos, ' ');
412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (pos)
413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos++;
414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos && os_strncmp(pos, "R=", 2) == 0) {
417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		retry = atoi(pos);
419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   retry == 1 ? "" : "not ");
421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos = os_strchr(pos, ' ');
422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (pos)
423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos++;
424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos && os_strncmp(pos, "C=", 2) == 0) {
427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		int hex_len;
428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		hex_len = os_strchr(pos, ' ') - (char *) pos;
430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (hexstr2bin(pos, data->passwd_change_challenge,
432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				       PASSWD_CHANGE_CHAL_LEN)) {
433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid "
434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   "failure challenge");
435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			} else {
436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure "
437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    "challenge",
438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    data->passwd_change_challenge,
439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    PASSWD_CHANGE_CHAL_LEN);
440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				data->passwd_change_challenge_valid = 1;
441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else {
443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "challenge len %d", hex_len);
445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos = os_strchr(pos, ' ');
447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (pos)
448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos++;
449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field "
451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "was not present in failure message");
452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos && os_strncmp(pos, "V=", 2) == 0) {
455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->passwd_change_version = atoi(pos);
457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "protocol version %d", data->passwd_change_version);
459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos = os_strchr(pos, ' ');
460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (pos)
461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos++;
462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos && os_strncmp(pos, "M=", 2) == 0) {
465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		msg = pos;
467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_msg(sm->msg_ctx, MSG_WARNING,
469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		"EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		"%d)",
471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		msg, retry == 1 ? "" : "not ", data->prev_error);
472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    data->passwd_change_version == 3 && config) {
474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (config->new_password == NULL) {
475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_msg(sm->msg_ctx, MSG_INFO,
476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				"EAP-MSCHAPV2: Password expired - password "
477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				"change required");
478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			eap_sm_request_new_password(sm);
479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (retry == 1 && config) {
481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* TODO: could prevent the current password from being used
482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * again at least for some period of time */
483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!config->mschapv2_retry)
484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			eap_sm_request_identity(sm);
485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sm_request_password(sm);
486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		config->mschapv2_retry = 1;
487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (config) {
488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* TODO: prevent retries using same username/password */
489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		config->mschapv2_retry = 0;
490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return retry == 1;
493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_mschapv2_change_password(
497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_sm *sm, struct eap_mschapv2_data *data,
498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id)
499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *resp;
501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ms_len;
502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *username, *password, *new_password;
503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t username_len, password_len, new_password_len;
504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_mschapv2_hdr *ms;
505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ms_change_password *cp;
506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 password_hash[16], password_hash_hash[16];
507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int pwhash;
508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	username = eap_get_config_identity(sm, &username_len);
510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	password = eap_get_config_password2(sm, &password_len, &pwhash);
511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	new_password = eap_get_config_new_password(sm, &new_password_len);
512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (username == NULL || password == NULL || new_password == NULL)
513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	username = mschapv2_remove_domain(username, &username_len);
516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->ignore = FALSE;
518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->methodState = METHOD_MAY_CONT;
519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->decision = DECISION_COND_SUCC;
520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->allowNotifications = TRUE;
521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms_len = sizeof(*ms) + sizeof(*cp);
523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     EAP_CODE_RESPONSE, id);
525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (resp == NULL)
526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms = wpabuf_put(resp, sizeof(*ms));
529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms->mschapv2_id = req->mschapv2_id + 1;
531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(ms->ms_length, ms_len);
532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	cp = wpabuf_put(resp, sizeof(*cp));
533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Encrypted-Password */
535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pwhash) {
536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (encrypt_pw_block_with_password_hash(
537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    new_password, new_password_len,
538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    password, cp->encr_password))
539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			goto fail;
540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (new_password_encrypted_with_old_nt_password_hash(
542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    new_password, new_password_len,
543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    password, password_len, cp->encr_password))
544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			goto fail;
545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Encrypted-Hash */
548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pwhash) {
549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		u8 new_password_hash[16];
550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		nt_password_hash(new_password, new_password_len,
551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 new_password_hash);
552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		nt_password_hash_encrypted_with_block(password,
553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						      new_password_hash,
554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						      cp->encr_hash);
555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		old_nt_password_hash_encrypted_with_new_nt_password_hash(
557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			new_password, new_password_len,
558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			password, password_len, cp->encr_hash);
559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Peer-Challenge */
562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_get_random(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto fail;
564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Reserved, must be zero */
566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(cp->reserved, 0, 8);
567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* NT-Response */
569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN);
571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    cp->peer_challenge, MSCHAPV2_CHAL_LEN);
573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  username, username_len);
575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password",
576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      new_password, new_password_len);
577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     username, username_len,
579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     new_password, new_password_len,
580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     cp->nt_response);
581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response",
582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN);
583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Authenticator response is not really needed yet, but calculate it
585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * here so that challenges need not be saved. */
586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	generate_authenticator_response(new_password, new_password_len,
587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					cp->peer_challenge,
588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					data->passwd_change_challenge,
589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					username, username_len,
590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					cp->nt_response, data->auth_response);
591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->auth_response_valid = 1;
592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Likewise, generate master_key here since we have the needed data
594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * available. */
595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	nt_password_hash(new_password, new_password_len, password_hash);
596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hash_nt_password_hash(password_hash, password_hash_hash);
597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	get_master_key(password_hash_hash, cp->nt_response, data->master_key);
598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->master_key_valid = 1;
599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Flags */
601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(cp->flags, 0, 2);
602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "(change pw)", id, ms->mschapv2_id);
605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
606526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return resp;
607526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
608526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtfail:
609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(resp);
610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return NULL;
611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message
616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @data: Pointer to private EAP method data from eap_mschapv2_init()
618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ret: Return values from EAP request validation and processing
619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @req: Pointer to EAP-MSCHAPv2 header from the request
620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @req_len: Length of the EAP-MSCHAPv2 data
621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @id: EAP identifier used in th erequest
622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * no reply available
624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    struct eap_mschapv2_data *data,
627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    struct eap_method_ret *ret,
628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    const struct eap_mschapv2_hdr *req,
629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    size_t req_len, u8 id)
630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *resp;
632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *msdata = (const u8 *) (req + 1);
633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	char *buf;
634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len = req_len - sizeof(*req);
635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int retry = 0;
636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  msdata, len);
640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * eap_mschapv2_failure_txt() expects a nul terminated string, so we
642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * must allocate a large enough temporary buffer to create that since
643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * the received message does not include nul termination.
644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = os_malloc(len + 1);
646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf) {
647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(buf, msdata, len);
648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		buf[len] = '\0';
649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		retry = eap_mschapv2_failure_txt(sm, data, buf);
650526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(buf);
651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->ignore = FALSE;
654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->methodState = METHOD_DONE;
655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->decision = DECISION_FAIL;
656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret->allowNotifications = FALSE;
657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    data->passwd_change_version == 3) {
660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		struct eap_peer_config *config = eap_get_config(sm);
661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (config && config->new_password)
662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return eap_mschapv2_change_password(sm, data, ret, req,
663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt							    id);
664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (config && config->pending_req_new_password)
665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* TODO: could try to retry authentication, e.g, after having
668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * changed the username/password. In this case, EAP MS-CHAP-v2
669526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * Failure Response would not be sent here. */
670526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
671526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
672526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
673526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure
674526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * message. */
675526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     EAP_CODE_RESPONSE, id);
677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (resp == NULL)
678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE); /* op_code */
681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return resp;
683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_mschapv2_check_config(struct eap_sm *sm)
687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len;
689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
690526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_get_config_identity(sm, &len) == NULL) {
691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sm_request_identity(sm);
693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_get_config_password(sm, &len) == NULL) {
697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
698526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_sm_request_password(sm);
699526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
701526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
707526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    const struct eap_mschapv2_hdr *ms)
708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t ms_len = WPA_GET_BE16(ms->ms_length);
710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ms_len == len)
712526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return 0;
713526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len);
716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sm->workaround) {
717526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Some authentication servers use invalid ms_len,
718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * ignore it for interoperability. */
719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   " invalid ms_len %lu (len %lu)",
721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) ms_len,
722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) len);
723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return 0;
724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
725526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
726526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return -1;
727526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
728526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
729526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
730526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
731526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					const struct wpabuf *reqData)
732526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
733526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
734526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * Store a copy of the challenge message, so that it can be processed
735526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * again in case retry is allowed after a possible failure.
736526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
737526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->prev_challenge);
738526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->prev_challenge = wpabuf_dup(reqData);
739526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
740526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
741526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
742526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
743526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * eap_mschapv2_process - Process an EAP-MSCHAPv2 request
744526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
745526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @priv: Pointer to private EAP method data from eap_mschapv2_init()
746526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ret: Return values from EAP request validation and processing
747526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @reqData: EAP request to be processed (eapReqData)
748526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
749526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * no reply available
750526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
751526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
752526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    struct eap_method_ret *ret,
753526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					    const struct wpabuf *reqData)
754526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
755526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_mschapv2_data *data = priv;
756526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_peer_config *config = eap_get_config(sm);
757526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct eap_mschapv2_hdr *ms;
758526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int using_prev_challenge = 0;
759526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos;
760526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len;
761526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 id;
762526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
763526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_mschapv2_check_config(sm)) {
764526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
765526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
766526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
767526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
768526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (config->mschapv2_retry && data->prev_challenge &&
769526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
770526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
771526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "with the previous challenge");
772526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
773526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		reqData = data->prev_challenge;
774526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		using_prev_challenge = 1;
775526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		config->mschapv2_retry = 0;
776526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
777526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
778526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData,
779526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       &len);
780526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos == NULL || len < sizeof(*ms) + 1) {
781526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
782526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
783526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
784526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
785526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ms = (const struct eap_mschapv2_hdr *) pos;
786526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_mschapv2_check_mslen(sm, len, ms)) {
787526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
788526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
789526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
790526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
791526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	id = eap_get_id(reqData);
792526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
793526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   id, ms->mschapv2_id);
794526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
795526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (ms->op_code) {
796526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case MSCHAPV2_OP_CHALLENGE:
797526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!using_prev_challenge)
798526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			eap_mschapv2_copy_challenge(data, reqData);
799526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_mschapv2_challenge(sm, data, ret, ms, len, id);
800526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case MSCHAPV2_OP_SUCCESS:
801526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_mschapv2_success(sm, data, ret, ms, len, id);
802526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case MSCHAPV2_OP_FAILURE:
803526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_mschapv2_failure(sm, data, ret, ms, len, id);
804526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
805526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
806526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   ms->op_code);
807526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ret->ignore = TRUE;
808526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
809526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
810526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
811526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
812526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
813526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
814526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
815526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_mschapv2_data *data = priv;
816526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data->success && data->master_key_valid;
817526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
818526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
819526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
820526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
821526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
822526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_mschapv2_data *data = priv;
823526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *key;
824526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int key_len;
825526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
826526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (!data->master_key_valid || !data->success)
827526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
828526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
829526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	key_len = 2 * MSCHAPV2_KEY_LEN;
830526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
831526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	key = os_malloc(key_len);
832526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (key == NULL)
833526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
834526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
835526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
836526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 *	peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
837526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
838526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
839526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				MSCHAPV2_KEY_LEN, 0, 0);
840526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
841526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
842526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			key, key_len);
843526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
844526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*len = key_len;
845526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return key;
846526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
847526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
848526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
849526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
850526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method
851526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, -1 on failure
852526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
853526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This function is used to register EAP-MSCHAPv2 peer method into the EAP
854526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * method list.
855526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
856526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint eap_peer_mschapv2_register(void)
857526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
858526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_method *eap;
859526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret;
860526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
861526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
862526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
863526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    "MSCHAPV2");
864526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap == NULL)
865526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
866526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
867526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->init = eap_mschapv2_init;
868526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->deinit = eap_mschapv2_deinit;
869526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->process = eap_mschapv2_process;
870526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->isKeyAvailable = eap_mschapv2_isKeyAvailable;
871526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->getKey = eap_mschapv2_getKey;
872526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
873526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = eap_peer_method_register(eap);
874526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret)
875526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_peer_method_free(eap);
876526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
877526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
878