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