remove @EAP_LDFLAGS@, no longer exists
[mech_eap.orig] / libeap / src / eap_server / eap_server_aka.c
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 "eap_common/eap_sim_common.h"
21 #include "eap_server/eap_i.h"
22 #include "eap_server/eap_sim_db.h"
23
24
25 struct eap_aka_data {
26         u8 mk[EAP_SIM_MK_LEN];
27         u8 nonce_s[EAP_SIM_NONCE_S_LEN];
28         u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
29         u8 k_encr[EAP_SIM_K_ENCR_LEN];
30         u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
31         u8 msk[EAP_SIM_KEYING_DATA_LEN];
32         u8 emsk[EAP_EMSK_LEN];
33         u8 rand[EAP_AKA_RAND_LEN];
34         u8 autn[EAP_AKA_AUTN_LEN];
35         u8 ck[EAP_AKA_CK_LEN];
36         u8 ik[EAP_AKA_IK_LEN];
37         u8 res[EAP_AKA_RES_MAX_LEN];
38         size_t res_len;
39         enum {
40                 IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
41         } state;
42         char *next_pseudonym;
43         char *next_reauth_id;
44         u16 counter;
45         struct eap_sim_reauth *reauth;
46         int auts_reported; /* whether the current AUTS has been reported to the
47                             * eap_sim_db */
48         u16 notification;
49         int use_result_ind;
50
51         struct wpabuf *id_msgs;
52         int pending_id;
53         u8 eap_method;
54         u8 *network_name;
55         size_t network_name_len;
56         u16 kdf;
57 };
58
59
60 static void eap_aka_determine_identity(struct eap_sm *sm,
61                                        struct eap_aka_data *data,
62                                        int before_identity, int after_reauth);
63
64
65 static const char * eap_aka_state_txt(int state)
66 {
67         switch (state) {
68         case IDENTITY:
69                 return "IDENTITY";
70         case CHALLENGE:
71                 return "CHALLENGE";
72         case REAUTH:
73                 return "REAUTH";
74         case SUCCESS:
75                 return "SUCCESS";
76         case FAILURE:
77                 return "FAILURE";
78         case NOTIFICATION:
79                 return "NOTIFICATION";
80         default:
81                 return "Unknown?!";
82         }
83 }
84
85
86 static void eap_aka_state(struct eap_aka_data *data, int state)
87 {
88         wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
89                    eap_aka_state_txt(data->state),
90                    eap_aka_state_txt(state));
91         data->state = state;
92 }
93
94
95 static void * eap_aka_init(struct eap_sm *sm)
96 {
97         struct eap_aka_data *data;
98
99         if (sm->eap_sim_db_priv == NULL) {
100                 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
101                 return NULL;
102         }
103
104         data = os_zalloc(sizeof(*data));
105         if (data == NULL)
106                 return NULL;
107
108         data->eap_method = EAP_TYPE_AKA;
109
110         data->state = IDENTITY;
111         eap_aka_determine_identity(sm, data, 1, 0);
112         data->pending_id = -1;
113
114         return data;
115 }
116
117
118 #ifdef EAP_SERVER_AKA_PRIME
119 static void * eap_aka_prime_init(struct eap_sm *sm)
120 {
121         struct eap_aka_data *data;
122         /* TODO: make ANID configurable; see 3GPP TS 24.302 */
123         char *network_name = "WLAN";
124
125         if (sm->eap_sim_db_priv == NULL) {
126                 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
127                 return NULL;
128         }
129
130         data = os_zalloc(sizeof(*data));
131         if (data == NULL)
132                 return NULL;
133
134         data->eap_method = EAP_TYPE_AKA_PRIME;
135         data->network_name = os_malloc(os_strlen(network_name));
136         if (data->network_name == NULL) {
137                 os_free(data);
138                 return NULL;
139         }
140
141         data->network_name_len = os_strlen(network_name);
142         os_memcpy(data->network_name, network_name, data->network_name_len);
143
144         data->state = IDENTITY;
145         eap_aka_determine_identity(sm, data, 1, 0);
146         data->pending_id = -1;
147
148         return data;
149 }
150 #endif /* EAP_SERVER_AKA_PRIME */
151
152
153 static void eap_aka_reset(struct eap_sm *sm, void *priv)
154 {
155         struct eap_aka_data *data = priv;
156         os_free(data->next_pseudonym);
157         os_free(data->next_reauth_id);
158         wpabuf_free(data->id_msgs);
159         os_free(data->network_name);
160         os_free(data);
161 }
162
163
164 static int eap_aka_add_id_msg(struct eap_aka_data *data,
165                               const struct wpabuf *msg)
166 {
167         if (msg == NULL)
168                 return -1;
169
170         if (data->id_msgs == NULL) {
171                 data->id_msgs = wpabuf_dup(msg);
172                 return data->id_msgs == NULL ? -1 : 0;
173         }
174
175         if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
176                 return -1;
177         wpabuf_put_buf(data->id_msgs, msg);
178
179         return 0;
180 }
181
182
183 static void eap_aka_add_checkcode(struct eap_aka_data *data,
184                                   struct eap_sim_msg *msg)
185 {
186         const u8 *addr;
187         size_t len;
188         u8 hash[SHA256_MAC_LEN];
189
190         wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
191
192         if (data->id_msgs == NULL) {
193                 /*
194                  * No EAP-AKA/Identity packets were exchanged - send empty
195                  * checkcode.
196                  */
197                 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
198                 return;
199         }
200
201         /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
202         addr = wpabuf_head(data->id_msgs);
203         len = wpabuf_len(data->id_msgs);
204         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
205         if (data->eap_method == EAP_TYPE_AKA_PRIME)
206                 sha256_vector(1, &addr, &len, hash);
207         else
208                 sha1_vector(1, &addr, &len, hash);
209
210         eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
211                         data->eap_method == EAP_TYPE_AKA_PRIME ?
212                         EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
213 }
214
215
216 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
217                                     const u8 *checkcode, size_t checkcode_len)
218 {
219         const u8 *addr;
220         size_t len;
221         u8 hash[SHA256_MAC_LEN];
222         size_t hash_len;
223
224         if (checkcode == NULL)
225                 return -1;
226
227         if (data->id_msgs == NULL) {
228                 if (checkcode_len != 0) {
229                         wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
230                                    "indicates that AKA/Identity messages were "
231                                    "used, but they were not");
232                         return -1;
233                 }
234                 return 0;
235         }
236
237         hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
238                 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
239
240         if (checkcode_len != hash_len) {
241                 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
242                            "that AKA/Identity message were not used, but they "
243                            "were");
244                 return -1;
245         }
246
247         /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
248         addr = wpabuf_head(data->id_msgs);
249         len = wpabuf_len(data->id_msgs);
250         if (data->eap_method == EAP_TYPE_AKA_PRIME)
251                 sha256_vector(1, &addr, &len, hash);
252         else
253                 sha1_vector(1, &addr, &len, hash);
254
255         if (os_memcmp(hash, checkcode, hash_len) != 0) {
256                 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
257                 return -1;
258         }
259
260         return 0;
261 }
262
263
264 static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
265                                               struct eap_aka_data *data, u8 id)
266 {
267         struct eap_sim_msg *msg;
268         struct wpabuf *buf;
269
270         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
271         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
272                                EAP_AKA_SUBTYPE_IDENTITY);
273         if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
274                                       sm->identity_len)) {
275                 wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
276                 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
277         } else {
278                 /*
279                  * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
280                  * ignored and the AKA/Identity is used to request the
281                  * identity.
282                  */
283                 wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
284                 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
285         }
286         buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
287         if (eap_aka_add_id_msg(data, buf) < 0) {
288                 wpabuf_free(buf);
289                 return NULL;
290         }
291         data->pending_id = id;
292         return buf;
293 }
294
295
296 static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
297                               struct eap_sim_msg *msg, u16 counter,
298                               const u8 *nonce_s)
299 {
300         os_free(data->next_pseudonym);
301         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
360 static 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
436 static 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 (os_get_random(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
483 static 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
522 static 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
545 static 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
563 static 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
609 static 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
754 static 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
787 static 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
799 static 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
915 static 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
949 static 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
1057 fail:
1058         data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1059         eap_aka_state(data, NOTIFICATION);
1060         eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
1061         data->reauth = NULL;
1062         os_free(decrypted);
1063 }
1064
1065
1066 static void eap_aka_process_client_error(struct eap_sm *sm,
1067                                          struct eap_aka_data *data,
1068                                          struct wpabuf *respData,
1069                                          struct eap_sim_attrs *attr)
1070 {
1071         wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
1072                    attr->client_error_code);
1073         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1074                 eap_aka_state(data, SUCCESS);
1075         else
1076                 eap_aka_state(data, FAILURE);
1077 }
1078
1079
1080 static void eap_aka_process_authentication_reject(
1081         struct eap_sm *sm, struct eap_aka_data *data,
1082         struct wpabuf *respData, struct eap_sim_attrs *attr)
1083 {
1084         wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
1085         eap_aka_state(data, FAILURE);
1086 }
1087
1088
1089 static void eap_aka_process_notification(struct eap_sm *sm,
1090                                          struct eap_aka_data *data,
1091                                          struct wpabuf *respData,
1092                                          struct eap_sim_attrs *attr)
1093 {
1094         wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
1095         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
1096                 eap_aka_state(data, SUCCESS);
1097         else
1098                 eap_aka_state(data, FAILURE);
1099 }
1100
1101
1102 static void eap_aka_process(struct eap_sm *sm, void *priv,
1103                             struct wpabuf *respData)
1104 {
1105         struct eap_aka_data *data = priv;
1106         const u8 *pos, *end;
1107         u8 subtype;
1108         size_t len;
1109         struct eap_sim_attrs attr;
1110
1111         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
1112                                &len);
1113         if (pos == NULL || len < 3)
1114                 return;
1115
1116         end = pos + len;
1117         subtype = *pos;
1118         pos += 3;
1119
1120         if (eap_aka_subtype_ok(data, subtype)) {
1121                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
1122                            "EAP-AKA Subtype in EAP Response");
1123                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1124                 eap_aka_state(data, NOTIFICATION);
1125                 return;
1126         }
1127
1128         if (eap_sim_parse_attr(pos, end, &attr,
1129                                data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
1130                                0)) {
1131                 wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
1132                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
1133                 eap_aka_state(data, NOTIFICATION);
1134                 return;
1135         }
1136
1137         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
1138                 eap_aka_process_client_error(sm, data, respData, &attr);
1139                 return;
1140         }
1141
1142         if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
1143                 eap_aka_process_authentication_reject(sm, data, respData,
1144                                                       &attr);
1145                 return;
1146         }
1147
1148         switch (data->state) {
1149         case IDENTITY:
1150                 eap_aka_process_identity(sm, data, respData, &attr);
1151                 break;
1152         case CHALLENGE:
1153                 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
1154                         eap_aka_process_sync_failure(sm, data, respData,
1155                                                      &attr);
1156                 } else {
1157                         eap_aka_process_challenge(sm, data, respData, &attr);
1158                 }
1159                 break;
1160         case REAUTH:
1161                 eap_aka_process_reauth(sm, data, respData, &attr);
1162                 break;
1163         case NOTIFICATION:
1164                 eap_aka_process_notification(sm, data, respData, &attr);
1165                 break;
1166         default:
1167                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
1168                            "process", data->state);
1169                 break;
1170         }
1171 }
1172
1173
1174 static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
1175 {
1176         struct eap_aka_data *data = priv;
1177         return data->state == SUCCESS || data->state == FAILURE;
1178 }
1179
1180
1181 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
1182 {
1183         struct eap_aka_data *data = priv;
1184         u8 *key;
1185
1186         if (data->state != SUCCESS)
1187                 return NULL;
1188
1189         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
1190         if (key == NULL)
1191                 return NULL;
1192         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
1193         *len = EAP_SIM_KEYING_DATA_LEN;
1194         return key;
1195 }
1196
1197
1198 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1199 {
1200         struct eap_aka_data *data = priv;
1201         u8 *key;
1202
1203         if (data->state != SUCCESS)
1204                 return NULL;
1205
1206         key = os_malloc(EAP_EMSK_LEN);
1207         if (key == NULL)
1208                 return NULL;
1209         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1210         *len = EAP_EMSK_LEN;
1211         return key;
1212 }
1213
1214
1215 static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
1216 {
1217         struct eap_aka_data *data = priv;
1218         return data->state == SUCCESS;
1219 }
1220
1221
1222 int eap_server_aka_register(void)
1223 {
1224         struct eap_method *eap;
1225         int ret;
1226
1227         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1228                                       EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
1229         if (eap == NULL)
1230                 return -1;
1231
1232         eap->init = eap_aka_init;
1233         eap->reset = eap_aka_reset;
1234         eap->buildReq = eap_aka_buildReq;
1235         eap->check = eap_aka_check;
1236         eap->process = eap_aka_process;
1237         eap->isDone = eap_aka_isDone;
1238         eap->getKey = eap_aka_getKey;
1239         eap->isSuccess = eap_aka_isSuccess;
1240         eap->get_emsk = eap_aka_get_emsk;
1241
1242         ret = eap_server_method_register(eap);
1243         if (ret)
1244                 eap_server_method_free(eap);
1245         return ret;
1246 }
1247
1248
1249 #ifdef EAP_SERVER_AKA_PRIME
1250 int eap_server_aka_prime_register(void)
1251 {
1252         struct eap_method *eap;
1253         int ret;
1254
1255         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1256                                       EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
1257                                       "AKA'");
1258         if (eap == NULL)
1259                 return -1;
1260
1261         eap->init = eap_aka_prime_init;
1262         eap->reset = eap_aka_reset;
1263         eap->buildReq = eap_aka_buildReq;
1264         eap->check = eap_aka_check;
1265         eap->process = eap_aka_process;
1266         eap->isDone = eap_aka_isDone;
1267         eap->getKey = eap_aka_getKey;
1268         eap->isSuccess = eap_aka_isSuccess;
1269         eap->get_emsk = eap_aka_get_emsk;
1270
1271         ret = eap_server_method_register(eap);
1272         if (ret)
1273                 eap_server_method_free(eap);
1274
1275         return ret;
1276 }
1277 #endif /* EAP_SERVER_AKA_PRIME */