xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_peer/eap_gpsk.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer  * EAP peer method: EAP-GPSK (RFC 5433)
33ff40c12SJohn Marino  * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  */
86d49e1aeSJan Lentfer 
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer 
116d49e1aeSJan Lentfer #include "common.h"
123ff40c12SJohn Marino #include "crypto/random.h"
136d49e1aeSJan Lentfer #include "eap_peer/eap_i.h"
146d49e1aeSJan Lentfer #include "eap_common/eap_gpsk_common.h"
156d49e1aeSJan Lentfer 
166d49e1aeSJan Lentfer struct eap_gpsk_data {
176d49e1aeSJan Lentfer 	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
186d49e1aeSJan Lentfer 	u8 rand_server[EAP_GPSK_RAND_LEN];
196d49e1aeSJan Lentfer 	u8 rand_peer[EAP_GPSK_RAND_LEN];
206d49e1aeSJan Lentfer 	u8 msk[EAP_MSK_LEN];
216d49e1aeSJan Lentfer 	u8 emsk[EAP_EMSK_LEN];
226d49e1aeSJan Lentfer 	u8 sk[EAP_GPSK_MAX_SK_LEN];
236d49e1aeSJan Lentfer 	size_t sk_len;
246d49e1aeSJan Lentfer 	u8 pk[EAP_GPSK_MAX_PK_LEN];
256d49e1aeSJan Lentfer 	size_t pk_len;
263ff40c12SJohn Marino 	u8 session_id[128];
273ff40c12SJohn Marino 	size_t id_len;
286d49e1aeSJan Lentfer 	u8 *id_peer;
296d49e1aeSJan Lentfer 	size_t id_peer_len;
306d49e1aeSJan Lentfer 	u8 *id_server;
316d49e1aeSJan Lentfer 	size_t id_server_len;
326d49e1aeSJan Lentfer 	int vendor; /* CSuite/Specifier */
336d49e1aeSJan Lentfer 	int specifier; /* CSuite/Specifier */
346d49e1aeSJan Lentfer 	u8 *psk;
356d49e1aeSJan Lentfer 	size_t psk_len;
363ff40c12SJohn Marino 	u16 forced_cipher; /* force cipher or 0 to allow all supported */
376d49e1aeSJan Lentfer };
386d49e1aeSJan Lentfer 
396d49e1aeSJan Lentfer 
406d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
416d49e1aeSJan Lentfer 					    u8 identifier,
426d49e1aeSJan Lentfer 					    const u8 *csuite_list,
436d49e1aeSJan Lentfer 					    size_t csuite_list_len);
446d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
456d49e1aeSJan Lentfer 					    u8 identifier);
466d49e1aeSJan Lentfer 
476d49e1aeSJan Lentfer 
486d49e1aeSJan Lentfer #ifndef CONFIG_NO_STDOUT_DEBUG
eap_gpsk_state_txt(int state)496d49e1aeSJan Lentfer static const char * eap_gpsk_state_txt(int state)
506d49e1aeSJan Lentfer {
516d49e1aeSJan Lentfer 	switch (state) {
526d49e1aeSJan Lentfer 	case GPSK_1:
536d49e1aeSJan Lentfer 		return "GPSK-1";
546d49e1aeSJan Lentfer 	case GPSK_3:
556d49e1aeSJan Lentfer 		return "GPSK-3";
566d49e1aeSJan Lentfer 	case SUCCESS:
576d49e1aeSJan Lentfer 		return "SUCCESS";
586d49e1aeSJan Lentfer 	case FAILURE:
596d49e1aeSJan Lentfer 		return "FAILURE";
606d49e1aeSJan Lentfer 	default:
616d49e1aeSJan Lentfer 		return "?";
626d49e1aeSJan Lentfer 	}
636d49e1aeSJan Lentfer }
646d49e1aeSJan Lentfer #endif /* CONFIG_NO_STDOUT_DEBUG */
656d49e1aeSJan Lentfer 
666d49e1aeSJan Lentfer 
eap_gpsk_state(struct eap_gpsk_data * data,int state)676d49e1aeSJan Lentfer static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
686d49e1aeSJan Lentfer {
696d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
706d49e1aeSJan Lentfer 		   eap_gpsk_state_txt(data->state),
716d49e1aeSJan Lentfer 		   eap_gpsk_state_txt(state));
726d49e1aeSJan Lentfer 	data->state = state;
736d49e1aeSJan Lentfer }
746d49e1aeSJan Lentfer 
756d49e1aeSJan Lentfer 
766d49e1aeSJan Lentfer static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
776d49e1aeSJan Lentfer 
786d49e1aeSJan Lentfer 
eap_gpsk_init(struct eap_sm * sm)796d49e1aeSJan Lentfer static void * eap_gpsk_init(struct eap_sm *sm)
806d49e1aeSJan Lentfer {
816d49e1aeSJan Lentfer 	struct eap_gpsk_data *data;
826d49e1aeSJan Lentfer 	const u8 *identity, *password;
836d49e1aeSJan Lentfer 	size_t identity_len, password_len;
843ff40c12SJohn Marino 	const char *phase1;
856d49e1aeSJan Lentfer 
866d49e1aeSJan Lentfer 	password = eap_get_config_password(sm, &password_len);
876d49e1aeSJan Lentfer 	if (password == NULL) {
886d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
896d49e1aeSJan Lentfer 		return NULL;
906d49e1aeSJan Lentfer 	}
916d49e1aeSJan Lentfer 
926d49e1aeSJan Lentfer 	data = os_zalloc(sizeof(*data));
936d49e1aeSJan Lentfer 	if (data == NULL)
946d49e1aeSJan Lentfer 		return NULL;
956d49e1aeSJan Lentfer 	data->state = GPSK_1;
966d49e1aeSJan Lentfer 
976d49e1aeSJan Lentfer 	identity = eap_get_config_identity(sm, &identity_len);
986d49e1aeSJan Lentfer 	if (identity) {
99*a1157835SDaniel Fojt 		data->id_peer = os_memdup(identity, identity_len);
1006d49e1aeSJan Lentfer 		if (data->id_peer == NULL) {
1016d49e1aeSJan Lentfer 			eap_gpsk_deinit(sm, data);
1026d49e1aeSJan Lentfer 			return NULL;
1036d49e1aeSJan Lentfer 		}
1046d49e1aeSJan Lentfer 		data->id_peer_len = identity_len;
1056d49e1aeSJan Lentfer 	}
1066d49e1aeSJan Lentfer 
1073ff40c12SJohn Marino 	phase1 = eap_get_config_phase1(sm);
1083ff40c12SJohn Marino 	if (phase1) {
1093ff40c12SJohn Marino 		const char *pos;
1103ff40c12SJohn Marino 
1113ff40c12SJohn Marino 		pos = os_strstr(phase1, "cipher=");
1123ff40c12SJohn Marino 		if (pos) {
1133ff40c12SJohn Marino 			data->forced_cipher = atoi(pos + 7);
1143ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u",
1153ff40c12SJohn Marino 				   data->forced_cipher);
1163ff40c12SJohn Marino 		}
1173ff40c12SJohn Marino 	}
1183ff40c12SJohn Marino 
119*a1157835SDaniel Fojt 	data->psk = os_memdup(password, password_len);
1206d49e1aeSJan Lentfer 	if (data->psk == NULL) {
1216d49e1aeSJan Lentfer 		eap_gpsk_deinit(sm, data);
1226d49e1aeSJan Lentfer 		return NULL;
1236d49e1aeSJan Lentfer 	}
1246d49e1aeSJan Lentfer 	data->psk_len = password_len;
1256d49e1aeSJan Lentfer 
1266d49e1aeSJan Lentfer 	return data;
1276d49e1aeSJan Lentfer }
1286d49e1aeSJan Lentfer 
1296d49e1aeSJan Lentfer 
eap_gpsk_deinit(struct eap_sm * sm,void * priv)1306d49e1aeSJan Lentfer static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
1316d49e1aeSJan Lentfer {
1326d49e1aeSJan Lentfer 	struct eap_gpsk_data *data = priv;
1336d49e1aeSJan Lentfer 	os_free(data->id_server);
1346d49e1aeSJan Lentfer 	os_free(data->id_peer);
135*a1157835SDaniel Fojt 	if (data->psk) {
136*a1157835SDaniel Fojt 		os_memset(data->psk, 0, data->psk_len);
1376d49e1aeSJan Lentfer 		os_free(data->psk);
138*a1157835SDaniel Fojt 	}
139*a1157835SDaniel Fojt 	bin_clear_free(data, sizeof(*data));
1406d49e1aeSJan Lentfer }
1416d49e1aeSJan Lentfer 
1426d49e1aeSJan Lentfer 
eap_gpsk_process_id_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)1436d49e1aeSJan Lentfer static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
1446d49e1aeSJan Lentfer 					     const u8 *pos, const u8 *end)
1456d49e1aeSJan Lentfer {
1466d49e1aeSJan Lentfer 	u16 alen;
1476d49e1aeSJan Lentfer 
1486d49e1aeSJan Lentfer 	if (end - pos < 2) {
1496d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
1506d49e1aeSJan Lentfer 		return NULL;
1516d49e1aeSJan Lentfer 	}
1526d49e1aeSJan Lentfer 	alen = WPA_GET_BE16(pos);
1536d49e1aeSJan Lentfer 	pos += 2;
1546d49e1aeSJan Lentfer 	if (end - pos < alen) {
1556d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
1566d49e1aeSJan Lentfer 		return NULL;
1576d49e1aeSJan Lentfer 	}
1586d49e1aeSJan Lentfer 	os_free(data->id_server);
159*a1157835SDaniel Fojt 	data->id_server = os_memdup(pos, alen);
1606d49e1aeSJan Lentfer 	if (data->id_server == NULL) {
1616d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
1626d49e1aeSJan Lentfer 		return NULL;
1636d49e1aeSJan Lentfer 	}
1646d49e1aeSJan Lentfer 	data->id_server_len = alen;
1656d49e1aeSJan Lentfer 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
1666d49e1aeSJan Lentfer 			  data->id_server, data->id_server_len);
1676d49e1aeSJan Lentfer 	pos += alen;
1686d49e1aeSJan Lentfer 
1696d49e1aeSJan Lentfer 	return pos;
1706d49e1aeSJan Lentfer }
1716d49e1aeSJan Lentfer 
1726d49e1aeSJan Lentfer 
eap_gpsk_process_rand_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)1736d49e1aeSJan Lentfer static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
1746d49e1aeSJan Lentfer 					       const u8 *pos, const u8 *end)
1756d49e1aeSJan Lentfer {
1766d49e1aeSJan Lentfer 	if (pos == NULL)
1776d49e1aeSJan Lentfer 		return NULL;
1786d49e1aeSJan Lentfer 
1796d49e1aeSJan Lentfer 	if (end - pos < EAP_GPSK_RAND_LEN) {
1806d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
1816d49e1aeSJan Lentfer 		return NULL;
1826d49e1aeSJan Lentfer 	}
1836d49e1aeSJan Lentfer 	os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
1846d49e1aeSJan Lentfer 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
1856d49e1aeSJan Lentfer 		    data->rand_server, EAP_GPSK_RAND_LEN);
1866d49e1aeSJan Lentfer 	pos += EAP_GPSK_RAND_LEN;
1876d49e1aeSJan Lentfer 
1886d49e1aeSJan Lentfer 	return pos;
1896d49e1aeSJan Lentfer }
1906d49e1aeSJan Lentfer 
1916d49e1aeSJan Lentfer 
eap_gpsk_select_csuite(struct eap_sm * sm,struct eap_gpsk_data * data,const u8 * csuite_list,size_t csuite_list_len)1926d49e1aeSJan Lentfer static int eap_gpsk_select_csuite(struct eap_sm *sm,
1936d49e1aeSJan Lentfer 				  struct eap_gpsk_data *data,
1946d49e1aeSJan Lentfer 				  const u8 *csuite_list,
1956d49e1aeSJan Lentfer 				  size_t csuite_list_len)
1966d49e1aeSJan Lentfer {
1976d49e1aeSJan Lentfer 	struct eap_gpsk_csuite *csuite;
1986d49e1aeSJan Lentfer 	int i, count;
1996d49e1aeSJan Lentfer 
2006d49e1aeSJan Lentfer 	count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
2016d49e1aeSJan Lentfer 	data->vendor = EAP_GPSK_VENDOR_IETF;
2026d49e1aeSJan Lentfer 	data->specifier = EAP_GPSK_CIPHER_RESERVED;
2036d49e1aeSJan Lentfer 	csuite = (struct eap_gpsk_csuite *) csuite_list;
2046d49e1aeSJan Lentfer 	for (i = 0; i < count; i++) {
2056d49e1aeSJan Lentfer 		int vendor, specifier;
2066d49e1aeSJan Lentfer 		vendor = WPA_GET_BE32(csuite->vendor);
2076d49e1aeSJan Lentfer 		specifier = WPA_GET_BE16(csuite->specifier);
2086d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
2096d49e1aeSJan Lentfer 			   i, vendor, specifier);
2106d49e1aeSJan Lentfer 		if (data->vendor == EAP_GPSK_VENDOR_IETF &&
2116d49e1aeSJan Lentfer 		    data->specifier == EAP_GPSK_CIPHER_RESERVED &&
2123ff40c12SJohn Marino 		    eap_gpsk_supported_ciphersuite(vendor, specifier) &&
2133ff40c12SJohn Marino 		    (!data->forced_cipher || data->forced_cipher == specifier))
2143ff40c12SJohn Marino 		{
2156d49e1aeSJan Lentfer 			data->vendor = vendor;
2166d49e1aeSJan Lentfer 			data->specifier = specifier;
2176d49e1aeSJan Lentfer 		}
2186d49e1aeSJan Lentfer 		csuite++;
2196d49e1aeSJan Lentfer 	}
2206d49e1aeSJan Lentfer 	if (data->vendor == EAP_GPSK_VENDOR_IETF &&
2216d49e1aeSJan Lentfer 	    data->specifier == EAP_GPSK_CIPHER_RESERVED) {
2226d49e1aeSJan Lentfer 		wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
2236d49e1aeSJan Lentfer 			"ciphersuite found");
2246d49e1aeSJan Lentfer 		return -1;
2256d49e1aeSJan Lentfer 	}
2266d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
2276d49e1aeSJan Lentfer 		   data->vendor, data->specifier);
2286d49e1aeSJan Lentfer 
2296d49e1aeSJan Lentfer 	return 0;
2306d49e1aeSJan Lentfer }
2316d49e1aeSJan Lentfer 
2326d49e1aeSJan Lentfer 
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)2336d49e1aeSJan Lentfer static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
2346d49e1aeSJan Lentfer 					       struct eap_gpsk_data *data,
2356d49e1aeSJan Lentfer 					       const u8 **list,
2366d49e1aeSJan Lentfer 					       size_t *list_len,
2376d49e1aeSJan Lentfer 					       const u8 *pos, const u8 *end)
2386d49e1aeSJan Lentfer {
239*a1157835SDaniel Fojt 	size_t len;
240*a1157835SDaniel Fojt 
2416d49e1aeSJan Lentfer 	if (pos == NULL)
2426d49e1aeSJan Lentfer 		return NULL;
2436d49e1aeSJan Lentfer 
2446d49e1aeSJan Lentfer 	if (end - pos < 2) {
2456d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
2466d49e1aeSJan Lentfer 		return NULL;
2476d49e1aeSJan Lentfer 	}
248*a1157835SDaniel Fojt 	len = WPA_GET_BE16(pos);
2496d49e1aeSJan Lentfer 	pos += 2;
250*a1157835SDaniel Fojt 	if (len > (size_t) (end - pos)) {
2516d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
2526d49e1aeSJan Lentfer 		return NULL;
2536d49e1aeSJan Lentfer 	}
254*a1157835SDaniel Fojt 	if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
2556d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
256*a1157835SDaniel Fojt 			   (unsigned long) len);
2576d49e1aeSJan Lentfer 		return NULL;
2586d49e1aeSJan Lentfer 	}
2596d49e1aeSJan Lentfer 
260*a1157835SDaniel Fojt 	if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
2616d49e1aeSJan Lentfer 		return NULL;
2626d49e1aeSJan Lentfer 
263*a1157835SDaniel Fojt 	*list = pos;
264*a1157835SDaniel Fojt 	*list_len = len;
265*a1157835SDaniel Fojt 	pos += len;
266*a1157835SDaniel Fojt 
2676d49e1aeSJan Lentfer 	return pos;
2686d49e1aeSJan Lentfer }
2696d49e1aeSJan Lentfer 
2706d49e1aeSJan Lentfer 
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)2716d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
2726d49e1aeSJan Lentfer 					       struct eap_gpsk_data *data,
2736d49e1aeSJan Lentfer 					       struct eap_method_ret *ret,
274*a1157835SDaniel Fojt 					       u8 identifier,
2756d49e1aeSJan Lentfer 					       const u8 *payload,
2766d49e1aeSJan Lentfer 					       size_t payload_len)
2776d49e1aeSJan Lentfer {
2786d49e1aeSJan Lentfer 	size_t csuite_list_len;
2796d49e1aeSJan Lentfer 	const u8 *csuite_list, *pos, *end;
2806d49e1aeSJan Lentfer 	struct wpabuf *resp;
2816d49e1aeSJan Lentfer 
2826d49e1aeSJan Lentfer 	if (data->state != GPSK_1) {
2836d49e1aeSJan Lentfer 		ret->ignore = TRUE;
2846d49e1aeSJan Lentfer 		return NULL;
2856d49e1aeSJan Lentfer 	}
2866d49e1aeSJan Lentfer 
2876d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
2886d49e1aeSJan Lentfer 
2896d49e1aeSJan Lentfer 	end = payload + payload_len;
2906d49e1aeSJan Lentfer 
2916d49e1aeSJan Lentfer 	pos = eap_gpsk_process_id_server(data, payload, end);
2926d49e1aeSJan Lentfer 	pos = eap_gpsk_process_rand_server(data, pos, end);
2936d49e1aeSJan Lentfer 	pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
2946d49e1aeSJan Lentfer 					   &csuite_list_len, pos, end);
2956d49e1aeSJan Lentfer 	if (pos == NULL) {
2963ff40c12SJohn Marino 		ret->methodState = METHOD_DONE;
2976d49e1aeSJan Lentfer 		eap_gpsk_state(data, FAILURE);
2986d49e1aeSJan Lentfer 		return NULL;
2996d49e1aeSJan Lentfer 	}
3006d49e1aeSJan Lentfer 
301*a1157835SDaniel Fojt 	resp = eap_gpsk_send_gpsk_2(data, identifier,
3026d49e1aeSJan Lentfer 				    csuite_list, csuite_list_len);
3036d49e1aeSJan Lentfer 	if (resp == NULL)
3046d49e1aeSJan Lentfer 		return NULL;
3056d49e1aeSJan Lentfer 
3066d49e1aeSJan Lentfer 	eap_gpsk_state(data, GPSK_3);
3076d49e1aeSJan Lentfer 
3086d49e1aeSJan Lentfer 	return resp;
3096d49e1aeSJan Lentfer }
3106d49e1aeSJan Lentfer 
3116d49e1aeSJan Lentfer 
eap_gpsk_send_gpsk_2(struct eap_gpsk_data * data,u8 identifier,const u8 * csuite_list,size_t csuite_list_len)3126d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
3136d49e1aeSJan Lentfer 					    u8 identifier,
3146d49e1aeSJan Lentfer 					    const u8 *csuite_list,
3156d49e1aeSJan Lentfer 					    size_t csuite_list_len)
3166d49e1aeSJan Lentfer {
3176d49e1aeSJan Lentfer 	struct wpabuf *resp;
3186d49e1aeSJan Lentfer 	size_t len, miclen;
3196d49e1aeSJan Lentfer 	u8 *rpos, *start;
3206d49e1aeSJan Lentfer 	struct eap_gpsk_csuite *csuite;
3216d49e1aeSJan Lentfer 
3226d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
3236d49e1aeSJan Lentfer 
3246d49e1aeSJan Lentfer 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
3256d49e1aeSJan Lentfer 	len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
3266d49e1aeSJan Lentfer 		2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
3276d49e1aeSJan Lentfer 		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
3286d49e1aeSJan Lentfer 
3296d49e1aeSJan Lentfer 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
3306d49e1aeSJan Lentfer 			     EAP_CODE_RESPONSE, identifier);
3316d49e1aeSJan Lentfer 	if (resp == NULL)
3326d49e1aeSJan Lentfer 		return NULL;
3336d49e1aeSJan Lentfer 
3346d49e1aeSJan Lentfer 	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
3356d49e1aeSJan Lentfer 	start = wpabuf_put(resp, 0);
3366d49e1aeSJan Lentfer 
3376d49e1aeSJan Lentfer 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
3386d49e1aeSJan Lentfer 			  data->id_peer, data->id_peer_len);
3396d49e1aeSJan Lentfer 	wpabuf_put_be16(resp, data->id_peer_len);
3406d49e1aeSJan Lentfer 	wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
3416d49e1aeSJan Lentfer 
3426d49e1aeSJan Lentfer 	wpabuf_put_be16(resp, data->id_server_len);
3436d49e1aeSJan Lentfer 	wpabuf_put_data(resp, data->id_server, data->id_server_len);
3446d49e1aeSJan Lentfer 
3453ff40c12SJohn Marino 	if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
3466d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
3476d49e1aeSJan Lentfer 			   "for RAND_Peer");
3486d49e1aeSJan Lentfer 		eap_gpsk_state(data, FAILURE);
3496d49e1aeSJan Lentfer 		wpabuf_free(resp);
3506d49e1aeSJan Lentfer 		return NULL;
3516d49e1aeSJan Lentfer 	}
3526d49e1aeSJan Lentfer 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
3536d49e1aeSJan Lentfer 		    data->rand_peer, EAP_GPSK_RAND_LEN);
3546d49e1aeSJan Lentfer 	wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
3556d49e1aeSJan Lentfer 	wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
3566d49e1aeSJan Lentfer 
3576d49e1aeSJan Lentfer 	wpabuf_put_be16(resp, csuite_list_len);
3586d49e1aeSJan Lentfer 	wpabuf_put_data(resp, csuite_list, csuite_list_len);
3596d49e1aeSJan Lentfer 
3606d49e1aeSJan Lentfer 	csuite = wpabuf_put(resp, sizeof(*csuite));
3616d49e1aeSJan Lentfer 	WPA_PUT_BE32(csuite->vendor, data->vendor);
3626d49e1aeSJan Lentfer 	WPA_PUT_BE16(csuite->specifier, data->specifier);
3636d49e1aeSJan Lentfer 
3646d49e1aeSJan Lentfer 	if (eap_gpsk_derive_keys(data->psk, data->psk_len,
3656d49e1aeSJan Lentfer 				 data->vendor, data->specifier,
3666d49e1aeSJan Lentfer 				 data->rand_peer, data->rand_server,
3676d49e1aeSJan Lentfer 				 data->id_peer, data->id_peer_len,
3686d49e1aeSJan Lentfer 				 data->id_server, data->id_server_len,
3696d49e1aeSJan Lentfer 				 data->msk, data->emsk,
3706d49e1aeSJan Lentfer 				 data->sk, &data->sk_len,
3716d49e1aeSJan Lentfer 				 data->pk, &data->pk_len) < 0) {
3726d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
3736d49e1aeSJan Lentfer 		eap_gpsk_state(data, FAILURE);
3746d49e1aeSJan Lentfer 		wpabuf_free(resp);
3756d49e1aeSJan Lentfer 		return NULL;
3766d49e1aeSJan Lentfer 	}
3776d49e1aeSJan Lentfer 
3783ff40c12SJohn Marino 	if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
3793ff40c12SJohn Marino 				       data->vendor, data->specifier,
3803ff40c12SJohn Marino 				       data->rand_peer, data->rand_server,
3813ff40c12SJohn Marino 				       data->id_peer, data->id_peer_len,
3823ff40c12SJohn Marino 				       data->id_server, data->id_server_len,
3833ff40c12SJohn Marino 				       EAP_TYPE_GPSK,
3843ff40c12SJohn Marino 				       data->session_id, &data->id_len) < 0) {
3853ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
3863ff40c12SJohn Marino 		eap_gpsk_state(data, FAILURE);
3873ff40c12SJohn Marino 		wpabuf_free(resp);
3883ff40c12SJohn Marino 		return NULL;
3893ff40c12SJohn Marino 	}
3903ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
3913ff40c12SJohn Marino 		    data->session_id, data->id_len);
3923ff40c12SJohn Marino 
3936d49e1aeSJan Lentfer 	/* No PD_Payload_1 */
3946d49e1aeSJan Lentfer 	wpabuf_put_be16(resp, 0);
3956d49e1aeSJan Lentfer 
3966d49e1aeSJan Lentfer 	rpos = wpabuf_put(resp, miclen);
3976d49e1aeSJan Lentfer 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
3986d49e1aeSJan Lentfer 				 data->specifier, start, rpos - start, rpos) <
3996d49e1aeSJan Lentfer 	    0) {
4006d49e1aeSJan Lentfer 		eap_gpsk_state(data, FAILURE);
4016d49e1aeSJan Lentfer 		wpabuf_free(resp);
4026d49e1aeSJan Lentfer 		return NULL;
4036d49e1aeSJan Lentfer 	}
4046d49e1aeSJan Lentfer 
4056d49e1aeSJan Lentfer 	return resp;
4066d49e1aeSJan Lentfer }
4076d49e1aeSJan Lentfer 
4086d49e1aeSJan Lentfer 
eap_gpsk_validate_rand(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)4096d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
4106d49e1aeSJan Lentfer 					 const u8 *pos, const u8 *end)
4116d49e1aeSJan Lentfer {
4126d49e1aeSJan Lentfer 	if (end - pos < EAP_GPSK_RAND_LEN) {
4136d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4146d49e1aeSJan Lentfer 			   "RAND_Peer");
4156d49e1aeSJan Lentfer 		return NULL;
4166d49e1aeSJan Lentfer 	}
4176d49e1aeSJan Lentfer 	if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
4186d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
4196d49e1aeSJan Lentfer 			   "GPSK-3 did not match");
4206d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
4216d49e1aeSJan Lentfer 			    data->rand_peer, EAP_GPSK_RAND_LEN);
4226d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
4236d49e1aeSJan Lentfer 			    pos, EAP_GPSK_RAND_LEN);
4246d49e1aeSJan Lentfer 		return NULL;
4256d49e1aeSJan Lentfer 	}
4266d49e1aeSJan Lentfer 	pos += EAP_GPSK_RAND_LEN;
4276d49e1aeSJan Lentfer 
4286d49e1aeSJan Lentfer 	if (end - pos < EAP_GPSK_RAND_LEN) {
4296d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4306d49e1aeSJan Lentfer 			   "RAND_Server");
4316d49e1aeSJan Lentfer 		return NULL;
4326d49e1aeSJan Lentfer 	}
4336d49e1aeSJan Lentfer 	if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
4346d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
4356d49e1aeSJan Lentfer 			   "GPSK-3 did not match");
4366d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
4376d49e1aeSJan Lentfer 			    data->rand_server, EAP_GPSK_RAND_LEN);
4386d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
4396d49e1aeSJan Lentfer 			    pos, EAP_GPSK_RAND_LEN);
4406d49e1aeSJan Lentfer 		return NULL;
4416d49e1aeSJan Lentfer 	}
4426d49e1aeSJan Lentfer 	pos += EAP_GPSK_RAND_LEN;
4436d49e1aeSJan Lentfer 
4446d49e1aeSJan Lentfer 	return pos;
4456d49e1aeSJan Lentfer }
4466d49e1aeSJan Lentfer 
4476d49e1aeSJan Lentfer 
eap_gpsk_validate_id_server(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)4486d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
4496d49e1aeSJan Lentfer 					      const u8 *pos, const u8 *end)
4506d49e1aeSJan Lentfer {
4516d49e1aeSJan Lentfer 	size_t len;
4526d49e1aeSJan Lentfer 
4536d49e1aeSJan Lentfer 	if (pos == NULL)
4546d49e1aeSJan Lentfer 		return NULL;
4556d49e1aeSJan Lentfer 
4566d49e1aeSJan Lentfer 	if (end - pos < (int) 2) {
4576d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4586d49e1aeSJan Lentfer 			   "length(ID_Server)");
4596d49e1aeSJan Lentfer 		return NULL;
4606d49e1aeSJan Lentfer 	}
4616d49e1aeSJan Lentfer 
4626d49e1aeSJan Lentfer 	len = WPA_GET_BE16(pos);
4636d49e1aeSJan Lentfer 	pos += 2;
4646d49e1aeSJan Lentfer 
4656d49e1aeSJan Lentfer 	if (end - pos < (int) len) {
4666d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4676d49e1aeSJan Lentfer 			   "ID_Server");
4686d49e1aeSJan Lentfer 		return NULL;
4696d49e1aeSJan Lentfer 	}
4706d49e1aeSJan Lentfer 
4716d49e1aeSJan Lentfer 	if (len != data->id_server_len ||
4726d49e1aeSJan Lentfer 	    os_memcmp(pos, data->id_server, len) != 0) {
4736d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
4746d49e1aeSJan Lentfer 			   "the one used in GPSK-1");
4756d49e1aeSJan Lentfer 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
4766d49e1aeSJan Lentfer 				  data->id_server, data->id_server_len);
4776d49e1aeSJan Lentfer 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
4786d49e1aeSJan Lentfer 				  pos, len);
4796d49e1aeSJan Lentfer 		return NULL;
4806d49e1aeSJan Lentfer 	}
4816d49e1aeSJan Lentfer 
4826d49e1aeSJan Lentfer 	pos += len;
4836d49e1aeSJan Lentfer 
4846d49e1aeSJan Lentfer 	return pos;
4856d49e1aeSJan Lentfer }
4866d49e1aeSJan Lentfer 
4876d49e1aeSJan Lentfer 
eap_gpsk_validate_csuite(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)4886d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
4896d49e1aeSJan Lentfer 					   const u8 *pos, const u8 *end)
4906d49e1aeSJan Lentfer {
4916d49e1aeSJan Lentfer 	int vendor, specifier;
4926d49e1aeSJan Lentfer 	const struct eap_gpsk_csuite *csuite;
4936d49e1aeSJan Lentfer 
4946d49e1aeSJan Lentfer 	if (pos == NULL)
4956d49e1aeSJan Lentfer 		return NULL;
4966d49e1aeSJan Lentfer 
4976d49e1aeSJan Lentfer 	if (end - pos < (int) sizeof(*csuite)) {
4986d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
4996d49e1aeSJan Lentfer 			   "CSuite_Sel");
5006d49e1aeSJan Lentfer 		return NULL;
5016d49e1aeSJan Lentfer 	}
5026d49e1aeSJan Lentfer 	csuite = (const struct eap_gpsk_csuite *) pos;
5036d49e1aeSJan Lentfer 	vendor = WPA_GET_BE32(csuite->vendor);
5046d49e1aeSJan Lentfer 	specifier = WPA_GET_BE16(csuite->specifier);
5056d49e1aeSJan Lentfer 	pos += sizeof(*csuite);
5066d49e1aeSJan Lentfer 	if (vendor != data->vendor || specifier != data->specifier) {
5076d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
5086d49e1aeSJan Lentfer 			   "match with the one sent in GPSK-2 (%d:%d)",
5096d49e1aeSJan Lentfer 			   vendor, specifier, data->vendor, data->specifier);
5106d49e1aeSJan Lentfer 		return NULL;
5116d49e1aeSJan Lentfer 	}
5126d49e1aeSJan Lentfer 
5136d49e1aeSJan Lentfer 	return pos;
5146d49e1aeSJan Lentfer }
5156d49e1aeSJan Lentfer 
5166d49e1aeSJan Lentfer 
eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data * data,const u8 * pos,const u8 * end)5176d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
5186d49e1aeSJan Lentfer 						 const u8 *pos, const u8 *end)
5196d49e1aeSJan Lentfer {
5206d49e1aeSJan Lentfer 	u16 alen;
5216d49e1aeSJan Lentfer 
5226d49e1aeSJan Lentfer 	if (pos == NULL)
5236d49e1aeSJan Lentfer 		return NULL;
5246d49e1aeSJan Lentfer 
5256d49e1aeSJan Lentfer 	if (end - pos < 2) {
5266d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
5276d49e1aeSJan Lentfer 			   "PD_Payload_2 length");
5286d49e1aeSJan Lentfer 		return NULL;
5296d49e1aeSJan Lentfer 	}
5306d49e1aeSJan Lentfer 	alen = WPA_GET_BE16(pos);
5316d49e1aeSJan Lentfer 	pos += 2;
5326d49e1aeSJan Lentfer 	if (end - pos < alen) {
5336d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
5346d49e1aeSJan Lentfer 			   "%d-octet PD_Payload_2", alen);
5356d49e1aeSJan Lentfer 		return NULL;
5366d49e1aeSJan Lentfer 	}
5376d49e1aeSJan Lentfer 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
5386d49e1aeSJan Lentfer 	pos += alen;
5396d49e1aeSJan Lentfer 
5406d49e1aeSJan Lentfer 	return pos;
5416d49e1aeSJan Lentfer }
5426d49e1aeSJan Lentfer 
5436d49e1aeSJan Lentfer 
eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data * data,const u8 * payload,const u8 * pos,const u8 * end)5446d49e1aeSJan Lentfer static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
5456d49e1aeSJan Lentfer 					       const u8 *payload,
5466d49e1aeSJan Lentfer 					       const u8 *pos, const u8 *end)
5476d49e1aeSJan Lentfer {
5486d49e1aeSJan Lentfer 	size_t miclen;
5496d49e1aeSJan Lentfer 	u8 mic[EAP_GPSK_MAX_MIC_LEN];
5506d49e1aeSJan Lentfer 
5516d49e1aeSJan Lentfer 	if (pos == NULL)
5526d49e1aeSJan Lentfer 		return NULL;
5536d49e1aeSJan Lentfer 
5546d49e1aeSJan Lentfer 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
5556d49e1aeSJan Lentfer 	if (end - pos < (int) miclen) {
5566d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
5576d49e1aeSJan Lentfer 			   "(left=%lu miclen=%lu)",
5586d49e1aeSJan Lentfer 			   (unsigned long) (end - pos),
5596d49e1aeSJan Lentfer 			   (unsigned long) miclen);
5606d49e1aeSJan Lentfer 		return NULL;
5616d49e1aeSJan Lentfer 	}
5626d49e1aeSJan Lentfer 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
5636d49e1aeSJan Lentfer 				 data->specifier, payload, pos - payload, mic)
5646d49e1aeSJan Lentfer 	    < 0) {
5656d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
5666d49e1aeSJan Lentfer 		return NULL;
5676d49e1aeSJan Lentfer 	}
568*a1157835SDaniel Fojt 	if (os_memcmp_const(mic, pos, miclen) != 0) {
5696d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
5706d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
5716d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
5726d49e1aeSJan Lentfer 		return NULL;
5736d49e1aeSJan Lentfer 	}
5746d49e1aeSJan Lentfer 	pos += miclen;
5756d49e1aeSJan Lentfer 
5766d49e1aeSJan Lentfer 	return pos;
5776d49e1aeSJan Lentfer }
5786d49e1aeSJan Lentfer 
5796d49e1aeSJan Lentfer 
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)5806d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
5816d49e1aeSJan Lentfer 					       struct eap_gpsk_data *data,
5826d49e1aeSJan Lentfer 					       struct eap_method_ret *ret,
583*a1157835SDaniel Fojt 					       u8 identifier,
5846d49e1aeSJan Lentfer 					       const u8 *payload,
5856d49e1aeSJan Lentfer 					       size_t payload_len)
5866d49e1aeSJan Lentfer {
5876d49e1aeSJan Lentfer 	struct wpabuf *resp;
5886d49e1aeSJan Lentfer 	const u8 *pos, *end;
5896d49e1aeSJan Lentfer 
5906d49e1aeSJan Lentfer 	if (data->state != GPSK_3) {
5916d49e1aeSJan Lentfer 		ret->ignore = TRUE;
5926d49e1aeSJan Lentfer 		return NULL;
5936d49e1aeSJan Lentfer 	}
5946d49e1aeSJan Lentfer 
5956d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
5966d49e1aeSJan Lentfer 
5976d49e1aeSJan Lentfer 	end = payload + payload_len;
5986d49e1aeSJan Lentfer 
5996d49e1aeSJan Lentfer 	pos = eap_gpsk_validate_rand(data, payload, end);
6006d49e1aeSJan Lentfer 	pos = eap_gpsk_validate_id_server(data, pos, end);
6016d49e1aeSJan Lentfer 	pos = eap_gpsk_validate_csuite(data, pos, end);
6026d49e1aeSJan Lentfer 	pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
6036d49e1aeSJan Lentfer 	pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
6046d49e1aeSJan Lentfer 
6056d49e1aeSJan Lentfer 	if (pos == NULL) {
6066d49e1aeSJan Lentfer 		eap_gpsk_state(data, FAILURE);
6076d49e1aeSJan Lentfer 		return NULL;
6086d49e1aeSJan Lentfer 	}
6096d49e1aeSJan Lentfer 	if (pos != end) {
6106d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
6116d49e1aeSJan Lentfer 			   "data in the end of GPSK-2",
6126d49e1aeSJan Lentfer 			   (unsigned long) (end - pos));
6136d49e1aeSJan Lentfer 	}
6146d49e1aeSJan Lentfer 
615*a1157835SDaniel Fojt 	resp = eap_gpsk_send_gpsk_4(data, identifier);
6166d49e1aeSJan Lentfer 	if (resp == NULL)
6176d49e1aeSJan Lentfer 		return NULL;
6186d49e1aeSJan Lentfer 
6196d49e1aeSJan Lentfer 	eap_gpsk_state(data, SUCCESS);
6206d49e1aeSJan Lentfer 	ret->methodState = METHOD_DONE;
6216d49e1aeSJan Lentfer 	ret->decision = DECISION_UNCOND_SUCC;
6226d49e1aeSJan Lentfer 
6236d49e1aeSJan Lentfer 	return resp;
6246d49e1aeSJan Lentfer }
6256d49e1aeSJan Lentfer 
6266d49e1aeSJan Lentfer 
eap_gpsk_send_gpsk_4(struct eap_gpsk_data * data,u8 identifier)6276d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
6286d49e1aeSJan Lentfer 					    u8 identifier)
6296d49e1aeSJan Lentfer {
6306d49e1aeSJan Lentfer 	struct wpabuf *resp;
6316d49e1aeSJan Lentfer 	u8 *rpos, *start;
6326d49e1aeSJan Lentfer 	size_t mlen;
6336d49e1aeSJan Lentfer 
6346d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
6356d49e1aeSJan Lentfer 
6366d49e1aeSJan Lentfer 	mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
6376d49e1aeSJan Lentfer 
6386d49e1aeSJan Lentfer 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
6396d49e1aeSJan Lentfer 			     EAP_CODE_RESPONSE, identifier);
6406d49e1aeSJan Lentfer 	if (resp == NULL)
6416d49e1aeSJan Lentfer 		return NULL;
6426d49e1aeSJan Lentfer 
6436d49e1aeSJan Lentfer 	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
6446d49e1aeSJan Lentfer 	start = wpabuf_put(resp, 0);
6456d49e1aeSJan Lentfer 
6466d49e1aeSJan Lentfer 	/* No PD_Payload_3 */
6476d49e1aeSJan Lentfer 	wpabuf_put_be16(resp, 0);
6486d49e1aeSJan Lentfer 
6496d49e1aeSJan Lentfer 	rpos = wpabuf_put(resp, mlen);
6506d49e1aeSJan Lentfer 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
6516d49e1aeSJan Lentfer 				 data->specifier, start, rpos - start, rpos) <
6526d49e1aeSJan Lentfer 	    0) {
6536d49e1aeSJan Lentfer 		eap_gpsk_state(data, FAILURE);
6546d49e1aeSJan Lentfer 		wpabuf_free(resp);
6556d49e1aeSJan Lentfer 		return NULL;
6566d49e1aeSJan Lentfer 	}
6576d49e1aeSJan Lentfer 
6586d49e1aeSJan Lentfer 	return resp;
6596d49e1aeSJan Lentfer }
6606d49e1aeSJan Lentfer 
6616d49e1aeSJan Lentfer 
eap_gpsk_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)6626d49e1aeSJan Lentfer static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
6636d49e1aeSJan Lentfer 					struct eap_method_ret *ret,
6646d49e1aeSJan Lentfer 					const struct wpabuf *reqData)
6656d49e1aeSJan Lentfer {
6666d49e1aeSJan Lentfer 	struct eap_gpsk_data *data = priv;
6676d49e1aeSJan Lentfer 	struct wpabuf *resp;
6686d49e1aeSJan Lentfer 	const u8 *pos;
6696d49e1aeSJan Lentfer 	size_t len;
670*a1157835SDaniel Fojt 	u8 opcode, id;
6716d49e1aeSJan Lentfer 
6726d49e1aeSJan Lentfer 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
6736d49e1aeSJan Lentfer 	if (pos == NULL || len < 1) {
6746d49e1aeSJan Lentfer 		ret->ignore = TRUE;
6756d49e1aeSJan Lentfer 		return NULL;
6766d49e1aeSJan Lentfer 	}
6776d49e1aeSJan Lentfer 
678*a1157835SDaniel Fojt 	id = eap_get_id(reqData);
679*a1157835SDaniel Fojt 	opcode = *pos++;
680*a1157835SDaniel Fojt 	len--;
681*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
6826d49e1aeSJan Lentfer 
6836d49e1aeSJan Lentfer 	ret->ignore = FALSE;
6846d49e1aeSJan Lentfer 	ret->methodState = METHOD_MAY_CONT;
6856d49e1aeSJan Lentfer 	ret->decision = DECISION_FAIL;
6866d49e1aeSJan Lentfer 	ret->allowNotifications = FALSE;
6876d49e1aeSJan Lentfer 
688*a1157835SDaniel Fojt 	switch (opcode) {
6896d49e1aeSJan Lentfer 	case EAP_GPSK_OPCODE_GPSK_1:
690*a1157835SDaniel Fojt 		resp = eap_gpsk_process_gpsk_1(sm, data, ret, id, pos, len);
6916d49e1aeSJan Lentfer 		break;
6926d49e1aeSJan Lentfer 	case EAP_GPSK_OPCODE_GPSK_3:
693*a1157835SDaniel Fojt 		resp = eap_gpsk_process_gpsk_3(sm, data, ret, id, pos, len);
6946d49e1aeSJan Lentfer 		break;
6956d49e1aeSJan Lentfer 	default:
696*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
697*a1157835SDaniel Fojt 			   "EAP-GPSK: Ignoring message with unknown opcode %d",
698*a1157835SDaniel Fojt 			   opcode);
6996d49e1aeSJan Lentfer 		ret->ignore = TRUE;
7006d49e1aeSJan Lentfer 		return NULL;
7016d49e1aeSJan Lentfer 	}
7026d49e1aeSJan Lentfer 
7036d49e1aeSJan Lentfer 	return resp;
7046d49e1aeSJan Lentfer }
7056d49e1aeSJan Lentfer 
7066d49e1aeSJan Lentfer 
eap_gpsk_isKeyAvailable(struct eap_sm * sm,void * priv)7076d49e1aeSJan Lentfer static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
7086d49e1aeSJan Lentfer {
7096d49e1aeSJan Lentfer 	struct eap_gpsk_data *data = priv;
7106d49e1aeSJan Lentfer 	return data->state == SUCCESS;
7116d49e1aeSJan Lentfer }
7126d49e1aeSJan Lentfer 
7136d49e1aeSJan Lentfer 
eap_gpsk_getKey(struct eap_sm * sm,void * priv,size_t * len)7146d49e1aeSJan Lentfer static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
7156d49e1aeSJan Lentfer {
7166d49e1aeSJan Lentfer 	struct eap_gpsk_data *data = priv;
7176d49e1aeSJan Lentfer 	u8 *key;
7186d49e1aeSJan Lentfer 
7196d49e1aeSJan Lentfer 	if (data->state != SUCCESS)
7206d49e1aeSJan Lentfer 		return NULL;
7216d49e1aeSJan Lentfer 
722*a1157835SDaniel Fojt 	key = os_memdup(data->msk, EAP_MSK_LEN);
7236d49e1aeSJan Lentfer 	if (key == NULL)
7246d49e1aeSJan Lentfer 		return NULL;
7256d49e1aeSJan Lentfer 	*len = EAP_MSK_LEN;
7266d49e1aeSJan Lentfer 
7276d49e1aeSJan Lentfer 	return key;
7286d49e1aeSJan Lentfer }
7296d49e1aeSJan Lentfer 
7306d49e1aeSJan Lentfer 
eap_gpsk_get_emsk(struct eap_sm * sm,void * priv,size_t * len)7316d49e1aeSJan Lentfer static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
7326d49e1aeSJan Lentfer {
7336d49e1aeSJan Lentfer 	struct eap_gpsk_data *data = priv;
7346d49e1aeSJan Lentfer 	u8 *key;
7356d49e1aeSJan Lentfer 
7366d49e1aeSJan Lentfer 	if (data->state != SUCCESS)
7376d49e1aeSJan Lentfer 		return NULL;
7386d49e1aeSJan Lentfer 
739*a1157835SDaniel Fojt 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
7406d49e1aeSJan Lentfer 	if (key == NULL)
7416d49e1aeSJan Lentfer 		return NULL;
7426d49e1aeSJan Lentfer 	*len = EAP_EMSK_LEN;
7436d49e1aeSJan Lentfer 
7446d49e1aeSJan Lentfer 	return key;
7456d49e1aeSJan Lentfer }
7466d49e1aeSJan Lentfer 
7476d49e1aeSJan Lentfer 
eap_gpsk_get_session_id(struct eap_sm * sm,void * priv,size_t * len)7483ff40c12SJohn Marino static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
7493ff40c12SJohn Marino {
7503ff40c12SJohn Marino 	struct eap_gpsk_data *data = priv;
7513ff40c12SJohn Marino 	u8 *sid;
7523ff40c12SJohn Marino 
7533ff40c12SJohn Marino 	if (data->state != SUCCESS)
7543ff40c12SJohn Marino 		return NULL;
7553ff40c12SJohn Marino 
756*a1157835SDaniel Fojt 	sid = os_memdup(data->session_id, data->id_len);
7573ff40c12SJohn Marino 	if (sid == NULL)
7583ff40c12SJohn Marino 		return NULL;
7593ff40c12SJohn Marino 	*len = data->id_len;
7603ff40c12SJohn Marino 
7613ff40c12SJohn Marino 	return sid;
7623ff40c12SJohn Marino }
7633ff40c12SJohn Marino 
7643ff40c12SJohn Marino 
eap_peer_gpsk_register(void)7656d49e1aeSJan Lentfer int eap_peer_gpsk_register(void)
7666d49e1aeSJan Lentfer {
7676d49e1aeSJan Lentfer 	struct eap_method *eap;
7686d49e1aeSJan Lentfer 
7696d49e1aeSJan Lentfer 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
7706d49e1aeSJan Lentfer 				    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
7716d49e1aeSJan Lentfer 	if (eap == NULL)
7726d49e1aeSJan Lentfer 		return -1;
7736d49e1aeSJan Lentfer 
7746d49e1aeSJan Lentfer 	eap->init = eap_gpsk_init;
7756d49e1aeSJan Lentfer 	eap->deinit = eap_gpsk_deinit;
7766d49e1aeSJan Lentfer 	eap->process = eap_gpsk_process;
7776d49e1aeSJan Lentfer 	eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
7786d49e1aeSJan Lentfer 	eap->getKey = eap_gpsk_getKey;
7796d49e1aeSJan Lentfer 	eap->get_emsk = eap_gpsk_get_emsk;
7803ff40c12SJohn Marino 	eap->getSessionId = eap_gpsk_get_session_id;
7816d49e1aeSJan Lentfer 
782*a1157835SDaniel Fojt 	return eap_peer_method_register(eap);
7836d49e1aeSJan Lentfer }
784