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