eap_server_aka.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
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 = (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
153static 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
164static 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
183static 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
216static 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
264static 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
296static 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	data->next_pseudonym =
302		eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
303	os_free(data->next_reauth_id);
304	if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
305		data->next_reauth_id =
306			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
307	} else {
308		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
309			   "count exceeded - force full authentication");
310		data->next_reauth_id = NULL;
311	}
312
313	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
314	    counter == 0 && nonce_s == NULL)
315		return 0;
316
317	wpa_printf(MSG_DEBUG, "   AT_IV");
318	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
319	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
320
321	if (counter > 0) {
322		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
323		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
324	}
325
326	if (nonce_s) {
327		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
328		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
329				EAP_SIM_NONCE_S_LEN);
330	}
331
332	if (data->next_pseudonym) {
333		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
334			   data->next_pseudonym);
335		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
336				os_strlen(data->next_pseudonym),
337				(u8 *) data->next_pseudonym,
338				os_strlen(data->next_pseudonym));
339	}
340
341	if (data->next_reauth_id) {
342		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
343			   data->next_reauth_id);
344		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
345				os_strlen(data->next_reauth_id),
346				(u8 *) data->next_reauth_id,
347				os_strlen(data->next_reauth_id));
348	}
349
350	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
351		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
352			   "AT_ENCR_DATA");
353		return -1;
354	}
355
356	return 0;
357}
358
359
360static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
361					       struct eap_aka_data *data,
362					       u8 id)
363{
364	struct eap_sim_msg *msg;
365
366	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
367	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
368			       EAP_AKA_SUBTYPE_CHALLENGE);
369	wpa_printf(MSG_DEBUG, "   AT_RAND");
370	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
371	wpa_printf(MSG_DEBUG, "   AT_AUTN");
372	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
373	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
374		if (data->kdf) {
375			/* Add the selected KDF into the beginning */
376			wpa_printf(MSG_DEBUG, "   AT_KDF");
377			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
378					NULL, 0);
379		}
380		wpa_printf(MSG_DEBUG, "   AT_KDF");
381		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
382				NULL, 0);
383		wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
384		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
385				data->network_name_len,
386				data->network_name, data->network_name_len);
387	}
388
389	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
390		eap_sim_msg_free(msg);
391		return NULL;
392	}
393
394	eap_aka_add_checkcode(data, msg);
395
396	if (sm->eap_sim_aka_result_ind) {
397		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
398		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
399	}
400
401#ifdef EAP_SERVER_AKA_PRIME
402	if (data->eap_method == EAP_TYPE_AKA) {
403		u16 flags = 0;
404		int i;
405		int aka_prime_preferred = 0;
406
407		i = 0;
408		while (sm->user && i < EAP_MAX_METHODS &&
409		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
410			sm->user->methods[i].method != EAP_TYPE_NONE)) {
411			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
412				if (sm->user->methods[i].method ==
413				    EAP_TYPE_AKA)
414					break;
415				if (sm->user->methods[i].method ==
416				    EAP_TYPE_AKA_PRIME) {
417					aka_prime_preferred = 1;
418					break;
419				}
420			}
421			i++;
422		}
423
424		if (aka_prime_preferred)
425			flags |= EAP_AKA_BIDDING_FLAG_D;
426		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
427	}
428#endif /* EAP_SERVER_AKA_PRIME */
429
430	wpa_printf(MSG_DEBUG, "   AT_MAC");
431	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
432	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
433}
434
435
436static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
437					    struct eap_aka_data *data, u8 id)
438{
439	struct eap_sim_msg *msg;
440
441	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
442
443	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
444		return NULL;
445	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
446			data->nonce_s, EAP_SIM_NONCE_S_LEN);
447
448	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
449		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
450						 sm->identity,
451						 sm->identity_len,
452						 data->nonce_s,
453						 data->msk, data->emsk);
454	} else {
455		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
456				    data->msk, data->emsk);
457		eap_sim_derive_keys_reauth(data->counter, sm->identity,
458					   sm->identity_len, data->nonce_s,
459					   data->mk, data->msk, data->emsk);
460	}
461
462	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
463			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
464
465	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
466		eap_sim_msg_free(msg);
467		return NULL;
468	}
469
470	eap_aka_add_checkcode(data, msg);
471
472	if (sm->eap_sim_aka_result_ind) {
473		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
474		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
475	}
476
477	wpa_printf(MSG_DEBUG, "   AT_MAC");
478	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
479	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
480}
481
482
483static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
484						  struct eap_aka_data *data,
485						  u8 id)
486{
487	struct eap_sim_msg *msg;
488
489	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
490	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
491			       EAP_AKA_SUBTYPE_NOTIFICATION);
492	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
493	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
494			NULL, 0);
495	if (data->use_result_ind) {
496		if (data->reauth) {
497			wpa_printf(MSG_DEBUG, "   AT_IV");
498			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
499			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
500						   EAP_SIM_AT_ENCR_DATA);
501			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
502				   data->counter);
503			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
504					NULL, 0);
505
506			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
507						     EAP_SIM_AT_PADDING)) {
508				wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
509					   "encrypt AT_ENCR_DATA");
510				eap_sim_msg_free(msg);
511				return NULL;
512			}
513		}
514
515		wpa_printf(MSG_DEBUG, "   AT_MAC");
516		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
517	}
518	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
519}
520
521
522static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
523{
524	struct eap_aka_data *data = priv;
525
526	data->auts_reported = 0;
527	switch (data->state) {
528	case IDENTITY:
529		return eap_aka_build_identity(sm, data, id);
530	case CHALLENGE:
531		return eap_aka_build_challenge(sm, data, id);
532	case REAUTH:
533		return eap_aka_build_reauth(sm, data, id);
534	case NOTIFICATION:
535		return eap_aka_build_notification(sm, data, id);
536	default:
537		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
538			   "buildReq", data->state);
539		break;
540	}
541	return NULL;
542}
543
544
545static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
546			     struct wpabuf *respData)
547{
548	struct eap_aka_data *data = priv;
549	const u8 *pos;
550	size_t len;
551
552	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
553			       &len);
554	if (pos == NULL || len < 3) {
555		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
556		return TRUE;
557	}
558
559	return FALSE;
560}
561
562
563static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
564{
565	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
566	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
567		return FALSE;
568
569	switch (data->state) {
570	case IDENTITY:
571		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
572			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
573				   "subtype %d", subtype);
574			return TRUE;
575		}
576		break;
577	case CHALLENGE:
578		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
579		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
580			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
581				   "subtype %d", subtype);
582			return TRUE;
583		}
584		break;
585	case REAUTH:
586		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
587			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
588				   "subtype %d", subtype);
589			return TRUE;
590		}
591		break;
592	case NOTIFICATION:
593		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
594			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
595				   "subtype %d", subtype);
596			return TRUE;
597		}
598		break;
599	default:
600		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
601			   "processing a response", data->state);
602		return TRUE;
603	}
604
605	return FALSE;
606}
607
608
609static void eap_aka_determine_identity(struct eap_sm *sm,
610				       struct eap_aka_data *data,
611				       int before_identity, int after_reauth)
612{
613	const u8 *identity;
614	size_t identity_len;
615	int res;
616
617	identity = NULL;
618	identity_len = 0;
619
620	if (after_reauth && data->reauth) {
621		identity = data->reauth->identity;
622		identity_len = data->reauth->identity_len;
623	} else if (sm->identity && sm->identity_len > 0 &&
624		   sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
625		identity = sm->identity;
626		identity_len = sm->identity_len;
627	} else {
628		identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
629						    sm->identity,
630						    sm->identity_len,
631						    &identity_len);
632		if (identity == NULL) {
633			data->reauth = eap_sim_db_get_reauth_entry(
634				sm->eap_sim_db_priv, sm->identity,
635				sm->identity_len);
636			if (data->reauth &&
637			    data->reauth->aka_prime !=
638			    (data->eap_method == EAP_TYPE_AKA_PRIME)) {
639				wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
640					   "was for different AKA version");
641				data->reauth = NULL;
642			}
643			if (data->reauth) {
644				wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
645					   "re-authentication");
646				identity = data->reauth->identity;
647				identity_len = data->reauth->identity_len;
648				data->counter = data->reauth->counter;
649				if (data->eap_method == EAP_TYPE_AKA_PRIME) {
650					os_memcpy(data->k_encr,
651						  data->reauth->k_encr,
652						  EAP_SIM_K_ENCR_LEN);
653					os_memcpy(data->k_aut,
654						  data->reauth->k_aut,
655						  EAP_AKA_PRIME_K_AUT_LEN);
656					os_memcpy(data->k_re,
657						  data->reauth->k_re,
658						  EAP_AKA_PRIME_K_RE_LEN);
659				} else {
660					os_memcpy(data->mk, data->reauth->mk,
661						  EAP_SIM_MK_LEN);
662				}
663			}
664		}
665	}
666
667	if (identity == NULL ||
668	    eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
669				      sm->identity_len) < 0) {
670		if (before_identity) {
671			wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
672				   "not known - send AKA-Identity request");
673			eap_aka_state(data, IDENTITY);
674			return;
675		} else {
676			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
677				   "permanent user name is known; try to use "
678				   "it");
679			/* eap_sim_db_get_aka_auth() will report failure, if
680			 * this identity is not known. */
681		}
682	}
683
684	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
685			  identity, identity_len);
686
687	if (!after_reauth && data->reauth) {
688		eap_aka_state(data, REAUTH);
689		return;
690	}
691
692	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
693				      identity_len, data->rand, data->autn,
694				      data->ik, data->ck, data->res,
695				      &data->res_len, sm);
696	if (res == EAP_SIM_DB_PENDING) {
697		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
698			   "not yet available - pending request");
699		sm->method_pending = METHOD_PENDING_WAIT;
700		return;
701	}
702
703#ifdef EAP_SERVER_AKA_PRIME
704	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
705		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
706		 * needed 6-octet SQN ^AK for CK',IK' derivation */
707		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
708						 data->autn,
709						 data->network_name,
710						 data->network_name_len);
711	}
712#endif /* EAP_SERVER_AKA_PRIME */
713
714	data->reauth = NULL;
715	data->counter = 0; /* reset re-auth counter since this is full auth */
716
717	if (res != 0) {
718		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
719			   "authentication data for the peer");
720		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
721		eap_aka_state(data, NOTIFICATION);
722		return;
723	}
724	if (sm->method_pending == METHOD_PENDING_WAIT) {
725		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
726			   "available - abort pending wait");
727		sm->method_pending = METHOD_PENDING_NONE;
728	}
729
730	identity_len = sm->identity_len;
731	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
732		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
733			   "character from identity");
734		identity_len--;
735	}
736	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
737			  sm->identity, identity_len);
738
739	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
740		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
741					  data->ck, data->k_encr, data->k_aut,
742					  data->k_re, data->msk, data->emsk);
743	} else {
744		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
745				  data->ck, data->mk);
746		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
747				    data->msk, data->emsk);
748	}
749
750	eap_aka_state(data, CHALLENGE);
751}
752
753
754static void eap_aka_process_identity(struct eap_sm *sm,
755				     struct eap_aka_data *data,
756				     struct wpabuf *respData,
757				     struct eap_sim_attrs *attr)
758{
759	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
760
761	if (attr->mac || attr->iv || attr->encr_data) {
762		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
763			   "received in EAP-Response/AKA-Identity");
764		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
765		eap_aka_state(data, NOTIFICATION);
766		return;
767	}
768
769	if (attr->identity) {
770		os_free(sm->identity);
771		sm->identity = os_malloc(attr->identity_len);
772		if (sm->identity) {
773			os_memcpy(sm->identity, attr->identity,
774				  attr->identity_len);
775			sm->identity_len = attr->identity_len;
776		}
777	}
778
779	eap_aka_determine_identity(sm, data, 0, 0);
780	if (eap_get_id(respData) == data->pending_id) {
781		data->pending_id = -1;
782		eap_aka_add_id_msg(data, respData);
783	}
784}
785
786
787static int eap_aka_verify_mac(struct eap_aka_data *data,
788			      const struct wpabuf *req,
789			      const u8 *mac, const u8 *extra,
790			      size_t extra_len)
791{
792	if (data->eap_method == EAP_TYPE_AKA_PRIME)
793		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
794						 extra_len);
795	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
796}
797
798
799static void eap_aka_process_challenge(struct eap_sm *sm,
800				      struct eap_aka_data *data,
801				      struct wpabuf *respData,
802				      struct eap_sim_attrs *attr)
803{
804	const u8 *identity;
805	size_t identity_len;
806
807	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
808
809#ifdef EAP_SERVER_AKA_PRIME
810#if 0
811	/* KDF negotiation; to be enabled only after more than one KDF is
812	 * supported */
813	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
814	    attr->kdf_count == 1 && attr->mac == NULL) {
815		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
816			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
817				   "unknown KDF");
818			data->notification =
819				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
820			eap_aka_state(data, NOTIFICATION);
821			return;
822		}
823
824		data->kdf = attr->kdf[0];
825
826		/* Allow negotiation to continue with the selected KDF by
827		 * sending another Challenge message */
828		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
829		return;
830	}
831#endif
832#endif /* EAP_SERVER_AKA_PRIME */
833
834	if (attr->checkcode &&
835	    eap_aka_verify_checkcode(data, attr->checkcode,
836				     attr->checkcode_len)) {
837		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
838			   "message");
839		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
840		eap_aka_state(data, NOTIFICATION);
841		return;
842	}
843	if (attr->mac == NULL ||
844	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
845		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
846			   "did not include valid AT_MAC");
847		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
848		eap_aka_state(data, NOTIFICATION);
849		return;
850	}
851
852	/*
853	 * AT_RES is padded, so verify that there is enough room for RES and
854	 * that the RES length in bits matches with the expected RES.
855	 */
856	if (attr->res == NULL || attr->res_len < data->res_len ||
857	    attr->res_len_bits != data->res_len * 8 ||
858	    os_memcmp(attr->res, data->res, data->res_len) != 0) {
859		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
860			   "include valid AT_RES (attr len=%lu, res len=%lu "
861			   "bits, expected %lu bits)",
862			   (unsigned long) attr->res_len,
863			   (unsigned long) attr->res_len_bits,
864			   (unsigned long) data->res_len * 8);
865		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
866		eap_aka_state(data, NOTIFICATION);
867		return;
868	}
869
870	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
871		   "correct AT_MAC");
872	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
873		data->use_result_ind = 1;
874		data->notification = EAP_SIM_SUCCESS;
875		eap_aka_state(data, NOTIFICATION);
876	} else
877		eap_aka_state(data, SUCCESS);
878
879	identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
880					    sm->identity_len, &identity_len);
881	if (identity == NULL) {
882		identity = sm->identity;
883		identity_len = sm->identity_len;
884	}
885
886	if (data->next_pseudonym) {
887		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
888					 identity_len,
889					 data->next_pseudonym);
890		data->next_pseudonym = NULL;
891	}
892	if (data->next_reauth_id) {
893		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
894#ifdef EAP_SERVER_AKA_PRIME
895			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
896						    identity,
897						    identity_len,
898						    data->next_reauth_id,
899						    data->counter + 1,
900						    data->k_encr, data->k_aut,
901						    data->k_re);
902#endif /* EAP_SERVER_AKA_PRIME */
903		} else {
904			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
905					      identity_len,
906					      data->next_reauth_id,
907					      data->counter + 1,
908					      data->mk);
909		}
910		data->next_reauth_id = NULL;
911	}
912}
913
914
915static void eap_aka_process_sync_failure(struct eap_sm *sm,
916					 struct eap_aka_data *data,
917					 struct wpabuf *respData,
918					 struct eap_sim_attrs *attr)
919{
920	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
921
922	if (attr->auts == NULL) {
923		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
924			   "message did not include valid AT_AUTS");
925		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
926		eap_aka_state(data, NOTIFICATION);
927		return;
928	}
929
930	/* Avoid re-reporting AUTS when processing pending EAP packet by
931	 * maintaining a local flag stating whether this AUTS has already been
932	 * reported. */
933	if (!data->auts_reported &&
934	    eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
935				     sm->identity_len, attr->auts,
936				     data->rand)) {
937		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
938		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
939		eap_aka_state(data, NOTIFICATION);
940		return;
941	}
942	data->auts_reported = 1;
943
944	/* Try again after resynchronization */
945	eap_aka_determine_identity(sm, data, 0, 0);
946}
947
948
949static void eap_aka_process_reauth(struct eap_sm *sm,
950				   struct eap_aka_data *data,
951				   struct wpabuf *respData,
952				   struct eap_sim_attrs *attr)
953{
954	struct eap_sim_attrs eattr;
955	u8 *decrypted = NULL;
956	const u8 *identity, *id2;
957	size_t identity_len, id2_len;
958
959	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
960
961	if (attr->mac == NULL ||
962	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
963			       EAP_SIM_NONCE_S_LEN)) {
964		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
965			   "did not include valid AT_MAC");
966		goto fail;
967	}
968
969	if (attr->encr_data == NULL || attr->iv == NULL) {
970		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
971			   "message did not include encrypted data");
972		goto fail;
973	}
974
975	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
976				       attr->encr_data_len, attr->iv, &eattr,
977				       0);
978	if (decrypted == NULL) {
979		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
980			   "data from reauthentication message");
981		goto fail;
982	}
983
984	if (eattr.counter != data->counter) {
985		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
986			   "used incorrect counter %u, expected %u",
987			   eattr.counter, data->counter);
988		goto fail;
989	}
990	os_free(decrypted);
991	decrypted = NULL;
992
993	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
994		   "the correct AT_MAC");
995
996	if (eattr.counter_too_small) {
997		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
998			   "included AT_COUNTER_TOO_SMALL - starting full "
999			   "authentication");
1000		eap_aka_determine_identity(sm, data, 0, 1);
1001		return;
1002	}
1003
1004	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
1005		data->use_result_ind = 1;
1006		data->notification = EAP_SIM_SUCCESS;
1007		eap_aka_state(data, NOTIFICATION);
1008	} else
1009		eap_aka_state(data, SUCCESS);
1010
1011	if (data->reauth) {
1012		identity = data->reauth->identity;
1013		identity_len = data->reauth->identity_len;
1014	} else {
1015		identity = sm->identity;
1016		identity_len = sm->identity_len;
1017	}
1018
1019	id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
1020				       identity_len, &id2_len);
1021	if (id2) {
1022		identity = id2;
1023		identity_len = id2_len;
1024	}
1025
1026	if (data->next_pseudonym) {
1027		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
1028					 identity_len, data->next_pseudonym);
1029		data->next_pseudonym = NULL;
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
1057fail:
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
1066static 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
1080static 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
1089static 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
1102static 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
1174static 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
1181static 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
1198static 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
1215static 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
1222int 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
1250int 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