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