eap_mschapv2.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. /*
  2. * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
  3. * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. *
  14. * This file implements EAP peer part of EAP-MSCHAPV2 method (EAP type 26).
  15. * draft-kamath-pppext-eap-mschapv2-00.txt defines the Microsoft EAP CHAP
  16. * Extensions Protocol, Version 2, for mutual authentication and key
  17. * derivation. This encapsulates MS-CHAP-v2 protocol which is defined in
  18. * RFC 2759. Use of EAP-MSCHAPV2 derived keys with MPPE cipher is described in
  19. * RFC 3079.
  20. */
  21. #include "includes.h"
  22. #include "common.h"
  23. #include "eap_i.h"
  24. #include "eap_config.h"
  25. #include "ms_funcs.h"
  26. #include "common/wpa_ctrl.h"
  27. #include "mschapv2.h"
  28. #ifdef _MSC_VER
  29. #pragma pack(push, 1)
  30. #endif /* _MSC_VER */
  31. struct eap_mschapv2_hdr {
  32. u8 op_code; /* MSCHAPV2_OP_* */
  33. u8 mschapv2_id; /* usually same as EAP identifier; must be changed
  34. * for challenges, but not for success/failure */
  35. u8 ms_length[2]; /* Note: misaligned; length - 5 */
  36. /* followed by data */
  37. } STRUCT_PACKED;
  38. /* Response Data field */
  39. struct ms_response {
  40. u8 peer_challenge[MSCHAPV2_CHAL_LEN];
  41. u8 reserved[8];
  42. u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
  43. u8 flags;
  44. } STRUCT_PACKED;
  45. /* Change-Password Data field */
  46. struct ms_change_password {
  47. u8 encr_password[516];
  48. u8 encr_hash[16];
  49. u8 peer_challenge[MSCHAPV2_CHAL_LEN];
  50. u8 reserved[8];
  51. u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
  52. u8 flags[2];
  53. } STRUCT_PACKED;
  54. #ifdef _MSC_VER
  55. #pragma pack(pop)
  56. #endif /* _MSC_VER */
  57. #define MSCHAPV2_OP_CHALLENGE 1
  58. #define MSCHAPV2_OP_RESPONSE 2
  59. #define MSCHAPV2_OP_SUCCESS 3
  60. #define MSCHAPV2_OP_FAILURE 4
  61. #define MSCHAPV2_OP_CHANGE_PASSWORD 7
  62. #define ERROR_RESTRICTED_LOGON_HOURS 646
  63. #define ERROR_ACCT_DISABLED 647
  64. #define ERROR_PASSWD_EXPIRED 648
  65. #define ERROR_NO_DIALIN_PERMISSION 649
  66. #define ERROR_AUTHENTICATION_FAILURE 691
  67. #define ERROR_CHANGING_PASSWORD 709
  68. #define PASSWD_CHANGE_CHAL_LEN 16
  69. #define MSCHAPV2_KEY_LEN 16
  70. struct eap_mschapv2_data {
  71. u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
  72. int auth_response_valid;
  73. int prev_error;
  74. u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];
  75. int passwd_change_challenge_valid;
  76. int passwd_change_version;
  77. /* Optional challenge values generated in EAP-FAST Phase 1 negotiation
  78. */
  79. u8 *peer_challenge;
  80. u8 *auth_challenge;
  81. int phase2;
  82. u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
  83. int master_key_valid;
  84. int success;
  85. struct wpabuf *prev_challenge;
  86. };
  87. static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv);
  88. static void * eap_mschapv2_init(struct eap_sm *sm)
  89. {
  90. struct eap_mschapv2_data *data;
  91. data = os_zalloc(sizeof(*data));
  92. if (data == NULL)
  93. return NULL;
  94. if (sm->peer_challenge) {
  95. data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
  96. if (data->peer_challenge == NULL) {
  97. eap_mschapv2_deinit(sm, data);
  98. return NULL;
  99. }
  100. os_memcpy(data->peer_challenge, sm->peer_challenge,
  101. MSCHAPV2_CHAL_LEN);
  102. }
  103. if (sm->auth_challenge) {
  104. data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
  105. if (data->auth_challenge == NULL) {
  106. eap_mschapv2_deinit(sm, data);
  107. return NULL;
  108. }
  109. os_memcpy(data->auth_challenge, sm->auth_challenge,
  110. MSCHAPV2_CHAL_LEN);
  111. }
  112. data->phase2 = sm->init_phase2;
  113. return data;
  114. }
  115. static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
  116. {
  117. struct eap_mschapv2_data *data = priv;
  118. os_free(data->peer_challenge);
  119. os_free(data->auth_challenge);
  120. wpabuf_free(data->prev_challenge);
  121. os_free(data);
  122. }
  123. static struct wpabuf * eap_mschapv2_challenge_reply(
  124. struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id,
  125. u8 mschapv2_id, const u8 *auth_challenge)
  126. {
  127. struct wpabuf *resp;
  128. struct eap_mschapv2_hdr *ms;
  129. u8 *peer_challenge;
  130. int ms_len;
  131. struct ms_response *r;
  132. size_t identity_len, password_len;
  133. const u8 *identity, *password;
  134. int pwhash;
  135. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
  136. identity = eap_get_config_identity(sm, &identity_len);
  137. password = eap_get_config_password2(sm, &password_len, &pwhash);
  138. if (identity == NULL || password == NULL)
  139. return NULL;
  140. ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len;
  141. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
  142. EAP_CODE_RESPONSE, id);
  143. if (resp == NULL)
  144. return NULL;
  145. ms = wpabuf_put(resp, sizeof(*ms));
  146. ms->op_code = MSCHAPV2_OP_RESPONSE;
  147. ms->mschapv2_id = mschapv2_id;
  148. if (data->prev_error) {
  149. /*
  150. * TODO: this does not seem to be enough when processing two
  151. * or more failure messages. IAS did not increment mschapv2_id
  152. * in its own packets, but it seemed to expect the peer to
  153. * increment this for all packets(?).
  154. */
  155. ms->mschapv2_id++;
  156. }
  157. WPA_PUT_BE16(ms->ms_length, ms_len);
  158. wpabuf_put_u8(resp, sizeof(*r)); /* Value-Size */
  159. /* Response */
  160. r = wpabuf_put(resp, sizeof(*r));
  161. peer_challenge = r->peer_challenge;
  162. if (data->peer_challenge) {
  163. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
  164. "in Phase 1");
  165. peer_challenge = data->peer_challenge;
  166. os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
  167. } else if (os_get_random(peer_challenge, MSCHAPV2_CHAL_LEN)) {
  168. wpabuf_free(resp);
  169. return NULL;
  170. }
  171. os_memset(r->reserved, 0, 8);
  172. if (data->auth_challenge) {
  173. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
  174. "in Phase 1");
  175. auth_challenge = data->auth_challenge;
  176. }
  177. if (mschapv2_derive_response(identity, identity_len, password,
  178. password_len, pwhash, auth_challenge,
  179. peer_challenge, r->nt_response,
  180. data->auth_response, data->master_key)) {
  181. wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive "
  182. "response");
  183. wpabuf_free(resp);
  184. return NULL;
  185. }
  186. data->auth_response_valid = 1;
  187. data->master_key_valid = 1;
  188. r->flags = 0; /* reserved, must be zero */
  189. wpabuf_put_data(resp, identity, identity_len);
  190. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
  191. "(response)", id, ms->mschapv2_id);
  192. return resp;
  193. }
  194. /**
  195. * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message
  196. * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
  197. * @data: Pointer to private EAP method data from eap_mschapv2_init()
  198. * @ret: Return values from EAP request validation and processing
  199. * @req: Pointer to EAP-MSCHAPv2 header from the request
  200. * @req_len: Length of the EAP-MSCHAPv2 data
  201. * @id: EAP identifier used in the request
  202. * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
  203. * no reply available
  204. */
  205. static struct wpabuf * eap_mschapv2_challenge(
  206. struct eap_sm *sm, struct eap_mschapv2_data *data,
  207. struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
  208. size_t req_len, u8 id)
  209. {
  210. size_t len, challenge_len;
  211. const u8 *pos, *challenge;
  212. if (eap_get_config_identity(sm, &len) == NULL ||
  213. eap_get_config_password(sm, &len) == NULL)
  214. return NULL;
  215. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
  216. if (req_len < sizeof(*req) + 1) {
  217. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
  218. "(len %lu)", (unsigned long) req_len);
  219. ret->ignore = TRUE;
  220. return NULL;
  221. }
  222. pos = (const u8 *) (req + 1);
  223. challenge_len = *pos++;
  224. len = req_len - sizeof(*req) - 1;
  225. if (challenge_len != MSCHAPV2_CHAL_LEN) {
  226. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
  227. "%lu", (unsigned long) challenge_len);
  228. ret->ignore = TRUE;
  229. return NULL;
  230. }
  231. if (len < challenge_len) {
  232. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
  233. " packet: len=%lu challenge_len=%lu",
  234. (unsigned long) len, (unsigned long) challenge_len);
  235. ret->ignore = TRUE;
  236. return NULL;
  237. }
  238. if (data->passwd_change_challenge_valid) {
  239. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
  240. "failure message");
  241. challenge = data->passwd_change_challenge;
  242. } else
  243. challenge = pos;
  244. pos += challenge_len;
  245. len -= challenge_len;
  246. wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
  247. pos, len);
  248. ret->ignore = FALSE;
  249. ret->methodState = METHOD_MAY_CONT;
  250. ret->decision = DECISION_FAIL;
  251. ret->allowNotifications = TRUE;
  252. return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
  253. challenge);
  254. }
  255. static void eap_mschapv2_password_changed(struct eap_sm *sm,
  256. struct eap_mschapv2_data *data)
  257. {
  258. struct eap_peer_config *config = eap_get_config(sm);
  259. if (config && config->new_password) {
  260. wpa_msg(sm->msg_ctx, MSG_INFO,
  261. WPA_EVENT_PASSWORD_CHANGED
  262. "EAP-MSCHAPV2: Password changed successfully");
  263. data->prev_error = 0;
  264. os_free(config->password);
  265. if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
  266. config->password = os_malloc(16);
  267. config->password_len = 16;
  268. if (config->password) {
  269. nt_password_hash(config->new_password,
  270. config->new_password_len,
  271. config->password);
  272. }
  273. os_free(config->new_password);
  274. } else {
  275. config->password = config->new_password;
  276. config->password_len = config->new_password_len;
  277. }
  278. config->new_password = NULL;
  279. config->new_password_len = 0;
  280. }
  281. }
  282. /**
  283. * eap_mschapv2_process - Process an EAP-MSCHAPv2 success message
  284. * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
  285. * @data: Pointer to private EAP method data from eap_mschapv2_init()
  286. * @ret: Return values from EAP request validation and processing
  287. * @req: Pointer to EAP-MSCHAPv2 header from the request
  288. * @req_len: Length of the EAP-MSCHAPv2 data
  289. * @id: EAP identifier used in th erequest
  290. * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
  291. * no reply available
  292. */
  293. static struct wpabuf * eap_mschapv2_success(struct eap_sm *sm,
  294. struct eap_mschapv2_data *data,
  295. struct eap_method_ret *ret,
  296. const struct eap_mschapv2_hdr *req,
  297. size_t req_len, u8 id)
  298. {
  299. struct wpabuf *resp;
  300. const u8 *pos;
  301. size_t len;
  302. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
  303. len = req_len - sizeof(*req);
  304. pos = (const u8 *) (req + 1);
  305. if (!data->auth_response_valid ||
  306. mschapv2_verify_auth_response(data->auth_response, pos, len)) {
  307. wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
  308. "response in success request");
  309. ret->methodState = METHOD_DONE;
  310. ret->decision = DECISION_FAIL;
  311. return NULL;
  312. }
  313. pos += 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
  314. len -= 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
  315. while (len > 0 && *pos == ' ') {
  316. pos++;
  317. len--;
  318. }
  319. wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
  320. pos, len);
  321. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
  322. /* Note: Only op_code of the EAP-MSCHAPV2 header is included in success
  323. * message. */
  324. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
  325. EAP_CODE_RESPONSE, id);
  326. if (resp == NULL) {
  327. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
  328. "buffer for success response");
  329. ret->ignore = TRUE;
  330. return NULL;
  331. }
  332. wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS); /* op_code */
  333. ret->methodState = METHOD_DONE;
  334. ret->decision = DECISION_UNCOND_SUCC;
  335. ret->allowNotifications = FALSE;
  336. data->success = 1;
  337. if (data->prev_error == ERROR_PASSWD_EXPIRED)
  338. eap_mschapv2_password_changed(sm, data);
  339. return resp;
  340. }
  341. static int eap_mschapv2_failure_txt(struct eap_sm *sm,
  342. struct eap_mschapv2_data *data, char *txt)
  343. {
  344. char *pos, *msg = "";
  345. int retry = 1;
  346. struct eap_peer_config *config = eap_get_config(sm);
  347. /* For example:
  348. * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure
  349. */
  350. pos = txt;
  351. if (pos && os_strncmp(pos, "E=", 2) == 0) {
  352. pos += 2;
  353. data->prev_error = atoi(pos);
  354. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
  355. data->prev_error);
  356. pos = os_strchr(pos, ' ');
  357. if (pos)
  358. pos++;
  359. }
  360. if (pos && os_strncmp(pos, "R=", 2) == 0) {
  361. pos += 2;
  362. retry = atoi(pos);
  363. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
  364. retry == 1 ? "" : "not ");
  365. pos = os_strchr(pos, ' ');
  366. if (pos)
  367. pos++;
  368. }
  369. if (pos && os_strncmp(pos, "C=", 2) == 0) {
  370. int hex_len;
  371. pos += 2;
  372. hex_len = os_strchr(pos, ' ') - (char *) pos;
  373. if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
  374. if (hexstr2bin(pos, data->passwd_change_challenge,
  375. PASSWD_CHANGE_CHAL_LEN)) {
  376. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid "
  377. "failure challenge");
  378. } else {
  379. wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure "
  380. "challenge",
  381. data->passwd_change_challenge,
  382. PASSWD_CHANGE_CHAL_LEN);
  383. data->passwd_change_challenge_valid = 1;
  384. }
  385. } else {
  386. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
  387. "challenge len %d", hex_len);
  388. }
  389. pos = os_strchr(pos, ' ');
  390. if (pos)
  391. pos++;
  392. } else {
  393. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field "
  394. "was not present in failure message");
  395. }
  396. if (pos && os_strncmp(pos, "V=", 2) == 0) {
  397. pos += 2;
  398. data->passwd_change_version = atoi(pos);
  399. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
  400. "protocol version %d", data->passwd_change_version);
  401. pos = os_strchr(pos, ' ');
  402. if (pos)
  403. pos++;
  404. }
  405. if (pos && os_strncmp(pos, "M=", 2) == 0) {
  406. pos += 2;
  407. msg = pos;
  408. }
  409. wpa_msg(sm->msg_ctx, MSG_WARNING,
  410. "EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
  411. "%d)",
  412. msg, retry == 1 ? "" : "not ", data->prev_error);
  413. if (data->prev_error == ERROR_PASSWD_EXPIRED &&
  414. data->passwd_change_version == 3 && config) {
  415. if (config->new_password == NULL) {
  416. wpa_msg(sm->msg_ctx, MSG_INFO,
  417. "EAP-MSCHAPV2: Password expired - password "
  418. "change required");
  419. eap_sm_request_new_password(sm);
  420. }
  421. } else if (retry == 1 && config) {
  422. /* TODO: could prevent the current password from being used
  423. * again at least for some period of time */
  424. if (!config->mschapv2_retry)
  425. eap_sm_request_identity(sm);
  426. eap_sm_request_password(sm);
  427. config->mschapv2_retry = 1;
  428. } else if (config) {
  429. /* TODO: prevent retries using same username/password */
  430. config->mschapv2_retry = 0;
  431. }
  432. return retry == 1;
  433. }
  434. static struct wpabuf * eap_mschapv2_change_password(
  435. struct eap_sm *sm, struct eap_mschapv2_data *data,
  436. struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id)
  437. {
  438. struct wpabuf *resp;
  439. int ms_len;
  440. const u8 *username, *password, *new_password;
  441. size_t username_len, password_len, new_password_len;
  442. struct eap_mschapv2_hdr *ms;
  443. struct ms_change_password *cp;
  444. u8 password_hash[16], password_hash_hash[16];
  445. int pwhash;
  446. username = eap_get_config_identity(sm, &username_len);
  447. password = eap_get_config_password2(sm, &password_len, &pwhash);
  448. new_password = eap_get_config_new_password(sm, &new_password_len);
  449. if (username == NULL || password == NULL || new_password == NULL)
  450. return NULL;
  451. username = mschapv2_remove_domain(username, &username_len);
  452. ret->ignore = FALSE;
  453. ret->methodState = METHOD_MAY_CONT;
  454. ret->decision = DECISION_COND_SUCC;
  455. ret->allowNotifications = TRUE;
  456. ms_len = sizeof(*ms) + sizeof(*cp);
  457. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
  458. EAP_CODE_RESPONSE, id);
  459. if (resp == NULL)
  460. return NULL;
  461. ms = wpabuf_put(resp, sizeof(*ms));
  462. ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
  463. ms->mschapv2_id = req->mschapv2_id + 1;
  464. WPA_PUT_BE16(ms->ms_length, ms_len);
  465. cp = wpabuf_put(resp, sizeof(*cp));
  466. /* Encrypted-Password */
  467. if (pwhash) {
  468. if (encrypt_pw_block_with_password_hash(
  469. new_password, new_password_len,
  470. password, cp->encr_password))
  471. goto fail;
  472. } else {
  473. if (new_password_encrypted_with_old_nt_password_hash(
  474. new_password, new_password_len,
  475. password, password_len, cp->encr_password))
  476. goto fail;
  477. }
  478. /* Encrypted-Hash */
  479. if (pwhash) {
  480. u8 new_password_hash[16];
  481. nt_password_hash(new_password, new_password_len,
  482. new_password_hash);
  483. nt_password_hash_encrypted_with_block(password,
  484. new_password_hash,
  485. cp->encr_hash);
  486. } else {
  487. old_nt_password_hash_encrypted_with_new_nt_password_hash(
  488. new_password, new_password_len,
  489. password, password_len, cp->encr_hash);
  490. }
  491. /* Peer-Challenge */
  492. if (os_get_random(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
  493. goto fail;
  494. /* Reserved, must be zero */
  495. os_memset(cp->reserved, 0, 8);
  496. /* NT-Response */
  497. wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
  498. data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN);
  499. wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
  500. cp->peer_challenge, MSCHAPV2_CHAL_LEN);
  501. wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
  502. username, username_len);
  503. wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password",
  504. new_password, new_password_len);
  505. generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
  506. username, username_len,
  507. new_password, new_password_len,
  508. cp->nt_response);
  509. wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response",
  510. cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN);
  511. /* Authenticator response is not really needed yet, but calculate it
  512. * here so that challenges need not be saved. */
  513. generate_authenticator_response(new_password, new_password_len,
  514. cp->peer_challenge,
  515. data->passwd_change_challenge,
  516. username, username_len,
  517. cp->nt_response, data->auth_response);
  518. data->auth_response_valid = 1;
  519. /* Likewise, generate master_key here since we have the needed data
  520. * available. */
  521. nt_password_hash(new_password, new_password_len, password_hash);
  522. hash_nt_password_hash(password_hash, password_hash_hash);
  523. get_master_key(password_hash_hash, cp->nt_response, data->master_key);
  524. data->master_key_valid = 1;
  525. /* Flags */
  526. os_memset(cp->flags, 0, 2);
  527. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
  528. "(change pw)", id, ms->mschapv2_id);
  529. return resp;
  530. fail:
  531. wpabuf_free(resp);
  532. return NULL;
  533. }
  534. /**
  535. * eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message
  536. * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
  537. * @data: Pointer to private EAP method data from eap_mschapv2_init()
  538. * @ret: Return values from EAP request validation and processing
  539. * @req: Pointer to EAP-MSCHAPv2 header from the request
  540. * @req_len: Length of the EAP-MSCHAPv2 data
  541. * @id: EAP identifier used in th erequest
  542. * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
  543. * no reply available
  544. */
  545. static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
  546. struct eap_mschapv2_data *data,
  547. struct eap_method_ret *ret,
  548. const struct eap_mschapv2_hdr *req,
  549. size_t req_len, u8 id)
  550. {
  551. struct wpabuf *resp;
  552. const u8 *msdata = (const u8 *) (req + 1);
  553. char *buf;
  554. size_t len = req_len - sizeof(*req);
  555. int retry = 0;
  556. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
  557. wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
  558. msdata, len);
  559. /*
  560. * eap_mschapv2_failure_txt() expects a nul terminated string, so we
  561. * must allocate a large enough temporary buffer to create that since
  562. * the received message does not include nul termination.
  563. */
  564. buf = os_malloc(len + 1);
  565. if (buf) {
  566. os_memcpy(buf, msdata, len);
  567. buf[len] = '\0';
  568. retry = eap_mschapv2_failure_txt(sm, data, buf);
  569. os_free(buf);
  570. }
  571. ret->ignore = FALSE;
  572. ret->methodState = METHOD_DONE;
  573. ret->decision = DECISION_FAIL;
  574. ret->allowNotifications = FALSE;
  575. if (data->prev_error == ERROR_PASSWD_EXPIRED &&
  576. data->passwd_change_version == 3) {
  577. struct eap_peer_config *config = eap_get_config(sm);
  578. if (config && config->new_password)
  579. return eap_mschapv2_change_password(sm, data, ret, req,
  580. id);
  581. if (config && config->pending_req_new_password)
  582. return NULL;
  583. } else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
  584. /* TODO: could try to retry authentication, e.g, after having
  585. * changed the username/password. In this case, EAP MS-CHAP-v2
  586. * Failure Response would not be sent here. */
  587. return NULL;
  588. }
  589. /* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure
  590. * message. */
  591. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
  592. EAP_CODE_RESPONSE, id);
  593. if (resp == NULL)
  594. return NULL;
  595. wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE); /* op_code */
  596. return resp;
  597. }
  598. static int eap_mschapv2_check_config(struct eap_sm *sm)
  599. {
  600. size_t len;
  601. if (eap_get_config_identity(sm, &len) == NULL) {
  602. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
  603. eap_sm_request_identity(sm);
  604. return -1;
  605. }
  606. if (eap_get_config_password(sm, &len) == NULL) {
  607. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
  608. eap_sm_request_password(sm);
  609. return -1;
  610. }
  611. return 0;
  612. }
  613. static int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
  614. const struct eap_mschapv2_hdr *ms)
  615. {
  616. size_t ms_len = WPA_GET_BE16(ms->ms_length);
  617. if (ms_len == len)
  618. return 0;
  619. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
  620. "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len);
  621. if (sm->workaround) {
  622. /* Some authentication servers use invalid ms_len,
  623. * ignore it for interoperability. */
  624. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
  625. " invalid ms_len %lu (len %lu)",
  626. (unsigned long) ms_len,
  627. (unsigned long) len);
  628. return 0;
  629. }
  630. return -1;
  631. }
  632. static void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
  633. const struct wpabuf *reqData)
  634. {
  635. /*
  636. * Store a copy of the challenge message, so that it can be processed
  637. * again in case retry is allowed after a possible failure.
  638. */
  639. wpabuf_free(data->prev_challenge);
  640. data->prev_challenge = wpabuf_dup(reqData);
  641. }
  642. /**
  643. * eap_mschapv2_process - Process an EAP-MSCHAPv2 request
  644. * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
  645. * @priv: Pointer to private EAP method data from eap_mschapv2_init()
  646. * @ret: Return values from EAP request validation and processing
  647. * @reqData: EAP request to be processed (eapReqData)
  648. * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
  649. * no reply available
  650. */
  651. static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
  652. struct eap_method_ret *ret,
  653. const struct wpabuf *reqData)
  654. {
  655. struct eap_mschapv2_data *data = priv;
  656. struct eap_peer_config *config = eap_get_config(sm);
  657. const struct eap_mschapv2_hdr *ms;
  658. int using_prev_challenge = 0;
  659. const u8 *pos;
  660. size_t len;
  661. u8 id;
  662. if (eap_mschapv2_check_config(sm)) {
  663. ret->ignore = TRUE;
  664. return NULL;
  665. }
  666. if (config->mschapv2_retry && data->prev_challenge &&
  667. data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
  668. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
  669. "with the previous challenge");
  670. reqData = data->prev_challenge;
  671. using_prev_challenge = 1;
  672. config->mschapv2_retry = 0;
  673. }
  674. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData,
  675. &len);
  676. if (pos == NULL || len < sizeof(*ms) + 1) {
  677. ret->ignore = TRUE;
  678. return NULL;
  679. }
  680. ms = (const struct eap_mschapv2_hdr *) pos;
  681. if (eap_mschapv2_check_mslen(sm, len, ms)) {
  682. ret->ignore = TRUE;
  683. return NULL;
  684. }
  685. id = eap_get_id(reqData);
  686. wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
  687. id, ms->mschapv2_id);
  688. switch (ms->op_code) {
  689. case MSCHAPV2_OP_CHALLENGE:
  690. if (!using_prev_challenge)
  691. eap_mschapv2_copy_challenge(data, reqData);
  692. return eap_mschapv2_challenge(sm, data, ret, ms, len, id);
  693. case MSCHAPV2_OP_SUCCESS:
  694. return eap_mschapv2_success(sm, data, ret, ms, len, id);
  695. case MSCHAPV2_OP_FAILURE:
  696. return eap_mschapv2_failure(sm, data, ret, ms, len, id);
  697. default:
  698. wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
  699. ms->op_code);
  700. ret->ignore = TRUE;
  701. return NULL;
  702. }
  703. }
  704. static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
  705. {
  706. struct eap_mschapv2_data *data = priv;
  707. return data->success && data->master_key_valid;
  708. }
  709. static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
  710. {
  711. struct eap_mschapv2_data *data = priv;
  712. u8 *key;
  713. int key_len;
  714. if (!data->master_key_valid || !data->success)
  715. return NULL;
  716. key_len = 2 * MSCHAPV2_KEY_LEN;
  717. key = os_malloc(key_len);
  718. if (key == NULL)
  719. return NULL;
  720. /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
  721. * peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
  722. get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
  723. get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
  724. MSCHAPV2_KEY_LEN, 0, 0);
  725. wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
  726. key, key_len);
  727. *len = key_len;
  728. return key;
  729. }
  730. /**
  731. * eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method
  732. * Returns: 0 on success, -1 on failure
  733. *
  734. * This function is used to register EAP-MSCHAPv2 peer method into the EAP
  735. * method list.
  736. */
  737. int eap_peer_mschapv2_register(void)
  738. {
  739. struct eap_method *eap;
  740. int ret;
  741. eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
  742. EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
  743. "MSCHAPV2");
  744. if (eap == NULL)
  745. return -1;
  746. eap->init = eap_mschapv2_init;
  747. eap->deinit = eap_mschapv2_deinit;
  748. eap->process = eap_mschapv2_process;
  749. eap->isKeyAvailable = eap_mschapv2_isKeyAvailable;
  750. eap->getKey = eap_mschapv2_getKey;
  751. ret = eap_peer_method_register(eap);
  752. if (ret)
  753. eap_peer_method_free(eap);
  754. return ret;
  755. }