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