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