eap_mschapv2.c 25 KB

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