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