eap_sim_db.c

Go to the documentation of this file.
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          * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
00118          * SIM-RESP-AUTH <IMSI> FAILURE
00119          * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
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          * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
00196          * AKA-RESP-AUTH <IMSI> FAILURE
00197          * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
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         /* <cmd> <IMSI> ... */
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                 /* Try to reconnect */
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         /* TODO: add limit for maximum length for pending list; remove latest
00518          * (i.e., last) entry from the list if the limit is reached; could also
00519          * use timeout to expire pending entries */
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         /* Remove possible realm from identity */
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         /* Remove possible realm from identity */
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                 /* Unknown identity prefix */
00818                 return -1;
00819         }
00820 
00821         /* TODO: Should consider asking HLR/AuC gateway whether this permanent
00822          * identity is known. If it is, EAP-SIM/AKA can skip identity request.
00823          * In case of EAP-AKA, this would reduce number of needed round-trips.
00824          * Ideally, this would be done with one wait, i.e., just request
00825          * authentication data and store it for the next use. This would then
00826          * need to use similar pending-request functionality as the normal
00827          * request for authentication data at later phase.
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         /* TODO: could store last two pseudonyms */
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 /* EAP_SERVER_AKA_PRIME */
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:52 2009 for hostapd by  doxygen 1.6.1