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