~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to src/eap_server/eap_sim.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * hostapd / EAP-SIM (RFC 4186)
3
 
 * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License version 2 as
7
 
 * published by the Free Software Foundation.
8
 
 *
9
 
 * Alternatively, this software may be distributed under the terms of BSD
10
 
 * license.
11
 
 *
12
 
 * See README and COPYING for more details.
13
 
 */
14
 
 
15
 
#include "includes.h"
16
 
 
17
 
#include "common.h"
18
 
#include "eap_server/eap_i.h"
19
 
#include "eap_common/eap_sim_common.h"
20
 
#include "eap_server/eap_sim_db.h"
21
 
 
22
 
 
23
 
struct eap_sim_data {
24
 
        u8 mk[EAP_SIM_MK_LEN];
25
 
        u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
26
 
        u8 nonce_s[EAP_SIM_NONCE_S_LEN];
27
 
        u8 k_aut[EAP_SIM_K_AUT_LEN];
28
 
        u8 k_encr[EAP_SIM_K_ENCR_LEN];
29
 
        u8 msk[EAP_SIM_KEYING_DATA_LEN];
30
 
        u8 emsk[EAP_EMSK_LEN];
31
 
        u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
32
 
        u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
33
 
        u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
34
 
        int num_chal;
35
 
        enum { START, CHALLENGE, REAUTH, SUCCESS, FAILURE } state;
36
 
        char *next_pseudonym;
37
 
        char *next_reauth_id;
38
 
        u16 counter;
39
 
        struct eap_sim_reauth *reauth;
40
 
};
41
 
 
42
 
 
43
 
static const char * eap_sim_state_txt(int state)
44
 
{
45
 
        switch (state) {
46
 
        case START:
47
 
                return "START";
48
 
        case CHALLENGE:
49
 
                return "CHALLENGE";
50
 
        case REAUTH:
51
 
                return "REAUTH";
52
 
        case SUCCESS:
53
 
                return "SUCCESS";
54
 
        case FAILURE:
55
 
                return "FAILURE";
56
 
        default:
57
 
                return "Unknown?!";
58
 
        }
59
 
}
60
 
 
61
 
 
62
 
static void eap_sim_state(struct eap_sim_data *data, int state)
63
 
{
64
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
65
 
                   eap_sim_state_txt(data->state),
66
 
                   eap_sim_state_txt(state));
67
 
        data->state = state;
68
 
}
69
 
 
70
 
 
71
 
static void * eap_sim_init(struct eap_sm *sm)
72
 
{
73
 
        struct eap_sim_data *data;
74
 
 
75
 
        if (sm->eap_sim_db_priv == NULL) {
76
 
                wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
77
 
                return NULL;
78
 
        }
79
 
 
80
 
        data = os_zalloc(sizeof(*data));
81
 
        if (data == NULL)
82
 
                return NULL;
83
 
        data->state = START;
84
 
 
85
 
        return data;
86
 
}
87
 
 
88
 
 
89
 
static void eap_sim_reset(struct eap_sm *sm, void *priv)
90
 
{
91
 
        struct eap_sim_data *data = priv;
92
 
        free(data->next_pseudonym);
93
 
        free(data->next_reauth_id);
94
 
        free(data);
95
 
}
96
 
 
97
 
 
98
 
static u8 * eap_sim_build_start(struct eap_sm *sm, struct eap_sim_data *data,
99
 
                                int id, size_t *reqDataLen)
100
 
{
101
 
        struct eap_sim_msg *msg;
102
 
        u8 ver[2];
103
 
 
104
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
105
 
        msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
106
 
                               EAP_SIM_SUBTYPE_START);
107
 
        if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
108
 
                                      sm->identity_len)) {
109
 
                wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
110
 
                eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
111
 
        }
112
 
        wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
113
 
        ver[0] = 0;
114
 
        ver[1] = EAP_SIM_VERSION;
115
 
        eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
116
 
                        ver, sizeof(ver));
117
 
        return eap_sim_msg_finish(msg, reqDataLen, NULL, NULL, 0);
118
 
}
119
 
 
120
 
 
121
 
static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
122
 
                              struct eap_sim_msg *msg, u16 counter,
123
 
                              const u8 *nonce_s)
124
 
{
125
 
        free(data->next_pseudonym);
126
 
        data->next_pseudonym =
127
 
                eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
128
 
        free(data->next_reauth_id);
129
 
        if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
130
 
                data->next_reauth_id =
131
 
                        eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0);
132
 
        } else {
133
 
                wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
134
 
                           "count exceeded - force full authentication");
135
 
                data->next_reauth_id = NULL;
136
 
        }
137
 
 
138
 
        if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
139
 
            counter == 0 && nonce_s == NULL)
140
 
                return 0;
141
 
 
142
 
        wpa_printf(MSG_DEBUG, "   AT_IV");
143
 
        wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
144
 
        eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
145
 
 
146
 
        if (counter > 0) {
147
 
                wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
148
 
                eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
149
 
        }
150
 
 
151
 
        if (nonce_s) {
152
 
                wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
153
 
                eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
154
 
                                EAP_SIM_NONCE_S_LEN);
155
 
        }
156
 
 
157
 
        if (data->next_pseudonym) {
158
 
                wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
159
 
                           data->next_pseudonym);
160
 
                eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
161
 
                                strlen(data->next_pseudonym),
162
 
                                (u8 *) data->next_pseudonym,
163
 
                                strlen(data->next_pseudonym));
164
 
        }
165
 
 
166
 
        if (data->next_reauth_id) {
167
 
                wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
168
 
                           data->next_reauth_id);
169
 
                eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
170
 
                                strlen(data->next_reauth_id),
171
 
                                (u8 *) data->next_reauth_id,
172
 
                                strlen(data->next_reauth_id));
173
 
        }
174
 
 
175
 
        if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
176
 
                wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
177
 
                           "AT_ENCR_DATA");
178
 
                return -1;
179
 
        }
180
 
 
181
 
        return 0;
182
 
}
183
 
 
184
 
 
185
 
static u8 * eap_sim_build_challenge(struct eap_sm *sm,
186
 
                                    struct eap_sim_data *data,
187
 
                                    int id, size_t *reqDataLen)
188
 
{
189
 
        struct eap_sim_msg *msg;
190
 
 
191
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
192
 
        msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
193
 
                               EAP_SIM_SUBTYPE_CHALLENGE);
194
 
        wpa_printf(MSG_DEBUG, "   AT_RAND");
195
 
        eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
196
 
                        data->num_chal * GSM_RAND_LEN);
197
 
 
198
 
        if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
199
 
                eap_sim_msg_free(msg);
200
 
                return NULL;
201
 
        }
202
 
 
203
 
        wpa_printf(MSG_DEBUG, "   AT_MAC");
204
 
        eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
205
 
        return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, data->nonce_mt,
206
 
                                  EAP_SIM_NONCE_MT_LEN);
207
 
}
208
 
 
209
 
 
210
 
static u8 * eap_sim_build_reauth(struct eap_sm *sm,
211
 
                                 struct eap_sim_data *data,
212
 
                                 int id, size_t *reqDataLen)
213
 
{
214
 
        struct eap_sim_msg *msg;
215
 
 
216
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
217
 
 
218
 
        if (hostapd_get_rand(data->nonce_s, EAP_SIM_NONCE_S_LEN))
219
 
                return NULL;
220
 
        wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
221
 
                        data->nonce_s, EAP_SIM_NONCE_S_LEN);
222
 
 
223
 
        eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
224
 
                            data->emsk);
225
 
        eap_sim_derive_keys_reauth(data->counter, sm->identity,
226
 
                                   sm->identity_len, data->nonce_s, data->mk,
227
 
                                   data->msk, data->emsk);
228
 
 
229
 
        msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
230
 
                               EAP_SIM_SUBTYPE_REAUTHENTICATION);
231
 
 
232
 
        if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
233
 
                eap_sim_msg_free(msg);
234
 
                return NULL;
235
 
        }
236
 
 
237
 
        wpa_printf(MSG_DEBUG, "   AT_MAC");
238
 
        eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
239
 
        return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, NULL, 0);
240
 
}
241
 
 
242
 
 
243
 
static u8 * eap_sim_buildReq(struct eap_sm *sm, void *priv, int id,
244
 
                             size_t *reqDataLen)
245
 
{
246
 
        struct eap_sim_data *data = priv;
247
 
 
248
 
        switch (data->state) {
249
 
        case START:
250
 
                return eap_sim_build_start(sm, data, id, reqDataLen);
251
 
        case CHALLENGE:
252
 
                return eap_sim_build_challenge(sm, data, id, reqDataLen);
253
 
        case REAUTH:
254
 
                return eap_sim_build_reauth(sm, data, id, reqDataLen);
255
 
        default:
256
 
                wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
257
 
                           "buildReq", data->state);
258
 
                break;
259
 
        }
260
 
        return NULL;
261
 
}
262
 
 
263
 
 
264
 
static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
265
 
                             u8 *respData, size_t respDataLen)
266
 
{
267
 
        struct eap_sim_data *data = priv;
268
 
        struct eap_hdr *resp;
269
 
        u8 *pos, subtype;
270
 
 
271
 
        resp = (struct eap_hdr *) respData;
272
 
        pos = (u8 *) (resp + 1);
273
 
        if (respDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_SIM ||
274
 
            (be_to_host16(resp->length)) > respDataLen) {
275
 
                wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
276
 
                return TRUE;
277
 
        }
278
 
        subtype = pos[1];
279
 
 
280
 
        if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
281
 
                return FALSE;
282
 
 
283
 
        switch (data->state) {
284
 
        case START:
285
 
                if (subtype != EAP_SIM_SUBTYPE_START) {
286
 
                        wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
287
 
                                   "subtype %d", subtype);
288
 
                        return TRUE;
289
 
                }
290
 
                break;
291
 
        case CHALLENGE:
292
 
                if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
293
 
                        wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
294
 
                                   "subtype %d", subtype);
295
 
                        return TRUE;
296
 
                }
297
 
                break;
298
 
        case REAUTH:
299
 
                if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
300
 
                        wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
301
 
                                   "subtype %d", subtype);
302
 
                        return TRUE;
303
 
                }
304
 
                break;
305
 
        default:
306
 
                wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
307
 
                           "processing a response", data->state);
308
 
                return TRUE;
309
 
        }
310
 
 
311
 
        return FALSE;
312
 
}
313
 
 
314
 
 
315
 
static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
316
 
{
317
 
        return version == EAP_SIM_VERSION;
318
 
}
319
 
 
320
 
 
321
 
static void eap_sim_process_start(struct eap_sm *sm,
322
 
                                  struct eap_sim_data *data,
323
 
                                  u8 *respData, size_t respDataLen,
324
 
                                  struct eap_sim_attrs *attr)
325
 
{
326
 
        const u8 *identity;
327
 
        size_t identity_len;
328
 
        u8 ver_list[2];
329
 
 
330
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
331
 
 
332
 
        if (attr->nonce_mt == NULL || attr->selected_version < 0) {
333
 
                wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
334
 
                           "required attributes");
335
 
                eap_sim_state(data, FAILURE);
336
 
                return;
337
 
        }
338
 
 
339
 
        if (!eap_sim_supported_ver(data, attr->selected_version)) {
340
 
                wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
341
 
                           "version %d", attr->selected_version);
342
 
                eap_sim_state(data, FAILURE);
343
 
                return;
344
 
        }
345
 
 
346
 
        if (attr->identity) {
347
 
                free(sm->identity);
348
 
                sm->identity = malloc(attr->identity_len);
349
 
                if (sm->identity) {
350
 
                        memcpy(sm->identity, attr->identity,
351
 
                               attr->identity_len);
352
 
                        sm->identity_len = attr->identity_len;
353
 
                }
354
 
        }
355
 
 
356
 
        identity = NULL;
357
 
        identity_len = 0;
358
 
 
359
 
        if (sm->identity && sm->identity_len > 0 &&
360
 
            sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) {
361
 
                identity = sm->identity;
362
 
                identity_len = sm->identity_len;
363
 
        } else {
364
 
                identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
365
 
                                                    sm->identity,
366
 
                                                    sm->identity_len,
367
 
                                                    &identity_len);
368
 
                if (identity == NULL) {
369
 
                        data->reauth = eap_sim_db_get_reauth_entry(
370
 
                                sm->eap_sim_db_priv, sm->identity,
371
 
                                sm->identity_len);
372
 
                        if (data->reauth) {
373
 
                                wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast "
374
 
                                           "re-authentication");
375
 
                                identity = data->reauth->identity;
376
 
                                identity_len = data->reauth->identity_len;
377
 
                                data->counter = data->reauth->counter;
378
 
                                memcpy(data->mk, data->reauth->mk,
379
 
                                       EAP_SIM_MK_LEN);
380
 
                        }
381
 
                }
382
 
        }
383
 
 
384
 
        if (identity == NULL) {
385
 
                wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
386
 
                           " user name");
387
 
                eap_sim_state(data, FAILURE);
388
 
                return;
389
 
        }
390
 
 
391
 
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
392
 
                          identity, identity_len);
393
 
 
394
 
        if (data->reauth) {
395
 
                eap_sim_state(data, REAUTH);
396
 
                return;
397
 
        }
398
 
 
399
 
        data->counter = 0; /* reset re-auth counter since this is full auth */
400
 
        data->reauth = NULL;
401
 
 
402
 
        data->num_chal = eap_sim_db_get_gsm_triplets(
403
 
                sm->eap_sim_db_priv, identity, identity_len,
404
 
                EAP_SIM_MAX_CHAL,
405
 
                (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
406
 
        if (data->num_chal == EAP_SIM_DB_PENDING) {
407
 
                wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
408
 
                           "not yet available - pending request");
409
 
                sm->method_pending = METHOD_PENDING_WAIT;
410
 
                return;
411
 
        }
412
 
        if (data->num_chal < 2) {
413
 
                wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
414
 
                           "authentication triplets for the peer");
415
 
                eap_sim_state(data, FAILURE);
416
 
                return;
417
 
        }
418
 
 
419
 
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
420
 
                          sm->identity, sm->identity_len);
421
 
 
422
 
        memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
423
 
        WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
424
 
        eap_sim_derive_mk(sm->identity, sm->identity_len, attr->nonce_mt,
425
 
                          attr->selected_version, ver_list, sizeof(ver_list),
426
 
                          data->num_chal, (const u8 *) data->kc, data->mk);
427
 
        eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
428
 
                            data->emsk);
429
 
 
430
 
        eap_sim_state(data, CHALLENGE);
431
 
}
432
 
 
433
 
 
434
 
static void eap_sim_process_challenge(struct eap_sm *sm,
435
 
                                      struct eap_sim_data *data,
436
 
                                      u8 *respData, size_t respDataLen,
437
 
                                      struct eap_sim_attrs *attr)
438
 
{
439
 
        const u8 *identity;
440
 
        size_t identity_len;
441
 
 
442
 
        if (attr->mac == NULL ||
443
 
            eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
444
 
                               (u8 *) data->sres,
445
 
                               data->num_chal * EAP_SIM_SRES_LEN)) {
446
 
                wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
447
 
                           "did not include valid AT_MAC");
448
 
                eap_sim_state(data, FAILURE);
449
 
                return;
450
 
        }
451
 
 
452
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
453
 
                   "correct AT_MAC");
454
 
        eap_sim_state(data, SUCCESS);
455
 
 
456
 
        identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
457
 
                                            sm->identity_len, &identity_len);
458
 
        if (identity == NULL) {
459
 
                identity = sm->identity;
460
 
                identity_len = sm->identity_len;
461
 
        }
462
 
 
463
 
        if (data->next_pseudonym) {
464
 
                eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
465
 
                                         identity_len,
466
 
                                         data->next_pseudonym);
467
 
                data->next_pseudonym = NULL;
468
 
        }
469
 
        if (data->next_reauth_id) {
470
 
                eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
471
 
                                      identity_len,
472
 
                                      data->next_reauth_id, data->counter + 1,
473
 
                                      data->mk);
474
 
                data->next_reauth_id = NULL;
475
 
        }
476
 
}
477
 
 
478
 
 
479
 
static void eap_sim_process_reauth(struct eap_sm *sm,
480
 
                                   struct eap_sim_data *data,
481
 
                                   u8 *respData, size_t respDataLen,
482
 
                                   struct eap_sim_attrs *attr)
483
 
{
484
 
        struct eap_sim_attrs eattr;
485
 
        u8 *decrypted = NULL;
486
 
        const u8 *identity, *id2;
487
 
        size_t identity_len, id2_len;
488
 
 
489
 
        if (attr->mac == NULL ||
490
 
            eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
491
 
                               data->nonce_s, EAP_SIM_NONCE_S_LEN)) {
492
 
                wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
493
 
                           "did not include valid AT_MAC");
494
 
                goto fail;
495
 
        }
496
 
 
497
 
        if (attr->encr_data == NULL || attr->iv == NULL) {
498
 
                wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
499
 
                           "message did not include encrypted data");
500
 
                goto fail;
501
 
        }
502
 
 
503
 
        decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
504
 
                                       attr->encr_data_len, attr->iv, &eattr,
505
 
                                       0);
506
 
        if (decrypted == NULL) {
507
 
                wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
508
 
                           "data from reauthentication message");
509
 
                goto fail;
510
 
        }
511
 
 
512
 
        if (eattr.counter != data->counter) {
513
 
                wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
514
 
                           "used incorrect counter %u, expected %u",
515
 
                           eattr.counter, data->counter);
516
 
                goto fail;
517
 
        }
518
 
        free(decrypted);
519
 
        decrypted = NULL;
520
 
 
521
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
522
 
                   "the correct AT_MAC");
523
 
        eap_sim_state(data, SUCCESS);
524
 
 
525
 
        if (data->reauth) {
526
 
                identity = data->reauth->identity;
527
 
                identity_len = data->reauth->identity_len;
528
 
        } else {
529
 
                identity = sm->identity;
530
 
                identity_len = sm->identity_len;
531
 
        }
532
 
 
533
 
        id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
534
 
                                       identity_len, &id2_len);
535
 
        if (id2) {
536
 
                identity = id2;
537
 
                identity_len = id2_len;
538
 
        }
539
 
 
540
 
        if (data->next_pseudonym) {
541
 
                eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
542
 
                                         identity_len, data->next_pseudonym);
543
 
                data->next_pseudonym = NULL;
544
 
        }
545
 
        if (data->next_reauth_id) {
546
 
                eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
547
 
                                      identity_len, data->next_reauth_id,
548
 
                                      data->counter + 1, data->mk);
549
 
                data->next_reauth_id = NULL;
550
 
        } else {
551
 
                eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
552
 
                data->reauth = NULL;
553
 
        }
554
 
 
555
 
        return;
556
 
 
557
 
fail:
558
 
        eap_sim_state(data, FAILURE);
559
 
        eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
560
 
        data->reauth = NULL;
561
 
        free(decrypted);
562
 
}
563
 
 
564
 
 
565
 
static void eap_sim_process_client_error(struct eap_sm *sm,
566
 
                                         struct eap_sim_data *data,
567
 
                                         u8 *respData, size_t respDataLen,
568
 
                                         struct eap_sim_attrs *attr)
569
 
{
570
 
        wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
571
 
                   attr->client_error_code);
572
 
        eap_sim_state(data, FAILURE);
573
 
}
574
 
 
575
 
 
576
 
static void eap_sim_process(struct eap_sm *sm, void *priv,
577
 
                            u8 *respData, size_t respDataLen)
578
 
{
579
 
        struct eap_sim_data *data = priv;
580
 
        struct eap_hdr *resp;
581
 
        u8 *pos, subtype;
582
 
        size_t len;
583
 
        struct eap_sim_attrs attr;
584
 
 
585
 
        resp = (struct eap_hdr *) respData;
586
 
        pos = (u8 *) (resp + 1);
587
 
        subtype = pos[1];
588
 
        len = be_to_host16(resp->length);
589
 
        pos += 4;
590
 
 
591
 
        if (eap_sim_parse_attr(pos, respData + len, &attr, 0, 0)) {
592
 
                wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
593
 
                eap_sim_state(data, FAILURE);
594
 
                return;
595
 
        }
596
 
 
597
 
        if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
598
 
                eap_sim_process_client_error(sm, data, respData, len, &attr);
599
 
                return;
600
 
        }
601
 
 
602
 
        switch (data->state) {
603
 
        case START:
604
 
                eap_sim_process_start(sm, data, respData, len, &attr);
605
 
                break;
606
 
        case CHALLENGE:
607
 
                eap_sim_process_challenge(sm, data, respData, len, &attr);
608
 
                break;
609
 
        case REAUTH:
610
 
                eap_sim_process_reauth(sm, data, respData, len, &attr);
611
 
                break;
612
 
        default:
613
 
                wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
614
 
                           "process", data->state);
615
 
                break;
616
 
        }
617
 
}
618
 
 
619
 
 
620
 
static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
621
 
{
622
 
        struct eap_sim_data *data = priv;
623
 
        return data->state == SUCCESS || data->state == FAILURE;
624
 
}
625
 
 
626
 
 
627
 
static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
628
 
{
629
 
        struct eap_sim_data *data = priv;
630
 
        u8 *key;
631
 
 
632
 
        if (data->state != SUCCESS)
633
 
                return NULL;
634
 
 
635
 
        key = malloc(EAP_SIM_KEYING_DATA_LEN);
636
 
        if (key == NULL)
637
 
                return NULL;
638
 
        memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
639
 
        *len = EAP_SIM_KEYING_DATA_LEN;
640
 
        return key;
641
 
}
642
 
 
643
 
 
644
 
static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
645
 
{
646
 
        struct eap_sim_data *data = priv;
647
 
        u8 *key;
648
 
 
649
 
        if (data->state != SUCCESS)
650
 
                return NULL;
651
 
 
652
 
        key = malloc(EAP_EMSK_LEN);
653
 
        if (key == NULL)
654
 
                return NULL;
655
 
        memcpy(key, data->emsk, EAP_EMSK_LEN);
656
 
        *len = EAP_EMSK_LEN;
657
 
        return key;
658
 
}
659
 
 
660
 
 
661
 
static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
662
 
{
663
 
        struct eap_sim_data *data = priv;
664
 
        return data->state == SUCCESS;
665
 
}
666
 
 
667
 
 
668
 
int eap_server_sim_register(void)
669
 
{
670
 
        struct eap_method *eap;
671
 
        int ret;
672
 
 
673
 
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
674
 
                                      EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
675
 
        if (eap == NULL)
676
 
                return -1;
677
 
 
678
 
        eap->init = eap_sim_init;
679
 
        eap->reset = eap_sim_reset;
680
 
        eap->buildReq = eap_sim_buildReq;
681
 
        eap->check = eap_sim_check;
682
 
        eap->process = eap_sim_process;
683
 
        eap->isDone = eap_sim_isDone;
684
 
        eap->getKey = eap_sim_getKey;
685
 
        eap->isSuccess = eap_sim_isSuccess;
686
 
        eap->get_emsk = eap_sim_get_emsk;
687
 
 
688
 
        ret = eap_server_method_register(eap);
689
 
        if (ret)
690
 
                eap_server_method_free(eap);
691
 
        return ret;
692
 
}