eap_server_pwd.c 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  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. wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
  522. eap_pwd_state(data, FAILURE);
  523. return;
  524. }
  525. data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
  526. if (data->id_peer == NULL) {
  527. wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
  528. return;
  529. }
  530. data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
  531. os_memcpy(data->id_peer, id->identity, data->id_peer_len);
  532. wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
  533. data->id_peer, data->id_peer_len);
  534. data->grp = os_zalloc(sizeof(EAP_PWD_group));
  535. if (data->grp == NULL) {
  536. wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
  537. "group");
  538. return;
  539. }
  540. if (data->password_hash) {
  541. res = hash_nt_password_hash(data->password, pwhashhash);
  542. if (res)
  543. return;
  544. password = pwhashhash;
  545. password_len = sizeof(pwhashhash);
  546. } else {
  547. password = data->password;
  548. password_len = data->password_len;
  549. }
  550. res = compute_password_element(data->grp, data->group_num,
  551. password, password_len,
  552. data->id_server, data->id_server_len,
  553. data->id_peer, data->id_peer_len,
  554. (u8 *) &data->token);
  555. os_memset(pwhashhash, 0, sizeof(pwhashhash));
  556. if (res) {
  557. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
  558. "PWE");
  559. return;
  560. }
  561. wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
  562. BN_num_bits(data->grp->prime));
  563. eap_pwd_state(data, PWD_Commit_Req);
  564. }
  565. static void
  566. eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
  567. const u8 *payload, size_t payload_len)
  568. {
  569. u8 *ptr;
  570. BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
  571. EC_POINT *K = NULL, *point = NULL;
  572. int res = 0;
  573. size_t prime_len, order_len;
  574. wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
  575. prime_len = BN_num_bytes(data->grp->prime);
  576. order_len = BN_num_bytes(data->grp->order);
  577. if (payload_len != 2 * prime_len + order_len) {
  578. wpa_printf(MSG_INFO,
  579. "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
  580. (unsigned int) payload_len,
  581. (unsigned int) (2 * prime_len + order_len));
  582. goto fin;
  583. }
  584. if (((data->peer_scalar = BN_new()) == NULL) ||
  585. ((data->k = BN_new()) == NULL) ||
  586. ((cofactor = BN_new()) == NULL) ||
  587. ((x = BN_new()) == NULL) ||
  588. ((y = BN_new()) == NULL) ||
  589. ((point = EC_POINT_new(data->grp->group)) == NULL) ||
  590. ((K = EC_POINT_new(data->grp->group)) == NULL) ||
  591. ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
  592. wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
  593. "fail");
  594. goto fin;
  595. }
  596. if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
  597. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
  598. "cofactor for curve");
  599. goto fin;
  600. }
  601. /* element, x then y, followed by scalar */
  602. ptr = (u8 *) payload;
  603. BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
  604. ptr += BN_num_bytes(data->grp->prime);
  605. BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
  606. ptr += BN_num_bytes(data->grp->prime);
  607. BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
  608. if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
  609. data->peer_element, x, y,
  610. data->bnctx)) {
  611. wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
  612. "fail");
  613. goto fin;
  614. }
  615. /* check to ensure peer's element is not in a small sub-group */
  616. if (BN_cmp(cofactor, BN_value_one())) {
  617. if (!EC_POINT_mul(data->grp->group, point, NULL,
  618. data->peer_element, cofactor, NULL)) {
  619. wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
  620. "multiply peer element by order");
  621. goto fin;
  622. }
  623. if (EC_POINT_is_at_infinity(data->grp->group, point)) {
  624. wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
  625. "is at infinity!\n");
  626. goto fin;
  627. }
  628. }
  629. /* compute the shared key, k */
  630. if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
  631. data->peer_scalar, data->bnctx)) ||
  632. (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
  633. data->bnctx)) ||
  634. (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
  635. data->bnctx))) {
  636. wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
  637. "fail");
  638. goto fin;
  639. }
  640. /* ensure that the shared key isn't in a small sub-group */
  641. if (BN_cmp(cofactor, BN_value_one())) {
  642. if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
  643. NULL)) {
  644. wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
  645. "multiply shared key point by order!\n");
  646. goto fin;
  647. }
  648. }
  649. /*
  650. * This check is strictly speaking just for the case above where
  651. * co-factor > 1 but it was suggested that even though this is probably
  652. * never going to happen it is a simple and safe check "just to be
  653. * sure" so let's be safe.
  654. */
  655. if (EC_POINT_is_at_infinity(data->grp->group, K)) {
  656. wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
  657. "at infinity");
  658. goto fin;
  659. }
  660. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
  661. NULL, data->bnctx)) {
  662. wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
  663. "shared secret from secret point");
  664. goto fin;
  665. }
  666. res = 1;
  667. fin:
  668. EC_POINT_clear_free(K);
  669. EC_POINT_clear_free(point);
  670. BN_clear_free(cofactor);
  671. BN_clear_free(x);
  672. BN_clear_free(y);
  673. if (res)
  674. eap_pwd_state(data, PWD_Confirm_Req);
  675. else
  676. eap_pwd_state(data, FAILURE);
  677. }
  678. static void
  679. eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
  680. const u8 *payload, size_t payload_len)
  681. {
  682. BIGNUM *x = NULL, *y = NULL;
  683. struct crypto_hash *hash;
  684. u32 cs;
  685. u16 grp;
  686. u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
  687. int offset;
  688. if (payload_len != SHA256_MAC_LEN) {
  689. wpa_printf(MSG_INFO,
  690. "EAP-pwd: Unexpected Confirm payload length %u (expected %u)",
  691. (unsigned int) payload_len, SHA256_MAC_LEN);
  692. goto fin;
  693. }
  694. /* build up the ciphersuite: group | random_function | prf */
  695. grp = htons(data->group_num);
  696. ptr = (u8 *) &cs;
  697. os_memcpy(ptr, &grp, sizeof(u16));
  698. ptr += sizeof(u16);
  699. *ptr = EAP_PWD_DEFAULT_RAND_FUNC;
  700. ptr += sizeof(u8);
  701. *ptr = EAP_PWD_DEFAULT_PRF;
  702. /* each component of the cruft will be at most as big as the prime */
  703. if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
  704. ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
  705. wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
  706. goto fin;
  707. }
  708. /*
  709. * commit is H(k | peer_element | peer_scalar | server_element |
  710. * server_scalar | ciphersuite)
  711. */
  712. hash = eap_pwd_h_init();
  713. if (hash == NULL)
  714. goto fin;
  715. /* k */
  716. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  717. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
  718. BN_bn2bin(data->k, cruft + offset);
  719. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  720. /* peer element: x, y */
  721. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  722. data->peer_element, x, y,
  723. data->bnctx)) {
  724. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  725. "assignment fail");
  726. goto fin;
  727. }
  728. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  729. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
  730. BN_bn2bin(x, cruft + offset);
  731. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  732. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  733. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
  734. BN_bn2bin(y, cruft + offset);
  735. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  736. /* peer scalar */
  737. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  738. offset = BN_num_bytes(data->grp->order) -
  739. BN_num_bytes(data->peer_scalar);
  740. BN_bn2bin(data->peer_scalar, cruft + offset);
  741. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
  742. /* server element: x, y */
  743. if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
  744. data->my_element, x, y,
  745. data->bnctx)) {
  746. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
  747. "assignment fail");
  748. goto fin;
  749. }
  750. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  751. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
  752. BN_bn2bin(x, cruft + offset);
  753. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  754. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  755. offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
  756. BN_bn2bin(y, cruft + offset);
  757. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
  758. /* server scalar */
  759. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  760. offset = BN_num_bytes(data->grp->order) -
  761. BN_num_bytes(data->my_scalar);
  762. BN_bn2bin(data->my_scalar, cruft + offset);
  763. eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
  764. /* ciphersuite */
  765. os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
  766. eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
  767. /* all done */
  768. eap_pwd_h_final(hash, conf);
  769. ptr = (u8 *) payload;
  770. if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
  771. wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
  772. "verify");
  773. goto fin;
  774. }
  775. wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
  776. if (compute_keys(data->grp, data->bnctx, data->k,
  777. data->peer_scalar, data->my_scalar, conf,
  778. data->my_confirm, &cs, data->msk, data->emsk,
  779. data->session_id) < 0)
  780. eap_pwd_state(data, FAILURE);
  781. else
  782. eap_pwd_state(data, SUCCESS);
  783. fin:
  784. bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
  785. BN_clear_free(x);
  786. BN_clear_free(y);
  787. }
  788. static void eap_pwd_process(struct eap_sm *sm, void *priv,
  789. struct wpabuf *respData)
  790. {
  791. struct eap_pwd_data *data = priv;
  792. const u8 *pos;
  793. size_t len;
  794. u8 lm_exch;
  795. u16 tot_len;
  796. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
  797. if ((pos == NULL) || (len < 1)) {
  798. wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
  799. (pos == NULL) ? "is NULL" : "is not NULL",
  800. (int) len);
  801. return;
  802. }
  803. lm_exch = *pos;
  804. pos++; /* skip over the bits and the exch */
  805. len--;
  806. /*
  807. * if we're fragmenting then this should be an ACK with no data,
  808. * just return and continue fragmenting in the "build" section above
  809. */
  810. if (data->out_frag_pos) {
  811. if (len > 1)
  812. wpa_printf(MSG_INFO, "EAP-pwd: Bad response! "
  813. "Fragmenting but not an ACK");
  814. else
  815. wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from "
  816. "peer");
  817. return;
  818. }
  819. /*
  820. * if we're receiving fragmented packets then we need to buffer...
  821. *
  822. * the first fragment has a total length
  823. */
  824. if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
  825. if (len < 2) {
  826. wpa_printf(MSG_DEBUG,
  827. "EAP-pwd: Frame too short to contain Total-Length field");
  828. return;
  829. }
  830. tot_len = WPA_GET_BE16(pos);
  831. wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
  832. "length = %d", tot_len);
  833. if (tot_len > 15000)
  834. return;
  835. if (data->inbuf) {
  836. wpa_printf(MSG_DEBUG,
  837. "EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
  838. return;
  839. }
  840. data->inbuf = wpabuf_alloc(tot_len);
  841. if (data->inbuf == NULL) {
  842. wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
  843. "buffer fragments!");
  844. return;
  845. }
  846. data->in_frag_pos = 0;
  847. pos += sizeof(u16);
  848. len -= sizeof(u16);
  849. }
  850. /*
  851. * the first and all intermediate fragments have the M bit set
  852. */
  853. if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
  854. if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
  855. wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
  856. "attack detected! (%d+%d > %d)",
  857. (int) data->in_frag_pos, (int) len,
  858. (int) wpabuf_size(data->inbuf));
  859. eap_pwd_state(data, FAILURE);
  860. return;
  861. }
  862. wpabuf_put_data(data->inbuf, pos, len);
  863. data->in_frag_pos += len;
  864. }
  865. if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
  866. wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
  867. (int) len);
  868. return;
  869. }
  870. /*
  871. * last fragment won't have the M bit set (but we're obviously
  872. * buffering fragments so that's how we know it's the last)
  873. */
  874. if (data->in_frag_pos) {
  875. pos = wpabuf_head_u8(data->inbuf);
  876. len = data->in_frag_pos;
  877. wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
  878. (int) len);
  879. }
  880. switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
  881. case EAP_PWD_OPCODE_ID_EXCH:
  882. eap_pwd_process_id_resp(sm, data, pos, len);
  883. break;
  884. case EAP_PWD_OPCODE_COMMIT_EXCH:
  885. eap_pwd_process_commit_resp(sm, data, pos, len);
  886. break;
  887. case EAP_PWD_OPCODE_CONFIRM_EXCH:
  888. eap_pwd_process_confirm_resp(sm, data, pos, len);
  889. break;
  890. }
  891. /*
  892. * if we had been buffering fragments, here's a great place
  893. * to clean up
  894. */
  895. if (data->in_frag_pos) {
  896. wpabuf_free(data->inbuf);
  897. data->inbuf = NULL;
  898. data->in_frag_pos = 0;
  899. }
  900. }
  901. static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
  902. {
  903. struct eap_pwd_data *data = priv;
  904. u8 *key;
  905. if (data->state != SUCCESS)
  906. return NULL;
  907. key = os_malloc(EAP_MSK_LEN);
  908. if (key == NULL)
  909. return NULL;
  910. os_memcpy(key, data->msk, EAP_MSK_LEN);
  911. *len = EAP_MSK_LEN;
  912. return key;
  913. }
  914. static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  915. {
  916. struct eap_pwd_data *data = priv;
  917. u8 *key;
  918. if (data->state != SUCCESS)
  919. return NULL;
  920. key = os_malloc(EAP_EMSK_LEN);
  921. if (key == NULL)
  922. return NULL;
  923. os_memcpy(key, data->emsk, EAP_EMSK_LEN);
  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_malloc(1 + SHA256_MAC_LEN);
  944. if (id == NULL)
  945. return NULL;
  946. os_memcpy(id, data->session_id, 1 + SHA256_MAC_LEN);
  947. *len = 1 + SHA256_MAC_LEN;
  948. return id;
  949. }
  950. int eap_server_pwd_register(void)
  951. {
  952. struct eap_method *eap;
  953. struct timeval tp;
  954. struct timezone tz;
  955. u32 sr;
  956. sr = 0xdeaddada;
  957. (void) gettimeofday(&tp, &tz);
  958. sr ^= (tp.tv_sec ^ tp.tv_usec);
  959. srandom(sr);
  960. eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
  961. EAP_VENDOR_IETF, EAP_TYPE_PWD,
  962. "PWD");
  963. if (eap == NULL)
  964. return -1;
  965. eap->init = eap_pwd_init;
  966. eap->reset = eap_pwd_reset;
  967. eap->buildReq = eap_pwd_build_req;
  968. eap->check = eap_pwd_check;
  969. eap->process = eap_pwd_process;
  970. eap->isDone = eap_pwd_is_done;
  971. eap->getKey = eap_pwd_getkey;
  972. eap->get_emsk = eap_pwd_get_emsk;
  973. eap->isSuccess = eap_pwd_is_success;
  974. eap->getSessionId = eap_pwd_get_session_id;
  975. return eap_server_method_register(eap);
  976. }