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