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