Line data Source code
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 :
86 12 : static int db_table_exists(sqlite3 *db, const char *name)
87 : {
88 : char cmd[128];
89 12 : os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
90 12 : return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
91 : }
92 :
93 :
94 6 : static int db_table_create_pseudonym(sqlite3 *db)
95 : {
96 6 : char *err = NULL;
97 6 : const char *sql =
98 : "CREATE TABLE pseudonyms("
99 : " permanent CHAR(21) PRIMARY KEY,"
100 : " pseudonym CHAR(21) NOT NULL"
101 : ");";
102 :
103 6 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
104 : "pseudonym information");
105 6 : if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
106 0 : wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
107 0 : sqlite3_free(err);
108 0 : return -1;
109 : }
110 :
111 6 : return 0;
112 : }
113 :
114 :
115 6 : static int db_table_create_reauth(sqlite3 *db)
116 : {
117 6 : char *err = NULL;
118 6 : 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 6 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
130 : "reauth information");
131 6 : if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
132 0 : wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
133 0 : sqlite3_free(err);
134 0 : return -1;
135 : }
136 :
137 6 : return 0;
138 : }
139 :
140 :
141 6 : static sqlite3 * db_open(const char *db_file)
142 : {
143 : sqlite3 *db;
144 :
145 6 : if (sqlite3_open(db_file, &db)) {
146 0 : wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
147 : "%s: %s", db_file, sqlite3_errmsg(db));
148 0 : sqlite3_close(db);
149 0 : return NULL;
150 : }
151 :
152 12 : if (!db_table_exists(db, "pseudonyms") &&
153 6 : db_table_create_pseudonym(db) < 0) {
154 0 : sqlite3_close(db);
155 0 : return NULL;
156 : }
157 :
158 12 : if (!db_table_exists(db, "reauth") &&
159 6 : db_table_create_reauth(db) < 0) {
160 0 : sqlite3_close(db);
161 0 : return NULL;
162 : }
163 :
164 6 : return db;
165 : }
166 :
167 :
168 121 : static int valid_db_string(const char *str)
169 : {
170 121 : const char *pos = str;
171 2558 : while (*pos) {
172 2907 : if ((*pos < '0' || *pos > '9') &&
173 1182 : (*pos < 'a' || *pos > 'f'))
174 0 : return 0;
175 2316 : pos++;
176 : }
177 121 : return 1;
178 : }
179 :
180 :
181 18 : static int db_add_pseudonym(struct eap_sim_db_data *data,
182 : const char *permanent, char *pseudonym)
183 : {
184 : char cmd[128];
185 18 : char *err = NULL;
186 :
187 18 : if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) {
188 0 : os_free(pseudonym);
189 0 : return -1;
190 : }
191 :
192 18 : os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
193 : "(permanent, pseudonym) VALUES ('%s', '%s');",
194 : permanent, pseudonym);
195 18 : os_free(pseudonym);
196 18 : if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
197 : {
198 0 : wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
199 0 : sqlite3_free(err);
200 0 : return -1;
201 : }
202 :
203 18 : return 0;
204 : }
205 :
206 :
207 6 : static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
208 : {
209 6 : struct eap_sim_db_data *data = ctx;
210 : int i;
211 :
212 12 : for (i = 0; i < argc; i++) {
213 6 : if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
214 6 : os_strlcpy(data->db_tmp_identity, argv[i],
215 : sizeof(data->db_tmp_identity));
216 : }
217 : }
218 :
219 6 : return 0;
220 : }
221 :
222 :
223 : static char *
224 9 : db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
225 : {
226 : char cmd[128];
227 :
228 9 : if (!valid_db_string(pseudonym))
229 0 : return NULL;
230 9 : os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity));
231 9 : os_snprintf(cmd, sizeof(cmd),
232 : "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';",
233 : pseudonym);
234 9 : if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
235 : SQLITE_OK)
236 0 : return NULL;
237 9 : if (data->db_tmp_identity[0] == '\0')
238 3 : return NULL;
239 6 : return data->db_tmp_identity;
240 : }
241 :
242 :
243 24 : 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 24 : char *err = NULL;
249 :
250 24 : if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) {
251 0 : os_free(reauth_id);
252 0 : return -1;
253 : }
254 :
255 24 : pos = cmd;
256 24 : end = pos + sizeof(cmd);
257 24 : 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 24 : os_free(reauth_id);
266 :
267 24 : if (mk) {
268 16 : pos += os_snprintf(pos, end - pos, ", '");
269 16 : pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN);
270 16 : pos += os_snprintf(pos, end - pos, "'");
271 : }
272 :
273 24 : if (k_encr) {
274 8 : pos += os_snprintf(pos, end - pos, ", '");
275 8 : pos += wpa_snprintf_hex(pos, end - pos, k_encr,
276 : EAP_SIM_K_ENCR_LEN);
277 8 : pos += os_snprintf(pos, end - pos, "'");
278 : }
279 :
280 24 : if (k_aut) {
281 8 : pos += os_snprintf(pos, end - pos, ", '");
282 8 : pos += wpa_snprintf_hex(pos, end - pos, k_aut,
283 : EAP_AKA_PRIME_K_AUT_LEN);
284 8 : pos += os_snprintf(pos, end - pos, "'");
285 : }
286 :
287 24 : if (k_re) {
288 8 : pos += os_snprintf(pos, end - pos, ", '");
289 8 : pos += wpa_snprintf_hex(pos, end - pos, k_re,
290 : EAP_AKA_PRIME_K_RE_LEN);
291 8 : pos += os_snprintf(pos, end - pos, "'");
292 : }
293 :
294 24 : os_snprintf(pos, end - pos, ");");
295 :
296 24 : if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
297 : {
298 0 : wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
299 0 : sqlite3_free(err);
300 0 : return -1;
301 : }
302 :
303 24 : return 0;
304 : }
305 :
306 :
307 15 : static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[])
308 : {
309 15 : struct eap_sim_db_data *data = ctx;
310 : int i;
311 15 : struct eap_sim_reauth *reauth = &data->db_tmp_reauth;
312 :
313 120 : for (i = 0; i < argc; i++) {
314 105 : if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
315 15 : os_strlcpy(data->db_tmp_identity, argv[i],
316 : sizeof(data->db_tmp_identity));
317 15 : reauth->permanent = data->db_tmp_identity;
318 90 : } else if (os_strcmp(col[i], "counter") == 0 && argv[i]) {
319 15 : reauth->counter = atoi(argv[i]);
320 75 : } else if (os_strcmp(col[i], "mk") == 0 && argv[i]) {
321 10 : hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk));
322 65 : } else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) {
323 5 : hexstr2bin(argv[i], reauth->k_encr,
324 : sizeof(reauth->k_encr));
325 60 : } else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) {
326 5 : hexstr2bin(argv[i], reauth->k_aut,
327 : sizeof(reauth->k_aut));
328 55 : } else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) {
329 5 : hexstr2bin(argv[i], reauth->k_re,
330 : sizeof(reauth->k_re));
331 : }
332 : }
333 :
334 15 : return 0;
335 : }
336 :
337 :
338 : static struct eap_sim_reauth *
339 25 : db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id)
340 : {
341 : char cmd[256];
342 :
343 25 : if (!valid_db_string(reauth_id))
344 0 : return NULL;
345 25 : os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth));
346 25 : os_strlcpy(data->db_tmp_pseudonym_str, reauth_id,
347 : sizeof(data->db_tmp_pseudonym_str));
348 25 : data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str;
349 25 : os_snprintf(cmd, sizeof(cmd),
350 : "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id);
351 25 : if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) !=
352 : SQLITE_OK)
353 0 : return NULL;
354 25 : if (data->db_tmp_reauth.permanent == NULL)
355 10 : return NULL;
356 15 : return &data->db_tmp_reauth;
357 : }
358 :
359 :
360 3 : static void db_remove_reauth(struct eap_sim_db_data *data,
361 : struct eap_sim_reauth *reauth)
362 : {
363 : char cmd[256];
364 :
365 3 : if (!valid_db_string(reauth->permanent))
366 3 : return;
367 3 : os_snprintf(cmd, sizeof(cmd),
368 : "DELETE FROM reauth WHERE permanent='%s';",
369 : reauth->permanent);
370 3 : sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL);
371 : }
372 :
373 : #endif /* CONFIG_SQLITE */
374 :
375 :
376 : static struct eap_sim_db_pending *
377 438 : eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka)
378 : {
379 438 : struct eap_sim_db_pending *entry, *prev = NULL;
380 :
381 438 : entry = data->pending;
382 876 : while (entry) {
383 291 : if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
384 291 : if (prev)
385 0 : prev->next = entry->next;
386 : else
387 291 : data->pending = entry->next;
388 291 : break;
389 : }
390 0 : prev = entry;
391 0 : entry = entry->next;
392 : }
393 438 : return entry;
394 : }
395 :
396 :
397 291 : static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
398 : struct eap_sim_db_pending *entry)
399 : {
400 291 : entry->next = data->pending;
401 291 : data->pending = entry;
402 291 : }
403 :
404 :
405 146 : static void eap_sim_db_free_pending(struct eap_sim_db_data *data,
406 : struct eap_sim_db_pending *entry)
407 : {
408 146 : eloop_cancel_timeout(eap_sim_db_query_timeout, data, entry);
409 146 : eloop_cancel_timeout(eap_sim_db_del_timeout, data, entry);
410 146 : os_free(entry);
411 146 : }
412 :
413 :
414 0 : static void eap_sim_db_del_pending(struct eap_sim_db_data *data,
415 : struct eap_sim_db_pending *entry)
416 : {
417 0 : struct eap_sim_db_pending **pp = &data->pending;
418 :
419 0 : while (*pp != NULL) {
420 0 : if (*pp == entry) {
421 0 : *pp = entry->next;
422 0 : eap_sim_db_free_pending(data, entry);
423 0 : return;
424 : }
425 0 : pp = &(*pp)->next;
426 : }
427 : }
428 :
429 :
430 0 : static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx)
431 : {
432 0 : struct eap_sim_db_data *data = eloop_ctx;
433 0 : struct eap_sim_db_pending *entry = user_ctx;
434 :
435 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Delete query timeout for %p", entry);
436 0 : eap_sim_db_del_pending(data, entry);
437 0 : }
438 :
439 :
440 1 : static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx)
441 : {
442 1 : struct eap_sim_db_data *data = eloop_ctx;
443 1 : 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 1 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Query timeout for %p", entry);
450 1 : entry->state = FAILURE;
451 1 : data->get_complete_cb(data->ctx, entry->cb_session_ctx);
452 1 : eloop_register_timeout(1, 0, eap_sim_db_del_timeout, data, entry);
453 1 : }
454 :
455 :
456 76 : 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 76 : entry = eap_sim_db_get_pending(data, imsi, 0);
470 76 : if (entry == NULL) {
471 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
472 : "received message found");
473 0 : return;
474 : }
475 :
476 76 : start = buf;
477 76 : if (os_strncmp(start, "FAILURE", 7) == 0) {
478 1 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
479 : "failure");
480 1 : entry->state = FAILURE;
481 1 : eap_sim_db_add_pending(data, entry);
482 1 : data->get_complete_cb(data->ctx, entry->cb_session_ctx);
483 1 : return;
484 : }
485 :
486 75 : num_chal = 0;
487 300 : while (num_chal < EAP_SIM_MAX_CHAL) {
488 225 : end = os_strchr(start, ' ');
489 225 : if (end)
490 150 : *end = '\0';
491 :
492 225 : pos = os_strchr(start, ':');
493 225 : if (pos == NULL)
494 0 : goto parse_fail;
495 225 : *pos = '\0';
496 225 : if (hexstr2bin(start, entry->u.sim.kc[num_chal],
497 : EAP_SIM_KC_LEN))
498 0 : goto parse_fail;
499 :
500 225 : start = pos + 1;
501 225 : pos = os_strchr(start, ':');
502 225 : if (pos == NULL)
503 0 : goto parse_fail;
504 225 : *pos = '\0';
505 225 : if (hexstr2bin(start, entry->u.sim.sres[num_chal],
506 : EAP_SIM_SRES_LEN))
507 0 : goto parse_fail;
508 :
509 225 : start = pos + 1;
510 225 : if (hexstr2bin(start, entry->u.sim.rand[num_chal],
511 : GSM_RAND_LEN))
512 0 : goto parse_fail;
513 :
514 225 : num_chal++;
515 225 : if (end == NULL)
516 75 : break;
517 : else
518 150 : start = end + 1;
519 : }
520 75 : entry->u.sim.num_chal = num_chal;
521 :
522 75 : entry->state = SUCCESS;
523 75 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
524 : "successfully - callback");
525 75 : eap_sim_db_add_pending(data, entry);
526 75 : data->get_complete_cb(data->ctx, entry->cb_session_ctx);
527 75 : return;
528 :
529 : parse_fail:
530 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
531 0 : eap_sim_db_free_pending(data, entry);
532 : }
533 :
534 :
535 69 : 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 69 : entry = eap_sim_db_get_pending(data, imsi, 1);
548 69 : if (entry == NULL) {
549 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
550 : "received message found");
551 0 : return;
552 : }
553 :
554 69 : start = buf;
555 69 : if (os_strncmp(start, "FAILURE", 7) == 0) {
556 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
557 : "failure");
558 0 : entry->state = FAILURE;
559 0 : eap_sim_db_add_pending(data, entry);
560 0 : data->get_complete_cb(data->ctx, entry->cb_session_ctx);
561 0 : return;
562 : }
563 :
564 69 : end = os_strchr(start, ' ');
565 69 : if (end == NULL)
566 0 : goto parse_fail;
567 69 : *end = '\0';
568 69 : if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
569 0 : goto parse_fail;
570 :
571 69 : start = end + 1;
572 69 : end = os_strchr(start, ' ');
573 69 : if (end == NULL)
574 0 : goto parse_fail;
575 69 : *end = '\0';
576 69 : if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
577 0 : goto parse_fail;
578 :
579 69 : start = end + 1;
580 69 : end = os_strchr(start, ' ');
581 69 : if (end == NULL)
582 0 : goto parse_fail;
583 69 : *end = '\0';
584 69 : if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
585 0 : goto parse_fail;
586 :
587 69 : start = end + 1;
588 69 : end = os_strchr(start, ' ');
589 69 : if (end == NULL)
590 0 : goto parse_fail;
591 69 : *end = '\0';
592 69 : if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
593 0 : goto parse_fail;
594 :
595 69 : start = end + 1;
596 69 : end = os_strchr(start, ' ');
597 69 : if (end)
598 0 : *end = '\0';
599 : else {
600 69 : end = start;
601 1242 : while (*end)
602 1104 : end++;
603 : }
604 69 : entry->u.aka.res_len = (end - start) / 2;
605 69 : if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
606 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
607 0 : entry->u.aka.res_len = 0;
608 0 : goto parse_fail;
609 : }
610 69 : if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
611 0 : goto parse_fail;
612 :
613 69 : entry->state = SUCCESS;
614 69 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
615 : "successfully - callback");
616 69 : eap_sim_db_add_pending(data, entry);
617 69 : data->get_complete_cb(data->ctx, entry->cb_session_ctx);
618 69 : return;
619 :
620 : parse_fail:
621 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
622 0 : eap_sim_db_free_pending(data, entry);
623 : }
624 :
625 :
626 150 : static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
627 : {
628 150 : struct eap_sim_db_data *data = eloop_ctx;
629 : char buf[1000], *pos, *cmd, *imsi;
630 : int res;
631 :
632 150 : res = recv(sock, buf, sizeof(buf) - 1, 0);
633 150 : if (res < 0)
634 148 : return;
635 150 : buf[res] = '\0';
636 150 : wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
637 : "external source", (u8 *) buf, res);
638 150 : if (res == 0)
639 2 : return;
640 :
641 148 : if (data->get_complete_cb == NULL) {
642 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
643 : "registered");
644 0 : return;
645 : }
646 :
647 : /* <cmd> <IMSI> ... */
648 :
649 148 : cmd = buf;
650 148 : pos = os_strchr(cmd, ' ');
651 148 : if (pos == NULL)
652 1 : goto parse_fail;
653 147 : *pos = '\0';
654 147 : imsi = pos + 1;
655 147 : pos = os_strchr(imsi, ' ');
656 147 : if (pos == NULL)
657 1 : goto parse_fail;
658 146 : *pos = '\0';
659 146 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
660 : cmd, imsi);
661 :
662 146 : if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
663 76 : eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
664 70 : else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
665 69 : eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
666 : else
667 1 : wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
668 : "'%s'", cmd);
669 146 : return;
670 :
671 : parse_fail:
672 2 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
673 : }
674 :
675 :
676 20 : 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 20 : if (os_strncmp(data->fname, "unix:", 5) != 0)
682 0 : return -1;
683 :
684 20 : data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
685 20 : if (data->sock < 0) {
686 0 : wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
687 0 : return -1;
688 : }
689 :
690 20 : os_memset(&addr, 0, sizeof(addr));
691 20 : addr.sun_family = AF_UNIX;
692 20 : os_snprintf(addr.sun_path, sizeof(addr.sun_path),
693 : "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
694 20 : os_free(data->local_sock);
695 20 : data->local_sock = os_strdup(addr.sun_path);
696 20 : if (data->local_sock == NULL) {
697 0 : close(data->sock);
698 0 : data->sock = -1;
699 0 : return -1;
700 : }
701 20 : if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
702 0 : wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
703 0 : close(data->sock);
704 0 : data->sock = -1;
705 0 : return -1;
706 : }
707 :
708 20 : os_memset(&addr, 0, sizeof(addr));
709 20 : addr.sun_family = AF_UNIX;
710 20 : os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
711 20 : if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
712 2 : wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
713 2 : strerror(errno));
714 2 : wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
715 : (u8 *) addr.sun_path,
716 : os_strlen(addr.sun_path));
717 2 : close(data->sock);
718 2 : data->sock = -1;
719 2 : unlink(data->local_sock);
720 2 : os_free(data->local_sock);
721 2 : data->local_sock = NULL;
722 2 : return -1;
723 : }
724 :
725 18 : eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
726 :
727 18 : return 0;
728 : }
729 :
730 :
731 18 : static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
732 : {
733 18 : if (data->sock >= 0) {
734 18 : eloop_unregister_read_sock(data->sock);
735 18 : close(data->sock);
736 18 : data->sock = -1;
737 : }
738 18 : if (data->local_sock) {
739 18 : unlink(data->local_sock);
740 18 : os_free(data->local_sock);
741 18 : data->local_sock = NULL;
742 : }
743 18 : }
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 *
755 18 : 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 18 : data = os_zalloc(sizeof(*data));
763 18 : if (data == NULL)
764 0 : return NULL;
765 :
766 18 : data->sock = -1;
767 18 : data->get_complete_cb = get_complete_cb;
768 18 : data->ctx = ctx;
769 18 : data->eap_sim_db_timeout = db_timeout;
770 18 : data->fname = os_strdup(config);
771 18 : if (data->fname == NULL)
772 0 : goto fail;
773 18 : pos = os_strstr(data->fname, " db=");
774 18 : if (pos) {
775 6 : *pos = '\0';
776 : #ifdef CONFIG_SQLITE
777 6 : pos += 4;
778 6 : data->sqlite_db = db_open(pos);
779 6 : if (data->sqlite_db == NULL)
780 0 : goto fail;
781 : #endif /* CONFIG_SQLITE */
782 : }
783 :
784 18 : if (os_strncmp(data->fname, "unix:", 5) == 0) {
785 18 : if (eap_sim_db_open_socket(data)) {
786 1 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
787 : "connection not available - will retry "
788 : "later");
789 : }
790 : }
791 :
792 18 : return data;
793 :
794 : fail:
795 0 : eap_sim_db_close_socket(data);
796 0 : os_free(data->fname);
797 0 : os_free(data);
798 0 : return NULL;
799 : }
800 :
801 :
802 28 : static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
803 : {
804 28 : os_free(p->permanent);
805 28 : os_free(p->pseudonym);
806 28 : os_free(p);
807 28 : }
808 :
809 :
810 28 : static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
811 : {
812 28 : os_free(r->permanent);
813 28 : os_free(r->reauth_id);
814 28 : os_free(r);
815 28 : }
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 : */
822 18 : void eap_sim_db_deinit(void *priv)
823 : {
824 18 : 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 18 : if (data->sqlite_db) {
831 6 : sqlite3_close(data->sqlite_db);
832 6 : data->sqlite_db = NULL;
833 : }
834 : #endif /* CONFIG_SQLITE */
835 :
836 18 : eap_sim_db_close_socket(data);
837 18 : os_free(data->fname);
838 :
839 18 : p = data->pseudonyms;
840 64 : while (p) {
841 28 : prev = p;
842 28 : p = p->next;
843 28 : eap_sim_db_free_pseudonym(prev);
844 : }
845 :
846 18 : r = data->reauths;
847 64 : while (r) {
848 28 : prevr = r;
849 28 : r = r->next;
850 28 : eap_sim_db_free_reauth(prevr);
851 : }
852 :
853 18 : pending = data->pending;
854 36 : while (pending) {
855 0 : prev_pending = pending;
856 0 : pending = pending->next;
857 0 : eap_sim_db_free_pending(data, prev_pending);
858 : }
859 :
860 18 : os_free(data);
861 18 : }
862 :
863 :
864 151 : static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
865 : size_t len)
866 : {
867 151 : int _errno = 0;
868 :
869 151 : if (send(data->sock, msg, len, 0) < 0) {
870 0 : _errno = errno;
871 0 : wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
872 0 : strerror(errno));
873 : }
874 :
875 151 : if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
876 : _errno == ECONNREFUSED) {
877 : /* Try to reconnect */
878 0 : eap_sim_db_close_socket(data);
879 0 : if (eap_sim_db_open_socket(data) < 0)
880 0 : return -1;
881 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
882 : "external server");
883 0 : if (send(data->sock, msg, len, 0) < 0) {
884 0 : wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
885 0 : strerror(errno));
886 0 : return -1;
887 : }
888 : }
889 :
890 151 : return 0;
891 : }
892 :
893 :
894 146 : static void eap_sim_db_expire_pending(struct eap_sim_db_data *data,
895 : struct eap_sim_db_pending *entry)
896 : {
897 146 : eloop_register_timeout(data->eap_sim_db_timeout, 0,
898 : eap_sim_db_query_timeout, data, entry);
899 146 : }
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 : */
925 155 : 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 310 : if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
937 310 : username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
938 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
939 : username);
940 0 : return EAP_SIM_DB_FAILURE;
941 : }
942 155 : imsi = username + 1;
943 155 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
944 : imsi);
945 :
946 155 : entry = eap_sim_db_get_pending(data, imsi, 0);
947 155 : if (entry) {
948 : int num_chal;
949 77 : if (entry->state == FAILURE) {
950 2 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
951 : "failure");
952 2 : eap_sim_db_free_pending(data, entry);
953 2 : return EAP_SIM_DB_FAILURE;
954 : }
955 :
956 75 : if (entry->state == PENDING) {
957 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
958 : "still pending");
959 0 : eap_sim_db_add_pending(data, entry);
960 0 : return EAP_SIM_DB_PENDING;
961 : }
962 :
963 75 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
964 : "%d challenges", entry->u.sim.num_chal);
965 75 : num_chal = entry->u.sim.num_chal;
966 75 : if (num_chal > max_chal)
967 0 : num_chal = max_chal;
968 75 : os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
969 75 : os_memcpy(sres, entry->u.sim.sres,
970 : num_chal * EAP_SIM_SRES_LEN);
971 75 : os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
972 75 : eap_sim_db_free_pending(data, entry);
973 75 : return num_chal;
974 : }
975 :
976 78 : if (data->sock < 0) {
977 2 : if (eap_sim_db_open_socket(data) < 0)
978 1 : return EAP_SIM_DB_FAILURE;
979 : }
980 :
981 77 : imsi_len = os_strlen(imsi);
982 77 : len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
983 154 : if (os_snprintf_error(sizeof(msg), len) ||
984 77 : len + imsi_len >= sizeof(msg))
985 0 : return EAP_SIM_DB_FAILURE;
986 77 : os_memcpy(msg + len, imsi, imsi_len);
987 77 : len += imsi_len;
988 77 : ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
989 77 : if (os_snprintf_error(sizeof(msg) - len, ret))
990 0 : return EAP_SIM_DB_FAILURE;
991 77 : len += ret;
992 :
993 77 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
994 : "data for IMSI '%s'", imsi);
995 77 : if (eap_sim_db_send(data, msg, len) < 0)
996 0 : return EAP_SIM_DB_FAILURE;
997 :
998 77 : entry = os_zalloc(sizeof(*entry));
999 77 : if (entry == NULL)
1000 0 : return EAP_SIM_DB_FAILURE;
1001 :
1002 77 : os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
1003 77 : entry->cb_session_ctx = cb_session_ctx;
1004 77 : entry->state = PENDING;
1005 77 : eap_sim_db_add_pending(data, entry);
1006 77 : eap_sim_db_expire_pending(data, entry);
1007 77 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
1008 :
1009 77 : return EAP_SIM_DB_PENDING;
1010 : }
1011 :
1012 :
1013 319 : 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 319 : if (random_get_bytes(buf, sizeof(buf)))
1019 0 : return NULL;
1020 319 : id = os_malloc(sizeof(buf) * 2 + 2);
1021 319 : if (id == NULL)
1022 0 : return NULL;
1023 :
1024 319 : pos = id;
1025 319 : end = id + sizeof(buf) * 2 + 2;
1026 319 : *pos++ = prefix;
1027 319 : wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
1028 :
1029 319 : 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 : */
1044 144 : char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
1045 : enum eap_sim_db_method method)
1046 : {
1047 144 : char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1048 :
1049 144 : switch (method) {
1050 : case EAP_SIM_DB_SIM:
1051 75 : prefix = EAP_SIM_PSEUDONYM_PREFIX;
1052 75 : break;
1053 : case EAP_SIM_DB_AKA:
1054 51 : prefix = EAP_AKA_PSEUDONYM_PREFIX;
1055 51 : break;
1056 : case EAP_SIM_DB_AKA_PRIME:
1057 18 : prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
1058 18 : break;
1059 : }
1060 :
1061 144 : 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 : */
1077 175 : char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
1078 : enum eap_sim_db_method method)
1079 : {
1080 175 : char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1081 :
1082 175 : switch (method) {
1083 : case EAP_SIM_DB_SIM:
1084 89 : prefix = EAP_SIM_REAUTH_ID_PREFIX;
1085 89 : break;
1086 : case EAP_SIM_DB_AKA:
1087 60 : prefix = EAP_AKA_REAUTH_ID_PREFIX;
1088 60 : break;
1089 : case EAP_SIM_DB_AKA_PRIME:
1090 26 : prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
1091 26 : break;
1092 : }
1093 :
1094 175 : 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 : */
1110 83 : 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 83 : 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 83 : if (data->sqlite_db)
1120 18 : return db_add_pseudonym(data, permanent, pseudonym);
1121 : #endif /* CONFIG_SQLITE */
1122 102 : for (p = data->pseudonyms; p; p = p->next) {
1123 74 : if (os_strcmp(permanent, p->permanent) == 0)
1124 37 : break;
1125 : }
1126 65 : if (p) {
1127 37 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1128 : "pseudonym: %s", p->pseudonym);
1129 37 : os_free(p->pseudonym);
1130 37 : p->pseudonym = pseudonym;
1131 37 : return 0;
1132 : }
1133 :
1134 28 : p = os_zalloc(sizeof(*p));
1135 28 : if (p == NULL) {
1136 0 : os_free(pseudonym);
1137 0 : return -1;
1138 : }
1139 :
1140 28 : p->next = data->pseudonyms;
1141 28 : p->permanent = os_strdup(permanent);
1142 28 : if (p->permanent == NULL) {
1143 0 : os_free(p);
1144 0 : os_free(pseudonym);
1145 0 : return -1;
1146 : }
1147 28 : p->pseudonym = pseudonym;
1148 28 : data->pseudonyms = p;
1149 :
1150 28 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
1151 28 : return 0;
1152 : }
1153 :
1154 :
1155 : static struct eap_sim_reauth *
1156 79 : 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 117 : for (r = data->reauths; r; r = r->next) {
1163 89 : if (os_strcmp(r->permanent, permanent) == 0)
1164 51 : break;
1165 : }
1166 :
1167 79 : if (r) {
1168 51 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1169 : "reauth_id: %s", r->reauth_id);
1170 51 : os_free(r->reauth_id);
1171 51 : r->reauth_id = reauth_id;
1172 : } else {
1173 28 : r = os_zalloc(sizeof(*r));
1174 28 : if (r == NULL) {
1175 0 : os_free(reauth_id);
1176 0 : return NULL;
1177 : }
1178 :
1179 28 : r->next = data->reauths;
1180 28 : r->permanent = os_strdup(permanent);
1181 28 : if (r->permanent == NULL) {
1182 0 : os_free(r);
1183 0 : os_free(reauth_id);
1184 0 : return NULL;
1185 : }
1186 28 : r->reauth_id = reauth_id;
1187 28 : data->reauths = r;
1188 28 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
1189 : }
1190 :
1191 79 : r->counter = counter;
1192 :
1193 79 : 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 : */
1213 85 : 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 85 : 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 85 : if (data->sqlite_db)
1223 16 : return db_add_reauth(data, permanent, reauth_id, counter, mk,
1224 : NULL, NULL, NULL);
1225 : #endif /* CONFIG_SQLITE */
1226 69 : r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
1227 69 : if (r == NULL)
1228 0 : return -1;
1229 :
1230 69 : os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
1231 :
1232 69 : 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 : */
1254 18 : 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 18 : 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 18 : if (data->sqlite_db)
1266 8 : return db_add_reauth(data, permanent, reauth_id, counter, NULL,
1267 : k_encr, k_aut, k_re);
1268 : #endif /* CONFIG_SQLITE */
1269 10 : r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
1270 10 : if (r == NULL)
1271 0 : return -1;
1272 :
1273 10 : os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
1274 10 : os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
1275 10 : os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
1276 :
1277 10 : 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 *
1289 18 : 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 18 : if (data->sqlite_db)
1295 9 : return db_get_pseudonym(data, pseudonym);
1296 : #endif /* CONFIG_SQLITE */
1297 :
1298 9 : p = data->pseudonyms;
1299 19 : while (p) {
1300 7 : if (os_strcmp(p->pseudonym, pseudonym) == 0)
1301 6 : return p->permanent;
1302 1 : p = p->next;
1303 : }
1304 :
1305 3 : 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 *
1316 44 : 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 44 : if (data->sqlite_db)
1323 25 : return db_get_reauth(data, reauth_id);
1324 : #endif /* CONFIG_SQLITE */
1325 :
1326 19 : r = data->reauths;
1327 39 : while (r) {
1328 20 : if (os_strcmp(r->reauth_id, reauth_id) == 0)
1329 19 : break;
1330 1 : r = r->next;
1331 : }
1332 :
1333 19 : 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 : */
1343 3 : void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
1344 : struct eap_sim_reauth *reauth)
1345 : {
1346 3 : struct eap_sim_reauth *r, *prev = NULL;
1347 : #ifdef CONFIG_SQLITE
1348 3 : if (data->sqlite_db) {
1349 3 : db_remove_reauth(data, reauth);
1350 3 : return;
1351 : }
1352 : #endif /* CONFIG_SQLITE */
1353 0 : r = data->reauths;
1354 0 : while (r) {
1355 0 : if (r == reauth) {
1356 0 : if (prev)
1357 0 : prev->next = r->next;
1358 : else
1359 0 : data->reauths = r->next;
1360 0 : eap_sim_db_free_reauth(r);
1361 0 : return;
1362 : }
1363 0 : prev = r;
1364 0 : 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 : */
1393 138 : 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 276 : if (username == NULL ||
1404 174 : (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1405 174 : username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1406 276 : username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
1407 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1408 : username);
1409 0 : return EAP_SIM_DB_FAILURE;
1410 : }
1411 138 : imsi = username + 1;
1412 138 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1413 : imsi);
1414 :
1415 138 : entry = eap_sim_db_get_pending(data, imsi, 1);
1416 138 : if (entry) {
1417 69 : if (entry->state == FAILURE) {
1418 0 : eap_sim_db_free_pending(data, entry);
1419 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
1420 0 : return EAP_SIM_DB_FAILURE;
1421 : }
1422 :
1423 69 : if (entry->state == PENDING) {
1424 0 : eap_sim_db_add_pending(data, entry);
1425 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
1426 0 : return EAP_SIM_DB_PENDING;
1427 : }
1428 :
1429 69 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
1430 : "received authentication data");
1431 69 : os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
1432 69 : os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
1433 69 : os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
1434 69 : os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
1435 69 : os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
1436 69 : *res_len = entry->u.aka.res_len;
1437 69 : eap_sim_db_free_pending(data, entry);
1438 69 : return 0;
1439 : }
1440 :
1441 69 : if (data->sock < 0) {
1442 0 : if (eap_sim_db_open_socket(data) < 0)
1443 0 : return EAP_SIM_DB_FAILURE;
1444 : }
1445 :
1446 69 : imsi_len = os_strlen(imsi);
1447 69 : len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
1448 138 : if (os_snprintf_error(sizeof(msg), len) ||
1449 69 : len + imsi_len >= sizeof(msg))
1450 0 : return EAP_SIM_DB_FAILURE;
1451 69 : os_memcpy(msg + len, imsi, imsi_len);
1452 69 : len += imsi_len;
1453 :
1454 69 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
1455 : "data for IMSI '%s'", imsi);
1456 69 : if (eap_sim_db_send(data, msg, len) < 0)
1457 0 : return EAP_SIM_DB_FAILURE;
1458 :
1459 69 : entry = os_zalloc(sizeof(*entry));
1460 69 : if (entry == NULL)
1461 0 : return EAP_SIM_DB_FAILURE;
1462 :
1463 69 : entry->aka = 1;
1464 69 : os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
1465 69 : entry->cb_session_ctx = cb_session_ctx;
1466 69 : entry->state = PENDING;
1467 69 : eap_sim_db_add_pending(data, entry);
1468 69 : eap_sim_db_expire_pending(data, entry);
1469 69 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
1470 :
1471 69 : 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 : */
1489 5 : 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 10 : if (username == NULL ||
1497 5 : (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1498 5 : username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1499 10 : username[1] == '\0' || os_strlen(username) > 20) {
1500 0 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1501 : username);
1502 0 : return -1;
1503 : }
1504 5 : imsi = username + 1;
1505 5 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1506 : imsi);
1507 :
1508 5 : if (data->sock >= 0) {
1509 : char msg[100];
1510 : int len, ret;
1511 :
1512 5 : imsi_len = os_strlen(imsi);
1513 5 : len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
1514 10 : if (os_snprintf_error(sizeof(msg), len) ||
1515 5 : len + imsi_len >= sizeof(msg))
1516 0 : return -1;
1517 5 : os_memcpy(msg + len, imsi, imsi_len);
1518 5 : len += imsi_len;
1519 :
1520 5 : ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1521 5 : if (os_snprintf_error(sizeof(msg) - len, ret))
1522 0 : return -1;
1523 5 : len += ret;
1524 5 : len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1525 : auts, EAP_AKA_AUTS_LEN);
1526 5 : ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1527 5 : if (os_snprintf_error(sizeof(msg) - len, ret))
1528 0 : return -1;
1529 5 : len += ret;
1530 5 : len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1531 : _rand, EAP_AKA_RAND_LEN);
1532 5 : wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
1533 : "IMSI '%s'", imsi);
1534 5 : if (eap_sim_db_send(data, msg, len) < 0)
1535 0 : return -1;
1536 : }
1537 :
1538 5 : 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 : */
1550 385 : char * sim_get_username(const u8 *identity, size_t identity_len)
1551 : {
1552 : size_t pos;
1553 :
1554 385 : if (identity == NULL)
1555 0 : return NULL;
1556 :
1557 6812 : for (pos = 0; pos < identity_len; pos++) {
1558 6466 : if (identity[pos] == '@' || identity[pos] == '\0')
1559 : break;
1560 : }
1561 :
1562 385 : return dup_binstr(identity, pos);
1563 : }
|