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