eap_sim_db.c 36 KB

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