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