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