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