1/*
2 * EAP peer method: EAP-GPSK (RFC 5433)
3 * Copyright (c) 2006-2014, Jouni Malinen <j@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
16struct 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
40static 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);
44static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
45					    u8 identifier);
46
47
48#ifndef CONFIG_NO_STDOUT_DEBUG
49static 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
67static 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
76static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
77
78
79static 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
132static 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
145static 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
176static 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
195static 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
236static 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
274static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
275					       struct eap_gpsk_data *data,
276					       struct eap_method_ret *ret,
277					       const struct wpabuf *reqData,
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, eap_get_id(reqData),
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
315static 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
412static 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
451static 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
491static 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
520static 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
547static 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
583static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
584					       struct eap_gpsk_data *data,
585					       struct eap_method_ret *ret,
586					       const struct wpabuf *reqData,
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, eap_get_id(reqData));
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
630static 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
665static 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
674	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
675	if (pos == NULL || len < 1) {
676		ret->ignore = TRUE;
677		return NULL;
678	}
679
680	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
681
682	ret->ignore = FALSE;
683	ret->methodState = METHOD_MAY_CONT;
684	ret->decision = DECISION_FAIL;
685	ret->allowNotifications = FALSE;
686
687	switch (*pos) {
688	case EAP_GPSK_OPCODE_GPSK_1:
689		resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
690					       pos + 1, len - 1);
691		break;
692	case EAP_GPSK_OPCODE_GPSK_3:
693		resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
694					       pos + 1, len - 1);
695		break;
696	default:
697		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
698			   "unknown opcode %d", *pos);
699		ret->ignore = TRUE;
700		return NULL;
701	}
702
703	return resp;
704}
705
706
707static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
708{
709	struct eap_gpsk_data *data = priv;
710	return data->state == SUCCESS;
711}
712
713
714static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
715{
716	struct eap_gpsk_data *data = priv;
717	u8 *key;
718
719	if (data->state != SUCCESS)
720		return NULL;
721
722	key = os_malloc(EAP_MSK_LEN);
723	if (key == NULL)
724		return NULL;
725	os_memcpy(key, data->msk, EAP_MSK_LEN);
726	*len = EAP_MSK_LEN;
727
728	return key;
729}
730
731
732static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
733{
734	struct eap_gpsk_data *data = priv;
735	u8 *key;
736
737	if (data->state != SUCCESS)
738		return NULL;
739
740	key = os_malloc(EAP_EMSK_LEN);
741	if (key == NULL)
742		return NULL;
743	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
744	*len = EAP_EMSK_LEN;
745
746	return key;
747}
748
749
750static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
751{
752	struct eap_gpsk_data *data = priv;
753	u8 *sid;
754
755	if (data->state != SUCCESS)
756		return NULL;
757
758	sid = os_malloc(data->id_len);
759	if (sid == NULL)
760		return NULL;
761	os_memcpy(sid, data->session_id, data->id_len);
762	*len = data->id_len;
763
764	return sid;
765}
766
767
768int eap_peer_gpsk_register(void)
769{
770	struct eap_method *eap;
771	int ret;
772
773	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
774				    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
775	if (eap == NULL)
776		return -1;
777
778	eap->init = eap_gpsk_init;
779	eap->deinit = eap_gpsk_deinit;
780	eap->process = eap_gpsk_process;
781	eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
782	eap->getKey = eap_gpsk_getKey;
783	eap->get_emsk = eap_gpsk_get_emsk;
784	eap->getSessionId = eap_gpsk_get_session_id;
785
786	ret = eap_peer_method_register(eap);
787	if (ret)
788		eap_peer_method_free(eap);
789	return ret;
790}
791