00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "includes.h"
00025 #include <sys/un.h>
00026
00027 #include "common.h"
00028 #include "eap_common/eap_sim_common.h"
00029 #include "eap_server/eap_sim_db.h"
00030 #include "eloop.h"
00031
00032 struct eap_sim_pseudonym {
00033 struct eap_sim_pseudonym *next;
00034 u8 *identity;
00035 size_t identity_len;
00036 char *pseudonym;
00037 };
00038
00039 struct eap_sim_db_pending {
00040 struct eap_sim_db_pending *next;
00041 u8 imsi[20];
00042 size_t imsi_len;
00043 enum { PENDING, SUCCESS, FAILURE } state;
00044 void *cb_session_ctx;
00045 struct os_time timestamp;
00046 int aka;
00047 union {
00048 struct {
00049 u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
00050 u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
00051 u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
00052 int num_chal;
00053 } sim;
00054 struct {
00055 u8 rand[EAP_AKA_RAND_LEN];
00056 u8 autn[EAP_AKA_AUTN_LEN];
00057 u8 ik[EAP_AKA_IK_LEN];
00058 u8 ck[EAP_AKA_CK_LEN];
00059 u8 res[EAP_AKA_RES_MAX_LEN];
00060 size_t res_len;
00061 } aka;
00062 } u;
00063 };
00064
00065 struct eap_sim_db_data {
00066 int sock;
00067 char *fname;
00068 char *local_sock;
00069 void (*get_complete_cb)(void *ctx, void *session_ctx);
00070 void *ctx;
00071 struct eap_sim_pseudonym *pseudonyms;
00072 struct eap_sim_reauth *reauths;
00073 struct eap_sim_db_pending *pending;
00074 };
00075
00076
00077 static struct eap_sim_db_pending *
00078 eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
00079 size_t imsi_len, int aka)
00080 {
00081 struct eap_sim_db_pending *entry, *prev = NULL;
00082
00083 entry = data->pending;
00084 while (entry) {
00085 if (entry->aka == aka && entry->imsi_len == imsi_len &&
00086 os_memcmp(entry->imsi, imsi, imsi_len) == 0) {
00087 if (prev)
00088 prev->next = entry->next;
00089 else
00090 data->pending = entry->next;
00091 break;
00092 }
00093 prev = entry;
00094 entry = entry->next;
00095 }
00096 return entry;
00097 }
00098
00099
00100 static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
00101 struct eap_sim_db_pending *entry)
00102 {
00103 entry->next = data->pending;
00104 data->pending = entry;
00105 }
00106
00107
00108 static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
00109 const char *imsi, char *buf)
00110 {
00111 char *start, *end, *pos;
00112 struct eap_sim_db_pending *entry;
00113 int num_chal;
00114
00115
00116
00117
00118
00119
00120
00121 entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0);
00122 if (entry == NULL) {
00123 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
00124 "received message found");
00125 return;
00126 }
00127
00128 start = buf;
00129 if (os_strncmp(start, "FAILURE", 7) == 0) {
00130 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
00131 "failure");
00132 entry->state = FAILURE;
00133 eap_sim_db_add_pending(data, entry);
00134 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
00135 return;
00136 }
00137
00138 num_chal = 0;
00139 while (num_chal < EAP_SIM_MAX_CHAL) {
00140 end = os_strchr(start, ' ');
00141 if (end)
00142 *end = '\0';
00143
00144 pos = os_strchr(start, ':');
00145 if (pos == NULL)
00146 goto parse_fail;
00147 *pos = '\0';
00148 if (hexstr2bin(start, entry->u.sim.kc[num_chal],
00149 EAP_SIM_KC_LEN))
00150 goto parse_fail;
00151
00152 start = pos + 1;
00153 pos = os_strchr(start, ':');
00154 if (pos == NULL)
00155 goto parse_fail;
00156 *pos = '\0';
00157 if (hexstr2bin(start, entry->u.sim.sres[num_chal],
00158 EAP_SIM_SRES_LEN))
00159 goto parse_fail;
00160
00161 start = pos + 1;
00162 if (hexstr2bin(start, entry->u.sim.rand[num_chal],
00163 GSM_RAND_LEN))
00164 goto parse_fail;
00165
00166 num_chal++;
00167 if (end == NULL)
00168 break;
00169 else
00170 start = end + 1;
00171 }
00172 entry->u.sim.num_chal = num_chal;
00173
00174 entry->state = SUCCESS;
00175 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
00176 "successfully - callback");
00177 eap_sim_db_add_pending(data, entry);
00178 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
00179 return;
00180
00181 parse_fail:
00182 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
00183 os_free(entry);
00184 }
00185
00186
00187 static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
00188 const char *imsi, char *buf)
00189 {
00190 char *start, *end;
00191 struct eap_sim_db_pending *entry;
00192
00193
00194
00195
00196
00197
00198
00199 entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1);
00200 if (entry == NULL) {
00201 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
00202 "received message found");
00203 return;
00204 }
00205
00206 start = buf;
00207 if (os_strncmp(start, "FAILURE", 7) == 0) {
00208 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
00209 "failure");
00210 entry->state = FAILURE;
00211 eap_sim_db_add_pending(data, entry);
00212 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
00213 return;
00214 }
00215
00216 end = os_strchr(start, ' ');
00217 if (end == NULL)
00218 goto parse_fail;
00219 *end = '\0';
00220 if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
00221 goto parse_fail;
00222
00223 start = end + 1;
00224 end = os_strchr(start, ' ');
00225 if (end == NULL)
00226 goto parse_fail;
00227 *end = '\0';
00228 if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
00229 goto parse_fail;
00230
00231 start = end + 1;
00232 end = os_strchr(start, ' ');
00233 if (end == NULL)
00234 goto parse_fail;
00235 *end = '\0';
00236 if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
00237 goto parse_fail;
00238
00239 start = end + 1;
00240 end = os_strchr(start, ' ');
00241 if (end == NULL)
00242 goto parse_fail;
00243 *end = '\0';
00244 if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
00245 goto parse_fail;
00246
00247 start = end + 1;
00248 end = os_strchr(start, ' ');
00249 if (end)
00250 *end = '\0';
00251 else {
00252 end = start;
00253 while (*end)
00254 end++;
00255 }
00256 entry->u.aka.res_len = (end - start) / 2;
00257 if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
00258 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
00259 entry->u.aka.res_len = 0;
00260 goto parse_fail;
00261 }
00262 if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
00263 goto parse_fail;
00264
00265 entry->state = SUCCESS;
00266 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
00267 "successfully - callback");
00268 eap_sim_db_add_pending(data, entry);
00269 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
00270 return;
00271
00272 parse_fail:
00273 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
00274 os_free(entry);
00275 }
00276
00277
00278 static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
00279 {
00280 struct eap_sim_db_data *data = eloop_ctx;
00281 char buf[1000], *pos, *cmd, *imsi;
00282 int res;
00283
00284 res = recv(sock, buf, sizeof(buf), 0);
00285 if (res < 0)
00286 return;
00287 wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
00288 "external source", (u8 *) buf, res);
00289 if (res == 0)
00290 return;
00291 if (res >= (int) sizeof(buf))
00292 res = sizeof(buf) - 1;
00293 buf[res] = '\0';
00294
00295 if (data->get_complete_cb == NULL) {
00296 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
00297 "registered");
00298 return;
00299 }
00300
00301
00302
00303 cmd = buf;
00304 pos = os_strchr(cmd, ' ');
00305 if (pos == NULL)
00306 goto parse_fail;
00307 *pos = '\0';
00308 imsi = pos + 1;
00309 pos = os_strchr(imsi, ' ');
00310 if (pos == NULL)
00311 goto parse_fail;
00312 *pos = '\0';
00313 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
00314 cmd, imsi);
00315
00316 if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
00317 eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
00318 else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
00319 eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
00320 else
00321 wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
00322 "'%s'", cmd);
00323 return;
00324
00325 parse_fail:
00326 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
00327 }
00328
00329
00330 static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
00331 {
00332 struct sockaddr_un addr;
00333 static int counter = 0;
00334
00335 if (os_strncmp(data->fname, "unix:", 5) != 0)
00336 return -1;
00337
00338 data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
00339 if (data->sock < 0) {
00340 perror("socket(eap_sim_db)");
00341 return -1;
00342 }
00343
00344 os_memset(&addr, 0, sizeof(addr));
00345 addr.sun_family = AF_UNIX;
00346 os_snprintf(addr.sun_path, sizeof(addr.sun_path),
00347 "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
00348 data->local_sock = os_strdup(addr.sun_path);
00349 if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00350 perror("bind(eap_sim_db)");
00351 close(data->sock);
00352 data->sock = -1;
00353 return -1;
00354 }
00355
00356 os_memset(&addr, 0, sizeof(addr));
00357 addr.sun_family = AF_UNIX;
00358 os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
00359 if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00360 perror("connect(eap_sim_db)");
00361 wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
00362 (u8 *) addr.sun_path,
00363 os_strlen(addr.sun_path));
00364 close(data->sock);
00365 data->sock = -1;
00366 return -1;
00367 }
00368
00369 eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
00370
00371 return 0;
00372 }
00373
00374
00375 static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
00376 {
00377 if (data->sock >= 0) {
00378 eloop_unregister_read_sock(data->sock);
00379 close(data->sock);
00380 data->sock = -1;
00381 }
00382 if (data->local_sock) {
00383 unlink(data->local_sock);
00384 os_free(data->local_sock);
00385 data->local_sock = NULL;
00386 }
00387 }
00388
00389
00397 void * eap_sim_db_init(const char *config,
00398 void (*get_complete_cb)(void *ctx, void *session_ctx),
00399 void *ctx)
00400 {
00401 struct eap_sim_db_data *data;
00402
00403 data = os_zalloc(sizeof(*data));
00404 if (data == NULL)
00405 return NULL;
00406
00407 data->sock = -1;
00408 data->get_complete_cb = get_complete_cb;
00409 data->ctx = ctx;
00410 data->fname = os_strdup(config);
00411 if (data->fname == NULL)
00412 goto fail;
00413
00414 if (os_strncmp(data->fname, "unix:", 5) == 0) {
00415 if (eap_sim_db_open_socket(data))
00416 goto fail;
00417 }
00418
00419 return data;
00420
00421 fail:
00422 eap_sim_db_close_socket(data);
00423 os_free(data->fname);
00424 os_free(data);
00425 return NULL;
00426 }
00427
00428
00429 static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
00430 {
00431 os_free(p->identity);
00432 os_free(p->pseudonym);
00433 os_free(p);
00434 }
00435
00436
00437 static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
00438 {
00439 os_free(r->identity);
00440 os_free(r->reauth_id);
00441 os_free(r);
00442 }
00443
00444
00449 void eap_sim_db_deinit(void *priv)
00450 {
00451 struct eap_sim_db_data *data = priv;
00452 struct eap_sim_pseudonym *p, *prev;
00453 struct eap_sim_reauth *r, *prevr;
00454 struct eap_sim_db_pending *pending, *prev_pending;
00455
00456 eap_sim_db_close_socket(data);
00457 os_free(data->fname);
00458
00459 p = data->pseudonyms;
00460 while (p) {
00461 prev = p;
00462 p = p->next;
00463 eap_sim_db_free_pseudonym(prev);
00464 }
00465
00466 r = data->reauths;
00467 while (r) {
00468 prevr = r;
00469 r = r->next;
00470 eap_sim_db_free_reauth(prevr);
00471 }
00472
00473 pending = data->pending;
00474 while (pending) {
00475 prev_pending = pending;
00476 pending = pending->next;
00477 os_free(prev_pending);
00478 }
00479
00480 os_free(data);
00481 }
00482
00483
00484 static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
00485 size_t len)
00486 {
00487 int _errno = 0;
00488
00489 if (send(data->sock, msg, len, 0) < 0) {
00490 _errno = errno;
00491 perror("send[EAP-SIM DB UNIX]");
00492 }
00493
00494 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
00495 _errno == ECONNREFUSED) {
00496
00497 eap_sim_db_close_socket(data);
00498 if (eap_sim_db_open_socket(data) < 0)
00499 return -1;
00500 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
00501 "external server");
00502 if (send(data->sock, msg, len, 0) < 0) {
00503 perror("send[EAP-SIM DB UNIX]");
00504 return -1;
00505 }
00506 }
00507
00508 return 0;
00509 }
00510
00511
00512 static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
00513 {
00514
00515
00516
00517 }
00518
00519
00547 int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
00548 size_t identity_len, int max_chal,
00549 u8 *_rand, u8 *kc, u8 *sres,
00550 void *cb_session_ctx)
00551 {
00552 struct eap_sim_db_data *data = priv;
00553 struct eap_sim_db_pending *entry;
00554 int len, ret;
00555 size_t i;
00556 char msg[40];
00557
00558 if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) {
00559 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
00560 identity, identity_len);
00561 return EAP_SIM_DB_FAILURE;
00562 }
00563 identity++;
00564 identity_len--;
00565 for (i = 0; i < identity_len; i++) {
00566 if (identity[i] == '@') {
00567 identity_len = i;
00568 break;
00569 }
00570 }
00571 if (identity_len + 1 > sizeof(entry->imsi)) {
00572 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
00573 identity, identity_len);
00574 return EAP_SIM_DB_FAILURE;
00575 }
00576 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
00577 identity, identity_len);
00578
00579 entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
00580 if (entry) {
00581 int num_chal;
00582 if (entry->state == FAILURE) {
00583 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
00584 "failure");
00585 os_free(entry);
00586 return EAP_SIM_DB_FAILURE;
00587 }
00588
00589 if (entry->state == PENDING) {
00590 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
00591 "still pending");
00592 eap_sim_db_add_pending(data, entry);
00593 return EAP_SIM_DB_PENDING;
00594 }
00595
00596 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
00597 "%d challenges", entry->u.sim.num_chal);
00598 num_chal = entry->u.sim.num_chal;
00599 if (num_chal > max_chal)
00600 num_chal = max_chal;
00601 os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
00602 os_memcpy(sres, entry->u.sim.sres,
00603 num_chal * EAP_SIM_SRES_LEN);
00604 os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
00605 os_free(entry);
00606 return num_chal;
00607 }
00608
00609 if (data->sock < 0) {
00610 if (eap_sim_db_open_socket(data) < 0)
00611 return EAP_SIM_DB_FAILURE;
00612 }
00613
00614 len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
00615 if (len < 0 || len + identity_len >= sizeof(msg))
00616 return EAP_SIM_DB_FAILURE;
00617 os_memcpy(msg + len, identity, identity_len);
00618 len += identity_len;
00619 ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
00620 if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
00621 return EAP_SIM_DB_FAILURE;
00622 len += ret;
00623
00624 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
00625 "data for IMSI", identity, identity_len);
00626 if (eap_sim_db_send(data, msg, len) < 0)
00627 return EAP_SIM_DB_FAILURE;
00628
00629 entry = os_zalloc(sizeof(*entry));
00630 if (entry == NULL)
00631 return EAP_SIM_DB_FAILURE;
00632
00633 os_get_time(&entry->timestamp);
00634 os_memcpy(entry->imsi, identity, identity_len);
00635 entry->imsi_len = identity_len;
00636 entry->cb_session_ctx = cb_session_ctx;
00637 entry->state = PENDING;
00638 eap_sim_db_add_pending(data, entry);
00639 eap_sim_db_expire_pending(data);
00640
00641 return EAP_SIM_DB_PENDING;
00642 }
00643
00644
00645 static struct eap_sim_pseudonym *
00646 eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
00647 size_t identity_len)
00648 {
00649 char *pseudonym;
00650 size_t len;
00651 struct eap_sim_pseudonym *p;
00652
00653 if (identity_len == 0 ||
00654 (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
00655 identity[0] != EAP_AKA_PSEUDONYM_PREFIX))
00656 return NULL;
00657
00658
00659 len = 0;
00660 while (len < identity_len) {
00661 if (identity[len] == '@')
00662 break;
00663 len++;
00664 }
00665
00666 pseudonym = os_malloc(len + 1);
00667 if (pseudonym == NULL)
00668 return NULL;
00669 os_memcpy(pseudonym, identity, len);
00670 pseudonym[len] = '\0';
00671
00672 p = data->pseudonyms;
00673 while (p) {
00674 if (os_strcmp(p->pseudonym, pseudonym) == 0)
00675 break;
00676 p = p->next;
00677 }
00678
00679 os_free(pseudonym);
00680
00681 return p;
00682 }
00683
00684
00685 static struct eap_sim_pseudonym *
00686 eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
00687 size_t identity_len)
00688 {
00689 struct eap_sim_pseudonym *p;
00690
00691 if (identity_len == 0 ||
00692 (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
00693 identity[0] != EAP_AKA_PERMANENT_PREFIX))
00694 return NULL;
00695
00696 p = data->pseudonyms;
00697 while (p) {
00698 if (identity_len == p->identity_len &&
00699 os_memcmp(p->identity, identity, identity_len) == 0)
00700 break;
00701 p = p->next;
00702 }
00703
00704 return p;
00705 }
00706
00707
00708 static struct eap_sim_reauth *
00709 eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
00710 size_t identity_len)
00711 {
00712 char *reauth_id;
00713 size_t len;
00714 struct eap_sim_reauth *r;
00715
00716 if (identity_len == 0 ||
00717 (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
00718 identity[0] != EAP_AKA_REAUTH_ID_PREFIX))
00719 return NULL;
00720
00721
00722 len = 0;
00723 while (len < identity_len) {
00724 if (identity[len] == '@')
00725 break;
00726 len++;
00727 }
00728
00729 reauth_id = os_malloc(len + 1);
00730 if (reauth_id == NULL)
00731 return NULL;
00732 os_memcpy(reauth_id, identity, len);
00733 reauth_id[len] = '\0';
00734
00735 r = data->reauths;
00736 while (r) {
00737 if (os_strcmp(r->reauth_id, reauth_id) == 0)
00738 break;
00739 r = r->next;
00740 }
00741
00742 os_free(reauth_id);
00743
00744 return r;
00745 }
00746
00747
00748 static struct eap_sim_reauth *
00749 eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
00750 size_t identity_len)
00751 {
00752 struct eap_sim_pseudonym *p;
00753 struct eap_sim_reauth *r;
00754
00755 if (identity_len == 0)
00756 return NULL;
00757
00758 p = eap_sim_db_get_pseudonym(data, identity, identity_len);
00759 if (p == NULL)
00760 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
00761 if (p) {
00762 identity = p->identity;
00763 identity_len = p->identity_len;
00764 }
00765
00766 r = data->reauths;
00767 while (r) {
00768 if (identity_len == r->identity_len &&
00769 os_memcmp(r->identity, identity, identity_len) == 0)
00770 break;
00771 r = r->next;
00772 }
00773
00774 return r;
00775 }
00776
00777
00788 int eap_sim_db_identity_known(void *priv, const u8 *identity,
00789 size_t identity_len)
00790 {
00791 struct eap_sim_db_data *data = priv;
00792
00793 if (identity == NULL || identity_len < 2)
00794 return -1;
00795
00796 if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
00797 identity[0] == EAP_AKA_PSEUDONYM_PREFIX) {
00798 struct eap_sim_pseudonym *p =
00799 eap_sim_db_get_pseudonym(data, identity, identity_len);
00800 return p ? 0 : -1;
00801 }
00802
00803 if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
00804 identity[0] == EAP_AKA_REAUTH_ID_PREFIX) {
00805 struct eap_sim_reauth *r =
00806 eap_sim_db_get_reauth(data, identity, identity_len);
00807 return r ? 0 : -1;
00808 }
00809
00810 if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
00811 identity[0] != EAP_AKA_PERMANENT_PREFIX) {
00812
00813 return -1;
00814 }
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 return -1;
00825 }
00826
00827
00828 static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
00829 {
00830 char *id, *pos, *end;
00831 u8 buf[10];
00832
00833 if (os_get_random(buf, sizeof(buf)))
00834 return NULL;
00835 id = os_malloc(sizeof(buf) * 2 + 2);
00836 if (id == NULL)
00837 return NULL;
00838
00839 pos = id;
00840 end = id + sizeof(buf) * 2 + 2;
00841 *pos++ = prefix;
00842 pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
00843
00844 return id;
00845 }
00846
00847
00859 char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
00860 {
00861 struct eap_sim_db_data *data = priv;
00862 return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX :
00863 EAP_SIM_PSEUDONYM_PREFIX);
00864 }
00865
00866
00879 char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
00880 {
00881 struct eap_sim_db_data *data = priv;
00882 return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX :
00883 EAP_SIM_REAUTH_ID_PREFIX);
00884 }
00885
00886
00900 int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
00901 size_t identity_len, char *pseudonym)
00902 {
00903 struct eap_sim_db_data *data = priv;
00904 struct eap_sim_pseudonym *p;
00905 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
00906 identity, identity_len);
00907 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
00908
00909
00910 p = eap_sim_db_get_pseudonym(data, identity, identity_len);
00911 if (p == NULL)
00912 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
00913
00914 if (p) {
00915 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
00916 "pseudonym: %s", p->pseudonym);
00917 os_free(p->pseudonym);
00918 p->pseudonym = pseudonym;
00919 return 0;
00920 }
00921
00922 p = os_zalloc(sizeof(*p));
00923 if (p == NULL) {
00924 os_free(pseudonym);
00925 return -1;
00926 }
00927
00928 p->next = data->pseudonyms;
00929 p->identity = os_malloc(identity_len);
00930 if (p->identity == NULL) {
00931 os_free(p);
00932 os_free(pseudonym);
00933 return -1;
00934 }
00935 os_memcpy(p->identity, identity, identity_len);
00936 p->identity_len = identity_len;
00937 p->pseudonym = pseudonym;
00938 data->pseudonyms = p;
00939
00940 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
00941 return 0;
00942 }
00943
00944
00945 static struct eap_sim_reauth *
00946 eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
00947 size_t identity_len, char *reauth_id, u16 counter)
00948 {
00949 struct eap_sim_reauth *r;
00950
00951 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
00952 identity, identity_len);
00953 wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
00954
00955 r = eap_sim_db_get_reauth(data, identity, identity_len);
00956 if (r == NULL)
00957 r = eap_sim_db_get_reauth_id(data, identity, identity_len);
00958
00959 if (r) {
00960 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
00961 "reauth_id: %s", r->reauth_id);
00962 os_free(r->reauth_id);
00963 r->reauth_id = reauth_id;
00964 } else {
00965 r = os_zalloc(sizeof(*r));
00966 if (r == NULL) {
00967 os_free(reauth_id);
00968 return NULL;
00969 }
00970
00971 r->next = data->reauths;
00972 r->identity = os_malloc(identity_len);
00973 if (r->identity == NULL) {
00974 os_free(r);
00975 os_free(reauth_id);
00976 return NULL;
00977 }
00978 os_memcpy(r->identity, identity, identity_len);
00979 r->identity_len = identity_len;
00980 r->reauth_id = reauth_id;
00981 data->reauths = r;
00982 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
00983 }
00984
00985 r->counter = counter;
00986
00987 return r;
00988 }
00989
00990
01007 int eap_sim_db_add_reauth(void *priv, const u8 *identity,
01008 size_t identity_len, char *reauth_id, u16 counter,
01009 const u8 *mk)
01010 {
01011 struct eap_sim_db_data *data = priv;
01012 struct eap_sim_reauth *r;
01013
01014 r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
01015 counter);
01016 if (r == NULL)
01017 return -1;
01018
01019 os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
01020 r->aka_prime = 0;
01021
01022 return 0;
01023 }
01024
01025
01026 #ifdef EAP_SERVER_AKA_PRIME
01027
01045 int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
01046 size_t identity_len, char *reauth_id,
01047 u16 counter, const u8 *k_encr, const u8 *k_aut,
01048 const u8 *k_re)
01049 {
01050 struct eap_sim_db_data *data = priv;
01051 struct eap_sim_reauth *r;
01052
01053 r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
01054 counter);
01055 if (r == NULL)
01056 return -1;
01057
01058 r->aka_prime = 1;
01059 os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
01060 os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
01061 os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
01062
01063 return 0;
01064 }
01065 #endif
01066
01067
01076 const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
01077 size_t identity_len, size_t *len)
01078 {
01079 struct eap_sim_db_data *data = priv;
01080 struct eap_sim_pseudonym *p;
01081
01082 if (identity == NULL)
01083 return NULL;
01084
01085 p = eap_sim_db_get_pseudonym(data, identity, identity_len);
01086 if (p == NULL)
01087 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
01088 if (p == NULL)
01089 return NULL;
01090
01091 *len = p->identity_len;
01092 return p->identity;
01093 }
01094
01095
01104 struct eap_sim_reauth *
01105 eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
01106 size_t identity_len)
01107 {
01108 struct eap_sim_db_data *data = priv;
01109 struct eap_sim_reauth *r;
01110
01111 if (identity == NULL)
01112 return NULL;
01113 r = eap_sim_db_get_reauth(data, identity, identity_len);
01114 if (r == NULL)
01115 r = eap_sim_db_get_reauth_id(data, identity, identity_len);
01116 return r;
01117 }
01118
01119
01126 void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
01127 {
01128 struct eap_sim_db_data *data = priv;
01129 struct eap_sim_reauth *r, *prev = NULL;
01130 r = data->reauths;
01131 while (r) {
01132 if (r == reauth) {
01133 if (prev)
01134 prev->next = r->next;
01135 else
01136 data->reauths = r->next;
01137 eap_sim_db_free_reauth(r);
01138 return;
01139 }
01140 prev = r;
01141 r = r->next;
01142 }
01143 }
01144
01145
01174 int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
01175 size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
01176 u8 *ck, u8 *res, size_t *res_len,
01177 void *cb_session_ctx)
01178 {
01179 struct eap_sim_db_data *data = priv;
01180 struct eap_sim_db_pending *entry;
01181 int len;
01182 size_t i;
01183 char msg[40];
01184
01185 if (identity_len < 2 || identity == NULL ||
01186 identity[0] != EAP_AKA_PERMANENT_PREFIX) {
01187 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
01188 identity, identity_len);
01189 return EAP_SIM_DB_FAILURE;
01190 }
01191 identity++;
01192 identity_len--;
01193 for (i = 0; i < identity_len; i++) {
01194 if (identity[i] == '@') {
01195 identity_len = i;
01196 break;
01197 }
01198 }
01199 if (identity_len + 1 > sizeof(entry->imsi)) {
01200 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
01201 identity, identity_len);
01202 return EAP_SIM_DB_FAILURE;
01203 }
01204 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
01205 identity, identity_len);
01206
01207 entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
01208 if (entry) {
01209 if (entry->state == FAILURE) {
01210 os_free(entry);
01211 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
01212 return EAP_SIM_DB_FAILURE;
01213 }
01214
01215 if (entry->state == PENDING) {
01216 eap_sim_db_add_pending(data, entry);
01217 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
01218 return EAP_SIM_DB_PENDING;
01219 }
01220
01221 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
01222 "received authentication data");
01223 os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
01224 os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
01225 os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
01226 os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
01227 os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
01228 *res_len = entry->u.aka.res_len;
01229 os_free(entry);
01230 return 0;
01231 }
01232
01233 if (data->sock < 0) {
01234 if (eap_sim_db_open_socket(data) < 0)
01235 return EAP_SIM_DB_FAILURE;
01236 }
01237
01238 len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
01239 if (len < 0 || len + identity_len >= sizeof(msg))
01240 return EAP_SIM_DB_FAILURE;
01241 os_memcpy(msg + len, identity, identity_len);
01242 len += identity_len;
01243
01244 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
01245 "data for IMSI", identity, identity_len);
01246 if (eap_sim_db_send(data, msg, len) < 0)
01247 return EAP_SIM_DB_FAILURE;
01248
01249 entry = os_zalloc(sizeof(*entry));
01250 if (entry == NULL)
01251 return EAP_SIM_DB_FAILURE;
01252
01253 os_get_time(&entry->timestamp);
01254 entry->aka = 1;
01255 os_memcpy(entry->imsi, identity, identity_len);
01256 entry->imsi_len = identity_len;
01257 entry->cb_session_ctx = cb_session_ctx;
01258 entry->state = PENDING;
01259 eap_sim_db_add_pending(data, entry);
01260 eap_sim_db_expire_pending(data);
01261
01262 return EAP_SIM_DB_PENDING;
01263 }
01264
01265
01281 int eap_sim_db_resynchronize(void *priv, const u8 *identity,
01282 size_t identity_len, const u8 *auts,
01283 const u8 *_rand)
01284 {
01285 struct eap_sim_db_data *data = priv;
01286 size_t i;
01287
01288 if (identity_len < 2 || identity == NULL ||
01289 identity[0] != EAP_AKA_PERMANENT_PREFIX) {
01290 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
01291 identity, identity_len);
01292 return -1;
01293 }
01294 identity++;
01295 identity_len--;
01296 for (i = 0; i < identity_len; i++) {
01297 if (identity[i] == '@') {
01298 identity_len = i;
01299 break;
01300 }
01301 }
01302 if (identity_len > 20) {
01303 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
01304 identity, identity_len);
01305 return -1;
01306 }
01307
01308 if (data->sock >= 0) {
01309 char msg[100];
01310 int len, ret;
01311
01312 len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
01313 if (len < 0 || len + identity_len >= sizeof(msg))
01314 return -1;
01315 os_memcpy(msg + len, identity, identity_len);
01316 len += identity_len;
01317
01318 ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
01319 if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
01320 return -1;
01321 len += ret;
01322 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
01323 auts, EAP_AKA_AUTS_LEN);
01324 ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
01325 if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
01326 return -1;
01327 len += ret;
01328 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
01329 _rand, EAP_AKA_RAND_LEN);
01330 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
01331 "IMSI", identity, identity_len);
01332 if (eap_sim_db_send(data, msg, len) < 0)
01333 return -1;
01334 }
01335
01336 return 0;
01337 }