eap_leap.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. * EAP peer method: LEAP
  3. * Copyright (c) 2004-2007, 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. #include "includes.h"
  15. #include "common.h"
  16. #include "eap_i.h"
  17. #include "ms_funcs.h"
  18. #include "crypto.h"
  19. #define LEAP_VERSION 1
  20. #define LEAP_CHALLENGE_LEN 8
  21. #define LEAP_RESPONSE_LEN 24
  22. #define LEAP_KEY_LEN 16
  23. struct eap_leap_data {
  24. enum {
  25. LEAP_WAIT_CHALLENGE,
  26. LEAP_WAIT_SUCCESS,
  27. LEAP_WAIT_RESPONSE,
  28. LEAP_DONE
  29. } state;
  30. u8 peer_challenge[LEAP_CHALLENGE_LEN];
  31. u8 peer_response[LEAP_RESPONSE_LEN];
  32. u8 ap_challenge[LEAP_CHALLENGE_LEN];
  33. u8 ap_response[LEAP_RESPONSE_LEN];
  34. };
  35. static void * eap_leap_init(struct eap_sm *sm)
  36. {
  37. struct eap_leap_data *data;
  38. data = os_zalloc(sizeof(*data));
  39. if (data == NULL)
  40. return NULL;
  41. data->state = LEAP_WAIT_CHALLENGE;
  42. sm->leap_done = FALSE;
  43. return data;
  44. }
  45. static void eap_leap_deinit(struct eap_sm *sm, void *priv)
  46. {
  47. os_free(priv);
  48. }
  49. static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
  50. struct eap_method_ret *ret,
  51. const struct wpabuf *reqData)
  52. {
  53. struct eap_leap_data *data = priv;
  54. struct wpabuf *resp;
  55. const u8 *pos, *challenge, *identity, *password;
  56. u8 challenge_len, *rpos;
  57. size_t identity_len, password_len, len;
  58. int pwhash;
  59. wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
  60. identity = eap_get_config_identity(sm, &identity_len);
  61. password = eap_get_config_password2(sm, &password_len, &pwhash);
  62. if (identity == NULL || password == NULL)
  63. return NULL;
  64. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
  65. if (pos == NULL || len < 3) {
  66. wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
  67. ret->ignore = TRUE;
  68. return NULL;
  69. }
  70. if (*pos != LEAP_VERSION) {
  71. wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
  72. "%d", *pos);
  73. ret->ignore = TRUE;
  74. return NULL;
  75. }
  76. pos++;
  77. pos++; /* skip unused byte */
  78. challenge_len = *pos++;
  79. if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) {
  80. wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
  81. "(challenge_len=%d reqDataLen=%lu)",
  82. challenge_len, (unsigned long) wpabuf_len(reqData));
  83. ret->ignore = TRUE;
  84. return NULL;
  85. }
  86. challenge = pos;
  87. os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
  88. wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
  89. challenge, LEAP_CHALLENGE_LEN);
  90. wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
  91. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
  92. 3 + LEAP_RESPONSE_LEN + identity_len,
  93. EAP_CODE_RESPONSE, eap_get_id(reqData));
  94. if (resp == NULL)
  95. return NULL;
  96. wpabuf_put_u8(resp, LEAP_VERSION);
  97. wpabuf_put_u8(resp, 0); /* unused */
  98. wpabuf_put_u8(resp, LEAP_RESPONSE_LEN);
  99. rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN);
  100. if (pwhash)
  101. challenge_response(challenge, password, rpos);
  102. else
  103. nt_challenge_response(challenge, password, password_len, rpos);
  104. os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
  105. wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
  106. rpos, LEAP_RESPONSE_LEN);
  107. wpabuf_put_data(resp, identity, identity_len);
  108. data->state = LEAP_WAIT_SUCCESS;
  109. return resp;
  110. }
  111. static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
  112. struct eap_method_ret *ret,
  113. const struct wpabuf *reqData)
  114. {
  115. struct eap_leap_data *data = priv;
  116. struct wpabuf *resp;
  117. u8 *pos;
  118. const u8 *identity;
  119. size_t identity_len;
  120. wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
  121. identity = eap_get_config_identity(sm, &identity_len);
  122. if (identity == NULL)
  123. return NULL;
  124. if (data->state != LEAP_WAIT_SUCCESS) {
  125. wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
  126. "unexpected state (%d) - ignored", data->state);
  127. ret->ignore = TRUE;
  128. return NULL;
  129. }
  130. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
  131. 3 + LEAP_CHALLENGE_LEN + identity_len,
  132. EAP_CODE_REQUEST, eap_get_id(reqData));
  133. if (resp == NULL)
  134. return NULL;
  135. wpabuf_put_u8(resp, LEAP_VERSION);
  136. wpabuf_put_u8(resp, 0); /* unused */
  137. wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN);
  138. pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN);
  139. if (os_get_random(pos, LEAP_CHALLENGE_LEN)) {
  140. wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
  141. "for challenge");
  142. wpabuf_free(resp);
  143. ret->ignore = TRUE;
  144. return NULL;
  145. }
  146. os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
  147. wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
  148. LEAP_CHALLENGE_LEN);
  149. wpabuf_put_data(resp, identity, identity_len);
  150. data->state = LEAP_WAIT_RESPONSE;
  151. return resp;
  152. }
  153. static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
  154. struct eap_method_ret *ret,
  155. const struct wpabuf *reqData)
  156. {
  157. struct eap_leap_data *data = priv;
  158. const u8 *pos, *password;
  159. u8 response_len, pw_hash[16], pw_hash_hash[16],
  160. expected[LEAP_RESPONSE_LEN];
  161. size_t password_len, len;
  162. int pwhash;
  163. wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
  164. password = eap_get_config_password2(sm, &password_len, &pwhash);
  165. if (password == NULL)
  166. return NULL;
  167. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
  168. if (pos == NULL || len < 3) {
  169. wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
  170. ret->ignore = TRUE;
  171. return NULL;
  172. }
  173. if (*pos != LEAP_VERSION) {
  174. wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
  175. "%d", *pos);
  176. ret->ignore = TRUE;
  177. return NULL;
  178. }
  179. pos++;
  180. pos++; /* skip unused byte */
  181. response_len = *pos++;
  182. if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) {
  183. wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
  184. "(response_len=%d reqDataLen=%lu)",
  185. response_len, (unsigned long) wpabuf_len(reqData));
  186. ret->ignore = TRUE;
  187. return NULL;
  188. }
  189. wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
  190. pos, LEAP_RESPONSE_LEN);
  191. os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
  192. if (pwhash) {
  193. if (hash_nt_password_hash(password, pw_hash_hash)) {
  194. ret->ignore = TRUE;
  195. return NULL;
  196. }
  197. } else {
  198. if (nt_password_hash(password, password_len, pw_hash) ||
  199. hash_nt_password_hash(pw_hash, pw_hash_hash)) {
  200. ret->ignore = TRUE;
  201. return NULL;
  202. }
  203. }
  204. challenge_response(data->ap_challenge, pw_hash_hash, expected);
  205. ret->methodState = METHOD_DONE;
  206. ret->allowNotifications = FALSE;
  207. if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
  208. wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
  209. "response - authentication failed");
  210. wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
  211. expected, LEAP_RESPONSE_LEN);
  212. ret->decision = DECISION_FAIL;
  213. return NULL;
  214. }
  215. ret->decision = DECISION_UNCOND_SUCC;
  216. /* LEAP is somewhat odd method since it sends EAP-Success in the middle
  217. * of the authentication. Use special variable to transit EAP state
  218. * machine to SUCCESS state. */
  219. sm->leap_done = TRUE;
  220. data->state = LEAP_DONE;
  221. /* No more authentication messages expected; AP will send EAPOL-Key
  222. * frames if encryption is enabled. */
  223. return NULL;
  224. }
  225. static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
  226. struct eap_method_ret *ret,
  227. const struct wpabuf *reqData)
  228. {
  229. const struct eap_hdr *eap;
  230. size_t password_len;
  231. const u8 *password;
  232. password = eap_get_config_password(sm, &password_len);
  233. if (password == NULL) {
  234. wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
  235. eap_sm_request_password(sm);
  236. ret->ignore = TRUE;
  237. return NULL;
  238. }
  239. /*
  240. * LEAP needs to be able to handle EAP-Success frame which does not
  241. * include Type field. Consequently, eap_hdr_validate() cannot be used
  242. * here. This validation will be done separately for EAP-Request and
  243. * EAP-Response frames.
  244. */
  245. eap = wpabuf_head(reqData);
  246. if (wpabuf_len(reqData) < sizeof(*eap) ||
  247. be_to_host16(eap->length) > wpabuf_len(reqData)) {
  248. wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
  249. ret->ignore = TRUE;
  250. return NULL;
  251. }
  252. ret->ignore = FALSE;
  253. ret->allowNotifications = TRUE;
  254. ret->methodState = METHOD_MAY_CONT;
  255. ret->decision = DECISION_FAIL;
  256. sm->leap_done = FALSE;
  257. switch (eap->code) {
  258. case EAP_CODE_REQUEST:
  259. return eap_leap_process_request(sm, priv, ret, reqData);
  260. case EAP_CODE_SUCCESS:
  261. return eap_leap_process_success(sm, priv, ret, reqData);
  262. case EAP_CODE_RESPONSE:
  263. return eap_leap_process_response(sm, priv, ret, reqData);
  264. default:
  265. wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
  266. "ignored", eap->code);
  267. ret->ignore = TRUE;
  268. return NULL;
  269. }
  270. }
  271. static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
  272. {
  273. struct eap_leap_data *data = priv;
  274. return data->state == LEAP_DONE;
  275. }
  276. static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
  277. {
  278. struct eap_leap_data *data = priv;
  279. u8 *key, pw_hash_hash[16], pw_hash[16];
  280. const u8 *addr[5], *password;
  281. size_t elen[5], password_len;
  282. int pwhash;
  283. if (data->state != LEAP_DONE)
  284. return NULL;
  285. password = eap_get_config_password2(sm, &password_len, &pwhash);
  286. if (password == NULL)
  287. return NULL;
  288. key = os_malloc(LEAP_KEY_LEN);
  289. if (key == NULL)
  290. return NULL;
  291. if (pwhash) {
  292. if (hash_nt_password_hash(password, pw_hash_hash)) {
  293. os_free(key);
  294. return NULL;
  295. }
  296. } else {
  297. if (nt_password_hash(password, password_len, pw_hash) ||
  298. hash_nt_password_hash(pw_hash, pw_hash_hash)) {
  299. os_free(key);
  300. return NULL;
  301. }
  302. }
  303. wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
  304. pw_hash_hash, 16);
  305. wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
  306. data->peer_challenge, LEAP_CHALLENGE_LEN);
  307. wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response",
  308. data->peer_response, LEAP_RESPONSE_LEN);
  309. wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge",
  310. data->ap_challenge, LEAP_CHALLENGE_LEN);
  311. wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
  312. data->ap_response, LEAP_RESPONSE_LEN);
  313. addr[0] = pw_hash_hash;
  314. elen[0] = 16;
  315. addr[1] = data->ap_challenge;
  316. elen[1] = LEAP_CHALLENGE_LEN;
  317. addr[2] = data->ap_response;
  318. elen[2] = LEAP_RESPONSE_LEN;
  319. addr[3] = data->peer_challenge;
  320. elen[3] = LEAP_CHALLENGE_LEN;
  321. addr[4] = data->peer_response;
  322. elen[4] = LEAP_RESPONSE_LEN;
  323. md5_vector(5, addr, elen, key);
  324. wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
  325. *len = LEAP_KEY_LEN;
  326. return key;
  327. }
  328. int eap_peer_leap_register(void)
  329. {
  330. struct eap_method *eap;
  331. int ret;
  332. eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
  333. EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
  334. if (eap == NULL)
  335. return -1;
  336. eap->init = eap_leap_init;
  337. eap->deinit = eap_leap_deinit;
  338. eap->process = eap_leap_process;
  339. eap->isKeyAvailable = eap_leap_isKeyAvailable;
  340. eap->getKey = eap_leap_getKey;
  341. ret = eap_peer_method_register(eap);
  342. if (ret)
  343. eap_peer_method_free(eap);
  344. return ret;
  345. }