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_memdup(pos, 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 	data->id_peer_len = alen;
    279 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
    280 			  data->id_peer, data->id_peer_len);
    281 	pos += alen;
    282 
    283 	if (end - pos < 2) {
    284 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    285 			   "ID_Server length");
    286 		eap_gpsk_state(data, FAILURE);
    287 		return;
    288 	}
    289 	alen = WPA_GET_BE16(pos);
    290 	pos += 2;
    291 	if (end - pos < alen) {
    292 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    293 			   "ID_Server");
    294 		eap_gpsk_state(data, FAILURE);
    295 		return;
    296 	}
    297 	if (alen != sm->server_id_len ||
    298 	    os_memcmp(pos, sm->server_id, alen) != 0) {
    299 		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
    300 			   "GPSK-2 did not match");
    301 		eap_gpsk_state(data, FAILURE);
    302 		return;
    303 	}
    304 	pos += alen;
    305 
    306 	if (end - pos < EAP_GPSK_RAND_LEN) {
    307 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    308 			   "RAND_Peer");
    309 		eap_gpsk_state(data, FAILURE);
    310 		return;
    311 	}
    312 	os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN);
    313 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
    314 		    data->rand_peer, EAP_GPSK_RAND_LEN);
    315 	pos += EAP_GPSK_RAND_LEN;
    316 
    317 	if (end - pos < EAP_GPSK_RAND_LEN) {
    318 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    319 			   "RAND_Server");
    320 		eap_gpsk_state(data, FAILURE);
    321 		return;
    322 	}
    323 	if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
    324 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
    325 			   "GPSK-2 did not match");
    326 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
    327 			    data->rand_server, EAP_GPSK_RAND_LEN);
    328 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
    329 			    pos, EAP_GPSK_RAND_LEN);
    330 		eap_gpsk_state(data, FAILURE);
    331 		return;
    332 	}
    333 	pos += EAP_GPSK_RAND_LEN;
    334 
    335 	if (end - pos < 2) {
    336 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    337 			   "CSuite_List length");
    338 		eap_gpsk_state(data, FAILURE);
    339 		return;
    340 	}
    341 	alen = WPA_GET_BE16(pos);
    342 	pos += 2;
    343 	if (end - pos < alen) {
    344 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    345 			   "CSuite_List");
    346 		eap_gpsk_state(data, FAILURE);
    347 		return;
    348 	}
    349 	if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
    350 	    os_memcmp(pos, data->csuite_list, alen) != 0) {
    351 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
    352 			   "GPSK-2 did not match");
    353 		eap_gpsk_state(data, FAILURE);
    354 		return;
    355 	}
    356 	pos += alen;
    357 
    358 	if (end - pos < (int) sizeof(*csuite)) {
    359 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    360 			   "CSuite_Sel");
    361 		eap_gpsk_state(data, FAILURE);
    362 		return;
    363 	}
    364 	csuite = (const struct eap_gpsk_csuite *) pos;
    365 	for (i = 0; i < data->csuite_count; i++) {
    366 		if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite))
    367 		    == 0)
    368 			break;
    369 	}
    370 	if (i == data->csuite_count) {
    371 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
    372 			   "ciphersuite %d:%d",
    373 			   WPA_GET_BE32(csuite->vendor),
    374 			   WPA_GET_BE16(csuite->specifier));
    375 		eap_gpsk_state(data, FAILURE);
    376 		return;
    377 	}
    378 	data->vendor = WPA_GET_BE32(csuite->vendor);
    379 	data->specifier = WPA_GET_BE16(csuite->specifier);
    380 	wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
    381 		   data->vendor, data->specifier);
    382 	pos += sizeof(*csuite);
    383 
    384 	if (end - pos < 2) {
    385 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    386 			   "PD_Payload_1 length");
    387 		eap_gpsk_state(data, FAILURE);
    388 		return;
    389 	}
    390 	alen = WPA_GET_BE16(pos);
    391 	pos += 2;
    392 	if (end - pos < alen) {
    393 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    394 			   "PD_Payload_1");
    395 		eap_gpsk_state(data, FAILURE);
    396 		return;
    397 	}
    398 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
    399 	pos += alen;
    400 
    401 	if (sm->user == NULL || sm->user->password == NULL) {
    402 		wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
    403 			   "for the user");
    404 		eap_gpsk_state(data, FAILURE);
    405 		return;
    406 	}
    407 
    408 	if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
    409 				 data->vendor, data->specifier,
    410 				 data->rand_peer, data->rand_server,
    411 				 data->id_peer, data->id_peer_len,
    412 				 sm->server_id, sm->server_id_len,
    413 				 data->msk, data->emsk,
    414 				 data->sk, &data->sk_len,
    415 				 data->pk, &data->pk_len) < 0) {
    416 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
    417 		eap_gpsk_state(data, FAILURE);
    418 		return;
    419 	}
    420 
    421 	if (eap_gpsk_derive_session_id(sm->user->password,
    422 				       sm->user->password_len,
    423 				       data->vendor, data->specifier,
    424 				       data->rand_peer, data->rand_server,
    425 				       data->id_peer, data->id_peer_len,
    426 				       sm->server_id, sm->server_id_len,
    427 				       EAP_TYPE_GPSK,
    428 				       data->session_id, &data->id_len) < 0) {
    429 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
    430 		eap_gpsk_state(data, FAILURE);
    431 		return;
    432 	}
    433 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
    434 		    data->session_id, data->id_len);
    435 
    436 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
    437 	if (end - pos < (int) miclen) {
    438 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
    439 			   "(left=%lu miclen=%lu)",
    440 			   (unsigned long) (end - pos),
    441 			   (unsigned long) miclen);
    442 		eap_gpsk_state(data, FAILURE);
    443 		return;
    444 	}
    445 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
    446 				 data->specifier, payload, pos - payload, mic)
    447 	    < 0) {
    448 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
    449 		eap_gpsk_state(data, FAILURE);
    450 		return;
    451 	}
    452 	if (os_memcmp_const(mic, pos, miclen) != 0) {
    453 		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
    454 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
    455 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
    456 		eap_gpsk_state(data, FAILURE);
    457 		return;
    458 	}
    459 	pos += miclen;
    460 
    461 	if (pos != end) {
    462 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
    463 			   "data in the end of GPSK-2",
    464 			   (unsigned long) (end - pos));
    465 	}
    466 
    467 	eap_gpsk_state(data, GPSK_3);
    468 }
    469 
    470 
    471 static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
    472 				    struct eap_gpsk_data *data,
    473 				    const u8 *payload, size_t payloadlen)
    474 {
    475 	const u8 *pos, *end;
    476 	u16 alen;
    477 	size_t miclen;
    478 	u8 mic[EAP_GPSK_MAX_MIC_LEN];
    479 
    480 	if (data->state != GPSK_3)
    481 		return;
    482 
    483 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");
    484 
    485 	pos = payload;
    486 	end = payload + payloadlen;
    487 
    488 	if (end - pos < 2) {
    489 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    490 			   "PD_Payload_1 length");
    491 		eap_gpsk_state(data, FAILURE);
    492 		return;
    493 	}
    494 	alen = WPA_GET_BE16(pos);
    495 	pos += 2;
    496 	if (end - pos < alen) {
    497 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
    498 			   "PD_Payload_1");
    499 		eap_gpsk_state(data, FAILURE);
    500 		return;
    501 	}
    502 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
    503 	pos += alen;
    504 
    505 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
    506 	if (end - pos < (int) miclen) {
    507 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
    508 			   "(left=%lu miclen=%lu)",
    509 			   (unsigned long) (end - pos),
    510 			   (unsigned long) miclen);
    511 		eap_gpsk_state(data, FAILURE);
    512 		return;
    513 	}
    514 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
    515 				 data->specifier, payload, pos - payload, mic)
    516 	    < 0) {
    517 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
    518 		eap_gpsk_state(data, FAILURE);
    519 		return;
    520 	}
    521 	if (os_memcmp_const(mic, pos, miclen) != 0) {
    522 		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
    523 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
    524 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
    525 		eap_gpsk_state(data, FAILURE);
    526 		return;
    527 	}
    528 	pos += miclen;
    529 
    530 	if (pos != end) {
    531 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
    532 			   "data in the end of GPSK-4",
    533 			   (unsigned long) (end - pos));
    534 	}
    535 
    536 	eap_gpsk_state(data, SUCCESS);
    537 }
    538 
    539 
    540 static void eap_gpsk_process(struct eap_sm *sm, void *priv,
    541 			     struct wpabuf *respData)
    542 {
    543 	struct eap_gpsk_data *data = priv;
    544 	const u8 *pos;
    545 	size_t len;
    546 
    547 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
    548 	if (pos == NULL || len < 1)
    549 		return;
    550 
    551 	switch (*pos) {
    552 	case EAP_GPSK_OPCODE_GPSK_2:
    553 		eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1);
    554 		break;
    555 	case EAP_GPSK_OPCODE_GPSK_4:
    556 		eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1);
    557 		break;
    558 	}
    559 }
    560 
    561 
    562 static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
    563 {
    564 	struct eap_gpsk_data *data = priv;
    565 	return data->state == SUCCESS || data->state == FAILURE;
    566 }
    567 
    568 
    569 static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
    570 {
    571 	struct eap_gpsk_data *data = priv;
    572 	u8 *key;
    573 
    574 	if (data->state != SUCCESS)
    575 		return NULL;
    576 
    577 	key = os_memdup(data->msk, EAP_MSK_LEN);
    578 	if (key == NULL)
    579 		return NULL;
    580 	*len = EAP_MSK_LEN;
    581 
    582 	return key;
    583 }
    584 
    585 
    586 static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    587 {
    588 	struct eap_gpsk_data *data = priv;
    589 	u8 *key;
    590 
    591 	if (data->state != SUCCESS)
    592 		return NULL;
    593 
    594 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
    595 	if (key == NULL)
    596 		return NULL;
    597 	*len = EAP_EMSK_LEN;
    598 
    599 	return key;
    600 }
    601 
    602 
    603 static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
    604 {
    605 	struct eap_gpsk_data *data = priv;
    606 	return data->state == SUCCESS;
    607 }
    608 
    609 
    610 static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    611 {
    612 	struct eap_gpsk_data *data = priv;
    613 	u8 *sid;
    614 
    615 	if (data->state != SUCCESS)
    616 		return NULL;
    617 
    618 	sid = os_memdup(data->session_id, data->id_len);
    619 	if (sid == NULL)
    620 		return NULL;
    621 	*len = data->id_len;
    622 
    623 	return sid;
    624 }
    625 
    626 
    627 int eap_server_gpsk_register(void)
    628 {
    629 	struct eap_method *eap;
    630 
    631 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    632 				      EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
    633 	if (eap == NULL)
    634 		return -1;
    635 
    636 	eap->init = eap_gpsk_init;
    637 	eap->reset = eap_gpsk_reset;
    638 	eap->buildReq = eap_gpsk_buildReq;
    639 	eap->check = eap_gpsk_check;
    640 	eap->process = eap_gpsk_process;
    641 	eap->isDone = eap_gpsk_isDone;
    642 	eap->getKey = eap_gpsk_getKey;
    643 	eap->isSuccess = eap_gpsk_isSuccess;
    644 	eap->get_emsk = eap_gpsk_get_emsk;
    645 	eap->getSessionId = eap_gpsk_get_session_id;
    646 
    647 	return eap_server_method_register(eap);
    648 }
    649