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