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