Home | History | Annotate | Download | only in eap_peer
      1 /*
      2  * EAP peer method: EAP-GPSK (RFC 5433)
      3  * Copyright (c) 2006-2014, 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_peer/eap_i.h"
     14 #include "eap_common/eap_gpsk_common.h"
     15 
     16 struct eap_gpsk_data {
     17 	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
     18 	u8 rand_server[EAP_GPSK_RAND_LEN];
     19 	u8 rand_peer[EAP_GPSK_RAND_LEN];
     20 	u8 msk[EAP_MSK_LEN];
     21 	u8 emsk[EAP_EMSK_LEN];
     22 	u8 sk[EAP_GPSK_MAX_SK_LEN];
     23 	size_t sk_len;
     24 	u8 pk[EAP_GPSK_MAX_PK_LEN];
     25 	size_t pk_len;
     26 	u8 session_id[128];
     27 	size_t id_len;
     28 	u8 *id_peer;
     29 	size_t id_peer_len;
     30 	u8 *id_server;
     31 	size_t id_server_len;
     32 	int vendor; /* CSuite/Specifier */
     33 	int specifier; /* CSuite/Specifier */
     34 	u8 *psk;
     35 	size_t psk_len;
     36 	u16 forced_cipher; /* force cipher or 0 to allow all supported */
     37 };
     38 
     39 
     40 static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
     41 					    u8 identifier,
     42 					    const u8 *csuite_list,
     43 					    size_t csuite_list_len);
     44 static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
     45 					    u8 identifier);
     46 
     47 
     48 #ifndef CONFIG_NO_STDOUT_DEBUG
     49 static const char * eap_gpsk_state_txt(int state)
     50 {
     51 	switch (state) {
     52 	case GPSK_1:
     53 		return "GPSK-1";
     54 	case GPSK_3:
     55 		return "GPSK-3";
     56 	case SUCCESS:
     57 		return "SUCCESS";
     58 	case FAILURE:
     59 		return "FAILURE";
     60 	default:
     61 		return "?";
     62 	}
     63 }
     64 #endif /* CONFIG_NO_STDOUT_DEBUG */
     65 
     66 
     67 static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
     68 {
     69 	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
     70 		   eap_gpsk_state_txt(data->state),
     71 		   eap_gpsk_state_txt(state));
     72 	data->state = state;
     73 }
     74 
     75 
     76 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
     77 
     78 
     79 static void * eap_gpsk_init(struct eap_sm *sm)
     80 {
     81 	struct eap_gpsk_data *data;
     82 	const u8 *identity, *password;
     83 	size_t identity_len, password_len;
     84 	const char *phase1;
     85 
     86 	password = eap_get_config_password(sm, &password_len);
     87 	if (password == NULL) {
     88 		wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
     89 		return NULL;
     90 	}
     91 
     92 	data = os_zalloc(sizeof(*data));
     93 	if (data == NULL)
     94 		return NULL;
     95 	data->state = GPSK_1;
     96 
     97 	identity = eap_get_config_identity(sm, &identity_len);
     98 	if (identity) {
     99 		data->id_peer = os_memdup(identity, identity_len);
    100 		if (data->id_peer == NULL) {
    101 			eap_gpsk_deinit(sm, data);
    102 			return NULL;
    103 		}
    104 		data->id_peer_len = identity_len;
    105 	}
    106 
    107 	phase1 = eap_get_config_phase1(sm);
    108 	if (phase1) {
    109 		const char *pos;
    110 
    111 		pos = os_strstr(phase1, "cipher=");
    112 		if (pos) {
    113 			data->forced_cipher = atoi(pos + 7);
    114 			wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
    115 				   data->forced_cipher);
    116 		}
    117 	}
    118 
    119 	data->psk = os_memdup(password, password_len);
    120 	if (data->psk == NULL) {
    121 		eap_gpsk_deinit(sm, data);
    122 		return NULL;
    123 	}
    124 	data->psk_len = password_len;
    125 
    126 	return data;
    127 }
    128 
    129 
    130 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
    131 {
    132 	struct eap_gpsk_data *data = priv;
    133 	os_free(data->id_server);
    134 	os_free(data->id_peer);
    135 	if (data->psk) {
    136 		os_memset(data->psk, 0, data->psk_len);
    137 		os_free(data->psk);
    138 	}
    139 	bin_clear_free(data, sizeof(*data));
    140 }
    141 
    142 
    143 static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
    144 					     const u8 *pos, const u8 *end)
    145 {
    146 	u16 alen;
    147 
    148 	if (end - pos < 2) {
    149 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
    150 		return NULL;
    151 	}
    152 	alen = WPA_GET_BE16(pos);
    153 	pos += 2;
    154 	if (end - pos < alen) {
    155 		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
    156 		return NULL;
    157 	}
    158 	os_free(data->id_server);
    159 	data->id_server = os_memdup(pos, alen);
    160 	if (data->id_server == NULL) {
    161 		wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
    162 		return NULL;
    163 	}
    164 	data->id_server_len = alen;
    165 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
    166 			  data->id_server, data->id_server_len);
    167 	pos += alen;
    168 
    169 	return pos;
    170 }
    171 
    172 
    173 static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
    174 					       const u8 *pos, const u8 *end)
    175 {
    176 	if (pos == NULL)
    177 		return NULL;
    178 
    179 	if (end - pos < EAP_GPSK_RAND_LEN) {
    180 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
    181 		return NULL;
    182 	}
    183 	os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
    184 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
    185 		    data->rand_server, EAP_GPSK_RAND_LEN);
    186 	pos += EAP_GPSK_RAND_LEN;
    187 
    188 	return pos;
    189 }
    190 
    191 
    192 static int eap_gpsk_select_csuite(struct eap_sm *sm,
    193 				  struct eap_gpsk_data *data,
    194 				  const u8 *csuite_list,
    195 				  size_t csuite_list_len)
    196 {
    197 	struct eap_gpsk_csuite *csuite;
    198 	int i, count;
    199 
    200 	count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
    201 	data->vendor = EAP_GPSK_VENDOR_IETF;
    202 	data->specifier = EAP_GPSK_CIPHER_RESERVED;
    203 	csuite = (struct eap_gpsk_csuite *) csuite_list;
    204 	for (i = 0; i < count; i++) {
    205 		int vendor, specifier;
    206 		vendor = WPA_GET_BE32(csuite->vendor);
    207 		specifier = WPA_GET_BE16(csuite->specifier);
    208 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
    209 			   i, vendor, specifier);
    210 		if (data->vendor == EAP_GPSK_VENDOR_IETF &&
    211 		    data->specifier == EAP_GPSK_CIPHER_RESERVED &&
    212 		    eap_gpsk_supported_ciphersuite(vendor, specifier) &&
    213 		    (!data->forced_cipher || data->forced_cipher == specifier))
    214 		{
    215 			data->vendor = vendor;
    216 			data->specifier = specifier;
    217 		}
    218 		csuite++;
    219 	}
    220 	if (data->vendor == EAP_GPSK_VENDOR_IETF &&
    221 	    data->specifier == EAP_GPSK_CIPHER_RESERVED) {
    222 		wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
    223 			"ciphersuite found");
    224 		return -1;
    225 	}
    226 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
    227 		   data->vendor, data->specifier);
    228 
    229 	return 0;
    230 }
    231 
    232 
    233 static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
    234 					       struct eap_gpsk_data *data,
    235 					       const u8 **list,
    236 					       size_t *list_len,
    237 					       const u8 *pos, const u8 *end)
    238 {
    239 	size_t len;
    240 
    241 	if (pos == NULL)
    242 		return NULL;
    243 
    244 	if (end - pos < 2) {
    245 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
    246 		return NULL;
    247 	}
    248 	len = WPA_GET_BE16(pos);
    249 	pos += 2;
    250 	if (len > (size_t) (end - pos)) {
    251 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
    252 		return NULL;
    253 	}
    254 	if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
    255 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
    256 			   (unsigned long) len);
    257 		return NULL;
    258 	}
    259 
    260 	if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
    261 		return NULL;
    262 
    263 	*list = pos;
    264 	*list_len = len;
    265 	pos += len;
    266 
    267 	return pos;
    268 }
    269 
    270 
    271 static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
    272 					       struct eap_gpsk_data *data,
    273 					       struct eap_method_ret *ret,
    274 					       u8 identifier,
    275 					       const u8 *payload,
    276 					       size_t payload_len)
    277 {
    278 	size_t csuite_list_len;
    279 	const u8 *csuite_list, *pos, *end;
    280 	struct wpabuf *resp;
    281 
    282 	if (data->state != GPSK_1) {
    283 		ret->ignore = TRUE;
    284 		return NULL;
    285 	}
    286 
    287 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
    288 
    289 	end = payload + payload_len;
    290 
    291 	pos = eap_gpsk_process_id_server(data, payload, end);
    292 	pos = eap_gpsk_process_rand_server(data, pos, end);
    293 	pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
    294 					   &csuite_list_len, pos, end);
    295 	if (pos == NULL) {
    296 		ret->methodState = METHOD_DONE;
    297 		eap_gpsk_state(data, FAILURE);
    298 		return NULL;
    299 	}
    300 
    301 	resp = eap_gpsk_send_gpsk_2(data, identifier,
    302 				    csuite_list, csuite_list_len);
    303 	if (resp == NULL)
    304 		return NULL;
    305 
    306 	eap_gpsk_state(data, GPSK_3);
    307 
    308 	return resp;
    309 }
    310 
    311 
    312 static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
    313 					    u8 identifier,
    314 					    const u8 *csuite_list,
    315 					    size_t csuite_list_len)
    316 {
    317 	struct wpabuf *resp;
    318 	size_t len, miclen;
    319 	u8 *rpos, *start;
    320 	struct eap_gpsk_csuite *csuite;
    321 
    322 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
    323 
    324 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
    325 	len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
    326 		2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
    327 		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
    328 
    329 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
    330 			     EAP_CODE_RESPONSE, identifier);
    331 	if (resp == NULL)
    332 		return NULL;
    333 
    334 	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
    335 	start = wpabuf_put(resp, 0);
    336 
    337 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
    338 			  data->id_peer, data->id_peer_len);
    339 	wpabuf_put_be16(resp, data->id_peer_len);
    340 	wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
    341 
    342 	wpabuf_put_be16(resp, data->id_server_len);
    343 	wpabuf_put_data(resp, data->id_server, data->id_server_len);
    344 
    345 	if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
    346 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
    347 			   "for RAND_Peer");
    348 		eap_gpsk_state(data, FAILURE);
    349 		wpabuf_free(resp);
    350 		return NULL;
    351 	}
    352 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
    353 		    data->rand_peer, EAP_GPSK_RAND_LEN);
    354 	wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
    355 	wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
    356 
    357 	wpabuf_put_be16(resp, csuite_list_len);
    358 	wpabuf_put_data(resp, csuite_list, csuite_list_len);
    359 
    360 	csuite = wpabuf_put(resp, sizeof(*csuite));
    361 	WPA_PUT_BE32(csuite->vendor, data->vendor);
    362 	WPA_PUT_BE16(csuite->specifier, data->specifier);
    363 
    364 	if (eap_gpsk_derive_keys(data->psk, data->psk_len,
    365 				 data->vendor, data->specifier,
    366 				 data->rand_peer, data->rand_server,
    367 				 data->id_peer, data->id_peer_len,
    368 				 data->id_server, data->id_server_len,
    369 				 data->msk, data->emsk,
    370 				 data->sk, &data->sk_len,
    371 				 data->pk, &data->pk_len) < 0) {
    372 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
    373 		eap_gpsk_state(data, FAILURE);
    374 		wpabuf_free(resp);
    375 		return NULL;
    376 	}
    377 
    378 	if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
    379 				       data->vendor, data->specifier,
    380 				       data->rand_peer, data->rand_server,
    381 				       data->id_peer, data->id_peer_len,
    382 				       data->id_server, data->id_server_len,
    383 				       EAP_TYPE_GPSK,
    384 				       data->session_id, &data->id_len) < 0) {
    385 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
    386 		eap_gpsk_state(data, FAILURE);
    387 		wpabuf_free(resp);
    388 		return NULL;
    389 	}
    390 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
    391 		    data->session_id, data->id_len);
    392 
    393 	/* No PD_Payload_1 */
    394 	wpabuf_put_be16(resp, 0);
    395 
    396 	rpos = wpabuf_put(resp, miclen);
    397 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
    398 				 data->specifier, start, rpos - start, rpos) <
    399 	    0) {
    400 		eap_gpsk_state(data, FAILURE);
    401 		wpabuf_free(resp);
    402 		return NULL;
    403 	}
    404 
    405 	return resp;
    406 }
    407 
    408 
    409 static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
    410 					 const u8 *pos, const u8 *end)
    411 {
    412 	if (end - pos < EAP_GPSK_RAND_LEN) {
    413 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
    414 			   "RAND_Peer");
    415 		return NULL;
    416 	}
    417 	if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
    418 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
    419 			   "GPSK-3 did not match");
    420 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
    421 			    data->rand_peer, EAP_GPSK_RAND_LEN);
    422 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
    423 			    pos, EAP_GPSK_RAND_LEN);
    424 		return NULL;
    425 	}
    426 	pos += EAP_GPSK_RAND_LEN;
    427 
    428 	if (end - pos < EAP_GPSK_RAND_LEN) {
    429 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
    430 			   "RAND_Server");
    431 		return NULL;
    432 	}
    433 	if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
    434 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
    435 			   "GPSK-3 did not match");
    436 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
    437 			    data->rand_server, EAP_GPSK_RAND_LEN);
    438 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
    439 			    pos, EAP_GPSK_RAND_LEN);
    440 		return NULL;
    441 	}
    442 	pos += EAP_GPSK_RAND_LEN;
    443 
    444 	return pos;
    445 }
    446 
    447 
    448 static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
    449 					      const u8 *pos, const u8 *end)
    450 {
    451 	size_t len;
    452 
    453 	if (pos == NULL)
    454 		return NULL;
    455 
    456 	if (end - pos < (int) 2) {
    457 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
    458 			   "length(ID_Server)");
    459 		return NULL;
    460 	}
    461 
    462 	len = WPA_GET_BE16(pos);
    463 	pos += 2;
    464 
    465 	if (end - pos < (int) len) {
    466 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
    467 			   "ID_Server");
    468 		return NULL;
    469 	}
    470 
    471 	if (len != data->id_server_len ||
    472 	    os_memcmp(pos, data->id_server, len) != 0) {
    473 		wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
    474 			   "the one used in GPSK-1");
    475 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
    476 				  data->id_server, data->id_server_len);
    477 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
    478 				  pos, len);
    479 		return NULL;
    480 	}
    481 
    482 	pos += len;
    483 
    484 	return pos;
    485 }
    486 
    487 
    488 static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
    489 					   const u8 *pos, const u8 *end)
    490 {
    491 	int vendor, specifier;
    492 	const struct eap_gpsk_csuite *csuite;
    493 
    494 	if (pos == NULL)
    495 		return NULL;
    496 
    497 	if (end - pos < (int) sizeof(*csuite)) {
    498 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
    499 			   "CSuite_Sel");
    500 		return NULL;
    501 	}
    502 	csuite = (const struct eap_gpsk_csuite *) pos;
    503 	vendor = WPA_GET_BE32(csuite->vendor);
    504 	specifier = WPA_GET_BE16(csuite->specifier);
    505 	pos += sizeof(*csuite);
    506 	if (vendor != data->vendor || specifier != data->specifier) {
    507 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
    508 			   "match with the one sent in GPSK-2 (%d:%d)",
    509 			   vendor, specifier, data->vendor, data->specifier);
    510 		return NULL;
    511 	}
    512 
    513 	return pos;
    514 }
    515 
    516 
    517 static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
    518 						 const u8 *pos, const u8 *end)
    519 {
    520 	u16 alen;
    521 
    522 	if (pos == NULL)
    523 		return NULL;
    524 
    525 	if (end - pos < 2) {
    526 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
    527 			   "PD_Payload_2 length");
    528 		return NULL;
    529 	}
    530 	alen = WPA_GET_BE16(pos);
    531 	pos += 2;
    532 	if (end - pos < alen) {
    533 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
    534 			   "%d-octet PD_Payload_2", alen);
    535 		return NULL;
    536 	}
    537 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
    538 	pos += alen;
    539 
    540 	return pos;
    541 }
    542 
    543 
    544 static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
    545 					       const u8 *payload,
    546 					       const u8 *pos, const u8 *end)
    547 {
    548 	size_t miclen;
    549 	u8 mic[EAP_GPSK_MAX_MIC_LEN];
    550 
    551 	if (pos == NULL)
    552 		return NULL;
    553 
    554 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
    555 	if (end - pos < (int) miclen) {
    556 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
    557 			   "(left=%lu miclen=%lu)",
    558 			   (unsigned long) (end - pos),
    559 			   (unsigned long) miclen);
    560 		return NULL;
    561 	}
    562 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
    563 				 data->specifier, payload, pos - payload, mic)
    564 	    < 0) {
    565 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
    566 		return NULL;
    567 	}
    568 	if (os_memcmp_const(mic, pos, miclen) != 0) {
    569 		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
    570 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
    571 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
    572 		return NULL;
    573 	}
    574 	pos += miclen;
    575 
    576 	return pos;
    577 }
    578 
    579 
    580 static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
    581 					       struct eap_gpsk_data *data,
    582 					       struct eap_method_ret *ret,
    583 					       u8 identifier,
    584 					       const u8 *payload,
    585 					       size_t payload_len)
    586 {
    587 	struct wpabuf *resp;
    588 	const u8 *pos, *end;
    589 
    590 	if (data->state != GPSK_3) {
    591 		ret->ignore = TRUE;
    592 		return NULL;
    593 	}
    594 
    595 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
    596 
    597 	end = payload + payload_len;
    598 
    599 	pos = eap_gpsk_validate_rand(data, payload, end);
    600 	pos = eap_gpsk_validate_id_server(data, pos, end);
    601 	pos = eap_gpsk_validate_csuite(data, pos, end);
    602 	pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
    603 	pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
    604 
    605 	if (pos == NULL) {
    606 		eap_gpsk_state(data, FAILURE);
    607 		return NULL;
    608 	}
    609 	if (pos != end) {
    610 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
    611 			   "data in the end of GPSK-2",
    612 			   (unsigned long) (end - pos));
    613 	}
    614 
    615 	resp = eap_gpsk_send_gpsk_4(data, identifier);
    616 	if (resp == NULL)
    617 		return NULL;
    618 
    619 	eap_gpsk_state(data, SUCCESS);
    620 	ret->methodState = METHOD_DONE;
    621 	ret->decision = DECISION_UNCOND_SUCC;
    622 
    623 	return resp;
    624 }
    625 
    626 
    627 static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
    628 					    u8 identifier)
    629 {
    630 	struct wpabuf *resp;
    631 	u8 *rpos, *start;
    632 	size_t mlen;
    633 
    634 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
    635 
    636 	mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
    637 
    638 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
    639 			     EAP_CODE_RESPONSE, identifier);
    640 	if (resp == NULL)
    641 		return NULL;
    642 
    643 	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
    644 	start = wpabuf_put(resp, 0);
    645 
    646 	/* No PD_Payload_3 */
    647 	wpabuf_put_be16(resp, 0);
    648 
    649 	rpos = wpabuf_put(resp, mlen);
    650 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
    651 				 data->specifier, start, rpos - start, rpos) <
    652 	    0) {
    653 		eap_gpsk_state(data, FAILURE);
    654 		wpabuf_free(resp);
    655 		return NULL;
    656 	}
    657 
    658 	return resp;
    659 }
    660 
    661 
    662 static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
    663 					struct eap_method_ret *ret,
    664 					const struct wpabuf *reqData)
    665 {
    666 	struct eap_gpsk_data *data = priv;
    667 	struct wpabuf *resp;
    668 	const u8 *pos;
    669 	size_t len;
    670 	u8 opcode, id;
    671 
    672 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
    673 	if (pos == NULL || len < 1) {
    674 		ret->ignore = TRUE;
    675 		return NULL;
    676 	}
    677 
    678 	id = eap_get_id(reqData);
    679 	opcode = *pos++;
    680 	len--;
    681 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
    682 
    683 	ret->ignore = FALSE;
    684 	ret->methodState = METHOD_MAY_CONT;
    685 	ret->decision = DECISION_FAIL;
    686 	ret->allowNotifications = FALSE;
    687 
    688 	switch (opcode) {
    689 	case EAP_GPSK_OPCODE_GPSK_1:
    690 		resp = eap_gpsk_process_gpsk_1(sm, data, ret, id, pos, len);
    691 		break;
    692 	case EAP_GPSK_OPCODE_GPSK_3:
    693 		resp = eap_gpsk_process_gpsk_3(sm, data, ret, id, pos, len);
    694 		break;
    695 	default:
    696 		wpa_printf(MSG_DEBUG,
    697 			   "EAP-GPSK: Ignoring message with unknown opcode %d",
    698 			   opcode);
    699 		ret->ignore = TRUE;
    700 		return NULL;
    701 	}
    702 
    703 	return resp;
    704 }
    705 
    706 
    707 static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
    708 {
    709 	struct eap_gpsk_data *data = priv;
    710 	return data->state == SUCCESS;
    711 }
    712 
    713 
    714 static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
    715 {
    716 	struct eap_gpsk_data *data = priv;
    717 	u8 *key;
    718 
    719 	if (data->state != SUCCESS)
    720 		return NULL;
    721 
    722 	key = os_memdup(data->msk, EAP_MSK_LEN);
    723 	if (key == NULL)
    724 		return NULL;
    725 	*len = EAP_MSK_LEN;
    726 
    727 	return key;
    728 }
    729 
    730 
    731 static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    732 {
    733 	struct eap_gpsk_data *data = priv;
    734 	u8 *key;
    735 
    736 	if (data->state != SUCCESS)
    737 		return NULL;
    738 
    739 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
    740 	if (key == NULL)
    741 		return NULL;
    742 	*len = EAP_EMSK_LEN;
    743 
    744 	return key;
    745 }
    746 
    747 
    748 static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    749 {
    750 	struct eap_gpsk_data *data = priv;
    751 	u8 *sid;
    752 
    753 	if (data->state != SUCCESS)
    754 		return NULL;
    755 
    756 	sid = os_memdup(data->session_id, data->id_len);
    757 	if (sid == NULL)
    758 		return NULL;
    759 	*len = data->id_len;
    760 
    761 	return sid;
    762 }
    763 
    764 
    765 int eap_peer_gpsk_register(void)
    766 {
    767 	struct eap_method *eap;
    768 
    769 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
    770 				    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
    771 	if (eap == NULL)
    772 		return -1;
    773 
    774 	eap->init = eap_gpsk_init;
    775 	eap->deinit = eap_gpsk_deinit;
    776 	eap->process = eap_gpsk_process;
    777 	eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
    778 	eap->getKey = eap_gpsk_getKey;
    779 	eap->get_emsk = eap_gpsk_get_emsk;
    780 	eap->getSessionId = eap_gpsk_get_session_id;
    781 
    782 	return eap_peer_method_register(eap);
    783 }
    784