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