eap_pwd.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. /*
  2. * EAP peer method: EAP-pwd (RFC 5931)
  3. * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
  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/sha256.h"
  11. #include "crypto/ms_funcs.h"
  12. #include "crypto/crypto.h"
  13. #include "eap_peer/eap_i.h"
  14. #include "eap_common/eap_pwd_common.h"
  15. struct eap_pwd_data {
  16. enum {
  17. PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req,
  18. SUCCESS_ON_FRAG_COMPLETION, SUCCESS, FAILURE
  19. } state;
  20. u8 *id_peer;
  21. size_t id_peer_len;
  22. u8 *id_server;
  23. size_t id_server_len;
  24. u8 *password;
  25. size_t password_len;
  26. int password_hash;
  27. u16 group_num;
  28. EAP_PWD_group *grp;
  29. struct wpabuf *inbuf;
  30. size_t in_frag_pos;
  31. struct wpabuf *outbuf;
  32. size_t out_frag_pos;
  33. size_t mtu;
  34. struct crypto_bignum *k;
  35. struct crypto_bignum *private_value;
  36. struct crypto_bignum *server_scalar;
  37. struct crypto_bignum *my_scalar;
  38. struct crypto_ec_point *my_element;
  39. struct crypto_ec_point *server_element;
  40. u8 msk[EAP_MSK_LEN];
  41. u8 emsk[EAP_EMSK_LEN];
  42. u8 session_id[1 + SHA256_MAC_LEN];
  43. };
  44. #ifndef CONFIG_NO_STDOUT_DEBUG
  45. static const char * eap_pwd_state_txt(int state)
  46. {
  47. switch (state) {
  48. case PWD_ID_Req:
  49. return "PWD-ID-Req";
  50. case PWD_Commit_Req:
  51. return "PWD-Commit-Req";
  52. case PWD_Confirm_Req:
  53. return "PWD-Confirm-Req";
  54. case SUCCESS_ON_FRAG_COMPLETION:
  55. return "SUCCESS_ON_FRAG_COMPLETION";
  56. case SUCCESS:
  57. return "SUCCESS";
  58. case FAILURE:
  59. return "FAILURE";
  60. default:
  61. return "PWD-UNK";
  62. }
  63. }
  64. #endif /* CONFIG_NO_STDOUT_DEBUG */
  65. static void eap_pwd_state(struct eap_pwd_data *data, int state)
  66. {
  67. wpa_printf(MSG_DEBUG, "EAP-PWD: %s -> %s",
  68. eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
  69. data->state = state;
  70. }
  71. static void * eap_pwd_init(struct eap_sm *sm)
  72. {
  73. struct eap_pwd_data *data;
  74. const u8 *identity, *password;
  75. size_t identity_len, password_len;
  76. int fragment_size;
  77. int pwhash;
  78. password = eap_get_config_password2(sm, &password_len, &pwhash);
  79. if (password == NULL) {
  80. wpa_printf(MSG_INFO, "EAP-PWD: No password configured!");
  81. return NULL;
  82. }
  83. identity = eap_get_config_identity(sm, &identity_len);
  84. if (identity == NULL) {
  85. wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!");
  86. return NULL;
  87. }
  88. if ((data = os_zalloc(sizeof(*data))) == NULL) {
  89. wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail");
  90. return NULL;
  91. }
  92. if ((data->id_peer = os_malloc(identity_len)) == NULL) {
  93. wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
  94. os_free(data);
  95. return NULL;
  96. }
  97. os_memcpy(data->id_peer, identity, identity_len);
  98. data->id_peer_len = identity_len;
  99. if ((data->password = os_malloc(password_len)) == NULL) {
  100. wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
  101. bin_clear_free(data->id_peer, data->id_peer_len);
  102. os_free(data);
  103. return NULL;
  104. }
  105. os_memcpy(data->password, password, password_len);
  106. data->password_len = password_len;
  107. data->password_hash = pwhash;
  108. data->out_frag_pos = data->in_frag_pos = 0;
  109. data->inbuf = data->outbuf = NULL;
  110. fragment_size = eap_get_config_fragment_size(sm);
  111. if (fragment_size <= 0)
  112. data->mtu = 1020; /* default from RFC 5931 */
  113. else
  114. data->mtu = fragment_size;
  115. data->state = PWD_ID_Req;
  116. return data;
  117. }
  118. static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
  119. {
  120. struct eap_pwd_data *data = priv;
  121. crypto_bignum_deinit(data->private_value, 1);
  122. crypto_bignum_deinit(data->server_scalar, 1);
  123. crypto_bignum_deinit(data->my_scalar, 1);
  124. crypto_bignum_deinit(data->k, 1);
  125. crypto_ec_point_deinit(data->my_element, 1);
  126. crypto_ec_point_deinit(data->server_element, 1);
  127. bin_clear_free(data->id_peer, data->id_peer_len);
  128. bin_clear_free(data->id_server, data->id_server_len);
  129. bin_clear_free(data->password, data->password_len);
  130. if (data->grp) {
  131. crypto_ec_deinit(data->grp->group);
  132. crypto_ec_point_deinit(data->grp->pwe, 1);
  133. os_free(data->grp);
  134. }
  135. wpabuf_free(data->inbuf);
  136. wpabuf_free(data->outbuf);
  137. bin_clear_free(data, sizeof(*data));
  138. }
  139. static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
  140. {
  141. struct eap_pwd_data *data = priv;
  142. u8 *key;
  143. if (data->state != SUCCESS)
  144. return NULL;
  145. key = os_memdup(data->msk, EAP_MSK_LEN);
  146. if (key == NULL)
  147. return NULL;
  148. *len = EAP_MSK_LEN;
  149. return key;
  150. }
  151. static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
  152. {
  153. struct eap_pwd_data *data = priv;
  154. u8 *id;
  155. if (data->state != SUCCESS)
  156. return NULL;
  157. id = os_memdup(data->session_id, 1 + SHA256_MAC_LEN);
  158. if (id == NULL)
  159. return NULL;
  160. *len = 1 + SHA256_MAC_LEN;
  161. return id;
  162. }
  163. static void
  164. eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
  165. struct eap_method_ret *ret,
  166. const struct wpabuf *reqData,
  167. const u8 *payload, size_t payload_len)
  168. {
  169. struct eap_pwd_id *id;
  170. const u8 *password;
  171. size_t password_len;
  172. u8 pwhashhash[16];
  173. int res;
  174. if (data->state != PWD_ID_Req) {
  175. ret->ignore = TRUE;
  176. eap_pwd_state(data, FAILURE);
  177. return;
  178. }
  179. if (payload_len < sizeof(struct eap_pwd_id)) {
  180. ret->ignore = TRUE;
  181. eap_pwd_state(data, FAILURE);
  182. return;
  183. }
  184. id = (struct eap_pwd_id *) payload;
  185. data->group_num = be_to_host16(id->group_num);
  186. wpa_printf(MSG_DEBUG,
  187. "EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u",
  188. data->group_num, id->random_function, id->prf, id->prep);
  189. if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
  190. (id->prf != EAP_PWD_DEFAULT_PRF)) {
  191. ret->ignore = TRUE;
  192. eap_pwd_state(data, FAILURE);
  193. return;
  194. }
  195. if (id->prep != EAP_PWD_PREP_NONE &&
  196. id->prep != EAP_PWD_PREP_MS) {
  197. wpa_printf(MSG_DEBUG,
  198. "EAP-PWD: Unsupported password pre-processing technique (Prep=%u)",
  199. id->prep);
  200. eap_pwd_state(data, FAILURE);
  201. return;
  202. }
  203. if (id->prep == EAP_PWD_PREP_NONE && data->password_hash) {
  204. wpa_printf(MSG_DEBUG,
  205. "EAP-PWD: Unhashed password not available");
  206. eap_pwd_state(data, FAILURE);
  207. return;
  208. }
  209. wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d",
  210. data->group_num);
  211. data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id));
  212. if (data->id_server == NULL) {
  213. wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
  214. eap_pwd_state(data, FAILURE);
  215. return;
  216. }
  217. data->id_server_len = payload_len - sizeof(struct eap_pwd_id);
  218. os_memcpy(data->id_server, id->identity, data->id_server_len);
  219. wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of",
  220. data->id_server, data->id_server_len);
  221. data->grp = os_zalloc(sizeof(EAP_PWD_group));
  222. if (data->grp == NULL) {
  223. wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
  224. "group");
  225. eap_pwd_state(data, FAILURE);
  226. return;
  227. }
  228. if (id->prep == EAP_PWD_PREP_MS) {
  229. #ifdef CONFIG_FIPS
  230. wpa_printf(MSG_ERROR,
  231. "EAP-PWD (peer): MS password hash not supported in FIPS mode");
  232. eap_pwd_state(data, FAILURE);
  233. return;
  234. #else /* CONFIG_FIPS */
  235. if (data->password_hash) {
  236. res = hash_nt_password_hash(data->password, pwhashhash);
  237. } else {
  238. u8 pwhash[16];
  239. res = nt_password_hash(data->password,
  240. data->password_len, pwhash);
  241. if (res == 0)
  242. res = hash_nt_password_hash(pwhash, pwhashhash);
  243. os_memset(pwhash, 0, sizeof(pwhash));
  244. }
  245. if (res) {
  246. eap_pwd_state(data, FAILURE);
  247. return;
  248. }
  249. password = pwhashhash;
  250. password_len = sizeof(pwhashhash);
  251. #endif /* CONFIG_FIPS */
  252. } else {
  253. password = data->password;
  254. password_len = data->password_len;
  255. }
  256. /* compute PWE */
  257. res = compute_password_element(data->grp, data->group_num,
  258. password, password_len,
  259. data->id_server, data->id_server_len,
  260. data->id_peer, data->id_peer_len,
  261. id->token);
  262. os_memset(pwhashhash, 0, sizeof(pwhashhash));
  263. if (res) {
  264. wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
  265. eap_pwd_state(data, FAILURE);
  266. return;
  267. }
  268. wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
  269. (int) crypto_ec_prime_len_bits(data->grp->group));
  270. data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
  271. data->id_peer_len);
  272. if (data->outbuf == NULL) {
  273. eap_pwd_state(data, FAILURE);
  274. return;
  275. }
  276. wpabuf_put_be16(data->outbuf, data->group_num);
  277. wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
  278. wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
  279. wpabuf_put_data(data->outbuf, id->token, sizeof(id->token));
  280. wpabuf_put_u8(data->outbuf, id->prep);
  281. wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len);
  282. eap_pwd_state(data, PWD_Commit_Req);
  283. }
  284. static void
  285. eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
  286. struct eap_method_ret *ret,
  287. const struct wpabuf *reqData,
  288. const u8 *payload, size_t payload_len)
  289. {
  290. struct crypto_ec_point *K = NULL, *point = NULL;
  291. struct crypto_bignum *mask = NULL, *cofactor = NULL;
  292. const u8 *ptr;
  293. u8 *scalar = NULL, *element = NULL;
  294. size_t prime_len, order_len;
  295. if (data->state != PWD_Commit_Req) {
  296. ret->ignore = TRUE;
  297. goto fin;
  298. }
  299. prime_len = crypto_ec_prime_len(data->grp->group);
  300. order_len = crypto_ec_order_len(data->grp->group);
  301. if (payload_len != 2 * prime_len + order_len) {
  302. wpa_printf(MSG_INFO,
  303. "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
  304. (unsigned int) payload_len,
  305. (unsigned int) (2 * prime_len + order_len));
  306. goto fin;
  307. }
  308. data->private_value = crypto_bignum_init();
  309. data->my_element = crypto_ec_point_init(data->grp->group);
  310. cofactor = crypto_bignum_init();
  311. data->my_scalar = crypto_bignum_init();
  312. mask = crypto_bignum_init();
  313. if (!data->private_value || !data->my_element || !cofactor ||
  314. !data->my_scalar || !mask) {
  315. wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
  316. goto fin;
  317. }
  318. if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) {
  319. wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
  320. "for curve");
  321. goto fin;
  322. }
  323. if (crypto_bignum_rand(data->private_value,
  324. crypto_ec_get_order(data->grp->group)) < 0 ||
  325. crypto_bignum_rand(mask,
  326. crypto_ec_get_order(data->grp->group)) < 0 ||
  327. crypto_bignum_add(data->private_value, mask,
  328. data->my_scalar) < 0 ||
  329. crypto_bignum_mod(data->my_scalar,
  330. crypto_ec_get_order(data->grp->group),
  331. data->my_scalar) < 0) {
  332. wpa_printf(MSG_INFO,
  333. "EAP-pwd (peer): unable to get randomness");
  334. goto fin;
  335. }
  336. if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
  337. data->my_element) < 0) {
  338. wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation "
  339. "fail");
  340. eap_pwd_state(data, FAILURE);
  341. goto fin;
  342. }
  343. if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
  344. wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
  345. goto fin;
  346. }
  347. /* process the request */
  348. data->k = crypto_bignum_init();
  349. K = crypto_ec_point_init(data->grp->group);
  350. point = crypto_ec_point_init(data->grp->group);
  351. if (!data->k || !K || !point) {
  352. wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
  353. "fail");
  354. goto fin;
  355. }
  356. /* element, x then y, followed by scalar */
  357. ptr = payload;
  358. data->server_element = crypto_ec_point_from_bin(data->grp->group, ptr);
  359. if (!data->server_element) {
  360. wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
  361. "fail");
  362. goto fin;
  363. }
  364. ptr += prime_len * 2;
  365. data->server_scalar = crypto_bignum_init_set(ptr, order_len);
  366. if (!data->server_scalar) {
  367. wpa_printf(MSG_INFO,
  368. "EAP-PWD (peer): setting peer scalar fail");
  369. goto fin;
  370. }
  371. /* check to ensure server's element is not in a small sub-group */
  372. if (!crypto_bignum_is_one(cofactor)) {
  373. if (crypto_ec_point_mul(data->grp->group, data->server_element,
  374. cofactor, point) < 0) {
  375. wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
  376. "server element by order!\n");
  377. goto fin;
  378. }
  379. if (crypto_ec_point_is_at_infinity(data->grp->group, point)) {
  380. wpa_printf(MSG_INFO, "EAP-PWD (peer): server element "
  381. "is at infinity!\n");
  382. goto fin;
  383. }
  384. }
  385. /* compute the shared key, k */
  386. if (crypto_ec_point_mul(data->grp->group, data->grp->pwe,
  387. data->server_scalar, K) < 0 ||
  388. crypto_ec_point_add(data->grp->group, K, data->server_element,
  389. K) < 0 ||
  390. crypto_ec_point_mul(data->grp->group, K, data->private_value,
  391. K) < 0) {
  392. wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key "
  393. "fail");
  394. goto fin;
  395. }
  396. /* ensure that the shared key isn't in a small sub-group */
  397. if (!crypto_bignum_is_one(cofactor)) {
  398. if (crypto_ec_point_mul(data->grp->group, K, cofactor, K) < 0) {
  399. wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
  400. "shared key point by order");
  401. goto fin;
  402. }
  403. }
  404. /*
  405. * This check is strictly speaking just for the case above where
  406. * co-factor > 1 but it was suggested that even though this is probably
  407. * never going to happen it is a simple and safe check "just to be
  408. * sure" so let's be safe.
  409. */
  410. if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
  411. wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at "
  412. "infinity!\n");
  413. goto fin;
  414. }
  415. if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) {
  416. wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
  417. "shared secret from point");
  418. goto fin;
  419. }
  420. /* now do the response */
  421. scalar = os_zalloc(order_len);
  422. element = os_zalloc(prime_len * 2);
  423. if (!scalar || !element) {
  424. wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail");
  425. goto fin;
  426. }
  427. /*
  428. * bignums occupy as little memory as possible so one that is
  429. * sufficiently smaller than the prime or order might need pre-pending
  430. * with zeros.
  431. */
  432. crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
  433. if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
  434. element + prime_len) != 0) {
  435. wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
  436. goto fin;
  437. }
  438. data->outbuf = wpabuf_alloc(order_len + 2 * prime_len);
  439. if (data->outbuf == NULL)
  440. goto fin;
  441. /* we send the element as (x,y) follwed by the scalar */
  442. wpabuf_put_data(data->outbuf, element, 2 * prime_len);
  443. wpabuf_put_data(data->outbuf, scalar, order_len);
  444. fin:
  445. os_free(scalar);
  446. os_free(element);
  447. crypto_bignum_deinit(mask, 1);
  448. crypto_bignum_deinit(cofactor, 1);
  449. crypto_ec_point_deinit(K, 1);
  450. crypto_ec_point_deinit(point, 1);
  451. if (data->outbuf == NULL)
  452. eap_pwd_state(data, FAILURE);
  453. else
  454. eap_pwd_state(data, PWD_Confirm_Req);
  455. }
  456. static void
  457. eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
  458. struct eap_method_ret *ret,
  459. const struct wpabuf *reqData,
  460. const u8 *payload, size_t payload_len)
  461. {
  462. struct crypto_hash *hash;
  463. u32 cs;
  464. u16 grp;
  465. u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
  466. size_t prime_len = 0, order_len = 0;
  467. if (data->state != PWD_Confirm_Req) {
  468. ret->ignore = TRUE;
  469. goto fin;
  470. }
  471. if (payload_len != SHA256_MAC_LEN) {
  472. wpa_printf(MSG_INFO,
  473. "EAP-pwd: Unexpected Confirm payload length %u (expected %u)",
  474. (unsigned int) payload_len, SHA256_MAC_LEN);
  475. goto fin;
  476. }
  477. prime_len = crypto_ec_prime_len(data->grp->group);
  478. order_len = crypto_ec_order_len(data->grp->group);
  479. /*
  480. * first build up the ciphersuite which is group | random_function |
  481. * prf
  482. */
  483. grp = htons(data->group_num);
  484. ptr = (u8 *) &cs;
  485. os_memcpy(ptr, &grp, sizeof(u16));
  486. ptr += sizeof(u16);
  487. *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
  488. ptr += sizeof(u8);
  489. *ptr = EAP_PWD_DEFAULT_PRF;
  490. /* each component of the point will be at most as big as the prime */
  491. cruft = os_malloc(prime_len * 2);
  492. if (!cruft) {
  493. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
  494. "fail");
  495. goto fin;
  496. }
  497. /*
  498. * server's commit is H(k | server_element | server_scalar |
  499. * peer_element | peer_scalar | ciphersuite)
  500. */
  501. hash = eap_pwd_h_init();
  502. if (hash == NULL)
  503. goto fin;
  504. /*
  505. * zero the memory each time because this is mod prime math and some
  506. * value may start with a few zeros and the previous one did not.
  507. */
  508. crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
  509. eap_pwd_h_update(hash, cruft, prime_len);
  510. /* server element: x, y */
  511. if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
  512. cruft, cruft + prime_len) != 0) {
  513. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  514. "assignment fail");
  515. goto fin;
  516. }
  517. eap_pwd_h_update(hash, cruft, prime_len * 2);
  518. /* server scalar */
  519. crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
  520. eap_pwd_h_update(hash, cruft, order_len);
  521. /* my element: x, y */
  522. if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
  523. cruft + prime_len) != 0) {
  524. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  525. "assignment fail");
  526. goto fin;
  527. }
  528. eap_pwd_h_update(hash, cruft, prime_len * 2);
  529. /* my scalar */
  530. crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
  531. eap_pwd_h_update(hash, cruft, order_len);
  532. /* the ciphersuite */
  533. eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
  534. /* random function fin */
  535. eap_pwd_h_final(hash, conf);
  536. ptr = (u8 *) payload;
  537. if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
  538. wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
  539. goto fin;
  540. }
  541. wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified");
  542. /*
  543. * compute confirm:
  544. * H(k | peer_element | peer_scalar | server_element | server_scalar |
  545. * ciphersuite)
  546. */
  547. hash = eap_pwd_h_init();
  548. if (hash == NULL)
  549. goto fin;
  550. /* k */
  551. crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
  552. eap_pwd_h_update(hash, cruft, prime_len);
  553. /* my element */
  554. if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
  555. cruft + prime_len) != 0) {
  556. wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
  557. "assignment fail");
  558. goto fin;
  559. }
  560. eap_pwd_h_update(hash, cruft, prime_len * 2);
  561. /* my scalar */
  562. crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
  563. eap_pwd_h_update(hash, cruft, order_len);
  564. /* server element: x, y */
  565. if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
  566. cruft, cruft + prime_len) != 0) {
  567. wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
  568. "assignment fail");
  569. goto fin;
  570. }
  571. eap_pwd_h_update(hash, cruft, prime_len * 2);
  572. /* server scalar */
  573. crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
  574. eap_pwd_h_update(hash, cruft, order_len);
  575. /* the ciphersuite */
  576. eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
  577. /* all done */
  578. eap_pwd_h_final(hash, conf);
  579. if (compute_keys(data->grp, data->k,
  580. data->my_scalar, data->server_scalar, conf, ptr,
  581. &cs, data->msk, data->emsk, data->session_id) < 0) {
  582. wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
  583. "EMSK");
  584. goto fin;
  585. }
  586. data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
  587. if (data->outbuf == NULL)
  588. goto fin;
  589. wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
  590. fin:
  591. bin_clear_free(cruft, prime_len * 2);
  592. if (data->outbuf == NULL) {
  593. ret->methodState = METHOD_DONE;
  594. ret->decision = DECISION_FAIL;
  595. eap_pwd_state(data, FAILURE);
  596. } else {
  597. eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
  598. }
  599. }
  600. static struct wpabuf *
  601. eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
  602. const struct wpabuf *reqData)
  603. {
  604. struct eap_pwd_data *data = priv;
  605. struct wpabuf *resp = NULL;
  606. const u8 *pos, *buf;
  607. size_t len;
  608. u16 tot_len = 0;
  609. u8 lm_exch;
  610. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len);
  611. if ((pos == NULL) || (len < 1)) {
  612. wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and "
  613. "len is %d",
  614. pos == NULL ? "NULL" : "not NULL", (int) len);
  615. ret->ignore = TRUE;
  616. return NULL;
  617. }
  618. ret->ignore = FALSE;
  619. ret->methodState = METHOD_MAY_CONT;
  620. ret->decision = DECISION_FAIL;
  621. ret->allowNotifications = FALSE;
  622. lm_exch = *pos;
  623. pos++; /* skip over the bits and the exch */
  624. len--;
  625. /*
  626. * we're fragmenting so send out the next fragment
  627. */
  628. if (data->out_frag_pos) {
  629. /*
  630. * this should be an ACK
  631. */
  632. if (len)
  633. wpa_printf(MSG_INFO, "Bad Response! Fragmenting but "
  634. "not an ACK");
  635. wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment");
  636. /*
  637. * check if there are going to be more fragments
  638. */
  639. len = wpabuf_len(data->outbuf) - data->out_frag_pos;
  640. if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
  641. len = data->mtu - EAP_PWD_HDR_SIZE;
  642. EAP_PWD_SET_MORE_BIT(lm_exch);
  643. }
  644. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
  645. EAP_PWD_HDR_SIZE + len,
  646. EAP_CODE_RESPONSE, eap_get_id(reqData));
  647. if (resp == NULL) {
  648. wpa_printf(MSG_INFO, "Unable to allocate memory for "
  649. "next fragment!");
  650. return NULL;
  651. }
  652. wpabuf_put_u8(resp, lm_exch);
  653. buf = wpabuf_head_u8(data->outbuf);
  654. wpabuf_put_data(resp, buf + data->out_frag_pos, len);
  655. data->out_frag_pos += len;
  656. /*
  657. * this is the last fragment so get rid of the out buffer
  658. */
  659. if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
  660. wpabuf_free(data->outbuf);
  661. data->outbuf = NULL;
  662. data->out_frag_pos = 0;
  663. }
  664. wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes",
  665. data->out_frag_pos == 0 ? "last" : "next",
  666. (int) len);
  667. if (data->state == SUCCESS_ON_FRAG_COMPLETION) {
  668. ret->methodState = METHOD_DONE;
  669. ret->decision = DECISION_UNCOND_SUCC;
  670. eap_pwd_state(data, SUCCESS);
  671. }
  672. return resp;
  673. }
  674. /*
  675. * see if this is a fragment that needs buffering
  676. *
  677. * if it's the first fragment there'll be a length field
  678. */
  679. if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
  680. if (len < 2) {
  681. wpa_printf(MSG_DEBUG,
  682. "EAP-pwd: Frame too short to contain Total-Length field");
  683. ret->ignore = TRUE;
  684. return NULL;
  685. }
  686. tot_len = WPA_GET_BE16(pos);
  687. wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose "
  688. "total length = %d", tot_len);
  689. if (tot_len > 15000)
  690. return NULL;
  691. if (data->inbuf) {
  692. wpa_printf(MSG_DEBUG,
  693. "EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
  694. ret->ignore = TRUE;
  695. return NULL;
  696. }
  697. data->inbuf = wpabuf_alloc(tot_len);
  698. if (data->inbuf == NULL) {
  699. wpa_printf(MSG_INFO, "Out of memory to buffer "
  700. "fragments!");
  701. return NULL;
  702. }
  703. data->in_frag_pos = 0;
  704. pos += sizeof(u16);
  705. len -= sizeof(u16);
  706. }
  707. /*
  708. * buffer and ACK the fragment
  709. */
  710. if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
  711. data->in_frag_pos += len;
  712. if (data->in_frag_pos > wpabuf_size(data->inbuf)) {
  713. wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack "
  714. "detected (%d vs. %d)!",
  715. (int) data->in_frag_pos,
  716. (int) wpabuf_len(data->inbuf));
  717. wpabuf_free(data->inbuf);
  718. data->inbuf = NULL;
  719. data->in_frag_pos = 0;
  720. return NULL;
  721. }
  722. wpabuf_put_data(data->inbuf, pos, len);
  723. }
  724. if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
  725. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
  726. EAP_PWD_HDR_SIZE,
  727. EAP_CODE_RESPONSE, eap_get_id(reqData));
  728. if (resp != NULL)
  729. wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch)));
  730. wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment",
  731. (int) len);
  732. return resp;
  733. }
  734. /*
  735. * we're buffering and this is the last fragment
  736. */
  737. if (data->in_frag_pos) {
  738. wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
  739. (int) len);
  740. pos = wpabuf_head_u8(data->inbuf);
  741. len = data->in_frag_pos;
  742. }
  743. wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d",
  744. EAP_PWD_GET_EXCHANGE(lm_exch), (int) len);
  745. switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
  746. case EAP_PWD_OPCODE_ID_EXCH:
  747. eap_pwd_perform_id_exchange(sm, data, ret, reqData,
  748. pos, len);
  749. break;
  750. case EAP_PWD_OPCODE_COMMIT_EXCH:
  751. eap_pwd_perform_commit_exchange(sm, data, ret, reqData,
  752. pos, len);
  753. break;
  754. case EAP_PWD_OPCODE_CONFIRM_EXCH:
  755. eap_pwd_perform_confirm_exchange(sm, data, ret, reqData,
  756. pos, len);
  757. break;
  758. default:
  759. wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown "
  760. "opcode %d", lm_exch);
  761. break;
  762. }
  763. /*
  764. * if we buffered the just processed input now's the time to free it
  765. */
  766. if (data->in_frag_pos) {
  767. wpabuf_free(data->inbuf);
  768. data->inbuf = NULL;
  769. data->in_frag_pos = 0;
  770. }
  771. if (data->outbuf == NULL) {
  772. ret->methodState = METHOD_DONE;
  773. ret->decision = DECISION_FAIL;
  774. return NULL; /* generic failure */
  775. }
  776. /*
  777. * we have output! Do we need to fragment it?
  778. */
  779. lm_exch = EAP_PWD_GET_EXCHANGE(lm_exch);
  780. len = wpabuf_len(data->outbuf);
  781. if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
  782. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu,
  783. EAP_CODE_RESPONSE, eap_get_id(reqData));
  784. /*
  785. * if so it's the first so include a length field
  786. */
  787. EAP_PWD_SET_LENGTH_BIT(lm_exch);
  788. EAP_PWD_SET_MORE_BIT(lm_exch);
  789. tot_len = len;
  790. /*
  791. * keep the packet at the MTU
  792. */
  793. len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16);
  794. wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total "
  795. "length = %d", tot_len);
  796. } else {
  797. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
  798. EAP_PWD_HDR_SIZE + len,
  799. EAP_CODE_RESPONSE, eap_get_id(reqData));
  800. }
  801. if (resp == NULL)
  802. return NULL;
  803. wpabuf_put_u8(resp, lm_exch);
  804. if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
  805. wpabuf_put_be16(resp, tot_len);
  806. data->out_frag_pos += len;
  807. }
  808. buf = wpabuf_head_u8(data->outbuf);
  809. wpabuf_put_data(resp, buf, len);
  810. /*
  811. * if we're not fragmenting then there's no need to carry this around
  812. */
  813. if (data->out_frag_pos == 0) {
  814. wpabuf_free(data->outbuf);
  815. data->outbuf = NULL;
  816. data->out_frag_pos = 0;
  817. if (data->state == SUCCESS_ON_FRAG_COMPLETION) {
  818. ret->methodState = METHOD_DONE;
  819. ret->decision = DECISION_UNCOND_SUCC;
  820. eap_pwd_state(data, SUCCESS);
  821. }
  822. }
  823. return resp;
  824. }
  825. static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv)
  826. {
  827. struct eap_pwd_data *data = priv;
  828. return data->state == SUCCESS;
  829. }
  830. static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  831. {
  832. struct eap_pwd_data *data = priv;
  833. u8 *key;
  834. if (data->state != SUCCESS)
  835. return NULL;
  836. if ((key = os_malloc(EAP_EMSK_LEN)) == NULL)
  837. return NULL;
  838. os_memcpy(key, data->emsk, EAP_EMSK_LEN);
  839. *len = EAP_EMSK_LEN;
  840. return key;
  841. }
  842. int eap_peer_pwd_register(void)
  843. {
  844. struct eap_method *eap;
  845. eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
  846. EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
  847. if (eap == NULL)
  848. return -1;
  849. eap->init = eap_pwd_init;
  850. eap->deinit = eap_pwd_deinit;
  851. eap->process = eap_pwd_process;
  852. eap->isKeyAvailable = eap_pwd_key_available;
  853. eap->getKey = eap_pwd_getkey;
  854. eap->getSessionId = eap_pwd_get_session_id;
  855. eap->get_emsk = eap_pwd_get_emsk;
  856. return eap_peer_method_register(eap);
  857. }