eap_leap.c 11 KB

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