eap_server_pwd.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. /*
  2. * hostapd / EAP-pwd (RFC 5931) server
  3. * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the BSD license.
  7. *
  8. * Alternatively, this software may be distributed under the terms of the
  9. * GNU General Public License version 2 as published by the Free Software
  10. * Foundation.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "eap_server/eap_i.h"
  17. #include "eap_common/eap_pwd_common.h"
  18. struct eap_pwd_data {
  19. enum {
  20. PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
  21. } state;
  22. u8 *id_peer;
  23. size_t id_peer_len;
  24. u8 *id_server;
  25. size_t id_server_len;
  26. u8 *password;
  27. size_t password_len;
  28. u32 token;
  29. u16 group_num;
  30. EAP_PWD_group *grp;
  31. BIGNUM *k;
  32. BIGNUM *private_value;
  33. BIGNUM *peer_scalar;
  34. BIGNUM *my_scalar;
  35. EC_POINT *my_element;
  36. EC_POINT *peer_element;
  37. u8 msk[EAP_MSK_LEN];
  38. u8 emsk[EAP_EMSK_LEN];
  39. BN_CTX *bnctx;
  40. };
  41. static const char * eap_pwd_state_txt(int state)
  42. {
  43. switch (state) {
  44. case PWD_ID_Req:
  45. return "PWD-ID-Req";
  46. case PWD_Commit_Req:
  47. return "PWD-Commit-Req";
  48. case PWD_Confirm_Req:
  49. return "PWD-Confirm-Req";
  50. case SUCCESS:
  51. return "SUCCESS";
  52. case FAILURE:
  53. return "FAILURE";
  54. default:
  55. return "PWD-Unk";
  56. }
  57. }
  58. static void eap_pwd_state(struct eap_pwd_data *data, int state)
  59. {
  60. wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
  61. eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
  62. data->state = state;
  63. }
  64. static void * eap_pwd_init(struct eap_sm *sm)
  65. {
  66. struct eap_pwd_data *data;
  67. if (sm->user == NULL || sm->user->password == NULL ||
  68. sm->user->password_len == 0) {
  69. wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not "
  70. "configured");
  71. return NULL;
  72. }
  73. data = os_zalloc(sizeof(*data));
  74. if (data == NULL)
  75. return NULL;
  76. data->group_num = sm->pwd_group;
  77. wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
  78. data->group_num);
  79. data->state = PWD_ID_Req;
  80. data->id_server = (u8 *) os_strdup("server");
  81. if (data->id_server)
  82. data->id_server_len = os_strlen((char *) data->id_server);
  83. data->password = os_malloc(sm->user->password_len);
  84. if (data->password == NULL) {
  85. wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
  86. "fail");
  87. os_free(data->id_server);
  88. os_free(data);
  89. return NULL;
  90. }
  91. data->password_len = sm->user->password_len;
  92. os_memcpy(data->password, sm->user->password, data->password_len);
  93. data->bnctx = BN_CTX_new();
  94. if (data->bnctx == NULL) {
  95. wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
  96. os_free(data->password);
  97. os_free(data->id_server);
  98. os_free(data);
  99. return NULL;
  100. }
  101. return data;
  102. }
  103. static void eap_pwd_reset(struct eap_sm *sm, void *priv)
  104. {
  105. struct eap_pwd_data *data = priv;
  106. BN_free(data->private_value);
  107. BN_free(data->peer_scalar);
  108. BN_free(data->my_scalar);
  109. BN_free(data->k);
  110. BN_CTX_free(data->bnctx);
  111. EC_POINT_free(data->my_element);
  112. EC_POINT_free(data->peer_element);
  113. os_free(data->id_peer);
  114. os_free(data->id_server);
  115. os_free(data->password);
  116. if (data->grp) {
  117. EC_GROUP_free(data->grp->group);
  118. EC_POINT_free(data->grp->pwe);
  119. BN_free(data->grp->order);
  120. BN_free(data->grp->prime);
  121. os_free(data->grp);
  122. }
  123. os_free(data);
  124. }
  125. static struct wpabuf *
  126. eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
  127. {
  128. struct wpabuf *req;
  129. wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
  130. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
  131. sizeof(struct eap_pwd_hdr) +
  132. sizeof(struct eap_pwd_id) + data->id_server_len,
  133. EAP_CODE_REQUEST, id);
  134. if (req == NULL) {
  135. eap_pwd_state(data, FAILURE);
  136. return NULL;
  137. }
  138. /* an lfsr is good enough to generate unpredictable tokens */
  139. data->token = os_random();
  140. wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
  141. wpabuf_put_be16(req, data->group_num);
  142. wpabuf_put_u8(req, EAP_PWD_DEFAULT_RAND_FUNC);
  143. wpabuf_put_u8(req, EAP_PWD_DEFAULT_PRF);
  144. wpabuf_put_data(req, &data->token, sizeof(data->token));
  145. wpabuf_put_u8(req, EAP_PWD_PREP_NONE);
  146. wpabuf_put_data(req, data->id_server, data->id_server_len);
  147. return req;
  148. }
  149. static struct wpabuf *
  150. eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
  151. {
  152. struct wpabuf *req = NULL;
  153. BIGNUM *mask = NULL, *x = NULL, *y = NULL;
  154. u8 *scalar = NULL, *element = NULL;
  155. u16 offset;
  156. wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
  157. if (((data->private_value = BN_new()) == NULL) ||
  158. ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
  159. ((data->my_scalar = BN_new()) == NULL) ||
  160. ((mask = BN_new()) == NULL)) {
  161. wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
  162. "fail");
  163. goto fin;
  164. }
  165. BN_rand_range(data->private_value, data->grp->order);
  166. BN_rand_range(mask, data->grp->order);
  167. BN_add(data->my_scalar, data->private_value, mask);
  168. BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
  169. data->bnctx);
  170. if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
  171. data->grp->pwe, mask, data->bnctx)) {
  172. wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
  173. "fail");
  174. eap_pwd_state(data, FAILURE);
  175. goto fin;
  176. }
  177. if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
  178. {
  179. wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
  180. "fail");
  181. goto fin;
  182. }
  183. BN_free(mask);
  184. if (((x = BN_new()) == NULL) ||
  185. ((y = BN_new()) == NULL)) {
  186. wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
  187. "fail");
  188. goto fin;
  189. }
  190. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  191. data->my_element, x, y,
  192. data->bnctx)) {
  193. wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
  194. "fail");
  195. goto fin;
  196. }
  197. if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
  198. ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
  199. NULL)) {
  200. wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
  201. goto fin;
  202. }
  203. /*
  204. * bignums occupy as little memory as possible so one that is
  205. * sufficiently smaller than the prime or order might need pre-pending
  206. * with zeros.
  207. */
  208. os_memset(scalar, 0, BN_num_bytes(data->grp->order));
  209. os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
  210. offset = BN_num_bytes(data->grp->order) -
  211. BN_num_bytes(data->my_scalar);
  212. BN_bn2bin(data->my_scalar, scalar + offset);
  213. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
  214. BN_bn2bin(x, element + offset);
  215. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
  216. BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
  217. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
  218. sizeof(struct eap_pwd_hdr) +
  219. (2 * BN_num_bytes(data->grp->prime)) +
  220. BN_num_bytes(data->grp->order),
  221. EAP_CODE_REQUEST, id);
  222. if (req == NULL)
  223. goto fin;
  224. wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
  225. /* We send the element as (x,y) followed by the scalar */
  226. wpabuf_put_data(req, element, (2 * BN_num_bytes(data->grp->prime)));
  227. wpabuf_put_data(req, scalar, BN_num_bytes(data->grp->order));
  228. fin:
  229. os_free(scalar);
  230. os_free(element);
  231. BN_free(x);
  232. BN_free(y);
  233. if (req == NULL)
  234. eap_pwd_state(data, FAILURE);
  235. return req;
  236. }
  237. static struct wpabuf *
  238. eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
  239. {
  240. struct wpabuf *req = NULL;
  241. BIGNUM *x = NULL, *y = NULL;
  242. HMAC_CTX ctx;
  243. u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
  244. wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
  245. /* Each component of the cruft will be at most as big as the prime */
  246. if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
  247. ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
  248. wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
  249. "fail");
  250. goto fin;
  251. }
  252. /*
  253. * commit is H(k | server_element | server_scalar | peer_element |
  254. * peer_scalar | ciphersuite)
  255. */
  256. H_Init(&ctx);
  257. /*
  258. * Zero the memory each time because this is mod prime math and some
  259. * value may start with a few zeros and the previous one did not.
  260. *
  261. * First is k
  262. */
  263. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  264. BN_bn2bin(data->k, cruft);
  265. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  266. /* server element: x, y */
  267. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  268. data->my_element, x, y,
  269. data->bnctx)) {
  270. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  271. "assignment fail");
  272. goto fin;
  273. }
  274. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  275. BN_bn2bin(x, cruft);
  276. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  277. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  278. BN_bn2bin(y, cruft);
  279. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  280. /* server scalar */
  281. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  282. BN_bn2bin(data->my_scalar, cruft);
  283. H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
  284. /* peer element: x, y */
  285. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  286. data->peer_element, x, y,
  287. data->bnctx)) {
  288. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  289. "assignment fail");
  290. goto fin;
  291. }
  292. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  293. BN_bn2bin(x, cruft);
  294. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  295. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  296. BN_bn2bin(y, cruft);
  297. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  298. /* peer scalar */
  299. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  300. BN_bn2bin(data->peer_scalar, cruft);
  301. H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
  302. /* ciphersuite */
  303. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  304. ptr = cruft;
  305. os_memcpy(ptr, &data->group_num, sizeof(u16));
  306. ptr += sizeof(u16);
  307. *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
  308. ptr += sizeof(u8);
  309. *ptr = EAP_PWD_DEFAULT_PRF;
  310. ptr += sizeof(u8);
  311. H_Update(&ctx, cruft, ptr-cruft);
  312. /* all done with the random function */
  313. H_Final(&ctx, conf);
  314. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
  315. sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
  316. EAP_CODE_REQUEST, id);
  317. if (req == NULL)
  318. goto fin;
  319. wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
  320. wpabuf_put_data(req, conf, SHA256_DIGEST_LENGTH);
  321. fin:
  322. os_free(cruft);
  323. BN_free(x);
  324. BN_free(y);
  325. if (req == NULL)
  326. eap_pwd_state(data, FAILURE);
  327. return req;
  328. }
  329. static struct wpabuf *
  330. eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
  331. {
  332. struct eap_pwd_data *data = priv;
  333. switch (data->state) {
  334. case PWD_ID_Req:
  335. return eap_pwd_build_id_req(sm, data, id);
  336. case PWD_Commit_Req:
  337. return eap_pwd_build_commit_req(sm, data, id);
  338. case PWD_Confirm_Req:
  339. return eap_pwd_build_confirm_req(sm, data, id);
  340. default:
  341. wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req",
  342. data->state);
  343. break;
  344. }
  345. return NULL;
  346. }
  347. static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
  348. struct wpabuf *respData)
  349. {
  350. struct eap_pwd_data *data = priv;
  351. const u8 *pos;
  352. size_t len;
  353. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
  354. if (pos == NULL || len < 1) {
  355. wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
  356. return TRUE;
  357. }
  358. wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: opcode=%d", *pos);
  359. if (data->state == PWD_ID_Req && *pos == EAP_PWD_OPCODE_ID_EXCH)
  360. return FALSE;
  361. if (data->state == PWD_Commit_Req &&
  362. *pos == EAP_PWD_OPCODE_COMMIT_EXCH)
  363. return FALSE;
  364. if (data->state == PWD_Confirm_Req &&
  365. *pos == EAP_PWD_OPCODE_CONFIRM_EXCH)
  366. return FALSE;
  367. wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
  368. *pos, data->state);
  369. return TRUE;
  370. }
  371. static void eap_pwd_process_id_resp(struct eap_sm *sm,
  372. struct eap_pwd_data *data,
  373. const u8 *payload, size_t payload_len)
  374. {
  375. struct eap_pwd_id *id;
  376. if (payload_len < sizeof(struct eap_pwd_id)) {
  377. wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
  378. return;
  379. }
  380. id = (struct eap_pwd_id *) payload;
  381. if ((data->group_num != be_to_host16(id->group_num)) ||
  382. (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
  383. (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
  384. (id->prf != EAP_PWD_DEFAULT_PRF)) {
  385. wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
  386. eap_pwd_state(data, FAILURE);
  387. return;
  388. }
  389. data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
  390. if (data->id_peer == NULL) {
  391. wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
  392. return;
  393. }
  394. data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
  395. os_memcpy(data->id_peer, id->identity, data->id_peer_len);
  396. wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
  397. data->id_peer, data->id_peer_len);
  398. if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) {
  399. wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
  400. "group");
  401. return;
  402. }
  403. if (compute_password_element(data->grp, data->group_num,
  404. data->password, data->password_len,
  405. data->id_server, data->id_server_len,
  406. data->id_peer, data->id_peer_len,
  407. (u8 *) &data->token)) {
  408. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
  409. "PWE");
  410. return;
  411. }
  412. wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
  413. BN_num_bits(data->grp->prime));
  414. eap_pwd_state(data, PWD_Commit_Req);
  415. }
  416. static void
  417. eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
  418. const u8 *payload, size_t payload_len)
  419. {
  420. u8 *ptr;
  421. BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
  422. EC_POINT *K = NULL, *point = NULL;
  423. int res = 0;
  424. wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
  425. if (((data->peer_scalar = BN_new()) == NULL) ||
  426. ((data->k = BN_new()) == NULL) ||
  427. ((cofactor = BN_new()) == NULL) ||
  428. ((x = BN_new()) == NULL) ||
  429. ((y = BN_new()) == NULL) ||
  430. ((point = EC_POINT_new(data->grp->group)) == NULL) ||
  431. ((K = EC_POINT_new(data->grp->group)) == NULL) ||
  432. ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
  433. wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
  434. "fail");
  435. goto fin;
  436. }
  437. if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
  438. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
  439. "cofactor for curve");
  440. goto fin;
  441. }
  442. /* element, x then y, followed by scalar */
  443. ptr = (u8 *) payload;
  444. BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
  445. ptr += BN_num_bytes(data->grp->prime);
  446. BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
  447. ptr += BN_num_bytes(data->grp->prime);
  448. BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
  449. if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
  450. data->peer_element, x, y,
  451. data->bnctx)) {
  452. wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
  453. "fail");
  454. goto fin;
  455. }
  456. /* check to ensure peer's element is not in a small sub-group */
  457. if (BN_cmp(cofactor, BN_value_one())) {
  458. if (!EC_POINT_mul(data->grp->group, point, NULL,
  459. data->peer_element, cofactor, NULL)) {
  460. wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
  461. "multiply peer element by order");
  462. goto fin;
  463. }
  464. if (EC_POINT_is_at_infinity(data->grp->group, point)) {
  465. wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
  466. "is at infinity!\n");
  467. goto fin;
  468. }
  469. }
  470. /* compute the shared key, k */
  471. if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
  472. data->peer_scalar, data->bnctx)) ||
  473. (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
  474. data->bnctx)) ||
  475. (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
  476. data->bnctx))) {
  477. wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
  478. "fail");
  479. goto fin;
  480. }
  481. /* ensure that the shared key isn't in a small sub-group */
  482. if (BN_cmp(cofactor, BN_value_one())) {
  483. if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
  484. NULL)) {
  485. wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
  486. "multiply shared key point by order!\n");
  487. goto fin;
  488. }
  489. }
  490. /*
  491. * This check is strictly speaking just for the case above where
  492. * co-factor > 1 but it was suggested that even though this is probably
  493. * never going to happen it is a simple and safe check "just to be
  494. * sure" so let's be safe.
  495. */
  496. if (EC_POINT_is_at_infinity(data->grp->group, K)) {
  497. wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
  498. "at infinity");
  499. goto fin;
  500. }
  501. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
  502. NULL, data->bnctx)) {
  503. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
  504. "shared secret from secret point");
  505. goto fin;
  506. }
  507. res = 1;
  508. fin:
  509. EC_POINT_free(K);
  510. EC_POINT_free(point);
  511. BN_free(cofactor);
  512. BN_free(x);
  513. BN_free(y);
  514. if (res)
  515. eap_pwd_state(data, PWD_Confirm_Req);
  516. else
  517. eap_pwd_state(data, FAILURE);
  518. }
  519. static void
  520. eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
  521. const u8 *payload, size_t payload_len)
  522. {
  523. BIGNUM *x = NULL, *y = NULL;
  524. HMAC_CTX ctx;
  525. u32 cs;
  526. u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
  527. /* build up the ciphersuite: group | random_function | prf */
  528. ptr = (u8 *) &cs;
  529. os_memcpy(ptr, &data->group_num, sizeof(u16));
  530. ptr += sizeof(u16);
  531. *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
  532. ptr += sizeof(u8);
  533. *ptr = EAP_PWD_DEFAULT_PRF;
  534. /* each component of the cruft will be at most as big as the prime */
  535. if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
  536. ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
  537. wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
  538. goto fin;
  539. }
  540. /*
  541. * commit is H(k | peer_element | peer_scalar | server_element |
  542. * server_scalar | ciphersuite)
  543. */
  544. H_Init(&ctx);
  545. /* k */
  546. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  547. BN_bn2bin(data->k, cruft);
  548. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  549. /* peer element: x, y */
  550. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  551. data->peer_element, x, y,
  552. data->bnctx)) {
  553. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  554. "assignment fail");
  555. goto fin;
  556. }
  557. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  558. BN_bn2bin(x, cruft);
  559. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  560. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  561. BN_bn2bin(y, cruft);
  562. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  563. /* peer scalar */
  564. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  565. BN_bn2bin(data->peer_scalar, cruft);
  566. H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
  567. /* server element: x, y */
  568. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  569. data->my_element, x, y,
  570. data->bnctx)) {
  571. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  572. "assignment fail");
  573. goto fin;
  574. }
  575. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  576. BN_bn2bin(x, cruft);
  577. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  578. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  579. BN_bn2bin(y, cruft);
  580. H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
  581. /* server scalar */
  582. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  583. BN_bn2bin(data->my_scalar, cruft);
  584. H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
  585. /* ciphersuite */
  586. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  587. H_Update(&ctx, (u8 *)&cs, sizeof(u32));
  588. /* all done */
  589. H_Final(&ctx, conf);
  590. ptr = (u8 *) payload;
  591. if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
  592. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
  593. "verify");
  594. goto fin;
  595. }
  596. wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
  597. if (compute_keys(data->grp, data->bnctx, data->k, data->my_element,
  598. data->peer_element, data->my_scalar,
  599. data->peer_scalar, &cs, data->msk, data->emsk) < 0)
  600. eap_pwd_state(data, FAILURE);
  601. else
  602. eap_pwd_state(data, SUCCESS);
  603. fin:
  604. os_free(cruft);
  605. BN_free(x);
  606. BN_free(y);
  607. }
  608. static void eap_pwd_process(struct eap_sm *sm, void *priv,
  609. struct wpabuf *respData)
  610. {
  611. struct eap_pwd_data *data = priv;
  612. const u8 *pos;
  613. size_t len;
  614. u8 exch;
  615. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
  616. if ((pos == NULL) || (len < 1)) {
  617. wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
  618. (pos == NULL) ? "is NULL" : "is not NULL",
  619. (int) len);
  620. return;
  621. }
  622. exch = *pos & 0x3f;
  623. switch (exch) {
  624. case EAP_PWD_OPCODE_ID_EXCH:
  625. eap_pwd_process_id_resp(sm, data, pos + 1, len - 1);
  626. break;
  627. case EAP_PWD_OPCODE_COMMIT_EXCH:
  628. eap_pwd_process_commit_resp(sm, data, pos + 1, len - 1);
  629. break;
  630. case EAP_PWD_OPCODE_CONFIRM_EXCH:
  631. eap_pwd_process_confirm_resp(sm, data, pos + 1, len - 1);
  632. break;
  633. }
  634. }
  635. static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
  636. {
  637. struct eap_pwd_data *data = priv;
  638. u8 *key;
  639. if (data->state != SUCCESS)
  640. return NULL;
  641. key = os_malloc(EAP_MSK_LEN);
  642. if (key == NULL)
  643. return NULL;
  644. os_memcpy(key, data->msk, EAP_MSK_LEN);
  645. *len = EAP_MSK_LEN;
  646. return key;
  647. }
  648. static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  649. {
  650. struct eap_pwd_data *data = priv;
  651. u8 *key;
  652. if (data->state != SUCCESS)
  653. return NULL;
  654. key = os_malloc(EAP_EMSK_LEN);
  655. if (key == NULL)
  656. return NULL;
  657. os_memcpy(key, data->emsk, EAP_EMSK_LEN);
  658. *len = EAP_EMSK_LEN;
  659. return key;
  660. }
  661. static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
  662. {
  663. struct eap_pwd_data *data = priv;
  664. return data->state == SUCCESS;
  665. }
  666. static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
  667. {
  668. struct eap_pwd_data *data = priv;
  669. return (data->state == SUCCESS) || (data->state == FAILURE);
  670. }
  671. int eap_server_pwd_register(void)
  672. {
  673. struct eap_method *eap;
  674. int ret;
  675. struct timeval tp;
  676. struct timezone tz;
  677. u32 sr;
  678. EVP_add_digest(EVP_sha256());
  679. sr = 0xdeaddada;
  680. (void) gettimeofday(&tp, &tz);
  681. sr ^= (tp.tv_sec ^ tp.tv_usec);
  682. srandom(sr);
  683. eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
  684. EAP_VENDOR_IETF, EAP_TYPE_PWD,
  685. "PWD");
  686. if (eap == NULL)
  687. return -1;
  688. eap->init = eap_pwd_init;
  689. eap->reset = eap_pwd_reset;
  690. eap->buildReq = eap_pwd_build_req;
  691. eap->check = eap_pwd_check;
  692. eap->process = eap_pwd_process;
  693. eap->isDone = eap_pwd_is_done;
  694. eap->getKey = eap_pwd_getkey;
  695. eap->get_emsk = eap_pwd_get_emsk;
  696. eap->isSuccess = eap_pwd_is_success;
  697. ret = eap_server_method_register(eap);
  698. if (ret)
  699. eap_server_method_free(eap);
  700. return ret;
  701. }