eap_sim_db.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. /*
  2. * hostapd / EAP-SIM database/authenticator gateway
  3. * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. *
  8. * This is an example implementation of the EAP-SIM/AKA database/authentication
  9. * gateway interface that is using an external program as an SS7 gateway to
  10. * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
  11. * implementation of such a gateway program. This eap_sim_db.c takes care of
  12. * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
  13. * gateway implementations for HLR/AuC access. Alternatively, it can also be
  14. * completely replaced if the in-memory database of pseudonyms/re-auth
  15. * identities is not suitable for some cases.
  16. */
  17. #include "includes.h"
  18. #include <sys/un.h>
  19. #include "common.h"
  20. #include "crypto/random.h"
  21. #include "eap_common/eap_sim_common.h"
  22. #include "eap_server/eap_sim_db.h"
  23. #include "eloop.h"
  24. struct eap_sim_pseudonym {
  25. struct eap_sim_pseudonym *next;
  26. u8 *identity;
  27. size_t identity_len;
  28. char *pseudonym;
  29. };
  30. struct eap_sim_db_pending {
  31. struct eap_sim_db_pending *next;
  32. u8 imsi[20];
  33. size_t imsi_len;
  34. enum { PENDING, SUCCESS, FAILURE } state;
  35. void *cb_session_ctx;
  36. struct os_time timestamp;
  37. int aka;
  38. union {
  39. struct {
  40. u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
  41. u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
  42. u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
  43. int num_chal;
  44. } sim;
  45. struct {
  46. u8 rand[EAP_AKA_RAND_LEN];
  47. u8 autn[EAP_AKA_AUTN_LEN];
  48. u8 ik[EAP_AKA_IK_LEN];
  49. u8 ck[EAP_AKA_CK_LEN];
  50. u8 res[EAP_AKA_RES_MAX_LEN];
  51. size_t res_len;
  52. } aka;
  53. } u;
  54. };
  55. struct eap_sim_db_data {
  56. int sock;
  57. char *fname;
  58. char *local_sock;
  59. void (*get_complete_cb)(void *ctx, void *session_ctx);
  60. void *ctx;
  61. struct eap_sim_pseudonym *pseudonyms;
  62. struct eap_sim_reauth *reauths;
  63. struct eap_sim_db_pending *pending;
  64. };
  65. static struct eap_sim_db_pending *
  66. eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
  67. size_t imsi_len, int aka)
  68. {
  69. struct eap_sim_db_pending *entry, *prev = NULL;
  70. entry = data->pending;
  71. while (entry) {
  72. if (entry->aka == aka && entry->imsi_len == imsi_len &&
  73. os_memcmp(entry->imsi, imsi, imsi_len) == 0) {
  74. if (prev)
  75. prev->next = entry->next;
  76. else
  77. data->pending = entry->next;
  78. break;
  79. }
  80. prev = entry;
  81. entry = entry->next;
  82. }
  83. return entry;
  84. }
  85. static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
  86. struct eap_sim_db_pending *entry)
  87. {
  88. entry->next = data->pending;
  89. data->pending = entry;
  90. }
  91. static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
  92. const char *imsi, char *buf)
  93. {
  94. char *start, *end, *pos;
  95. struct eap_sim_db_pending *entry;
  96. int num_chal;
  97. /*
  98. * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
  99. * SIM-RESP-AUTH <IMSI> FAILURE
  100. * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
  101. */
  102. entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0);
  103. if (entry == NULL) {
  104. wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
  105. "received message found");
  106. return;
  107. }
  108. start = buf;
  109. if (os_strncmp(start, "FAILURE", 7) == 0) {
  110. wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
  111. "failure");
  112. entry->state = FAILURE;
  113. eap_sim_db_add_pending(data, entry);
  114. data->get_complete_cb(data->ctx, entry->cb_session_ctx);
  115. return;
  116. }
  117. num_chal = 0;
  118. while (num_chal < EAP_SIM_MAX_CHAL) {
  119. end = os_strchr(start, ' ');
  120. if (end)
  121. *end = '\0';
  122. pos = os_strchr(start, ':');
  123. if (pos == NULL)
  124. goto parse_fail;
  125. *pos = '\0';
  126. if (hexstr2bin(start, entry->u.sim.kc[num_chal],
  127. EAP_SIM_KC_LEN))
  128. goto parse_fail;
  129. start = pos + 1;
  130. pos = os_strchr(start, ':');
  131. if (pos == NULL)
  132. goto parse_fail;
  133. *pos = '\0';
  134. if (hexstr2bin(start, entry->u.sim.sres[num_chal],
  135. EAP_SIM_SRES_LEN))
  136. goto parse_fail;
  137. start = pos + 1;
  138. if (hexstr2bin(start, entry->u.sim.rand[num_chal],
  139. GSM_RAND_LEN))
  140. goto parse_fail;
  141. num_chal++;
  142. if (end == NULL)
  143. break;
  144. else
  145. start = end + 1;
  146. }
  147. entry->u.sim.num_chal = num_chal;
  148. entry->state = SUCCESS;
  149. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
  150. "successfully - callback");
  151. eap_sim_db_add_pending(data, entry);
  152. data->get_complete_cb(data->ctx, entry->cb_session_ctx);
  153. return;
  154. parse_fail:
  155. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
  156. os_free(entry);
  157. }
  158. static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
  159. const char *imsi, char *buf)
  160. {
  161. char *start, *end;
  162. struct eap_sim_db_pending *entry;
  163. /*
  164. * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
  165. * AKA-RESP-AUTH <IMSI> FAILURE
  166. * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
  167. */
  168. entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1);
  169. if (entry == NULL) {
  170. wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
  171. "received message found");
  172. return;
  173. }
  174. start = buf;
  175. if (os_strncmp(start, "FAILURE", 7) == 0) {
  176. wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
  177. "failure");
  178. entry->state = FAILURE;
  179. eap_sim_db_add_pending(data, entry);
  180. data->get_complete_cb(data->ctx, entry->cb_session_ctx);
  181. return;
  182. }
  183. end = os_strchr(start, ' ');
  184. if (end == NULL)
  185. goto parse_fail;
  186. *end = '\0';
  187. if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
  188. goto parse_fail;
  189. start = end + 1;
  190. end = os_strchr(start, ' ');
  191. if (end == NULL)
  192. goto parse_fail;
  193. *end = '\0';
  194. if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
  195. goto parse_fail;
  196. start = end + 1;
  197. end = os_strchr(start, ' ');
  198. if (end == NULL)
  199. goto parse_fail;
  200. *end = '\0';
  201. if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
  202. goto parse_fail;
  203. start = end + 1;
  204. end = os_strchr(start, ' ');
  205. if (end == NULL)
  206. goto parse_fail;
  207. *end = '\0';
  208. if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
  209. goto parse_fail;
  210. start = end + 1;
  211. end = os_strchr(start, ' ');
  212. if (end)
  213. *end = '\0';
  214. else {
  215. end = start;
  216. while (*end)
  217. end++;
  218. }
  219. entry->u.aka.res_len = (end - start) / 2;
  220. if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
  221. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
  222. entry->u.aka.res_len = 0;
  223. goto parse_fail;
  224. }
  225. if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
  226. goto parse_fail;
  227. entry->state = SUCCESS;
  228. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
  229. "successfully - callback");
  230. eap_sim_db_add_pending(data, entry);
  231. data->get_complete_cb(data->ctx, entry->cb_session_ctx);
  232. return;
  233. parse_fail:
  234. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
  235. os_free(entry);
  236. }
  237. static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
  238. {
  239. struct eap_sim_db_data *data = eloop_ctx;
  240. char buf[1000], *pos, *cmd, *imsi;
  241. int res;
  242. res = recv(sock, buf, sizeof(buf), 0);
  243. if (res < 0)
  244. return;
  245. wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
  246. "external source", (u8 *) buf, res);
  247. if (res == 0)
  248. return;
  249. if (res >= (int) sizeof(buf))
  250. res = sizeof(buf) - 1;
  251. buf[res] = '\0';
  252. if (data->get_complete_cb == NULL) {
  253. wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
  254. "registered");
  255. return;
  256. }
  257. /* <cmd> <IMSI> ... */
  258. cmd = buf;
  259. pos = os_strchr(cmd, ' ');
  260. if (pos == NULL)
  261. goto parse_fail;
  262. *pos = '\0';
  263. imsi = pos + 1;
  264. pos = os_strchr(imsi, ' ');
  265. if (pos == NULL)
  266. goto parse_fail;
  267. *pos = '\0';
  268. wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
  269. cmd, imsi);
  270. if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
  271. eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
  272. else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
  273. eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
  274. else
  275. wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
  276. "'%s'", cmd);
  277. return;
  278. parse_fail:
  279. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
  280. }
  281. static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
  282. {
  283. struct sockaddr_un addr;
  284. static int counter = 0;
  285. if (os_strncmp(data->fname, "unix:", 5) != 0)
  286. return -1;
  287. data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
  288. if (data->sock < 0) {
  289. perror("socket(eap_sim_db)");
  290. return -1;
  291. }
  292. os_memset(&addr, 0, sizeof(addr));
  293. addr.sun_family = AF_UNIX;
  294. os_snprintf(addr.sun_path, sizeof(addr.sun_path),
  295. "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
  296. os_free(data->local_sock);
  297. data->local_sock = os_strdup(addr.sun_path);
  298. if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  299. perror("bind(eap_sim_db)");
  300. close(data->sock);
  301. data->sock = -1;
  302. return -1;
  303. }
  304. os_memset(&addr, 0, sizeof(addr));
  305. addr.sun_family = AF_UNIX;
  306. os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
  307. if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  308. perror("connect(eap_sim_db)");
  309. wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
  310. (u8 *) addr.sun_path,
  311. os_strlen(addr.sun_path));
  312. close(data->sock);
  313. data->sock = -1;
  314. return -1;
  315. }
  316. eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
  317. return 0;
  318. }
  319. static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
  320. {
  321. if (data->sock >= 0) {
  322. eloop_unregister_read_sock(data->sock);
  323. close(data->sock);
  324. data->sock = -1;
  325. }
  326. if (data->local_sock) {
  327. unlink(data->local_sock);
  328. os_free(data->local_sock);
  329. data->local_sock = NULL;
  330. }
  331. }
  332. /**
  333. * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
  334. * @config: Configuration data (e.g., file name)
  335. * @get_complete_cb: Callback function for reporting availability of triplets
  336. * @ctx: Context pointer for get_complete_cb
  337. * Returns: Pointer to a private data structure or %NULL on failure
  338. */
  339. void * eap_sim_db_init(const char *config,
  340. void (*get_complete_cb)(void *ctx, void *session_ctx),
  341. void *ctx)
  342. {
  343. struct eap_sim_db_data *data;
  344. data = os_zalloc(sizeof(*data));
  345. if (data == NULL)
  346. return NULL;
  347. data->sock = -1;
  348. data->get_complete_cb = get_complete_cb;
  349. data->ctx = ctx;
  350. data->fname = os_strdup(config);
  351. if (data->fname == NULL)
  352. goto fail;
  353. if (os_strncmp(data->fname, "unix:", 5) == 0) {
  354. if (eap_sim_db_open_socket(data)) {
  355. wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
  356. "connection not available - will retry "
  357. "later");
  358. }
  359. }
  360. return data;
  361. fail:
  362. eap_sim_db_close_socket(data);
  363. os_free(data->fname);
  364. os_free(data);
  365. return NULL;
  366. }
  367. static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
  368. {
  369. os_free(p->identity);
  370. os_free(p->pseudonym);
  371. os_free(p);
  372. }
  373. static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
  374. {
  375. os_free(r->identity);
  376. os_free(r->reauth_id);
  377. os_free(r);
  378. }
  379. /**
  380. * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
  381. * @priv: Private data pointer from eap_sim_db_init()
  382. */
  383. void eap_sim_db_deinit(void *priv)
  384. {
  385. struct eap_sim_db_data *data = priv;
  386. struct eap_sim_pseudonym *p, *prev;
  387. struct eap_sim_reauth *r, *prevr;
  388. struct eap_sim_db_pending *pending, *prev_pending;
  389. eap_sim_db_close_socket(data);
  390. os_free(data->fname);
  391. p = data->pseudonyms;
  392. while (p) {
  393. prev = p;
  394. p = p->next;
  395. eap_sim_db_free_pseudonym(prev);
  396. }
  397. r = data->reauths;
  398. while (r) {
  399. prevr = r;
  400. r = r->next;
  401. eap_sim_db_free_reauth(prevr);
  402. }
  403. pending = data->pending;
  404. while (pending) {
  405. prev_pending = pending;
  406. pending = pending->next;
  407. os_free(prev_pending);
  408. }
  409. os_free(data);
  410. }
  411. static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
  412. size_t len)
  413. {
  414. int _errno = 0;
  415. if (send(data->sock, msg, len, 0) < 0) {
  416. _errno = errno;
  417. perror("send[EAP-SIM DB UNIX]");
  418. }
  419. if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
  420. _errno == ECONNREFUSED) {
  421. /* Try to reconnect */
  422. eap_sim_db_close_socket(data);
  423. if (eap_sim_db_open_socket(data) < 0)
  424. return -1;
  425. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
  426. "external server");
  427. if (send(data->sock, msg, len, 0) < 0) {
  428. perror("send[EAP-SIM DB UNIX]");
  429. return -1;
  430. }
  431. }
  432. return 0;
  433. }
  434. static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
  435. {
  436. /* TODO: add limit for maximum length for pending list; remove latest
  437. * (i.e., last) entry from the list if the limit is reached; could also
  438. * use timeout to expire pending entries */
  439. }
  440. /**
  441. * eap_sim_db_get_gsm_triplets - Get GSM triplets
  442. * @priv: Private data pointer from eap_sim_db_init()
  443. * @identity: User name identity
  444. * @identity_len: Length of identity in bytes
  445. * @max_chal: Maximum number of triplets
  446. * @_rand: Buffer for RAND values
  447. * @kc: Buffer for Kc values
  448. * @sres: Buffer for SRES values
  449. * @cb_session_ctx: Session callback context for get_complete_cb()
  450. * Returns: Number of triplets received (has to be less than or equal to
  451. * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
  452. * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
  453. * callback function registered with eap_sim_db_init() will be called once the
  454. * results become available.
  455. *
  456. * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
  457. * ASCII format.
  458. *
  459. * When using an external server for GSM triplets, this function can always
  460. * start a request and return EAP_SIM_DB_PENDING immediately if authentication
  461. * triplets are not available. Once the triplets are received, callback
  462. * function registered with eap_sim_db_init() is called to notify EAP state
  463. * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
  464. * function will then be called again and the newly received triplets will then
  465. * be given to the caller.
  466. */
  467. int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
  468. size_t identity_len, int max_chal,
  469. u8 *_rand, u8 *kc, u8 *sres,
  470. void *cb_session_ctx)
  471. {
  472. struct eap_sim_db_data *data = priv;
  473. struct eap_sim_db_pending *entry;
  474. int len, ret;
  475. size_t i;
  476. char msg[40];
  477. if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) {
  478. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
  479. identity, identity_len);
  480. return EAP_SIM_DB_FAILURE;
  481. }
  482. identity++;
  483. identity_len--;
  484. for (i = 0; i < identity_len; i++) {
  485. if (identity[i] == '@') {
  486. identity_len = i;
  487. break;
  488. }
  489. }
  490. if (identity_len + 1 > sizeof(entry->imsi)) {
  491. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
  492. identity, identity_len);
  493. return EAP_SIM_DB_FAILURE;
  494. }
  495. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
  496. identity, identity_len);
  497. entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
  498. if (entry) {
  499. int num_chal;
  500. if (entry->state == FAILURE) {
  501. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
  502. "failure");
  503. os_free(entry);
  504. return EAP_SIM_DB_FAILURE;
  505. }
  506. if (entry->state == PENDING) {
  507. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
  508. "still pending");
  509. eap_sim_db_add_pending(data, entry);
  510. return EAP_SIM_DB_PENDING;
  511. }
  512. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
  513. "%d challenges", entry->u.sim.num_chal);
  514. num_chal = entry->u.sim.num_chal;
  515. if (num_chal > max_chal)
  516. num_chal = max_chal;
  517. os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
  518. os_memcpy(sres, entry->u.sim.sres,
  519. num_chal * EAP_SIM_SRES_LEN);
  520. os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
  521. os_free(entry);
  522. return num_chal;
  523. }
  524. if (data->sock < 0) {
  525. if (eap_sim_db_open_socket(data) < 0)
  526. return EAP_SIM_DB_FAILURE;
  527. }
  528. len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
  529. if (len < 0 || len + identity_len >= sizeof(msg))
  530. return EAP_SIM_DB_FAILURE;
  531. os_memcpy(msg + len, identity, identity_len);
  532. len += identity_len;
  533. ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
  534. if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
  535. return EAP_SIM_DB_FAILURE;
  536. len += ret;
  537. wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
  538. "data for IMSI", identity, identity_len);
  539. if (eap_sim_db_send(data, msg, len) < 0)
  540. return EAP_SIM_DB_FAILURE;
  541. entry = os_zalloc(sizeof(*entry));
  542. if (entry == NULL)
  543. return EAP_SIM_DB_FAILURE;
  544. os_get_time(&entry->timestamp);
  545. os_memcpy(entry->imsi, identity, identity_len);
  546. entry->imsi_len = identity_len;
  547. entry->cb_session_ctx = cb_session_ctx;
  548. entry->state = PENDING;
  549. eap_sim_db_add_pending(data, entry);
  550. eap_sim_db_expire_pending(data);
  551. return EAP_SIM_DB_PENDING;
  552. }
  553. static struct eap_sim_pseudonym *
  554. eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
  555. size_t identity_len)
  556. {
  557. char *pseudonym;
  558. size_t len;
  559. struct eap_sim_pseudonym *p;
  560. if (identity_len == 0 ||
  561. (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
  562. identity[0] != EAP_AKA_PSEUDONYM_PREFIX &&
  563. identity[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX))
  564. return NULL;
  565. /* Remove possible realm from identity */
  566. len = 0;
  567. while (len < identity_len) {
  568. if (identity[len] == '@')
  569. break;
  570. len++;
  571. }
  572. pseudonym = os_malloc(len + 1);
  573. if (pseudonym == NULL)
  574. return NULL;
  575. os_memcpy(pseudonym, identity, len);
  576. pseudonym[len] = '\0';
  577. p = data->pseudonyms;
  578. while (p) {
  579. if (os_strcmp(p->pseudonym, pseudonym) == 0)
  580. break;
  581. p = p->next;
  582. }
  583. os_free(pseudonym);
  584. return p;
  585. }
  586. static struct eap_sim_pseudonym *
  587. eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
  588. size_t identity_len)
  589. {
  590. struct eap_sim_pseudonym *p;
  591. if (identity_len == 0 ||
  592. (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
  593. identity[0] != EAP_AKA_PERMANENT_PREFIX &&
  594. identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX))
  595. return NULL;
  596. p = data->pseudonyms;
  597. while (p) {
  598. if (identity_len == p->identity_len &&
  599. os_memcmp(p->identity, identity, identity_len) == 0)
  600. break;
  601. p = p->next;
  602. }
  603. return p;
  604. }
  605. static struct eap_sim_reauth *
  606. eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
  607. size_t identity_len)
  608. {
  609. char *reauth_id;
  610. size_t len;
  611. struct eap_sim_reauth *r;
  612. if (identity_len == 0 ||
  613. (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
  614. identity[0] != EAP_AKA_REAUTH_ID_PREFIX &&
  615. identity[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX))
  616. return NULL;
  617. /* Remove possible realm from identity */
  618. len = 0;
  619. while (len < identity_len) {
  620. if (identity[len] == '@')
  621. break;
  622. len++;
  623. }
  624. reauth_id = os_malloc(len + 1);
  625. if (reauth_id == NULL)
  626. return NULL;
  627. os_memcpy(reauth_id, identity, len);
  628. reauth_id[len] = '\0';
  629. r = data->reauths;
  630. while (r) {
  631. if (os_strcmp(r->reauth_id, reauth_id) == 0)
  632. break;
  633. r = r->next;
  634. }
  635. os_free(reauth_id);
  636. return r;
  637. }
  638. static struct eap_sim_reauth *
  639. eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
  640. size_t identity_len)
  641. {
  642. struct eap_sim_pseudonym *p;
  643. struct eap_sim_reauth *r;
  644. if (identity_len == 0)
  645. return NULL;
  646. p = eap_sim_db_get_pseudonym(data, identity, identity_len);
  647. if (p == NULL)
  648. p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
  649. if (p) {
  650. identity = p->identity;
  651. identity_len = p->identity_len;
  652. }
  653. r = data->reauths;
  654. while (r) {
  655. if (identity_len == r->identity_len &&
  656. os_memcmp(r->identity, identity, identity_len) == 0)
  657. break;
  658. r = r->next;
  659. }
  660. return r;
  661. }
  662. /**
  663. * eap_sim_db_identity_known - Verify whether the given identity is known
  664. * @priv: Private data pointer from eap_sim_db_init()
  665. * @identity: User name identity
  666. * @identity_len: Length of identity in bytes
  667. * Returns: 0 if the user is found or -1 on failure
  668. *
  669. * In most cases, the user name is ['0','1','6'] | IMSI, i.e., 1 followed by
  670. * the IMSI in ASCII format for EAP-SIM, ['2','3','7'] | pseudonym, or
  671. * ['4','5','7'] | reauth_id.
  672. */
  673. int eap_sim_db_identity_known(void *priv, const u8 *identity,
  674. size_t identity_len)
  675. {
  676. struct eap_sim_db_data *data = priv;
  677. if (identity == NULL || identity_len < 2)
  678. return -1;
  679. if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
  680. identity[0] == EAP_AKA_PSEUDONYM_PREFIX ||
  681. identity[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) {
  682. struct eap_sim_pseudonym *p =
  683. eap_sim_db_get_pseudonym(data, identity, identity_len);
  684. return p ? 0 : -1;
  685. }
  686. if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
  687. identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
  688. identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) {
  689. struct eap_sim_reauth *r =
  690. eap_sim_db_get_reauth(data, identity, identity_len);
  691. return r ? 0 : -1;
  692. }
  693. if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
  694. identity[0] != EAP_AKA_PERMANENT_PREFIX &&
  695. identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) {
  696. /* Unknown identity prefix */
  697. return -1;
  698. }
  699. /* TODO: Should consider asking HLR/AuC gateway whether this permanent
  700. * identity is known. If it is, EAP-SIM/AKA can skip identity request.
  701. * In case of EAP-AKA, this would reduce number of needed round-trips.
  702. * Ideally, this would be done with one wait, i.e., just request
  703. * authentication data and store it for the next use. This would then
  704. * need to use similar pending-request functionality as the normal
  705. * request for authentication data at later phase.
  706. */
  707. return -1;
  708. }
  709. static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
  710. {
  711. char *id, *pos, *end;
  712. u8 buf[10];
  713. if (random_get_bytes(buf, sizeof(buf)))
  714. return NULL;
  715. id = os_malloc(sizeof(buf) * 2 + 2);
  716. if (id == NULL)
  717. return NULL;
  718. pos = id;
  719. end = id + sizeof(buf) * 2 + 2;
  720. *pos++ = prefix;
  721. pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
  722. return id;
  723. }
  724. /**
  725. * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
  726. * @priv: Private data pointer from eap_sim_db_init()
  727. * @method: EAP method (SIM/AKA/AKA')
  728. * Returns: Next pseudonym (allocated string) or %NULL on failure
  729. *
  730. * This function is used to generate a pseudonym for EAP-SIM. The returned
  731. * pseudonym is not added to database at this point; it will need to be added
  732. * with eap_sim_db_add_pseudonym() once the authentication has been completed
  733. * successfully. Caller is responsible for freeing the returned buffer.
  734. */
  735. char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
  736. {
  737. struct eap_sim_db_data *data = priv;
  738. char prefix = EAP_SIM_REAUTH_ID_PREFIX;
  739. switch (method) {
  740. case EAP_SIM_DB_SIM:
  741. prefix = EAP_SIM_PSEUDONYM_PREFIX;
  742. break;
  743. case EAP_SIM_DB_AKA:
  744. prefix = EAP_AKA_PSEUDONYM_PREFIX;
  745. break;
  746. case EAP_SIM_DB_AKA_PRIME:
  747. prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
  748. break;
  749. }
  750. return eap_sim_db_get_next(data, prefix);
  751. }
  752. /**
  753. * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
  754. * @priv: Private data pointer from eap_sim_db_init()
  755. * @method: EAP method (SIM/AKA/AKA')
  756. * Returns: Next reauth_id (allocated string) or %NULL on failure
  757. *
  758. * This function is used to generate a fast re-authentication identity for
  759. * EAP-SIM. The returned reauth_id is not added to database at this point; it
  760. * will need to be added with eap_sim_db_add_reauth() once the authentication
  761. * has been completed successfully. Caller is responsible for freeing the
  762. * returned buffer.
  763. */
  764. char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
  765. {
  766. struct eap_sim_db_data *data = priv;
  767. char prefix = EAP_SIM_REAUTH_ID_PREFIX;
  768. switch (method) {
  769. case EAP_SIM_DB_SIM:
  770. prefix = EAP_SIM_REAUTH_ID_PREFIX;
  771. break;
  772. case EAP_SIM_DB_AKA:
  773. prefix = EAP_AKA_REAUTH_ID_PREFIX;
  774. break;
  775. case EAP_SIM_DB_AKA_PRIME:
  776. prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
  777. break;
  778. }
  779. return eap_sim_db_get_next(data, prefix);
  780. }
  781. /**
  782. * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
  783. * @priv: Private data pointer from eap_sim_db_init()
  784. * @identity: Identity of the user (may be permanent identity or pseudonym)
  785. * @identity_len: Length of identity
  786. * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
  787. * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
  788. * free it.
  789. * Returns: 0 on success, -1 on failure
  790. *
  791. * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
  792. * responsible of freeing pseudonym buffer once it is not needed anymore.
  793. */
  794. int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
  795. size_t identity_len, char *pseudonym)
  796. {
  797. struct eap_sim_db_data *data = priv;
  798. struct eap_sim_pseudonym *p;
  799. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
  800. identity, identity_len);
  801. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
  802. /* TODO: could store last two pseudonyms */
  803. p = eap_sim_db_get_pseudonym(data, identity, identity_len);
  804. if (p == NULL)
  805. p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
  806. if (p) {
  807. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
  808. "pseudonym: %s", p->pseudonym);
  809. os_free(p->pseudonym);
  810. p->pseudonym = pseudonym;
  811. return 0;
  812. }
  813. p = os_zalloc(sizeof(*p));
  814. if (p == NULL) {
  815. os_free(pseudonym);
  816. return -1;
  817. }
  818. p->next = data->pseudonyms;
  819. p->identity = os_malloc(identity_len);
  820. if (p->identity == NULL) {
  821. os_free(p);
  822. os_free(pseudonym);
  823. return -1;
  824. }
  825. os_memcpy(p->identity, identity, identity_len);
  826. p->identity_len = identity_len;
  827. p->pseudonym = pseudonym;
  828. data->pseudonyms = p;
  829. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
  830. return 0;
  831. }
  832. static struct eap_sim_reauth *
  833. eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
  834. size_t identity_len, char *reauth_id, u16 counter)
  835. {
  836. struct eap_sim_reauth *r;
  837. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
  838. identity, identity_len);
  839. wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
  840. r = eap_sim_db_get_reauth(data, identity, identity_len);
  841. if (r == NULL)
  842. r = eap_sim_db_get_reauth_id(data, identity, identity_len);
  843. if (r) {
  844. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
  845. "reauth_id: %s", r->reauth_id);
  846. os_free(r->reauth_id);
  847. r->reauth_id = reauth_id;
  848. } else {
  849. r = os_zalloc(sizeof(*r));
  850. if (r == NULL) {
  851. os_free(reauth_id);
  852. return NULL;
  853. }
  854. r->next = data->reauths;
  855. r->identity = os_malloc(identity_len);
  856. if (r->identity == NULL) {
  857. os_free(r);
  858. os_free(reauth_id);
  859. return NULL;
  860. }
  861. os_memcpy(r->identity, identity, identity_len);
  862. r->identity_len = identity_len;
  863. r->reauth_id = reauth_id;
  864. data->reauths = r;
  865. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
  866. }
  867. r->counter = counter;
  868. return r;
  869. }
  870. /**
  871. * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
  872. * @priv: Private data pointer from eap_sim_db_init()
  873. * @identity: Identity of the user (may be permanent identity or pseudonym)
  874. * @identity_len: Length of identity
  875. * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
  876. * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
  877. * free it.
  878. * @counter: AT_COUNTER value for fast re-authentication
  879. * @mk: 16-byte MK from the previous full authentication or %NULL
  880. * Returns: 0 on success, -1 on failure
  881. *
  882. * This function adds a new re-authentication entry for an EAP-SIM user.
  883. * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
  884. * anymore.
  885. */
  886. int eap_sim_db_add_reauth(void *priv, const u8 *identity,
  887. size_t identity_len, char *reauth_id, u16 counter,
  888. const u8 *mk)
  889. {
  890. struct eap_sim_db_data *data = priv;
  891. struct eap_sim_reauth *r;
  892. r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
  893. counter);
  894. if (r == NULL)
  895. return -1;
  896. os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
  897. r->aka_prime = 0;
  898. return 0;
  899. }
  900. #ifdef EAP_SERVER_AKA_PRIME
  901. /**
  902. * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
  903. * @priv: Private data pointer from eap_sim_db_init()
  904. * @identity: Identity of the user (may be permanent identity or pseudonym)
  905. * @identity_len: Length of identity
  906. * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
  907. * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
  908. * free it.
  909. * @counter: AT_COUNTER value for fast re-authentication
  910. * @k_encr: K_encr from the previous full authentication
  911. * @k_aut: K_aut from the previous full authentication
  912. * @k_re: 32-byte K_re from the previous full authentication
  913. * Returns: 0 on success, -1 on failure
  914. *
  915. * This function adds a new re-authentication entry for an EAP-AKA' user.
  916. * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
  917. * anymore.
  918. */
  919. int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
  920. size_t identity_len, char *reauth_id,
  921. u16 counter, const u8 *k_encr, const u8 *k_aut,
  922. const u8 *k_re)
  923. {
  924. struct eap_sim_db_data *data = priv;
  925. struct eap_sim_reauth *r;
  926. r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
  927. counter);
  928. if (r == NULL)
  929. return -1;
  930. r->aka_prime = 1;
  931. os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
  932. os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
  933. os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
  934. return 0;
  935. }
  936. #endif /* EAP_SERVER_AKA_PRIME */
  937. /**
  938. * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
  939. * @priv: Private data pointer from eap_sim_db_init()
  940. * @identity: Identity of the user (may be permanent identity or pseudonym)
  941. * @identity_len: Length of identity
  942. * @len: Buffer for length of the returned permanent identity
  943. * Returns: Pointer to the permanent identity, or %NULL if not found
  944. */
  945. const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
  946. size_t identity_len, size_t *len)
  947. {
  948. struct eap_sim_db_data *data = priv;
  949. struct eap_sim_pseudonym *p;
  950. if (identity == NULL)
  951. return NULL;
  952. p = eap_sim_db_get_pseudonym(data, identity, identity_len);
  953. if (p == NULL)
  954. p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
  955. if (p == NULL)
  956. return NULL;
  957. *len = p->identity_len;
  958. return p->identity;
  959. }
  960. /**
  961. * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
  962. * @priv: Private data pointer from eap_sim_db_init()
  963. * @identity: Identity of the user (may be permanent identity, pseudonym, or
  964. * reauth_id)
  965. * @identity_len: Length of identity
  966. * Returns: Pointer to the re-auth entry, or %NULL if not found
  967. */
  968. struct eap_sim_reauth *
  969. eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
  970. size_t identity_len)
  971. {
  972. struct eap_sim_db_data *data = priv;
  973. struct eap_sim_reauth *r;
  974. if (identity == NULL)
  975. return NULL;
  976. r = eap_sim_db_get_reauth(data, identity, identity_len);
  977. if (r == NULL)
  978. r = eap_sim_db_get_reauth_id(data, identity, identity_len);
  979. return r;
  980. }
  981. /**
  982. * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
  983. * @priv: Private data pointer from eap_sim_db_init()
  984. * @reauth: Pointer to re-authentication entry from
  985. * eap_sim_db_get_reauth_entry()
  986. */
  987. void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
  988. {
  989. struct eap_sim_db_data *data = priv;
  990. struct eap_sim_reauth *r, *prev = NULL;
  991. r = data->reauths;
  992. while (r) {
  993. if (r == reauth) {
  994. if (prev)
  995. prev->next = r->next;
  996. else
  997. data->reauths = r->next;
  998. eap_sim_db_free_reauth(r);
  999. return;
  1000. }
  1001. prev = r;
  1002. r = r->next;
  1003. }
  1004. }
  1005. /**
  1006. * eap_sim_db_get_aka_auth - Get AKA authentication values
  1007. * @priv: Private data pointer from eap_sim_db_init()
  1008. * @identity: User name identity
  1009. * @identity_len: Length of identity in bytes
  1010. * @_rand: Buffer for RAND value
  1011. * @autn: Buffer for AUTN value
  1012. * @ik: Buffer for IK value
  1013. * @ck: Buffer for CK value
  1014. * @res: Buffer for RES value
  1015. * @res_len: Buffer for RES length
  1016. * @cb_session_ctx: Session callback context for get_complete_cb()
  1017. * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
  1018. * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
  1019. * case, the callback function registered with eap_sim_db_init() will be
  1020. * called once the results become available.
  1021. *
  1022. * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
  1023. * ASCII format for EAP-AKA and '6' | IMSI for EAP-AKA'.
  1024. *
  1025. * When using an external server for AKA authentication, this function can
  1026. * always start a request and return EAP_SIM_DB_PENDING immediately if
  1027. * authentication triplets are not available. Once the authentication data are
  1028. * received, callback function registered with eap_sim_db_init() is called to
  1029. * notify EAP state machine to reprocess the message. This
  1030. * eap_sim_db_get_aka_auth() function will then be called again and the newly
  1031. * received triplets will then be given to the caller.
  1032. */
  1033. int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
  1034. size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
  1035. u8 *ck, u8 *res, size_t *res_len,
  1036. void *cb_session_ctx)
  1037. {
  1038. struct eap_sim_db_data *data = priv;
  1039. struct eap_sim_db_pending *entry;
  1040. int len;
  1041. size_t i;
  1042. char msg[40];
  1043. if (identity_len < 2 || identity == NULL ||
  1044. (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
  1045. identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
  1046. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
  1047. identity, identity_len);
  1048. return EAP_SIM_DB_FAILURE;
  1049. }
  1050. identity++;
  1051. identity_len--;
  1052. for (i = 0; i < identity_len; i++) {
  1053. if (identity[i] == '@') {
  1054. identity_len = i;
  1055. break;
  1056. }
  1057. }
  1058. if (identity_len + 1 > sizeof(entry->imsi)) {
  1059. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
  1060. identity, identity_len);
  1061. return EAP_SIM_DB_FAILURE;
  1062. }
  1063. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
  1064. identity, identity_len);
  1065. entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
  1066. if (entry) {
  1067. if (entry->state == FAILURE) {
  1068. os_free(entry);
  1069. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
  1070. return EAP_SIM_DB_FAILURE;
  1071. }
  1072. if (entry->state == PENDING) {
  1073. eap_sim_db_add_pending(data, entry);
  1074. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
  1075. return EAP_SIM_DB_PENDING;
  1076. }
  1077. wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
  1078. "received authentication data");
  1079. os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
  1080. os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
  1081. os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
  1082. os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
  1083. os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
  1084. *res_len = entry->u.aka.res_len;
  1085. os_free(entry);
  1086. return 0;
  1087. }
  1088. if (data->sock < 0) {
  1089. if (eap_sim_db_open_socket(data) < 0)
  1090. return EAP_SIM_DB_FAILURE;
  1091. }
  1092. len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
  1093. if (len < 0 || len + identity_len >= sizeof(msg))
  1094. return EAP_SIM_DB_FAILURE;
  1095. os_memcpy(msg + len, identity, identity_len);
  1096. len += identity_len;
  1097. wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
  1098. "data for IMSI", identity, identity_len);
  1099. if (eap_sim_db_send(data, msg, len) < 0)
  1100. return EAP_SIM_DB_FAILURE;
  1101. entry = os_zalloc(sizeof(*entry));
  1102. if (entry == NULL)
  1103. return EAP_SIM_DB_FAILURE;
  1104. os_get_time(&entry->timestamp);
  1105. entry->aka = 1;
  1106. os_memcpy(entry->imsi, identity, identity_len);
  1107. entry->imsi_len = identity_len;
  1108. entry->cb_session_ctx = cb_session_ctx;
  1109. entry->state = PENDING;
  1110. eap_sim_db_add_pending(data, entry);
  1111. eap_sim_db_expire_pending(data);
  1112. return EAP_SIM_DB_PENDING;
  1113. }
  1114. /**
  1115. * eap_sim_db_resynchronize - Resynchronize AKA AUTN
  1116. * @priv: Private data pointer from eap_sim_db_init()
  1117. * @identity: User name identity
  1118. * @identity_len: Length of identity in bytes
  1119. * @auts: AUTS value from the peer
  1120. * @_rand: RAND value used in the rejected message
  1121. * Returns: 0 on success, -1 on failure
  1122. *
  1123. * This function is called when the peer reports synchronization failure in the
  1124. * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
  1125. * HLR/AuC to allow it to resynchronize with the peer. After this,
  1126. * eap_sim_db_get_aka_auth() will be called again to to fetch updated
  1127. * RAND/AUTN values for the next challenge.
  1128. */
  1129. int eap_sim_db_resynchronize(void *priv, const u8 *identity,
  1130. size_t identity_len, const u8 *auts,
  1131. const u8 *_rand)
  1132. {
  1133. struct eap_sim_db_data *data = priv;
  1134. size_t i;
  1135. if (identity_len < 2 || identity == NULL ||
  1136. (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
  1137. identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
  1138. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
  1139. identity, identity_len);
  1140. return -1;
  1141. }
  1142. identity++;
  1143. identity_len--;
  1144. for (i = 0; i < identity_len; i++) {
  1145. if (identity[i] == '@') {
  1146. identity_len = i;
  1147. break;
  1148. }
  1149. }
  1150. if (identity_len > 20) {
  1151. wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
  1152. identity, identity_len);
  1153. return -1;
  1154. }
  1155. if (data->sock >= 0) {
  1156. char msg[100];
  1157. int len, ret;
  1158. len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
  1159. if (len < 0 || len + identity_len >= sizeof(msg))
  1160. return -1;
  1161. os_memcpy(msg + len, identity, identity_len);
  1162. len += identity_len;
  1163. ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
  1164. if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
  1165. return -1;
  1166. len += ret;
  1167. len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
  1168. auts, EAP_AKA_AUTS_LEN);
  1169. ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
  1170. if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
  1171. return -1;
  1172. len += ret;
  1173. len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
  1174. _rand, EAP_AKA_RAND_LEN);
  1175. wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
  1176. "IMSI", identity, identity_len);
  1177. if (eap_sim_db_send(data, msg, len) < 0)
  1178. return -1;
  1179. }
  1180. return 0;
  1181. }