eap_gpsk.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. /*
  2. * EAP peer method: EAP-GPSK (RFC 5433)
  3. * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "crypto/random.h"
  17. #include "eap_peer/eap_i.h"
  18. #include "eap_common/eap_gpsk_common.h"
  19. struct eap_gpsk_data {
  20. enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
  21. u8 rand_server[EAP_GPSK_RAND_LEN];
  22. u8 rand_peer[EAP_GPSK_RAND_LEN];
  23. u8 msk[EAP_MSK_LEN];
  24. u8 emsk[EAP_EMSK_LEN];
  25. u8 sk[EAP_GPSK_MAX_SK_LEN];
  26. size_t sk_len;
  27. u8 pk[EAP_GPSK_MAX_PK_LEN];
  28. size_t pk_len;
  29. u8 session_id;
  30. int session_id_set;
  31. u8 *id_peer;
  32. size_t id_peer_len;
  33. u8 *id_server;
  34. size_t id_server_len;
  35. int vendor; /* CSuite/Specifier */
  36. int specifier; /* CSuite/Specifier */
  37. u8 *psk;
  38. size_t psk_len;
  39. };
  40. static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
  41. u8 identifier,
  42. const u8 *csuite_list,
  43. size_t csuite_list_len);
  44. static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
  45. u8 identifier);
  46. #ifndef CONFIG_NO_STDOUT_DEBUG
  47. static const char * eap_gpsk_state_txt(int state)
  48. {
  49. switch (state) {
  50. case GPSK_1:
  51. return "GPSK-1";
  52. case GPSK_3:
  53. return "GPSK-3";
  54. case SUCCESS:
  55. return "SUCCESS";
  56. case FAILURE:
  57. return "FAILURE";
  58. default:
  59. return "?";
  60. }
  61. }
  62. #endif /* CONFIG_NO_STDOUT_DEBUG */
  63. static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
  64. {
  65. wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
  66. eap_gpsk_state_txt(data->state),
  67. eap_gpsk_state_txt(state));
  68. data->state = state;
  69. }
  70. static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
  71. static void * eap_gpsk_init(struct eap_sm *sm)
  72. {
  73. struct eap_gpsk_data *data;
  74. const u8 *identity, *password;
  75. size_t identity_len, password_len;
  76. password = eap_get_config_password(sm, &password_len);
  77. if (password == NULL) {
  78. wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
  79. return NULL;
  80. }
  81. data = os_zalloc(sizeof(*data));
  82. if (data == NULL)
  83. return NULL;
  84. data->state = GPSK_1;
  85. identity = eap_get_config_identity(sm, &identity_len);
  86. if (identity) {
  87. data->id_peer = os_malloc(identity_len);
  88. if (data->id_peer == NULL) {
  89. eap_gpsk_deinit(sm, data);
  90. return NULL;
  91. }
  92. os_memcpy(data->id_peer, identity, identity_len);
  93. data->id_peer_len = identity_len;
  94. }
  95. data->psk = os_malloc(password_len);
  96. if (data->psk == NULL) {
  97. eap_gpsk_deinit(sm, data);
  98. return NULL;
  99. }
  100. os_memcpy(data->psk, password, password_len);
  101. data->psk_len = password_len;
  102. return data;
  103. }
  104. static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
  105. {
  106. struct eap_gpsk_data *data = priv;
  107. os_free(data->id_server);
  108. os_free(data->id_peer);
  109. os_free(data->psk);
  110. os_free(data);
  111. }
  112. static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
  113. const u8 *pos, const u8 *end)
  114. {
  115. u16 alen;
  116. if (end - pos < 2) {
  117. wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
  118. return NULL;
  119. }
  120. alen = WPA_GET_BE16(pos);
  121. pos += 2;
  122. if (end - pos < alen) {
  123. wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
  124. return NULL;
  125. }
  126. os_free(data->id_server);
  127. data->id_server = os_malloc(alen);
  128. if (data->id_server == NULL) {
  129. wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
  130. return NULL;
  131. }
  132. os_memcpy(data->id_server, pos, alen);
  133. data->id_server_len = alen;
  134. wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
  135. data->id_server, data->id_server_len);
  136. pos += alen;
  137. return pos;
  138. }
  139. static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
  140. const u8 *pos, const u8 *end)
  141. {
  142. if (pos == NULL)
  143. return NULL;
  144. if (end - pos < EAP_GPSK_RAND_LEN) {
  145. wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
  146. return NULL;
  147. }
  148. os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
  149. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
  150. data->rand_server, EAP_GPSK_RAND_LEN);
  151. pos += EAP_GPSK_RAND_LEN;
  152. return pos;
  153. }
  154. static int eap_gpsk_select_csuite(struct eap_sm *sm,
  155. struct eap_gpsk_data *data,
  156. const u8 *csuite_list,
  157. size_t csuite_list_len)
  158. {
  159. struct eap_gpsk_csuite *csuite;
  160. int i, count;
  161. count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
  162. data->vendor = EAP_GPSK_VENDOR_IETF;
  163. data->specifier = EAP_GPSK_CIPHER_RESERVED;
  164. csuite = (struct eap_gpsk_csuite *) csuite_list;
  165. for (i = 0; i < count; i++) {
  166. int vendor, specifier;
  167. vendor = WPA_GET_BE32(csuite->vendor);
  168. specifier = WPA_GET_BE16(csuite->specifier);
  169. wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
  170. i, vendor, specifier);
  171. if (data->vendor == EAP_GPSK_VENDOR_IETF &&
  172. data->specifier == EAP_GPSK_CIPHER_RESERVED &&
  173. eap_gpsk_supported_ciphersuite(vendor, specifier)) {
  174. data->vendor = vendor;
  175. data->specifier = specifier;
  176. }
  177. csuite++;
  178. }
  179. if (data->vendor == EAP_GPSK_VENDOR_IETF &&
  180. data->specifier == EAP_GPSK_CIPHER_RESERVED) {
  181. wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
  182. "ciphersuite found");
  183. return -1;
  184. }
  185. wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
  186. data->vendor, data->specifier);
  187. return 0;
  188. }
  189. static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
  190. struct eap_gpsk_data *data,
  191. const u8 **list,
  192. size_t *list_len,
  193. const u8 *pos, const u8 *end)
  194. {
  195. if (pos == NULL)
  196. return NULL;
  197. if (end - pos < 2) {
  198. wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
  199. return NULL;
  200. }
  201. *list_len = WPA_GET_BE16(pos);
  202. pos += 2;
  203. if (end - pos < (int) *list_len) {
  204. wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
  205. return NULL;
  206. }
  207. if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
  208. wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
  209. (unsigned long) *list_len);
  210. return NULL;
  211. }
  212. *list = pos;
  213. pos += *list_len;
  214. if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
  215. return NULL;
  216. return pos;
  217. }
  218. static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
  219. struct eap_gpsk_data *data,
  220. struct eap_method_ret *ret,
  221. const struct wpabuf *reqData,
  222. const u8 *payload,
  223. size_t payload_len)
  224. {
  225. size_t csuite_list_len;
  226. const u8 *csuite_list, *pos, *end;
  227. struct wpabuf *resp;
  228. if (data->state != GPSK_1) {
  229. ret->ignore = TRUE;
  230. return NULL;
  231. }
  232. wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
  233. end = payload + payload_len;
  234. pos = eap_gpsk_process_id_server(data, payload, end);
  235. pos = eap_gpsk_process_rand_server(data, pos, end);
  236. pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
  237. &csuite_list_len, pos, end);
  238. if (pos == NULL) {
  239. eap_gpsk_state(data, FAILURE);
  240. return NULL;
  241. }
  242. resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData),
  243. csuite_list, csuite_list_len);
  244. if (resp == NULL)
  245. return NULL;
  246. eap_gpsk_state(data, GPSK_3);
  247. return resp;
  248. }
  249. static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
  250. u8 identifier,
  251. const u8 *csuite_list,
  252. size_t csuite_list_len)
  253. {
  254. struct wpabuf *resp;
  255. size_t len, miclen;
  256. u8 *rpos, *start;
  257. struct eap_gpsk_csuite *csuite;
  258. wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
  259. miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
  260. len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
  261. 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
  262. sizeof(struct eap_gpsk_csuite) + 2 + miclen;
  263. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
  264. EAP_CODE_RESPONSE, identifier);
  265. if (resp == NULL)
  266. return NULL;
  267. wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
  268. start = wpabuf_put(resp, 0);
  269. wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
  270. data->id_peer, data->id_peer_len);
  271. wpabuf_put_be16(resp, data->id_peer_len);
  272. wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
  273. wpabuf_put_be16(resp, data->id_server_len);
  274. wpabuf_put_data(resp, data->id_server, data->id_server_len);
  275. if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
  276. wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
  277. "for RAND_Peer");
  278. eap_gpsk_state(data, FAILURE);
  279. wpabuf_free(resp);
  280. return NULL;
  281. }
  282. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
  283. data->rand_peer, EAP_GPSK_RAND_LEN);
  284. wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
  285. wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
  286. wpabuf_put_be16(resp, csuite_list_len);
  287. wpabuf_put_data(resp, csuite_list, csuite_list_len);
  288. csuite = wpabuf_put(resp, sizeof(*csuite));
  289. WPA_PUT_BE32(csuite->vendor, data->vendor);
  290. WPA_PUT_BE16(csuite->specifier, data->specifier);
  291. if (eap_gpsk_derive_keys(data->psk, data->psk_len,
  292. data->vendor, data->specifier,
  293. data->rand_peer, data->rand_server,
  294. data->id_peer, data->id_peer_len,
  295. data->id_server, data->id_server_len,
  296. data->msk, data->emsk,
  297. data->sk, &data->sk_len,
  298. data->pk, &data->pk_len) < 0) {
  299. wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
  300. eap_gpsk_state(data, FAILURE);
  301. wpabuf_free(resp);
  302. return NULL;
  303. }
  304. /* No PD_Payload_1 */
  305. wpabuf_put_be16(resp, 0);
  306. rpos = wpabuf_put(resp, miclen);
  307. if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
  308. data->specifier, start, rpos - start, rpos) <
  309. 0) {
  310. eap_gpsk_state(data, FAILURE);
  311. wpabuf_free(resp);
  312. return NULL;
  313. }
  314. return resp;
  315. }
  316. static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
  317. const u8 *pos, const u8 *end)
  318. {
  319. if (end - pos < EAP_GPSK_RAND_LEN) {
  320. wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
  321. "RAND_Peer");
  322. return NULL;
  323. }
  324. if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
  325. wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
  326. "GPSK-3 did not match");
  327. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
  328. data->rand_peer, EAP_GPSK_RAND_LEN);
  329. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
  330. pos, EAP_GPSK_RAND_LEN);
  331. return NULL;
  332. }
  333. pos += EAP_GPSK_RAND_LEN;
  334. if (end - pos < EAP_GPSK_RAND_LEN) {
  335. wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
  336. "RAND_Server");
  337. return NULL;
  338. }
  339. if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
  340. wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
  341. "GPSK-3 did not match");
  342. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
  343. data->rand_server, EAP_GPSK_RAND_LEN);
  344. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
  345. pos, EAP_GPSK_RAND_LEN);
  346. return NULL;
  347. }
  348. pos += EAP_GPSK_RAND_LEN;
  349. return pos;
  350. }
  351. static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
  352. const u8 *pos, const u8 *end)
  353. {
  354. size_t len;
  355. if (pos == NULL)
  356. return NULL;
  357. if (end - pos < (int) 2) {
  358. wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
  359. "length(ID_Server)");
  360. return NULL;
  361. }
  362. len = WPA_GET_BE16(pos);
  363. pos += 2;
  364. if (end - pos < (int) len) {
  365. wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
  366. "ID_Server");
  367. return NULL;
  368. }
  369. if (len != data->id_server_len ||
  370. os_memcmp(pos, data->id_server, len) != 0) {
  371. wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
  372. "the one used in GPSK-1");
  373. wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
  374. data->id_server, data->id_server_len);
  375. wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
  376. pos, len);
  377. return NULL;
  378. }
  379. pos += len;
  380. return pos;
  381. }
  382. static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
  383. const u8 *pos, const u8 *end)
  384. {
  385. int vendor, specifier;
  386. const struct eap_gpsk_csuite *csuite;
  387. if (pos == NULL)
  388. return NULL;
  389. if (end - pos < (int) sizeof(*csuite)) {
  390. wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
  391. "CSuite_Sel");
  392. return NULL;
  393. }
  394. csuite = (const struct eap_gpsk_csuite *) pos;
  395. vendor = WPA_GET_BE32(csuite->vendor);
  396. specifier = WPA_GET_BE16(csuite->specifier);
  397. pos += sizeof(*csuite);
  398. if (vendor != data->vendor || specifier != data->specifier) {
  399. wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
  400. "match with the one sent in GPSK-2 (%d:%d)",
  401. vendor, specifier, data->vendor, data->specifier);
  402. return NULL;
  403. }
  404. return pos;
  405. }
  406. static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
  407. const u8 *pos, const u8 *end)
  408. {
  409. u16 alen;
  410. if (pos == NULL)
  411. return NULL;
  412. if (end - pos < 2) {
  413. wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
  414. "PD_Payload_2 length");
  415. return NULL;
  416. }
  417. alen = WPA_GET_BE16(pos);
  418. pos += 2;
  419. if (end - pos < alen) {
  420. wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
  421. "%d-octet PD_Payload_2", alen);
  422. return NULL;
  423. }
  424. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
  425. pos += alen;
  426. return pos;
  427. }
  428. static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
  429. const u8 *payload,
  430. const u8 *pos, const u8 *end)
  431. {
  432. size_t miclen;
  433. u8 mic[EAP_GPSK_MAX_MIC_LEN];
  434. if (pos == NULL)
  435. return NULL;
  436. miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
  437. if (end - pos < (int) miclen) {
  438. wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
  439. "(left=%lu miclen=%lu)",
  440. (unsigned long) (end - pos),
  441. (unsigned long) miclen);
  442. return NULL;
  443. }
  444. if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
  445. data->specifier, payload, pos - payload, mic)
  446. < 0) {
  447. wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
  448. return NULL;
  449. }
  450. if (os_memcmp(mic, pos, miclen) != 0) {
  451. wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
  452. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
  453. wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
  454. return NULL;
  455. }
  456. pos += miclen;
  457. return pos;
  458. }
  459. static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
  460. struct eap_gpsk_data *data,
  461. struct eap_method_ret *ret,
  462. const struct wpabuf *reqData,
  463. const u8 *payload,
  464. size_t payload_len)
  465. {
  466. struct wpabuf *resp;
  467. const u8 *pos, *end;
  468. if (data->state != GPSK_3) {
  469. ret->ignore = TRUE;
  470. return NULL;
  471. }
  472. wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
  473. end = payload + payload_len;
  474. pos = eap_gpsk_validate_rand(data, payload, end);
  475. pos = eap_gpsk_validate_id_server(data, pos, end);
  476. pos = eap_gpsk_validate_csuite(data, pos, end);
  477. pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
  478. pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
  479. if (pos == NULL) {
  480. eap_gpsk_state(data, FAILURE);
  481. return NULL;
  482. }
  483. if (pos != end) {
  484. wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
  485. "data in the end of GPSK-2",
  486. (unsigned long) (end - pos));
  487. }
  488. resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
  489. if (resp == NULL)
  490. return NULL;
  491. eap_gpsk_state(data, SUCCESS);
  492. ret->methodState = METHOD_DONE;
  493. ret->decision = DECISION_UNCOND_SUCC;
  494. return resp;
  495. }
  496. static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
  497. u8 identifier)
  498. {
  499. struct wpabuf *resp;
  500. u8 *rpos, *start;
  501. size_t mlen;
  502. wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
  503. mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
  504. resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
  505. EAP_CODE_RESPONSE, identifier);
  506. if (resp == NULL)
  507. return NULL;
  508. wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
  509. start = wpabuf_put(resp, 0);
  510. /* No PD_Payload_3 */
  511. wpabuf_put_be16(resp, 0);
  512. rpos = wpabuf_put(resp, mlen);
  513. if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
  514. data->specifier, start, rpos - start, rpos) <
  515. 0) {
  516. eap_gpsk_state(data, FAILURE);
  517. wpabuf_free(resp);
  518. return NULL;
  519. }
  520. return resp;
  521. }
  522. static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
  523. struct eap_method_ret *ret,
  524. const struct wpabuf *reqData)
  525. {
  526. struct eap_gpsk_data *data = priv;
  527. struct wpabuf *resp;
  528. const u8 *pos;
  529. size_t len;
  530. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
  531. if (pos == NULL || len < 1) {
  532. ret->ignore = TRUE;
  533. return NULL;
  534. }
  535. wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
  536. ret->ignore = FALSE;
  537. ret->methodState = METHOD_MAY_CONT;
  538. ret->decision = DECISION_FAIL;
  539. ret->allowNotifications = FALSE;
  540. switch (*pos) {
  541. case EAP_GPSK_OPCODE_GPSK_1:
  542. resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
  543. pos + 1, len - 1);
  544. break;
  545. case EAP_GPSK_OPCODE_GPSK_3:
  546. resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
  547. pos + 1, len - 1);
  548. break;
  549. default:
  550. wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
  551. "unknown opcode %d", *pos);
  552. ret->ignore = TRUE;
  553. return NULL;
  554. }
  555. return resp;
  556. }
  557. static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
  558. {
  559. struct eap_gpsk_data *data = priv;
  560. return data->state == SUCCESS;
  561. }
  562. static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
  563. {
  564. struct eap_gpsk_data *data = priv;
  565. u8 *key;
  566. if (data->state != SUCCESS)
  567. return NULL;
  568. key = os_malloc(EAP_MSK_LEN);
  569. if (key == NULL)
  570. return NULL;
  571. os_memcpy(key, data->msk, EAP_MSK_LEN);
  572. *len = EAP_MSK_LEN;
  573. return key;
  574. }
  575. static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  576. {
  577. struct eap_gpsk_data *data = priv;
  578. u8 *key;
  579. if (data->state != SUCCESS)
  580. return NULL;
  581. key = os_malloc(EAP_EMSK_LEN);
  582. if (key == NULL)
  583. return NULL;
  584. os_memcpy(key, data->emsk, EAP_EMSK_LEN);
  585. *len = EAP_EMSK_LEN;
  586. return key;
  587. }
  588. int eap_peer_gpsk_register(void)
  589. {
  590. struct eap_method *eap;
  591. int ret;
  592. eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
  593. EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
  594. if (eap == NULL)
  595. return -1;
  596. eap->init = eap_gpsk_init;
  597. eap->deinit = eap_gpsk_deinit;
  598. eap->process = eap_gpsk_process;
  599. eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
  600. eap->getKey = eap_gpsk_getKey;
  601. eap->get_emsk = eap_gpsk_get_emsk;
  602. ret = eap_peer_method_register(eap);
  603. if (ret)
  604. eap_peer_method_free(eap);
  605. return ret;
  606. }