eap_server_pax.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. /*
  2. * hostapd / EAP-PAX (RFC 4746) server
  3. * Copyright (c) 2005-2007, 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 "eap_server/eap_i.h"
  17. #include "eap_common/eap_pax_common.h"
  18. /*
  19. * Note: only PAX_STD subprotocol is currently supported
  20. *
  21. * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
  22. * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
  23. * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
  24. * RSAES-OAEP).
  25. */
  26. struct eap_pax_data {
  27. enum { PAX_STD_1, PAX_STD_3, SUCCESS, FAILURE } state;
  28. u8 mac_id;
  29. union {
  30. u8 e[2 * EAP_PAX_RAND_LEN];
  31. struct {
  32. u8 x[EAP_PAX_RAND_LEN]; /* server rand */
  33. u8 y[EAP_PAX_RAND_LEN]; /* client rand */
  34. } r;
  35. } rand;
  36. u8 ak[EAP_PAX_AK_LEN];
  37. u8 mk[EAP_PAX_MK_LEN];
  38. u8 ck[EAP_PAX_CK_LEN];
  39. u8 ick[EAP_PAX_ICK_LEN];
  40. int keys_set;
  41. char *cid;
  42. size_t cid_len;
  43. };
  44. static void * eap_pax_init(struct eap_sm *sm)
  45. {
  46. struct eap_pax_data *data;
  47. data = os_zalloc(sizeof(*data));
  48. if (data == NULL)
  49. return NULL;
  50. data->state = PAX_STD_1;
  51. /*
  52. * TODO: make this configurable once EAP_PAX_HMAC_SHA256_128 is
  53. * supported
  54. */
  55. data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128;
  56. return data;
  57. }
  58. static void eap_pax_reset(struct eap_sm *sm, void *priv)
  59. {
  60. struct eap_pax_data *data = priv;
  61. os_free(data->cid);
  62. os_free(data);
  63. }
  64. static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm,
  65. struct eap_pax_data *data, u8 id)
  66. {
  67. struct wpabuf *req;
  68. struct eap_pax_hdr *pax;
  69. u8 *pos;
  70. wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)");
  71. if (os_get_random(data->rand.r.x, EAP_PAX_RAND_LEN)) {
  72. wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
  73. data->state = FAILURE;
  74. return NULL;
  75. }
  76. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
  77. sizeof(*pax) + 2 + EAP_PAX_RAND_LEN +
  78. EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
  79. if (req == NULL) {
  80. wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
  81. "request");
  82. data->state = FAILURE;
  83. return NULL;
  84. }
  85. pax = wpabuf_put(req, sizeof(*pax));
  86. pax->op_code = EAP_PAX_OP_STD_1;
  87. pax->flags = 0;
  88. pax->mac_id = data->mac_id;
  89. pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
  90. pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
  91. wpabuf_put_be16(req, EAP_PAX_RAND_LEN);
  92. wpabuf_put_data(req, data->rand.r.x, EAP_PAX_RAND_LEN);
  93. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)",
  94. data->rand.r.x, EAP_PAX_RAND_LEN);
  95. pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
  96. eap_pax_mac(data->mac_id, (u8 *) "", 0,
  97. wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
  98. NULL, 0, NULL, 0, pos);
  99. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
  100. return req;
  101. }
  102. static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
  103. struct eap_pax_data *data, u8 id)
  104. {
  105. struct wpabuf *req;
  106. struct eap_pax_hdr *pax;
  107. u8 *pos;
  108. wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)");
  109. req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
  110. sizeof(*pax) + 2 + EAP_PAX_MAC_LEN +
  111. EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
  112. if (req == NULL) {
  113. wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
  114. "request");
  115. data->state = FAILURE;
  116. return NULL;
  117. }
  118. pax = wpabuf_put(req, sizeof(*pax));
  119. pax->op_code = EAP_PAX_OP_STD_3;
  120. pax->flags = 0;
  121. pax->mac_id = data->mac_id;
  122. pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
  123. pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
  124. wpabuf_put_be16(req, EAP_PAX_MAC_LEN);
  125. pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
  126. eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
  127. data->rand.r.y, EAP_PAX_RAND_LEN,
  128. (u8 *) data->cid, data->cid_len, NULL, 0, pos);
  129. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
  130. pos, EAP_PAX_MAC_LEN);
  131. pos += EAP_PAX_MAC_LEN;
  132. /* Optional ADE could be added here, if needed */
  133. pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
  134. eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
  135. wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
  136. NULL, 0, NULL, 0, pos);
  137. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
  138. return req;
  139. }
  140. static struct wpabuf * eap_pax_buildReq(struct eap_sm *sm, void *priv, u8 id)
  141. {
  142. struct eap_pax_data *data = priv;
  143. switch (data->state) {
  144. case PAX_STD_1:
  145. return eap_pax_build_std_1(sm, data, id);
  146. case PAX_STD_3:
  147. return eap_pax_build_std_3(sm, data, id);
  148. default:
  149. wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown state %d in buildReq",
  150. data->state);
  151. break;
  152. }
  153. return NULL;
  154. }
  155. static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
  156. struct wpabuf *respData)
  157. {
  158. struct eap_pax_data *data = priv;
  159. struct eap_pax_hdr *resp;
  160. const u8 *pos;
  161. size_t len, mlen;
  162. u8 icvbuf[EAP_PAX_ICV_LEN], *icv;
  163. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
  164. if (pos == NULL || len < sizeof(*resp)) {
  165. wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
  166. return TRUE;
  167. }
  168. mlen = sizeof(struct eap_hdr) + 1 + len;
  169. resp = (struct eap_pax_hdr *) pos;
  170. wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
  171. "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
  172. "public_key_id 0x%x",
  173. resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id,
  174. resp->public_key_id);
  175. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
  176. (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN);
  177. if (data->state == PAX_STD_1 &&
  178. resp->op_code != EAP_PAX_OP_STD_2) {
  179. wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
  180. "ignore op %d", resp->op_code);
  181. return TRUE;
  182. }
  183. if (data->state == PAX_STD_3 &&
  184. resp->op_code != EAP_PAX_OP_ACK) {
  185. wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
  186. "ignore op %d", resp->op_code);
  187. return TRUE;
  188. }
  189. if (resp->op_code != EAP_PAX_OP_STD_2 &&
  190. resp->op_code != EAP_PAX_OP_ACK) {
  191. wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x",
  192. resp->op_code);
  193. }
  194. if (data->mac_id != resp->mac_id) {
  195. wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
  196. "received 0x%x", data->mac_id, resp->mac_id);
  197. return TRUE;
  198. }
  199. if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
  200. wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
  201. "received 0x%x", EAP_PAX_DH_GROUP_NONE,
  202. resp->dh_group_id);
  203. return TRUE;
  204. }
  205. if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
  206. wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
  207. "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
  208. resp->public_key_id);
  209. return TRUE;
  210. }
  211. if (resp->flags & EAP_PAX_FLAGS_MF) {
  212. /* TODO: add support for reassembling fragments */
  213. wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
  214. return TRUE;
  215. }
  216. if (resp->flags & EAP_PAX_FLAGS_CE) {
  217. wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
  218. return TRUE;
  219. }
  220. if (data->keys_set) {
  221. if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
  222. wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
  223. return TRUE;
  224. }
  225. icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
  226. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
  227. eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
  228. wpabuf_mhead(respData),
  229. wpabuf_len(respData) - EAP_PAX_ICV_LEN,
  230. NULL, 0, NULL, 0, icvbuf);
  231. if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
  232. wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
  233. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
  234. icvbuf, EAP_PAX_ICV_LEN);
  235. return TRUE;
  236. }
  237. }
  238. return FALSE;
  239. }
  240. static void eap_pax_process_std_2(struct eap_sm *sm,
  241. struct eap_pax_data *data,
  242. struct wpabuf *respData)
  243. {
  244. struct eap_pax_hdr *resp;
  245. u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
  246. const u8 *pos;
  247. size_t len, left;
  248. int i;
  249. if (data->state != PAX_STD_1)
  250. return;
  251. wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2");
  252. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
  253. if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN)
  254. return;
  255. resp = (struct eap_pax_hdr *) pos;
  256. pos = (u8 *) (resp + 1);
  257. left = len - sizeof(*resp);
  258. if (left < 2 + EAP_PAX_RAND_LEN ||
  259. WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
  260. wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)");
  261. return;
  262. }
  263. pos += 2;
  264. left -= 2;
  265. os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN);
  266. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
  267. data->rand.r.y, EAP_PAX_RAND_LEN);
  268. pos += EAP_PAX_RAND_LEN;
  269. left -= EAP_PAX_RAND_LEN;
  270. if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) {
  271. wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
  272. return;
  273. }
  274. data->cid_len = WPA_GET_BE16(pos);
  275. os_free(data->cid);
  276. data->cid = os_malloc(data->cid_len);
  277. if (data->cid == NULL) {
  278. wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for "
  279. "CID");
  280. return;
  281. }
  282. os_memcpy(data->cid, pos + 2, data->cid_len);
  283. pos += 2 + data->cid_len;
  284. left -= 2 + data->cid_len;
  285. wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
  286. (u8 *) data->cid, data->cid_len);
  287. if (left < 2 + EAP_PAX_MAC_LEN ||
  288. WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
  289. wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)");
  290. return;
  291. }
  292. pos += 2;
  293. left -= 2;
  294. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
  295. pos, EAP_PAX_MAC_LEN);
  296. if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) {
  297. wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID",
  298. (u8 *) data->cid, data->cid_len);
  299. data->state = FAILURE;
  300. return;
  301. }
  302. for (i = 0;
  303. i < EAP_MAX_METHODS &&
  304. (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
  305. sm->user->methods[i].method != EAP_TYPE_NONE);
  306. i++) {
  307. if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
  308. sm->user->methods[i].method == EAP_TYPE_PAX)
  309. break;
  310. }
  311. if (i >= EAP_MAX_METHODS ||
  312. sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
  313. sm->user->methods[i].method != EAP_TYPE_PAX) {
  314. wpa_hexdump_ascii(MSG_DEBUG,
  315. "EAP-PAX: EAP-PAX not enabled for CID",
  316. (u8 *) data->cid, data->cid_len);
  317. data->state = FAILURE;
  318. return;
  319. }
  320. if (sm->user->password == NULL ||
  321. sm->user->password_len != EAP_PAX_AK_LEN) {
  322. wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in "
  323. "user database for CID",
  324. (u8 *) data->cid, data->cid_len);
  325. data->state = FAILURE;
  326. return;
  327. }
  328. os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN);
  329. if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
  330. data->rand.e, data->mk, data->ck,
  331. data->ick) < 0) {
  332. wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
  333. "key derivation");
  334. data->state = FAILURE;
  335. return;
  336. }
  337. data->keys_set = 1;
  338. eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
  339. data->rand.r.x, EAP_PAX_RAND_LEN,
  340. data->rand.r.y, EAP_PAX_RAND_LEN,
  341. (u8 *) data->cid, data->cid_len, mac);
  342. if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) {
  343. wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
  344. "PAX_STD-2");
  345. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
  346. mac, EAP_PAX_MAC_LEN);
  347. data->state = FAILURE;
  348. return;
  349. }
  350. pos += EAP_PAX_MAC_LEN;
  351. left -= EAP_PAX_MAC_LEN;
  352. if (left < EAP_PAX_ICV_LEN) {
  353. wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in "
  354. "PAX_STD-2", (unsigned long) left);
  355. return;
  356. }
  357. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
  358. eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
  359. wpabuf_head(respData),
  360. wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
  361. icvbuf);
  362. if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
  363. wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
  364. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
  365. icvbuf, EAP_PAX_ICV_LEN);
  366. return;
  367. }
  368. pos += EAP_PAX_ICV_LEN;
  369. left -= EAP_PAX_ICV_LEN;
  370. if (left > 0) {
  371. wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
  372. pos, left);
  373. }
  374. data->state = PAX_STD_3;
  375. }
  376. static void eap_pax_process_ack(struct eap_sm *sm,
  377. struct eap_pax_data *data,
  378. struct wpabuf *respData)
  379. {
  380. if (data->state != PAX_STD_3)
  381. return;
  382. wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX-ACK - authentication "
  383. "completed successfully");
  384. data->state = SUCCESS;
  385. }
  386. static void eap_pax_process(struct eap_sm *sm, void *priv,
  387. struct wpabuf *respData)
  388. {
  389. struct eap_pax_data *data = priv;
  390. struct eap_pax_hdr *resp;
  391. const u8 *pos;
  392. size_t len;
  393. if (sm->user == NULL || sm->user->password == NULL) {
  394. wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not "
  395. "configured");
  396. data->state = FAILURE;
  397. return;
  398. }
  399. pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
  400. if (pos == NULL || len < sizeof(*resp))
  401. return;
  402. resp = (struct eap_pax_hdr *) pos;
  403. switch (resp->op_code) {
  404. case EAP_PAX_OP_STD_2:
  405. eap_pax_process_std_2(sm, data, respData);
  406. break;
  407. case EAP_PAX_OP_ACK:
  408. eap_pax_process_ack(sm, data, respData);
  409. break;
  410. }
  411. }
  412. static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv)
  413. {
  414. struct eap_pax_data *data = priv;
  415. return data->state == SUCCESS || data->state == FAILURE;
  416. }
  417. static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
  418. {
  419. struct eap_pax_data *data = priv;
  420. u8 *key;
  421. if (data->state != SUCCESS)
  422. return NULL;
  423. key = os_malloc(EAP_MSK_LEN);
  424. if (key == NULL)
  425. return NULL;
  426. *len = EAP_MSK_LEN;
  427. eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
  428. "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
  429. EAP_MSK_LEN, key);
  430. return key;
  431. }
  432. static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
  433. {
  434. struct eap_pax_data *data = priv;
  435. u8 *key;
  436. if (data->state != SUCCESS)
  437. return NULL;
  438. key = os_malloc(EAP_EMSK_LEN);
  439. if (key == NULL)
  440. return NULL;
  441. *len = EAP_EMSK_LEN;
  442. eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
  443. "Extended Master Session Key",
  444. data->rand.e, 2 * EAP_PAX_RAND_LEN,
  445. EAP_EMSK_LEN, key);
  446. return key;
  447. }
  448. static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
  449. {
  450. struct eap_pax_data *data = priv;
  451. return data->state == SUCCESS;
  452. }
  453. int eap_server_pax_register(void)
  454. {
  455. struct eap_method *eap;
  456. int ret;
  457. eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
  458. EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
  459. if (eap == NULL)
  460. return -1;
  461. eap->init = eap_pax_init;
  462. eap->reset = eap_pax_reset;
  463. eap->buildReq = eap_pax_buildReq;
  464. eap->check = eap_pax_check;
  465. eap->process = eap_pax_process;
  466. eap->isDone = eap_pax_isDone;
  467. eap->getKey = eap_pax_getKey;
  468. eap->isSuccess = eap_pax_isSuccess;
  469. eap->get_emsk = eap_pax_get_emsk;
  470. ret = eap_server_method_register(eap);
  471. if (ret)
  472. eap_server_method_free(eap);
  473. return ret;
  474. }