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
, get_cert_ref
, certificate_t
*,
196 private_mem_cred_t
*this, certificate_t
*cert
)
198 certificate_t
*cached
;
200 this->lock
->write_lock(this->lock
);
201 if (this->untrusted
->find_first(this->untrusted
,
202 (linked_list_match_t
)certificate_equals
,
203 (void**)&cached
, cert
) == SUCCESS
)
206 cert
= cached
->get_ref(cached
);
208 this->lock
->unlock(this->lock
);
213 METHOD(mem_cred_t
, add_crl
, bool,
214 private_mem_cred_t
*this, crl_t
*crl
)
216 certificate_t
*current
, *cert
= &crl
->certificate
;
217 enumerator_t
*enumerator
;
220 this->lock
->write_lock(this->lock
);
221 enumerator
= this->untrusted
->create_enumerator(this->untrusted
);
222 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
224 if (current
->get_type(current
) == CERT_X509_CRL
)
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
);
231 /* compare authorityKeyIdentifiers if available */
232 if (chunk_equals(authkey
, authkey_c
))
238 identification_t
*issuer
= cert
->get_issuer(cert
);
239 identification_t
*issuer_c
= current
->get_issuer(current
);
241 /* otherwise compare issuer distinguished names */
242 if (issuer
->equals(issuer
, issuer_c
))
249 new = crl_is_newer(crl
, crl_c
);
252 this->untrusted
->remove_at(this->untrusted
, enumerator
);
262 enumerator
->destroy(enumerator
);
266 this->untrusted
->insert_first(this->untrusted
, cert
);
268 this->lock
->unlock(this->lock
);
273 * Data for key enumerator
278 identification_t
*id
;
282 * Destroy key enumerator data
284 static void key_data_destroy(key_data_t
*data
)
286 data
->lock
->unlock(data
->lock
);
291 * filter function for private key enumerator
293 static bool key_filter(key_data_t
*data
, private_key_t
**in
, private_key_t
**out
)
298 if (data
->type
== KEY_ANY
|| data
->type
== key
->get_type(key
))
300 if (data
->id
== NULL
||
301 key
->has_fingerprint(key
, data
->id
->get_encoding(data
->id
)))
310 METHOD(credential_set_t
, create_private_enumerator
, enumerator_t
*,
311 private_mem_cred_t
*this, key_type_t type
, identification_t
*id
)
320 this->lock
->read_lock(this->lock
);
321 return enumerator_create_filter(this->keys
->create_enumerator(this->keys
),
322 (void*)key_filter
, data
, (void*)key_data_destroy
);
325 METHOD(mem_cred_t
, add_key
, void,
326 private_mem_cred_t
*this, private_key_t
*key
)
328 enumerator_t
*enumerator
;
329 private_key_t
*current
;
331 this->lock
->write_lock(this->lock
);
333 enumerator
= this->keys
->create_enumerator(this->keys
);
334 while (enumerator
->enumerate(enumerator
, ¤t
))
336 if (current
->equals(current
, key
))
338 this->keys
->remove_at(this->keys
, enumerator
);
339 current
->destroy(current
);
343 enumerator
->destroy(enumerator
);
345 this->keys
->insert_first(this->keys
, key
);
347 this->lock
->unlock(this->lock
);
355 shared_key_t
*shared
;
356 /* list of owners, identification_t */
357 linked_list_t
*owners
;
361 * Clean up a shared entry
363 static void shared_entry_destroy(shared_entry_t
*entry
)
365 entry
->owners
->destroy_offset(entry
->owners
,
366 offsetof(identification_t
, destroy
));
367 entry
->shared
->destroy(entry
->shared
);
372 * Check if two shared key entries equal
374 static bool shared_entry_equals(shared_entry_t
*a
, shared_entry_t
*b
)
376 enumerator_t
*e1
, *e2
;
377 identification_t
*id1
, *id2
;
380 if (a
->shared
->get_type(a
->shared
) != b
->shared
->get_type(b
->shared
))
384 if (!chunk_equals(a
->shared
->get_key(a
->shared
),
385 b
->shared
->get_key(b
->shared
)))
389 if (a
->owners
->get_count(a
->owners
) != b
->owners
->get_count(b
->owners
))
393 e1
= a
->owners
->create_enumerator(a
->owners
);
394 e2
= b
->owners
->create_enumerator(b
->owners
);
395 while (e1
->enumerate(e1
, &id1
) && e2
->enumerate(e2
, &id2
))
397 if (!id1
->equals(id1
, id2
))
410 * Data for the shared_key enumerator
414 identification_t
*me
;
415 identification_t
*other
;
416 shared_key_type_t type
;
420 * free shared key enumerator data and unlock list
422 static void shared_data_destroy(shared_data_t
*data
)
424 data
->lock
->unlock(data
->lock
);
429 * Get the best match of an owner in an entry.
431 static id_match_t
has_owner(shared_entry_t
*entry
, identification_t
*owner
)
433 enumerator_t
*enumerator
;
434 id_match_t match
, best
= ID_MATCH_NONE
;
435 identification_t
*current
;
437 enumerator
= entry
->owners
->create_enumerator(entry
->owners
);
438 while (enumerator
->enumerate(enumerator
, ¤t
))
440 match
= owner
->matches(owner
, current
);
446 enumerator
->destroy(enumerator
);
451 * enumerator filter function for shared entries
453 static bool shared_filter(shared_data_t
*data
,
454 shared_entry_t
**in
, shared_key_t
**out
,
455 void **unused1
, id_match_t
*me
,
456 void **unused2
, id_match_t
*other
)
458 id_match_t my_match
= ID_MATCH_NONE
, other_match
= ID_MATCH_NONE
;
459 shared_entry_t
*entry
= *in
;
461 if (data
->type
!= SHARED_ANY
&&
462 entry
->shared
->get_type(entry
->shared
) != data
->type
)
468 my_match
= has_owner(entry
, data
->me
);
472 other_match
= has_owner(entry
, data
->other
);
474 if ((data
->me
|| data
->other
) && (!my_match
&& !other_match
))
478 *out
= entry
->shared
;
485 *other
= other_match
;
490 METHOD(credential_set_t
, create_shared_enumerator
, enumerator_t
*,
491 private_mem_cred_t
*this, shared_key_type_t type
,
492 identification_t
*me
, identification_t
*other
)
502 data
->lock
->read_lock(data
->lock
);
503 return enumerator_create_filter(
504 this->shared
->create_enumerator(this->shared
),
505 (void*)shared_filter
, data
, (void*)shared_data_destroy
);
508 METHOD(mem_cred_t
, add_shared_list
, void,
509 private_mem_cred_t
*this, shared_key_t
*shared
, linked_list_t
* owners
)
511 shared_entry_t
*current
, *new;
512 enumerator_t
*enumerator
;
519 this->lock
->write_lock(this->lock
);
521 enumerator
= this->shared
->create_enumerator(this->shared
);
522 while (enumerator
->enumerate(enumerator
, ¤t
))
524 if (shared_entry_equals(current
, new))
526 this->shared
->remove_at(this->shared
, enumerator
);
527 shared_entry_destroy(current
);
531 enumerator
->destroy(enumerator
);
533 this->shared
->insert_first(this->shared
, new);
535 this->lock
->unlock(this->lock
);
538 METHOD(mem_cred_t
, add_shared
, void,
539 private_mem_cred_t
*this, shared_key_t
*shared
, ...)
541 identification_t
*id
;
542 linked_list_t
*owners
= linked_list_create();
545 va_start(args
, shared
);
548 id
= va_arg(args
, identification_t
*);
551 owners
->insert_first(owners
, id
);
557 add_shared_list(this, shared
, owners
);
561 * Certificate distribution point
564 certificate_type_t type
;
565 identification_t
*id
;
570 * Destroy a CDP entry
572 static void cdp_destroy(cdp_t
*this)
574 this->id
->destroy(this->id
);
579 METHOD(mem_cred_t
, add_cdp
, void,
580 private_mem_cred_t
*this, certificate_type_t type
,
581 identification_t
*id
, char *uri
)
590 this->lock
->write_lock(this->lock
);
591 this->cdps
->insert_last(this->cdps
, cdp
);
592 this->lock
->unlock(this->lock
);
596 * CDP enumerator data
599 certificate_type_t type
;
600 identification_t
*id
;
605 * Clean up CDP enumerator data
607 static void cdp_data_destroy(cdp_data_t
*data
)
609 data
->lock
->unlock(data
->lock
);
614 * CDP enumerator filter
616 static bool cdp_filter(cdp_data_t
*data
, cdp_t
**cdp
, char **uri
)
618 if (data
->type
!= CERT_ANY
&& data
->type
!= (*cdp
)->type
)
622 if (data
->id
&& !(*cdp
)->id
->matches((*cdp
)->id
, data
->id
))
630 METHOD(credential_set_t
, create_cdp_enumerator
, enumerator_t
*,
631 private_mem_cred_t
*this, certificate_type_t type
, identification_t
*id
)
640 this->lock
->read_lock(this->lock
);
641 return enumerator_create_filter(this->cdps
->create_enumerator(this->cdps
),
642 (void*)cdp_filter
, data
, (void*)cdp_data_destroy
);
646 static void reset_secrets(private_mem_cred_t
*this)
648 this->keys
->destroy_offset(this->keys
, offsetof(private_key_t
, destroy
));
649 this->shared
->destroy_function(this->shared
, (void*)shared_entry_destroy
);
650 this->keys
= linked_list_create();
651 this->shared
= linked_list_create();
654 METHOD(mem_cred_t
, replace_secrets
, void,
655 private_mem_cred_t
*this, mem_cred_t
*other_set
, bool clone
)
657 private_mem_cred_t
*other
= (private_mem_cred_t
*)other_set
;
658 enumerator_t
*enumerator
;
659 shared_entry_t
*entry
, *new_entry
;
662 this->lock
->write_lock(this->lock
);
668 enumerator
= other
->keys
->create_enumerator(other
->keys
);
669 while (enumerator
->enumerate(enumerator
, &key
))
671 this->keys
->insert_last(this->keys
, key
->get_ref(key
));
673 enumerator
->destroy(enumerator
);
674 enumerator
= other
->shared
->create_enumerator(other
->shared
);
675 while (enumerator
->enumerate(enumerator
, &entry
))
678 .shared
= entry
->shared
->get_ref(entry
->shared
),
679 .owners
= entry
->owners
->clone_offset(entry
->owners
,
680 offsetof(identification_t
, clone
)),
682 this->shared
->insert_last(this->shared
, new_entry
);
684 enumerator
->destroy(enumerator
);
688 while (other
->keys
->remove_first(other
->keys
, (void**)&key
) == SUCCESS
)
690 this->keys
->insert_last(this->keys
, key
);
692 while (other
->shared
->remove_first(other
->shared
,
693 (void**)&entry
) == SUCCESS
)
695 this->shared
->insert_last(this->shared
, entry
);
698 this->lock
->unlock(this->lock
);
701 METHOD(mem_cred_t
, clear_secrets
, void,
702 private_mem_cred_t
*this)
704 this->lock
->write_lock(this->lock
);
706 this->lock
->unlock(this->lock
);
709 METHOD(mem_cred_t
, clear_
, void,
710 private_mem_cred_t
*this)
712 this->lock
->write_lock(this->lock
);
713 this->trusted
->destroy_offset(this->trusted
,
714 offsetof(certificate_t
, destroy
));
715 this->untrusted
->destroy_offset(this->untrusted
,
716 offsetof(certificate_t
, destroy
));
717 this->cdps
->destroy_function(this->cdps
, (void*)cdp_destroy
);
718 this->trusted
= linked_list_create();
719 this->untrusted
= linked_list_create();
720 this->cdps
= linked_list_create();
721 this->lock
->unlock(this->lock
);
726 METHOD(mem_cred_t
, destroy
, void,
727 private_mem_cred_t
*this)
730 this->trusted
->destroy(this->trusted
);
731 this->untrusted
->destroy(this->untrusted
);
732 this->keys
->destroy(this->keys
);
733 this->shared
->destroy(this->shared
);
734 this->cdps
->destroy(this->cdps
);
735 this->lock
->destroy(this->lock
);
742 mem_cred_t
*mem_cred_create()
744 private_mem_cred_t
*this;
749 .create_shared_enumerator
= _create_shared_enumerator
,
750 .create_private_enumerator
= _create_private_enumerator
,
751 .create_cert_enumerator
= _create_cert_enumerator
,
752 .create_cdp_enumerator
= _create_cdp_enumerator
,
753 .cache_cert
= (void*)nop
,
755 .add_cert
= _add_cert
,
756 .add_cert_ref
= _add_cert_ref
,
757 .get_cert_ref
= _get_cert_ref
,
760 .add_shared
= _add_shared
,
761 .add_shared_list
= _add_shared_list
,
763 .replace_secrets
= _replace_secrets
,
765 .clear_secrets
= _clear_secrets
,
768 .trusted
= linked_list_create(),
769 .untrusted
= linked_list_create(),
770 .keys
= linked_list_create(),
771 .shared
= linked_list_create(),
772 .cdps
= linked_list_create(),
773 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
776 return &this->public;