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