Moved data structures to new collections subfolder
[strongswan.git] / src / libstrongswan / credentials / sets / mem_cred.c
1 /*
2 * Copyright (C) 2010 Tobias Brunner
3 * Hochschule fuer Technik Rapperwsil
4 * Copyright (C) 2010 Martin Willi
5 * Copyright (C) 2010 revosec AG
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "mem_cred.h"
19
20 #include <threading/rwlock.h>
21 #include <collections/linked_list.h>
22
23 typedef struct private_mem_cred_t private_mem_cred_t;
24
25 /**
26 * Private data of an mem_cred_t object.
27 */
28 struct private_mem_cred_t {
29
30 /**
31 * Public mem_cred_t interface.
32 */
33 mem_cred_t public;
34
35 /**
36 * Lock for this set
37 */
38 rwlock_t *lock;
39
40 /**
41 * List of trusted certificates, certificate_t
42 */
43 linked_list_t *trusted;
44
45 /**
46 * List of trusted and untrusted certificates, certificate_t
47 */
48 linked_list_t *untrusted;
49
50 /**
51 * List of private keys, private_key_t
52 */
53 linked_list_t *keys;
54
55 /**
56 * List of shared keys, as shared_entry_t
57 */
58 linked_list_t *shared;
59
60 /**
61 * List of CDPs, as cdp_t
62 */
63 linked_list_t *cdps;
64 };
65
66 /**
67 * Data for the certificate enumerator
68 */
69 typedef struct {
70 rwlock_t *lock;
71 certificate_type_t cert;
72 key_type_t key;
73 identification_t *id;
74 } cert_data_t;
75
76 /**
77 * destroy cert_data
78 */
79 static void cert_data_destroy(cert_data_t *data)
80 {
81 data->lock->unlock(data->lock);
82 free(data);
83 }
84
85 /**
86 * filter function for certs enumerator
87 */
88 static bool certs_filter(cert_data_t *data, certificate_t **in, certificate_t **out)
89 {
90 public_key_t *public;
91 certificate_t *cert = *in;
92
93 if (data->cert == CERT_ANY || data->cert == cert->get_type(cert))
94 {
95 public = cert->get_public_key(cert);
96 if (public)
97 {
98 if (data->key == KEY_ANY || data->key == public->get_type(public))
99 {
100 if (data->id && public->has_fingerprint(public,
101 data->id->get_encoding(data->id)))
102 {
103 public->destroy(public);
104 *out = *in;
105 return TRUE;
106 }
107 }
108 public->destroy(public);
109 }
110 else if (data->key != KEY_ANY)
111 {
112 return FALSE;
113 }
114 if (data->id == NULL || cert->has_subject(cert, data->id))
115 {
116 *out = *in;
117 return TRUE;
118 }
119 }
120 return FALSE;
121 }
122
123 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
124 private_mem_cred_t *this, certificate_type_t cert, key_type_t key,
125 identification_t *id, bool trusted)
126 {
127 cert_data_t *data;
128 enumerator_t *enumerator;
129
130 INIT(data,
131 .lock = this->lock,
132 .cert = cert,
133 .key = key,
134 .id = id,
135 );
136 this->lock->read_lock(this->lock);
137 if (trusted)
138 {
139 enumerator = this->trusted->create_enumerator(this->trusted);
140 }
141 else
142 {
143 enumerator = this->untrusted->create_enumerator(this->untrusted);
144 }
145 return enumerator_create_filter(enumerator, (void*)certs_filter, data,
146 (void*)cert_data_destroy);
147 }
148
149 static bool certificate_equals(certificate_t *item, certificate_t *cert)
150 {
151 return item->equals(item, cert);
152 }
153
154 /**
155 * Add a certificate the the cache. Returns a reference to "cert" or a
156 * previously cached certificate that equals "cert".
157 */
158 static certificate_t *add_cert_internal(private_mem_cred_t *this, bool trusted,
159 certificate_t *cert)
160 {
161 certificate_t *cached;
162 this->lock->write_lock(this->lock);
163 if (this->untrusted->find_first(this->untrusted,
164 (linked_list_match_t)certificate_equals,
165 (void**)&cached, cert) == SUCCESS)
166 {
167 cert->destroy(cert);
168 cert = cached->get_ref(cached);
169 }
170 else
171 {
172 if (trusted)
173 {
174 this->trusted->insert_first(this->trusted, cert->get_ref(cert));
175 }
176 this->untrusted->insert_first(this->untrusted, cert->get_ref(cert));
177 }
178 this->lock->unlock(this->lock);
179 return cert;
180 }
181
182 METHOD(mem_cred_t, add_cert, void,
183 private_mem_cred_t *this, bool trusted, certificate_t *cert)
184 {
185 certificate_t *cached = add_cert_internal(this, trusted, cert);
186 cached->destroy(cached);
187 }
188
189 METHOD(mem_cred_t, add_cert_ref, certificate_t*,
190 private_mem_cred_t *this, bool trusted, certificate_t *cert)
191 {
192 return add_cert_internal(this, trusted, cert);
193 }
194
195 METHOD(mem_cred_t, add_crl, bool,
196 private_mem_cred_t *this, crl_t *crl)
197 {
198 certificate_t *current, *cert = &crl->certificate;
199 enumerator_t *enumerator;
200 bool new = TRUE;
201
202 this->lock->write_lock(this->lock);
203 enumerator = this->untrusted->create_enumerator(this->untrusted);
204 while (enumerator->enumerate(enumerator, (void**)&current))
205 {
206 if (current->get_type(current) == CERT_X509_CRL)
207 {
208 bool found = FALSE;
209 crl_t *crl_c = (crl_t*)current;
210 chunk_t authkey = crl->get_authKeyIdentifier(crl);
211 chunk_t authkey_c = crl_c->get_authKeyIdentifier(crl_c);
212
213 /* compare authorityKeyIdentifiers if available */
214 if (chunk_equals(authkey, authkey_c))
215 {
216 found = TRUE;
217 }
218 else
219 {
220 identification_t *issuer = cert->get_issuer(cert);
221 identification_t *issuer_c = current->get_issuer(current);
222
223 /* otherwise compare issuer distinguished names */
224 if (issuer->equals(issuer, issuer_c))
225 {
226 found = TRUE;
227 }
228 }
229 if (found)
230 {
231 new = crl_is_newer(crl, crl_c);
232 if (new)
233 {
234 this->untrusted->remove_at(this->untrusted, enumerator);
235 }
236 else
237 {
238 cert->destroy(cert);
239 }
240 break;
241 }
242 }
243 }
244 enumerator->destroy(enumerator);
245
246 if (new)
247 {
248 this->untrusted->insert_first(this->untrusted, cert);
249 }
250 this->lock->unlock(this->lock);
251 return new;
252 }
253
254 /**
255 * Data for key enumerator
256 */
257 typedef struct {
258 rwlock_t *lock;
259 key_type_t type;
260 identification_t *id;
261 } key_data_t;
262
263 /**
264 * Destroy key enumerator data
265 */
266 static void key_data_destroy(key_data_t *data)
267 {
268 data->lock->unlock(data->lock);
269 free(data);
270 }
271
272 /**
273 * filter function for private key enumerator
274 */
275 static bool key_filter(key_data_t *data, private_key_t **in, private_key_t **out)
276 {
277 private_key_t *key;
278
279 key = *in;
280 if (data->type == KEY_ANY || data->type == key->get_type(key))
281 {
282 if (data->id == NULL ||
283 key->has_fingerprint(key, data->id->get_encoding(data->id)))
284 {
285 *out = key;
286 return TRUE;
287 }
288 }
289 return FALSE;
290 }
291
292 METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
293 private_mem_cred_t *this, key_type_t type, identification_t *id)
294 {
295 key_data_t *data;
296
297 INIT(data,
298 .lock = this->lock,
299 .type = type,
300 .id = id,
301 );
302 this->lock->read_lock(this->lock);
303 return enumerator_create_filter(this->keys->create_enumerator(this->keys),
304 (void*)key_filter, data, (void*)key_data_destroy);
305 }
306
307 METHOD(mem_cred_t, add_key, void,
308 private_mem_cred_t *this, private_key_t *key)
309 {
310 this->lock->write_lock(this->lock);
311 this->keys->insert_first(this->keys, key);
312 this->lock->unlock(this->lock);
313 }
314
315 /**
316 * Shared key entry
317 */
318 typedef struct {
319 /* shared key */
320 shared_key_t *shared;
321 /* list of owners, identification_t */
322 linked_list_t *owners;
323 } shared_entry_t;
324
325 /**
326 * Clean up a shared entry
327 */
328 static void shared_entry_destroy(shared_entry_t *entry)
329 {
330 entry->owners->destroy_offset(entry->owners,
331 offsetof(identification_t, destroy));
332 entry->shared->destroy(entry->shared);
333 free(entry);
334 }
335
336 /**
337 * Data for the shared_key enumerator
338 */
339 typedef struct {
340 rwlock_t *lock;
341 identification_t *me;
342 identification_t *other;
343 shared_key_type_t type;
344 } shared_data_t;
345
346 /**
347 * free shared key enumerator data and unlock list
348 */
349 static void shared_data_destroy(shared_data_t *data)
350 {
351 data->lock->unlock(data->lock);
352 free(data);
353 }
354
355 /**
356 * Get the best match of an owner in an entry.
357 */
358 static id_match_t has_owner(shared_entry_t *entry, identification_t *owner)
359 {
360 enumerator_t *enumerator;
361 id_match_t match, best = ID_MATCH_NONE;
362 identification_t *current;
363
364 enumerator = entry->owners->create_enumerator(entry->owners);
365 while (enumerator->enumerate(enumerator, &current))
366 {
367 match = owner->matches(owner, current);
368 if (match > best)
369 {
370 best = match;
371 }
372 }
373 enumerator->destroy(enumerator);
374 return best;
375 }
376
377 /**
378 * enumerator filter function for shared entries
379 */
380 static bool shared_filter(shared_data_t *data,
381 shared_entry_t **in, shared_key_t **out,
382 void **unused1, id_match_t *me,
383 void **unused2, id_match_t *other)
384 {
385 id_match_t my_match = ID_MATCH_NONE, other_match = ID_MATCH_NONE;
386 shared_entry_t *entry = *in;
387
388 if (data->type != SHARED_ANY &&
389 entry->shared->get_type(entry->shared) != data->type)
390 {
391 return FALSE;
392 }
393 if (data->me)
394 {
395 my_match = has_owner(entry, data->me);
396 }
397 if (data->other)
398 {
399 other_match = has_owner(entry, data->other);
400 }
401 if ((data->me || data->other) && (!my_match && !other_match))
402 {
403 return FALSE;
404 }
405 *out = entry->shared;
406 if (me)
407 {
408 *me = my_match;
409 }
410 if (other)
411 {
412 *other = other_match;
413 }
414 return TRUE;
415 }
416
417 METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
418 private_mem_cred_t *this, shared_key_type_t type,
419 identification_t *me, identification_t *other)
420 {
421 shared_data_t *data;
422
423 INIT(data,
424 .lock = this->lock,
425 .me = me,
426 .other = other,
427 .type = type,
428 );
429 data->lock->read_lock(data->lock);
430 return enumerator_create_filter(
431 this->shared->create_enumerator(this->shared),
432 (void*)shared_filter, data, (void*)shared_data_destroy);
433 }
434
435 METHOD(mem_cred_t, add_shared_list, void,
436 private_mem_cred_t *this, shared_key_t *shared, linked_list_t* owners)
437 {
438 shared_entry_t *entry;
439
440 INIT(entry,
441 .shared = shared,
442 .owners = owners,
443 );
444
445 this->lock->write_lock(this->lock);
446 this->shared->insert_first(this->shared, entry);
447 this->lock->unlock(this->lock);
448 }
449
450 METHOD(mem_cred_t, add_shared, void,
451 private_mem_cred_t *this, shared_key_t *shared, ...)
452 {
453 identification_t *id;
454 linked_list_t *owners = linked_list_create();
455 va_list args;
456
457 va_start(args, shared);
458 do
459 {
460 id = va_arg(args, identification_t*);
461 if (id)
462 {
463 owners->insert_first(owners, id);
464 }
465 }
466 while (id);
467 va_end(args);
468
469 add_shared_list(this, shared, owners);
470 }
471
472 /**
473 * Certificate distribution point
474 */
475 typedef struct {
476 certificate_type_t type;
477 identification_t *id;
478 char *uri;
479 } cdp_t;
480
481 /**
482 * Destroy a CDP entry
483 */
484 static void cdp_destroy(cdp_t *this)
485 {
486 this->id->destroy(this->id);
487 free(this->uri);
488 free(this);
489 }
490
491 METHOD(mem_cred_t, add_cdp, void,
492 private_mem_cred_t *this, certificate_type_t type,
493 identification_t *id, char *uri)
494 {
495 cdp_t *cdp;
496
497 INIT(cdp,
498 .type = type,
499 .id = id->clone(id),
500 .uri = strdup(uri),
501 );
502 this->lock->write_lock(this->lock);
503 this->cdps->insert_last(this->cdps, cdp);
504 this->lock->unlock(this->lock);
505 }
506
507 /**
508 * CDP enumerator data
509 */
510 typedef struct {
511 certificate_type_t type;
512 identification_t *id;
513 rwlock_t *lock;
514 } cdp_data_t;
515
516 /**
517 * Clean up CDP enumerator data
518 */
519 static void cdp_data_destroy(cdp_data_t *data)
520 {
521 data->lock->unlock(data->lock);
522 free(data);
523 }
524
525 /**
526 * CDP enumerator filter
527 */
528 static bool cdp_filter(cdp_data_t *data, cdp_t **cdp, char **uri)
529 {
530 if (data->type != CERT_ANY && data->type != (*cdp)->type)
531 {
532 return FALSE;
533 }
534 if (data->id && !(*cdp)->id->matches((*cdp)->id, data->id))
535 {
536 return FALSE;
537 }
538 *uri = (*cdp)->uri;
539 return TRUE;
540 }
541
542 METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
543 private_mem_cred_t *this, certificate_type_t type, identification_t *id)
544 {
545 cdp_data_t *data;
546
547 INIT(data,
548 .type = type,
549 .id = id,
550 .lock = this->lock,
551 );
552 this->lock->read_lock(this->lock);
553 return enumerator_create_filter(this->cdps->create_enumerator(this->cdps),
554 (void*)cdp_filter, data, (void*)cdp_data_destroy);
555
556 }
557
558 METHOD(mem_cred_t, clear_secrets, void,
559 private_mem_cred_t *this)
560 {
561 this->lock->write_lock(this->lock);
562 this->keys->destroy_offset(this->keys, offsetof(private_key_t, destroy));
563 this->shared->destroy_function(this->shared, (void*)shared_entry_destroy);
564 this->keys = linked_list_create();
565 this->shared = linked_list_create();
566 this->lock->unlock(this->lock);
567 }
568
569 METHOD(mem_cred_t, clear_, void,
570 private_mem_cred_t *this)
571 {
572 this->lock->write_lock(this->lock);
573 this->trusted->destroy_offset(this->trusted,
574 offsetof(certificate_t, destroy));
575 this->untrusted->destroy_offset(this->untrusted,
576 offsetof(certificate_t, destroy));
577 this->cdps->destroy_function(this->cdps, (void*)cdp_destroy);
578 this->trusted = linked_list_create();
579 this->untrusted = linked_list_create();
580 this->cdps = linked_list_create();
581 this->lock->unlock(this->lock);
582
583 clear_secrets(this);
584 }
585
586 METHOD(mem_cred_t, destroy, void,
587 private_mem_cred_t *this)
588 {
589 clear_(this);
590 this->trusted->destroy(this->trusted);
591 this->untrusted->destroy(this->untrusted);
592 this->keys->destroy(this->keys);
593 this->shared->destroy(this->shared);
594 this->cdps->destroy(this->cdps);
595 this->lock->destroy(this->lock);
596 free(this);
597 }
598
599 /**
600 * See header
601 */
602 mem_cred_t *mem_cred_create()
603 {
604 private_mem_cred_t *this;
605
606 INIT(this,
607 .public = {
608 .set = {
609 .create_shared_enumerator = _create_shared_enumerator,
610 .create_private_enumerator = _create_private_enumerator,
611 .create_cert_enumerator = _create_cert_enumerator,
612 .create_cdp_enumerator = _create_cdp_enumerator,
613 .cache_cert = (void*)nop,
614 },
615 .add_cert = _add_cert,
616 .add_cert_ref = _add_cert_ref,
617 .add_crl = _add_crl,
618 .add_key = _add_key,
619 .add_shared = _add_shared,
620 .add_shared_list = _add_shared_list,
621 .add_cdp = _add_cdp,
622 .clear = _clear_,
623 .clear_secrets = _clear_secrets,
624 .destroy = _destroy,
625 },
626 .trusted = linked_list_create(),
627 .untrusted = linked_list_create(),
628 .keys = linked_list_create(),
629 .shared = linked_list_create(),
630 .cdps = linked_list_create(),
631 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
632 );
633
634 return &this->public;
635 }