2 * Copyright (C) 2010-2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperwsil
4 * Copyright (C) 2010 Martin Willi
5 * Copyright (C) 2010 revosec AG
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>.
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
20 #include <threading/rwlock.h>
21 #include <collections/linked_list.h>
23 typedef struct private_mem_cred_t private_mem_cred_t
;
26 * Private data of an mem_cred_t object.
28 struct private_mem_cred_t
{
31 * Public mem_cred_t interface.
41 * List of trusted certificates, certificate_t
43 linked_list_t
*trusted
;
46 * List of trusted and untrusted certificates, certificate_t
48 linked_list_t
*untrusted
;
51 * List of private keys, private_key_t
56 * List of shared keys, as shared_entry_t
58 linked_list_t
*shared
;
61 * List of CDPs, as cdp_t
67 * Data for the certificate enumerator
71 certificate_type_t cert
;
79 static void cert_data_destroy(cert_data_t
*data
)
81 data
->lock
->unlock(data
->lock
);
86 * filter function for certs enumerator
88 static bool certs_filter(cert_data_t
*data
, certificate_t
**in
, certificate_t
**out
)
91 certificate_t
*cert
= *in
;
93 if (data
->cert
== CERT_ANY
|| data
->cert
== cert
->get_type(cert
))
95 public = cert
->get_public_key(cert
);
98 if (data
->key
== KEY_ANY
|| data
->key
== public->get_type(public))
100 if (data
->id
&& public->has_fingerprint(public,
101 data
->id
->get_encoding(data
->id
)))
103 public->destroy(public);
108 public->destroy(public);
110 else if (data
->key
!= KEY_ANY
)
114 if (data
->id
== NULL
|| cert
->has_subject(cert
, data
->id
))
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
)
128 enumerator_t
*enumerator
;
136 this->lock
->read_lock(this->lock
);
139 enumerator
= this->trusted
->create_enumerator(this->trusted
);
143 enumerator
= this->untrusted
->create_enumerator(this->untrusted
);
145 return enumerator_create_filter(enumerator
, (void*)certs_filter
, data
,
146 (void*)cert_data_destroy
);
149 static bool certificate_equals(certificate_t
*item
, certificate_t
*cert
)
151 return item
->equals(item
, cert
);
155 * Add a certificate the the cache. Returns a reference to "cert" or a
156 * previously cached certificate that equals "cert".
158 static certificate_t
*add_cert_internal(private_mem_cred_t
*this, bool trusted
,
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
)
168 cert
= cached
->get_ref(cached
);
174 this->trusted
->insert_first(this->trusted
, cert
->get_ref(cert
));
176 this->untrusted
->insert_first(this->untrusted
, cert
->get_ref(cert
));
178 this->lock
->unlock(this->lock
);
182 METHOD(mem_cred_t
, add_cert
, void,
183 private_mem_cred_t
*this, bool trusted
, certificate_t
*cert
)
185 certificate_t
*cached
= add_cert_internal(this, trusted
, cert
);
186 cached
->destroy(cached
);
189 METHOD(mem_cred_t
, add_cert_ref
, certificate_t
*,
190 private_mem_cred_t
*this, bool trusted
, certificate_t
*cert
)
192 return add_cert_internal(this, trusted
, cert
);
195 METHOD(mem_cred_t
, add_crl
, bool,
196 private_mem_cred_t
*this, crl_t
*crl
)
198 certificate_t
*current
, *cert
= &crl
->certificate
;
199 enumerator_t
*enumerator
;
202 this->lock
->write_lock(this->lock
);
203 enumerator
= this->untrusted
->create_enumerator(this->untrusted
);
204 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
206 if (current
->get_type(current
) == CERT_X509_CRL
)
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
);
213 /* compare authorityKeyIdentifiers if available */
214 if (chunk_equals(authkey
, authkey_c
))
220 identification_t
*issuer
= cert
->get_issuer(cert
);
221 identification_t
*issuer_c
= current
->get_issuer(current
);
223 /* otherwise compare issuer distinguished names */
224 if (issuer
->equals(issuer
, issuer_c
))
231 new = crl_is_newer(crl
, crl_c
);
234 this->untrusted
->remove_at(this->untrusted
, enumerator
);
244 enumerator
->destroy(enumerator
);
248 this->untrusted
->insert_first(this->untrusted
, cert
);
250 this->lock
->unlock(this->lock
);
255 * Data for key enumerator
260 identification_t
*id
;
264 * Destroy key enumerator data
266 static void key_data_destroy(key_data_t
*data
)
268 data
->lock
->unlock(data
->lock
);
273 * filter function for private key enumerator
275 static bool key_filter(key_data_t
*data
, private_key_t
**in
, private_key_t
**out
)
280 if (data
->type
== KEY_ANY
|| data
->type
== key
->get_type(key
))
282 if (data
->id
== NULL
||
283 key
->has_fingerprint(key
, data
->id
->get_encoding(data
->id
)))
292 METHOD(credential_set_t
, create_private_enumerator
, enumerator_t
*,
293 private_mem_cred_t
*this, key_type_t type
, identification_t
*id
)
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
);
307 METHOD(mem_cred_t
, add_key
, void,
308 private_mem_cred_t
*this, private_key_t
*key
)
310 enumerator_t
*enumerator
;
311 private_key_t
*current
;
313 this->lock
->write_lock(this->lock
);
315 enumerator
= this->keys
->create_enumerator(this->keys
);
316 while (enumerator
->enumerate(enumerator
, ¤t
))
318 if (current
->equals(current
, key
))
320 this->keys
->remove_at(this->keys
, enumerator
);
321 current
->destroy(current
);
325 enumerator
->destroy(enumerator
);
327 this->keys
->insert_first(this->keys
, key
);
329 this->lock
->unlock(this->lock
);
337 shared_key_t
*shared
;
338 /* list of owners, identification_t */
339 linked_list_t
*owners
;
343 * Clean up a shared entry
345 static void shared_entry_destroy(shared_entry_t
*entry
)
347 entry
->owners
->destroy_offset(entry
->owners
,
348 offsetof(identification_t
, destroy
));
349 entry
->shared
->destroy(entry
->shared
);
354 * Check if two shared key entries equal
356 static bool shared_entry_equals(shared_entry_t
*a
, shared_entry_t
*b
)
358 enumerator_t
*e1
, *e2
;
359 identification_t
*id1
, *id2
;
362 if (a
->shared
->get_type(a
->shared
) != b
->shared
->get_type(b
->shared
))
366 if (!chunk_equals(a
->shared
->get_key(a
->shared
),
367 b
->shared
->get_key(b
->shared
)))
371 if (a
->owners
->get_count(a
->owners
) != b
->owners
->get_count(b
->owners
))
375 e1
= a
->owners
->create_enumerator(a
->owners
);
376 e2
= b
->owners
->create_enumerator(b
->owners
);
377 while (e1
->enumerate(e1
, &id1
) && e2
->enumerate(e2
, &id2
))
379 if (!id1
->equals(id1
, id2
))
392 * Data for the shared_key enumerator
396 identification_t
*me
;
397 identification_t
*other
;
398 shared_key_type_t type
;
402 * free shared key enumerator data and unlock list
404 static void shared_data_destroy(shared_data_t
*data
)
406 data
->lock
->unlock(data
->lock
);
411 * Get the best match of an owner in an entry.
413 static id_match_t
has_owner(shared_entry_t
*entry
, identification_t
*owner
)
415 enumerator_t
*enumerator
;
416 id_match_t match
, best
= ID_MATCH_NONE
;
417 identification_t
*current
;
419 enumerator
= entry
->owners
->create_enumerator(entry
->owners
);
420 while (enumerator
->enumerate(enumerator
, ¤t
))
422 match
= owner
->matches(owner
, current
);
428 enumerator
->destroy(enumerator
);
433 * enumerator filter function for shared entries
435 static bool shared_filter(shared_data_t
*data
,
436 shared_entry_t
**in
, shared_key_t
**out
,
437 void **unused1
, id_match_t
*me
,
438 void **unused2
, id_match_t
*other
)
440 id_match_t my_match
= ID_MATCH_NONE
, other_match
= ID_MATCH_NONE
;
441 shared_entry_t
*entry
= *in
;
443 if (data
->type
!= SHARED_ANY
&&
444 entry
->shared
->get_type(entry
->shared
) != data
->type
)
450 my_match
= has_owner(entry
, data
->me
);
454 other_match
= has_owner(entry
, data
->other
);
456 if ((data
->me
|| data
->other
) && (!my_match
&& !other_match
))
460 *out
= entry
->shared
;
467 *other
= other_match
;
472 METHOD(credential_set_t
, create_shared_enumerator
, enumerator_t
*,
473 private_mem_cred_t
*this, shared_key_type_t type
,
474 identification_t
*me
, identification_t
*other
)
484 data
->lock
->read_lock(data
->lock
);
485 return enumerator_create_filter(
486 this->shared
->create_enumerator(this->shared
),
487 (void*)shared_filter
, data
, (void*)shared_data_destroy
);
490 METHOD(mem_cred_t
, add_shared_list
, void,
491 private_mem_cred_t
*this, shared_key_t
*shared
, linked_list_t
* owners
)
493 shared_entry_t
*current
, *new;
494 enumerator_t
*enumerator
;
501 this->lock
->write_lock(this->lock
);
503 enumerator
= this->shared
->create_enumerator(this->shared
);
504 while (enumerator
->enumerate(enumerator
, ¤t
))
506 if (shared_entry_equals(current
, new))
508 this->shared
->remove_at(this->shared
, enumerator
);
509 shared_entry_destroy(current
);
513 enumerator
->destroy(enumerator
);
515 this->shared
->insert_first(this->shared
, new);
517 this->lock
->unlock(this->lock
);
520 METHOD(mem_cred_t
, add_shared
, void,
521 private_mem_cred_t
*this, shared_key_t
*shared
, ...)
523 identification_t
*id
;
524 linked_list_t
*owners
= linked_list_create();
527 va_start(args
, shared
);
530 id
= va_arg(args
, identification_t
*);
533 owners
->insert_first(owners
, id
);
539 add_shared_list(this, shared
, owners
);
543 * Certificate distribution point
546 certificate_type_t type
;
547 identification_t
*id
;
552 * Destroy a CDP entry
554 static void cdp_destroy(cdp_t
*this)
556 this->id
->destroy(this->id
);
561 METHOD(mem_cred_t
, add_cdp
, void,
562 private_mem_cred_t
*this, certificate_type_t type
,
563 identification_t
*id
, char *uri
)
572 this->lock
->write_lock(this->lock
);
573 this->cdps
->insert_last(this->cdps
, cdp
);
574 this->lock
->unlock(this->lock
);
578 * CDP enumerator data
581 certificate_type_t type
;
582 identification_t
*id
;
587 * Clean up CDP enumerator data
589 static void cdp_data_destroy(cdp_data_t
*data
)
591 data
->lock
->unlock(data
->lock
);
596 * CDP enumerator filter
598 static bool cdp_filter(cdp_data_t
*data
, cdp_t
**cdp
, char **uri
)
600 if (data
->type
!= CERT_ANY
&& data
->type
!= (*cdp
)->type
)
604 if (data
->id
&& !(*cdp
)->id
->matches((*cdp
)->id
, data
->id
))
612 METHOD(credential_set_t
, create_cdp_enumerator
, enumerator_t
*,
613 private_mem_cred_t
*this, certificate_type_t type
, identification_t
*id
)
622 this->lock
->read_lock(this->lock
);
623 return enumerator_create_filter(this->cdps
->create_enumerator(this->cdps
),
624 (void*)cdp_filter
, data
, (void*)cdp_data_destroy
);
628 static void reset_secrets(private_mem_cred_t
*this)
630 this->keys
->destroy_offset(this->keys
, offsetof(private_key_t
, destroy
));
631 this->shared
->destroy_function(this->shared
, (void*)shared_entry_destroy
);
632 this->keys
= linked_list_create();
633 this->shared
= linked_list_create();
636 METHOD(mem_cred_t
, replace_secrets
, void,
637 private_mem_cred_t
*this, mem_cred_t
*other_set
, bool clone
)
639 private_mem_cred_t
*other
= (private_mem_cred_t
*)other_set
;
640 enumerator_t
*enumerator
;
641 shared_entry_t
*entry
, *new_entry
;
644 this->lock
->write_lock(this->lock
);
650 enumerator
= other
->keys
->create_enumerator(other
->keys
);
651 while (enumerator
->enumerate(enumerator
, &key
))
653 this->keys
->insert_last(this->keys
, key
->get_ref(key
));
655 enumerator
->destroy(enumerator
);
656 enumerator
= other
->shared
->create_enumerator(other
->shared
);
657 while (enumerator
->enumerate(enumerator
, &entry
))
660 .shared
= entry
->shared
->get_ref(entry
->shared
),
661 .owners
= entry
->owners
->clone_offset(entry
->owners
,
662 offsetof(identification_t
, clone
)),
664 this->shared
->insert_last(this->shared
, new_entry
);
666 enumerator
->destroy(enumerator
);
670 while (other
->keys
->remove_first(other
->keys
, (void**)&key
) == SUCCESS
)
672 this->keys
->insert_last(this->keys
, key
);
674 while (other
->shared
->remove_first(other
->shared
,
675 (void**)&entry
) == SUCCESS
)
677 this->shared
->insert_last(this->shared
, entry
);
680 this->lock
->unlock(this->lock
);
683 METHOD(mem_cred_t
, clear_secrets
, void,
684 private_mem_cred_t
*this)
686 this->lock
->write_lock(this->lock
);
688 this->lock
->unlock(this->lock
);
691 METHOD(mem_cred_t
, clear_
, void,
692 private_mem_cred_t
*this)
694 this->lock
->write_lock(this->lock
);
695 this->trusted
->destroy_offset(this->trusted
,
696 offsetof(certificate_t
, destroy
));
697 this->untrusted
->destroy_offset(this->untrusted
,
698 offsetof(certificate_t
, destroy
));
699 this->cdps
->destroy_function(this->cdps
, (void*)cdp_destroy
);
700 this->trusted
= linked_list_create();
701 this->untrusted
= linked_list_create();
702 this->cdps
= linked_list_create();
703 this->lock
->unlock(this->lock
);
708 METHOD(mem_cred_t
, destroy
, void,
709 private_mem_cred_t
*this)
712 this->trusted
->destroy(this->trusted
);
713 this->untrusted
->destroy(this->untrusted
);
714 this->keys
->destroy(this->keys
);
715 this->shared
->destroy(this->shared
);
716 this->cdps
->destroy(this->cdps
);
717 this->lock
->destroy(this->lock
);
724 mem_cred_t
*mem_cred_create()
726 private_mem_cred_t
*this;
731 .create_shared_enumerator
= _create_shared_enumerator
,
732 .create_private_enumerator
= _create_private_enumerator
,
733 .create_cert_enumerator
= _create_cert_enumerator
,
734 .create_cdp_enumerator
= _create_cdp_enumerator
,
735 .cache_cert
= (void*)nop
,
737 .add_cert
= _add_cert
,
738 .add_cert_ref
= _add_cert_ref
,
741 .add_shared
= _add_shared
,
742 .add_shared_list
= _add_shared_list
,
744 .replace_secrets
= _replace_secrets
,
746 .clear_secrets
= _clear_secrets
,
749 .trusted
= linked_list_create(),
750 .untrusted
= linked_list_create(),
751 .keys
= linked_list_create(),
752 .shared
= linked_list_create(),
753 .cdps
= linked_list_create(),
754 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
757 return &this->public;