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