eap_leap.c 11 KB

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