Moving charon to libcharon.
[strongswan.git] / src / libcharon / sa / authenticators / eap / sim_manager.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "sim_manager.h"
17
18 #include <daemon.h>
19 #include <utils/linked_list.h>
20
21 typedef struct private_sim_manager_t private_sim_manager_t;
22
23 /**
24 * Private data of an sim_manager_t object.
25 */
26 struct private_sim_manager_t {
27
28 /**
29 * Public sim_manager_t interface.
30 */
31 sim_manager_t public;
32
33 /**
34 * list of added cards
35 */
36 linked_list_t *cards;
37
38 /**
39 * list of added provider
40 */
41 linked_list_t *providers;
42
43 /**
44 * list of added hooks
45 */
46 linked_list_t *hooks;
47 };
48
49 /**
50 * Implementation of sim_manager_t.add_card
51 */
52 static void add_card(private_sim_manager_t *this, sim_card_t *card)
53 {
54 this->cards->insert_last(this->cards, card);
55 }
56
57 /**
58 * Implementation of sim_manager_t.remove_card
59 */
60 static void remove_card(private_sim_manager_t *this, sim_card_t *card)
61 {
62 this->cards->remove(this->cards, card, NULL);
63 }
64
65 /**
66 * Implementation of sim_manager_t.card_get_triplet
67 */
68 static bool card_get_triplet(private_sim_manager_t *this, identification_t *id,
69 char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN],
70 char kc[SIM_KC_LEN])
71 {
72 enumerator_t *enumerator;
73 sim_card_t *card;
74 int tried = 0;
75
76 enumerator = this->cards->create_enumerator(this->cards);
77 while (enumerator->enumerate(enumerator, &card))
78 {
79 if (card->get_triplet(card, id, rand, sres, kc))
80 {
81 enumerator->destroy(enumerator);
82 return TRUE;
83 }
84 tried++;
85 }
86 enumerator->destroy(enumerator);
87 DBG1(DBG_IKE, "tried %d SIM cards, but none has triplets for '%Y'",
88 tried, id);
89 return FALSE;
90 }
91
92 /**
93 * Implementation of sim_manager_t.card_get_quintuplet
94 */
95 static status_t card_get_quintuplet(private_sim_manager_t *this,
96 identification_t *id, char rand[AKA_RAND_LEN],
97 char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN],
98 char ik[AKA_IK_LEN], char res[AKA_RES_MAX],
99 int *res_len)
100 {
101 enumerator_t *enumerator;
102 sim_card_t *card;
103 status_t status = NOT_FOUND;
104 int tried = 0;
105
106 enumerator = this->cards->create_enumerator(this->cards);
107 while (enumerator->enumerate(enumerator, &card))
108 {
109 status = card->get_quintuplet(card, id, rand, autn, ck, ik, res, res_len);
110 switch (status)
111 { /* try next on error, but not on INVALID_STATE */
112 case SUCCESS:
113 case INVALID_STATE:
114 enumerator->destroy(enumerator);
115 return status;
116 case NOT_SUPPORTED:
117 case FAILED:
118 default:
119 tried++;
120 continue;
121 }
122 }
123 enumerator->destroy(enumerator);
124 DBG1(DBG_IKE, "tried %d SIM cards, but none has quintuplets for '%Y'",
125 tried, id);
126 return status;
127 }
128
129 /**
130 * Implementation of sim_manager_t.card_resync
131 */
132 static bool card_resync(private_sim_manager_t *this, identification_t *id,
133 char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
134 {
135 enumerator_t *enumerator;
136 sim_card_t *card;
137
138 enumerator = this->cards->create_enumerator(this->cards);
139 while (enumerator->enumerate(enumerator, &card))
140 {
141 if (card->resync(card, id, rand, auts))
142 {
143 enumerator->destroy(enumerator);
144 return TRUE;
145 }
146 }
147 enumerator->destroy(enumerator);
148 return FALSE;
149 }
150
151 /**
152 * Implementation of sim_manager_t.card_set_pseudonym
153 */
154 static void card_set_pseudonym(private_sim_manager_t *this,
155 identification_t *id, identification_t *pseudonym)
156 {
157 enumerator_t *enumerator;
158 sim_card_t *card;
159
160 DBG1(DBG_IKE, "storing pseudonym '%Y' for '%Y'", pseudonym, id);
161
162 enumerator = this->cards->create_enumerator(this->cards);
163 while (enumerator->enumerate(enumerator, &card))
164 {
165 card->set_pseudonym(card, id, pseudonym);
166 }
167 enumerator->destroy(enumerator);
168 }
169
170 /**
171 * Implementation of sim_manager_t.card_get_pseudonym
172 */
173 static identification_t* card_get_pseudonym(private_sim_manager_t *this,
174 identification_t *id)
175 {
176 enumerator_t *enumerator;
177 sim_card_t *card;
178 identification_t *pseudonym = NULL;
179
180 enumerator = this->cards->create_enumerator(this->cards);
181 while (enumerator->enumerate(enumerator, &card))
182 {
183 pseudonym = card->get_pseudonym(card, id);
184 if (pseudonym)
185 {
186 DBG1(DBG_IKE, "using stored pseudonym identity '%Y' "
187 "instead of '%Y'", pseudonym, id);
188 break;
189 }
190 }
191 enumerator->destroy(enumerator);
192 return pseudonym;
193 }
194
195 /**
196 * Implementation of sim_manager_t.card_set_reauth
197 */
198 static void card_set_reauth(private_sim_manager_t *this, identification_t *id,
199 identification_t *next, char mk[HASH_SIZE_SHA1],
200 u_int16_t counter)
201 {
202 enumerator_t *enumerator;
203 sim_card_t *card;
204
205 DBG1(DBG_IKE, "storing next reauthentication identity '%Y' for '%Y'",
206 next, id);
207
208 enumerator = this->cards->create_enumerator(this->cards);
209 while (enumerator->enumerate(enumerator, &card))
210 {
211 card->set_reauth(card, id, next, mk, counter);
212 }
213 enumerator->destroy(enumerator);
214 }
215
216 /**
217 * Implementation of sim_manager_t.card_get_reauth
218 */
219 static identification_t* card_get_reauth(private_sim_manager_t *this,
220 identification_t *id, char mk[HASH_SIZE_SHA1],
221 u_int16_t *counter)
222 {
223 enumerator_t *enumerator;
224 sim_card_t *card;
225 identification_t *reauth = NULL;
226
227 enumerator = this->cards->create_enumerator(this->cards);
228 while (enumerator->enumerate(enumerator, &card))
229 {
230 reauth = card->get_reauth(card, id, mk, counter);
231 if (reauth)
232 {
233 DBG1(DBG_IKE, "using stored reauthentication identity '%Y' "
234 "instead of '%Y'", reauth, id);
235 break;
236 }
237 }
238 enumerator->destroy(enumerator);
239 return reauth;
240 }
241
242 /**
243 * Implementation of sim_manager_t.add_provider
244 */
245 static void add_provider(private_sim_manager_t *this, sim_provider_t *provider)
246 {
247 this->providers->insert_last(this->providers, provider);
248 }
249
250 /**
251 * Implementation of sim_manager_t.remove_provider
252 */
253 static void remove_provider(private_sim_manager_t *this,
254 sim_provider_t *provider)
255 {
256 this->providers->remove(this->providers, provider, NULL);
257 }
258
259 /**
260 * Implementation of sim_manager_t.provider_get_triplet
261 */
262 static bool provider_get_triplet(private_sim_manager_t *this,
263 identification_t *id, char rand[SIM_RAND_LEN],
264 char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
265 {
266 enumerator_t *enumerator;
267 sim_provider_t *provider;
268 int tried = 0;
269
270 enumerator = this->providers->create_enumerator(this->providers);
271 while (enumerator->enumerate(enumerator, &provider))
272 {
273 if (provider->get_triplet(provider, id, rand, sres, kc))
274 {
275 enumerator->destroy(enumerator);
276 return TRUE;
277 }
278 tried++;
279 }
280 enumerator->destroy(enumerator);
281 DBG1(DBG_IKE, "tried %d SIM providers, but none had a triplet for '%Y'",
282 tried, id);
283 return FALSE;
284 }
285
286 /**
287 * Implementation of sim_manager_t.provider_get_quintuplet
288 */
289 static bool provider_get_quintuplet(private_sim_manager_t *this,
290 identification_t *id, char rand[AKA_RAND_LEN],
291 char xres[AKA_RES_MAX], int *xres_len,
292 char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
293 char autn[AKA_AUTN_LEN])
294 {
295 enumerator_t *enumerator;
296 sim_provider_t *provider;
297 int tried = 0;
298
299 enumerator = this->providers->create_enumerator(this->providers);
300 while (enumerator->enumerate(enumerator, &provider))
301 {
302 if (provider->get_quintuplet(provider, id, rand, xres, xres_len,
303 ck, ik, autn))
304 {
305 enumerator->destroy(enumerator);
306 return TRUE;
307 }
308 }
309 enumerator->destroy(enumerator);
310 DBG1(DBG_IKE, "tried %d SIM providers, but none had a quintuplet for '%Y'",
311 tried, id);
312 return FALSE;
313 }
314
315 /**
316 * Implementation of sim_manager_t.provider_resync
317 */
318 static bool provider_resync(private_sim_manager_t *this, identification_t *id,
319 char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
320 {
321 enumerator_t *enumerator;
322 sim_provider_t *provider;
323
324 enumerator = this->providers->create_enumerator(this->providers);
325 while (enumerator->enumerate(enumerator, &provider))
326 {
327 if (provider->resync(provider, id, rand, auts))
328 {
329 enumerator->destroy(enumerator);
330 return TRUE;
331 }
332 }
333 enumerator->destroy(enumerator);
334 return FALSE;
335 }
336
337 /**
338 * Implementation of sim_manager_t.provider_is_pseudonym
339 */
340 static identification_t* provider_is_pseudonym(private_sim_manager_t *this,
341 identification_t *id)
342 {
343 enumerator_t *enumerator;
344 sim_provider_t *provider;
345 identification_t *permanent = NULL;
346
347 enumerator = this->providers->create_enumerator(this->providers);
348 while (enumerator->enumerate(enumerator, &provider))
349 {
350 permanent = provider->is_pseudonym(provider, id);
351 if (permanent)
352 {
353 DBG1(DBG_IKE, "received pseudonym identity '%Y' "
354 "mapping to '%Y'", id, permanent);
355 break;
356 }
357 }
358 enumerator->destroy(enumerator);
359 return permanent;
360 }
361
362 /**
363 * Implementation of sim_manager_t.provider_gen_pseudonym
364 */
365 static identification_t* provider_gen_pseudonym(private_sim_manager_t *this,
366 identification_t *id)
367 {
368 enumerator_t *enumerator;
369 sim_provider_t *provider;
370 identification_t *pseudonym = NULL;
371
372 enumerator = this->providers->create_enumerator(this->providers);
373 while (enumerator->enumerate(enumerator, &provider))
374 {
375 pseudonym = provider->gen_pseudonym(provider, id);
376 if (pseudonym)
377 {
378 DBG1(DBG_IKE, "proposing new pseudonym '%Y'", pseudonym);
379 break;
380 }
381 }
382 enumerator->destroy(enumerator);
383 return pseudonym;
384 }
385
386 /**
387 * Implementation of sim_manager_t.provider_is_reauth
388 */
389 static identification_t* provider_is_reauth(private_sim_manager_t *this,
390 identification_t *id, char mk[HASH_SIZE_SHA1],
391 u_int16_t *counter)
392 {
393 enumerator_t *enumerator;
394 sim_provider_t *provider;
395 identification_t *permanent = NULL;
396
397 enumerator = this->providers->create_enumerator(this->providers);
398 while (enumerator->enumerate(enumerator, &provider))
399 {
400 permanent = provider->is_reauth(provider, id, mk, counter);
401 if (permanent)
402 {
403 DBG1(DBG_IKE, "received reauthentication identity '%Y' "
404 "mapping to '%Y'", id, permanent);
405 break;
406 }
407 }
408 enumerator->destroy(enumerator);
409 return permanent;
410 }
411
412 /**
413 * Implementation of sim_manager_t.provider_gen_reauth
414 */
415 static identification_t* provider_gen_reauth(private_sim_manager_t *this,
416 identification_t *id, char mk[HASH_SIZE_SHA1])
417 {
418 enumerator_t *enumerator;
419 sim_provider_t *provider;
420 identification_t *reauth = NULL;
421
422 enumerator = this->providers->create_enumerator(this->providers);
423 while (enumerator->enumerate(enumerator, &provider))
424 {
425 reauth = provider->gen_reauth(provider, id, mk);
426 if (reauth)
427 {
428 DBG1(DBG_IKE, "proposing new reauthentication identity '%Y'", reauth);
429 break;
430 }
431 }
432 enumerator->destroy(enumerator);
433 return reauth;
434 }
435
436 /**
437 * Implementation of sim_manager_t.add_hooks
438 */
439 static void add_hooks(private_sim_manager_t *this, sim_hooks_t *hooks)
440 {
441 this->hooks->insert_last(this->hooks, hooks);
442 }
443
444 /**
445 * Implementation of sim_manager_t.remove_hooks
446 */
447 static void remove_hooks(private_sim_manager_t *this, sim_hooks_t *hooks)
448 {
449 this->hooks->remove(this->hooks, hooks, NULL);
450 }
451
452 /**
453 * Implementation of sim_manager_t.message_hook
454 */
455 static void message_hook(private_sim_manager_t *this,
456 simaka_message_t *message, bool inbound, bool decrypted)
457 {
458 enumerator_t *enumerator;
459 sim_hooks_t *hooks;
460
461 enumerator = this->hooks->create_enumerator(this->hooks);
462 while (enumerator->enumerate(enumerator, &hooks))
463 {
464 hooks->message(hooks, message, inbound, decrypted);
465 }
466 enumerator->destroy(enumerator);
467 }
468
469 /**
470 * Implementation of sim_manager_t.key_hook
471 */
472 static void key_hook(private_sim_manager_t *this,
473 chunk_t k_encr, chunk_t k_auth)
474 {
475 enumerator_t *enumerator;
476 sim_hooks_t *hooks;
477
478 enumerator = this->hooks->create_enumerator(this->hooks);
479 while (enumerator->enumerate(enumerator, &hooks))
480 {
481 hooks->keys(hooks, k_encr, k_auth);
482 }
483 enumerator->destroy(enumerator);
484 }
485
486 /**
487 * Implementation of sim_manager_t.destroy.
488 */
489 static void destroy(private_sim_manager_t *this)
490 {
491 this->cards->destroy(this->cards);
492 this->providers->destroy(this->providers);
493 this->hooks->destroy(this->hooks);
494 free(this);
495 }
496
497 /**
498 * See header
499 */
500 sim_manager_t *sim_manager_create()
501 {
502 private_sim_manager_t *this = malloc_thing(private_sim_manager_t);
503
504 this->public.add_card = (void(*)(sim_manager_t*, sim_card_t *card))add_card;
505 this->public.remove_card = (void(*)(sim_manager_t*, sim_card_t *card))remove_card;
506 this->public.card_get_triplet = (bool(*)(sim_manager_t*, identification_t *id, char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]))card_get_triplet;
507 this->public.card_get_quintuplet = (status_t(*)(sim_manager_t*, identification_t *id, char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char res[AKA_RES_MAX], int *res_len))card_get_quintuplet;
508 this->public.card_resync = (bool(*)(sim_manager_t*, identification_t *id, char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]))card_resync;
509 this->public.card_set_pseudonym = (void(*)(sim_manager_t*, identification_t *id, identification_t *pseudonym))card_set_pseudonym;
510 this->public.card_get_pseudonym = (identification_t*(*)(sim_manager_t*, identification_t *id))card_get_pseudonym;
511 this->public.card_set_reauth = (void(*)(sim_manager_t*, identification_t *id, identification_t *next, char mk[HASH_SIZE_SHA1], u_int16_t counter))card_set_reauth;
512 this->public.card_get_reauth = (identification_t*(*)(sim_manager_t*, identification_t *id, char mk[HASH_SIZE_SHA1], u_int16_t *counter))card_get_reauth;
513 this->public.add_provider = (void(*)(sim_manager_t*, sim_provider_t *provider))add_provider;
514 this->public.remove_provider = (void(*)(sim_manager_t*, sim_provider_t *provider))remove_provider;
515 this->public.provider_get_triplet = (bool(*)(sim_manager_t*, identification_t *id, char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]))provider_get_triplet;
516 this->public.provider_get_quintuplet = (bool(*)(sim_manager_t*, identification_t *id, char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len, char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN]))provider_get_quintuplet;
517 this->public.provider_resync = (bool(*)(sim_manager_t*, identification_t *id, char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]))provider_resync;
518 this->public.provider_is_pseudonym = (identification_t*(*)(sim_manager_t*, identification_t *id))provider_is_pseudonym;
519 this->public.provider_gen_pseudonym = (identification_t*(*)(sim_manager_t*, identification_t *id))provider_gen_pseudonym;
520 this->public.provider_is_reauth = (identification_t*(*)(sim_manager_t*, identification_t *id, char mk[HASH_SIZE_SHA1], u_int16_t *counter))provider_is_reauth;
521 this->public.provider_gen_reauth = (identification_t*(*)(sim_manager_t*, identification_t *id, char mk[HASH_SIZE_SHA1]))provider_gen_reauth;
522 this->public.add_hooks = (void(*)(sim_manager_t*, sim_hooks_t *hooks))add_hooks;
523 this->public.remove_hooks = (void(*)(sim_manager_t*, sim_hooks_t *hooks))remove_hooks;
524 this->public.message_hook = (void(*)(sim_manager_t*, simaka_message_t *message, bool inbound, bool decrypted))message_hook;
525 this->public.key_hook = (void(*)(sim_manager_t*, chunk_t k_encr, chunk_t k_auth))key_hook;
526 this->public.destroy = (void(*)(sim_manager_t*))destroy;
527
528 this->cards = linked_list_create();
529 this->providers = linked_list_create();
530 this->hooks = linked_list_create();
531
532 return &this->public;
533 }
534