xref: /netbsd-src/external/bsd/wpa/dist/src/eap_server/eap_server_aka.c (revision a4ddc2c8fb9af816efe3b1c375a5530aef0e89e9)
1 /*
2  * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
3  * Copyright (c) 2005-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/sha256.h"
19 #include "crypto/crypto.h"
20 #include "crypto/random.h"
21 #include "eap_common/eap_sim_common.h"
22 #include "eap_server/eap_i.h"
23 #include "eap_server/eap_sim_db.h"
24 
25 
26 struct eap_aka_data {
27 	u8 mk[EAP_SIM_MK_LEN];
28 	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
29 	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
30 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
31 	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
32 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
33 	u8 emsk[EAP_EMSK_LEN];
34 	u8 rand[EAP_AKA_RAND_LEN];
35 	u8 autn[EAP_AKA_AUTN_LEN];
36 	u8 ck[EAP_AKA_CK_LEN];
37 	u8 ik[EAP_AKA_IK_LEN];
38 	u8 res[EAP_AKA_RES_MAX_LEN];
39 	size_t res_len;
40 	enum {
41 		IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
42 	} state;
43 	char *next_pseudonym;
44 	char *next_reauth_id;
45 	u16 counter;
46 	struct eap_sim_reauth *reauth;
47 	int auts_reported; /* whether the current AUTS has been reported to the
48 			    * eap_sim_db */
49 	u16 notification;
50 	int use_result_ind;
51 
52 	struct wpabuf *id_msgs;
53 	int pending_id;
54 	u8 eap_method;
55 	u8 *network_name;
56 	size_t network_name_len;
57 	u16 kdf;
58 };
59 
60 
61 static void eap_aka_determine_identity(struct eap_sm *sm,
62 				       struct eap_aka_data *data,
63 				       int before_identity, int after_reauth);
64 
65 
66 static const char * eap_aka_state_txt(int state)
67 {
68 	switch (state) {
69 	case IDENTITY:
70 		return "IDENTITY";
71 	case CHALLENGE:
72 		return "CHALLENGE";
73 	case REAUTH:
74 		return "REAUTH";
75 	case SUCCESS:
76 		return "SUCCESS";
77 	case FAILURE:
78 		return "FAILURE";
79 	case NOTIFICATION:
80 		return "NOTIFICATION";
81 	default:
82 		return "Unknown?!";
83 	}
84 }
85 
86 
87 static void eap_aka_state(struct eap_aka_data *data, int state)
88 {
89 	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
90 		   eap_aka_state_txt(data->state),
91 		   eap_aka_state_txt(state));
92 	data->state = state;
93 }
94 
95 
96 static void * eap_aka_init(struct eap_sm *sm)
97 {
98 	struct eap_aka_data *data;
99 
100 	if (sm->eap_sim_db_priv == NULL) {
101 		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
102 		return NULL;
103 	}
104 
105 	data = os_zalloc(sizeof(*data));
106 	if (data == NULL)
107 		return NULL;
108 
109 	data->eap_method = EAP_TYPE_AKA;
110 
111 	data->state = IDENTITY;
112 	eap_aka_determine_identity(sm, data, 1, 0);
113 	data->pending_id = -1;
114 
115 	return data;
116 }
117 
118 
119 #ifdef EAP_SERVER_AKA_PRIME
120 static void * eap_aka_prime_init(struct eap_sm *sm)
121 {
122 	struct eap_aka_data *data;
123 	/* TODO: make ANID configurable; see 3GPP TS 24.302 */
124 	char *network_name = "WLAN";
125 
126 	if (sm->eap_sim_db_priv == NULL) {
127 		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
128 		return NULL;
129 	}
130 
131 	data = os_zalloc(sizeof(*data));
132 	if (data == NULL)
133 		return NULL;
134 
135 	data->eap_method = EAP_TYPE_AKA_PRIME;
136 	data->network_name = (u8 *) os_strdup(network_name);
137 	if (data->network_name == NULL) {
138 		os_free(data);
139 		return NULL;
140 	}
141 
142 	data->network_name_len = os_strlen(network_name);
143 
144 	data->state = IDENTITY;
145 	eap_aka_determine_identity(sm, data, 1, 0);
146 	data->pending_id = -1;
147 
148 	return data;
149 }
150 #endif /* EAP_SERVER_AKA_PRIME */
151 
152 
153 static void eap_aka_reset(struct eap_sm *sm, void *priv)
154 {
155 	struct eap_aka_data *data = priv;
156 	os_free(data->next_pseudonym);
157 	os_free(data->next_reauth_id);
158 	wpabuf_free(data->id_msgs);
159 	os_free(data->network_name);
160 	os_free(data);
161 }
162 
163 
164 static int eap_aka_add_id_msg(struct eap_aka_data *data,
165 			      const struct wpabuf *msg)
166 {
167 	if (msg == NULL)
168 		return -1;
169 
170 	if (data->id_msgs == NULL) {
171 		data->id_msgs = wpabuf_dup(msg);
172 		return data->id_msgs == NULL ? -1 : 0;
173 	}
174 
175 	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
176 		return -1;
177 	wpabuf_put_buf(data->id_msgs, msg);
178 
179 	return 0;
180 }
181 
182 
183 static void eap_aka_add_checkcode(struct eap_aka_data *data,
184 				  struct eap_sim_msg *msg)
185 {
186 	const u8 *addr;
187 	size_t len;
188 	u8 hash[SHA256_MAC_LEN];
189 
190 	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
191 
192 	if (data->id_msgs == NULL) {
193 		/*
194 		 * No EAP-AKA/Identity packets were exchanged - send empty
195 		 * checkcode.
196 		 */
197 		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
198 		return;
199 	}
200 
201 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
202 	addr = wpabuf_head(data->id_msgs);
203 	len = wpabuf_len(data->id_msgs);
204 	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
205 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
206 		sha256_vector(1, &addr, &len, hash);
207 	else
208 		sha1_vector(1, &addr, &len, hash);
209 
210 	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
211 			data->eap_method == EAP_TYPE_AKA_PRIME ?
212 			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
213 }
214 
215 
216 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
217 				    const u8 *checkcode, size_t checkcode_len)
218 {
219 	const u8 *addr;
220 	size_t len;
221 	u8 hash[SHA256_MAC_LEN];
222 	size_t hash_len;
223 
224 	if (checkcode == NULL)
225 		return -1;
226 
227 	if (data->id_msgs == NULL) {
228 		if (checkcode_len != 0) {
229 			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
230 				   "indicates that AKA/Identity messages were "
231 				   "used, but they were not");
232 			return -1;
233 		}
234 		return 0;
235 	}
236 
237 	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
238 		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
239 
240 	if (checkcode_len != hash_len) {
241 		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
242 			   "that AKA/Identity message were not used, but they "
243 			   "were");
244 		return -1;
245 	}
246 
247 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
248 	addr = wpabuf_head(data->id_msgs);
249 	len = wpabuf_len(data->id_msgs);
250 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
251 		sha256_vector(1, &addr, &len, hash);
252 	else
253 		sha1_vector(1, &addr, &len, hash);
254 
255 	if (os_memcmp(hash, checkcode, hash_len) != 0) {
256 		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
257 		return -1;
258 	}
259 
260 	return 0;
261 }
262 
263 
264 static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
265 					      struct eap_aka_data *data, u8 id)
266 {
267 	struct eap_sim_msg *msg;
268 	struct wpabuf *buf;
269 
270 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
271 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
272 			       EAP_AKA_SUBTYPE_IDENTITY);
273 	if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
274 				      sm->identity_len)) {
275 		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
276 		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
277 	} else {
278 		/*
279 		 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
280 		 * ignored and the AKA/Identity is used to request the
281 		 * identity.
282 		 */
283 		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
284 		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
285 	}
286 	buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
287 	if (eap_aka_add_id_msg(data, buf) < 0) {
288 		wpabuf_free(buf);
289 		return NULL;
290 	}
291 	data->pending_id = id;
292 	return buf;
293 }
294 
295 
296 static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
297 			      struct eap_sim_msg *msg, u16 counter,
298 			      const u8 *nonce_s)
299 {
300 	os_free(data->next_pseudonym);
301 	if (nonce_s == NULL) {
302 		data->next_pseudonym =
303 			eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
304 	} else {
305 		/* Do not update pseudonym during re-authentication */
306 		data->next_pseudonym = NULL;
307 	}
308 	os_free(data->next_reauth_id);
309 	if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
310 		data->next_reauth_id =
311 			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
312 	} else {
313 		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
314 			   "count exceeded - force full authentication");
315 		data->next_reauth_id = NULL;
316 	}
317 
318 	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
319 	    counter == 0 && nonce_s == NULL)
320 		return 0;
321 
322 	wpa_printf(MSG_DEBUG, "   AT_IV");
323 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
324 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
325 
326 	if (counter > 0) {
327 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
328 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
329 	}
330 
331 	if (nonce_s) {
332 		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
333 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
334 				EAP_SIM_NONCE_S_LEN);
335 	}
336 
337 	if (data->next_pseudonym) {
338 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
339 			   data->next_pseudonym);
340 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
341 				os_strlen(data->next_pseudonym),
342 				(u8 *) data->next_pseudonym,
343 				os_strlen(data->next_pseudonym));
344 	}
345 
346 	if (data->next_reauth_id) {
347 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
348 			   data->next_reauth_id);
349 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
350 				os_strlen(data->next_reauth_id),
351 				(u8 *) data->next_reauth_id,
352 				os_strlen(data->next_reauth_id));
353 	}
354 
355 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
356 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
357 			   "AT_ENCR_DATA");
358 		return -1;
359 	}
360 
361 	return 0;
362 }
363 
364 
365 static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
366 					       struct eap_aka_data *data,
367 					       u8 id)
368 {
369 	struct eap_sim_msg *msg;
370 
371 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
372 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
373 			       EAP_AKA_SUBTYPE_CHALLENGE);
374 	wpa_printf(MSG_DEBUG, "   AT_RAND");
375 	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
376 	wpa_printf(MSG_DEBUG, "   AT_AUTN");
377 	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
378 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
379 		if (data->kdf) {
380 			/* Add the selected KDF into the beginning */
381 			wpa_printf(MSG_DEBUG, "   AT_KDF");
382 			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
383 					NULL, 0);
384 		}
385 		wpa_printf(MSG_DEBUG, "   AT_KDF");
386 		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
387 				NULL, 0);
388 		wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
389 		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
390 				data->network_name_len,
391 				data->network_name, data->network_name_len);
392 	}
393 
394 	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
395 		eap_sim_msg_free(msg);
396 		return NULL;
397 	}
398 
399 	eap_aka_add_checkcode(data, msg);
400 
401 	if (sm->eap_sim_aka_result_ind) {
402 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
403 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
404 	}
405 
406 #ifdef EAP_SERVER_AKA_PRIME
407 	if (data->eap_method == EAP_TYPE_AKA) {
408 		u16 flags = 0;
409 		int i;
410 		int aka_prime_preferred = 0;
411 
412 		i = 0;
413 		while (sm->user && i < EAP_MAX_METHODS &&
414 		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
415 			sm->user->methods[i].method != EAP_TYPE_NONE)) {
416 			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
417 				if (sm->user->methods[i].method ==
418 				    EAP_TYPE_AKA)
419 					break;
420 				if (sm->user->methods[i].method ==
421 				    EAP_TYPE_AKA_PRIME) {
422 					aka_prime_preferred = 1;
423 					break;
424 				}
425 			}
426 			i++;
427 		}
428 
429 		if (aka_prime_preferred)
430 			flags |= EAP_AKA_BIDDING_FLAG_D;
431 		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
432 	}
433 #endif /* EAP_SERVER_AKA_PRIME */
434 
435 	wpa_printf(MSG_DEBUG, "   AT_MAC");
436 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
437 	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
438 }
439 
440 
441 static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
442 					    struct eap_aka_data *data, u8 id)
443 {
444 	struct eap_sim_msg *msg;
445 
446 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
447 
448 	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
449 		return NULL;
450 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
451 			data->nonce_s, EAP_SIM_NONCE_S_LEN);
452 
453 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
454 		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
455 						 sm->identity,
456 						 sm->identity_len,
457 						 data->nonce_s,
458 						 data->msk, data->emsk);
459 	} else {
460 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
461 				    data->msk, data->emsk);
462 		eap_sim_derive_keys_reauth(data->counter, sm->identity,
463 					   sm->identity_len, data->nonce_s,
464 					   data->mk, data->msk, data->emsk);
465 	}
466 
467 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
468 			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
469 
470 	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
471 		eap_sim_msg_free(msg);
472 		return NULL;
473 	}
474 
475 	eap_aka_add_checkcode(data, msg);
476 
477 	if (sm->eap_sim_aka_result_ind) {
478 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
479 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
480 	}
481 
482 	wpa_printf(MSG_DEBUG, "   AT_MAC");
483 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
484 	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
485 }
486 
487 
488 static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
489 						  struct eap_aka_data *data,
490 						  u8 id)
491 {
492 	struct eap_sim_msg *msg;
493 
494 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
495 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
496 			       EAP_AKA_SUBTYPE_NOTIFICATION);
497 	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
498 	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
499 			NULL, 0);
500 	if (data->use_result_ind) {
501 		if (data->reauth) {
502 			wpa_printf(MSG_DEBUG, "   AT_IV");
503 			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
504 			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
505 						   EAP_SIM_AT_ENCR_DATA);
506 			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
507 				   data->counter);
508 			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
509 					NULL, 0);
510 
511 			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
512 						     EAP_SIM_AT_PADDING)) {
513 				wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
514 					   "encrypt AT_ENCR_DATA");
515 				eap_sim_msg_free(msg);
516 				return NULL;
517 			}
518 		}
519 
520 		wpa_printf(MSG_DEBUG, "   AT_MAC");
521 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
522 	}
523 	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
524 }
525 
526 
527 static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
528 {
529 	struct eap_aka_data *data = priv;
530 
531 	data->auts_reported = 0;
532 	switch (data->state) {
533 	case IDENTITY:
534 		return eap_aka_build_identity(sm, data, id);
535 	case CHALLENGE:
536 		return eap_aka_build_challenge(sm, data, id);
537 	case REAUTH:
538 		return eap_aka_build_reauth(sm, data, id);
539 	case NOTIFICATION:
540 		return eap_aka_build_notification(sm, data, id);
541 	default:
542 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
543 			   "buildReq", data->state);
544 		break;
545 	}
546 	return NULL;
547 }
548 
549 
550 static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
551 			     struct wpabuf *respData)
552 {
553 	struct eap_aka_data *data = priv;
554 	const u8 *pos;
555 	size_t len;
556 
557 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
558 			       &len);
559 	if (pos == NULL || len < 3) {
560 		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
561 		return TRUE;
562 	}
563 
564 	return FALSE;
565 }
566 
567 
568 static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
569 {
570 	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
571 	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
572 		return FALSE;
573 
574 	switch (data->state) {
575 	case IDENTITY:
576 		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
577 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
578 				   "subtype %d", subtype);
579 			return TRUE;
580 		}
581 		break;
582 	case CHALLENGE:
583 		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
584 		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
585 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
586 				   "subtype %d", subtype);
587 			return TRUE;
588 		}
589 		break;
590 	case REAUTH:
591 		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
592 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
593 				   "subtype %d", subtype);
594 			return TRUE;
595 		}
596 		break;
597 	case NOTIFICATION:
598 		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
599 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
600 				   "subtype %d", subtype);
601 			return TRUE;
602 		}
603 		break;
604 	default:
605 		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
606 			   "processing a response", data->state);
607 		return TRUE;
608 	}
609 
610 	return FALSE;
611 }
612 
613 
614 static void eap_aka_determine_identity(struct eap_sm *sm,
615 				       struct eap_aka_data *data,
616 				       int before_identity, int after_reauth)
617 {
618 	const u8 *identity;
619 	size_t identity_len;
620 	int res;
621 
622 	identity = NULL;
623 	identity_len = 0;
624 
625 	if (after_reauth && data->reauth) {
626 		identity = data->reauth->identity;
627 		identity_len = data->reauth->identity_len;
628 	} else if (sm->identity && sm->identity_len > 0 &&
629 		   sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
630 		identity = sm->identity;
631 		identity_len = sm->identity_len;
632 	} else {
633 		identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
634 						    sm->identity,
635 						    sm->identity_len,
636 						    &identity_len);
637 		if (identity == NULL) {
638 			data->reauth = eap_sim_db_get_reauth_entry(
639 				sm->eap_sim_db_priv, sm->identity,
640 				sm->identity_len);
641 			if (data->reauth &&
642 			    data->reauth->aka_prime !=
643 			    (data->eap_method == EAP_TYPE_AKA_PRIME)) {
644 				wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
645 					   "was for different AKA version");
646 				data->reauth = NULL;
647 			}
648 			if (data->reauth) {
649 				wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
650 					   "re-authentication");
651 				identity = data->reauth->identity;
652 				identity_len = data->reauth->identity_len;
653 				data->counter = data->reauth->counter;
654 				if (data->eap_method == EAP_TYPE_AKA_PRIME) {
655 					os_memcpy(data->k_encr,
656 						  data->reauth->k_encr,
657 						  EAP_SIM_K_ENCR_LEN);
658 					os_memcpy(data->k_aut,
659 						  data->reauth->k_aut,
660 						  EAP_AKA_PRIME_K_AUT_LEN);
661 					os_memcpy(data->k_re,
662 						  data->reauth->k_re,
663 						  EAP_AKA_PRIME_K_RE_LEN);
664 				} else {
665 					os_memcpy(data->mk, data->reauth->mk,
666 						  EAP_SIM_MK_LEN);
667 				}
668 			}
669 		}
670 	}
671 
672 	if (identity == NULL ||
673 	    eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
674 				      sm->identity_len) < 0) {
675 		if (before_identity) {
676 			wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
677 				   "not known - send AKA-Identity request");
678 			eap_aka_state(data, IDENTITY);
679 			return;
680 		} else {
681 			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
682 				   "permanent user name is known; try to use "
683 				   "it");
684 			/* eap_sim_db_get_aka_auth() will report failure, if
685 			 * this identity is not known. */
686 		}
687 	}
688 
689 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
690 			  identity, identity_len);
691 
692 	if (!after_reauth && data->reauth) {
693 		eap_aka_state(data, REAUTH);
694 		return;
695 	}
696 
697 	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
698 				      identity_len, data->rand, data->autn,
699 				      data->ik, data->ck, data->res,
700 				      &data->res_len, sm);
701 	if (res == EAP_SIM_DB_PENDING) {
702 		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
703 			   "not yet available - pending request");
704 		sm->method_pending = METHOD_PENDING_WAIT;
705 		return;
706 	}
707 
708 #ifdef EAP_SERVER_AKA_PRIME
709 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
710 		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
711 		 * needed 6-octet SQN ^AK for CK',IK' derivation */
712 		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
713 						 data->autn,
714 						 data->network_name,
715 						 data->network_name_len);
716 	}
717 #endif /* EAP_SERVER_AKA_PRIME */
718 
719 	data->reauth = NULL;
720 	data->counter = 0; /* reset re-auth counter since this is full auth */
721 
722 	if (res != 0) {
723 		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
724 			   "authentication data for the peer");
725 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
726 		eap_aka_state(data, NOTIFICATION);
727 		return;
728 	}
729 	if (sm->method_pending == METHOD_PENDING_WAIT) {
730 		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
731 			   "available - abort pending wait");
732 		sm->method_pending = METHOD_PENDING_NONE;
733 	}
734 
735 	identity_len = sm->identity_len;
736 	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
737 		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
738 			   "character from identity");
739 		identity_len--;
740 	}
741 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
742 			  sm->identity, identity_len);
743 
744 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
745 		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
746 					  data->ck, data->k_encr, data->k_aut,
747 					  data->k_re, data->msk, data->emsk);
748 	} else {
749 		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
750 				  data->ck, data->mk);
751 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
752 				    data->msk, data->emsk);
753 	}
754 
755 	eap_aka_state(data, CHALLENGE);
756 }
757 
758 
759 static void eap_aka_process_identity(struct eap_sm *sm,
760 				     struct eap_aka_data *data,
761 				     struct wpabuf *respData,
762 				     struct eap_sim_attrs *attr)
763 {
764 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
765 
766 	if (attr->mac || attr->iv || attr->encr_data) {
767 		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
768 			   "received in EAP-Response/AKA-Identity");
769 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
770 		eap_aka_state(data, NOTIFICATION);
771 		return;
772 	}
773 
774 	if (attr->identity) {
775 		os_free(sm->identity);
776 		sm->identity = os_malloc(attr->identity_len);
777 		if (sm->identity) {
778 			os_memcpy(sm->identity, attr->identity,
779 				  attr->identity_len);
780 			sm->identity_len = attr->identity_len;
781 		}
782 	}
783 
784 	eap_aka_determine_identity(sm, data, 0, 0);
785 	if (eap_get_id(respData) == data->pending_id) {
786 		data->pending_id = -1;
787 		eap_aka_add_id_msg(data, respData);
788 	}
789 }
790 
791 
792 static int eap_aka_verify_mac(struct eap_aka_data *data,
793 			      const struct wpabuf *req,
794 			      const u8 *mac, const u8 *extra,
795 			      size_t extra_len)
796 {
797 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
798 		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
799 						 extra_len);
800 	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
801 }
802 
803 
804 static void eap_aka_process_challenge(struct eap_sm *sm,
805 				      struct eap_aka_data *data,
806 				      struct wpabuf *respData,
807 				      struct eap_sim_attrs *attr)
808 {
809 	const u8 *identity;
810 	size_t identity_len;
811 
812 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
813 
814 #ifdef EAP_SERVER_AKA_PRIME
815 #if 0
816 	/* KDF negotiation; to be enabled only after more than one KDF is
817 	 * supported */
818 	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
819 	    attr->kdf_count == 1 && attr->mac == NULL) {
820 		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
821 			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
822 				   "unknown KDF");
823 			data->notification =
824 				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
825 			eap_aka_state(data, NOTIFICATION);
826 			return;
827 		}
828 
829 		data->kdf = attr->kdf[0];
830 
831 		/* Allow negotiation to continue with the selected KDF by
832 		 * sending another Challenge message */
833 		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
834 		return;
835 	}
836 #endif
837 #endif /* EAP_SERVER_AKA_PRIME */
838 
839 	if (attr->checkcode &&
840 	    eap_aka_verify_checkcode(data, attr->checkcode,
841 				     attr->checkcode_len)) {
842 		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
843 			   "message");
844 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
845 		eap_aka_state(data, NOTIFICATION);
846 		return;
847 	}
848 	if (attr->mac == NULL ||
849 	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
850 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
851 			   "did not include valid AT_MAC");
852 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
853 		eap_aka_state(data, NOTIFICATION);
854 		return;
855 	}
856 
857 	/*
858 	 * AT_RES is padded, so verify that there is enough room for RES and
859 	 * that the RES length in bits matches with the expected RES.
860 	 */
861 	if (attr->res == NULL || attr->res_len < data->res_len ||
862 	    attr->res_len_bits != data->res_len * 8 ||
863 	    os_memcmp(attr->res, data->res, data->res_len) != 0) {
864 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
865 			   "include valid AT_RES (attr len=%lu, res len=%lu "
866 			   "bits, expected %lu bits)",
867 			   (unsigned long) attr->res_len,
868 			   (unsigned long) attr->res_len_bits,
869 			   (unsigned long) data->res_len * 8);
870 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
871 		eap_aka_state(data, NOTIFICATION);
872 		return;
873 	}
874 
875 	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
876 		   "correct AT_MAC");
877 	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
878 		data->use_result_ind = 1;
879 		data->notification = EAP_SIM_SUCCESS;
880 		eap_aka_state(data, NOTIFICATION);
881 	} else
882 		eap_aka_state(data, SUCCESS);
883 
884 	identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
885 					    sm->identity_len, &identity_len);
886 	if (identity == NULL) {
887 		identity = sm->identity;
888 		identity_len = sm->identity_len;
889 	}
890 
891 	if (data->next_pseudonym) {
892 		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
893 					 identity_len,
894 					 data->next_pseudonym);
895 		data->next_pseudonym = NULL;
896 	}
897 	if (data->next_reauth_id) {
898 		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
899 #ifdef EAP_SERVER_AKA_PRIME
900 			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
901 						    identity,
902 						    identity_len,
903 						    data->next_reauth_id,
904 						    data->counter + 1,
905 						    data->k_encr, data->k_aut,
906 						    data->k_re);
907 #endif /* EAP_SERVER_AKA_PRIME */
908 		} else {
909 			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
910 					      identity_len,
911 					      data->next_reauth_id,
912 					      data->counter + 1,
913 					      data->mk);
914 		}
915 		data->next_reauth_id = NULL;
916 	}
917 }
918 
919 
920 static void eap_aka_process_sync_failure(struct eap_sm *sm,
921 					 struct eap_aka_data *data,
922 					 struct wpabuf *respData,
923 					 struct eap_sim_attrs *attr)
924 {
925 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
926 
927 	if (attr->auts == NULL) {
928 		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
929 			   "message did not include valid AT_AUTS");
930 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
931 		eap_aka_state(data, NOTIFICATION);
932 		return;
933 	}
934 
935 	/* Avoid re-reporting AUTS when processing pending EAP packet by
936 	 * maintaining a local flag stating whether this AUTS has already been
937 	 * reported. */
938 	if (!data->auts_reported &&
939 	    eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
940 				     sm->identity_len, attr->auts,
941 				     data->rand)) {
942 		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
943 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
944 		eap_aka_state(data, NOTIFICATION);
945 		return;
946 	}
947 	data->auts_reported = 1;
948 
949 	/* Try again after resynchronization */
950 	eap_aka_determine_identity(sm, data, 0, 0);
951 }
952 
953 
954 static void eap_aka_process_reauth(struct eap_sm *sm,
955 				   struct eap_aka_data *data,
956 				   struct wpabuf *respData,
957 				   struct eap_sim_attrs *attr)
958 {
959 	struct eap_sim_attrs eattr;
960 	u8 *decrypted = NULL;
961 	const u8 *identity, *id2;
962 	size_t identity_len, id2_len;
963 
964 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
965 
966 	if (attr->mac == NULL ||
967 	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
968 			       EAP_SIM_NONCE_S_LEN)) {
969 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
970 			   "did not include valid AT_MAC");
971 		goto fail;
972 	}
973 
974 	if (attr->encr_data == NULL || attr->iv == NULL) {
975 		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
976 			   "message did not include encrypted data");
977 		goto fail;
978 	}
979 
980 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
981 				       attr->encr_data_len, attr->iv, &eattr,
982 				       0);
983 	if (decrypted == NULL) {
984 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
985 			   "data from reauthentication message");
986 		goto fail;
987 	}
988 
989 	if (eattr.counter != data->counter) {
990 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
991 			   "used incorrect counter %u, expected %u",
992 			   eattr.counter, data->counter);
993 		goto fail;
994 	}
995 	os_free(decrypted);
996 	decrypted = NULL;
997 
998 	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
999 		   "the correct AT_MAC");
1000 
1001 	if (eattr.counter_too_small) {
1002 		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
1003 			   "included AT_COUNTER_TOO_SMALL - starting full "
1004 			   "authentication");
1005 		eap_aka_determine_identity(sm, data, 0, 1);
1006 		return;
1007 	}
1008 
1009 	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
1010 		data->use_result_ind = 1;
1011 		data->notification = EAP_SIM_SUCCESS;
1012 		eap_aka_state(data, NOTIFICATION);
1013 	} else
1014 		eap_aka_state(data, SUCCESS);
1015 
1016 	if (data->reauth) {
1017 		identity = data->reauth->identity;
1018 		identity_len = data->reauth->identity_len;
1019 	} else {
1020 		identity = sm->identity;
1021 		identity_len = sm->identity_len;
1022 	}
1023 
1024 	id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
1025 				       identity_len, &id2_len);
1026 	if (id2) {
1027 		identity = id2;
1028 		identity_len = id2_len;
1029 	}
1030 
1031 	if (data->next_reauth_id) {
1032 		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1033 #ifdef EAP_SERVER_AKA_PRIME
1034 			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
1035 						    identity,
1036 						    identity_len,
1037 						    data->next_reauth_id,
1038 						    data->counter + 1,
1039 						    data->k_encr, data->k_aut,
1040 						    data->k_re);
1041 #endif /* EAP_SERVER_AKA_PRIME */
1042 		} else {
1043 			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
1044 					      identity_len,
1045 					      data->next_reauth_id,
1046 					      data->counter + 1,
1047 					      data->mk);
1048 		}
1049 		data->next_reauth_id = NULL;
1050 	} else {
1051 		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
1052 		data->reauth = NULL;
1053 	}
1054 
1055 	return;
1056 
1057 fail:
1058 	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1059 	eap_aka_state(data, NOTIFICATION);
1060 	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
1061 	data->reauth = NULL;
1062 	os_free(decrypted);
1063 }
1064 
1065 
1066 static void eap_aka_process_client_error(struct eap_sm *sm,
1067 					 struct eap_aka_data *data,
1068 					 struct wpabuf *respData,
1069 					 struct eap_sim_attrs *attr)
1070 {
1071 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
1072 		   attr->client_error_code);
1073 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1074 		eap_aka_state(data, SUCCESS);
1075 	else
1076 		eap_aka_state(data, FAILURE);
1077 }
1078 
1079 
1080 static void eap_aka_process_authentication_reject(
1081 	struct eap_sm *sm, struct eap_aka_data *data,
1082 	struct wpabuf *respData, struct eap_sim_attrs *attr)
1083 {
1084 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
1085 	eap_aka_state(data, FAILURE);
1086 }
1087 
1088 
1089 static void eap_aka_process_notification(struct eap_sm *sm,
1090 					 struct eap_aka_data *data,
1091 					 struct wpabuf *respData,
1092 					 struct eap_sim_attrs *attr)
1093 {
1094 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
1095 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1096 		eap_aka_state(data, SUCCESS);
1097 	else
1098 		eap_aka_state(data, FAILURE);
1099 }
1100 
1101 
1102 static void eap_aka_process(struct eap_sm *sm, void *priv,
1103 			    struct wpabuf *respData)
1104 {
1105 	struct eap_aka_data *data = priv;
1106 	const u8 *pos, *end;
1107 	u8 subtype;
1108 	size_t len;
1109 	struct eap_sim_attrs attr;
1110 
1111 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
1112 			       &len);
1113 	if (pos == NULL || len < 3)
1114 		return;
1115 
1116 	end = pos + len;
1117 	subtype = *pos;
1118 	pos += 3;
1119 
1120 	if (eap_aka_subtype_ok(data, subtype)) {
1121 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
1122 			   "EAP-AKA Subtype in EAP Response");
1123 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1124 		eap_aka_state(data, NOTIFICATION);
1125 		return;
1126 	}
1127 
1128 	if (eap_sim_parse_attr(pos, end, &attr,
1129 			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
1130 			       0)) {
1131 		wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
1132 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1133 		eap_aka_state(data, NOTIFICATION);
1134 		return;
1135 	}
1136 
1137 	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
1138 		eap_aka_process_client_error(sm, data, respData, &attr);
1139 		return;
1140 	}
1141 
1142 	if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
1143 		eap_aka_process_authentication_reject(sm, data, respData,
1144 						      &attr);
1145 		return;
1146 	}
1147 
1148 	switch (data->state) {
1149 	case IDENTITY:
1150 		eap_aka_process_identity(sm, data, respData, &attr);
1151 		break;
1152 	case CHALLENGE:
1153 		if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
1154 			eap_aka_process_sync_failure(sm, data, respData,
1155 						     &attr);
1156 		} else {
1157 			eap_aka_process_challenge(sm, data, respData, &attr);
1158 		}
1159 		break;
1160 	case REAUTH:
1161 		eap_aka_process_reauth(sm, data, respData, &attr);
1162 		break;
1163 	case NOTIFICATION:
1164 		eap_aka_process_notification(sm, data, respData, &attr);
1165 		break;
1166 	default:
1167 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
1168 			   "process", data->state);
1169 		break;
1170 	}
1171 }
1172 
1173 
1174 static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
1175 {
1176 	struct eap_aka_data *data = priv;
1177 	return data->state == SUCCESS || data->state == FAILURE;
1178 }
1179 
1180 
1181 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
1182 {
1183 	struct eap_aka_data *data = priv;
1184 	u8 *key;
1185 
1186 	if (data->state != SUCCESS)
1187 		return NULL;
1188 
1189 	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
1190 	if (key == NULL)
1191 		return NULL;
1192 	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
1193 	*len = EAP_SIM_KEYING_DATA_LEN;
1194 	return key;
1195 }
1196 
1197 
1198 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1199 {
1200 	struct eap_aka_data *data = priv;
1201 	u8 *key;
1202 
1203 	if (data->state != SUCCESS)
1204 		return NULL;
1205 
1206 	key = os_malloc(EAP_EMSK_LEN);
1207 	if (key == NULL)
1208 		return NULL;
1209 	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1210 	*len = EAP_EMSK_LEN;
1211 	return key;
1212 }
1213 
1214 
1215 static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
1216 {
1217 	struct eap_aka_data *data = priv;
1218 	return data->state == SUCCESS;
1219 }
1220 
1221 
1222 int eap_server_aka_register(void)
1223 {
1224 	struct eap_method *eap;
1225 	int ret;
1226 
1227 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1228 				      EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
1229 	if (eap == NULL)
1230 		return -1;
1231 
1232 	eap->init = eap_aka_init;
1233 	eap->reset = eap_aka_reset;
1234 	eap->buildReq = eap_aka_buildReq;
1235 	eap->check = eap_aka_check;
1236 	eap->process = eap_aka_process;
1237 	eap->isDone = eap_aka_isDone;
1238 	eap->getKey = eap_aka_getKey;
1239 	eap->isSuccess = eap_aka_isSuccess;
1240 	eap->get_emsk = eap_aka_get_emsk;
1241 
1242 	ret = eap_server_method_register(eap);
1243 	if (ret)
1244 		eap_server_method_free(eap);
1245 	return ret;
1246 }
1247 
1248 
1249 #ifdef EAP_SERVER_AKA_PRIME
1250 int eap_server_aka_prime_register(void)
1251 {
1252 	struct eap_method *eap;
1253 	int ret;
1254 
1255 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1256 				      EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
1257 				      "AKA'");
1258 	if (eap == NULL)
1259 		return -1;
1260 
1261 	eap->init = eap_aka_prime_init;
1262 	eap->reset = eap_aka_reset;
1263 	eap->buildReq = eap_aka_buildReq;
1264 	eap->check = eap_aka_check;
1265 	eap->process = eap_aka_process;
1266 	eap->isDone = eap_aka_isDone;
1267 	eap->getKey = eap_aka_getKey;
1268 	eap->isSuccess = eap_aka_isSuccess;
1269 	eap->get_emsk = eap_aka_get_emsk;
1270 
1271 	ret = eap_server_method_register(eap);
1272 	if (ret)
1273 		eap_server_method_free(eap);
1274 
1275 	return ret;
1276 }
1277 #endif /* EAP_SERVER_AKA_PRIME */
1278