xref: /dragonfly/contrib/wpa_supplicant/src/eap_server/eap_sim_db.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1 /*
2  * hostapd / EAP-SIM database/authenticator gateway
3  * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  *
8  * This is an example implementation of the EAP-SIM/AKA database/authentication
9  * gateway interface that is using an external program as an SS7 gateway to
10  * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
11  * implementation of such a gateway program. This eap_sim_db.c takes care of
12  * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
13  * gateway implementations for HLR/AuC access. Alternatively, it can also be
14  * completely replaced if the in-memory database of pseudonyms/re-auth
15  * identities is not suitable for some cases.
16  */
17 
18 #include "includes.h"
19 #include <sys/un.h>
20 #ifdef CONFIG_SQLITE
21 #include <sqlite3.h>
22 #endif /* CONFIG_SQLITE */
23 
24 #include "common.h"
25 #include "crypto/random.h"
26 #include "eap_common/eap_sim_common.h"
27 #include "eap_server/eap_sim_db.h"
28 #include "eloop.h"
29 
30 struct eap_sim_pseudonym {
31           struct eap_sim_pseudonym *next;
32           char *permanent; /* permanent username */
33           char *pseudonym; /* pseudonym username */
34 };
35 
36 struct eap_sim_db_pending {
37           struct eap_sim_db_pending *next;
38           char imsi[20];
39           enum { PENDING, SUCCESS, FAILURE } state;
40           void *cb_session_ctx;
41           int aka;
42           union {
43                     struct {
44                               u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
45                               u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
46                               u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
47                               int num_chal;
48                     } sim;
49                     struct {
50                               u8 rand[EAP_AKA_RAND_LEN];
51                               u8 autn[EAP_AKA_AUTN_LEN];
52                               u8 ik[EAP_AKA_IK_LEN];
53                               u8 ck[EAP_AKA_CK_LEN];
54                               u8 res[EAP_AKA_RES_MAX_LEN];
55                               size_t res_len;
56                     } aka;
57           } u;
58 };
59 
60 struct eap_sim_db_data {
61           int sock;
62           char *fname;
63           char *local_sock;
64           void (*get_complete_cb)(void *ctx, void *session_ctx);
65           void *ctx;
66           struct eap_sim_pseudonym *pseudonyms;
67           struct eap_sim_reauth *reauths;
68           struct eap_sim_db_pending *pending;
69           unsigned int eap_sim_db_timeout;
70 #ifdef CONFIG_SQLITE
71           sqlite3 *sqlite_db;
72           char db_tmp_identity[100];
73           char db_tmp_pseudonym_str[100];
74           struct eap_sim_pseudonym db_tmp_pseudonym;
75           struct eap_sim_reauth db_tmp_reauth;
76 #endif /* CONFIG_SQLITE */
77 };
78 
79 
80 static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx);
81 static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx);
82 
83 
84 #ifdef CONFIG_SQLITE
85 
db_table_exists(sqlite3 * db,const char * name)86 static int db_table_exists(sqlite3 *db, const char *name)
87 {
88           char cmd[128];
89           os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
90           return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
91 }
92 
93 
db_table_create_pseudonym(sqlite3 * db)94 static int db_table_create_pseudonym(sqlite3 *db)
95 {
96           char *err = NULL;
97           const char *sql =
98                     "CREATE TABLE pseudonyms("
99                     "  permanent CHAR(21) PRIMARY KEY,"
100                     "  pseudonym CHAR(21) NOT NULL"
101                     ");";
102 
103           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
104                        "pseudonym information");
105           if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
106                     wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
107                     sqlite3_free(err);
108                     return -1;
109           }
110 
111           return 0;
112 }
113 
114 
db_table_create_reauth(sqlite3 * db)115 static int db_table_create_reauth(sqlite3 *db)
116 {
117           char *err = NULL;
118           const char *sql =
119                     "CREATE TABLE reauth("
120                     "  permanent CHAR(21) PRIMARY KEY,"
121                     "  reauth_id CHAR(21) NOT NULL,"
122                     "  counter INTEGER,"
123                     "  mk CHAR(40),"
124                     "  k_encr CHAR(32),"
125                     "  k_aut CHAR(64),"
126                     "  k_re CHAR(64)"
127                     ");";
128 
129           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
130                        "reauth information");
131           if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
132                     wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
133                     sqlite3_free(err);
134                     return -1;
135           }
136 
137           return 0;
138 }
139 
140 
db_open(const char * db_file)141 static sqlite3 * db_open(const char *db_file)
142 {
143           sqlite3 *db;
144 
145           if (sqlite3_open(db_file, &db)) {
146                     wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
147                                  "%s: %s", db_file, sqlite3_errmsg(db));
148                     sqlite3_close(db);
149                     return NULL;
150           }
151 
152           if (!db_table_exists(db, "pseudonyms") &&
153               db_table_create_pseudonym(db) < 0) {
154                     sqlite3_close(db);
155                     return NULL;
156           }
157 
158           if (!db_table_exists(db, "reauth") &&
159               db_table_create_reauth(db) < 0) {
160                     sqlite3_close(db);
161                     return NULL;
162           }
163 
164           return db;
165 }
166 
167 
valid_db_string(const char * str)168 static int valid_db_string(const char *str)
169 {
170           const char *pos = str;
171           while (*pos) {
172                     if ((*pos < '0' || *pos > '9') &&
173                         (*pos < 'a' || *pos > 'f'))
174                               return 0;
175                     pos++;
176           }
177           return 1;
178 }
179 
180 
db_add_pseudonym(struct eap_sim_db_data * data,const char * permanent,char * pseudonym)181 static int db_add_pseudonym(struct eap_sim_db_data *data,
182                                   const char *permanent, char *pseudonym)
183 {
184           char cmd[128];
185           char *err = NULL;
186 
187           if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) {
188                     os_free(pseudonym);
189                     return -1;
190           }
191 
192           os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
193                         "(permanent, pseudonym) VALUES ('%s', '%s');",
194                         permanent, pseudonym);
195           os_free(pseudonym);
196           if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
197           {
198                     wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
199                     sqlite3_free(err);
200                     return -1;
201           }
202 
203           return 0;
204 }
205 
206 
get_pseudonym_cb(void * ctx,int argc,char * argv[],char * col[])207 static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
208 {
209           struct eap_sim_db_data *data = ctx;
210           int i;
211 
212           for (i = 0; i < argc; i++) {
213                     if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
214                               os_strlcpy(data->db_tmp_identity, argv[i],
215                                            sizeof(data->db_tmp_identity));
216                     }
217           }
218 
219           return 0;
220 }
221 
222 
223 static char *
db_get_pseudonym(struct eap_sim_db_data * data,const char * pseudonym)224 db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
225 {
226           char cmd[128];
227 
228           if (!valid_db_string(pseudonym))
229                     return NULL;
230           os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity));
231           os_snprintf(cmd, sizeof(cmd),
232                         "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';",
233                         pseudonym);
234           if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
235               SQLITE_OK)
236                     return NULL;
237           if (data->db_tmp_identity[0] == '\0')
238                     return NULL;
239           return data->db_tmp_identity;
240 }
241 
242 
db_add_reauth(struct eap_sim_db_data * data,const char * permanent,char * reauth_id,u16 counter,const u8 * mk,const u8 * k_encr,const u8 * k_aut,const u8 * k_re)243 static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
244                                char *reauth_id, u16 counter, const u8 *mk,
245                                const u8 *k_encr, const u8 *k_aut, const u8 *k_re)
246 {
247           char cmd[2000], *pos, *end;
248           char *err = NULL;
249 
250           if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) {
251                     os_free(reauth_id);
252                     return -1;
253           }
254 
255           pos = cmd;
256           end = pos + sizeof(cmd);
257           pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth "
258                                  "(permanent, reauth_id, counter%s%s%s%s) "
259                                  "VALUES ('%s', '%s', %u",
260                                  mk ? ", mk" : "",
261                                  k_encr ? ", k_encr" : "",
262                                  k_aut ? ", k_aut" : "",
263                                  k_re ? ", k_re" : "",
264                                  permanent, reauth_id, counter);
265           os_free(reauth_id);
266 
267           if (mk) {
268                     pos += os_snprintf(pos, end - pos, ", '");
269                     pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN);
270                     pos += os_snprintf(pos, end - pos, "'");
271           }
272 
273           if (k_encr) {
274                     pos += os_snprintf(pos, end - pos, ", '");
275                     pos += wpa_snprintf_hex(pos, end - pos, k_encr,
276                                                   EAP_SIM_K_ENCR_LEN);
277                     pos += os_snprintf(pos, end - pos, "'");
278           }
279 
280           if (k_aut) {
281                     pos += os_snprintf(pos, end - pos, ", '");
282                     pos += wpa_snprintf_hex(pos, end - pos, k_aut,
283                                                   EAP_AKA_PRIME_K_AUT_LEN);
284                     pos += os_snprintf(pos, end - pos, "'");
285           }
286 
287           if (k_re) {
288                     pos += os_snprintf(pos, end - pos, ", '");
289                     pos += wpa_snprintf_hex(pos, end - pos, k_re,
290                                                   EAP_AKA_PRIME_K_RE_LEN);
291                     pos += os_snprintf(pos, end - pos, "'");
292           }
293 
294           os_snprintf(pos, end - pos, ");");
295 
296           if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
297           {
298                     wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
299                     sqlite3_free(err);
300                     return -1;
301           }
302 
303           return 0;
304 }
305 
306 
get_reauth_cb(void * ctx,int argc,char * argv[],char * col[])307 static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[])
308 {
309           struct eap_sim_db_data *data = ctx;
310           int i;
311           struct eap_sim_reauth *reauth = &data->db_tmp_reauth;
312 
313           for (i = 0; i < argc; i++) {
314                     if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
315                               os_strlcpy(data->db_tmp_identity, argv[i],
316                                            sizeof(data->db_tmp_identity));
317                               reauth->permanent = data->db_tmp_identity;
318                     } else if (os_strcmp(col[i], "counter") == 0 && argv[i]) {
319                               reauth->counter = atoi(argv[i]);
320                     } else if (os_strcmp(col[i], "mk") == 0 && argv[i]) {
321                               hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk));
322                     } else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) {
323                               hexstr2bin(argv[i], reauth->k_encr,
324                                            sizeof(reauth->k_encr));
325                     } else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) {
326                               hexstr2bin(argv[i], reauth->k_aut,
327                                            sizeof(reauth->k_aut));
328                     } else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) {
329                               hexstr2bin(argv[i], reauth->k_re,
330                                            sizeof(reauth->k_re));
331                     }
332           }
333 
334           return 0;
335 }
336 
337 
338 static struct eap_sim_reauth *
db_get_reauth(struct eap_sim_db_data * data,const char * reauth_id)339 db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id)
340 {
341           char cmd[256];
342 
343           if (!valid_db_string(reauth_id))
344                     return NULL;
345           os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth));
346           os_strlcpy(data->db_tmp_pseudonym_str, reauth_id,
347                        sizeof(data->db_tmp_pseudonym_str));
348           data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str;
349           os_snprintf(cmd, sizeof(cmd),
350                         "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id);
351           if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) !=
352               SQLITE_OK)
353                     return NULL;
354           if (data->db_tmp_reauth.permanent == NULL)
355                     return NULL;
356           return &data->db_tmp_reauth;
357 }
358 
359 
db_remove_reauth(struct eap_sim_db_data * data,struct eap_sim_reauth * reauth)360 static void db_remove_reauth(struct eap_sim_db_data *data,
361                                    struct eap_sim_reauth *reauth)
362 {
363           char cmd[256];
364 
365           if (!valid_db_string(reauth->permanent))
366                     return;
367           os_snprintf(cmd, sizeof(cmd),
368                         "DELETE FROM reauth WHERE permanent='%s';",
369                         reauth->permanent);
370           sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL);
371 }
372 
373 #endif /* CONFIG_SQLITE */
374 
375 
376 static struct eap_sim_db_pending *
eap_sim_db_get_pending(struct eap_sim_db_data * data,const char * imsi,int aka)377 eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka)
378 {
379           struct eap_sim_db_pending *entry, *prev = NULL;
380 
381           entry = data->pending;
382           while (entry) {
383                     if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
384                               if (prev)
385                                         prev->next = entry->next;
386                               else
387                                         data->pending = entry->next;
388                               break;
389                     }
390                     prev = entry;
391                     entry = entry->next;
392           }
393           return entry;
394 }
395 
396 
eap_sim_db_add_pending(struct eap_sim_db_data * data,struct eap_sim_db_pending * entry)397 static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
398                                            struct eap_sim_db_pending *entry)
399 {
400           entry->next = data->pending;
401           data->pending = entry;
402 }
403 
404 
eap_sim_db_free_pending(struct eap_sim_db_data * data,struct eap_sim_db_pending * entry)405 static void eap_sim_db_free_pending(struct eap_sim_db_data *data,
406                                             struct eap_sim_db_pending *entry)
407 {
408           eloop_cancel_timeout(eap_sim_db_query_timeout, data, entry);
409           eloop_cancel_timeout(eap_sim_db_del_timeout, data, entry);
410           os_free(entry);
411 }
412 
413 
eap_sim_db_del_pending(struct eap_sim_db_data * data,struct eap_sim_db_pending * entry)414 static void eap_sim_db_del_pending(struct eap_sim_db_data *data,
415                                            struct eap_sim_db_pending *entry)
416 {
417           struct eap_sim_db_pending **pp = &data->pending;
418 
419           while (*pp != NULL) {
420                     if (*pp == entry) {
421                               *pp = entry->next;
422                               eap_sim_db_free_pending(data, entry);
423                               return;
424                     }
425                     pp = &(*pp)->next;
426           }
427 }
428 
429 
eap_sim_db_del_timeout(void * eloop_ctx,void * user_ctx)430 static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx)
431 {
432           struct eap_sim_db_data *data = eloop_ctx;
433           struct eap_sim_db_pending *entry = user_ctx;
434 
435           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Delete query timeout for %p", entry);
436           eap_sim_db_del_pending(data, entry);
437 }
438 
439 
eap_sim_db_query_timeout(void * eloop_ctx,void * user_ctx)440 static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx)
441 {
442           struct eap_sim_db_data *data = eloop_ctx;
443           struct eap_sim_db_pending *entry = user_ctx;
444 
445           /*
446            * Report failure and allow some time for EAP server to process it
447            * before deleting the query.
448            */
449           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Query timeout for %p", entry);
450           entry->state = FAILURE;
451           data->get_complete_cb(data->ctx, entry->cb_session_ctx);
452           eloop_register_timeout(1, 0, eap_sim_db_del_timeout, data, entry);
453 }
454 
455 
eap_sim_db_sim_resp_auth(struct eap_sim_db_data * data,const char * imsi,char * buf)456 static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
457                                              const char *imsi, char *buf)
458 {
459           char *start, *end, *pos;
460           struct eap_sim_db_pending *entry;
461           int num_chal;
462 
463           /*
464            * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
465            * SIM-RESP-AUTH <IMSI> FAILURE
466            * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
467            */
468 
469           entry = eap_sim_db_get_pending(data, imsi, 0);
470           if (entry == NULL) {
471                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
472                                  "received message found");
473                     return;
474           }
475 
476           start = buf;
477           if (os_strncmp(start, "FAILURE", 7) == 0) {
478                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
479                                  "failure");
480                     entry->state = FAILURE;
481                     eap_sim_db_add_pending(data, entry);
482                     data->get_complete_cb(data->ctx, entry->cb_session_ctx);
483                     return;
484           }
485 
486           num_chal = 0;
487           while (num_chal < EAP_SIM_MAX_CHAL) {
488                     end = os_strchr(start, ' ');
489                     if (end)
490                               *end = '\0';
491 
492                     pos = os_strchr(start, ':');
493                     if (pos == NULL)
494                               goto parse_fail;
495                     *pos = '\0';
496                     if (hexstr2bin(start, entry->u.sim.kc[num_chal],
497                                      EAP_SIM_KC_LEN))
498                               goto parse_fail;
499 
500                     start = pos + 1;
501                     pos = os_strchr(start, ':');
502                     if (pos == NULL)
503                               goto parse_fail;
504                     *pos = '\0';
505                     if (hexstr2bin(start, entry->u.sim.sres[num_chal],
506                                      EAP_SIM_SRES_LEN))
507                               goto parse_fail;
508 
509                     start = pos + 1;
510                     if (hexstr2bin(start, entry->u.sim.rand[num_chal],
511                                      GSM_RAND_LEN))
512                               goto parse_fail;
513 
514                     num_chal++;
515                     if (end == NULL)
516                               break;
517                     else
518                               start = end + 1;
519           }
520           entry->u.sim.num_chal = num_chal;
521 
522           entry->state = SUCCESS;
523           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
524                        "successfully - callback");
525           eap_sim_db_add_pending(data, entry);
526           data->get_complete_cb(data->ctx, entry->cb_session_ctx);
527           return;
528 
529 parse_fail:
530           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
531           eap_sim_db_free_pending(data, entry);
532 }
533 
534 
eap_sim_db_aka_resp_auth(struct eap_sim_db_data * data,const char * imsi,char * buf)535 static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
536                                              const char *imsi, char *buf)
537 {
538           char *start, *end;
539           struct eap_sim_db_pending *entry;
540 
541           /*
542            * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
543            * AKA-RESP-AUTH <IMSI> FAILURE
544            * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
545            */
546 
547           entry = eap_sim_db_get_pending(data, imsi, 1);
548           if (entry == NULL) {
549                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
550                                  "received message found");
551                     return;
552           }
553 
554           start = buf;
555           if (os_strncmp(start, "FAILURE", 7) == 0) {
556                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
557                                  "failure");
558                     entry->state = FAILURE;
559                     eap_sim_db_add_pending(data, entry);
560                     data->get_complete_cb(data->ctx, entry->cb_session_ctx);
561                     return;
562           }
563 
564           end = os_strchr(start, ' ');
565           if (end == NULL)
566                     goto parse_fail;
567           *end = '\0';
568           if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
569                     goto parse_fail;
570 
571           start = end + 1;
572           end = os_strchr(start, ' ');
573           if (end == NULL)
574                     goto parse_fail;
575           *end = '\0';
576           if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
577                     goto parse_fail;
578 
579           start = end + 1;
580           end = os_strchr(start, ' ');
581           if (end == NULL)
582                     goto parse_fail;
583           *end = '\0';
584           if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
585                     goto parse_fail;
586 
587           start = end + 1;
588           end = os_strchr(start, ' ');
589           if (end == NULL)
590                     goto parse_fail;
591           *end = '\0';
592           if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
593                     goto parse_fail;
594 
595           start = end + 1;
596           end = os_strchr(start, ' ');
597           if (end)
598                     *end = '\0';
599           else {
600                     end = start;
601                     while (*end)
602                               end++;
603           }
604           entry->u.aka.res_len = (end - start) / 2;
605           if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
606                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
607                     entry->u.aka.res_len = 0;
608                     goto parse_fail;
609           }
610           if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
611                     goto parse_fail;
612 
613           entry->state = SUCCESS;
614           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
615                        "successfully - callback");
616           eap_sim_db_add_pending(data, entry);
617           data->get_complete_cb(data->ctx, entry->cb_session_ctx);
618           return;
619 
620 parse_fail:
621           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
622           eap_sim_db_free_pending(data, entry);
623 }
624 
625 
eap_sim_db_receive(int sock,void * eloop_ctx,void * sock_ctx)626 static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
627 {
628           struct eap_sim_db_data *data = eloop_ctx;
629           char buf[1000], *pos, *cmd, *imsi;
630           int res;
631 
632           res = recv(sock, buf, sizeof(buf) - 1, 0);
633           if (res < 0)
634                     return;
635           buf[res] = '\0';
636           wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
637                                     "external source", (u8 *) buf, res);
638           if (res == 0)
639                     return;
640 
641           if (data->get_complete_cb == NULL) {
642                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
643                                  "registered");
644                     return;
645           }
646 
647           /* <cmd> <IMSI> ... */
648 
649           cmd = buf;
650           pos = os_strchr(cmd, ' ');
651           if (pos == NULL)
652                     goto parse_fail;
653           *pos = '\0';
654           imsi = pos + 1;
655           pos = os_strchr(imsi, ' ');
656           if (pos == NULL)
657                     goto parse_fail;
658           *pos = '\0';
659           wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
660                        cmd, imsi);
661 
662           if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
663                     eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
664           else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
665                     eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
666           else
667                     wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
668                                  "'%s'", cmd);
669           return;
670 
671 parse_fail:
672           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
673 }
674 
675 
eap_sim_db_open_socket(struct eap_sim_db_data * data)676 static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
677 {
678           struct sockaddr_un addr;
679           static int counter = 0;
680 
681           if (os_strncmp(data->fname, "unix:", 5) != 0)
682                     return -1;
683 
684           data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
685           if (data->sock < 0) {
686                     wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
687                     return -1;
688           }
689 
690           os_memset(&addr, 0, sizeof(addr));
691           addr.sun_family = AF_UNIX;
692           os_snprintf(addr.sun_path, sizeof(addr.sun_path),
693                         "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
694           os_free(data->local_sock);
695           data->local_sock = os_strdup(addr.sun_path);
696           if (data->local_sock == NULL) {
697                     close(data->sock);
698                     data->sock = -1;
699                     return -1;
700           }
701           if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
702                     wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
703                     close(data->sock);
704                     data->sock = -1;
705                     return -1;
706           }
707 
708           os_memset(&addr, 0, sizeof(addr));
709           addr.sun_family = AF_UNIX;
710           os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
711           if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
712                     wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
713                                  strerror(errno));
714                     wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
715                                           (u8 *) addr.sun_path,
716                                           os_strlen(addr.sun_path));
717                     close(data->sock);
718                     data->sock = -1;
719                     unlink(data->local_sock);
720                     os_free(data->local_sock);
721                     data->local_sock = NULL;
722                     return -1;
723           }
724 
725           eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
726 
727           return 0;
728 }
729 
730 
eap_sim_db_close_socket(struct eap_sim_db_data * data)731 static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
732 {
733           if (data->sock >= 0) {
734                     eloop_unregister_read_sock(data->sock);
735                     close(data->sock);
736                     data->sock = -1;
737           }
738           if (data->local_sock) {
739                     unlink(data->local_sock);
740                     os_free(data->local_sock);
741                     data->local_sock = NULL;
742           }
743 }
744 
745 
746 /**
747  * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
748  * @config: Configuration data (e.g., file name)
749  * @db_timeout: Database lookup timeout
750  * @get_complete_cb: Callback function for reporting availability of triplets
751  * @ctx: Context pointer for get_complete_cb
752  * Returns: Pointer to a private data structure or %NULL on failure
753  */
754 struct eap_sim_db_data *
eap_sim_db_init(const char * config,unsigned int db_timeout,void (* get_complete_cb)(void * ctx,void * session_ctx),void * ctx)755 eap_sim_db_init(const char *config, unsigned int db_timeout,
756                     void (*get_complete_cb)(void *ctx, void *session_ctx),
757                     void *ctx)
758 {
759           struct eap_sim_db_data *data;
760           char *pos;
761 
762           data = os_zalloc(sizeof(*data));
763           if (data == NULL)
764                     return NULL;
765 
766           data->sock = -1;
767           data->get_complete_cb = get_complete_cb;
768           data->ctx = ctx;
769           data->eap_sim_db_timeout = db_timeout;
770           data->fname = os_strdup(config);
771           if (data->fname == NULL)
772                     goto fail;
773           pos = os_strstr(data->fname, " db=");
774           if (pos) {
775                     *pos = '\0';
776 #ifdef CONFIG_SQLITE
777                     pos += 4;
778                     data->sqlite_db = db_open(pos);
779                     if (data->sqlite_db == NULL)
780                               goto fail;
781 #endif /* CONFIG_SQLITE */
782           }
783 
784           if (os_strncmp(data->fname, "unix:", 5) == 0) {
785                     if (eap_sim_db_open_socket(data)) {
786                               wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
787                                            "connection not available - will retry "
788                                            "later");
789                     }
790           }
791 
792           return data;
793 
794 fail:
795           eap_sim_db_close_socket(data);
796           os_free(data->fname);
797           os_free(data);
798           return NULL;
799 }
800 
801 
eap_sim_db_free_pseudonym(struct eap_sim_pseudonym * p)802 static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
803 {
804           os_free(p->permanent);
805           os_free(p->pseudonym);
806           os_free(p);
807 }
808 
809 
eap_sim_db_free_reauth(struct eap_sim_reauth * r)810 static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
811 {
812           os_free(r->permanent);
813           os_free(r->reauth_id);
814           os_free(r);
815 }
816 
817 
818 /**
819  * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
820  * @priv: Private data pointer from eap_sim_db_init()
821  */
eap_sim_db_deinit(void * priv)822 void eap_sim_db_deinit(void *priv)
823 {
824           struct eap_sim_db_data *data = priv;
825           struct eap_sim_pseudonym *p, *prev;
826           struct eap_sim_reauth *r, *prevr;
827           struct eap_sim_db_pending *pending, *prev_pending;
828 
829 #ifdef CONFIG_SQLITE
830           if (data->sqlite_db) {
831                     sqlite3_close(data->sqlite_db);
832                     data->sqlite_db = NULL;
833           }
834 #endif /* CONFIG_SQLITE */
835 
836           eap_sim_db_close_socket(data);
837           os_free(data->fname);
838 
839           p = data->pseudonyms;
840           while (p) {
841                     prev = p;
842                     p = p->next;
843                     eap_sim_db_free_pseudonym(prev);
844           }
845 
846           r = data->reauths;
847           while (r) {
848                     prevr = r;
849                     r = r->next;
850                     eap_sim_db_free_reauth(prevr);
851           }
852 
853           pending = data->pending;
854           while (pending) {
855                     prev_pending = pending;
856                     pending = pending->next;
857                     eap_sim_db_free_pending(data, prev_pending);
858           }
859 
860           os_free(data);
861 }
862 
863 
eap_sim_db_send(struct eap_sim_db_data * data,const char * msg,size_t len)864 static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
865                                  size_t len)
866 {
867           int _errno = 0;
868 
869           if (send(data->sock, msg, len, 0) < 0) {
870                     _errno = errno;
871                     wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
872                                  strerror(errno));
873           }
874 
875           if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
876               _errno == ECONNREFUSED) {
877                     /* Try to reconnect */
878                     eap_sim_db_close_socket(data);
879                     if (eap_sim_db_open_socket(data) < 0)
880                               return -1;
881                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
882                                  "external server");
883                     if (send(data->sock, msg, len, 0) < 0) {
884                               wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
885                                            strerror(errno));
886                               return -1;
887                     }
888           }
889 
890           return 0;
891 }
892 
893 
eap_sim_db_expire_pending(struct eap_sim_db_data * data,struct eap_sim_db_pending * entry)894 static void eap_sim_db_expire_pending(struct eap_sim_db_data *data,
895                                               struct eap_sim_db_pending *entry)
896 {
897           eloop_register_timeout(data->eap_sim_db_timeout, 0,
898                                      eap_sim_db_query_timeout, data, entry);
899 }
900 
901 
902 /**
903  * eap_sim_db_get_gsm_triplets - Get GSM triplets
904  * @data: Private data pointer from eap_sim_db_init()
905  * @username: Permanent username (prefix | IMSI)
906  * @max_chal: Maximum number of triplets
907  * @_rand: Buffer for RAND values
908  * @kc: Buffer for Kc values
909  * @sres: Buffer for SRES values
910  * @cb_session_ctx: Session callback context for get_complete_cb()
911  * Returns: Number of triplets received (has to be less than or equal to
912  * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
913  * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
914  * callback function registered with eap_sim_db_init() will be called once the
915  * results become available.
916  *
917  * When using an external server for GSM triplets, this function can always
918  * start a request and return EAP_SIM_DB_PENDING immediately if authentication
919  * triplets are not available. Once the triplets are received, callback
920  * function registered with eap_sim_db_init() is called to notify EAP state
921  * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
922  * function will then be called again and the newly received triplets will then
923  * be given to the caller.
924  */
eap_sim_db_get_gsm_triplets(struct eap_sim_db_data * data,const char * username,int max_chal,u8 * _rand,u8 * kc,u8 * sres,void * cb_session_ctx)925 int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
926                                         const char *username, int max_chal,
927                                         u8 *_rand, u8 *kc, u8 *sres,
928                                         void *cb_session_ctx)
929 {
930           struct eap_sim_db_pending *entry;
931           int len, ret;
932           char msg[40];
933           const char *imsi;
934           size_t imsi_len;
935 
936           if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
937               username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
938                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
939                                  username);
940                     return EAP_SIM_DB_FAILURE;
941           }
942           imsi = username + 1;
943           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
944                        imsi);
945 
946           entry = eap_sim_db_get_pending(data, imsi, 0);
947           if (entry) {
948                     int num_chal;
949                     if (entry->state == FAILURE) {
950                               wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
951                                            "failure");
952                               eap_sim_db_free_pending(data, entry);
953                               return EAP_SIM_DB_FAILURE;
954                     }
955 
956                     if (entry->state == PENDING) {
957                               wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
958                                            "still pending");
959                               eap_sim_db_add_pending(data, entry);
960                               return EAP_SIM_DB_PENDING;
961                     }
962 
963                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
964                                  "%d challenges", entry->u.sim.num_chal);
965                     num_chal = entry->u.sim.num_chal;
966                     if (num_chal > max_chal)
967                               num_chal = max_chal;
968                     os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
969                     os_memcpy(sres, entry->u.sim.sres,
970                                 num_chal * EAP_SIM_SRES_LEN);
971                     os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
972                     eap_sim_db_free_pending(data, entry);
973                     return num_chal;
974           }
975 
976           if (data->sock < 0) {
977                     if (eap_sim_db_open_socket(data) < 0)
978                               return EAP_SIM_DB_FAILURE;
979           }
980 
981           imsi_len = os_strlen(imsi);
982           len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
983           if (os_snprintf_error(sizeof(msg), len) ||
984               len + imsi_len >= sizeof(msg))
985                     return EAP_SIM_DB_FAILURE;
986           os_memcpy(msg + len, imsi, imsi_len);
987           len += imsi_len;
988           ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
989           if (os_snprintf_error(sizeof(msg) - len, ret))
990                     return EAP_SIM_DB_FAILURE;
991           len += ret;
992 
993           wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
994                        "data for IMSI '%s'", imsi);
995           if (eap_sim_db_send(data, msg, len) < 0)
996                     return EAP_SIM_DB_FAILURE;
997 
998           entry = os_zalloc(sizeof(*entry));
999           if (entry == NULL)
1000                     return EAP_SIM_DB_FAILURE;
1001 
1002           os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
1003           entry->cb_session_ctx = cb_session_ctx;
1004           entry->state = PENDING;
1005           eap_sim_db_add_pending(data, entry);
1006           eap_sim_db_expire_pending(data, entry);
1007           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
1008 
1009           return EAP_SIM_DB_PENDING;
1010 }
1011 
1012 
eap_sim_db_get_next(struct eap_sim_db_data * data,char prefix)1013 static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
1014 {
1015           char *id, *pos, *end;
1016           u8 buf[10];
1017 
1018           if (random_get_bytes(buf, sizeof(buf)))
1019                     return NULL;
1020           id = os_malloc(sizeof(buf) * 2 + 2);
1021           if (id == NULL)
1022                     return NULL;
1023 
1024           pos = id;
1025           end = id + sizeof(buf) * 2 + 2;
1026           *pos++ = prefix;
1027           wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
1028 
1029           return id;
1030 }
1031 
1032 
1033 /**
1034  * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
1035  * @data: Private data pointer from eap_sim_db_init()
1036  * @method: EAP method (SIM/AKA/AKA')
1037  * Returns: Next pseudonym (allocated string) or %NULL on failure
1038  *
1039  * This function is used to generate a pseudonym for EAP-SIM. The returned
1040  * pseudonym is not added to database at this point; it will need to be added
1041  * with eap_sim_db_add_pseudonym() once the authentication has been completed
1042  * successfully. Caller is responsible for freeing the returned buffer.
1043  */
eap_sim_db_get_next_pseudonym(struct eap_sim_db_data * data,enum eap_sim_db_method method)1044 char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
1045                                              enum eap_sim_db_method method)
1046 {
1047           char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1048 
1049           switch (method) {
1050           case EAP_SIM_DB_SIM:
1051                     prefix = EAP_SIM_PSEUDONYM_PREFIX;
1052                     break;
1053           case EAP_SIM_DB_AKA:
1054                     prefix = EAP_AKA_PSEUDONYM_PREFIX;
1055                     break;
1056           case EAP_SIM_DB_AKA_PRIME:
1057                     prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
1058                     break;
1059           }
1060 
1061           return eap_sim_db_get_next(data, prefix);
1062 }
1063 
1064 
1065 /**
1066  * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
1067  * @data: Private data pointer from eap_sim_db_init()
1068  * @method: EAP method (SIM/AKA/AKA')
1069  * Returns: Next reauth_id (allocated string) or %NULL on failure
1070  *
1071  * This function is used to generate a fast re-authentication identity for
1072  * EAP-SIM. The returned reauth_id is not added to database at this point; it
1073  * will need to be added with eap_sim_db_add_reauth() once the authentication
1074  * has been completed successfully. Caller is responsible for freeing the
1075  * returned buffer.
1076  */
eap_sim_db_get_next_reauth_id(struct eap_sim_db_data * data,enum eap_sim_db_method method)1077 char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
1078                                              enum eap_sim_db_method method)
1079 {
1080           char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1081 
1082           switch (method) {
1083           case EAP_SIM_DB_SIM:
1084                     prefix = EAP_SIM_REAUTH_ID_PREFIX;
1085                     break;
1086           case EAP_SIM_DB_AKA:
1087                     prefix = EAP_AKA_REAUTH_ID_PREFIX;
1088                     break;
1089           case EAP_SIM_DB_AKA_PRIME:
1090                     prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
1091                     break;
1092           }
1093 
1094           return eap_sim_db_get_next(data, prefix);
1095 }
1096 
1097 
1098 /**
1099  * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
1100  * @data: Private data pointer from eap_sim_db_init()
1101  * @permanent: Permanent username
1102  * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
1103  * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
1104  * free it.
1105  * Returns: 0 on success, -1 on failure
1106  *
1107  * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
1108  * responsible of freeing pseudonym buffer once it is not needed anymore.
1109  */
eap_sim_db_add_pseudonym(struct eap_sim_db_data * data,const char * permanent,char * pseudonym)1110 int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
1111                                    const char *permanent, char *pseudonym)
1112 {
1113           struct eap_sim_pseudonym *p;
1114           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
1115                        "username '%s'", pseudonym, permanent);
1116 
1117           /* TODO: could store last two pseudonyms */
1118 #ifdef CONFIG_SQLITE
1119           if (data->sqlite_db)
1120                     return db_add_pseudonym(data, permanent, pseudonym);
1121 #endif /* CONFIG_SQLITE */
1122           for (p = data->pseudonyms; p; p = p->next) {
1123                     if (os_strcmp(permanent, p->permanent) == 0)
1124                               break;
1125           }
1126           if (p) {
1127                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1128                                  "pseudonym: %s", p->pseudonym);
1129                     os_free(p->pseudonym);
1130                     p->pseudonym = pseudonym;
1131                     return 0;
1132           }
1133 
1134           p = os_zalloc(sizeof(*p));
1135           if (p == NULL) {
1136                     os_free(pseudonym);
1137                     return -1;
1138           }
1139 
1140           p->next = data->pseudonyms;
1141           p->permanent = os_strdup(permanent);
1142           if (p->permanent == NULL) {
1143                     os_free(p);
1144                     os_free(pseudonym);
1145                     return -1;
1146           }
1147           p->pseudonym = pseudonym;
1148           data->pseudonyms = p;
1149 
1150           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
1151           return 0;
1152 }
1153 
1154 
1155 static struct eap_sim_reauth *
eap_sim_db_add_reauth_data(struct eap_sim_db_data * data,const char * permanent,char * reauth_id,u16 counter)1156 eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
1157                                  const char *permanent,
1158                                  char *reauth_id, u16 counter)
1159 {
1160           struct eap_sim_reauth *r;
1161 
1162           for (r = data->reauths; r; r = r->next) {
1163                     if (os_strcmp(r->permanent, permanent) == 0)
1164                               break;
1165           }
1166 
1167           if (r) {
1168                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1169                                  "reauth_id: %s", r->reauth_id);
1170                     os_free(r->reauth_id);
1171                     r->reauth_id = reauth_id;
1172           } else {
1173                     r = os_zalloc(sizeof(*r));
1174                     if (r == NULL) {
1175                               os_free(reauth_id);
1176                               return NULL;
1177                     }
1178 
1179                     r->next = data->reauths;
1180                     r->permanent = os_strdup(permanent);
1181                     if (r->permanent == NULL) {
1182                               os_free(r);
1183                               os_free(reauth_id);
1184                               return NULL;
1185                     }
1186                     r->reauth_id = reauth_id;
1187                     data->reauths = r;
1188                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
1189           }
1190 
1191           r->counter = counter;
1192 
1193           return r;
1194 }
1195 
1196 
1197 /**
1198  * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
1199  * @priv: Private data pointer from eap_sim_db_init()
1200  * @permanent: Permanent username
1201  * @identity_len: Length of identity
1202  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1203  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1204  * free it.
1205  * @counter: AT_COUNTER value for fast re-authentication
1206  * @mk: 16-byte MK from the previous full authentication or %NULL
1207  * Returns: 0 on success, -1 on failure
1208  *
1209  * This function adds a new re-authentication entry for an EAP-SIM user.
1210  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1211  * anymore.
1212  */
eap_sim_db_add_reauth(struct eap_sim_db_data * data,const char * permanent,char * reauth_id,u16 counter,const u8 * mk)1213 int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
1214                                 char *reauth_id, u16 counter, const u8 *mk)
1215 {
1216           struct eap_sim_reauth *r;
1217 
1218           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
1219                        "identity '%s'", reauth_id, permanent);
1220 
1221 #ifdef CONFIG_SQLITE
1222           if (data->sqlite_db)
1223                     return db_add_reauth(data, permanent, reauth_id, counter, mk,
1224                                              NULL, NULL, NULL);
1225 #endif /* CONFIG_SQLITE */
1226           r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
1227           if (r == NULL)
1228                     return -1;
1229 
1230           os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
1231 
1232           return 0;
1233 }
1234 
1235 
1236 #ifdef EAP_SERVER_AKA_PRIME
1237 /**
1238  * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
1239  * @data: Private data pointer from eap_sim_db_init()
1240  * @permanent: Permanent username
1241  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1242  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1243  * free it.
1244  * @counter: AT_COUNTER value for fast re-authentication
1245  * @k_encr: K_encr from the previous full authentication
1246  * @k_aut: K_aut from the previous full authentication
1247  * @k_re: 32-byte K_re from the previous full authentication
1248  * Returns: 0 on success, -1 on failure
1249  *
1250  * This function adds a new re-authentication entry for an EAP-AKA' user.
1251  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1252  * anymore.
1253  */
eap_sim_db_add_reauth_prime(struct eap_sim_db_data * data,const char * permanent,char * reauth_id,u16 counter,const u8 * k_encr,const u8 * k_aut,const u8 * k_re)1254 int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
1255                                         const char *permanent, char *reauth_id,
1256                                         u16 counter, const u8 *k_encr,
1257                                         const u8 *k_aut, const u8 *k_re)
1258 {
1259           struct eap_sim_reauth *r;
1260 
1261           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
1262                        "identity '%s'", reauth_id, permanent);
1263 
1264 #ifdef CONFIG_SQLITE
1265           if (data->sqlite_db)
1266                     return db_add_reauth(data, permanent, reauth_id, counter, NULL,
1267                                              k_encr, k_aut, k_re);
1268 #endif /* CONFIG_SQLITE */
1269           r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
1270           if (r == NULL)
1271                     return -1;
1272 
1273           os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
1274           os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
1275           os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
1276 
1277           return 0;
1278 }
1279 #endif /* EAP_SERVER_AKA_PRIME */
1280 
1281 
1282 /**
1283  * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
1284  * @data: Private data pointer from eap_sim_db_init()
1285  * @pseudonym: Pseudonym username
1286  * Returns: Pointer to permanent username or %NULL if not found
1287  */
1288 const char *
eap_sim_db_get_permanent(struct eap_sim_db_data * data,const char * pseudonym)1289 eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
1290 {
1291           struct eap_sim_pseudonym *p;
1292 
1293 #ifdef CONFIG_SQLITE
1294           if (data->sqlite_db)
1295                     return db_get_pseudonym(data, pseudonym);
1296 #endif /* CONFIG_SQLITE */
1297 
1298           p = data->pseudonyms;
1299           while (p) {
1300                     if (os_strcmp(p->pseudonym, pseudonym) == 0)
1301                               return p->permanent;
1302                     p = p->next;
1303           }
1304 
1305           return NULL;
1306 }
1307 
1308 
1309 /**
1310  * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
1311  * @data: Private data pointer from eap_sim_db_init()
1312  * @reauth_id: Fast re-authentication username
1313  * Returns: Pointer to the re-auth entry, or %NULL if not found
1314  */
1315 struct eap_sim_reauth *
eap_sim_db_get_reauth_entry(struct eap_sim_db_data * data,const char * reauth_id)1316 eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
1317                                   const char *reauth_id)
1318 {
1319           struct eap_sim_reauth *r;
1320 
1321 #ifdef CONFIG_SQLITE
1322           if (data->sqlite_db)
1323                     return db_get_reauth(data, reauth_id);
1324 #endif /* CONFIG_SQLITE */
1325 
1326           r = data->reauths;
1327           while (r) {
1328                     if (os_strcmp(r->reauth_id, reauth_id) == 0)
1329                               break;
1330                     r = r->next;
1331           }
1332 
1333           return r;
1334 }
1335 
1336 
1337 /**
1338  * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
1339  * @data: Private data pointer from eap_sim_db_init()
1340  * @reauth: Pointer to re-authentication entry from
1341  * eap_sim_db_get_reauth_entry()
1342  */
eap_sim_db_remove_reauth(struct eap_sim_db_data * data,struct eap_sim_reauth * reauth)1343 void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
1344                                     struct eap_sim_reauth *reauth)
1345 {
1346           struct eap_sim_reauth *r, *prev = NULL;
1347 #ifdef CONFIG_SQLITE
1348           if (data->sqlite_db) {
1349                     db_remove_reauth(data, reauth);
1350                     return;
1351           }
1352 #endif /* CONFIG_SQLITE */
1353           r = data->reauths;
1354           while (r) {
1355                     if (r == reauth) {
1356                               if (prev)
1357                                         prev->next = r->next;
1358                               else
1359                                         data->reauths = r->next;
1360                               eap_sim_db_free_reauth(r);
1361                               return;
1362                     }
1363                     prev = r;
1364                     r = r->next;
1365           }
1366 }
1367 
1368 
1369 /**
1370  * eap_sim_db_get_aka_auth - Get AKA authentication values
1371  * @data: Private data pointer from eap_sim_db_init()
1372  * @username: Permanent username (prefix | IMSI)
1373  * @_rand: Buffer for RAND value
1374  * @autn: Buffer for AUTN value
1375  * @ik: Buffer for IK value
1376  * @ck: Buffer for CK value
1377  * @res: Buffer for RES value
1378  * @res_len: Buffer for RES length
1379  * @cb_session_ctx: Session callback context for get_complete_cb()
1380  * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
1381  * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
1382  * case, the callback function registered with eap_sim_db_init() will be
1383  * called once the results become available.
1384  *
1385  * When using an external server for AKA authentication, this function can
1386  * always start a request and return EAP_SIM_DB_PENDING immediately if
1387  * authentication triplets are not available. Once the authentication data are
1388  * received, callback function registered with eap_sim_db_init() is called to
1389  * notify EAP state machine to reprocess the message. This
1390  * eap_sim_db_get_aka_auth() function will then be called again and the newly
1391  * received triplets will then be given to the caller.
1392  */
eap_sim_db_get_aka_auth(struct eap_sim_db_data * data,const char * username,u8 * _rand,u8 * autn,u8 * ik,u8 * ck,u8 * res,size_t * res_len,void * cb_session_ctx)1393 int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
1394                                   u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
1395                                   u8 *res, size_t *res_len, void *cb_session_ctx)
1396 {
1397           struct eap_sim_db_pending *entry;
1398           int len;
1399           char msg[40];
1400           const char *imsi;
1401           size_t imsi_len;
1402 
1403           if (username == NULL ||
1404               (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1405                username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1406               username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
1407                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1408                                  username);
1409                     return EAP_SIM_DB_FAILURE;
1410           }
1411           imsi = username + 1;
1412           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1413                        imsi);
1414 
1415           entry = eap_sim_db_get_pending(data, imsi, 1);
1416           if (entry) {
1417                     if (entry->state == FAILURE) {
1418                               eap_sim_db_free_pending(data, entry);
1419                               wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
1420                               return EAP_SIM_DB_FAILURE;
1421                     }
1422 
1423                     if (entry->state == PENDING) {
1424                               eap_sim_db_add_pending(data, entry);
1425                               wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
1426                               return EAP_SIM_DB_PENDING;
1427                     }
1428 
1429                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
1430                                  "received authentication data");
1431                     os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
1432                     os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
1433                     os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
1434                     os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
1435                     os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
1436                     *res_len = entry->u.aka.res_len;
1437                     eap_sim_db_free_pending(data, entry);
1438                     return 0;
1439           }
1440 
1441           if (data->sock < 0) {
1442                     if (eap_sim_db_open_socket(data) < 0)
1443                               return EAP_SIM_DB_FAILURE;
1444           }
1445 
1446           imsi_len = os_strlen(imsi);
1447           len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
1448           if (os_snprintf_error(sizeof(msg), len) ||
1449               len + imsi_len >= sizeof(msg))
1450                     return EAP_SIM_DB_FAILURE;
1451           os_memcpy(msg + len, imsi, imsi_len);
1452           len += imsi_len;
1453 
1454           wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
1455                         "data for IMSI '%s'", imsi);
1456           if (eap_sim_db_send(data, msg, len) < 0)
1457                     return EAP_SIM_DB_FAILURE;
1458 
1459           entry = os_zalloc(sizeof(*entry));
1460           if (entry == NULL)
1461                     return EAP_SIM_DB_FAILURE;
1462 
1463           entry->aka = 1;
1464           os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
1465           entry->cb_session_ctx = cb_session_ctx;
1466           entry->state = PENDING;
1467           eap_sim_db_add_pending(data, entry);
1468           eap_sim_db_expire_pending(data, entry);
1469           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
1470 
1471           return EAP_SIM_DB_PENDING;
1472 }
1473 
1474 
1475 /**
1476  * eap_sim_db_resynchronize - Resynchronize AKA AUTN
1477  * @data: Private data pointer from eap_sim_db_init()
1478  * @username: Permanent username
1479  * @auts: AUTS value from the peer
1480  * @_rand: RAND value used in the rejected message
1481  * Returns: 0 on success, -1 on failure
1482  *
1483  * This function is called when the peer reports synchronization failure in the
1484  * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
1485  * HLR/AuC to allow it to resynchronize with the peer. After this,
1486  * eap_sim_db_get_aka_auth() will be called again to to fetch updated
1487  * RAND/AUTN values for the next challenge.
1488  */
eap_sim_db_resynchronize(struct eap_sim_db_data * data,const char * username,const u8 * auts,const u8 * _rand)1489 int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
1490                                    const char *username,
1491                                    const u8 *auts, const u8 *_rand)
1492 {
1493           const char *imsi;
1494           size_t imsi_len;
1495 
1496           if (username == NULL ||
1497               (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1498                username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1499               username[1] == '\0' || os_strlen(username) > 20) {
1500                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1501                                  username);
1502                     return -1;
1503           }
1504           imsi = username + 1;
1505           wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1506                        imsi);
1507 
1508           if (data->sock >= 0) {
1509                     char msg[100];
1510                     int len, ret;
1511 
1512                     imsi_len = os_strlen(imsi);
1513                     len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
1514                     if (os_snprintf_error(sizeof(msg), len) ||
1515                         len + imsi_len >= sizeof(msg))
1516                               return -1;
1517                     os_memcpy(msg + len, imsi, imsi_len);
1518                     len += imsi_len;
1519 
1520                     ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1521                     if (os_snprintf_error(sizeof(msg) - len, ret))
1522                               return -1;
1523                     len += ret;
1524                     len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1525                                                   auts, EAP_AKA_AUTS_LEN);
1526                     ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1527                     if (os_snprintf_error(sizeof(msg) - len, ret))
1528                               return -1;
1529                     len += ret;
1530                     len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1531                                                   _rand, EAP_AKA_RAND_LEN);
1532                     wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
1533                                  "IMSI '%s'", imsi);
1534                     if (eap_sim_db_send(data, msg, len) < 0)
1535                               return -1;
1536           }
1537 
1538           return 0;
1539 }
1540 
1541 
1542 /**
1543  * sim_get_username - Extract username from SIM identity
1544  * @identity: Identity
1545  * @identity_len: Identity length
1546  * Returns: Allocated buffer with the username part of the identity
1547  *
1548  * Caller is responsible for freeing the returned buffer with os_free().
1549  */
sim_get_username(const u8 * identity,size_t identity_len)1550 char * sim_get_username(const u8 *identity, size_t identity_len)
1551 {
1552           size_t pos;
1553 
1554           if (identity == NULL)
1555                     return NULL;
1556 
1557           for (pos = 0; pos < identity_len; pos++) {
1558                     if (identity[pos] == '@' || identity[pos] == '\0')
1559                               break;
1560           }
1561 
1562           return dup_binstr(identity, pos);
1563 }
1564