eap_server_pwd.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129
  1. /*
  2. * hostapd / EAP-pwd (RFC 5931) server
  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 "eap_server/eap_i.h"
  13. #include "eap_common/eap_pwd_common.h"
  14. struct eap_pwd_data {
  15. enum {
  16. PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
  17. } state;
  18. u8 *id_peer;
  19. size_t id_peer_len;
  20. u8 *id_server;
  21. size_t id_server_len;
  22. u8 *password;
  23. size_t password_len;
  24. int password_hash;
  25. u32 token;
  26. u16 group_num;
  27. EAP_PWD_group *grp;
  28. struct wpabuf *inbuf;
  29. size_t in_frag_pos;
  30. struct wpabuf *outbuf;
  31. size_t out_frag_pos;
  32. size_t mtu;
  33. BIGNUM *k;
  34. BIGNUM *private_value;
  35. BIGNUM *peer_scalar;
  36. BIGNUM *my_scalar;
  37. EC_POINT *my_element;
  38. EC_POINT *peer_element;
  39. u8 my_confirm[SHA256_MAC_LEN];
  40. u8 msk[EAP_MSK_LEN];
  41. u8 emsk[EAP_EMSK_LEN];
  42. u8 session_id[1 + SHA256_MAC_LEN];
  43. BN_CTX *bnctx;
  44. };
  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:
  55. return "SUCCESS";
  56. case FAILURE:
  57. return "FAILURE";
  58. default:
  59. return "PWD-Unk";
  60. }
  61. }
  62. static void eap_pwd_state(struct eap_pwd_data *data, int state)
  63. {
  64. wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
  65. eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
  66. data->state = state;
  67. }
  68. static void * eap_pwd_init(struct eap_sm *sm)
  69. {
  70. struct eap_pwd_data *data;
  71. if (sm->user == NULL || sm->user->password == NULL ||
  72. sm->user->password_len == 0) {
  73. wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not "
  74. "configured");
  75. return NULL;
  76. }
  77. data = os_zalloc(sizeof(*data));
  78. if (data == NULL)
  79. return NULL;
  80. data->group_num = sm->pwd_group;
  81. wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
  82. data->group_num);
  83. data->state = PWD_ID_Req;
  84. data->id_server = (u8 *) os_strdup("server");
  85. if (data->id_server)
  86. data->id_server_len = os_strlen((char *) data->id_server);
  87. data->password = os_malloc(sm->user->password_len);
  88. if (data->password == NULL) {
  89. wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
  90. "fail");
  91. bin_clear_free(data->id_server, data->id_server_len);
  92. os_free(data);
  93. return NULL;
  94. }
  95. data->password_len = sm->user->password_len;
  96. os_memcpy(data->password, sm->user->password, data->password_len);
  97. data->password_hash = sm->user->password_hash;
  98. data->bnctx = BN_CTX_new();
  99. if (data->bnctx == NULL) {
  100. wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
  101. bin_clear_free(data->password, data->password_len);
  102. bin_clear_free(data->id_server, data->id_server_len);
  103. os_free(data);
  104. return NULL;
  105. }
  106. data->in_frag_pos = data->out_frag_pos = 0;
  107. data->inbuf = data->outbuf = NULL;
  108. /* use default MTU from RFC 5931 if not configured otherwise */
  109. data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
  110. return data;
  111. }
  112. static void eap_pwd_reset(struct eap_sm *sm, void *priv)
  113. {
  114. struct eap_pwd_data *data = priv;
  115. BN_clear_free(data->private_value);
  116. BN_clear_free(data->peer_scalar);
  117. BN_clear_free(data->my_scalar);
  118. BN_clear_free(data->k);
  119. BN_CTX_free(data->bnctx);
  120. EC_POINT_clear_free(data->my_element);
  121. EC_POINT_clear_free(data->peer_element);
  122. bin_clear_free(data->id_peer, data->id_peer_len);
  123. bin_clear_free(data->id_server, data->id_server_len);
  124. bin_clear_free(data->password, data->password_len);
  125. if (data->grp) {
  126. EC_GROUP_free(data->grp->group);
  127. EC_POINT_clear_free(data->grp->pwe);
  128. BN_clear_free(data->grp->order);
  129. BN_clear_free(data->grp->prime);
  130. os_free(data->grp);
  131. }
  132. wpabuf_free(data->inbuf);
  133. wpabuf_free(data->outbuf);
  134. bin_clear_free(data, sizeof(*data));
  135. }
  136. static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
  137. u8 id)
  138. {
  139. wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
  140. /*
  141. * if we're fragmenting then we already have an id request, just return
  142. */
  143. if (data->out_frag_pos)
  144. return;
  145. data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
  146. data->id_server_len);
  147. if (data->outbuf == NULL) {
  148. eap_pwd_state(data, FAILURE);
  149. return;
  150. }
  151. if (os_get_random((u8 *) &data->token, sizeof(data->token)) < 0) {
  152. wpabuf_free(data->outbuf);
  153. data->outbuf = NULL;
  154. eap_pwd_state(data, FAILURE);
  155. return;
  156. }
  157. wpabuf_put_be16(data->outbuf, data->group_num);
  158. wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
  159. wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
  160. wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
  161. wpabuf_put_u8(data->outbuf, data->password_hash ? EAP_PWD_PREP_MS :
  162. EAP_PWD_PREP_NONE);
  163. wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
  164. }
  165. static void eap_pwd_build_commit_req(struct eap_sm *sm,
  166. struct eap_pwd_data *data, u8 id)
  167. {
  168. BIGNUM *mask = NULL, *x = NULL, *y = NULL;
  169. u8 *scalar = NULL, *element = NULL;
  170. u16 offset;
  171. wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
  172. /*
  173. * if we're fragmenting then we already have an commit request, just
  174. * return
  175. */
  176. if (data->out_frag_pos)
  177. return;
  178. if (((data->private_value = BN_new()) == NULL) ||
  179. ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
  180. ((data->my_scalar = BN_new()) == NULL) ||
  181. ((mask = BN_new()) == NULL)) {
  182. wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
  183. "fail");
  184. goto fin;
  185. }
  186. if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
  187. BN_rand_range(mask, data->grp->order) != 1 ||
  188. BN_add(data->my_scalar, data->private_value, mask) != 1 ||
  189. BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
  190. data->bnctx) != 1) {
  191. wpa_printf(MSG_INFO,
  192. "EAP-pwd (server): unable to get randomness");
  193. goto fin;
  194. }
  195. if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
  196. data->grp->pwe, mask, data->bnctx)) {
  197. wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
  198. "fail");
  199. eap_pwd_state(data, FAILURE);
  200. goto fin;
  201. }
  202. if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
  203. {
  204. wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
  205. "fail");
  206. goto fin;
  207. }
  208. BN_clear_free(mask);
  209. if (((x = BN_new()) == NULL) ||
  210. ((y = BN_new()) == NULL)) {
  211. wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
  212. "fail");
  213. goto fin;
  214. }
  215. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  216. data->my_element, x, y,
  217. data->bnctx)) {
  218. wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
  219. "fail");
  220. goto fin;
  221. }
  222. if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
  223. ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
  224. NULL)) {
  225. wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
  226. goto fin;
  227. }
  228. /*
  229. * bignums occupy as little memory as possible so one that is
  230. * sufficiently smaller than the prime or order might need pre-pending
  231. * with zeros.
  232. */
  233. os_memset(scalar, 0, BN_num_bytes(data->grp->order));
  234. os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
  235. offset = BN_num_bytes(data->grp->order) -
  236. BN_num_bytes(data->my_scalar);
  237. BN_bn2bin(data->my_scalar, scalar + offset);
  238. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
  239. BN_bn2bin(x, element + offset);
  240. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
  241. BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
  242. data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
  243. BN_num_bytes(data->grp->order));
  244. if (data->outbuf == NULL)
  245. goto fin;
  246. /* We send the element as (x,y) followed by the scalar */
  247. wpabuf_put_data(data->outbuf, element,
  248. 2 * BN_num_bytes(data->grp->prime));
  249. wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
  250. fin:
  251. os_free(scalar);
  252. os_free(element);
  253. BN_clear_free(x);
  254. BN_clear_free(y);
  255. if (data->outbuf == NULL)
  256. eap_pwd_state(data, FAILURE);
  257. }
  258. static void eap_pwd_build_confirm_req(struct eap_sm *sm,
  259. struct eap_pwd_data *data, u8 id)
  260. {
  261. BIGNUM *x = NULL, *y = NULL;
  262. struct crypto_hash *hash;
  263. u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
  264. u16 grp;
  265. int offset;
  266. wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
  267. /*
  268. * if we're fragmenting then we already have an confirm request, just
  269. * return
  270. */
  271. if (data->out_frag_pos)
  272. return;
  273. /* Each component of the cruft will be at most as big as the prime */
  274. if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
  275. ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
  276. wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
  277. "fail");
  278. goto fin;
  279. }
  280. /*
  281. * commit is H(k | server_element | server_scalar | peer_element |
  282. * peer_scalar | ciphersuite)
  283. */
  284. hash = eap_pwd_h_init();
  285. if (hash == NULL)
  286. goto fin;
  287. /*
  288. * Zero the memory each time because this is mod prime math and some
  289. * value may start with a few zeros and the previous one did not.
  290. *
  291. * First is k
  292. */
  293. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  294. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
  295. BN_bn2bin(data->k, cruft + offset);
  296. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  297. /* server element: x, y */
  298. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  299. data->my_element, x, y,
  300. data->bnctx)) {
  301. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  302. "assignment fail");
  303. goto fin;
  304. }
  305. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  306. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
  307. BN_bn2bin(x, cruft + offset);
  308. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  309. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  310. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
  311. BN_bn2bin(y, cruft + offset);
  312. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  313. /* server scalar */
  314. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  315. offset = BN_num_bytes(data->grp->order) -
  316. BN_num_bytes(data->my_scalar);
  317. BN_bn2bin(data->my_scalar, cruft + offset);
  318. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
  319. /* peer element: x, y */
  320. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  321. data->peer_element, x, y,
  322. data->bnctx)) {
  323. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  324. "assignment fail");
  325. goto fin;
  326. }
  327. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  328. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
  329. BN_bn2bin(x, cruft + offset);
  330. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  331. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  332. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
  333. BN_bn2bin(y, cruft + offset);
  334. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  335. /* peer scalar */
  336. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  337. offset = BN_num_bytes(data->grp->order) -
  338. BN_num_bytes(data->peer_scalar);
  339. BN_bn2bin(data->peer_scalar, cruft + offset);
  340. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
  341. /* ciphersuite */
  342. grp = htons(data->group_num);
  343. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  344. ptr = cruft;
  345. os_memcpy(ptr, &grp, sizeof(u16));
  346. ptr += sizeof(u16);
  347. *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
  348. ptr += sizeof(u8);
  349. *ptr = EAP_PWD_DEFAULT_PRF;
  350. ptr += sizeof(u8);
  351. eap_pwd_h_update(hash, cruft, ptr - cruft);
  352. /* all done with the random function */
  353. eap_pwd_h_final(hash, conf);
  354. os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
  355. data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
  356. if (data->outbuf == NULL)
  357. goto fin;
  358. wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
  359. fin:
  360. bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
  361. BN_clear_free(x);
  362. BN_clear_free(y);
  363. if (data->outbuf == NULL)
  364. eap_pwd_state(data, FAILURE);
  365. }
  366. static struct wpabuf *
  367. eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
  368. {
  369. struct eap_pwd_data *data = priv;
  370. struct wpabuf *req;
  371. u8 lm_exch;
  372. const u8 *buf;
  373. u16 totlen = 0;
  374. size_t len;
  375. /*
  376. * if we're buffering response fragments then just ACK
  377. */
  378. if (data->in_frag_pos) {
  379. wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a fragment!!");
  380. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
  381. EAP_PWD_HDR_SIZE, EAP_CODE_REQUEST, id);
  382. if (req == NULL) {
  383. eap_pwd_state(data, FAILURE);
  384. return NULL;
  385. }
  386. switch (data->state) {
  387. case PWD_ID_Req:
  388. wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
  389. break;
  390. case PWD_Commit_Req:
  391. wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
  392. break;
  393. case PWD_Confirm_Req:
  394. wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
  395. break;
  396. default:
  397. eap_pwd_state(data, FAILURE); /* just to be sure */
  398. wpabuf_free(req);
  399. return NULL;
  400. }
  401. return req;
  402. }
  403. /*
  404. * build the data portion of a request
  405. */
  406. switch (data->state) {
  407. case PWD_ID_Req:
  408. eap_pwd_build_id_req(sm, data, id);
  409. lm_exch = EAP_PWD_OPCODE_ID_EXCH;
  410. break;
  411. case PWD_Commit_Req:
  412. eap_pwd_build_commit_req(sm, data, id);
  413. lm_exch = EAP_PWD_OPCODE_COMMIT_EXCH;
  414. break;
  415. case PWD_Confirm_Req:
  416. eap_pwd_build_confirm_req(sm, data, id);
  417. lm_exch = EAP_PWD_OPCODE_CONFIRM_EXCH;
  418. break;
  419. default:
  420. wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req",
  421. data->state);
  422. eap_pwd_state(data, FAILURE);
  423. lm_exch = 0; /* hush now, sweet compiler */
  424. break;
  425. }
  426. if (data->state == FAILURE)
  427. return NULL;
  428. /*
  429. * determine whether that data needs to be fragmented
  430. */
  431. len = wpabuf_len(data->outbuf) - data->out_frag_pos;
  432. if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
  433. len = data->mtu - EAP_PWD_HDR_SIZE;
  434. EAP_PWD_SET_MORE_BIT(lm_exch);
  435. /*
  436. * if this is the first fragment, need to set the M bit
  437. * and add the total length to the eap_pwd_hdr
  438. */
  439. if (data->out_frag_pos == 0) {
  440. EAP_PWD_SET_LENGTH_BIT(lm_exch);
  441. totlen = wpabuf_len(data->outbuf) +
  442. EAP_PWD_HDR_SIZE + sizeof(u16);
  443. len -= sizeof(u16);
  444. wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, "
  445. "total length = %d", totlen);
  446. }
  447. wpa_printf(MSG_DEBUG, "EAP-pwd: Send a %d byte fragment",
  448. (int) len);
  449. }
  450. /*
  451. * alloc an eap request and populate it with the data
  452. */
  453. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
  454. EAP_PWD_HDR_SIZE + len +
  455. (totlen ? sizeof(u16) : 0),
  456. EAP_CODE_REQUEST, id);
  457. if (req == NULL) {
  458. eap_pwd_state(data, FAILURE);
  459. return NULL;
  460. }
  461. wpabuf_put_u8(req, lm_exch);
  462. if (EAP_PWD_GET_LENGTH_BIT(lm_exch))
  463. wpabuf_put_be16(req, totlen);
  464. buf = wpabuf_head_u8(data->outbuf);
  465. wpabuf_put_data(req, buf + data->out_frag_pos, len);
  466. data->out_frag_pos += len;
  467. /*
  468. * either not fragged or last fragment, either way free up the data
  469. */
  470. if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
  471. wpabuf_free(data->outbuf);
  472. data->outbuf = NULL;
  473. data->out_frag_pos = 0;
  474. }
  475. return req;
  476. }
  477. static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
  478. struct wpabuf *respData)
  479. {
  480. struct eap_pwd_data *data = priv;
  481. const u8 *pos;
  482. size_t len;
  483. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
  484. if (pos == NULL || len < 1) {
  485. wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
  486. return TRUE;
  487. }
  488. wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d",
  489. EAP_PWD_GET_EXCHANGE(*pos), (int) len);
  490. if (data->state == PWD_ID_Req &&
  491. ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
  492. return FALSE;
  493. if (data->state == PWD_Commit_Req &&
  494. ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
  495. return FALSE;
  496. if (data->state == PWD_Confirm_Req &&
  497. ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
  498. return FALSE;
  499. wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
  500. *pos, data->state);
  501. return TRUE;
  502. }
  503. static void eap_pwd_process_id_resp(struct eap_sm *sm,
  504. struct eap_pwd_data *data,
  505. const u8 *payload, size_t payload_len)
  506. {
  507. struct eap_pwd_id *id;
  508. const u8 *password;
  509. size_t password_len;
  510. u8 pwhashhash[16];
  511. int res;
  512. if (payload_len < sizeof(struct eap_pwd_id)) {
  513. wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
  514. return;
  515. }
  516. id = (struct eap_pwd_id *) payload;
  517. if ((data->group_num != be_to_host16(id->group_num)) ||
  518. (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
  519. (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
  520. (id->prf != EAP_PWD_DEFAULT_PRF) ||
  521. id->prep !=
  522. data->password_hash ? EAP_PWD_PREP_MS : EAP_PWD_PREP_NONE) {
  523. wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
  524. eap_pwd_state(data, FAILURE);
  525. return;
  526. }
  527. data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
  528. if (data->id_peer == NULL) {
  529. wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
  530. return;
  531. }
  532. data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
  533. os_memcpy(data->id_peer, id->identity, data->id_peer_len);
  534. wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
  535. data->id_peer, data->id_peer_len);
  536. data->grp = os_zalloc(sizeof(EAP_PWD_group));
  537. if (data->grp == NULL) {
  538. wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
  539. "group");
  540. return;
  541. }
  542. if (data->password_hash) {
  543. res = hash_nt_password_hash(data->password, pwhashhash);
  544. if (res)
  545. return;
  546. password = pwhashhash;
  547. password_len = sizeof(pwhashhash);
  548. } else {
  549. password = data->password;
  550. password_len = data->password_len;
  551. }
  552. res = compute_password_element(data->grp, data->group_num,
  553. password, password_len,
  554. data->id_server, data->id_server_len,
  555. data->id_peer, data->id_peer_len,
  556. (u8 *) &data->token);
  557. os_memset(pwhashhash, 0, sizeof(pwhashhash));
  558. if (res) {
  559. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
  560. "PWE");
  561. return;
  562. }
  563. wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
  564. BN_num_bits(data->grp->prime));
  565. eap_pwd_state(data, PWD_Commit_Req);
  566. }
  567. static void
  568. eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
  569. const u8 *payload, size_t payload_len)
  570. {
  571. u8 *ptr;
  572. BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
  573. EC_POINT *K = NULL, *point = NULL;
  574. int res = 0;
  575. size_t prime_len, order_len;
  576. wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
  577. prime_len = BN_num_bytes(data->grp->prime);
  578. order_len = BN_num_bytes(data->grp->order);
  579. if (payload_len != 2 * prime_len + order_len) {
  580. wpa_printf(MSG_INFO,
  581. "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
  582. (unsigned int) payload_len,
  583. (unsigned int) (2 * prime_len + order_len));
  584. goto fin;
  585. }
  586. if (((data->peer_scalar = BN_new()) == NULL) ||
  587. ((data->k = BN_new()) == NULL) ||
  588. ((cofactor = BN_new()) == NULL) ||
  589. ((x = BN_new()) == NULL) ||
  590. ((y = BN_new()) == NULL) ||
  591. ((point = EC_POINT_new(data->grp->group)) == NULL) ||
  592. ((K = EC_POINT_new(data->grp->group)) == NULL) ||
  593. ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
  594. wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
  595. "fail");
  596. goto fin;
  597. }
  598. if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
  599. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
  600. "cofactor for curve");
  601. goto fin;
  602. }
  603. /* element, x then y, followed by scalar */
  604. ptr = (u8 *) payload;
  605. BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
  606. ptr += BN_num_bytes(data->grp->prime);
  607. BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
  608. ptr += BN_num_bytes(data->grp->prime);
  609. BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
  610. if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
  611. data->peer_element, x, y,
  612. data->bnctx)) {
  613. wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
  614. "fail");
  615. goto fin;
  616. }
  617. /* check to ensure peer's element is not in a small sub-group */
  618. if (BN_cmp(cofactor, BN_value_one())) {
  619. if (!EC_POINT_mul(data->grp->group, point, NULL,
  620. data->peer_element, cofactor, NULL)) {
  621. wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
  622. "multiply peer element by order");
  623. goto fin;
  624. }
  625. if (EC_POINT_is_at_infinity(data->grp->group, point)) {
  626. wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
  627. "is at infinity!\n");
  628. goto fin;
  629. }
  630. }
  631. /* compute the shared key, k */
  632. if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
  633. data->peer_scalar, data->bnctx)) ||
  634. (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
  635. data->bnctx)) ||
  636. (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
  637. data->bnctx))) {
  638. wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
  639. "fail");
  640. goto fin;
  641. }
  642. /* ensure that the shared key isn't in a small sub-group */
  643. if (BN_cmp(cofactor, BN_value_one())) {
  644. if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
  645. NULL)) {
  646. wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
  647. "multiply shared key point by order!\n");
  648. goto fin;
  649. }
  650. }
  651. /*
  652. * This check is strictly speaking just for the case above where
  653. * co-factor > 1 but it was suggested that even though this is probably
  654. * never going to happen it is a simple and safe check "just to be
  655. * sure" so let's be safe.
  656. */
  657. if (EC_POINT_is_at_infinity(data->grp->group, K)) {
  658. wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
  659. "at infinity");
  660. goto fin;
  661. }
  662. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
  663. NULL, data->bnctx)) {
  664. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
  665. "shared secret from secret point");
  666. goto fin;
  667. }
  668. res = 1;
  669. fin:
  670. EC_POINT_clear_free(K);
  671. EC_POINT_clear_free(point);
  672. BN_clear_free(cofactor);
  673. BN_clear_free(x);
  674. BN_clear_free(y);
  675. if (res)
  676. eap_pwd_state(data, PWD_Confirm_Req);
  677. else
  678. eap_pwd_state(data, FAILURE);
  679. }
  680. static void
  681. eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
  682. const u8 *payload, size_t payload_len)
  683. {
  684. BIGNUM *x = NULL, *y = NULL;
  685. struct crypto_hash *hash;
  686. u32 cs;
  687. u16 grp;
  688. u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
  689. int offset;
  690. if (payload_len != SHA256_MAC_LEN) {
  691. wpa_printf(MSG_INFO,
  692. "EAP-pwd: Unexpected Confirm payload length %u (expected %u)",
  693. (unsigned int) payload_len, SHA256_MAC_LEN);
  694. goto fin;
  695. }
  696. /* build up the ciphersuite: group | random_function | prf */
  697. grp = htons(data->group_num);
  698. ptr = (u8 *) &cs;
  699. os_memcpy(ptr, &grp, sizeof(u16));
  700. ptr += sizeof(u16);
  701. *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
  702. ptr += sizeof(u8);
  703. *ptr = EAP_PWD_DEFAULT_PRF;
  704. /* each component of the cruft will be at most as big as the prime */
  705. if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
  706. ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
  707. wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
  708. goto fin;
  709. }
  710. /*
  711. * commit is H(k | peer_element | peer_scalar | server_element |
  712. * server_scalar | ciphersuite)
  713. */
  714. hash = eap_pwd_h_init();
  715. if (hash == NULL)
  716. goto fin;
  717. /* k */
  718. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  719. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
  720. BN_bn2bin(data->k, cruft + offset);
  721. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  722. /* peer element: x, y */
  723. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  724. data->peer_element, x, y,
  725. data->bnctx)) {
  726. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  727. "assignment fail");
  728. goto fin;
  729. }
  730. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  731. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
  732. BN_bn2bin(x, cruft + offset);
  733. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  734. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  735. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
  736. BN_bn2bin(y, cruft + offset);
  737. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  738. /* peer scalar */
  739. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  740. offset = BN_num_bytes(data->grp->order) -
  741. BN_num_bytes(data->peer_scalar);
  742. BN_bn2bin(data->peer_scalar, cruft + offset);
  743. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
  744. /* server element: x, y */
  745. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  746. data->my_element, x, y,
  747. data->bnctx)) {
  748. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  749. "assignment fail");
  750. goto fin;
  751. }
  752. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  753. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
  754. BN_bn2bin(x, cruft + offset);
  755. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  756. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  757. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
  758. BN_bn2bin(y, cruft + offset);
  759. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  760. /* server scalar */
  761. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  762. offset = BN_num_bytes(data->grp->order) -
  763. BN_num_bytes(data->my_scalar);
  764. BN_bn2bin(data->my_scalar, cruft + offset);
  765. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
  766. /* ciphersuite */
  767. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  768. eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
  769. /* all done */
  770. eap_pwd_h_final(hash, conf);
  771. ptr = (u8 *) payload;
  772. if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
  773. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
  774. "verify");
  775. goto fin;
  776. }
  777. wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
  778. if (compute_keys(data->grp, data->bnctx, data->k,
  779. data->peer_scalar, data->my_scalar, conf,
  780. data->my_confirm, &cs, data->msk, data->emsk,
  781. data->session_id) < 0)
  782. eap_pwd_state(data, FAILURE);
  783. else
  784. eap_pwd_state(data, SUCCESS);
  785. fin:
  786. bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
  787. BN_clear_free(x);
  788. BN_clear_free(y);
  789. }
  790. static void eap_pwd_process(struct eap_sm *sm, void *priv,
  791. struct wpabuf *respData)
  792. {
  793. struct eap_pwd_data *data = priv;
  794. const u8 *pos;
  795. size_t len;
  796. u8 lm_exch;
  797. u16 tot_len;
  798. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
  799. if ((pos == NULL) || (len < 1)) {
  800. wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
  801. (pos == NULL) ? "is NULL" : "is not NULL",
  802. (int) len);
  803. return;
  804. }
  805. lm_exch = *pos;
  806. pos++; /* skip over the bits and the exch */
  807. len--;
  808. /*
  809. * if we're fragmenting then this should be an ACK with no data,
  810. * just return and continue fragmenting in the "build" section above
  811. */
  812. if (data->out_frag_pos) {
  813. if (len > 1)
  814. wpa_printf(MSG_INFO, "EAP-pwd: Bad response! "
  815. "Fragmenting but not an ACK");
  816. else
  817. wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from "
  818. "peer");
  819. return;
  820. }
  821. /*
  822. * if we're receiving fragmented packets then we need to buffer...
  823. *
  824. * the first fragment has a total length
  825. */
  826. if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
  827. if (len < 2) {
  828. wpa_printf(MSG_DEBUG,
  829. "EAP-pwd: Frame too short to contain Total-Length field");
  830. return;
  831. }
  832. tot_len = WPA_GET_BE16(pos);
  833. wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
  834. "length = %d", tot_len);
  835. if (tot_len > 15000)
  836. return;
  837. if (data->inbuf) {
  838. wpa_printf(MSG_DEBUG,
  839. "EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
  840. return;
  841. }
  842. data->inbuf = wpabuf_alloc(tot_len);
  843. if (data->inbuf == NULL) {
  844. wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
  845. "buffer fragments!");
  846. return;
  847. }
  848. data->in_frag_pos = 0;
  849. pos += sizeof(u16);
  850. len -= sizeof(u16);
  851. }
  852. /*
  853. * the first and all intermediate fragments have the M bit set
  854. */
  855. if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
  856. if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
  857. wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
  858. "attack detected! (%d+%d > %d)",
  859. (int) data->in_frag_pos, (int) len,
  860. (int) wpabuf_size(data->inbuf));
  861. eap_pwd_state(data, FAILURE);
  862. return;
  863. }
  864. wpabuf_put_data(data->inbuf, pos, len);
  865. data->in_frag_pos += len;
  866. }
  867. if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
  868. wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
  869. (int) len);
  870. return;
  871. }
  872. /*
  873. * last fragment won't have the M bit set (but we're obviously
  874. * buffering fragments so that's how we know it's the last)
  875. */
  876. if (data->in_frag_pos) {
  877. pos = wpabuf_head_u8(data->inbuf);
  878. len = data->in_frag_pos;
  879. wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
  880. (int) len);
  881. }
  882. switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
  883. case EAP_PWD_OPCODE_ID_EXCH:
  884. eap_pwd_process_id_resp(sm, data, pos, len);
  885. break;
  886. case EAP_PWD_OPCODE_COMMIT_EXCH:
  887. eap_pwd_process_commit_resp(sm, data, pos, len);
  888. break;
  889. case EAP_PWD_OPCODE_CONFIRM_EXCH:
  890. eap_pwd_process_confirm_resp(sm, data, pos, len);
  891. break;
  892. }
  893. /*
  894. * if we had been buffering fragments, here's a great place
  895. * to clean up
  896. */
  897. if (data->in_frag_pos) {
  898. wpabuf_free(data->inbuf);
  899. data->inbuf = NULL;
  900. data->in_frag_pos = 0;
  901. }
  902. }
  903. static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
  904. {
  905. struct eap_pwd_data *data = priv;
  906. u8 *key;
  907. if (data->state != SUCCESS)
  908. return NULL;
  909. key = os_memdup(data->msk, EAP_MSK_LEN);
  910. if (key == NULL)
  911. return NULL;
  912. *len = EAP_MSK_LEN;
  913. return key;
  914. }
  915. static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  916. {
  917. struct eap_pwd_data *data = priv;
  918. u8 *key;
  919. if (data->state != SUCCESS)
  920. return NULL;
  921. key = os_memdup(data->emsk, EAP_EMSK_LEN);
  922. if (key == NULL)
  923. return NULL;
  924. *len = EAP_EMSK_LEN;
  925. return key;
  926. }
  927. static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
  928. {
  929. struct eap_pwd_data *data = priv;
  930. return data->state == SUCCESS;
  931. }
  932. static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
  933. {
  934. struct eap_pwd_data *data = priv;
  935. return (data->state == SUCCESS) || (data->state == FAILURE);
  936. }
  937. static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
  938. {
  939. struct eap_pwd_data *data = priv;
  940. u8 *id;
  941. if (data->state != SUCCESS)
  942. return NULL;
  943. id = os_memdup(data->session_id, 1 + SHA256_MAC_LEN);
  944. if (id == NULL)
  945. return NULL;
  946. *len = 1 + SHA256_MAC_LEN;
  947. return id;
  948. }
  949. int eap_server_pwd_register(void)
  950. {
  951. struct eap_method *eap;
  952. struct timeval tp;
  953. struct timezone tz;
  954. u32 sr;
  955. sr = 0xdeaddada;
  956. (void) gettimeofday(&tp, &tz);
  957. sr ^= (tp.tv_sec ^ tp.tv_usec);
  958. srandom(sr);
  959. eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
  960. EAP_VENDOR_IETF, EAP_TYPE_PWD,
  961. "PWD");
  962. if (eap == NULL)
  963. return -1;
  964. eap->init = eap_pwd_init;
  965. eap->reset = eap_pwd_reset;
  966. eap->buildReq = eap_pwd_build_req;
  967. eap->check = eap_pwd_check;
  968. eap->process = eap_pwd_process;
  969. eap->isDone = eap_pwd_is_done;
  970. eap->getKey = eap_pwd_getkey;
  971. eap->get_emsk = eap_pwd_get_emsk;
  972. eap->isSuccess = eap_pwd_is_success;
  973. eap->getSessionId = eap_pwd_get_session_id;
  974. return eap_server_method_register(eap);
  975. }