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