xref: /freebsd/contrib/wpa/src/eap_peer/eap_gpsk.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
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 
21 struct 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 
44 static 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);
48 static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
49 					    u8 identifier);
50 
51 
52 #ifndef CONFIG_NO_STDOUT_DEBUG
53 static 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 
71 static 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 
80 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
81 
82 
83 static 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 
123 static 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 
133 static 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 
164 static 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 
183 static 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 
222 static 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 
256 static 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 
296 static 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 
378 static 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 
417 static 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 
457 static 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 
486 static 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 
513 static 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 
549 static 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 
596 static 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 
631 static 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 
673 static 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 
680 static 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 
698 static 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 
716 int 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