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