eap_server_pax.c 15 KB

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