xref: /netbsd-src/external/bsd/wpa/dist/src/eap_peer/eap_gpsk.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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 
22 struct 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 
45 static 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);
49 static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
50 					    u8 identifier);
51 
52 
53 #ifndef CONFIG_NO_STDOUT_DEBUG
54 static 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 
72 static 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 
81 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
82 
83 
84 static 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 
124 static 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 
134 static 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 
165 static 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 
184 static 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 
223 static 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 
257 static 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 
297 static 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 
379 static 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 
418 static 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 
458 static 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 
487 static 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 
514 static 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 
550 static 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 
597 static 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 
632 static 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 
674 static 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 
681 static 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 
699 static 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 
717 int 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