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