automake build system
[mech_eap.orig] / src / eap_peer / eap_aka.c
1 /*
2  * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
3  * Copyright (c) 2004-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 "pcsc_funcs.h"
19 #include "crypto/crypto.h"
20 #include "crypto/sha1.h"
21 #include "crypto/sha256.h"
22 #include "crypto/milenage.h"
23 #include "eap_common/eap_sim_common.h"
24 #include "eap_config.h"
25 #include "eap_i.h"
26
27
28 struct eap_aka_data {
29         u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN];
30         size_t res_len;
31         u8 nonce_s[EAP_SIM_NONCE_S_LEN];
32         u8 mk[EAP_SIM_MK_LEN];
33         u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
34         u8 k_encr[EAP_SIM_K_ENCR_LEN];
35         u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
36         u8 msk[EAP_SIM_KEYING_DATA_LEN];
37         u8 emsk[EAP_EMSK_LEN];
38         u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
39         u8 auts[EAP_AKA_AUTS_LEN];
40
41         int num_id_req, num_notification;
42         u8 *pseudonym;
43         size_t pseudonym_len;
44         u8 *reauth_id;
45         size_t reauth_id_len;
46         int reauth;
47         unsigned int counter, counter_too_small;
48         u8 *last_eap_identity;
49         size_t last_eap_identity_len;
50         enum {
51                 CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
52         } state;
53
54         struct wpabuf *id_msgs;
55         int prev_id;
56         int result_ind, use_result_ind;
57         u8 eap_method;
58         u8 *network_name;
59         size_t network_name_len;
60         u16 kdf;
61         int kdf_negotiation;
62 };
63
64
65 #ifndef CONFIG_NO_STDOUT_DEBUG
66 static const char * eap_aka_state_txt(int state)
67 {
68         switch (state) {
69         case CONTINUE:
70                 return "CONTINUE";
71         case RESULT_SUCCESS:
72                 return "RESULT_SUCCESS";
73         case RESULT_FAILURE:
74                 return "RESULT_FAILURE";
75         case SUCCESS:
76                 return "SUCCESS";
77         case FAILURE:
78                 return "FAILURE";
79         default:
80                 return "?";
81         }
82 }
83 #endif /* CONFIG_NO_STDOUT_DEBUG */
84
85
86 static void eap_aka_state(struct eap_aka_data *data, int state)
87 {
88         wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
89                    eap_aka_state_txt(data->state),
90                    eap_aka_state_txt(state));
91         data->state = state;
92 }
93
94
95 static void * eap_aka_init(struct eap_sm *sm)
96 {
97         struct eap_aka_data *data;
98         const char *phase1 = eap_get_config_phase1(sm);
99
100         data = os_zalloc(sizeof(*data));
101         if (data == NULL)
102                 return NULL;
103
104         data->eap_method = EAP_TYPE_AKA;
105
106         eap_aka_state(data, CONTINUE);
107         data->prev_id = -1;
108
109         data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
110
111         return data;
112 }
113
114
115 #ifdef EAP_AKA_PRIME
116 static void * eap_aka_prime_init(struct eap_sm *sm)
117 {
118         struct eap_aka_data *data = eap_aka_init(sm);
119         if (data == NULL)
120                 return NULL;
121         data->eap_method = EAP_TYPE_AKA_PRIME;
122         return data;
123 }
124 #endif /* EAP_AKA_PRIME */
125
126
127 static void eap_aka_deinit(struct eap_sm *sm, void *priv)
128 {
129         struct eap_aka_data *data = priv;
130         if (data) {
131                 os_free(data->pseudonym);
132                 os_free(data->reauth_id);
133                 os_free(data->last_eap_identity);
134                 wpabuf_free(data->id_msgs);
135                 os_free(data->network_name);
136                 os_free(data);
137         }
138 }
139
140
141 static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
142 {
143         struct eap_peer_config *conf;
144
145         wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
146
147         conf = eap_get_config(sm);
148         if (conf == NULL)
149                 return -1;
150         if (conf->pcsc) {
151                 return scard_umts_auth(sm->scard_ctx, data->rand,
152                                        data->autn, data->res, &data->res_len,
153                                        data->ik, data->ck, data->auts);
154         }
155
156 #ifdef CONFIG_USIM_SIMULATOR
157         if (conf->password) {
158                 u8 opc[16], k[16], sqn[6];
159                 const char *pos;
160                 wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage "
161                            "implementation for UMTS authentication");
162                 if (conf->password_len < 78) {
163                         wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage "
164                                    "password");
165                         return -1;
166                 }
167                 pos = (const char *) conf->password;
168                 if (hexstr2bin(pos, k, 16))
169                         return -1;
170                 pos += 32;
171                 if (*pos != ':')
172                         return -1;
173                 pos++;
174
175                 if (hexstr2bin(pos, opc, 16))
176                         return -1;
177                 pos += 32;
178                 if (*pos != ':')
179                         return -1;
180                 pos++;
181
182                 if (hexstr2bin(pos, sqn, 6))
183                         return -1;
184
185                 return milenage_check(opc, k, sqn, data->rand, data->autn,
186                                       data->ik, data->ck,
187                                       data->res, &data->res_len, data->auts);
188         }
189 #endif /* CONFIG_USIM_SIMULATOR */
190
191 #ifdef CONFIG_USIM_HARDCODED
192         wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for "
193                    "testing");
194
195         /* These hardcoded Kc and SRES values are used for testing.
196          * Could consider making them configurable. */
197         os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN);
198         data->res_len = EAP_AKA_RES_MAX_LEN;
199         os_memset(data->ik, '3', EAP_AKA_IK_LEN);
200         os_memset(data->ck, '4', EAP_AKA_CK_LEN);
201         {
202                 u8 autn[EAP_AKA_AUTN_LEN];
203                 os_memset(autn, '1', EAP_AKA_AUTN_LEN);
204                 if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
205                         wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
206                                    "with expected value");
207                         return -1;
208                 }
209         }
210 #if 0
211         {
212                 static int test_resync = 1;
213                 if (test_resync) {
214                         /* Test Resynchronization */
215                         test_resync = 0;
216                         return -2;
217                 }
218         }
219 #endif
220         return 0;
221
222 #else /* CONFIG_USIM_HARDCODED */
223
224         wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorith "
225                    "enabled");
226         return -1;
227
228 #endif /* CONFIG_USIM_HARDCODED */
229 }
230
231
232 #define CLEAR_PSEUDONYM 0x01
233 #define CLEAR_REAUTH_ID 0x02
234 #define CLEAR_EAP_ID    0x04
235
236 static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
237 {
238         wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
239                    id & CLEAR_PSEUDONYM ? " pseudonym" : "",
240                    id & CLEAR_REAUTH_ID ? " reauth_id" : "",
241                    id & CLEAR_EAP_ID ? " eap_id" : "");
242         if (id & CLEAR_PSEUDONYM) {
243                 os_free(data->pseudonym);
244                 data->pseudonym = NULL;
245                 data->pseudonym_len = 0;
246         }
247         if (id & CLEAR_REAUTH_ID) {
248                 os_free(data->reauth_id);
249                 data->reauth_id = NULL;
250                 data->reauth_id_len = 0;
251         }
252         if (id & CLEAR_EAP_ID) {
253                 os_free(data->last_eap_identity);
254                 data->last_eap_identity = NULL;
255                 data->last_eap_identity_len = 0;
256         }
257 }
258
259
260 static int eap_aka_learn_ids(struct eap_aka_data *data,
261                              struct eap_sim_attrs *attr)
262 {
263         if (attr->next_pseudonym) {
264                 os_free(data->pseudonym);
265                 data->pseudonym = os_malloc(attr->next_pseudonym_len);
266                 if (data->pseudonym == NULL) {
267                         wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
268                                    "next pseudonym");
269                         return -1;
270                 }
271                 os_memcpy(data->pseudonym, attr->next_pseudonym,
272                           attr->next_pseudonym_len);
273                 data->pseudonym_len = attr->next_pseudonym_len;
274                 wpa_hexdump_ascii(MSG_DEBUG,
275                                   "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
276                                   data->pseudonym,
277                                   data->pseudonym_len);
278         }
279
280         if (attr->next_reauth_id) {
281                 os_free(data->reauth_id);
282                 data->reauth_id = os_malloc(attr->next_reauth_id_len);
283                 if (data->reauth_id == NULL) {
284                         wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
285                                    "next reauth_id");
286                         return -1;
287                 }
288                 os_memcpy(data->reauth_id, attr->next_reauth_id,
289                           attr->next_reauth_id_len);
290                 data->reauth_id_len = attr->next_reauth_id_len;
291                 wpa_hexdump_ascii(MSG_DEBUG,
292                                   "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
293                                   data->reauth_id,
294                                   data->reauth_id_len);
295         }
296
297         return 0;
298 }
299
300
301 static int eap_aka_add_id_msg(struct eap_aka_data *data,
302                               const struct wpabuf *msg)
303 {
304         if (msg == NULL)
305                 return -1;
306
307         if (data->id_msgs == NULL) {
308                 data->id_msgs = wpabuf_dup(msg);
309                 return data->id_msgs == NULL ? -1 : 0;
310         }
311
312         if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
313                 return -1;
314         wpabuf_put_buf(data->id_msgs, msg);
315
316         return 0;
317 }
318
319
320 static void eap_aka_add_checkcode(struct eap_aka_data *data,
321                                   struct eap_sim_msg *msg)
322 {
323         const u8 *addr;
324         size_t len;
325         u8 hash[SHA256_MAC_LEN];
326
327         wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
328
329         if (data->id_msgs == NULL) {
330                 /*
331                  * No EAP-AKA/Identity packets were exchanged - send empty
332                  * checkcode.
333                  */
334                 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
335                 return;
336         }
337
338         /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
339         addr = wpabuf_head(data->id_msgs);
340         len = wpabuf_len(data->id_msgs);
341         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
342 #ifdef EAP_AKA_PRIME
343         if (data->eap_method == EAP_TYPE_AKA_PRIME)
344                 sha256_vector(1, &addr, &len, hash);
345         else
346 #endif /* EAP_AKA_PRIME */
347                 sha1_vector(1, &addr, &len, hash);
348
349         eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
350                         data->eap_method == EAP_TYPE_AKA_PRIME ?
351                         EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
352 }
353
354
355 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
356                                     const u8 *checkcode, size_t checkcode_len)
357 {
358         const u8 *addr;
359         size_t len;
360         u8 hash[SHA256_MAC_LEN];
361         size_t hash_len;
362
363         if (checkcode == NULL)
364                 return -1;
365
366         if (data->id_msgs == NULL) {
367                 if (checkcode_len != 0) {
368                         wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
369                                    "indicates that AKA/Identity messages were "
370                                    "used, but they were not");
371                         return -1;
372                 }
373                 return 0;
374         }
375
376         hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
377                 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
378
379         if (checkcode_len != hash_len) {
380                 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
381                            "indicates that AKA/Identity message were not "
382                            "used, but they were");
383                 return -1;
384         }
385
386         /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
387         addr = wpabuf_head(data->id_msgs);
388         len = wpabuf_len(data->id_msgs);
389 #ifdef EAP_AKA_PRIME
390         if (data->eap_method == EAP_TYPE_AKA_PRIME)
391                 sha256_vector(1, &addr, &len, hash);
392         else
393 #endif /* EAP_AKA_PRIME */
394                 sha1_vector(1, &addr, &len, hash);
395
396         if (os_memcmp(hash, checkcode, hash_len) != 0) {
397                 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
398                 return -1;
399         }
400
401         return 0;
402 }
403
404
405 static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
406                                             int err)
407 {
408         struct eap_sim_msg *msg;
409
410         eap_aka_state(data, FAILURE);
411         data->num_id_req = 0;
412         data->num_notification = 0;
413
414         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
415                                EAP_AKA_SUBTYPE_CLIENT_ERROR);
416         eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
417         return eap_sim_msg_finish(msg, NULL, NULL, 0);
418 }
419
420
421 static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
422                                                      u8 id)
423 {
424         struct eap_sim_msg *msg;
425
426         eap_aka_state(data, FAILURE);
427         data->num_id_req = 0;
428         data->num_notification = 0;
429
430         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
431                    "(id=%d)", id);
432         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
433                                EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
434         return eap_sim_msg_finish(msg, NULL, NULL, 0);
435 }
436
437
438 static struct wpabuf * eap_aka_synchronization_failure(
439         struct eap_aka_data *data, u8 id)
440 {
441         struct eap_sim_msg *msg;
442
443         data->num_id_req = 0;
444         data->num_notification = 0;
445
446         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
447                    "(id=%d)", id);
448         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
449                                EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
450         wpa_printf(MSG_DEBUG, "   AT_AUTS");
451         eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
452                              EAP_AKA_AUTS_LEN);
453         return eap_sim_msg_finish(msg, NULL, NULL, 0);
454 }
455
456
457 static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
458                                                  struct eap_aka_data *data,
459                                                  u8 id,
460                                                  enum eap_sim_id_req id_req)
461 {
462         const u8 *identity = NULL;
463         size_t identity_len = 0;
464         struct eap_sim_msg *msg;
465
466         data->reauth = 0;
467         if (id_req == ANY_ID && data->reauth_id) {
468                 identity = data->reauth_id;
469                 identity_len = data->reauth_id_len;
470                 data->reauth = 1;
471         } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
472                    data->pseudonym) {
473                 identity = data->pseudonym;
474                 identity_len = data->pseudonym_len;
475                 eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
476         } else if (id_req != NO_ID_REQ) {
477                 identity = eap_get_config_identity(sm, &identity_len);
478                 if (identity) {
479                         eap_aka_clear_identities(data, CLEAR_PSEUDONYM |
480                                                  CLEAR_REAUTH_ID);
481                 }
482         }
483         if (id_req != NO_ID_REQ)
484                 eap_aka_clear_identities(data, CLEAR_EAP_ID);
485
486         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
487         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
488                                EAP_AKA_SUBTYPE_IDENTITY);
489
490         if (identity) {
491                 wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
492                                   identity, identity_len);
493                 eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
494                                 identity, identity_len);
495         }
496
497         return eap_sim_msg_finish(msg, NULL, NULL, 0);
498 }
499
500
501 static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
502                                                   u8 id)
503 {
504         struct eap_sim_msg *msg;
505
506         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
507         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
508                                EAP_AKA_SUBTYPE_CHALLENGE);
509         wpa_printf(MSG_DEBUG, "   AT_RES");
510         eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
511                         data->res, data->res_len);
512         eap_aka_add_checkcode(data, msg);
513         if (data->use_result_ind) {
514                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
515                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
516         }
517         wpa_printf(MSG_DEBUG, "   AT_MAC");
518         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
519         return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0);
520 }
521
522
523 static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
524                                                u8 id, int counter_too_small,
525                                                const u8 *nonce_s)
526 {
527         struct eap_sim_msg *msg;
528         unsigned int counter;
529
530         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
531                    id);
532         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
533                                EAP_AKA_SUBTYPE_REAUTHENTICATION);
534         wpa_printf(MSG_DEBUG, "   AT_IV");
535         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
536         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
537
538         if (counter_too_small) {
539                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
540                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
541                 counter = data->counter_too_small;
542         } else
543                 counter = data->counter;
544
545         wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
546         eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
547
548         if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
549                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
550                            "AT_ENCR_DATA");
551                 eap_sim_msg_free(msg);
552                 return NULL;
553         }
554         eap_aka_add_checkcode(data, msg);
555         if (data->use_result_ind) {
556                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
557                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
558         }
559         wpa_printf(MSG_DEBUG, "   AT_MAC");
560         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
561         return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
562                                   EAP_SIM_NONCE_S_LEN);
563 }
564
565
566 static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
567                                                      u8 id, u16 notification)
568 {
569         struct eap_sim_msg *msg;
570         u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
571
572         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
573         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
574                                EAP_AKA_SUBTYPE_NOTIFICATION);
575         if (k_aut && data->reauth) {
576                 wpa_printf(MSG_DEBUG, "   AT_IV");
577                 wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
578                 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
579                                            EAP_SIM_AT_ENCR_DATA);
580                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
581                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
582                                 NULL, 0);
583                 if (eap_sim_msg_add_encr_end(msg, data->k_encr,
584                                              EAP_SIM_AT_PADDING)) {
585                         wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
586                                    "AT_ENCR_DATA");
587                         eap_sim_msg_free(msg);
588                         return NULL;
589                 }
590         }
591         if (k_aut) {
592                 wpa_printf(MSG_DEBUG, "   AT_MAC");
593                 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
594         }
595         return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
596 }
597
598
599 static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
600                                                 struct eap_aka_data *data,
601                                                 u8 id,
602                                                 const struct wpabuf *reqData,
603                                                 struct eap_sim_attrs *attr)
604 {
605         int id_error;
606         struct wpabuf *buf;
607
608         wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
609
610         id_error = 0;
611         switch (attr->id_req) {
612         case NO_ID_REQ:
613                 break;
614         case ANY_ID:
615                 if (data->num_id_req > 0)
616                         id_error++;
617                 data->num_id_req++;
618                 break;
619         case FULLAUTH_ID:
620                 if (data->num_id_req > 1)
621                         id_error++;
622                 data->num_id_req++;
623                 break;
624         case PERMANENT_ID:
625                 if (data->num_id_req > 2)
626                         id_error++;
627                 data->num_id_req++;
628                 break;
629         }
630         if (id_error) {
631                 wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
632                            "used within one authentication");
633                 return eap_aka_client_error(data, id,
634                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
635         }
636
637         buf = eap_aka_response_identity(sm, data, id, attr->id_req);
638
639         if (data->prev_id != id) {
640                 eap_aka_add_id_msg(data, reqData);
641                 eap_aka_add_id_msg(data, buf);
642                 data->prev_id = id;
643         }
644
645         return buf;
646 }
647
648
649 static int eap_aka_verify_mac(struct eap_aka_data *data,
650                               const struct wpabuf *req,
651                               const u8 *mac, const u8 *extra,
652                               size_t extra_len)
653 {
654         if (data->eap_method == EAP_TYPE_AKA_PRIME)
655                 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
656                                                  extra_len);
657         return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
658 }
659
660
661 #ifdef EAP_AKA_PRIME
662 static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
663                                                 u8 id, u16 kdf)
664 {
665         struct eap_sim_msg *msg;
666
667         data->kdf_negotiation = 1;
668         data->kdf = kdf;
669         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
670                    "select)", id);
671         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
672                                EAP_AKA_SUBTYPE_CHALLENGE);
673         wpa_printf(MSG_DEBUG, "   AT_KDF");
674         eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
675         return eap_sim_msg_finish(msg, NULL, NULL, 0);
676 }
677
678
679 static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
680                                              u8 id, struct eap_sim_attrs *attr)
681 {
682         size_t i;
683
684         for (i = 0; i < attr->kdf_count; i++) {
685                 if (attr->kdf[i] == EAP_AKA_PRIME_KDF)
686                         return eap_aka_prime_kdf_select(data, id,
687                                                         EAP_AKA_PRIME_KDF);
688         }
689
690         /* No matching KDF found - fail authentication as if AUTN had been
691          * incorrect */
692         return eap_aka_authentication_reject(data, id);
693 }
694
695
696 static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
697                                    struct eap_sim_attrs *attr)
698 {
699         size_t i, j;
700
701         if (attr->kdf_count == 0)
702                 return 0;
703
704         /* The only allowed (and required) duplication of a KDF is the addition
705          * of the selected KDF into the beginning of the list. */
706
707         if (data->kdf_negotiation) {
708                 if (attr->kdf[0] != data->kdf) {
709                         wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
710                                    "accept the selected KDF");
711                         return 0;
712                 }
713
714                 for (i = 1; i < attr->kdf_count; i++) {
715                         if (attr->kdf[i] == data->kdf)
716                                 break;
717                 }
718                 if (i == attr->kdf_count &&
719                     attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) {
720                         wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
721                                    "duplicate the selected KDF");
722                         return 0;
723                 }
724
725                 /* TODO: should check that the list is identical to the one
726                  * used in the previous Challenge message apart from the added
727                  * entry in the beginning. */
728         }
729
730         for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
731                 for (j = i + 1; j < attr->kdf_count; j++) {
732                         if (attr->kdf[i] == attr->kdf[j]) {
733                                 wpa_printf(MSG_WARNING, "EAP-AKA': The server "
734                                            "included a duplicated KDF");
735                                 return 0;
736                         }
737                 }
738         }
739
740         return 1;
741 }
742 #endif /* EAP_AKA_PRIME */
743
744
745 static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
746                                                  struct eap_aka_data *data,
747                                                  u8 id,
748                                                  const struct wpabuf *reqData,
749                                                  struct eap_sim_attrs *attr)
750 {
751         const u8 *identity;
752         size_t identity_len;
753         int res;
754         struct eap_sim_attrs eattr;
755
756         wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
757
758         if (attr->checkcode &&
759             eap_aka_verify_checkcode(data, attr->checkcode,
760                                      attr->checkcode_len)) {
761                 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
762                            "message");
763                 return eap_aka_client_error(data, id,
764                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
765         }
766
767 #ifdef EAP_AKA_PRIME
768         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
769                 if (!attr->kdf_input || attr->kdf_input_len == 0) {
770                         wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
771                                    "did not include non-empty AT_KDF_INPUT");
772                         /* Fail authentication as if AUTN had been incorrect */
773                         return eap_aka_authentication_reject(data, id);
774                 }
775                 os_free(data->network_name);
776                 data->network_name = os_malloc(attr->kdf_input_len);
777                 if (data->network_name == NULL) {
778                         wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
779                                    "storing Network Name");
780                         return eap_aka_authentication_reject(data, id);
781                 }
782                 os_memcpy(data->network_name, attr->kdf_input,
783                           attr->kdf_input_len);
784                 data->network_name_len = attr->kdf_input_len;
785                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
786                                   "(AT_KDF_INPUT)",
787                                   data->network_name, data->network_name_len);
788                 /* TODO: check Network Name per 3GPP.33.402 */
789
790                 if (!eap_aka_prime_kdf_valid(data, attr))
791                         return eap_aka_authentication_reject(data, id);
792
793                 if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
794                         return eap_aka_prime_kdf_neg(data, id, attr);
795
796                 data->kdf = EAP_AKA_PRIME_KDF;
797                 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
798         }
799
800         if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
801                 u16 flags = WPA_GET_BE16(attr->bidding);
802                 if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
803                     eap_allowed_method(sm, EAP_VENDOR_IETF,
804                                        EAP_TYPE_AKA_PRIME)) {
805                         wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
806                                    "AKA' to AKA detected");
807                         /* Fail authentication as if AUTN had been incorrect */
808                         return eap_aka_authentication_reject(data, id);
809                 }
810         }
811 #endif /* EAP_AKA_PRIME */
812
813         data->reauth = 0;
814         if (!attr->mac || !attr->rand || !attr->autn) {
815                 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
816                            "did not include%s%s%s",
817                            !attr->mac ? " AT_MAC" : "",
818                            !attr->rand ? " AT_RAND" : "",
819                            !attr->autn ? " AT_AUTN" : "");
820                 return eap_aka_client_error(data, id,
821                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
822         }
823         os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
824         os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);
825
826         res = eap_aka_umts_auth(sm, data);
827         if (res == -1) {
828                 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
829                            "failed (AUTN)");
830                 return eap_aka_authentication_reject(data, id);
831         } else if (res == -2) {
832                 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
833                            "failed (AUTN seq# -> AUTS)");
834                 return eap_aka_synchronization_failure(data, id);
835         } else if (res) {
836                 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
837                 return eap_aka_client_error(data, id,
838                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
839         }
840 #ifdef EAP_AKA_PRIME
841         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
842                 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
843                  * needed 6-octet SQN ^ AK for CK',IK' derivation */
844                 u16 amf = WPA_GET_BE16(data->autn + 6);
845                 if (!(amf & 0x8000)) {
846                         wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
847                                    "not set (AMF=0x%4x)", amf);
848                         return eap_aka_authentication_reject(data, id);
849                 }
850                 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
851                                                  data->autn,
852                                                  data->network_name,
853                                                  data->network_name_len);
854         }
855 #endif /* EAP_AKA_PRIME */
856         if (data->last_eap_identity) {
857                 identity = data->last_eap_identity;
858                 identity_len = data->last_eap_identity_len;
859         } else if (data->pseudonym) {
860                 identity = data->pseudonym;
861                 identity_len = data->pseudonym_len;
862         } else
863                 identity = eap_get_config_identity(sm, &identity_len);
864         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
865                           "derivation", identity, identity_len);
866         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
867                 eap_aka_prime_derive_keys(identity, identity_len, data->ik,
868                                           data->ck, data->k_encr, data->k_aut,
869                                           data->k_re, data->msk, data->emsk);
870         } else {
871                 eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
872                                   data->mk);
873                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
874                                     data->msk, data->emsk);
875         }
876         if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
877                 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
878                            "used invalid AT_MAC");
879                 return eap_aka_client_error(data, id,
880                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
881         }
882
883         /* Old reauthentication and pseudonym identities must not be used
884          * anymore. In other words, if no new identities are received, full
885          * authentication will be used on next reauthentication. */
886         eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
887                                  CLEAR_EAP_ID);
888
889         if (attr->encr_data) {
890                 u8 *decrypted;
891                 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
892                                                attr->encr_data_len, attr->iv,
893                                                &eattr, 0);
894                 if (decrypted == NULL) {
895                         return eap_aka_client_error(
896                                 data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
897                 }
898                 eap_aka_learn_ids(data, &eattr);
899                 os_free(decrypted);
900         }
901
902         if (data->result_ind && attr->result_ind)
903                 data->use_result_ind = 1;
904
905         if (data->state != FAILURE && data->state != RESULT_FAILURE) {
906                 eap_aka_state(data, data->use_result_ind ?
907                               RESULT_SUCCESS : SUCCESS);
908         }
909
910         data->num_id_req = 0;
911         data->num_notification = 0;
912         /* RFC 4187 specifies that counter is initialized to one after
913          * fullauth, but initializing it to zero makes it easier to implement
914          * reauth verification. */
915         data->counter = 0;
916         return eap_aka_response_challenge(data, id);
917 }
918
919
920 static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
921                                                struct eap_sim_attrs *attr)
922 {
923         struct eap_sim_attrs eattr;
924         u8 *decrypted;
925
926         if (attr->encr_data == NULL || attr->iv == NULL) {
927                 wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
928                            "reauth did not include encrypted data");
929                 return -1;
930         }
931
932         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
933                                        attr->encr_data_len, attr->iv, &eattr,
934                                        0);
935         if (decrypted == NULL) {
936                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
937                            "data from notification message");
938                 return -1;
939         }
940
941         if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
942                 wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
943                            "message does not match with counter in reauth "
944                            "message");
945                 os_free(decrypted);
946                 return -1;
947         }
948
949         os_free(decrypted);
950         return 0;
951 }
952
953
954 static int eap_aka_process_notification_auth(struct eap_aka_data *data,
955                                              const struct wpabuf *reqData,
956                                              struct eap_sim_attrs *attr)
957 {
958         if (attr->mac == NULL) {
959                 wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
960                            "Notification message");
961                 return -1;
962         }
963
964         if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
965                 wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
966                            "used invalid AT_MAC");
967                 return -1;
968         }
969
970         if (data->reauth &&
971             eap_aka_process_notification_reauth(data, attr)) {
972                 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
973                            "message after reauth");
974                 return -1;
975         }
976
977         return 0;
978 }
979
980
981 static struct wpabuf * eap_aka_process_notification(
982         struct eap_sm *sm, struct eap_aka_data *data, u8 id,
983         const struct wpabuf *reqData, struct eap_sim_attrs *attr)
984 {
985         wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
986         if (data->num_notification > 0) {
987                 wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
988                            "rounds (only one allowed)");
989                 return eap_aka_client_error(data, id,
990                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
991         }
992         data->num_notification++;
993         if (attr->notification == -1) {
994                 wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
995                            "Notification message");
996                 return eap_aka_client_error(data, id,
997                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
998         }
999
1000         if ((attr->notification & 0x4000) == 0 &&
1001             eap_aka_process_notification_auth(data, reqData, attr)) {
1002                 return eap_aka_client_error(data, id,
1003                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1004         }
1005
1006         eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
1007         if (attr->notification >= 0 && attr->notification < 32768) {
1008                 eap_aka_state(data, FAILURE);
1009         } else if (attr->notification == EAP_SIM_SUCCESS &&
1010                    data->state == RESULT_SUCCESS)
1011                 eap_aka_state(data, SUCCESS);
1012         return eap_aka_response_notification(data, id, attr->notification);
1013 }
1014
1015
1016 static struct wpabuf * eap_aka_process_reauthentication(
1017         struct eap_sm *sm, struct eap_aka_data *data, u8 id,
1018         const struct wpabuf *reqData, struct eap_sim_attrs *attr)
1019 {
1020         struct eap_sim_attrs eattr;
1021         u8 *decrypted;
1022
1023         wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
1024
1025         if (attr->checkcode &&
1026             eap_aka_verify_checkcode(data, attr->checkcode,
1027                                      attr->checkcode_len)) {
1028                 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
1029                            "message");
1030                 return eap_aka_client_error(data, id,
1031                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1032         }
1033
1034         if (data->reauth_id == NULL) {
1035                 wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
1036                            "reauthentication, but no reauth_id available");
1037                 return eap_aka_client_error(data, id,
1038                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1039         }
1040
1041         data->reauth = 1;
1042         if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
1043                 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
1044                            "did not have valid AT_MAC");
1045                 return eap_aka_client_error(data, id,
1046                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1047         }
1048
1049         if (attr->encr_data == NULL || attr->iv == NULL) {
1050                 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
1051                            "message did not include encrypted data");
1052                 return eap_aka_client_error(data, id,
1053                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1054         }
1055
1056         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
1057                                        attr->encr_data_len, attr->iv, &eattr,
1058                                        0);
1059         if (decrypted == NULL) {
1060                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
1061                            "data from reauthentication message");
1062                 return eap_aka_client_error(data, id,
1063                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1064         }
1065
1066         if (eattr.nonce_s == NULL || eattr.counter < 0) {
1067                 wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
1068                            !eattr.nonce_s ? " AT_NONCE_S" : "",
1069                            eattr.counter < 0 ? " AT_COUNTER" : "");
1070                 os_free(decrypted);
1071                 return eap_aka_client_error(data, id,
1072                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1073         }
1074
1075         if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
1076                 struct wpabuf *res;
1077                 wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
1078                            "(%d <= %d)", eattr.counter, data->counter);
1079                 data->counter_too_small = eattr.counter;
1080
1081                 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
1082                  * reauth_id must not be used to start a new reauthentication.
1083                  * However, since it was used in the last EAP-Response-Identity
1084                  * packet, it has to saved for the following fullauth to be
1085                  * used in MK derivation. */
1086                 os_free(data->last_eap_identity);
1087                 data->last_eap_identity = data->reauth_id;
1088                 data->last_eap_identity_len = data->reauth_id_len;
1089                 data->reauth_id = NULL;
1090                 data->reauth_id_len = 0;
1091
1092                 res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s);
1093                 os_free(decrypted);
1094
1095                 return res;
1096         }
1097         data->counter = eattr.counter;
1098
1099         os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
1100         wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
1101                     data->nonce_s, EAP_SIM_NONCE_S_LEN);
1102
1103         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
1104                 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
1105                                                  data->reauth_id,
1106                                                  data->reauth_id_len,
1107                                                  data->nonce_s,
1108                                                  data->msk, data->emsk);
1109         } else {
1110                 eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
1111                                            data->reauth_id_len,
1112                                            data->nonce_s, data->mk,
1113                                            data->msk, data->emsk);
1114         }
1115         eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
1116         eap_aka_learn_ids(data, &eattr);
1117
1118         if (data->result_ind && attr->result_ind)
1119                 data->use_result_ind = 1;
1120
1121         if (data->state != FAILURE && data->state != RESULT_FAILURE) {
1122                 eap_aka_state(data, data->use_result_ind ?
1123                               RESULT_SUCCESS : SUCCESS);
1124         }
1125
1126         data->num_id_req = 0;
1127         data->num_notification = 0;
1128         if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
1129                 wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
1130                            "fast reauths performed - force fullauth");
1131                 eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
1132         }
1133         os_free(decrypted);
1134         return eap_aka_response_reauth(data, id, 0, data->nonce_s);
1135 }
1136
1137
1138 static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
1139                                        struct eap_method_ret *ret,
1140                                        const struct wpabuf *reqData)
1141 {
1142         struct eap_aka_data *data = priv;
1143         const struct eap_hdr *req;
1144         u8 subtype, id;
1145         struct wpabuf *res;
1146         const u8 *pos;
1147         struct eap_sim_attrs attr;
1148         size_t len;
1149
1150         wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData);
1151         if (eap_get_config_identity(sm, &len) == NULL) {
1152                 wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
1153                 eap_sm_request_identity(sm);
1154                 ret->ignore = TRUE;
1155                 return NULL;
1156         }
1157
1158         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
1159                                &len);
1160         if (pos == NULL || len < 1) {
1161                 ret->ignore = TRUE;
1162                 return NULL;
1163         }
1164         req = wpabuf_head(reqData);
1165         id = req->identifier;
1166         len = be_to_host16(req->length);
1167
1168         ret->ignore = FALSE;
1169         ret->methodState = METHOD_MAY_CONT;
1170         ret->decision = DECISION_FAIL;
1171         ret->allowNotifications = TRUE;
1172
1173         subtype = *pos++;
1174         wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
1175         pos += 2; /* Reserved */
1176
1177         if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
1178                                data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
1179                                0)) {
1180                 res = eap_aka_client_error(data, id,
1181                                            EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1182                 goto done;
1183         }
1184
1185         switch (subtype) {
1186         case EAP_AKA_SUBTYPE_IDENTITY:
1187                 res = eap_aka_process_identity(sm, data, id, reqData, &attr);
1188                 break;
1189         case EAP_AKA_SUBTYPE_CHALLENGE:
1190                 res = eap_aka_process_challenge(sm, data, id, reqData, &attr);
1191                 break;
1192         case EAP_AKA_SUBTYPE_NOTIFICATION:
1193                 res = eap_aka_process_notification(sm, data, id, reqData,
1194                                                    &attr);
1195                 break;
1196         case EAP_AKA_SUBTYPE_REAUTHENTICATION:
1197                 res = eap_aka_process_reauthentication(sm, data, id, reqData,
1198                                                        &attr);
1199                 break;
1200         case EAP_AKA_SUBTYPE_CLIENT_ERROR:
1201                 wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
1202                 res = eap_aka_client_error(data, id,
1203                                            EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1204                 break;
1205         default:
1206                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
1207                 res = eap_aka_client_error(data, id,
1208                                            EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1209                 break;
1210         }
1211
1212 done:
1213         if (data->state == FAILURE) {
1214                 ret->decision = DECISION_FAIL;
1215                 ret->methodState = METHOD_DONE;
1216         } else if (data->state == SUCCESS) {
1217                 ret->decision = data->use_result_ind ?
1218                         DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
1219                 /*
1220                  * It is possible for the server to reply with AKA
1221                  * Notification, so we must allow the method to continue and
1222                  * not only accept EAP-Success at this point.
1223                  */
1224                 ret->methodState = data->use_result_ind ?
1225                         METHOD_DONE : METHOD_MAY_CONT;
1226         } else if (data->state == RESULT_FAILURE)
1227                 ret->methodState = METHOD_CONT;
1228         else if (data->state == RESULT_SUCCESS)
1229                 ret->methodState = METHOD_CONT;
1230
1231         if (ret->methodState == METHOD_DONE) {
1232                 ret->allowNotifications = FALSE;
1233         }
1234
1235         return res;
1236 }
1237
1238
1239 static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
1240 {
1241         struct eap_aka_data *data = priv;
1242         return data->pseudonym || data->reauth_id;
1243 }
1244
1245
1246 static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
1247 {
1248         struct eap_aka_data *data = priv;
1249         eap_aka_clear_identities(data, CLEAR_EAP_ID);
1250         data->prev_id = -1;
1251         wpabuf_free(data->id_msgs);
1252         data->id_msgs = NULL;
1253         data->use_result_ind = 0;
1254         data->kdf_negotiation = 0;
1255 }
1256
1257
1258 static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
1259 {
1260         struct eap_aka_data *data = priv;
1261         data->num_id_req = 0;
1262         data->num_notification = 0;
1263         eap_aka_state(data, CONTINUE);
1264         return priv;
1265 }
1266
1267
1268 static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
1269                                        size_t *len)
1270 {
1271         struct eap_aka_data *data = priv;
1272
1273         if (data->reauth_id) {
1274                 *len = data->reauth_id_len;
1275                 return data->reauth_id;
1276         }
1277
1278         if (data->pseudonym) {
1279                 *len = data->pseudonym_len;
1280                 return data->pseudonym;
1281         }
1282
1283         return NULL;
1284 }
1285
1286
1287 static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
1288 {
1289         struct eap_aka_data *data = priv;
1290         return data->state == SUCCESS;
1291 }
1292
1293
1294 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
1295 {
1296         struct eap_aka_data *data = priv;
1297         u8 *key;
1298
1299         if (data->state != SUCCESS)
1300                 return NULL;
1301
1302         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
1303         if (key == NULL)
1304                 return NULL;
1305
1306         *len = EAP_SIM_KEYING_DATA_LEN;
1307         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
1308
1309         return key;
1310 }
1311
1312
1313 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1314 {
1315         struct eap_aka_data *data = priv;
1316         u8 *key;
1317
1318         if (data->state != SUCCESS)
1319                 return NULL;
1320
1321         key = os_malloc(EAP_EMSK_LEN);
1322         if (key == NULL)
1323                 return NULL;
1324
1325         *len = EAP_EMSK_LEN;
1326         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
1327
1328         return key;
1329 }
1330
1331
1332 int eap_peer_aka_register(void)
1333 {
1334         struct eap_method *eap;
1335         int ret;
1336
1337         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1338                                     EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
1339         if (eap == NULL)
1340                 return -1;
1341
1342         eap->init = eap_aka_init;
1343         eap->deinit = eap_aka_deinit;
1344         eap->process = eap_aka_process;
1345         eap->isKeyAvailable = eap_aka_isKeyAvailable;
1346         eap->getKey = eap_aka_getKey;
1347         eap->has_reauth_data = eap_aka_has_reauth_data;
1348         eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
1349         eap->init_for_reauth = eap_aka_init_for_reauth;
1350         eap->get_identity = eap_aka_get_identity;
1351         eap->get_emsk = eap_aka_get_emsk;
1352
1353         ret = eap_peer_method_register(eap);
1354         if (ret)
1355                 eap_peer_method_free(eap);
1356         return ret;
1357 }
1358
1359
1360 #ifdef EAP_AKA_PRIME
1361 int eap_peer_aka_prime_register(void)
1362 {
1363         struct eap_method *eap;
1364         int ret;
1365
1366         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
1367                                     EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
1368                                     "AKA'");
1369         if (eap == NULL)
1370                 return -1;
1371
1372         eap->init = eap_aka_prime_init;
1373         eap->deinit = eap_aka_deinit;
1374         eap->process = eap_aka_process;
1375         eap->isKeyAvailable = eap_aka_isKeyAvailable;
1376         eap->getKey = eap_aka_getKey;
1377         eap->has_reauth_data = eap_aka_has_reauth_data;
1378         eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
1379         eap->init_for_reauth = eap_aka_init_for_reauth;
1380         eap->get_identity = eap_aka_get_identity;
1381         eap->get_emsk = eap_aka_get_emsk;
1382
1383         ret = eap_peer_method_register(eap);
1384         if (ret)
1385                 eap_peer_method_free(eap);
1386
1387         return ret;
1388 }
1389 #endif /* EAP_AKA_PRIME */