/* * hostapd / EAP-SIM database/authenticator gateway * Copyright (c) 2005, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ /* This is an example implementation of the EAP-SIM database/authentication * gateway interface that is expected to be replaced with an implementation of * SS7 gateway to GSM authentication center (HLR/AuC) or a local * implementation of SIM triplet generator. * * The example implementation here reads triplets from a text file in * IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex strings. This * is used to simulate an HLR/AuC. As such, it is not very useful for real life * authentication, but it is useful both as an example implementation and for * EAP-SIM testing. */ #include #include #include #include "common.h" #include "eap_sim_common.h" #include "eap_sim_db.h" /* TODO: add an alternative callback based version of the interface. This is * needed to work better with the single threaded design of hostapd. For this, * the EAP data has to be stored somewhere and eap_sim_db is given a context * pointer for this and a callback function. The callback function will re-send * the EAP data through normal operations which will eventually end up calling * eap_sim_db_get_gsm_triplets() again for the same user. This time, eap_sim_db * should have the triplets available immediately. */ struct eap_sim_db_data { char *fname; }; #define KC_LEN 8 #define SRES_LEN 4 #define RAND_LEN 16 /* Initialize EAP-SIM database/authentication gateway interface. * Returns pointer to a private data structure. */ void * eap_sim_db_init(const char *config) { struct eap_sim_db_data *data; data = malloc(sizeof(*data)); if (data == NULL) { return NULL; } memset(data, 0, sizeof(*data)); data->fname = strdup(config); if (data->fname == NULL) { free(data); return NULL; } return data; } /* Deinitialize EAP-SIM database/authentication gateway interface. * priv is the pointer from eap_sim_db_init(). */ void eap_sim_db_deinit(void *priv) { struct eap_sim_db_data *data = priv; free(data->fname); free(data); } /* Get GSM triplets for user name identity (identity_len bytes). In most cases, * the user name is '1' | IMSI, i.e., 1 followed by the IMSI in ASCII format. * The identity may also include NAI realm (@realm). * priv is the pointer from eap_sim_db_init(). * Returns the number of triplets received (has to be less than or equal to * max_chal) or -1 on error (e.g., user not found). rand, kc, and sres are * pointers to data areas for the triplets. */ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, size_t identity_len, int max_chal, u8 *rand, u8 *kc, u8 *sres) { struct eap_sim_db_data *data = priv; FILE *f; int count, i; char buf[80], *pos, *next; f = fopen(data->fname, "r"); if (f == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: could not open triplet " "file '%s'", data->fname); return -1; } if (identity_len < 2 || identity[0] != '1') { wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", identity, identity_len); fclose(f); return -1; } identity++; identity_len--; for (i = 0; i < identity_len; i++) { if (identity[i] == '@') { identity_len = i; break; } } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: get triplets for IMSI", identity, identity_len); count = 0; while (count < max_chal && fgets(buf, sizeof(buf), f)) { /* Parse IMSI:Kc:SRES:RAND and match IMSI with identity. */ buf[sizeof(buf) - 1] = '\0'; pos = buf; while (*pos != '\0' && *pos != '\n') pos++; if (*pos == '\n') *pos = '\0'; if (pos - buf < 60 || pos[0] == '#') continue; pos = strchr(buf, ':'); if (pos == NULL) continue; *pos++ = '\0'; if (strlen(buf) != identity_len || memcmp(buf, identity, identity_len) != 0) continue; next = strchr(pos, ':'); if (next == NULL) continue; *next++ = '\0'; if (hexstr2bin(pos, &kc[count * KC_LEN], KC_LEN) < 0) continue; pos = next; next = strchr(pos, ':'); if (next == NULL) continue; *next++ = '\0'; if (hexstr2bin(pos, &sres[count * SRES_LEN], SRES_LEN) < 0) continue; if (hexstr2bin(next, &rand[count * RAND_LEN], RAND_LEN) < 0) continue; count++; } fclose(f); if (count == 0) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: no triplets found"); count = -1; } return count; } /* Verify whether the given user identity (identity_len bytes) is known. In * most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in * ASCII format. * priv is the pointer from eap_sim_db_init(). * Returns 0 if the user is found and GSM triplets would be available for it or * -1 on error (e.g., user not found or no triplets available). */ int eap_sim_db_identity_known(void *priv, const u8 *identity, size_t identity_len) { struct eap_sim_db_data *data = priv; FILE *f; char buf[80], *pos; int i; if (identity_len < 1 || identity[0] != '1') { return -1; } f = fopen(data->fname, "r"); if (f == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: could not open triplet " "file '%s'", data->fname); return -1; } if (identity_len < 2 || identity[0] != '1') { wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", identity, identity_len); return -1; } identity++; identity_len--; for (i = 0; i < identity_len; i++) { if (identity[i] == '@') { identity_len = i; break; } } while (fgets(buf, sizeof(buf), f)) { /* Parse IMSI:Kc:SRES:RAND and match IMSI with identity. */ buf[sizeof(buf) - 1] = '\0'; pos = buf; while (*pos != '\0' && *pos != '\n') pos++; if (*pos == '\n') *pos = '\0'; if (pos - buf < 60 || pos[0] == '#') continue; pos = strchr(buf, ':'); if (pos == NULL) continue; *pos++ = '\0'; if (strlen(buf) != identity_len || memcmp(buf, identity, identity_len) != 0) continue; fclose(f); return 0; } /* IMSI not found */ fclose(f); return -1; }