xref: /freebsd/contrib/wpa/src/eap_peer/eap_gpsk.c (revision 71099ec5097cff9b4a566e5474b7f214bd539e8a)
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 
16 struct 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;
27 	int session_id_set;
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 
39 static 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);
43 static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
44 					    u8 identifier);
45 
46 
47 #ifndef CONFIG_NO_STDOUT_DEBUG
48 static 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 
66 static 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 
75 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
76 
77 
78 static 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 
118 static 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 
128 static 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 
159 static 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 
178 static 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 
217 static 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 
251 static 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 
291 static 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 	/* No PD_Payload_1 */
358 	wpabuf_put_be16(resp, 0);
359 
360 	rpos = wpabuf_put(resp, miclen);
361 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
362 				 data->specifier, start, rpos - start, rpos) <
363 	    0) {
364 		eap_gpsk_state(data, FAILURE);
365 		wpabuf_free(resp);
366 		return NULL;
367 	}
368 
369 	return resp;
370 }
371 
372 
373 static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
374 					 const u8 *pos, const u8 *end)
375 {
376 	if (end - pos < EAP_GPSK_RAND_LEN) {
377 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
378 			   "RAND_Peer");
379 		return NULL;
380 	}
381 	if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
382 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
383 			   "GPSK-3 did not match");
384 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
385 			    data->rand_peer, EAP_GPSK_RAND_LEN);
386 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
387 			    pos, EAP_GPSK_RAND_LEN);
388 		return NULL;
389 	}
390 	pos += EAP_GPSK_RAND_LEN;
391 
392 	if (end - pos < EAP_GPSK_RAND_LEN) {
393 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
394 			   "RAND_Server");
395 		return NULL;
396 	}
397 	if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
398 		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
399 			   "GPSK-3 did not match");
400 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
401 			    data->rand_server, EAP_GPSK_RAND_LEN);
402 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
403 			    pos, EAP_GPSK_RAND_LEN);
404 		return NULL;
405 	}
406 	pos += EAP_GPSK_RAND_LEN;
407 
408 	return pos;
409 }
410 
411 
412 static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
413 					      const u8 *pos, const u8 *end)
414 {
415 	size_t len;
416 
417 	if (pos == NULL)
418 		return NULL;
419 
420 	if (end - pos < (int) 2) {
421 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
422 			   "length(ID_Server)");
423 		return NULL;
424 	}
425 
426 	len = WPA_GET_BE16(pos);
427 	pos += 2;
428 
429 	if (end - pos < (int) len) {
430 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
431 			   "ID_Server");
432 		return NULL;
433 	}
434 
435 	if (len != data->id_server_len ||
436 	    os_memcmp(pos, data->id_server, len) != 0) {
437 		wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
438 			   "the one used in GPSK-1");
439 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
440 				  data->id_server, data->id_server_len);
441 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
442 				  pos, len);
443 		return NULL;
444 	}
445 
446 	pos += len;
447 
448 	return pos;
449 }
450 
451 
452 static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
453 					   const u8 *pos, const u8 *end)
454 {
455 	int vendor, specifier;
456 	const struct eap_gpsk_csuite *csuite;
457 
458 	if (pos == NULL)
459 		return NULL;
460 
461 	if (end - pos < (int) sizeof(*csuite)) {
462 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
463 			   "CSuite_Sel");
464 		return NULL;
465 	}
466 	csuite = (const struct eap_gpsk_csuite *) pos;
467 	vendor = WPA_GET_BE32(csuite->vendor);
468 	specifier = WPA_GET_BE16(csuite->specifier);
469 	pos += sizeof(*csuite);
470 	if (vendor != data->vendor || specifier != data->specifier) {
471 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
472 			   "match with the one sent in GPSK-2 (%d:%d)",
473 			   vendor, specifier, data->vendor, data->specifier);
474 		return NULL;
475 	}
476 
477 	return pos;
478 }
479 
480 
481 static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
482 						 const u8 *pos, const u8 *end)
483 {
484 	u16 alen;
485 
486 	if (pos == NULL)
487 		return NULL;
488 
489 	if (end - pos < 2) {
490 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
491 			   "PD_Payload_2 length");
492 		return NULL;
493 	}
494 	alen = WPA_GET_BE16(pos);
495 	pos += 2;
496 	if (end - pos < alen) {
497 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
498 			   "%d-octet PD_Payload_2", alen);
499 		return NULL;
500 	}
501 	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
502 	pos += alen;
503 
504 	return pos;
505 }
506 
507 
508 static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
509 					       const u8 *payload,
510 					       const u8 *pos, const u8 *end)
511 {
512 	size_t miclen;
513 	u8 mic[EAP_GPSK_MAX_MIC_LEN];
514 
515 	if (pos == NULL)
516 		return NULL;
517 
518 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
519 	if (end - pos < (int) miclen) {
520 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
521 			   "(left=%lu miclen=%lu)",
522 			   (unsigned long) (end - pos),
523 			   (unsigned long) miclen);
524 		return NULL;
525 	}
526 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
527 				 data->specifier, payload, pos - payload, mic)
528 	    < 0) {
529 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
530 		return NULL;
531 	}
532 	if (os_memcmp(mic, pos, miclen) != 0) {
533 		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
534 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
535 		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
536 		return NULL;
537 	}
538 	pos += miclen;
539 
540 	return pos;
541 }
542 
543 
544 static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
545 					       struct eap_gpsk_data *data,
546 					       struct eap_method_ret *ret,
547 					       const struct wpabuf *reqData,
548 					       const u8 *payload,
549 					       size_t payload_len)
550 {
551 	struct wpabuf *resp;
552 	const u8 *pos, *end;
553 
554 	if (data->state != GPSK_3) {
555 		ret->ignore = TRUE;
556 		return NULL;
557 	}
558 
559 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
560 
561 	end = payload + payload_len;
562 
563 	pos = eap_gpsk_validate_rand(data, payload, end);
564 	pos = eap_gpsk_validate_id_server(data, pos, end);
565 	pos = eap_gpsk_validate_csuite(data, pos, end);
566 	pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
567 	pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
568 
569 	if (pos == NULL) {
570 		eap_gpsk_state(data, FAILURE);
571 		return NULL;
572 	}
573 	if (pos != end) {
574 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
575 			   "data in the end of GPSK-2",
576 			   (unsigned long) (end - pos));
577 	}
578 
579 	resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
580 	if (resp == NULL)
581 		return NULL;
582 
583 	eap_gpsk_state(data, SUCCESS);
584 	ret->methodState = METHOD_DONE;
585 	ret->decision = DECISION_UNCOND_SUCC;
586 
587 	return resp;
588 }
589 
590 
591 static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
592 					    u8 identifier)
593 {
594 	struct wpabuf *resp;
595 	u8 *rpos, *start;
596 	size_t mlen;
597 
598 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
599 
600 	mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
601 
602 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
603 			     EAP_CODE_RESPONSE, identifier);
604 	if (resp == NULL)
605 		return NULL;
606 
607 	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
608 	start = wpabuf_put(resp, 0);
609 
610 	/* No PD_Payload_3 */
611 	wpabuf_put_be16(resp, 0);
612 
613 	rpos = wpabuf_put(resp, mlen);
614 	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
615 				 data->specifier, start, rpos - start, rpos) <
616 	    0) {
617 		eap_gpsk_state(data, FAILURE);
618 		wpabuf_free(resp);
619 		return NULL;
620 	}
621 
622 	return resp;
623 }
624 
625 
626 static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
627 					struct eap_method_ret *ret,
628 					const struct wpabuf *reqData)
629 {
630 	struct eap_gpsk_data *data = priv;
631 	struct wpabuf *resp;
632 	const u8 *pos;
633 	size_t len;
634 
635 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
636 	if (pos == NULL || len < 1) {
637 		ret->ignore = TRUE;
638 		return NULL;
639 	}
640 
641 	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
642 
643 	ret->ignore = FALSE;
644 	ret->methodState = METHOD_MAY_CONT;
645 	ret->decision = DECISION_FAIL;
646 	ret->allowNotifications = FALSE;
647 
648 	switch (*pos) {
649 	case EAP_GPSK_OPCODE_GPSK_1:
650 		resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
651 					       pos + 1, len - 1);
652 		break;
653 	case EAP_GPSK_OPCODE_GPSK_3:
654 		resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
655 					       pos + 1, len - 1);
656 		break;
657 	default:
658 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
659 			   "unknown opcode %d", *pos);
660 		ret->ignore = TRUE;
661 		return NULL;
662 	}
663 
664 	return resp;
665 }
666 
667 
668 static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
669 {
670 	struct eap_gpsk_data *data = priv;
671 	return data->state == SUCCESS;
672 }
673 
674 
675 static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
676 {
677 	struct eap_gpsk_data *data = priv;
678 	u8 *key;
679 
680 	if (data->state != SUCCESS)
681 		return NULL;
682 
683 	key = os_malloc(EAP_MSK_LEN);
684 	if (key == NULL)
685 		return NULL;
686 	os_memcpy(key, data->msk, EAP_MSK_LEN);
687 	*len = EAP_MSK_LEN;
688 
689 	return key;
690 }
691 
692 
693 static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
694 {
695 	struct eap_gpsk_data *data = priv;
696 	u8 *key;
697 
698 	if (data->state != SUCCESS)
699 		return NULL;
700 
701 	key = os_malloc(EAP_EMSK_LEN);
702 	if (key == NULL)
703 		return NULL;
704 	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
705 	*len = EAP_EMSK_LEN;
706 
707 	return key;
708 }
709 
710 
711 int eap_peer_gpsk_register(void)
712 {
713 	struct eap_method *eap;
714 	int ret;
715 
716 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
717 				    EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
718 	if (eap == NULL)
719 		return -1;
720 
721 	eap->init = eap_gpsk_init;
722 	eap->deinit = eap_gpsk_deinit;
723 	eap->process = eap_gpsk_process;
724 	eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
725 	eap->getKey = eap_gpsk_getKey;
726 	eap->get_emsk = eap_gpsk_get_emsk;
727 
728 	ret = eap_peer_method_register(eap);
729 	if (ret)
730 		eap_peer_method_free(eap);
731 	return ret;
732 }
733