2 * Copyright (C) 2010-2016 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperwsil
5 * Copyright (C) 2010 Martin Willi
6 * Copyright (C) 2010 revosec AG
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 #include <threading/rwlock.h>
22 #include <collections/linked_list.h>
24 typedef struct private_mem_cred_t private_mem_cred_t
;
27 * Private data of an mem_cred_t object.
29 struct private_mem_cred_t
{
32 * Public mem_cred_t interface.
42 * List of trusted certificates, certificate_t
44 linked_list_t
*trusted
;
47 * List of trusted and untrusted certificates, certificate_t
49 linked_list_t
*untrusted
;
52 * List of private keys, private_key_t
57 * List of shared keys, as shared_entry_t
59 linked_list_t
*shared
;
62 * List of CDPs, as cdp_t
68 * Data for the certificate enumerator
72 certificate_type_t cert
;
80 static void cert_data_destroy(cert_data_t
*data
)
82 data
->lock
->unlock(data
->lock
);
87 * filter function for certs enumerator
89 static bool certs_filter(cert_data_t
*data
, certificate_t
**in
, certificate_t
**out
)
92 certificate_t
*cert
= *in
;
94 if (data
->cert
== CERT_ANY
|| data
->cert
== cert
->get_type(cert
))
96 public = cert
->get_public_key(cert
);
99 if (data
->key
== KEY_ANY
|| data
->key
== public->get_type(public))
101 if (data
->id
&& public->has_fingerprint(public,
102 data
->id
->get_encoding(data
->id
)))
104 public->destroy(public);
109 public->destroy(public);
111 else if (data
->key
!= KEY_ANY
)
115 if (data
->id
== NULL
|| cert
->has_subject(cert
, data
->id
))
124 METHOD(credential_set_t
, create_cert_enumerator
, enumerator_t
*,
125 private_mem_cred_t
*this, certificate_type_t cert
, key_type_t key
,
126 identification_t
*id
, bool trusted
)
129 enumerator_t
*enumerator
;
137 this->lock
->read_lock(this->lock
);
140 enumerator
= this->trusted
->create_enumerator(this->trusted
);
144 enumerator
= this->untrusted
->create_enumerator(this->untrusted
);
146 return enumerator_create_filter(enumerator
, (void*)certs_filter
, data
,
147 (void*)cert_data_destroy
);
150 static bool certificate_equals(certificate_t
*item
, certificate_t
*cert
)
152 return item
->equals(item
, cert
);
156 * Add a certificate the the cache. Returns a reference to "cert" or a
157 * previously cached certificate that equals "cert".
159 static certificate_t
*add_cert_internal(private_mem_cred_t
*this, bool trusted
,
162 certificate_t
*cached
;
163 this->lock
->write_lock(this->lock
);
164 if (this->untrusted
->find_first(this->untrusted
,
165 (linked_list_match_t
)certificate_equals
,
166 (void**)&cached
, cert
) == SUCCESS
)
169 cert
= cached
->get_ref(cached
);
175 this->trusted
->insert_first(this->trusted
, cert
->get_ref(cert
));
177 this->untrusted
->insert_first(this->untrusted
, cert
->get_ref(cert
));
179 this->lock
->unlock(this->lock
);
183 METHOD(mem_cred_t
, add_cert
, void,
184 private_mem_cred_t
*this, bool trusted
, certificate_t
*cert
)
186 certificate_t
*cached
= add_cert_internal(this, trusted
, cert
);
187 cached
->destroy(cached
);
190 METHOD(mem_cred_t
, add_cert_ref
, certificate_t
*,
191 private_mem_cred_t
*this, bool trusted
, certificate_t
*cert
)
193 return add_cert_internal(this, trusted
, cert
);
196 METHOD(mem_cred_t
, get_cert_ref
, certificate_t
*,
197 private_mem_cred_t
*this, certificate_t
*cert
)
199 certificate_t
*cached
;
201 this->lock
->read_lock(this->lock
);
202 if (this->untrusted
->find_first(this->untrusted
,
203 (linked_list_match_t
)certificate_equals
,
204 (void**)&cached
, cert
) == SUCCESS
)
207 cert
= cached
->get_ref(cached
);
209 this->lock
->unlock(this->lock
);
214 METHOD(mem_cred_t
, add_crl
, bool,
215 private_mem_cred_t
*this, crl_t
*crl
)
217 certificate_t
*current
, *cert
= &crl
->certificate
;
218 enumerator_t
*enumerator
;
221 this->lock
->write_lock(this->lock
);
222 enumerator
= this->untrusted
->create_enumerator(this->untrusted
);
223 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
225 if (current
->get_type(current
) == CERT_X509_CRL
)
229 crl_t
*crl_c
= (crl_t
*)current
;
230 chunk_t authkey
= crl
->get_authKeyIdentifier(crl
);
231 chunk_t authkey_c
= crl_c
->get_authKeyIdentifier(crl_c
);
233 /* compare authorityKeyIdentifiers if available */
234 if (chunk_equals(authkey
, authkey_c
))
240 identification_t
*issuer
= cert
->get_issuer(cert
);
241 identification_t
*issuer_c
= current
->get_issuer(current
);
243 /* otherwise compare issuer distinguished names */
244 if (issuer
->equals(issuer
, issuer_c
))
251 /* we keep at most one delta CRL for each base CRL */
252 if (crl
->is_delta_crl(crl
, &base
))
254 if (!crl_c
->is_delta_crl(crl_c
, NULL
))
256 if (chunk_equals(base
, crl_c
->get_serial(crl_c
)))
257 { /* keep the added delta and the existing base CRL
258 * but check if this is the newest delta CRL for
264 else if (crl_c
->is_delta_crl(crl_c
, &base
))
266 if (chunk_equals(base
, crl
->get_serial(crl
)))
267 { /* keep the existing delta and the added base CRL,
268 * but check if we don't store it already */
272 new = crl_is_newer(crl
, crl_c
);
278 /* we remove the existing older CRL but there might be other
279 * delta or base CRLs we can replace */
280 this->untrusted
->remove_at(this->untrusted
, enumerator
);
281 current
->destroy(current
);
285 enumerator
->destroy(enumerator
);
289 this->untrusted
->insert_first(this->untrusted
, cert
);
291 this->lock
->unlock(this->lock
);
296 * Data for key enumerator
301 identification_t
*id
;
305 * Destroy key enumerator data
307 static void key_data_destroy(key_data_t
*data
)
309 data
->lock
->unlock(data
->lock
);
314 * filter function for private key enumerator
316 static bool key_filter(key_data_t
*data
, private_key_t
**in
, private_key_t
**out
)
321 if (data
->type
== KEY_ANY
|| data
->type
== key
->get_type(key
))
323 if (data
->id
== NULL
||
324 key
->has_fingerprint(key
, data
->id
->get_encoding(data
->id
)))
333 METHOD(credential_set_t
, create_private_enumerator
, enumerator_t
*,
334 private_mem_cred_t
*this, key_type_t type
, identification_t
*id
)
343 this->lock
->read_lock(this->lock
);
344 return enumerator_create_filter(this->keys
->create_enumerator(this->keys
),
345 (void*)key_filter
, data
, (void*)key_data_destroy
);
348 METHOD(mem_cred_t
, add_key
, void,
349 private_mem_cred_t
*this, private_key_t
*key
)
351 enumerator_t
*enumerator
;
352 private_key_t
*current
;
354 this->lock
->write_lock(this->lock
);
356 enumerator
= this->keys
->create_enumerator(this->keys
);
357 while (enumerator
->enumerate(enumerator
, ¤t
))
359 if (current
->equals(current
, key
))
361 this->keys
->remove_at(this->keys
, enumerator
);
362 current
->destroy(current
);
366 enumerator
->destroy(enumerator
);
368 this->keys
->insert_first(this->keys
, key
);
370 this->lock
->unlock(this->lock
);
378 shared_key_t
*shared
;
379 /* list of owners, identification_t */
380 linked_list_t
*owners
;
384 * Clean up a shared entry
386 static void shared_entry_destroy(shared_entry_t
*entry
)
388 entry
->owners
->destroy_offset(entry
->owners
,
389 offsetof(identification_t
, destroy
));
390 entry
->shared
->destroy(entry
->shared
);
395 * Check if two shared key entries equal
397 static bool shared_entry_equals(shared_entry_t
*a
, shared_entry_t
*b
)
399 enumerator_t
*e1
, *e2
;
400 identification_t
*id1
, *id2
;
403 if (a
->shared
->get_type(a
->shared
) != b
->shared
->get_type(b
->shared
))
407 if (!chunk_equals(a
->shared
->get_key(a
->shared
),
408 b
->shared
->get_key(b
->shared
)))
412 if (a
->owners
->get_count(a
->owners
) != b
->owners
->get_count(b
->owners
))
416 e1
= a
->owners
->create_enumerator(a
->owners
);
417 e2
= b
->owners
->create_enumerator(b
->owners
);
418 while (e1
->enumerate(e1
, &id1
) && e2
->enumerate(e2
, &id2
))
420 if (!id1
->equals(id1
, id2
))
433 * Data for the shared_key enumerator
437 identification_t
*me
;
438 identification_t
*other
;
439 shared_key_type_t type
;
443 * free shared key enumerator data and unlock list
445 static void shared_data_destroy(shared_data_t
*data
)
447 data
->lock
->unlock(data
->lock
);
452 * Get the best match of an owner in an entry.
454 static id_match_t
has_owner(shared_entry_t
*entry
, identification_t
*owner
)
456 enumerator_t
*enumerator
;
457 id_match_t match
, best
= ID_MATCH_NONE
;
458 identification_t
*current
;
460 enumerator
= entry
->owners
->create_enumerator(entry
->owners
);
461 while (enumerator
->enumerate(enumerator
, ¤t
))
463 match
= owner
->matches(owner
, current
);
469 enumerator
->destroy(enumerator
);
474 * enumerator filter function for shared entries
476 static bool shared_filter(shared_data_t
*data
,
477 shared_entry_t
**in
, shared_key_t
**out
,
478 void **unused1
, id_match_t
*me
,
479 void **unused2
, id_match_t
*other
)
481 id_match_t my_match
= ID_MATCH_NONE
, other_match
= ID_MATCH_NONE
;
482 shared_entry_t
*entry
= *in
;
484 if (data
->type
!= SHARED_ANY
&&
485 entry
->shared
->get_type(entry
->shared
) != data
->type
)
491 my_match
= has_owner(entry
, data
->me
);
495 other_match
= has_owner(entry
, data
->other
);
497 if ((data
->me
|| data
->other
) && (!my_match
&& !other_match
))
501 *out
= entry
->shared
;
508 *other
= other_match
;
513 METHOD(credential_set_t
, create_shared_enumerator
, enumerator_t
*,
514 private_mem_cred_t
*this, shared_key_type_t type
,
515 identification_t
*me
, identification_t
*other
)
525 data
->lock
->read_lock(data
->lock
);
526 return enumerator_create_filter(
527 this->shared
->create_enumerator(this->shared
),
528 (void*)shared_filter
, data
, (void*)shared_data_destroy
);
531 METHOD(mem_cred_t
, add_shared_list
, void,
532 private_mem_cred_t
*this, shared_key_t
*shared
, linked_list_t
* owners
)
534 shared_entry_t
*current
, *new;
535 enumerator_t
*enumerator
;
542 this->lock
->write_lock(this->lock
);
544 enumerator
= this->shared
->create_enumerator(this->shared
);
545 while (enumerator
->enumerate(enumerator
, ¤t
))
547 if (shared_entry_equals(current
, new))
549 this->shared
->remove_at(this->shared
, enumerator
);
550 shared_entry_destroy(current
);
554 enumerator
->destroy(enumerator
);
556 this->shared
->insert_first(this->shared
, new);
558 this->lock
->unlock(this->lock
);
561 METHOD(mem_cred_t
, add_shared
, void,
562 private_mem_cred_t
*this, shared_key_t
*shared
, ...)
564 identification_t
*id
;
565 linked_list_t
*owners
= linked_list_create();
568 va_start(args
, shared
);
571 id
= va_arg(args
, identification_t
*);
574 owners
->insert_first(owners
, id
);
580 add_shared_list(this, shared
, owners
);
584 * Certificate distribution point
587 certificate_type_t type
;
588 identification_t
*id
;
593 * Destroy a CDP entry
595 static void cdp_destroy(cdp_t
*this)
597 this->id
->destroy(this->id
);
602 METHOD(mem_cred_t
, add_cdp
, void,
603 private_mem_cred_t
*this, certificate_type_t type
,
604 identification_t
*id
, char *uri
)
613 this->lock
->write_lock(this->lock
);
614 this->cdps
->insert_last(this->cdps
, cdp
);
615 this->lock
->unlock(this->lock
);
619 * CDP enumerator data
622 certificate_type_t type
;
623 identification_t
*id
;
628 * Clean up CDP enumerator data
630 static void cdp_data_destroy(cdp_data_t
*data
)
632 data
->lock
->unlock(data
->lock
);
637 * CDP enumerator filter
639 static bool cdp_filter(cdp_data_t
*data
, cdp_t
**cdp
, char **uri
)
641 if (data
->type
!= CERT_ANY
&& data
->type
!= (*cdp
)->type
)
645 if (data
->id
&& !(*cdp
)->id
->matches((*cdp
)->id
, data
->id
))
653 METHOD(credential_set_t
, create_cdp_enumerator
, enumerator_t
*,
654 private_mem_cred_t
*this, certificate_type_t type
, identification_t
*id
)
663 this->lock
->read_lock(this->lock
);
664 return enumerator_create_filter(this->cdps
->create_enumerator(this->cdps
),
665 (void*)cdp_filter
, data
, (void*)cdp_data_destroy
);
669 static void reset_certs(private_mem_cred_t
*this)
671 this->trusted
->destroy_offset(this->trusted
,
672 offsetof(certificate_t
, destroy
));
673 this->untrusted
->destroy_offset(this->untrusted
,
674 offsetof(certificate_t
, destroy
));
675 this->trusted
= linked_list_create();
676 this->untrusted
= linked_list_create();
679 static void copy_certs(linked_list_t
*dst
, linked_list_t
*src
, bool clone
)
681 enumerator_t
*enumerator
;
684 enumerator
= src
->create_enumerator(src
);
685 while (enumerator
->enumerate(enumerator
, &cert
))
689 cert
= cert
->get_ref(cert
);
693 src
->remove_at(src
, enumerator
);
695 dst
->insert_last(dst
, cert
);
697 enumerator
->destroy(enumerator
);
700 METHOD(mem_cred_t
, replace_certs
, void,
701 private_mem_cred_t
*this, mem_cred_t
*other_set
, bool clone
)
703 private_mem_cred_t
*other
= (private_mem_cred_t
*)other_set
;
705 this->lock
->write_lock(this->lock
);
707 copy_certs(this->untrusted
, other
->untrusted
, clone
);
708 copy_certs(this->trusted
, other
->trusted
, clone
);
709 this->lock
->unlock(this->lock
);
712 static void reset_secrets(private_mem_cred_t
*this)
714 this->keys
->destroy_offset(this->keys
, offsetof(private_key_t
, destroy
));
715 this->shared
->destroy_function(this->shared
, (void*)shared_entry_destroy
);
716 this->keys
= linked_list_create();
717 this->shared
= linked_list_create();
720 METHOD(mem_cred_t
, replace_secrets
, void,
721 private_mem_cred_t
*this, mem_cred_t
*other_set
, bool clone
)
723 private_mem_cred_t
*other
= (private_mem_cred_t
*)other_set
;
724 enumerator_t
*enumerator
;
725 shared_entry_t
*entry
, *new_entry
;
728 this->lock
->write_lock(this->lock
);
734 enumerator
= other
->keys
->create_enumerator(other
->keys
);
735 while (enumerator
->enumerate(enumerator
, &key
))
737 this->keys
->insert_last(this->keys
, key
->get_ref(key
));
739 enumerator
->destroy(enumerator
);
740 enumerator
= other
->shared
->create_enumerator(other
->shared
);
741 while (enumerator
->enumerate(enumerator
, &entry
))
744 .shared
= entry
->shared
->get_ref(entry
->shared
),
745 .owners
= entry
->owners
->clone_offset(entry
->owners
,
746 offsetof(identification_t
, clone
)),
748 this->shared
->insert_last(this->shared
, new_entry
);
750 enumerator
->destroy(enumerator
);
754 while (other
->keys
->remove_first(other
->keys
, (void**)&key
) == SUCCESS
)
756 this->keys
->insert_last(this->keys
, key
);
758 while (other
->shared
->remove_first(other
->shared
,
759 (void**)&entry
) == SUCCESS
)
761 this->shared
->insert_last(this->shared
, entry
);
764 this->lock
->unlock(this->lock
);
767 METHOD(mem_cred_t
, clear_secrets
, void,
768 private_mem_cred_t
*this)
770 this->lock
->write_lock(this->lock
);
772 this->lock
->unlock(this->lock
);
775 METHOD(mem_cred_t
, clear_
, void,
776 private_mem_cred_t
*this)
778 this->lock
->write_lock(this->lock
);
779 this->cdps
->destroy_function(this->cdps
, (void*)cdp_destroy
);
780 this->cdps
= linked_list_create();
783 this->lock
->unlock(this->lock
);
786 METHOD(mem_cred_t
, destroy
, void,
787 private_mem_cred_t
*this)
790 this->trusted
->destroy(this->trusted
);
791 this->untrusted
->destroy(this->untrusted
);
792 this->keys
->destroy(this->keys
);
793 this->shared
->destroy(this->shared
);
794 this->cdps
->destroy(this->cdps
);
795 this->lock
->destroy(this->lock
);
802 mem_cred_t
*mem_cred_create()
804 private_mem_cred_t
*this;
809 .create_shared_enumerator
= _create_shared_enumerator
,
810 .create_private_enumerator
= _create_private_enumerator
,
811 .create_cert_enumerator
= _create_cert_enumerator
,
812 .create_cdp_enumerator
= _create_cdp_enumerator
,
813 .cache_cert
= (void*)nop
,
815 .add_cert
= _add_cert
,
816 .add_cert_ref
= _add_cert_ref
,
817 .get_cert_ref
= _get_cert_ref
,
820 .add_shared
= _add_shared
,
821 .add_shared_list
= _add_shared_list
,
823 .replace_certs
= _replace_certs
,
824 .replace_secrets
= _replace_secrets
,
826 .clear_secrets
= _clear_secrets
,
829 .trusted
= linked_list_create(),
830 .untrusted
= linked_list_create(),
831 .keys
= linked_list_create(),
832 .shared
= linked_list_create(),
833 .cdps
= linked_list_create(),
834 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
837 return &this->public;