Home | History | Annotate | Download | only in eap_server
      1 /*
      2  * hostapd / EAP-PAX (RFC 4746) server
      3  * Copyright (c) 2005-2007, Jouni Malinen <j (at) 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