xref: /freebsd-src/contrib/wpa/src/eap_peer/eap_gpsk.c (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
139beb93cSSam Leffler /*
23157ba21SRui Paulo  * EAP peer method: EAP-GPSK (RFC 5433)
35b9c547cSRui Paulo  * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12f05cddf9SRui Paulo #include "crypto/random.h"
1339beb93cSSam Leffler #include "eap_peer/eap_i.h"
1439beb93cSSam Leffler #include "eap_common/eap_gpsk_common.h"
1539beb93cSSam Leffler 
1639beb93cSSam Leffler struct eap_gpsk_data {
1739beb93cSSam Leffler 	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
1839beb93cSSam Leffler 	u8 rand_server[EAP_GPSK_RAND_LEN];
1939beb93cSSam Leffler 	u8 rand_peer[EAP_GPSK_RAND_LEN];
2039beb93cSSam Leffler 	u8 msk[EAP_MSK_LEN];
2139beb93cSSam Leffler 	u8 emsk[EAP_EMSK_LEN];
2239beb93cSSam Leffler 	u8 sk[EAP_GPSK_MAX_SK_LEN];
2339beb93cSSam Leffler 	size_t sk_len;
2439beb93cSSam Leffler 	u8 pk[EAP_GPSK_MAX_PK_LEN];
2539beb93cSSam Leffler 	size_t pk_len;
265b9c547cSRui Paulo 	u8 session_id[128];
275b9c547cSRui Paulo 	size_t id_len;
2839beb93cSSam Leffler 	u8 *id_peer;
2939beb93cSSam Leffler 	size_t id_peer_len;
3039beb93cSSam Leffler 	u8 *id_server;
3139beb93cSSam Leffler 	size_t id_server_len;
3239beb93cSSam Leffler 	int vendor; /* CSuite/Specifier */
3339beb93cSSam Leffler 	int specifier; /* CSuite/Specifier */
3439beb93cSSam Leffler 	u8 *psk;
3539beb93cSSam Leffler 	size_t psk_len;
365b9c547cSRui Paulo 	u16 forced_cipher; /* force cipher or 0 to allow all supported */
3739beb93cSSam Leffler };
3839beb93cSSam Leffler 
3939beb93cSSam Leffler 
4039beb93cSSam Leffler static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
4139beb93cSSam Leffler 					    u8 identifier,
4239beb93cSSam Leffler 					    const u8 *csuite_list,
4339beb93cSSam Leffler 					    size_t csuite_list_len);
4439beb93cSSam Leffler static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
4539beb93cSSam Leffler 					    u8 identifier);
4639beb93cSSam Leffler 
4739beb93cSSam Leffler 
4839beb93cSSam Leffler #ifndef CONFIG_NO_STDOUT_DEBUG
eap_gpsk_state_txt(int state)4939beb93cSSam Leffler static const char * eap_gpsk_state_txt(int state)
5039beb93cSSam Leffler {
5139beb93cSSam Leffler 	switch (state) {
5239beb93cSSam Leffler 	case GPSK_1:
5339beb93cSSam Leffler 		return "GPSK-1";
5439beb93cSSam Leffler 	case GPSK_3:
5539beb93cSSam Leffler 		return "GPSK-3";
5639beb93cSSam Leffler 	case SUCCESS:
5739beb93cSSam Leffler 		return "SUCCESS";
5839beb93cSSam Leffler 	case FAILURE:
5939beb93cSSam Leffler 		return "FAILURE";
6039beb93cSSam Leffler 	default:
6139beb93cSSam Leffler 		return "?";
6239beb93cSSam Leffler 	}
6339beb93cSSam Leffler }
6439beb93cSSam Leffler #endif /* CONFIG_NO_STDOUT_DEBUG */
6539beb93cSSam Leffler 
6639beb93cSSam Leffler 
eap_gpsk_state(struct eap_gpsk_data * data,int state)6739beb93cSSam Leffler static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
6839beb93cSSam Leffler {
6939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
7039beb93cSSam Leffler 		   eap_gpsk_state_txt(data->state),
7139beb93cSSam Leffler 		   eap_gpsk_state_txt(state));
7239beb93cSSam Leffler 	data->state = state;
7339beb93cSSam Leffler }
7439beb93cSSam Leffler 
7539beb93cSSam Leffler 
7639beb93cSSam Leffler static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
7739beb93cSSam Leffler 
7839beb93cSSam Leffler 
eap_gpsk_init(struct eap_sm * sm)7939beb93cSSam Leffler static void * eap_gpsk_init(struct eap_sm *sm)
8039beb93cSSam Leffler {
8139beb93cSSam Leffler 	struct eap_gpsk_data *data;
8239beb93cSSam Leffler 	const u8 *identity, *password;
8339beb93cSSam Leffler 	size_t identity_len, password_len;
845b9c547cSRui Paulo 	const char *phase1;
8539beb93cSSam Leffler 
8639beb93cSSam Leffler 	password = eap_get_config_password(sm, &password_len);
8739beb93cSSam Leffler 	if (password == NULL) {
8839beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
8939beb93cSSam Leffler 		return NULL;
9039beb93cSSam Leffler 	}
9139beb93cSSam Leffler 
9239beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
9339beb93cSSam Leffler 	if (data == NULL)
9439beb93cSSam Leffler 		return NULL;
9539beb93cSSam Leffler 	data->state = GPSK_1;
9639beb93cSSam Leffler 
9739beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
9839beb93cSSam Leffler 	if (identity) {
9985732ac8SCy Schubert 		data->id_peer = os_memdup(identity, identity_len);
10039beb93cSSam Leffler 		if (data->id_peer == NULL) {
10139beb93cSSam Leffler 			eap_gpsk_deinit(sm, data);
10239beb93cSSam Leffler 			return NULL;
10339beb93cSSam Leffler 		}
10439beb93cSSam Leffler 		data->id_peer_len = identity_len;
10539beb93cSSam Leffler 	}
10639beb93cSSam Leffler 
1075b9c547cSRui Paulo 	phase1 = eap_get_config_phase1(sm);
1085b9c547cSRui Paulo 	if (phase1) {
1095b9c547cSRui Paulo 		const char *pos;
1105b9c547cSRui Paulo 
1115b9c547cSRui Paulo 		pos = os_strstr(phase1, "cipher=");
1125b9c547cSRui Paulo 		if (pos) {
1135b9c547cSRui Paulo 			data->forced_cipher = atoi(pos + 7);
1145b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
1155b9c547cSRui Paulo 				   data->forced_cipher);
1165b9c547cSRui Paulo 		}
1175b9c547cSRui Paulo 	}
1185b9c547cSRui Paulo 
11985732ac8SCy Schubert 	data->psk = os_memdup(password, password_len);
12039beb93cSSam Leffler 	if (data->psk == NULL) {
12139beb93cSSam Leffler 		eap_gpsk_deinit(sm, data);
12239beb93cSSam Leffler 		return NULL;
12339beb93cSSam Leffler 	}
12439beb93cSSam Leffler 	data->psk_len = password_len;
12539beb93cSSam Leffler 
12639beb93cSSam Leffler 	return data;
12739beb93cSSam Leffler }
12839beb93cSSam Leffler 
12939beb93cSSam Leffler 
eap_gpsk_deinit(struct eap_sm * sm,void * priv)13039beb93cSSam Leffler static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
13139beb93cSSam Leffler {
13239beb93cSSam Leffler 	struct eap_gpsk_data *data = priv;
13339beb93cSSam Leffler 	os_free(data->id_server);
13439beb93cSSam Leffler 	os_free(data->id_peer);
1355b9c547cSRui Paulo 	if (data->psk) {
1365b9c547cSRui Paulo 		os_memset(data->psk, 0, data->psk_len);
13739beb93cSSam Leffler 		os_free(data->psk);
1385b9c547cSRui Paulo 	}
1395b9c547cSRui Paulo 	bin_clear_free(data, sizeof(*data));
14039beb93cSSam Leffler }
14139beb93cSSam Leffler 
14239beb93cSSam Leffler 
eap_gpsk_process_id_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)14339beb93cSSam Leffler static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
14439beb93cSSam Leffler 					     const u8 *pos, const u8 *end)
14539beb93cSSam Leffler {
14639beb93cSSam Leffler 	u16 alen;
14739beb93cSSam Leffler 
14839beb93cSSam Leffler 	if (end - pos < 2) {
14939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
15039beb93cSSam Leffler 		return NULL;
15139beb93cSSam Leffler 	}
15239beb93cSSam Leffler 	alen = WPA_GET_BE16(pos);
15339beb93cSSam Leffler 	pos += 2;
15439beb93cSSam Leffler 	if (end - pos < alen) {
15539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
15639beb93cSSam Leffler 		return NULL;
15739beb93cSSam Leffler 	}
15839beb93cSSam Leffler 	os_free(data->id_server);
15985732ac8SCy Schubert 	data->id_server = os_memdup(pos, alen);
16039beb93cSSam Leffler 	if (data->id_server == NULL) {
16139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
16239beb93cSSam Leffler 		return NULL;
16339beb93cSSam Leffler 	}
16439beb93cSSam Leffler 	data->id_server_len = alen;
16539beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
16639beb93cSSam Leffler 			  data->id_server, data->id_server_len);
16739beb93cSSam Leffler 	pos += alen;
16839beb93cSSam Leffler 
16939beb93cSSam Leffler 	return pos;
17039beb93cSSam Leffler }
17139beb93cSSam Leffler 
17239beb93cSSam Leffler 
eap_gpsk_process_rand_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)17339beb93cSSam Leffler static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
17439beb93cSSam Leffler 					       const u8 *pos, const u8 *end)
17539beb93cSSam Leffler {
17639beb93cSSam Leffler 	if (pos == NULL)
17739beb93cSSam Leffler 		return NULL;
17839beb93cSSam Leffler 
17939beb93cSSam Leffler 	if (end - pos < EAP_GPSK_RAND_LEN) {
18039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
18139beb93cSSam Leffler 		return NULL;
18239beb93cSSam Leffler 	}
18339beb93cSSam Leffler 	os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
18439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
18539beb93cSSam Leffler 		    data->rand_server, EAP_GPSK_RAND_LEN);
18639beb93cSSam Leffler 	pos += EAP_GPSK_RAND_LEN;
18739beb93cSSam Leffler 
18839beb93cSSam Leffler 	return pos;
18939beb93cSSam Leffler }
19039beb93cSSam Leffler 
19139beb93cSSam Leffler 
eap_gpsk_select_csuite(struct eap_sm * sm,struct eap_gpsk_data * data,const u8 * csuite_list,size_t csuite_list_len)19239beb93cSSam Leffler static int eap_gpsk_select_csuite(struct eap_sm *sm,
19339beb93cSSam Leffler 				  struct eap_gpsk_data *data,
19439beb93cSSam Leffler 				  const u8 *csuite_list,
19539beb93cSSam Leffler 				  size_t csuite_list_len)
19639beb93cSSam Leffler {
19739beb93cSSam Leffler 	struct eap_gpsk_csuite *csuite;
19839beb93cSSam Leffler 	int i, count;
19939beb93cSSam Leffler 
20039beb93cSSam Leffler 	count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
20139beb93cSSam Leffler 	data->vendor = EAP_GPSK_VENDOR_IETF;
20239beb93cSSam Leffler 	data->specifier = EAP_GPSK_CIPHER_RESERVED;
20339beb93cSSam Leffler 	csuite = (struct eap_gpsk_csuite *) csuite_list;
20439beb93cSSam Leffler 	for (i = 0; i < count; i++) {
20539beb93cSSam Leffler 		int vendor, specifier;
20639beb93cSSam Leffler 		vendor = WPA_GET_BE32(csuite->vendor);
20739beb93cSSam Leffler 		specifier = WPA_GET_BE16(csuite->specifier);
20839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
20939beb93cSSam Leffler 			   i, vendor, specifier);
21039beb93cSSam Leffler 		if (data->vendor == EAP_GPSK_VENDOR_IETF &&
21139beb93cSSam Leffler 		    data->specifier == EAP_GPSK_CIPHER_RESERVED &&
2125b9c547cSRui Paulo 		    eap_gpsk_supported_ciphersuite(vendor, specifier) &&
2135b9c547cSRui Paulo 		    (!data->forced_cipher || data->forced_cipher == specifier))
2145b9c547cSRui Paulo 		{
21539beb93cSSam Leffler 			data->vendor = vendor;
21639beb93cSSam Leffler 			data->specifier = specifier;
21739beb93cSSam Leffler 		}
21839beb93cSSam Leffler 		csuite++;
21939beb93cSSam Leffler 	}
22039beb93cSSam Leffler 	if (data->vendor == EAP_GPSK_VENDOR_IETF &&
22139beb93cSSam Leffler 	    data->specifier == EAP_GPSK_CIPHER_RESERVED) {
22239beb93cSSam Leffler 		wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
22339beb93cSSam Leffler 			"ciphersuite found");
22439beb93cSSam Leffler 		return -1;
22539beb93cSSam Leffler 	}
22639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
22739beb93cSSam Leffler 		   data->vendor, data->specifier);
22839beb93cSSam Leffler 
22939beb93cSSam Leffler 	return 0;
23039beb93cSSam Leffler }
23139beb93cSSam Leffler 
23239beb93cSSam Leffler 
eap_gpsk_process_csuite_list(struct eap_sm * sm,struct eap_gpsk_data * data,const u8 ** list,size_t * list_len,const u8 * pos,const u8 * end)23339beb93cSSam Leffler static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
23439beb93cSSam Leffler 					       struct eap_gpsk_data *data,
23539beb93cSSam Leffler 					       const u8 **list,
23639beb93cSSam Leffler 					       size_t *list_len,
23739beb93cSSam Leffler 					       const u8 *pos, const u8 *end)
23839beb93cSSam Leffler {
2395b9c547cSRui Paulo 	size_t len;
2405b9c547cSRui Paulo 
24139beb93cSSam Leffler 	if (pos == NULL)
24239beb93cSSam Leffler 		return NULL;
24339beb93cSSam Leffler 
24439beb93cSSam Leffler 	if (end - pos < 2) {
24539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
24639beb93cSSam Leffler 		return NULL;
24739beb93cSSam Leffler 	}
2485b9c547cSRui Paulo 	len = WPA_GET_BE16(pos);
24939beb93cSSam Leffler 	pos += 2;
2505b9c547cSRui Paulo 	if (len > (size_t) (end - pos)) {
25139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
25239beb93cSSam Leffler 		return NULL;
25339beb93cSSam Leffler 	}
2545b9c547cSRui Paulo 	if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
25539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
2565b9c547cSRui Paulo 			   (unsigned long) len);
25739beb93cSSam Leffler 		return NULL;
25839beb93cSSam Leffler 	}
25939beb93cSSam Leffler 
2605b9c547cSRui Paulo 	if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
26139beb93cSSam Leffler 		return NULL;
26239beb93cSSam Leffler 
2635b9c547cSRui Paulo 	*list = pos;
2645b9c547cSRui Paulo 	*list_len = len;
2655b9c547cSRui Paulo 	pos += len;
2665b9c547cSRui Paulo 
26739beb93cSSam Leffler 	return pos;
26839beb93cSSam Leffler }
26939beb93cSSam Leffler 
27039beb93cSSam Leffler 
eap_gpsk_process_gpsk_1(struct eap_sm * sm,struct eap_gpsk_data * data,struct eap_method_ret * ret,u8 identifier,const u8 * payload,size_t payload_len)27139beb93cSSam Leffler static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
27239beb93cSSam Leffler 					       struct eap_gpsk_data *data,
27339beb93cSSam Leffler 					       struct eap_method_ret *ret,
274325151a3SRui Paulo 					       u8 identifier,
27539beb93cSSam Leffler 					       const u8 *payload,
27639beb93cSSam Leffler 					       size_t payload_len)
27739beb93cSSam Leffler {
27839beb93cSSam Leffler 	size_t csuite_list_len;
27939beb93cSSam Leffler 	const u8 *csuite_list, *pos, *end;
28039beb93cSSam Leffler 	struct wpabuf *resp;
28139beb93cSSam Leffler 
28239beb93cSSam Leffler 	if (data->state != GPSK_1) {
283*c1d255d3SCy Schubert 		ret->ignore = true;
28439beb93cSSam Leffler 		return NULL;
28539beb93cSSam Leffler 	}
28639beb93cSSam Leffler 
28739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
28839beb93cSSam Leffler 
28939beb93cSSam Leffler 	end = payload + payload_len;
29039beb93cSSam Leffler 
29139beb93cSSam Leffler 	pos = eap_gpsk_process_id_server(data, payload, end);
29239beb93cSSam Leffler 	pos = eap_gpsk_process_rand_server(data, pos, end);
29339beb93cSSam Leffler 	pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
29439beb93cSSam Leffler 					   &csuite_list_len, pos, end);
29539beb93cSSam Leffler 	if (pos == NULL) {
2965b9c547cSRui Paulo 		ret->methodState = METHOD_DONE;
29739beb93cSSam Leffler 		eap_gpsk_state(data, FAILURE);
29839beb93cSSam Leffler 		return NULL;
29939beb93cSSam Leffler 	}
30039beb93cSSam Leffler 
301325151a3SRui Paulo 	resp = eap_gpsk_send_gpsk_2(data, identifier,
30239beb93cSSam Leffler 				    csuite_list, csuite_list_len);
30339beb93cSSam Leffler 	if (resp == NULL)
30439beb93cSSam Leffler 		return NULL;
30539beb93cSSam Leffler 
30639beb93cSSam Leffler 	eap_gpsk_state(data, GPSK_3);
30739beb93cSSam Leffler 
30839beb93cSSam Leffler 	return resp;
30939beb93cSSam Leffler }
31039beb93cSSam Leffler 
31139beb93cSSam Leffler 
eap_gpsk_send_gpsk_2(struct eap_gpsk_data * data,u8 identifier,const u8 * csuite_list,size_t csuite_list_len)31239beb93cSSam Leffler static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
31339beb93cSSam Leffler 					    u8 identifier,
31439beb93cSSam Leffler 					    const u8 *csuite_list,
31539beb93cSSam Leffler 					    size_t csuite_list_len)
31639beb93cSSam Leffler {
31739beb93cSSam Leffler 	struct wpabuf *resp;
31839beb93cSSam Leffler 	size_t len, miclen;
31939beb93cSSam Leffler 	u8 *rpos, *start;
32039beb93cSSam Leffler 	struct eap_gpsk_csuite *csuite;
32139beb93cSSam Leffler 
32239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
32339beb93cSSam Leffler 
32439beb93cSSam Leffler 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
32539beb93cSSam Leffler 	len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
32639beb93cSSam Leffler 		2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
32739beb93cSSam Leffler 		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
32839beb93cSSam Leffler 
32939beb93cSSam Leffler 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
33039beb93cSSam Leffler 			     EAP_CODE_RESPONSE, identifier);
33139beb93cSSam Leffler 	if (resp == NULL)
33239beb93cSSam Leffler 		return NULL;
33339beb93cSSam Leffler 
33439beb93cSSam Leffler 	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
33539beb93cSSam Leffler 	start = wpabuf_put(resp, 0);
33639beb93cSSam Leffler 
33739beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
33839beb93cSSam Leffler 			  data->id_peer, data->id_peer_len);
33939beb93cSSam Leffler 	wpabuf_put_be16(resp, data->id_peer_len);
34039beb93cSSam Leffler 	wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
34139beb93cSSam Leffler 
34239beb93cSSam Leffler 	wpabuf_put_be16(resp, data->id_server_len);
34339beb93cSSam Leffler 	wpabuf_put_data(resp, data->id_server, data->id_server_len);
34439beb93cSSam Leffler 
345f05cddf9SRui Paulo 	if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
34639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
34739beb93cSSam Leffler 			   "for RAND_Peer");
34839beb93cSSam Leffler 		eap_gpsk_state(data, FAILURE);
34939beb93cSSam Leffler 		wpabuf_free(resp);
35039beb93cSSam Leffler 		return NULL;
35139beb93cSSam Leffler 	}
35239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
35339beb93cSSam Leffler 		    data->rand_peer, EAP_GPSK_RAND_LEN);
35439beb93cSSam Leffler 	wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
35539beb93cSSam Leffler 	wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
35639beb93cSSam Leffler 
35739beb93cSSam Leffler 	wpabuf_put_be16(resp, csuite_list_len);
35839beb93cSSam Leffler 	wpabuf_put_data(resp, csuite_list, csuite_list_len);
35939beb93cSSam Leffler 
36039beb93cSSam Leffler 	csuite = wpabuf_put(resp, sizeof(*csuite));
36139beb93cSSam Leffler 	WPA_PUT_BE32(csuite->vendor, data->vendor);
36239beb93cSSam Leffler 	WPA_PUT_BE16(csuite->specifier, data->specifier);
36339beb93cSSam Leffler 
36439beb93cSSam Leffler 	if (eap_gpsk_derive_keys(data->psk, data->psk_len,
36539beb93cSSam Leffler 				 data->vendor, data->specifier,
36639beb93cSSam Leffler 				 data->rand_peer, data->rand_server,
36739beb93cSSam Leffler 				 data->id_peer, data->id_peer_len,
36839beb93cSSam Leffler 				 data->id_server, data->id_server_len,
36939beb93cSSam Leffler 				 data->msk, data->emsk,
37039beb93cSSam Leffler 				 data->sk, &data->sk_len,
37139beb93cSSam Leffler 				 data->pk, &data->pk_len) < 0) {
37239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
37339beb93cSSam Leffler 		eap_gpsk_state(data, FAILURE);
37439beb93cSSam Leffler 		wpabuf_free(resp);
37539beb93cSSam Leffler 		return NULL;
37639beb93cSSam Leffler 	}
37739beb93cSSam Leffler 
3785b9c547cSRui Paulo 	if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
3795b9c547cSRui Paulo 				       data->vendor, data->specifier,
3805b9c547cSRui Paulo 				       data->rand_peer, data->rand_server,
3815b9c547cSRui Paulo 				       data->id_peer, data->id_peer_len,
3825b9c547cSRui Paulo 				       data->id_server, data->id_server_len,
3835b9c547cSRui Paulo 				       EAP_TYPE_GPSK,
3845b9c547cSRui Paulo 				       data->session_id, &data->id_len) < 0) {
3855b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
3865b9c547cSRui Paulo 		eap_gpsk_state(data, FAILURE);
3875b9c547cSRui Paulo 		wpabuf_free(resp);
3885b9c547cSRui Paulo 		return NULL;
3895b9c547cSRui Paulo 	}
3905b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
3915b9c547cSRui Paulo 		    data->session_id, data->id_len);
3925b9c547cSRui Paulo 
39339beb93cSSam Leffler 	/* No PD_Payload_1 */
39439beb93cSSam Leffler 	wpabuf_put_be16(resp, 0);
39539beb93cSSam Leffler 
39639beb93cSSam Leffler 	rpos = wpabuf_put(resp, miclen);
39739beb93cSSam Leffler 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
39839beb93cSSam Leffler 				 data->specifier, start, rpos - start, rpos) <
39939beb93cSSam Leffler 	    0) {
40039beb93cSSam Leffler 		eap_gpsk_state(data, FAILURE);
40139beb93cSSam Leffler 		wpabuf_free(resp);
40239beb93cSSam Leffler 		return NULL;
40339beb93cSSam Leffler 	}
40439beb93cSSam Leffler 
40539beb93cSSam Leffler 	return resp;
40639beb93cSSam Leffler }
40739beb93cSSam Leffler 
40839beb93cSSam Leffler 
eap_gpsk_validate_rand(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)40939beb93cSSam Leffler static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
41039beb93cSSam Leffler 					 const u8 *pos, const u8 *end)
41139beb93cSSam Leffler {
41239beb93cSSam Leffler 	if (end - pos < EAP_GPSK_RAND_LEN) {
41339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
41439beb93cSSam Leffler 			   "RAND_Peer");
41539beb93cSSam Leffler 		return NULL;
41639beb93cSSam Leffler 	}
41739beb93cSSam Leffler 	if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
41839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
41939beb93cSSam Leffler 			   "GPSK-3 did not match");
42039beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
42139beb93cSSam Leffler 			    data->rand_peer, EAP_GPSK_RAND_LEN);
42239beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
42339beb93cSSam Leffler 			    pos, EAP_GPSK_RAND_LEN);
42439beb93cSSam Leffler 		return NULL;
42539beb93cSSam Leffler 	}
42639beb93cSSam Leffler 	pos += EAP_GPSK_RAND_LEN;
42739beb93cSSam Leffler 
42839beb93cSSam Leffler 	if (end - pos < EAP_GPSK_RAND_LEN) {
42939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
43039beb93cSSam Leffler 			   "RAND_Server");
43139beb93cSSam Leffler 		return NULL;
43239beb93cSSam Leffler 	}
43339beb93cSSam Leffler 	if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
43439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
43539beb93cSSam Leffler 			   "GPSK-3 did not match");
43639beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
43739beb93cSSam Leffler 			    data->rand_server, EAP_GPSK_RAND_LEN);
43839beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
43939beb93cSSam Leffler 			    pos, EAP_GPSK_RAND_LEN);
44039beb93cSSam Leffler 		return NULL;
44139beb93cSSam Leffler 	}
44239beb93cSSam Leffler 	pos += EAP_GPSK_RAND_LEN;
44339beb93cSSam Leffler 
44439beb93cSSam Leffler 	return pos;
44539beb93cSSam Leffler }
44639beb93cSSam Leffler 
44739beb93cSSam Leffler 
eap_gpsk_validate_id_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)44839beb93cSSam Leffler static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
44939beb93cSSam Leffler 					      const u8 *pos, const u8 *end)
45039beb93cSSam Leffler {
45139beb93cSSam Leffler 	size_t len;
45239beb93cSSam Leffler 
45339beb93cSSam Leffler 	if (pos == NULL)
45439beb93cSSam Leffler 		return NULL;
45539beb93cSSam Leffler 
45639beb93cSSam Leffler 	if (end - pos < (int) 2) {
45739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
45839beb93cSSam Leffler 			   "length(ID_Server)");
45939beb93cSSam Leffler 		return NULL;
46039beb93cSSam Leffler 	}
46139beb93cSSam Leffler 
46239beb93cSSam Leffler 	len = WPA_GET_BE16(pos);
46339beb93cSSam Leffler 	pos += 2;
46439beb93cSSam Leffler 
46539beb93cSSam Leffler 	if (end - pos < (int) len) {
46639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
46739beb93cSSam Leffler 			   "ID_Server");
46839beb93cSSam Leffler 		return NULL;
46939beb93cSSam Leffler 	}
47039beb93cSSam Leffler 
47139beb93cSSam Leffler 	if (len != data->id_server_len ||
47239beb93cSSam Leffler 	    os_memcmp(pos, data->id_server, len) != 0) {
47339beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
47439beb93cSSam Leffler 			   "the one used in GPSK-1");
47539beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
47639beb93cSSam Leffler 				  data->id_server, data->id_server_len);
47739beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
47839beb93cSSam Leffler 				  pos, len);
47939beb93cSSam Leffler 		return NULL;
48039beb93cSSam Leffler 	}
48139beb93cSSam Leffler 
48239beb93cSSam Leffler 	pos += len;
48339beb93cSSam Leffler 
48439beb93cSSam Leffler 	return pos;
48539beb93cSSam Leffler }
48639beb93cSSam Leffler 
48739beb93cSSam Leffler 
eap_gpsk_validate_csuite(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)48839beb93cSSam Leffler static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
48939beb93cSSam Leffler 					   const u8 *pos, const u8 *end)
49039beb93cSSam Leffler {
49139beb93cSSam Leffler 	int vendor, specifier;
49239beb93cSSam Leffler 	const struct eap_gpsk_csuite *csuite;
49339beb93cSSam Leffler 
49439beb93cSSam Leffler 	if (pos == NULL)
49539beb93cSSam Leffler 		return NULL;
49639beb93cSSam Leffler 
49739beb93cSSam Leffler 	if (end - pos < (int) sizeof(*csuite)) {
49839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
49939beb93cSSam Leffler 			   "CSuite_Sel");
50039beb93cSSam Leffler 		return NULL;
50139beb93cSSam Leffler 	}
50239beb93cSSam Leffler 	csuite = (const struct eap_gpsk_csuite *) pos;
50339beb93cSSam Leffler 	vendor = WPA_GET_BE32(csuite->vendor);
50439beb93cSSam Leffler 	specifier = WPA_GET_BE16(csuite->specifier);
50539beb93cSSam Leffler 	pos += sizeof(*csuite);
50639beb93cSSam Leffler 	if (vendor != data->vendor || specifier != data->specifier) {
50739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
50839beb93cSSam Leffler 			   "match with the one sent in GPSK-2 (%d:%d)",
50939beb93cSSam Leffler 			   vendor, specifier, data->vendor, data->specifier);
51039beb93cSSam Leffler 		return NULL;
51139beb93cSSam Leffler 	}
51239beb93cSSam Leffler 
51339beb93cSSam Leffler 	return pos;
51439beb93cSSam Leffler }
51539beb93cSSam Leffler 
51639beb93cSSam Leffler 
eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)51739beb93cSSam Leffler static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
51839beb93cSSam Leffler 						 const u8 *pos, const u8 *end)
51939beb93cSSam Leffler {
52039beb93cSSam Leffler 	u16 alen;
52139beb93cSSam Leffler 
52239beb93cSSam Leffler 	if (pos == NULL)
52339beb93cSSam Leffler 		return NULL;
52439beb93cSSam Leffler 
52539beb93cSSam Leffler 	if (end - pos < 2) {
52639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
52739beb93cSSam Leffler 			   "PD_Payload_2 length");
52839beb93cSSam Leffler 		return NULL;
52939beb93cSSam Leffler 	}
53039beb93cSSam Leffler 	alen = WPA_GET_BE16(pos);
53139beb93cSSam Leffler 	pos += 2;
53239beb93cSSam Leffler 	if (end - pos < alen) {
53339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
53439beb93cSSam Leffler 			   "%d-octet PD_Payload_2", alen);
53539beb93cSSam Leffler 		return NULL;
53639beb93cSSam Leffler 	}
53739beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
53839beb93cSSam Leffler 	pos += alen;
53939beb93cSSam Leffler 
54039beb93cSSam Leffler 	return pos;
54139beb93cSSam Leffler }
54239beb93cSSam Leffler 
54339beb93cSSam Leffler 
eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data * data,const u8 * payload,const u8 * pos,const u8 * end)54439beb93cSSam Leffler static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
54539beb93cSSam Leffler 					       const u8 *payload,
54639beb93cSSam Leffler 					       const u8 *pos, const u8 *end)
54739beb93cSSam Leffler {
54839beb93cSSam Leffler 	size_t miclen;
54939beb93cSSam Leffler 	u8 mic[EAP_GPSK_MAX_MIC_LEN];
55039beb93cSSam Leffler 
55139beb93cSSam Leffler 	if (pos == NULL)
55239beb93cSSam Leffler 		return NULL;
55339beb93cSSam Leffler 
55439beb93cSSam Leffler 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
55539beb93cSSam Leffler 	if (end - pos < (int) miclen) {
55639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
55739beb93cSSam Leffler 			   "(left=%lu miclen=%lu)",
55839beb93cSSam Leffler 			   (unsigned long) (end - pos),
55939beb93cSSam Leffler 			   (unsigned long) miclen);
56039beb93cSSam Leffler 		return NULL;
56139beb93cSSam Leffler 	}
56239beb93cSSam Leffler 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
56339beb93cSSam Leffler 				 data->specifier, payload, pos - payload, mic)
56439beb93cSSam Leffler 	    < 0) {
56539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
56639beb93cSSam Leffler 		return NULL;
56739beb93cSSam Leffler 	}
5685b9c547cSRui Paulo 	if (os_memcmp_const(mic, pos, miclen) != 0) {
56939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
57039beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
57139beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
57239beb93cSSam Leffler 		return NULL;
57339beb93cSSam Leffler 	}
57439beb93cSSam Leffler 	pos += miclen;
57539beb93cSSam Leffler 
57639beb93cSSam Leffler 	return pos;
57739beb93cSSam Leffler }
57839beb93cSSam Leffler 
57939beb93cSSam Leffler 
eap_gpsk_process_gpsk_3(struct eap_sm * sm,struct eap_gpsk_data * data,struct eap_method_ret * ret,u8 identifier,const u8 * payload,size_t payload_len)58039beb93cSSam Leffler static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
58139beb93cSSam Leffler 					       struct eap_gpsk_data *data,
58239beb93cSSam Leffler 					       struct eap_method_ret *ret,
583325151a3SRui Paulo 					       u8 identifier,
58439beb93cSSam Leffler 					       const u8 *payload,
58539beb93cSSam Leffler 					       size_t payload_len)
58639beb93cSSam Leffler {
58739beb93cSSam Leffler 	struct wpabuf *resp;
58839beb93cSSam Leffler 	const u8 *pos, *end;
58939beb93cSSam Leffler 
59039beb93cSSam Leffler 	if (data->state != GPSK_3) {
591*c1d255d3SCy Schubert 		ret->ignore = true;
59239beb93cSSam Leffler 		return NULL;
59339beb93cSSam Leffler 	}
59439beb93cSSam Leffler 
59539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
59639beb93cSSam Leffler 
59739beb93cSSam Leffler 	end = payload + payload_len;
59839beb93cSSam Leffler 
59939beb93cSSam Leffler 	pos = eap_gpsk_validate_rand(data, payload, end);
60039beb93cSSam Leffler 	pos = eap_gpsk_validate_id_server(data, pos, end);
60139beb93cSSam Leffler 	pos = eap_gpsk_validate_csuite(data, pos, end);
60239beb93cSSam Leffler 	pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
60339beb93cSSam Leffler 	pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
60439beb93cSSam Leffler 
60539beb93cSSam Leffler 	if (pos == NULL) {
60639beb93cSSam Leffler 		eap_gpsk_state(data, FAILURE);
60739beb93cSSam Leffler 		return NULL;
60839beb93cSSam Leffler 	}
60939beb93cSSam Leffler 	if (pos != end) {
61039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
61139beb93cSSam Leffler 			   "data in the end of GPSK-2",
61239beb93cSSam Leffler 			   (unsigned long) (end - pos));
61339beb93cSSam Leffler 	}
61439beb93cSSam Leffler 
615325151a3SRui Paulo 	resp = eap_gpsk_send_gpsk_4(data, identifier);
61639beb93cSSam Leffler 	if (resp == NULL)
61739beb93cSSam Leffler 		return NULL;
61839beb93cSSam Leffler 
61939beb93cSSam Leffler 	eap_gpsk_state(data, SUCCESS);
62039beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
62139beb93cSSam Leffler 	ret->decision = DECISION_UNCOND_SUCC;
62239beb93cSSam Leffler 
62339beb93cSSam Leffler 	return resp;
62439beb93cSSam Leffler }
62539beb93cSSam Leffler 
62639beb93cSSam Leffler 
eap_gpsk_send_gpsk_4(struct eap_gpsk_data * data,u8 identifier)62739beb93cSSam Leffler static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
62839beb93cSSam Leffler 					    u8 identifier)
62939beb93cSSam Leffler {
63039beb93cSSam Leffler 	struct wpabuf *resp;
63139beb93cSSam Leffler 	u8 *rpos, *start;
63239beb93cSSam Leffler 	size_t mlen;
63339beb93cSSam Leffler 
63439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
63539beb93cSSam Leffler 
63639beb93cSSam Leffler 	mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
63739beb93cSSam Leffler 
63839beb93cSSam Leffler 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
63939beb93cSSam Leffler 			     EAP_CODE_RESPONSE, identifier);
64039beb93cSSam Leffler 	if (resp == NULL)
64139beb93cSSam Leffler 		return NULL;
64239beb93cSSam Leffler 
64339beb93cSSam Leffler 	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
64439beb93cSSam Leffler 	start = wpabuf_put(resp, 0);
64539beb93cSSam Leffler 
64639beb93cSSam Leffler 	/* No PD_Payload_3 */
64739beb93cSSam Leffler 	wpabuf_put_be16(resp, 0);
64839beb93cSSam Leffler 
64939beb93cSSam Leffler 	rpos = wpabuf_put(resp, mlen);
65039beb93cSSam Leffler 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
65139beb93cSSam Leffler 				 data->specifier, start, rpos - start, rpos) <
65239beb93cSSam Leffler 	    0) {
65339beb93cSSam Leffler 		eap_gpsk_state(data, FAILURE);
65439beb93cSSam Leffler 		wpabuf_free(resp);
65539beb93cSSam Leffler 		return NULL;
65639beb93cSSam Leffler 	}
65739beb93cSSam Leffler 
65839beb93cSSam Leffler 	return resp;
65939beb93cSSam Leffler }
66039beb93cSSam Leffler 
66139beb93cSSam Leffler 
eap_gpsk_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)66239beb93cSSam Leffler static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
66339beb93cSSam Leffler 					struct eap_method_ret *ret,
66439beb93cSSam Leffler 					const struct wpabuf *reqData)
66539beb93cSSam Leffler {
66639beb93cSSam Leffler 	struct eap_gpsk_data *data = priv;
66739beb93cSSam Leffler 	struct wpabuf *resp;
66839beb93cSSam Leffler 	const u8 *pos;
66939beb93cSSam Leffler 	size_t len;
670325151a3SRui Paulo 	u8 opcode, id;
67139beb93cSSam Leffler 
67239beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
67339beb93cSSam Leffler 	if (pos == NULL || len < 1) {
674*c1d255d3SCy Schubert 		ret->ignore = true;
67539beb93cSSam Leffler 		return NULL;
67639beb93cSSam Leffler 	}
67739beb93cSSam Leffler 
678325151a3SRui Paulo 	id = eap_get_id(reqData);
679325151a3SRui Paulo 	opcode = *pos++;
680325151a3SRui Paulo 	len--;
681325151a3SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
68239beb93cSSam Leffler 
683*c1d255d3SCy Schubert 	ret->ignore = false;
68439beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
68539beb93cSSam Leffler 	ret->decision = DECISION_FAIL;
686*c1d255d3SCy Schubert 	ret->allowNotifications = false;
68739beb93cSSam Leffler 
688325151a3SRui Paulo 	switch (opcode) {
68939beb93cSSam Leffler 	case EAP_GPSK_OPCODE_GPSK_1:
690325151a3SRui Paulo 		resp = eap_gpsk_process_gpsk_1(sm, data, ret, id, pos, len);
69139beb93cSSam Leffler 		break;
69239beb93cSSam Leffler 	case EAP_GPSK_OPCODE_GPSK_3:
693325151a3SRui Paulo 		resp = eap_gpsk_process_gpsk_3(sm, data, ret, id, pos, len);
69439beb93cSSam Leffler 		break;
69539beb93cSSam Leffler 	default:
696325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
697325151a3SRui Paulo 			   "EAP-GPSK: Ignoring message with unknown opcode %d",
698325151a3SRui Paulo 			   opcode);
699*c1d255d3SCy Schubert 		ret->ignore = true;
70039beb93cSSam Leffler 		return NULL;
70139beb93cSSam Leffler 	}
70239beb93cSSam Leffler 
70339beb93cSSam Leffler 	return resp;
70439beb93cSSam Leffler }
70539beb93cSSam Leffler 
70639beb93cSSam Leffler 
eap_gpsk_isKeyAvailable(struct eap_sm * sm,void * priv)707*c1d255d3SCy Schubert static bool eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
70839beb93cSSam Leffler {
70939beb93cSSam Leffler 	struct eap_gpsk_data *data = priv;
71039beb93cSSam Leffler 	return data->state == SUCCESS;
71139beb93cSSam Leffler }
71239beb93cSSam Leffler 
71339beb93cSSam Leffler 
eap_gpsk_getKey(struct eap_sm * sm,void * priv,size_t * len)71439beb93cSSam Leffler static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
71539beb93cSSam Leffler {
71639beb93cSSam Leffler 	struct eap_gpsk_data *data = priv;
71739beb93cSSam Leffler 	u8 *key;
71839beb93cSSam Leffler 
71939beb93cSSam Leffler 	if (data->state != SUCCESS)
72039beb93cSSam Leffler 		return NULL;
72139beb93cSSam Leffler 
72285732ac8SCy Schubert 	key = os_memdup(data->msk, EAP_MSK_LEN);
72339beb93cSSam Leffler 	if (key == NULL)
72439beb93cSSam Leffler 		return NULL;
72539beb93cSSam Leffler 	*len = EAP_MSK_LEN;
72639beb93cSSam Leffler 
72739beb93cSSam Leffler 	return key;
72839beb93cSSam Leffler }
72939beb93cSSam Leffler 
73039beb93cSSam Leffler 
eap_gpsk_get_emsk(struct eap_sm * sm,void * priv,size_t * len)73139beb93cSSam Leffler static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
73239beb93cSSam Leffler {
73339beb93cSSam Leffler 	struct eap_gpsk_data *data = priv;
73439beb93cSSam Leffler 	u8 *key;
73539beb93cSSam Leffler 
73639beb93cSSam Leffler 	if (data->state != SUCCESS)
73739beb93cSSam Leffler 		return NULL;
73839beb93cSSam Leffler 
73985732ac8SCy Schubert 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
74039beb93cSSam Leffler 	if (key == NULL)
74139beb93cSSam Leffler 		return NULL;
74239beb93cSSam Leffler 	*len = EAP_EMSK_LEN;
74339beb93cSSam Leffler 
74439beb93cSSam Leffler 	return key;
74539beb93cSSam Leffler }
74639beb93cSSam Leffler 
74739beb93cSSam Leffler 
eap_gpsk_get_session_id(struct eap_sm * sm,void * priv,size_t * len)7485b9c547cSRui Paulo static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
7495b9c547cSRui Paulo {
7505b9c547cSRui Paulo 	struct eap_gpsk_data *data = priv;
7515b9c547cSRui Paulo 	u8 *sid;
7525b9c547cSRui Paulo 
7535b9c547cSRui Paulo 	if (data->state != SUCCESS)
7545b9c547cSRui Paulo 		return NULL;
7555b9c547cSRui Paulo 
75685732ac8SCy Schubert 	sid = os_memdup(data->session_id, data->id_len);
7575b9c547cSRui Paulo 	if (sid == NULL)
7585b9c547cSRui Paulo 		return NULL;
7595b9c547cSRui Paulo 	*len = data->id_len;
7605b9c547cSRui Paulo 
7615b9c547cSRui Paulo 	return sid;
7625b9c547cSRui Paulo }
7635b9c547cSRui Paulo 
7645b9c547cSRui Paulo 
eap_peer_gpsk_register(void)76539beb93cSSam Leffler int eap_peer_gpsk_register(void)
76639beb93cSSam Leffler {
76739beb93cSSam Leffler 	struct eap_method *eap;
76839beb93cSSam Leffler 
76939beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
77039beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
77139beb93cSSam Leffler 	if (eap == NULL)
77239beb93cSSam Leffler 		return -1;
77339beb93cSSam Leffler 
77439beb93cSSam Leffler 	eap->init = eap_gpsk_init;
77539beb93cSSam Leffler 	eap->deinit = eap_gpsk_deinit;
77639beb93cSSam Leffler 	eap->process = eap_gpsk_process;
77739beb93cSSam Leffler 	eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
77839beb93cSSam Leffler 	eap->getKey = eap_gpsk_getKey;
77939beb93cSSam Leffler 	eap->get_emsk = eap_gpsk_get_emsk;
7805b9c547cSRui Paulo 	eap->getSessionId = eap_gpsk_get_session_id;
78139beb93cSSam Leffler 
782780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
78339beb93cSSam Leffler }
784