988e709ade4897a9e7d320d81cff84b880023653
[strongswan.git] / src / libstrongswan / credentials / sets / mem_cred.c
1 /*
2 * Copyright (C) 2010-2015 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, get_cert_ref, certificate_t*,
196 private_mem_cred_t *this, certificate_t *cert)
197 {
198 certificate_t *cached;
199
200 this->lock->read_lock(this->lock);
201 if (this->untrusted->find_first(this->untrusted,
202 (linked_list_match_t)certificate_equals,
203 (void**)&cached, cert) == SUCCESS)
204 {
205 cert->destroy(cert);
206 cert = cached->get_ref(cached);
207 }
208 this->lock->unlock(this->lock);
209
210 return cert;
211 }
212
213 METHOD(mem_cred_t, add_crl, bool,
214 private_mem_cred_t *this, crl_t *crl)
215 {
216 certificate_t *current, *cert = &crl->certificate;
217 enumerator_t *enumerator;
218 bool new = TRUE;
219
220 this->lock->write_lock(this->lock);
221 enumerator = this->untrusted->create_enumerator(this->untrusted);
222 while (enumerator->enumerate(enumerator, (void**)&current))
223 {
224 if (current->get_type(current) == CERT_X509_CRL)
225 {
226 bool found = FALSE;
227 crl_t *crl_c = (crl_t*)current;
228 chunk_t authkey = crl->get_authKeyIdentifier(crl);
229 chunk_t authkey_c = crl_c->get_authKeyIdentifier(crl_c);
230
231 /* compare authorityKeyIdentifiers if available */
232 if (chunk_equals(authkey, authkey_c))
233 {
234 found = TRUE;
235 }
236 else
237 {
238 identification_t *issuer = cert->get_issuer(cert);
239 identification_t *issuer_c = current->get_issuer(current);
240
241 /* otherwise compare issuer distinguished names */
242 if (issuer->equals(issuer, issuer_c))
243 {
244 found = TRUE;
245 }
246 }
247 if (found)
248 {
249 new = crl_is_newer(crl, crl_c);
250 if (new)
251 {
252 this->untrusted->remove_at(this->untrusted, enumerator);
253 current->destroy(current);
254 }
255 else
256 {
257 cert->destroy(cert);
258 }
259 break;
260 }
261 }
262 }
263 enumerator->destroy(enumerator);
264
265 if (new)
266 {
267 this->untrusted->insert_first(this->untrusted, cert);
268 }
269 this->lock->unlock(this->lock);
270 return new;
271 }
272
273 /**
274 * Data for key enumerator
275 */
276 typedef struct {
277 rwlock_t *lock;
278 key_type_t type;
279 identification_t *id;
280 } key_data_t;
281
282 /**
283 * Destroy key enumerator data
284 */
285 static void key_data_destroy(key_data_t *data)
286 {
287 data->lock->unlock(data->lock);
288 free(data);
289 }
290
291 /**
292 * filter function for private key enumerator
293 */
294 static bool key_filter(key_data_t *data, private_key_t **in, private_key_t **out)
295 {
296 private_key_t *key;
297
298 key = *in;
299 if (data->type == KEY_ANY || data->type == key->get_type(key))
300 {
301 if (data->id == NULL ||
302 key->has_fingerprint(key, data->id->get_encoding(data->id)))
303 {
304 *out = key;
305 return TRUE;
306 }
307 }
308 return FALSE;
309 }
310
311 METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
312 private_mem_cred_t *this, key_type_t type, identification_t *id)
313 {
314 key_data_t *data;
315
316 INIT(data,
317 .lock = this->lock,
318 .type = type,
319 .id = id,
320 );
321 this->lock->read_lock(this->lock);
322 return enumerator_create_filter(this->keys->create_enumerator(this->keys),
323 (void*)key_filter, data, (void*)key_data_destroy);
324 }
325
326 METHOD(mem_cred_t, add_key, void,
327 private_mem_cred_t *this, private_key_t *key)
328 {
329 enumerator_t *enumerator;
330 private_key_t *current;
331
332 this->lock->write_lock(this->lock);
333
334 enumerator = this->keys->create_enumerator(this->keys);
335 while (enumerator->enumerate(enumerator, &current))
336 {
337 if (current->equals(current, key))
338 {
339 this->keys->remove_at(this->keys, enumerator);
340 current->destroy(current);
341 break;
342 }
343 }
344 enumerator->destroy(enumerator);
345
346 this->keys->insert_first(this->keys, key);
347
348 this->lock->unlock(this->lock);
349 }
350
351 /**
352 * Shared key entry
353 */
354 typedef struct {
355 /* shared key */
356 shared_key_t *shared;
357 /* list of owners, identification_t */
358 linked_list_t *owners;
359 } shared_entry_t;
360
361 /**
362 * Clean up a shared entry
363 */
364 static void shared_entry_destroy(shared_entry_t *entry)
365 {
366 entry->owners->destroy_offset(entry->owners,
367 offsetof(identification_t, destroy));
368 entry->shared->destroy(entry->shared);
369 free(entry);
370 }
371
372 /**
373 * Check if two shared key entries equal
374 */
375 static bool shared_entry_equals(shared_entry_t *a, shared_entry_t *b)
376 {
377 enumerator_t *e1, *e2;
378 identification_t *id1, *id2;
379 bool equals = TRUE;
380
381 if (a->shared->get_type(a->shared) != b->shared->get_type(b->shared))
382 {
383 return FALSE;
384 }
385 if (!chunk_equals(a->shared->get_key(a->shared),
386 b->shared->get_key(b->shared)))
387 {
388 return FALSE;
389 }
390 if (a->owners->get_count(a->owners) != b->owners->get_count(b->owners))
391 {
392 return FALSE;
393 }
394 e1 = a->owners->create_enumerator(a->owners);
395 e2 = b->owners->create_enumerator(b->owners);
396 while (e1->enumerate(e1, &id1) && e2->enumerate(e2, &id2))
397 {
398 if (!id1->equals(id1, id2))
399 {
400 equals = FALSE;
401 break;
402 }
403 }
404 e1->destroy(e1);
405 e2->destroy(e2);
406
407 return equals;
408 }
409
410 /**
411 * Data for the shared_key enumerator
412 */
413 typedef struct {
414 rwlock_t *lock;
415 identification_t *me;
416 identification_t *other;
417 shared_key_type_t type;
418 } shared_data_t;
419
420 /**
421 * free shared key enumerator data and unlock list
422 */
423 static void shared_data_destroy(shared_data_t *data)
424 {
425 data->lock->unlock(data->lock);
426 free(data);
427 }
428
429 /**
430 * Get the best match of an owner in an entry.
431 */
432 static id_match_t has_owner(shared_entry_t *entry, identification_t *owner)
433 {
434 enumerator_t *enumerator;
435 id_match_t match, best = ID_MATCH_NONE;
436 identification_t *current;
437
438 enumerator = entry->owners->create_enumerator(entry->owners);
439 while (enumerator->enumerate(enumerator, &current))
440 {
441 match = owner->matches(owner, current);
442 if (match > best)
443 {
444 best = match;
445 }
446 }
447 enumerator->destroy(enumerator);
448 return best;
449 }
450
451 /**
452 * enumerator filter function for shared entries
453 */
454 static bool shared_filter(shared_data_t *data,
455 shared_entry_t **in, shared_key_t **out,
456 void **unused1, id_match_t *me,
457 void **unused2, id_match_t *other)
458 {
459 id_match_t my_match = ID_MATCH_NONE, other_match = ID_MATCH_NONE;
460 shared_entry_t *entry = *in;
461
462 if (data->type != SHARED_ANY &&
463 entry->shared->get_type(entry->shared) != data->type)
464 {
465 return FALSE;
466 }
467 if (data->me)
468 {
469 my_match = has_owner(entry, data->me);
470 }
471 if (data->other)
472 {
473 other_match = has_owner(entry, data->other);
474 }
475 if ((data->me || data->other) && (!my_match && !other_match))
476 {
477 return FALSE;
478 }
479 *out = entry->shared;
480 if (me)
481 {
482 *me = my_match;
483 }
484 if (other)
485 {
486 *other = other_match;
487 }
488 return TRUE;
489 }
490
491 METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
492 private_mem_cred_t *this, shared_key_type_t type,
493 identification_t *me, identification_t *other)
494 {
495 shared_data_t *data;
496
497 INIT(data,
498 .lock = this->lock,
499 .me = me,
500 .other = other,
501 .type = type,
502 );
503 data->lock->read_lock(data->lock);
504 return enumerator_create_filter(
505 this->shared->create_enumerator(this->shared),
506 (void*)shared_filter, data, (void*)shared_data_destroy);
507 }
508
509 METHOD(mem_cred_t, add_shared_list, void,
510 private_mem_cred_t *this, shared_key_t *shared, linked_list_t* owners)
511 {
512 shared_entry_t *current, *new;
513 enumerator_t *enumerator;
514
515 INIT(new,
516 .shared = shared,
517 .owners = owners,
518 );
519
520 this->lock->write_lock(this->lock);
521
522 enumerator = this->shared->create_enumerator(this->shared);
523 while (enumerator->enumerate(enumerator, &current))
524 {
525 if (shared_entry_equals(current, new))
526 {
527 this->shared->remove_at(this->shared, enumerator);
528 shared_entry_destroy(current);
529 break;
530 }
531 }
532 enumerator->destroy(enumerator);
533
534 this->shared->insert_first(this->shared, new);
535
536 this->lock->unlock(this->lock);
537 }
538
539 METHOD(mem_cred_t, add_shared, void,
540 private_mem_cred_t *this, shared_key_t *shared, ...)
541 {
542 identification_t *id;
543 linked_list_t *owners = linked_list_create();
544 va_list args;
545
546 va_start(args, shared);
547 do
548 {
549 id = va_arg(args, identification_t*);
550 if (id)
551 {
552 owners->insert_first(owners, id);
553 }
554 }
555 while (id);
556 va_end(args);
557
558 add_shared_list(this, shared, owners);
559 }
560
561 /**
562 * Certificate distribution point
563 */
564 typedef struct {
565 certificate_type_t type;
566 identification_t *id;
567 char *uri;
568 } cdp_t;
569
570 /**
571 * Destroy a CDP entry
572 */
573 static void cdp_destroy(cdp_t *this)
574 {
575 this->id->destroy(this->id);
576 free(this->uri);
577 free(this);
578 }
579
580 METHOD(mem_cred_t, add_cdp, void,
581 private_mem_cred_t *this, certificate_type_t type,
582 identification_t *id, char *uri)
583 {
584 cdp_t *cdp;
585
586 INIT(cdp,
587 .type = type,
588 .id = id->clone(id),
589 .uri = strdup(uri),
590 );
591 this->lock->write_lock(this->lock);
592 this->cdps->insert_last(this->cdps, cdp);
593 this->lock->unlock(this->lock);
594 }
595
596 /**
597 * CDP enumerator data
598 */
599 typedef struct {
600 certificate_type_t type;
601 identification_t *id;
602 rwlock_t *lock;
603 } cdp_data_t;
604
605 /**
606 * Clean up CDP enumerator data
607 */
608 static void cdp_data_destroy(cdp_data_t *data)
609 {
610 data->lock->unlock(data->lock);
611 free(data);
612 }
613
614 /**
615 * CDP enumerator filter
616 */
617 static bool cdp_filter(cdp_data_t *data, cdp_t **cdp, char **uri)
618 {
619 if (data->type != CERT_ANY && data->type != (*cdp)->type)
620 {
621 return FALSE;
622 }
623 if (data->id && !(*cdp)->id->matches((*cdp)->id, data->id))
624 {
625 return FALSE;
626 }
627 *uri = (*cdp)->uri;
628 return TRUE;
629 }
630
631 METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
632 private_mem_cred_t *this, certificate_type_t type, identification_t *id)
633 {
634 cdp_data_t *data;
635
636 INIT(data,
637 .type = type,
638 .id = id,
639 .lock = this->lock,
640 );
641 this->lock->read_lock(this->lock);
642 return enumerator_create_filter(this->cdps->create_enumerator(this->cdps),
643 (void*)cdp_filter, data, (void*)cdp_data_destroy);
644
645 }
646
647 static void reset_certs(private_mem_cred_t *this)
648 {
649 this->trusted->destroy_offset(this->trusted,
650 offsetof(certificate_t, destroy));
651 this->untrusted->destroy_offset(this->untrusted,
652 offsetof(certificate_t, destroy));
653 this->trusted = linked_list_create();
654 this->untrusted = linked_list_create();
655 }
656
657 static void copy_certs(linked_list_t *dst, linked_list_t *src, bool clone)
658 {
659 enumerator_t *enumerator;
660 certificate_t *cert;
661
662 enumerator = src->create_enumerator(src);
663 while (enumerator->enumerate(enumerator, &cert))
664 {
665 if (clone)
666 {
667 cert = cert->get_ref(cert);
668 }
669 else
670 {
671 src->remove_at(src, enumerator);
672 }
673 dst->insert_last(dst, cert);
674 }
675 enumerator->destroy(enumerator);
676 }
677
678 METHOD(mem_cred_t, replace_certs, void,
679 private_mem_cred_t *this, mem_cred_t *other_set, bool clone)
680 {
681 private_mem_cred_t *other = (private_mem_cred_t*)other_set;
682
683 this->lock->write_lock(this->lock);
684 reset_certs(this);
685 copy_certs(this->untrusted, other->untrusted, clone);
686 copy_certs(this->trusted, other->trusted, clone);
687 this->lock->unlock(this->lock);
688 }
689
690 static void reset_secrets(private_mem_cred_t *this)
691 {
692 this->keys->destroy_offset(this->keys, offsetof(private_key_t, destroy));
693 this->shared->destroy_function(this->shared, (void*)shared_entry_destroy);
694 this->keys = linked_list_create();
695 this->shared = linked_list_create();
696 }
697
698 METHOD(mem_cred_t, replace_secrets, void,
699 private_mem_cred_t *this, mem_cred_t *other_set, bool clone)
700 {
701 private_mem_cred_t *other = (private_mem_cred_t*)other_set;
702 enumerator_t *enumerator;
703 shared_entry_t *entry, *new_entry;
704 private_key_t *key;
705
706 this->lock->write_lock(this->lock);
707
708 reset_secrets(this);
709
710 if (clone)
711 {
712 enumerator = other->keys->create_enumerator(other->keys);
713 while (enumerator->enumerate(enumerator, &key))
714 {
715 this->keys->insert_last(this->keys, key->get_ref(key));
716 }
717 enumerator->destroy(enumerator);
718 enumerator = other->shared->create_enumerator(other->shared);
719 while (enumerator->enumerate(enumerator, &entry))
720 {
721 INIT(new_entry,
722 .shared = entry->shared->get_ref(entry->shared),
723 .owners = entry->owners->clone_offset(entry->owners,
724 offsetof(identification_t, clone)),
725 );
726 this->shared->insert_last(this->shared, new_entry);
727 }
728 enumerator->destroy(enumerator);
729 }
730 else
731 {
732 while (other->keys->remove_first(other->keys, (void**)&key) == SUCCESS)
733 {
734 this->keys->insert_last(this->keys, key);
735 }
736 while (other->shared->remove_first(other->shared,
737 (void**)&entry) == SUCCESS)
738 {
739 this->shared->insert_last(this->shared, entry);
740 }
741 }
742 this->lock->unlock(this->lock);
743 }
744
745 METHOD(mem_cred_t, clear_secrets, void,
746 private_mem_cred_t *this)
747 {
748 this->lock->write_lock(this->lock);
749 reset_secrets(this);
750 this->lock->unlock(this->lock);
751 }
752
753 METHOD(mem_cred_t, clear_, void,
754 private_mem_cred_t *this)
755 {
756 this->lock->write_lock(this->lock);
757 this->cdps->destroy_function(this->cdps, (void*)cdp_destroy);
758 this->cdps = linked_list_create();
759 reset_certs(this);
760 reset_secrets(this);
761 this->lock->unlock(this->lock);
762 }
763
764 METHOD(mem_cred_t, destroy, void,
765 private_mem_cred_t *this)
766 {
767 clear_(this);
768 this->trusted->destroy(this->trusted);
769 this->untrusted->destroy(this->untrusted);
770 this->keys->destroy(this->keys);
771 this->shared->destroy(this->shared);
772 this->cdps->destroy(this->cdps);
773 this->lock->destroy(this->lock);
774 free(this);
775 }
776
777 /**
778 * See header
779 */
780 mem_cred_t *mem_cred_create()
781 {
782 private_mem_cred_t *this;
783
784 INIT(this,
785 .public = {
786 .set = {
787 .create_shared_enumerator = _create_shared_enumerator,
788 .create_private_enumerator = _create_private_enumerator,
789 .create_cert_enumerator = _create_cert_enumerator,
790 .create_cdp_enumerator = _create_cdp_enumerator,
791 .cache_cert = (void*)nop,
792 },
793 .add_cert = _add_cert,
794 .add_cert_ref = _add_cert_ref,
795 .get_cert_ref = _get_cert_ref,
796 .add_crl = _add_crl,
797 .add_key = _add_key,
798 .add_shared = _add_shared,
799 .add_shared_list = _add_shared_list,
800 .add_cdp = _add_cdp,
801 .replace_certs = _replace_certs,
802 .replace_secrets = _replace_secrets,
803 .clear = _clear_,
804 .clear_secrets = _clear_secrets,
805 .destroy = _destroy,
806 },
807 .trusted = linked_list_create(),
808 .untrusted = linked_list_create(),
809 .keys = linked_list_create(),
810 .shared = linked_list_create(),
811 .cdps = linked_list_create(),
812 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
813 );
814
815 return &this->public;
816 }