Merge branch 'vendor/OPENSSL'
[dragonfly.git] / contrib / hostapd / src / eap_server / eap_sim_db.c
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 static struct eap_sim_reauth *
946 eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
947                            size_t identity_len, char *reauth_id, u16 counter)
948 {
949         struct eap_sim_reauth *r;
950
951         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
952                           identity, identity_len);
953         wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
954
955         r = eap_sim_db_get_reauth(data, identity, identity_len);
956         if (r == NULL)
957                 r = eap_sim_db_get_reauth_id(data, identity, identity_len);
958
959         if (r) {
960                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
961                            "reauth_id: %s", r->reauth_id);
962                 os_free(r->reauth_id);
963                 r->reauth_id = reauth_id;
964         } else {
965                 r = os_zalloc(sizeof(*r));
966                 if (r == NULL) {
967                         os_free(reauth_id);
968                         return NULL;
969                 }
970
971                 r->next = data->reauths;
972                 r->identity = os_malloc(identity_len);
973                 if (r->identity == NULL) {
974                         os_free(r);
975                         os_free(reauth_id);
976                         return NULL;
977                 }
978                 os_memcpy(r->identity, identity, identity_len);
979                 r->identity_len = identity_len;
980                 r->reauth_id = reauth_id;
981                 data->reauths = r;
982                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
983         }
984
985         r->counter = counter;
986
987         return r;
988 }
989
990
991 /**
992  * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
993  * @priv: Private data pointer from eap_sim_db_init()
994  * @identity: Identity of the user (may be permanent identity or pseudonym)
995  * @identity_len: Length of identity
996  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
997  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
998  * free it.
999  * @counter: AT_COUNTER value for fast re-authentication
1000  * @mk: 16-byte MK from the previous full authentication or %NULL
1001  * Returns: 0 on success, -1 on failure
1002  *
1003  * This function adds a new re-authentication entry for an EAP-SIM user.
1004  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1005  * anymore.
1006  */
1007 int eap_sim_db_add_reauth(void *priv, const u8 *identity,
1008                           size_t identity_len, char *reauth_id, u16 counter,
1009                           const u8 *mk)
1010 {
1011         struct eap_sim_db_data *data = priv;
1012         struct eap_sim_reauth *r;
1013
1014         r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
1015                                        counter);
1016         if (r == NULL)
1017                 return -1;
1018
1019         os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
1020         r->aka_prime = 0;
1021
1022         return 0;
1023 }
1024
1025
1026 #ifdef EAP_AKA_PRIME
1027 /**
1028  * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
1029  * @priv: Private data pointer from eap_sim_db_init()
1030  * @identity: Identity of the user (may be permanent identity or pseudonym)
1031  * @identity_len: Length of identity
1032  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1033  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1034  * free it.
1035  * @counter: AT_COUNTER value for fast re-authentication
1036  * @k_encr: K_encr from the previous full authentication
1037  * @k_aut: K_aut from the previous full authentication
1038  * @k_re: 32-byte K_re from the previous full authentication
1039  * Returns: 0 on success, -1 on failure
1040  *
1041  * This function adds a new re-authentication entry for an EAP-AKA' user.
1042  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1043  * anymore.
1044  */
1045 int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
1046                                 size_t identity_len, char *reauth_id,
1047                                 u16 counter, const u8 *k_encr, const u8 *k_aut,
1048                                 const u8 *k_re)
1049 {
1050         struct eap_sim_db_data *data = priv;
1051         struct eap_sim_reauth *r;
1052
1053         r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
1054                                        counter);
1055         if (r == NULL)
1056                 return -1;
1057
1058         r->aka_prime = 1;
1059         os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
1060         os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
1061         os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
1062
1063         return 0;
1064 }
1065 #endif /* EAP_AKA_PRIME */
1066
1067
1068 /**
1069  * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
1070  * @priv: Private data pointer from eap_sim_db_init()
1071  * @identity: Identity of the user (may be permanent identity or pseudonym)
1072  * @identity_len: Length of identity
1073  * @len: Buffer for length of the returned permanent identity
1074  * Returns: Pointer to the permanent identity, or %NULL if not found
1075  */
1076 const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
1077                                     size_t identity_len, size_t *len)
1078 {
1079         struct eap_sim_db_data *data = priv;
1080         struct eap_sim_pseudonym *p;
1081
1082         if (identity == NULL)
1083                 return NULL;
1084
1085         p = eap_sim_db_get_pseudonym(data, identity, identity_len);
1086         if (p == NULL)
1087                 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
1088         if (p == NULL)
1089                 return NULL;
1090
1091         *len = p->identity_len;
1092         return p->identity;
1093 }
1094
1095
1096 /**
1097  * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
1098  * @priv: Private data pointer from eap_sim_db_init()
1099  * @identity: Identity of the user (may be permanent identity, pseudonym, or
1100  * reauth_id)
1101  * @identity_len: Length of identity
1102  * Returns: Pointer to the re-auth entry, or %NULL if not found
1103  */
1104 struct eap_sim_reauth *
1105 eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
1106                             size_t identity_len)
1107 {
1108         struct eap_sim_db_data *data = priv;
1109         struct eap_sim_reauth *r;
1110
1111         if (identity == NULL)
1112                 return NULL;
1113         r = eap_sim_db_get_reauth(data, identity, identity_len);
1114         if (r == NULL)
1115                 r = eap_sim_db_get_reauth_id(data, identity, identity_len);
1116         return r;
1117 }
1118
1119
1120 /**
1121  * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
1122  * @priv: Private data pointer from eap_sim_db_init()
1123  * @reauth: Pointer to re-authentication entry from
1124  * eap_sim_db_get_reauth_entry()
1125  */
1126 void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
1127 {
1128         struct eap_sim_db_data *data = priv;
1129         struct eap_sim_reauth *r, *prev = NULL;
1130         r = data->reauths;
1131         while (r) {
1132                 if (r == reauth) {
1133                         if (prev)
1134                                 prev->next = r->next;
1135                         else
1136                                 data->reauths = r->next;
1137                         eap_sim_db_free_reauth(r);
1138                         return;
1139                 }
1140                 prev = r;
1141                 r = r->next;
1142         }
1143 }
1144
1145
1146 /**
1147  * eap_sim_db_get_aka_auth - Get AKA authentication values
1148  * @priv: Private data pointer from eap_sim_db_init()
1149  * @identity: User name identity
1150  * @identity_len: Length of identity in bytes
1151  * @_rand: Buffer for RAND value
1152  * @autn: Buffer for AUTN value
1153  * @ik: Buffer for IK value
1154  * @ck: Buffer for CK value
1155  * @res: Buffer for RES value
1156  * @res_len: Buffer for RES length
1157  * @cb_session_ctx: Session callback context for get_complete_cb()
1158  * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
1159  * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
1160  * case, the callback function registered with eap_sim_db_init() will be
1161  * called once the results become available.
1162  *
1163  * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
1164  * ASCII format.
1165  *
1166  * When using an external server for AKA authentication, this function can
1167  * always start a request and return EAP_SIM_DB_PENDING immediately if
1168  * authentication triplets are not available. Once the authentication data are
1169  * received, callback function registered with eap_sim_db_init() is called to
1170  * notify EAP state machine to reprocess the message. This
1171  * eap_sim_db_get_aka_auth() function will then be called again and the newly
1172  * received triplets will then be given to the caller.
1173  */
1174 int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
1175                             size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
1176                             u8 *ck, u8 *res, size_t *res_len,
1177                             void *cb_session_ctx)
1178 {
1179         struct eap_sim_db_data *data = priv;
1180         struct eap_sim_db_pending *entry;
1181         int len;
1182         size_t i;
1183         char msg[40];
1184
1185         if (identity_len < 2 || identity == NULL ||
1186             identity[0] != EAP_AKA_PERMANENT_PREFIX) {
1187                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
1188                                   identity, identity_len);
1189                 return EAP_SIM_DB_FAILURE;
1190         }
1191         identity++;
1192         identity_len--;
1193         for (i = 0; i < identity_len; i++) {
1194                 if (identity[i] == '@') {
1195                         identity_len = i;
1196                         break;
1197                 }
1198         }
1199         if (identity_len + 1 > sizeof(entry->imsi)) {
1200                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
1201                                   identity, identity_len);
1202                 return EAP_SIM_DB_FAILURE;
1203         }
1204         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
1205                           identity, identity_len);
1206
1207         entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
1208         if (entry) {
1209                 if (entry->state == FAILURE) {
1210                         os_free(entry);
1211                         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
1212                         return EAP_SIM_DB_FAILURE;
1213                 }
1214
1215                 if (entry->state == PENDING) {
1216                         eap_sim_db_add_pending(data, entry);
1217                         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
1218                         return EAP_SIM_DB_PENDING;
1219                 }
1220
1221                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
1222                            "received authentication data");
1223                 os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
1224                 os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
1225                 os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
1226                 os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
1227                 os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
1228                 *res_len = entry->u.aka.res_len;
1229                 os_free(entry);
1230                 return 0;
1231         }
1232
1233         if (data->sock < 0) {
1234                 if (eap_sim_db_open_socket(data) < 0)
1235                         return EAP_SIM_DB_FAILURE;
1236         }
1237
1238         len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
1239         if (len < 0 || len + identity_len >= sizeof(msg))
1240                 return EAP_SIM_DB_FAILURE;
1241         os_memcpy(msg + len, identity, identity_len);
1242         len += identity_len;
1243
1244         wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
1245                     "data for IMSI", identity, identity_len);
1246         if (eap_sim_db_send(data, msg, len) < 0)
1247                 return EAP_SIM_DB_FAILURE;
1248
1249         entry = os_zalloc(sizeof(*entry));
1250         if (entry == NULL)
1251                 return EAP_SIM_DB_FAILURE;
1252
1253         os_get_time(&entry->timestamp);
1254         entry->aka = 1;
1255         os_memcpy(entry->imsi, identity, identity_len);
1256         entry->imsi_len = identity_len;
1257         entry->cb_session_ctx = cb_session_ctx;
1258         entry->state = PENDING;
1259         eap_sim_db_add_pending(data, entry);
1260         eap_sim_db_expire_pending(data);
1261
1262         return EAP_SIM_DB_PENDING;
1263 }
1264
1265
1266 /**
1267  * eap_sim_db_resynchronize - Resynchronize AKA AUTN
1268  * @priv: Private data pointer from eap_sim_db_init()
1269  * @identity: User name identity
1270  * @identity_len: Length of identity in bytes
1271  * @auts: AUTS value from the peer
1272  * @_rand: RAND value used in the rejected message
1273  * Returns: 0 on success, -1 on failure
1274  *
1275  * This function is called when the peer reports synchronization failure in the
1276  * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
1277  * HLR/AuC to allow it to resynchronize with the peer. After this,
1278  * eap_sim_db_get_aka_auth() will be called again to to fetch updated
1279  * RAND/AUTN values for the next challenge.
1280  */
1281 int eap_sim_db_resynchronize(void *priv, const u8 *identity,
1282                              size_t identity_len, const u8 *auts,
1283                              const u8 *_rand)
1284 {
1285         struct eap_sim_db_data *data = priv;
1286         size_t i;
1287
1288         if (identity_len < 2 || identity == NULL ||
1289             identity[0] != EAP_AKA_PERMANENT_PREFIX) {
1290                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
1291                                   identity, identity_len);
1292                 return -1;
1293         }
1294         identity++;
1295         identity_len--;
1296         for (i = 0; i < identity_len; i++) {
1297                 if (identity[i] == '@') {
1298                         identity_len = i;
1299                         break;
1300                 }
1301         }
1302         if (identity_len > 20) {
1303                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
1304                                   identity, identity_len);
1305                 return -1;
1306         }
1307
1308         if (data->sock >= 0) {
1309                 char msg[100];
1310                 int len, ret;
1311
1312                 len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
1313                 if (len < 0 || len + identity_len >= sizeof(msg))
1314                         return -1;
1315                 os_memcpy(msg + len, identity, identity_len);
1316                 len += identity_len;
1317
1318                 ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1319                 if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
1320                         return -1;
1321                 len += ret;
1322                 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1323                                         auts, EAP_AKA_AUTS_LEN);
1324                 ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1325                 if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
1326                         return -1;
1327                 len += ret;
1328                 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1329                                         _rand, EAP_AKA_RAND_LEN);
1330                 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
1331                             "IMSI", identity, identity_len);
1332                 if (eap_sim_db_send(data, msg, len) < 0)
1333                         return -1;
1334         }
1335
1336         return 0;
1337 }