~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to src/eap_server/eap_sim_db.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * hostapd / EAP-SIM database/authenticator gateway
 
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
 * This is an example implementation of the EAP-SIM/AKA database/authentication
 
15
 * gateway interface that is using an external program as an SS7 gateway to
 
16
 * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
 
17
 * implementation of such a gateway program. This eap_sim_db.c takes care of
 
18
 * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
 
19
 * gateway implementations for HLR/AuC access. Alternatively, it can also be
 
20
 * completely replaced if the in-memory database of pseudonyms/re-auth
 
21
 * identities is not suitable for some cases.
 
22
 */
 
23
 
 
24
#include "includes.h"
 
25
#include <sys/un.h>
 
26
 
 
27
#include "common.h"
 
28
#include "eap_common/eap_sim_common.h"
 
29
#include "eap_server/eap_sim_db.h"
 
30
#include "eloop.h"
 
31
 
 
32
struct eap_sim_pseudonym {
 
33
        struct eap_sim_pseudonym *next;
 
34
        u8 *identity;
 
35
        size_t identity_len;
 
36
        char *pseudonym;
 
37
};
 
38
 
 
39
struct eap_sim_db_pending {
 
40
        struct eap_sim_db_pending *next;
 
41
        u8 imsi[20];
 
42
        size_t imsi_len;
 
43
        enum { PENDING, SUCCESS, FAILURE } state;
 
44
        void *cb_session_ctx;
 
45
        struct os_time timestamp;
 
46
        int aka;
 
47
        union {
 
48
                struct {
 
49
                        u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
 
50
                        u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
 
51
                        u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
 
52
                        int num_chal;
 
53
                } sim;
 
54
                struct {
 
55
                        u8 rand[EAP_AKA_RAND_LEN];
 
56
                        u8 autn[EAP_AKA_AUTN_LEN];
 
57
                        u8 ik[EAP_AKA_IK_LEN];
 
58
                        u8 ck[EAP_AKA_CK_LEN];
 
59
                        u8 res[EAP_AKA_RES_MAX_LEN];
 
60
                        size_t res_len;
 
61
                } aka;
 
62
        } u;
 
63
};
 
64
 
 
65
struct eap_sim_db_data {
 
66
        int sock;
 
67
        char *fname;
 
68
        char *local_sock;
 
69
        void (*get_complete_cb)(void *ctx, void *session_ctx);
 
70
        void *ctx;
 
71
        struct eap_sim_pseudonym *pseudonyms;
 
72
        struct eap_sim_reauth *reauths;
 
73
        struct eap_sim_db_pending *pending;
 
74
};
 
75
 
 
76
 
 
77
static struct eap_sim_db_pending *
 
78
eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
 
79
                       size_t imsi_len, int aka)
 
80
{
 
81
        struct eap_sim_db_pending *entry, *prev = NULL;
 
82
 
 
83
        entry = data->pending;
 
84
        while (entry) {
 
85
                if (entry->aka == aka && entry->imsi_len == imsi_len &&
 
86
                    os_memcmp(entry->imsi, imsi, imsi_len) == 0) {
 
87
                        if (prev)
 
88
                                prev->next = entry->next;
 
89
                        else
 
90
                                data->pending = entry->next;
 
91
                        break;
 
92
                }
 
93
                prev = entry;
 
94
                entry = entry->next;
 
95
        }
 
96
        return entry;
 
97
}
 
98
 
 
99
 
 
100
static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
 
101
                                   struct eap_sim_db_pending *entry)
 
102
{
 
103
        entry->next = data->pending;
 
104
        data->pending = entry;
 
105
}
 
106
 
 
107
 
 
108
static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
 
109
                                     const char *imsi, char *buf)
 
110
{
 
111
        char *start, *end, *pos;
 
112
        struct eap_sim_db_pending *entry;
 
113
        int num_chal;
 
114
 
 
115
        /*
 
116
         * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
 
117
         * SIM-RESP-AUTH <IMSI> FAILURE
 
118
         * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
 
119
         */
 
120
 
 
121
        entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0);
 
122
        if (entry == NULL) {
 
123
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
 
124
                           "received message found");
 
125
                return;
 
126
        }
 
127
 
 
128
        start = buf;
 
129
        if (os_strncmp(start, "FAILURE", 7) == 0) {
 
130
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
 
131
                           "failure");
 
132
                entry->state = FAILURE;
 
133
                eap_sim_db_add_pending(data, entry);
 
134
                data->get_complete_cb(data->ctx, entry->cb_session_ctx);
 
135
                return;
 
136
        }
 
137
 
 
138
        num_chal = 0;
 
139
        while (num_chal < EAP_SIM_MAX_CHAL) {
 
140
                end = os_strchr(start, ' ');
 
141
                if (end)
 
142
                        *end = '\0';
 
143
 
 
144
                pos = os_strchr(start, ':');
 
145
                if (pos == NULL)
 
146
                        goto parse_fail;
 
147
                *pos = '\0';
 
148
                if (hexstr2bin(start, entry->u.sim.kc[num_chal],
 
149
                               EAP_SIM_KC_LEN))
 
150
                        goto parse_fail;
 
151
 
 
152
                start = pos + 1;
 
153
                pos = os_strchr(start, ':');
 
154
                if (pos == NULL)
 
155
                        goto parse_fail;
 
156
                *pos = '\0';
 
157
                if (hexstr2bin(start, entry->u.sim.sres[num_chal],
 
158
                               EAP_SIM_SRES_LEN))
 
159
                        goto parse_fail;
 
160
 
 
161
                start = pos + 1;
 
162
                if (hexstr2bin(start, entry->u.sim.rand[num_chal],
 
163
                               GSM_RAND_LEN))
 
164
                        goto parse_fail;
 
165
 
 
166
                num_chal++;
 
167
                if (end == NULL)
 
168
                        break;
 
169
                else
 
170
                        start = end + 1;
 
171
        }
 
172
        entry->u.sim.num_chal = num_chal;
 
173
 
 
174
        entry->state = SUCCESS;
 
175
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
 
176
                   "successfully - callback");
 
177
        eap_sim_db_add_pending(data, entry);
 
178
        data->get_complete_cb(data->ctx, entry->cb_session_ctx);
 
179
        return;
 
180
 
 
181
parse_fail:
 
182
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
 
183
        os_free(entry);
 
184
}
 
185
 
 
186
 
 
187
static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
 
188
                                     const char *imsi, char *buf)
 
189
{
 
190
        char *start, *end;
 
191
        struct eap_sim_db_pending *entry;
 
192
 
 
193
        /*
 
194
         * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
 
195
         * AKA-RESP-AUTH <IMSI> FAILURE
 
196
         * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
 
197
         */
 
198
 
 
199
        entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1);
 
200
        if (entry == NULL) {
 
201
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
 
202
                           "received message found");
 
203
                return;
 
204
        }
 
205
 
 
206
        start = buf;
 
207
        if (os_strncmp(start, "FAILURE", 7) == 0) {
 
208
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
 
209
                           "failure");
 
210
                entry->state = FAILURE;
 
211
                eap_sim_db_add_pending(data, entry);
 
212
                data->get_complete_cb(data->ctx, entry->cb_session_ctx);
 
213
                return;
 
214
        }
 
215
 
 
216
        end = os_strchr(start, ' ');
 
217
        if (end == NULL)
 
218
                goto parse_fail;
 
219
        *end = '\0';
 
220
        if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
 
221
                goto parse_fail;
 
222
 
 
223
        start = end + 1;
 
224
        end = os_strchr(start, ' ');
 
225
        if (end == NULL)
 
226
                goto parse_fail;
 
227
        *end = '\0';
 
228
        if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
 
229
                goto parse_fail;
 
230
 
 
231
        start = end + 1;
 
232
        end = os_strchr(start, ' ');
 
233
        if (end == NULL)
 
234
                goto parse_fail;
 
235
        *end = '\0';
 
236
        if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
 
237
                goto parse_fail;
 
238
 
 
239
        start = end + 1;
 
240
        end = os_strchr(start, ' ');
 
241
        if (end == NULL)
 
242
                goto parse_fail;
 
243
        *end = '\0';
 
244
        if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
 
245
                goto parse_fail;
 
246
 
 
247
        start = end + 1;
 
248
        end = os_strchr(start, ' ');
 
249
        if (end)
 
250
                *end = '\0';
 
251
        else {
 
252
                end = start;
 
253
                while (*end)
 
254
                        end++;
 
255
        }
 
256
        entry->u.aka.res_len = (end - start) / 2;
 
257
        if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
 
258
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
 
259
                entry->u.aka.res_len = 0;
 
260
                goto parse_fail;
 
261
        }
 
262
        if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
 
263
                goto parse_fail;
 
264
 
 
265
        entry->state = SUCCESS;
 
266
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
 
267
                   "successfully - callback");
 
268
        eap_sim_db_add_pending(data, entry);
 
269
        data->get_complete_cb(data->ctx, entry->cb_session_ctx);
 
270
        return;
 
271
 
 
272
parse_fail:
 
273
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
 
274
        os_free(entry);
 
275
}
 
276
 
 
277
 
 
278
static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
 
279
{
 
280
        struct eap_sim_db_data *data = eloop_ctx;
 
281
        char buf[1000], *pos, *cmd, *imsi;
 
282
        int res;
 
283
 
 
284
        res = recv(sock, buf, sizeof(buf), 0);
 
285
        if (res < 0)
 
286
                return;
 
287
        wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
 
288
                              "external source", (u8 *) buf, res);
 
289
        if (res == 0)
 
290
                return;
 
291
        if (res >= (int) sizeof(buf))
 
292
                res = sizeof(buf) - 1;
 
293
        buf[res] = '\0';
 
294
 
 
295
        if (data->get_complete_cb == NULL) {
 
296
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
 
297
                           "registered");
 
298
                return;
 
299
        }
 
300
 
 
301
        /* <cmd> <IMSI> ... */
 
302
 
 
303
        cmd = buf;
 
304
        pos = os_strchr(cmd, ' ');
 
305
        if (pos == NULL)
 
306
                goto parse_fail;
 
307
        *pos = '\0';
 
308
        imsi = pos + 1;
 
309
        pos = os_strchr(imsi, ' ');
 
310
        if (pos == NULL)
 
311
                goto parse_fail;
 
312
        *pos = '\0';
 
313
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
 
314
                   cmd, imsi);
 
315
 
 
316
        if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
 
317
                eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
 
318
        else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
 
319
                eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
 
320
        else
 
321
                wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
 
322
                           "'%s'", cmd);
 
323
        return;
 
324
 
 
325
parse_fail:
 
326
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
 
327
}
 
328
 
 
329
 
 
330
static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
 
331
{
 
332
        struct sockaddr_un addr;
 
333
        static int counter = 0;
 
334
 
 
335
        if (os_strncmp(data->fname, "unix:", 5) != 0)
 
336
                return -1;
 
337
 
 
338
        data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
 
339
        if (data->sock < 0) {
 
340
                perror("socket(eap_sim_db)");
 
341
                return -1;
 
342
        }
 
343
 
 
344
        os_memset(&addr, 0, sizeof(addr));
 
345
        addr.sun_family = AF_UNIX;
 
346
        os_snprintf(addr.sun_path, sizeof(addr.sun_path),
 
347
                    "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
 
348
        data->local_sock = os_strdup(addr.sun_path);
 
349
        if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 
350
                perror("bind(eap_sim_db)");
 
351
                close(data->sock);
 
352
                data->sock = -1;
 
353
                return -1;
 
354
        }
 
355
 
 
356
        os_memset(&addr, 0, sizeof(addr));
 
357
        addr.sun_family = AF_UNIX;
 
358
        os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
 
359
        if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 
360
                perror("connect(eap_sim_db)");
 
361
                wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
 
362
                                  (u8 *) addr.sun_path,
 
363
                                  os_strlen(addr.sun_path));
 
364
                close(data->sock);
 
365
                data->sock = -1;
 
366
                return -1;
 
367
        }
 
368
 
 
369
        eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
 
370
 
 
371
        return 0;
 
372
}
 
373
 
 
374
 
 
375
static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
 
376
{
 
377
        if (data->sock >= 0) {
 
378
                eloop_unregister_read_sock(data->sock);
 
379
                close(data->sock);
 
380
                data->sock = -1;
 
381
        }
 
382
        if (data->local_sock) {
 
383
                unlink(data->local_sock);
 
384
                os_free(data->local_sock);
 
385
                data->local_sock = NULL;
 
386
        }
 
387
}
 
388
 
 
389
 
 
390
/**
 
391
 * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
 
392
 * @config: Configuration data (e.g., file name)
 
393
 * @get_complete_cb: Callback function for reporting availability of triplets
 
394
 * @ctx: Context pointer for get_complete_cb
 
395
 * Returns: Pointer to a private data structure or %NULL on failure
 
396
 */
 
397
void * eap_sim_db_init(const char *config,
 
398
                       void (*get_complete_cb)(void *ctx, void *session_ctx),
 
399
                       void *ctx)
 
400
{
 
401
        struct eap_sim_db_data *data;
 
402
 
 
403
        data = os_zalloc(sizeof(*data));
 
404
        if (data == NULL)
 
405
                return NULL;
 
406
 
 
407
        data->sock = -1;
 
408
        data->get_complete_cb = get_complete_cb;
 
409
        data->ctx = ctx;
 
410
        data->fname = os_strdup(config);
 
411
        if (data->fname == NULL)
 
412
                goto fail;
 
413
 
 
414
        if (os_strncmp(data->fname, "unix:", 5) == 0) {
 
415
                if (eap_sim_db_open_socket(data))
 
416
                        goto fail;
 
417
        }
 
418
 
 
419
        return data;
 
420
 
 
421
fail:
 
422
        eap_sim_db_close_socket(data);
 
423
        os_free(data->fname);
 
424
        os_free(data);
 
425
        return NULL;
 
426
}
 
427
 
 
428
 
 
429
static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
 
430
{
 
431
        os_free(p->identity);
 
432
        os_free(p->pseudonym);
 
433
        os_free(p);
 
434
}
 
435
 
 
436
 
 
437
static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
 
438
{
 
439
        os_free(r->identity);
 
440
        os_free(r->reauth_id);
 
441
        os_free(r);
 
442
}
 
443
 
 
444
 
 
445
/**
 
446
 * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
 
447
 * @priv: Private data pointer from eap_sim_db_init()
 
448
 */
 
449
void eap_sim_db_deinit(void *priv)
 
450
{
 
451
        struct eap_sim_db_data *data = priv;
 
452
        struct eap_sim_pseudonym *p, *prev;
 
453
        struct eap_sim_reauth *r, *prevr;
 
454
        struct eap_sim_db_pending *pending, *prev_pending;
 
455
 
 
456
        eap_sim_db_close_socket(data);
 
457
        os_free(data->fname);
 
458
 
 
459
        p = data->pseudonyms;
 
460
        while (p) {
 
461
                prev = p;
 
462
                p = p->next;
 
463
                eap_sim_db_free_pseudonym(prev);
 
464
        }
 
465
 
 
466
        r = data->reauths;
 
467
        while (r) {
 
468
                prevr = r;
 
469
                r = r->next;
 
470
                eap_sim_db_free_reauth(prevr);
 
471
        }
 
472
 
 
473
        pending = data->pending;
 
474
        while (pending) {
 
475
                prev_pending = pending;
 
476
                pending = pending->next;
 
477
                os_free(prev_pending);
 
478
        }
 
479
 
 
480
        os_free(data);
 
481
}
 
482
 
 
483
 
 
484
static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
 
485
                           size_t len)
 
486
{
 
487
        int _errno = 0;
 
488
 
 
489
        if (send(data->sock, msg, len, 0) < 0) {
 
490
                _errno = errno;
 
491
                perror("send[EAP-SIM DB UNIX]");
 
492
        }
 
493
 
 
494
        if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
 
495
            _errno == ECONNREFUSED) {
 
496
                /* Try to reconnect */
 
497
                eap_sim_db_close_socket(data);
 
498
                if (eap_sim_db_open_socket(data) < 0)
 
499
                        return -1;
 
500
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
 
501
                           "external server");
 
502
                if (send(data->sock, msg, len, 0) < 0) {
 
503
                        perror("send[EAP-SIM DB UNIX]");
 
504
                        return -1;
 
505
                }
 
506
        }
 
507
 
 
508
        return 0;
 
509
}
 
510
 
 
511
 
 
512
static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
 
513
{
 
514
        /* TODO: add limit for maximum length for pending list; remove latest
 
515
         * (i.e., last) entry from the list if the limit is reached; could also
 
516
         * use timeout to expire pending entries */
 
517
}
 
518
 
 
519
 
 
520
/**
 
521
 * eap_sim_db_get_gsm_triplets - Get GSM triplets
 
522
 * @priv: Private data pointer from eap_sim_db_init()
 
523
 * @identity: User name identity
 
524
 * @identity_len: Length of identity in bytes
 
525
 * @max_chal: Maximum number of triplets
 
526
 * @_rand: Buffer for RAND values
 
527
 * @kc: Buffer for Kc values
 
528
 * @sres: Buffer for SRES values
 
529
 * @cb_session_ctx: Session callback context for get_complete_cb()
 
530
 * Returns: Number of triplets received (has to be less than or equal to
 
531
 * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
 
532
 * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
 
533
 * callback function registered with eap_sim_db_init() will be called once the
 
534
 * results become available.
 
535
 *
 
536
 * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
 
537
 * ASCII format.
 
538
 *
 
539
 * When using an external server for GSM triplets, this function can always
 
540
 * start a request and return EAP_SIM_DB_PENDING immediately if authentication
 
541
 * triplets are not available. Once the triplets are received, callback
 
542
 * function registered with eap_sim_db_init() is called to notify EAP state
 
543
 * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
 
544
 * function will then be called again and the newly received triplets will then
 
545
 * be given to the caller.
 
546
 */
 
547
int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
 
548
                                size_t identity_len, int max_chal,
 
549
                                u8 *_rand, u8 *kc, u8 *sres,
 
550
                                void *cb_session_ctx)
 
551
{
 
552
        struct eap_sim_db_data *data = priv;
 
553
        struct eap_sim_db_pending *entry;
 
554
        int len, ret;
 
555
        size_t i;
 
556
        char msg[40];
 
557
 
 
558
        if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) {
 
559
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
 
560
                                  identity, identity_len);
 
561
                return EAP_SIM_DB_FAILURE;
 
562
        }
 
563
        identity++;
 
564
        identity_len--;
 
565
        for (i = 0; i < identity_len; i++) {
 
566
                if (identity[i] == '@') {
 
567
                        identity_len = i;
 
568
                        break;
 
569
                }
 
570
        }
 
571
        if (identity_len + 1 > sizeof(entry->imsi)) {
 
572
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
 
573
                                  identity, identity_len);
 
574
                return EAP_SIM_DB_FAILURE;
 
575
        }
 
576
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
 
577
                          identity, identity_len);
 
578
 
 
579
        entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
 
580
        if (entry) {
 
581
                int num_chal;
 
582
                if (entry->state == FAILURE) {
 
583
                        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
 
584
                                   "failure");
 
585
                        os_free(entry);
 
586
                        return EAP_SIM_DB_FAILURE;
 
587
                }
 
588
 
 
589
                if (entry->state == PENDING) {
 
590
                        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
 
591
                                   "still pending");
 
592
                        eap_sim_db_add_pending(data, entry);
 
593
                        return EAP_SIM_DB_PENDING;
 
594
                }
 
595
 
 
596
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
 
597
                           "%d challenges", entry->u.sim.num_chal);
 
598
                num_chal = entry->u.sim.num_chal;
 
599
                if (num_chal > max_chal)
 
600
                        num_chal = max_chal;
 
601
                os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
 
602
                os_memcpy(sres, entry->u.sim.sres,
 
603
                          num_chal * EAP_SIM_SRES_LEN);
 
604
                os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
 
605
                os_free(entry);
 
606
                return num_chal;
 
607
        }
 
608
 
 
609
        if (data->sock < 0) {
 
610
                if (eap_sim_db_open_socket(data) < 0)
 
611
                        return EAP_SIM_DB_FAILURE;
 
612
        }
 
613
 
 
614
        len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
 
615
        if (len < 0 || len + identity_len >= sizeof(msg))
 
616
                return EAP_SIM_DB_FAILURE;
 
617
        os_memcpy(msg + len, identity, identity_len);
 
618
        len += identity_len;
 
619
        ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
 
620
        if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
 
621
                return EAP_SIM_DB_FAILURE;
 
622
        len += ret;
 
623
 
 
624
        wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
 
625
                    "data for IMSI", identity, identity_len);
 
626
        if (eap_sim_db_send(data, msg, len) < 0)
 
627
                return EAP_SIM_DB_FAILURE;
 
628
 
 
629
        entry = os_zalloc(sizeof(*entry));
 
630
        if (entry == NULL)
 
631
                return EAP_SIM_DB_FAILURE;
 
632
 
 
633
        os_get_time(&entry->timestamp);
 
634
        os_memcpy(entry->imsi, identity, identity_len);
 
635
        entry->imsi_len = identity_len;
 
636
        entry->cb_session_ctx = cb_session_ctx;
 
637
        entry->state = PENDING;
 
638
        eap_sim_db_add_pending(data, entry);
 
639
        eap_sim_db_expire_pending(data);
 
640
 
 
641
        return EAP_SIM_DB_PENDING;
 
642
}
 
643
 
 
644
 
 
645
static struct eap_sim_pseudonym *
 
646
eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
 
647
                         size_t identity_len)
 
648
{
 
649
        char *pseudonym;
 
650
        size_t len;
 
651
        struct eap_sim_pseudonym *p;
 
652
 
 
653
        if (identity_len == 0 ||
 
654
            (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
 
655
             identity[0] != EAP_AKA_PSEUDONYM_PREFIX))
 
656
                return NULL;
 
657
 
 
658
        /* Remove possible realm from identity */
 
659
        len = 0;
 
660
        while (len < identity_len) {
 
661
                if (identity[len] == '@')
 
662
                        break;
 
663
                len++;
 
664
        }
 
665
 
 
666
        pseudonym = os_malloc(len + 1);
 
667
        if (pseudonym == NULL)
 
668
                return NULL;
 
669
        os_memcpy(pseudonym, identity, len);
 
670
        pseudonym[len] = '\0';
 
671
 
 
672
        p = data->pseudonyms;
 
673
        while (p) {
 
674
                if (os_strcmp(p->pseudonym, pseudonym) == 0)
 
675
                        break;
 
676
                p = p->next;
 
677
        }
 
678
 
 
679
        os_free(pseudonym);
 
680
 
 
681
        return p;
 
682
}
 
683
 
 
684
 
 
685
static struct eap_sim_pseudonym *
 
686
eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
 
687
                            size_t identity_len)
 
688
{
 
689
        struct eap_sim_pseudonym *p;
 
690
 
 
691
        if (identity_len == 0 ||
 
692
            (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
 
693
             identity[0] != EAP_AKA_PERMANENT_PREFIX))
 
694
                return NULL;
 
695
 
 
696
        p = data->pseudonyms;
 
697
        while (p) {
 
698
                if (identity_len == p->identity_len &&
 
699
                    os_memcmp(p->identity, identity, identity_len) == 0)
 
700
                        break;
 
701
                p = p->next;
 
702
        }
 
703
 
 
704
        return p;
 
705
}
 
706
 
 
707
 
 
708
static struct eap_sim_reauth *
 
709
eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
 
710
                      size_t identity_len)
 
711
{
 
712
        char *reauth_id;
 
713
        size_t len;
 
714
        struct eap_sim_reauth *r;
 
715
 
 
716
        if (identity_len == 0 ||
 
717
            (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
 
718
             identity[0] != EAP_AKA_REAUTH_ID_PREFIX))
 
719
                return NULL;
 
720
 
 
721
        /* Remove possible realm from identity */
 
722
        len = 0;
 
723
        while (len < identity_len) {
 
724
                if (identity[len] == '@')
 
725
                        break;
 
726
                len++;
 
727
        }
 
728
 
 
729
        reauth_id = os_malloc(len + 1);
 
730
        if (reauth_id == NULL)
 
731
                return NULL;
 
732
        os_memcpy(reauth_id, identity, len);
 
733
        reauth_id[len] = '\0';
 
734
 
 
735
        r = data->reauths;
 
736
        while (r) {
 
737
                if (os_strcmp(r->reauth_id, reauth_id) == 0)
 
738
                        break;
 
739
                r = r->next;
 
740
        }
 
741
 
 
742
        os_free(reauth_id);
 
743
 
 
744
        return r;
 
745
}
 
746
 
 
747
 
 
748
static struct eap_sim_reauth *
 
749
eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
 
750
                         size_t identity_len)
 
751
{
 
752
        struct eap_sim_pseudonym *p;
 
753
        struct eap_sim_reauth *r;
 
754
 
 
755
        if (identity_len == 0)
 
756
                return NULL;
 
757
 
 
758
        p = eap_sim_db_get_pseudonym(data, identity, identity_len);
 
759
        if (p == NULL)
 
760
                p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
 
761
        if (p) {
 
762
                identity = p->identity;
 
763
                identity_len = p->identity_len;
 
764
        }
 
765
 
 
766
        r = data->reauths;
 
767
        while (r) {
 
768
                if (identity_len == r->identity_len &&
 
769
                    os_memcmp(r->identity, identity, identity_len) == 0)
 
770
                        break;
 
771
                r = r->next;
 
772
        }
 
773
 
 
774
        return r;
 
775
}
 
776
 
 
777
 
 
778
/**
 
779
 * eap_sim_db_identity_known - Verify whether the given identity is known
 
780
 * @priv: Private data pointer from eap_sim_db_init()
 
781
 * @identity: User name identity
 
782
 * @identity_len: Length of identity in bytes 
 
783
 * Returns: 0 if the user is found or -1 on failure
 
784
 *
 
785
 * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the
 
786
 * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id.
 
787
 */
 
788
int eap_sim_db_identity_known(void *priv, const u8 *identity,
 
789
                              size_t identity_len)
 
790
{
 
791
        struct eap_sim_db_data *data = priv;
 
792
 
 
793
        if (identity == NULL || identity_len < 2)
 
794
                return -1;
 
795
 
 
796
        if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
 
797
            identity[0] == EAP_AKA_PSEUDONYM_PREFIX) {
 
798
                struct eap_sim_pseudonym *p =
 
799
                        eap_sim_db_get_pseudonym(data, identity, identity_len);
 
800
                return p ? 0 : -1;
 
801
        }
 
802
 
 
803
        if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
 
804
            identity[0] == EAP_AKA_REAUTH_ID_PREFIX) {
 
805
                struct eap_sim_reauth *r =
 
806
                        eap_sim_db_get_reauth(data, identity, identity_len);
 
807
                return r ? 0 : -1;
 
808
        }
 
809
 
 
810
        if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
 
811
            identity[0] != EAP_AKA_PERMANENT_PREFIX) {
 
812
                /* Unknown identity prefix */
 
813
                return -1;
 
814
        }
 
815
 
 
816
        /* TODO: Should consider asking HLR/AuC gateway whether this permanent
 
817
         * identity is known. If it is, EAP-SIM/AKA can skip identity request.
 
818
         * In case of EAP-AKA, this would reduce number of needed round-trips.
 
819
         * Ideally, this would be done with one wait, i.e., just request
 
820
         * authentication data and store it for the next use. This would then
 
821
         * need to use similar pending-request functionality as the normal
 
822
         * request for authentication data at later phase.
 
823
         */
 
824
        return -1;
 
825
}
 
826
 
 
827
 
 
828
static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
 
829
{
 
830
        char *id, *pos, *end;
 
831
        u8 buf[10];
 
832
 
 
833
        if (os_get_random(buf, sizeof(buf)))
 
834
                return NULL;
 
835
        id = os_malloc(sizeof(buf) * 2 + 2);
 
836
        if (id == NULL)
 
837
                return NULL;
 
838
 
 
839
        pos = id;
 
840
        end = id + sizeof(buf) * 2 + 2;
 
841
        *pos++ = prefix;
 
842
        pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
 
843
        
 
844
        return id;
 
845
}
 
846
 
 
847
 
 
848
/**
 
849
 * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
 
850
 * @priv: Private data pointer from eap_sim_db_init()
 
851
 * @aka: Using EAP-AKA instead of EAP-SIM
 
852
 * Returns: Next pseudonym (allocated string) or %NULL on failure
 
853
 *
 
854
 * This function is used to generate a pseudonym for EAP-SIM. The returned
 
855
 * pseudonym is not added to database at this point; it will need to be added
 
856
 * with eap_sim_db_add_pseudonym() once the authentication has been completed
 
857
 * successfully. Caller is responsible for freeing the returned buffer.
 
858
 */
 
859
char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
 
860
{
 
861
        struct eap_sim_db_data *data = priv;
 
862
        return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX :
 
863
                                   EAP_SIM_PSEUDONYM_PREFIX);
 
864
}
 
865
 
 
866
 
 
867
/**
 
868
 * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
 
869
 * @priv: Private data pointer from eap_sim_db_init()
 
870
 * @aka: Using EAP-AKA instead of EAP-SIM
 
871
 * Returns: Next reauth_id (allocated string) or %NULL on failure
 
872
 *
 
873
 * This function is used to generate a fast re-authentication identity for
 
874
 * EAP-SIM. The returned reauth_id is not added to database at this point; it
 
875
 * will need to be added with eap_sim_db_add_reauth() once the authentication
 
876
 * has been completed successfully. Caller is responsible for freeing the
 
877
 * returned buffer.
 
878
 */
 
879
char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
 
880
{
 
881
        struct eap_sim_db_data *data = priv;
 
882
        return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX :
 
883
                                   EAP_SIM_REAUTH_ID_PREFIX);
 
884
}
 
885
 
 
886
 
 
887
/**
 
888
 * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
 
889
 * @priv: Private data pointer from eap_sim_db_init()
 
890
 * @identity: Identity of the user (may be permanent identity or pseudonym)
 
891
 * @identity_len: Length of identity
 
892
 * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
 
893
 * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
 
894
 * free it.
 
895
 * Returns: 0 on success, -1 on failure
 
896
 *
 
897
 * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
 
898
 * responsible of freeing pseudonym buffer once it is not needed anymore.
 
899
 */
 
900
int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
 
901
                             size_t identity_len, char *pseudonym)
 
902
{
 
903
        struct eap_sim_db_data *data = priv;
 
904
        struct eap_sim_pseudonym *p;
 
905
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
 
906
                          identity, identity_len);
 
907
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
 
908
 
 
909
        /* TODO: could store last two pseudonyms */
 
910
        p = eap_sim_db_get_pseudonym(data, identity, identity_len);
 
911
        if (p == NULL)
 
912
                p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
 
913
 
 
914
        if (p) {
 
915
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
 
916
                           "pseudonym: %s", p->pseudonym);
 
917
                os_free(p->pseudonym);
 
918
                p->pseudonym = pseudonym;
 
919
                return 0;
 
920
        }
 
921
 
 
922
        p = os_zalloc(sizeof(*p));
 
923
        if (p == NULL) {
 
924
                os_free(pseudonym);
 
925
                return -1;
 
926
        }
 
927
 
 
928
        p->next = data->pseudonyms;
 
929
        p->identity = os_malloc(identity_len);
 
930
        if (p->identity == NULL) {
 
931
                os_free(p);
 
932
                os_free(pseudonym);
 
933
                return -1;
 
934
        }
 
935
        os_memcpy(p->identity, identity, identity_len);
 
936
        p->identity_len = identity_len;
 
937
        p->pseudonym = pseudonym;
 
938
        data->pseudonyms = p;
 
939
 
 
940
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
 
941
        return 0;
 
942
}
 
943
 
 
944
 
 
945
/**
 
946
 * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
 
947
 * @priv: Private data pointer from eap_sim_db_init()
 
948
 * @identity: Identity of the user (may be permanent identity or pseudonym)
 
949
 * @identity_len: Length of identity
 
950
 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
 
951
 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
 
952
 * free it.
 
953
 * @mk: 16-byte MK from the previous full authentication
 
954
 * Returns: 0 on success, -1 on failure
 
955
 *
 
956
 * This function adds a new re-authentication entry for an EAP-SIM user.
 
957
 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
 
958
 * anymore.
 
959
 */
 
960
int eap_sim_db_add_reauth(void *priv, const u8 *identity,
 
961
                          size_t identity_len, char *reauth_id, u16 counter,
 
962
                          const u8 *mk)
 
963
{
 
964
        struct eap_sim_db_data *data = priv;
 
965
        struct eap_sim_reauth *r;
 
966
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
 
967
                          identity, identity_len);
 
968
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
 
969
 
 
970
        r = eap_sim_db_get_reauth(data, identity, identity_len);
 
971
        if (r == NULL)
 
972
                r = eap_sim_db_get_reauth_id(data, identity, identity_len);
 
973
 
 
974
        if (r) {
 
975
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
 
976
                           "reauth_id: %s", r->reauth_id);
 
977
                os_free(r->reauth_id);
 
978
                r->reauth_id = reauth_id;
 
979
        } else {
 
980
                r = os_zalloc(sizeof(*r));
 
981
                if (r == NULL) {
 
982
                        os_free(reauth_id);
 
983
                        return -1;
 
984
                }
 
985
 
 
986
                r->next = data->reauths;
 
987
                r->identity = os_malloc(identity_len);
 
988
                if (r->identity == NULL) {
 
989
                        os_free(r);
 
990
                        os_free(reauth_id);
 
991
                        return -1;
 
992
                }
 
993
                os_memcpy(r->identity, identity, identity_len);
 
994
                r->identity_len = identity_len;
 
995
                r->reauth_id = reauth_id;
 
996
                data->reauths = r;
 
997
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
 
998
        }
 
999
 
 
1000
        r->counter = counter;
 
1001
        os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
 
1002
 
 
1003
        return 0;
 
1004
}
 
1005
 
 
1006
 
 
1007
/**
 
1008
 * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
 
1009
 * @priv: Private data pointer from eap_sim_db_init()
 
1010
 * @identity: Identity of the user (may be permanent identity or pseudonym)
 
1011
 * @identity_len: Length of identity
 
1012
 * @len: Buffer for length of the returned permanent identity
 
1013
 * Returns: Pointer to the permanent identity, or %NULL if not found
 
1014
 */
 
1015
const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
 
1016
                                    size_t identity_len, size_t *len)
 
1017
{
 
1018
        struct eap_sim_db_data *data = priv;
 
1019
        struct eap_sim_pseudonym *p;
 
1020
 
 
1021
        if (identity == NULL)
 
1022
                return NULL;
 
1023
 
 
1024
        p = eap_sim_db_get_pseudonym(data, identity, identity_len);
 
1025
        if (p == NULL)
 
1026
                p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
 
1027
        if (p == NULL)
 
1028
                return NULL;
 
1029
 
 
1030
        *len = p->identity_len;
 
1031
        return p->identity;
 
1032
}
 
1033
 
 
1034
 
 
1035
/**
 
1036
 * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
 
1037
 * @priv: Private data pointer from eap_sim_db_init()
 
1038
 * @identity: Identity of the user (may be permanent identity, pseudonym, or
 
1039
 * reauth_id)
 
1040
 * @identity_len: Length of identity
 
1041
 * @len: Buffer for length of the returned permanent identity
 
1042
 * Returns: Pointer to the re-auth entry, or %NULL if not found
 
1043
 */
 
1044
struct eap_sim_reauth *
 
1045
eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
 
1046
                            size_t identity_len)
 
1047
{
 
1048
        struct eap_sim_db_data *data = priv;
 
1049
        struct eap_sim_reauth *r;
 
1050
 
 
1051
        if (identity == NULL)
 
1052
                return NULL;
 
1053
        r = eap_sim_db_get_reauth(data, identity, identity_len);
 
1054
        if (r == NULL)
 
1055
                r = eap_sim_db_get_reauth_id(data, identity, identity_len);
 
1056
        return r;
 
1057
}
 
1058
 
 
1059
 
 
1060
/**
 
1061
 * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
 
1062
 * @priv: Private data pointer from eap_sim_db_init()
 
1063
 * @reauth: Pointer to re-authentication entry from
 
1064
 * eap_sim_db_get_reauth_entry()
 
1065
 */
 
1066
void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
 
1067
{
 
1068
        struct eap_sim_db_data *data = priv;
 
1069
        struct eap_sim_reauth *r, *prev = NULL;
 
1070
        r = data->reauths;
 
1071
        while (r) {
 
1072
                if (r == reauth) {
 
1073
                        if (prev)
 
1074
                                prev->next = r->next;
 
1075
                        else
 
1076
                                data->reauths = r->next;
 
1077
                        eap_sim_db_free_reauth(r);
 
1078
                        return;
 
1079
                }
 
1080
                prev = r;
 
1081
                r = r->next;
 
1082
        }
 
1083
}
 
1084
 
 
1085
 
 
1086
/**
 
1087
 * eap_sim_db_get_aka_auth - Get AKA authentication values
 
1088
 * @priv: Private data pointer from eap_sim_db_init()
 
1089
 * @identity: User name identity
 
1090
 * @identity_len: Length of identity in bytes
 
1091
 * @_rand: Buffer for RAND value
 
1092
 * @autn: Buffer for AUTN value
 
1093
 * @ik: Buffer for IK value
 
1094
 * @ck: Buffer for CK value
 
1095
 * @res: Buffer for RES value
 
1096
 * @res_len: Buffer for RES length
 
1097
 * @cb_session_ctx: Session callback context for get_complete_cb()
 
1098
 * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
 
1099
 * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
 
1100
 * case, the callback function registered with eap_sim_db_init() will be
 
1101
 * called once the results become available.
 
1102
 *
 
1103
 * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
 
1104
 * ASCII format.
 
1105
 *
 
1106
 * When using an external server for AKA authentication, this function can
 
1107
 * always start a request and return EAP_SIM_DB_PENDING immediately if
 
1108
 * authentication triplets are not available. Once the authentication data are
 
1109
 * received, callback function registered with eap_sim_db_init() is called to
 
1110
 * notify EAP state machine to reprocess the message. This
 
1111
 * eap_sim_db_get_aka_auth() function will then be called again and the newly
 
1112
 * received triplets will then be given to the caller.
 
1113
 */
 
1114
int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
 
1115
                            size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
 
1116
                            u8 *ck, u8 *res, size_t *res_len,
 
1117
                            void *cb_session_ctx)
 
1118
{
 
1119
        struct eap_sim_db_data *data = priv;
 
1120
        struct eap_sim_db_pending *entry;
 
1121
        int len;
 
1122
        size_t i;
 
1123
        char msg[40];
 
1124
 
 
1125
        if (identity_len < 2 || identity == NULL ||
 
1126
            identity[0] != EAP_AKA_PERMANENT_PREFIX) {
 
1127
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
 
1128
                                  identity, identity_len);
 
1129
                return EAP_SIM_DB_FAILURE;
 
1130
        }
 
1131
        identity++;
 
1132
        identity_len--;
 
1133
        for (i = 0; i < identity_len; i++) {
 
1134
                if (identity[i] == '@') {
 
1135
                        identity_len = i;
 
1136
                        break;
 
1137
                }
 
1138
        }
 
1139
        if (identity_len + 1 > sizeof(entry->imsi)) {
 
1140
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
 
1141
                                  identity, identity_len);
 
1142
                return EAP_SIM_DB_FAILURE;
 
1143
        }
 
1144
        wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
 
1145
                          identity, identity_len);
 
1146
 
 
1147
        entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
 
1148
        if (entry) {
 
1149
                if (entry->state == FAILURE) {
 
1150
                        os_free(entry);
 
1151
                        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
 
1152
                        return EAP_SIM_DB_FAILURE;
 
1153
                }
 
1154
 
 
1155
                if (entry->state == PENDING) {
 
1156
                        eap_sim_db_add_pending(data, entry);
 
1157
                        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
 
1158
                        return EAP_SIM_DB_PENDING;
 
1159
                }
 
1160
 
 
1161
                wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
 
1162
                           "received authentication data");
 
1163
                os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
 
1164
                os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
 
1165
                os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
 
1166
                os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
 
1167
                os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
 
1168
                *res_len = entry->u.aka.res_len;
 
1169
                os_free(entry);
 
1170
                return 0;
 
1171
        }
 
1172
 
 
1173
        if (data->sock < 0) {
 
1174
                if (eap_sim_db_open_socket(data) < 0)
 
1175
                        return EAP_SIM_DB_FAILURE;
 
1176
        }
 
1177
 
 
1178
        len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
 
1179
        if (len < 0 || len + identity_len >= sizeof(msg))
 
1180
                return EAP_SIM_DB_FAILURE;
 
1181
        os_memcpy(msg + len, identity, identity_len);
 
1182
        len += identity_len;
 
1183
 
 
1184
        wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
 
1185
                    "data for IMSI", identity, identity_len);
 
1186
        if (eap_sim_db_send(data, msg, len) < 0)
 
1187
                return EAP_SIM_DB_FAILURE;
 
1188
 
 
1189
        entry = os_zalloc(sizeof(*entry));
 
1190
        if (entry == NULL)
 
1191
                return EAP_SIM_DB_FAILURE;
 
1192
 
 
1193
        os_get_time(&entry->timestamp);
 
1194
        entry->aka = 1;
 
1195
        os_memcpy(entry->imsi, identity, identity_len);
 
1196
        entry->imsi_len = identity_len;
 
1197
        entry->cb_session_ctx = cb_session_ctx;
 
1198
        entry->state = PENDING;
 
1199
        eap_sim_db_add_pending(data, entry);
 
1200
        eap_sim_db_expire_pending(data);
 
1201
 
 
1202
        return EAP_SIM_DB_PENDING;
 
1203
}
 
1204
 
 
1205
 
 
1206
/**
 
1207
 * eap_sim_db_resynchronize - Resynchronize AKA AUTN
 
1208
 * @priv: Private data pointer from eap_sim_db_init()
 
1209
 * @identity: User name identity
 
1210
 * @identity_len: Length of identity in bytes
 
1211
 * @auts: AUTS value from the peer
 
1212
 * @_rand: RAND value used in the rejected message
 
1213
 * Returns: 0 on success, -1 on failure
 
1214
 *
 
1215
 * This function is called when the peer reports synchronization failure in the
 
1216
 * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
 
1217
 * HLR/AuC to allow it to resynchronize with the peer. After this,
 
1218
 * eap_sim_db_get_aka_auth() will be called again to to fetch updated
 
1219
 * RAND/AUTN values for the next challenge.
 
1220
 */
 
1221
int eap_sim_db_resynchronize(void *priv, const u8 *identity,
 
1222
                             size_t identity_len, const u8 *auts,
 
1223
                             const u8 *_rand)
 
1224
{
 
1225
        struct eap_sim_db_data *data = priv;
 
1226
        size_t i;
 
1227
 
 
1228
        if (identity_len < 2 || identity == NULL ||
 
1229
            identity[0] != EAP_AKA_PERMANENT_PREFIX) {
 
1230
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
 
1231
                                  identity, identity_len);
 
1232
                return -1;
 
1233
        }
 
1234
        identity++;
 
1235
        identity_len--;
 
1236
        for (i = 0; i < identity_len; i++) {
 
1237
                if (identity[i] == '@') {
 
1238
                        identity_len = i;
 
1239
                        break;
 
1240
                }
 
1241
        }
 
1242
        if (identity_len > 20) {
 
1243
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
 
1244
                                  identity, identity_len);
 
1245
                return -1;
 
1246
        }
 
1247
 
 
1248
        if (data->sock >= 0) {
 
1249
                char msg[100];
 
1250
                int len, ret;
 
1251
 
 
1252
                len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
 
1253
                if (len < 0 || len + identity_len >= sizeof(msg))
 
1254
                        return -1;
 
1255
                os_memcpy(msg + len, identity, identity_len);
 
1256
                len += identity_len;
 
1257
 
 
1258
                ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
 
1259
                if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
 
1260
                        return -1;
 
1261
                len += ret;
 
1262
                len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
 
1263
                                        auts, EAP_AKA_AUTS_LEN);
 
1264
                ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
 
1265
                if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
 
1266
                        return -1;
 
1267
                len += ret;
 
1268
                len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
 
1269
                                        _rand, EAP_AKA_RAND_LEN);
 
1270
                wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
 
1271
                            "IMSI", identity, identity_len);
 
1272
                if (eap_sim_db_send(data, msg, len) < 0)
 
1273
                        return -1;
 
1274
        }
 
1275
 
 
1276
        return 0;
 
1277
}