Renamed key_encod{ing,der}_t and constants, prepare for generic credential encoding
[strongswan.git] / src / libstrongswan / credentials / credential_manager.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "credential_manager.h"
17
18 #include <library.h>
19 #include <debug.h>
20 #include <threading/thread_value.h>
21 #include <threading/mutex.h>
22 #include <threading/rwlock.h>
23 #include <utils/linked_list.h>
24 #include <credentials/sets/cert_cache.h>
25 #include <credentials/sets/auth_cfg_wrapper.h>
26 #include <credentials/certificates/x509.h>
27
28 /**
29 * Maximum length of a certificate trust chain
30 */
31 #define MAX_TRUST_PATH_LEN 7
32
33 typedef struct private_credential_manager_t private_credential_manager_t;
34
35 /**
36 * private data of credential_manager
37 */
38 struct private_credential_manager_t {
39
40 /**
41 * public functions
42 */
43 credential_manager_t public;
44
45 /**
46 * list of credential sets
47 */
48 linked_list_t *sets;
49
50 /**
51 * thread local set of credentials, linked_list_t with credential_set_t's
52 */
53 thread_value_t *local_sets;
54
55 /**
56 * trust relationship and certificate cache
57 */
58 cert_cache_t *cache;
59
60 /**
61 * certificates queued for persistent caching
62 */
63 linked_list_t *cache_queue;
64
65 /**
66 * list of certificate validators, cert_validator_t
67 */
68 linked_list_t *validators;
69
70 /**
71 * read-write lock to sets list
72 */
73 rwlock_t *lock;
74
75 /**
76 * mutex for cache queue
77 */
78 mutex_t *queue_mutex;
79 };
80
81 /** data to pass to create_private_enumerator */
82 typedef struct {
83 private_credential_manager_t *this;
84 key_type_t type;
85 identification_t* keyid;
86 } private_data_t;
87
88 /** data to pass to create_cert_enumerator */
89 typedef struct {
90 private_credential_manager_t *this;
91 certificate_type_t cert;
92 key_type_t key;
93 identification_t *id;
94 bool trusted;
95 } cert_data_t;
96
97 /** data to pass to create_cdp_enumerator */
98 typedef struct {
99 private_credential_manager_t *this;
100 certificate_type_t type;
101 identification_t *id;
102 } cdp_data_t;
103
104 /** data to pass to create_shared_enumerator */
105 typedef struct {
106 private_credential_manager_t *this;
107 shared_key_type_t type;
108 identification_t *me;
109 identification_t *other;
110 } shared_data_t;
111
112 /** enumerator over local and global sets */
113 typedef struct {
114 /** implements enumerator_t */
115 enumerator_t public;
116 /** enumerator over global sets */
117 enumerator_t *global;
118 /** enumerator over local sets */
119 enumerator_t *local;
120 } sets_enumerator_t;
121
122
123 METHOD(enumerator_t, sets_enumerate, bool,
124 sets_enumerator_t *this, credential_set_t **set)
125 {
126 if (this->global)
127 {
128 if (this->global->enumerate(this->global, set))
129 {
130 return TRUE;
131 }
132 /* end of global sets, look for local */
133 this->global->destroy(this->global);
134 this->global = NULL;
135 }
136 if (this->local)
137 {
138 return this->local->enumerate(this->local, set);
139 }
140 return FALSE;
141 }
142
143 METHOD(enumerator_t, sets_destroy, void,
144 sets_enumerator_t *this)
145 {
146 DESTROY_IF(this->global);
147 DESTROY_IF(this->local);
148 free(this);
149 }
150
151 /**
152 * create an enumerator over both, global and local sets
153 */
154 static enumerator_t *create_sets_enumerator(private_credential_manager_t *this)
155 {
156 sets_enumerator_t *enumerator;
157 linked_list_t *local;
158
159 INIT(enumerator,
160 .public.enumerate = (void*)_sets_enumerate,
161 .public.destroy = _sets_destroy,
162 .global = this->sets->create_enumerator(this->sets),
163 );
164 local = this->local_sets->get(this->local_sets);
165 if (local)
166 {
167 enumerator->local = local->create_enumerator(local);
168 }
169 return &enumerator->public;
170 }
171
172 /**
173 * cleanup function for cert data
174 */
175 static void destroy_cert_data(cert_data_t *data)
176 {
177 data->this->lock->unlock(data->this->lock);
178 free(data);
179 }
180
181 /**
182 * enumerator constructor for certificates
183 */
184 static enumerator_t *create_cert(credential_set_t *set, cert_data_t *data)
185 {
186 return set->create_cert_enumerator(set, data->cert, data->key,
187 data->id, data->trusted);
188 }
189
190 METHOD(credential_manager_t, create_cert_enumerator, enumerator_t*,
191 private_credential_manager_t *this, certificate_type_t certificate,
192 key_type_t key, identification_t *id, bool trusted)
193 {
194 cert_data_t *data = malloc_thing(cert_data_t);
195 data->this = this;
196 data->cert = certificate;
197 data->key = key;
198 data->id = id;
199 data->trusted = trusted;
200
201 this->lock->read_lock(this->lock);
202 return enumerator_create_nested(create_sets_enumerator(this),
203 (void*)create_cert, data,
204 (void*)destroy_cert_data);
205 }
206
207 METHOD(credential_manager_t, get_cert, certificate_t*,
208 private_credential_manager_t *this, certificate_type_t cert, key_type_t key,
209 identification_t *id, bool trusted)
210 {
211 certificate_t *current, *found = NULL;
212 enumerator_t *enumerator;
213
214 enumerator = create_cert_enumerator(this, cert, key, id, trusted);
215 if (enumerator->enumerate(enumerator, &current))
216 {
217 /* TODO: best match? order by keyid, subject, sualtname */
218 found = current->get_ref(current);
219 }
220 enumerator->destroy(enumerator);
221 return found;
222 }
223
224
225 /**
226 * cleanup function for cdp data
227 */
228 static void destroy_cdp_data(cdp_data_t *data)
229 {
230 data->this->lock->unlock(data->this->lock);
231 free(data);
232 }
233
234 /**
235 * enumerator constructor for CDPs
236 */
237 static enumerator_t *create_cdp(credential_set_t *set, cdp_data_t *data)
238 {
239 return set->create_cdp_enumerator(set, data->type, data->id);
240 }
241
242 METHOD(credential_manager_t, create_cdp_enumerator, enumerator_t*,
243 private_credential_manager_t *this, certificate_type_t type,
244 identification_t *id)
245 {
246 cdp_data_t *data;
247
248 INIT(data,
249 .this = this,
250 .type = type,
251 .id = id,
252 );
253 this->lock->read_lock(this->lock);
254 return enumerator_create_nested(create_sets_enumerator(this),
255 (void*)create_cdp, data,
256 (void*)destroy_cdp_data);
257 }
258
259 /**
260 * cleanup function for private data
261 */
262 static void destroy_private_data(private_data_t *data)
263 {
264 data->this->lock->unlock(data->this->lock);
265 free(data);
266 }
267
268 /**
269 * enumerator constructor for private keys
270 */
271 static enumerator_t *create_private(credential_set_t *set, private_data_t *data)
272 {
273 return set->create_private_enumerator(set, data->type, data->keyid);
274 }
275
276 /**
277 * Create an enumerator over private keys
278 */
279 static enumerator_t *create_private_enumerator(
280 private_credential_manager_t *this, key_type_t key, identification_t *keyid)
281 {
282 private_data_t *data;
283
284 INIT(data,
285 .this = this,
286 .type = key,
287 .keyid = keyid,
288 );
289 this->lock->read_lock(this->lock);
290 return enumerator_create_nested(create_sets_enumerator(this),
291 (void*)create_private, data,
292 (void*)destroy_private_data);
293 }
294
295 /**
296 * Look up a private key by its key identifier
297 */
298 static private_key_t* get_private_by_keyid(private_credential_manager_t *this,
299 key_type_t key, identification_t *keyid)
300 {
301 private_key_t *found = NULL;
302 enumerator_t *enumerator;
303
304 enumerator = create_private_enumerator(this, key, keyid);
305 if (enumerator->enumerate(enumerator, &found))
306 {
307 found->get_ref(found);
308 }
309 enumerator->destroy(enumerator);
310 return found;
311 }
312
313 /**
314 * cleanup function for shared data
315 */
316 static void destroy_shared_data(shared_data_t *data)
317 {
318 data->this->lock->unlock(data->this->lock);
319 free(data);
320 }
321
322 /**
323 * enumerator constructor for shared keys
324 */
325 static enumerator_t *create_shared(credential_set_t *set, shared_data_t *data)
326 {
327 return set->create_shared_enumerator(set, data->type, data->me, data->other);
328 }
329
330 METHOD(credential_manager_t, create_shared_enumerator, enumerator_t*,
331 private_credential_manager_t *this, shared_key_type_t type,
332 identification_t *me, identification_t *other)
333 {
334 shared_data_t *data;
335
336 INIT(data,
337 .this = this,
338 .type = type,
339 .me = me,
340 .other = other,
341 );
342 this->lock->read_lock(this->lock);
343 return enumerator_create_nested(create_sets_enumerator(this),
344 (void*)create_shared, data,
345 (void*)destroy_shared_data);
346 }
347
348 METHOD(credential_manager_t, get_shared, shared_key_t*,
349 private_credential_manager_t *this, shared_key_type_t type,
350 identification_t *me, identification_t *other)
351 {
352 shared_key_t *current, *found = NULL;
353 id_match_t *best_me = ID_MATCH_NONE, *best_other = ID_MATCH_NONE;
354 id_match_t *match_me, *match_other;
355 enumerator_t *enumerator;
356
357 enumerator = create_shared_enumerator(this, type, me, other);
358 while (enumerator->enumerate(enumerator, &current, &match_me, &match_other))
359 {
360 if (match_other > best_other ||
361 (match_other == best_other && match_me > best_me))
362 {
363 DESTROY_IF(found);
364 found = current->get_ref(current);
365 best_me = match_me;
366 best_other = match_other;
367 }
368 }
369 enumerator->destroy(enumerator);
370 return found;
371 }
372
373 METHOD(credential_manager_t, add_local_set, void,
374 private_credential_manager_t *this, credential_set_t *set)
375 {
376 linked_list_t *sets;
377
378 sets = this->local_sets->get(this->local_sets);
379 if (!sets)
380 { /* first invocation */
381 sets = linked_list_create();
382 this->local_sets->set(this->local_sets, sets);
383 }
384 sets->insert_last(sets, set);
385 }
386
387 METHOD(credential_manager_t, remove_local_set, void,
388 private_credential_manager_t *this, credential_set_t *set)
389 {
390 linked_list_t *sets;
391
392 sets = this->local_sets->get(this->local_sets);
393 sets->remove(sets, set, NULL);
394 }
395
396 METHOD(credential_manager_t, cache_cert, void,
397 private_credential_manager_t *this, certificate_t *cert)
398 {
399 credential_set_t *set;
400 enumerator_t *enumerator;
401
402 if (this->lock->try_write_lock(this->lock))
403 {
404 enumerator = this->sets->create_enumerator(this->sets);
405 while (enumerator->enumerate(enumerator, &set))
406 {
407 set->cache_cert(set, cert);
408 }
409 enumerator->destroy(enumerator);
410 this->lock->unlock(this->lock);
411 }
412 else
413 { /* we can't cache now as other threads are active, queue for later */
414 this->queue_mutex->lock(this->queue_mutex);
415 this->cache_queue->insert_last(this->cache_queue, cert->get_ref(cert));
416 this->queue_mutex->unlock(this->queue_mutex);
417 }
418 }
419
420 /**
421 * Try to cache certificates queued for caching
422 */
423 static void cache_queue(private_credential_manager_t *this)
424 {
425 credential_set_t *set;
426 certificate_t *cert;
427 enumerator_t *enumerator;
428
429 this->queue_mutex->lock(this->queue_mutex);
430 if (this->cache_queue->get_count(this->cache_queue) > 0 &&
431 this->lock->try_write_lock(this->lock))
432 {
433 while (this->cache_queue->remove_last(this->cache_queue,
434 (void**)&cert) == SUCCESS)
435 {
436 enumerator = this->sets->create_enumerator(this->sets);
437 while (enumerator->enumerate(enumerator, &set))
438 {
439 set->cache_cert(set, cert);
440 }
441 enumerator->destroy(enumerator);
442 cert->destroy(cert);
443 }
444 this->lock->unlock(this->lock);
445 }
446 this->queue_mutex->unlock(this->queue_mutex);
447 }
448
449 /**
450 * check a certificate for its lifetime
451 */
452 static bool check_certificate(private_credential_manager_t *this,
453 certificate_t *subject, certificate_t *issuer,
454 bool online, int pathlen, auth_cfg_t *auth)
455 {
456 time_t not_before, not_after;
457 cert_validator_t *validator;
458 enumerator_t *enumerator;
459
460 if (!subject->get_validity(subject, NULL, &not_before, &not_after))
461 {
462 DBG1(DBG_CFG, "subject certificate invalid (valid from %T to %T)",
463 &not_before, FALSE, &not_after, FALSE);
464 return FALSE;
465 }
466 if (!issuer->get_validity(issuer, NULL, &not_before, &not_after))
467 {
468 DBG1(DBG_CFG, "issuer certificate invalid (valid from %T to %T)",
469 &not_before, FALSE, &not_after, FALSE);
470 return FALSE;
471 }
472 if (issuer->get_type(issuer) == CERT_X509 &&
473 subject->get_type(subject) == CERT_X509)
474 {
475 int pathlen_constraint;
476 x509_t *x509;
477
478 /* check path length constraint */
479 x509 = (x509_t*)issuer;
480 pathlen_constraint = x509->get_pathLenConstraint(x509);
481 if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT &&
482 pathlen > pathlen_constraint)
483 {
484 DBG1(DBG_CFG, "path length of %d violates constraint of %d",
485 pathlen, pathlen_constraint);
486 return FALSE;
487 }
488 }
489
490 enumerator = this->validators->create_enumerator(this->validators);
491 while (enumerator->enumerate(enumerator, &validator))
492 {
493 if (!validator->validate(validator, subject, issuer,
494 online, pathlen, auth))
495 {
496 enumerator->destroy(enumerator);
497 return FALSE;
498 }
499 }
500 enumerator->destroy(enumerator);
501 return TRUE;
502 }
503
504 /**
505 * Get a trusted certificate from a credential set
506 */
507 static certificate_t *get_pretrusted_cert(private_credential_manager_t *this,
508 key_type_t type, identification_t *id)
509 {
510 certificate_t *subject;
511 public_key_t *public;
512
513 subject = get_cert(this, CERT_ANY, type, id, TRUE);
514 if (!subject)
515 {
516 return NULL;
517 }
518 public = subject->get_public_key(subject);
519 if (!public)
520 {
521 subject->destroy(subject);
522 return NULL;
523 }
524 public->destroy(public);
525 return subject;
526 }
527
528 /**
529 * Get the issuing certificate of a subject certificate
530 */
531 static certificate_t *get_issuer_cert(private_credential_manager_t *this,
532 certificate_t *subject, bool trusted)
533 {
534 enumerator_t *enumerator;
535 certificate_t *issuer = NULL, *candidate;
536
537 enumerator = create_cert_enumerator(this, subject->get_type(subject), KEY_ANY,
538 subject->get_issuer(subject), trusted);
539 while (enumerator->enumerate(enumerator, &candidate))
540 {
541 if (this->cache->issued_by(this->cache, subject, candidate))
542 {
543 issuer = candidate->get_ref(candidate);
544 break;
545 }
546 }
547 enumerator->destroy(enumerator);
548 return issuer;
549 }
550
551 /**
552 * try to verify the trust chain of subject, return TRUE if trusted
553 */
554 static bool verify_trust_chain(private_credential_manager_t *this,
555 certificate_t *subject, auth_cfg_t *result,
556 bool trusted, bool online)
557 {
558 certificate_t *current, *issuer;
559 auth_cfg_t *auth;
560 int pathlen;
561
562 auth = auth_cfg_create();
563 current = subject->get_ref(subject);
564
565 for (pathlen = 0; pathlen <= MAX_TRUST_PATH_LEN; pathlen++)
566 {
567 issuer = get_issuer_cert(this, current, TRUE);
568 if (issuer)
569 {
570 /* accept only self-signed CAs as trust anchor */
571 if (this->cache->issued_by(this->cache, issuer, issuer))
572 {
573 auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer));
574 DBG1(DBG_CFG, " using trusted ca certificate \"%Y\"",
575 issuer->get_subject(issuer));
576 trusted = TRUE;
577 }
578 else
579 {
580 auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
581 DBG1(DBG_CFG, " using trusted intermediate ca certificate "
582 "\"%Y\"", issuer->get_subject(issuer));
583 }
584 }
585 else
586 {
587 issuer = get_issuer_cert(this, current, FALSE);
588 if (issuer)
589 {
590 if (current->equals(current, issuer))
591 {
592 DBG1(DBG_CFG, " self-signed certificate \"%Y\" is not trusted",
593 current->get_subject(current));
594 issuer->destroy(issuer);
595 break;
596 }
597 auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
598 DBG1(DBG_CFG, " using untrusted intermediate certificate "
599 "\"%Y\"", issuer->get_subject(issuer));
600 }
601 else
602 {
603 DBG1(DBG_CFG, "no issuer certificate found for \"%Y\"",
604 current->get_subject(current));
605 break;
606 }
607 }
608 if (!check_certificate(this, current, issuer, online, pathlen,
609 current == subject ? auth : NULL))
610 {
611 trusted = FALSE;
612 issuer->destroy(issuer);
613 break;
614 }
615 current->destroy(current);
616 current = issuer;
617 if (trusted)
618 {
619 DBG1(DBG_CFG, " reached self-signed root ca with a path length of %d",
620 pathlen);
621 break;
622 }
623 }
624 current->destroy(current);
625 if (pathlen > MAX_TRUST_PATH_LEN)
626 {
627 DBG1(DBG_CFG, "maximum path length of %d exceeded", MAX_TRUST_PATH_LEN);
628 }
629 if (trusted)
630 {
631 result->merge(result, auth, FALSE);
632 }
633 auth->destroy(auth);
634 return trusted;
635 }
636
637 /**
638 * enumerator for trusted certificates
639 */
640 typedef struct {
641 /** implements enumerator_t interface */
642 enumerator_t public;
643 /** enumerator over candidate peer certificates */
644 enumerator_t *candidates;
645 /** reference to the credential_manager */
646 private_credential_manager_t *this;
647 /** type of the requested key */
648 key_type_t type;
649 /** identity the requested key belongs to */
650 identification_t *id;
651 /** TRUE to do CRL/OCSP checking */
652 bool online;
653 /** pretrusted certificate we have served at first invocation */
654 certificate_t *pretrusted;
655 /** currently enumerating auth config */
656 auth_cfg_t *auth;
657 } trusted_enumerator_t;
658
659 METHOD(enumerator_t, trusted_enumerate, bool,
660 trusted_enumerator_t *this, certificate_t **cert, auth_cfg_t **auth)
661 {
662 certificate_t *current;
663
664 DESTROY_IF(this->auth);
665 this->auth = auth_cfg_create();
666
667 if (!this->candidates)
668 {
669 /* first invocation, build enumerator for next one */
670 this->candidates = create_cert_enumerator(this->this, CERT_ANY,
671 this->type, this->id, FALSE);
672 /* check if we have a trusted certificate for that peer */
673 this->pretrusted = get_pretrusted_cert(this->this, this->type, this->id);
674 if (this->pretrusted)
675 {
676 /* if we find a trusted self signed certificate, we just accept it.
677 * However, in order to fulfill authorization rules, we try to build
678 * the trust chain if it is not self signed */
679 if (this->this->cache->issued_by(this->this->cache,
680 this->pretrusted, this->pretrusted) ||
681 verify_trust_chain(this->this, this->pretrusted, this->auth,
682 TRUE, this->online))
683 {
684 this->auth->add(this->auth, AUTH_RULE_SUBJECT_CERT,
685 this->pretrusted->get_ref(this->pretrusted));
686 DBG1(DBG_CFG, " using trusted certificate \"%Y\"",
687 this->pretrusted->get_subject(this->pretrusted));
688 *cert = this->pretrusted;
689 if (auth)
690 {
691 *auth = this->auth;
692 }
693 return TRUE;
694 }
695 }
696 }
697 /* try to verify the trust chain for each certificate found */
698 while (this->candidates->enumerate(this->candidates, &current))
699 {
700 if (this->pretrusted &&
701 this->pretrusted->equals(this->pretrusted, current))
702 { /* skip pretrusted certificate we already served */
703 continue;
704 }
705
706 DBG1(DBG_CFG, " using certificate \"%Y\"",
707 current->get_subject(current));
708 if (verify_trust_chain(this->this, current, this->auth, FALSE,
709 this->online))
710 {
711 *cert = current;
712 if (auth)
713 {
714 *auth = this->auth;
715 }
716 return TRUE;
717 }
718 }
719 return FALSE;
720 }
721
722 METHOD(enumerator_t, trusted_destroy, void,
723 trusted_enumerator_t *this)
724 {
725 DESTROY_IF(this->pretrusted);
726 DESTROY_IF(this->auth);
727 DESTROY_IF(this->candidates);
728 free(this);
729 }
730
731 METHOD(credential_manager_t, create_trusted_enumerator, enumerator_t*,
732 private_credential_manager_t *this, key_type_t type,
733 identification_t *id, bool online)
734 {
735 trusted_enumerator_t *enumerator;
736
737 INIT(enumerator,
738 .public = {
739 .enumerate = (void*)_trusted_enumerate,
740 .destroy = _trusted_destroy,
741 },
742 .this = this,
743 .type = type,
744 .id = id,
745 .online = online,
746 );
747 return &enumerator->public;
748 }
749
750 /**
751 * enumerator for public keys
752 */
753 typedef struct {
754 /** implements enumerator_t interface */
755 enumerator_t public;
756 /** enumerator over candidate peer certificates */
757 enumerator_t *inner;
758 /** reference to the credential_manager */
759 private_credential_manager_t *this;
760 /** currently enumerating key */
761 public_key_t *current;
762 /** credset wrapper around auth config */
763 auth_cfg_wrapper_t *wrapper;
764 } public_enumerator_t;
765
766 METHOD(enumerator_t, public_enumerate, bool,
767 public_enumerator_t *this, public_key_t **key, auth_cfg_t **auth)
768 {
769 certificate_t *cert;
770
771 while (this->inner->enumerate(this->inner, &cert, auth))
772 {
773 DESTROY_IF(this->current);
774 this->current = cert->get_public_key(cert);
775 if (this->current)
776 {
777 *key = this->current;
778 return TRUE;
779 }
780 }
781 return FALSE;
782 }
783
784 METHOD(enumerator_t, public_destroy, void,
785 public_enumerator_t *this)
786 {
787 DESTROY_IF(this->current);
788 this->inner->destroy(this->inner);
789 if (this->wrapper)
790 {
791 remove_local_set(this->this, &this->wrapper->set);
792 this->wrapper->destroy(this->wrapper);
793 }
794 this->this->lock->unlock(this->this->lock);
795
796 /* check for delayed certificate cache queue */
797 cache_queue(this->this);
798 free(this);
799 }
800
801 METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
802 private_credential_manager_t *this, key_type_t type, identification_t *id,
803 auth_cfg_t *auth)
804 {
805 public_enumerator_t *enumerator;
806
807 INIT(enumerator,
808 .public = {
809 .enumerate = (void*)_public_enumerate,
810 .destroy = _public_destroy,
811 },
812 .inner = create_trusted_enumerator(this, type, id, TRUE),
813 .this = this,
814 );
815 if (auth)
816 {
817 enumerator->wrapper = auth_cfg_wrapper_create(auth);
818 add_local_set(this, &enumerator->wrapper->set);
819 }
820 this->lock->read_lock(this->lock);
821 return &enumerator->public;
822 }
823
824 /**
825 * Check if a certificate's keyid is contained in the auth helper
826 */
827 static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert)
828 {
829 enumerator_t *enumerator;
830 identification_t *value;
831 auth_rule_t type;
832 bool found = FALSE;
833
834 enumerator = auth->create_enumerator(auth);
835 while (enumerator->enumerate(enumerator, &type, &value))
836 {
837 if (type == AUTH_RULE_CA_CERT &&
838 cert->equals(cert, (certificate_t*)value))
839 {
840 found = TRUE;
841 break;
842 }
843 }
844 enumerator->destroy(enumerator);
845 return found;
846 }
847
848 /**
849 * build a trustchain from subject up to a trust anchor in trusted
850 */
851 static auth_cfg_t *build_trustchain(private_credential_manager_t *this,
852 certificate_t *subject, auth_cfg_t *auth)
853 {
854 certificate_t *issuer, *current;
855 auth_cfg_t *trustchain;
856 int pathlen = 0;
857
858 trustchain = auth_cfg_create();
859
860 current = auth->get(auth, AUTH_RULE_CA_CERT);
861 if (!current)
862 {
863 /* no trust anchor specified, return this cert only */
864 trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT,
865 subject->get_ref(subject));
866 return trustchain;
867 }
868 current = subject->get_ref(subject);
869 while (TRUE)
870 {
871 if (auth_contains_cacert(auth, current))
872 {
873 trustchain->add(trustchain, AUTH_RULE_CA_CERT, current);
874 return trustchain;
875 }
876 if (subject == current)
877 {
878 trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT, current);
879 }
880 else
881 {
882 trustchain->add(trustchain, AUTH_RULE_IM_CERT, current);
883 }
884 issuer = get_issuer_cert(this, current, FALSE);
885 if (!issuer || issuer->equals(issuer, current) ||
886 pathlen > MAX_TRUST_PATH_LEN)
887 {
888 DESTROY_IF(issuer);
889 break;
890 }
891 current = issuer;
892 pathlen++;
893 }
894 trustchain->destroy(trustchain);
895 return NULL;
896 }
897
898 /**
899 * find a private key of a give certificate
900 */
901 static private_key_t *get_private_by_cert(private_credential_manager_t *this,
902 certificate_t *cert, key_type_t type)
903 {
904 private_key_t *private = NULL;
905 identification_t *keyid;
906 chunk_t chunk;
907 public_key_t *public;
908
909 public = cert->get_public_key(cert);
910 if (public)
911 {
912 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
913 {
914 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
915 private = get_private_by_keyid(this, type, keyid);
916 keyid->destroy(keyid);
917 }
918 public->destroy(public);
919 }
920 return private;
921 }
922
923 METHOD(credential_manager_t, get_private, private_key_t*,
924 private_credential_manager_t *this, key_type_t type, identification_t *id,
925 auth_cfg_t *auth)
926 {
927 enumerator_t *enumerator;
928 certificate_t *cert;
929 private_key_t *private = NULL;
930 auth_cfg_t *trustchain;
931
932 /* check if this is a lookup by key ID, and do it if so */
933 if (id && id->get_type(id) == ID_KEY_ID)
934 {
935 private = get_private_by_keyid(this, type, id);
936 if (private)
937 {
938 return private;
939 }
940 }
941
942 /* if a specific certificate is preferred, check for a matching key */
943 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
944 if (cert)
945 {
946 private = get_private_by_cert(this, cert, type);
947 if (private)
948 {
949 trustchain = build_trustchain(this, cert, auth);
950 if (trustchain)
951 {
952 auth->merge(auth, trustchain, FALSE);
953 trustchain->destroy(trustchain);
954 }
955 return private;
956 }
957 }
958
959 /* try to build a trust chain for each certificate found */
960 enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
961 while (enumerator->enumerate(enumerator, &cert))
962 {
963 private = get_private_by_cert(this, cert, type);
964 if (private)
965 {
966 trustchain = build_trustchain(this, cert, auth);
967 if (trustchain)
968 {
969 auth->merge(auth, trustchain, FALSE);
970 trustchain->destroy(trustchain);
971 break;
972 }
973 private->destroy(private);
974 private = NULL;
975 }
976 }
977 enumerator->destroy(enumerator);
978
979 /* if no valid trustchain was found, fall back to the first usable cert */
980 if (!private)
981 {
982 enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
983 while (enumerator->enumerate(enumerator, &cert))
984 {
985 private = get_private_by_cert(this, cert, type);
986 if (private)
987 {
988 auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert));
989 break;
990 }
991 }
992 enumerator->destroy(enumerator);
993 }
994 return private;
995 }
996
997 METHOD(credential_manager_t, flush_cache, void,
998 private_credential_manager_t *this, certificate_type_t type)
999 {
1000 this->cache->flush(this->cache, type);
1001 }
1002
1003 METHOD(credential_manager_t, issued_by, bool,
1004 private_credential_manager_t *this, certificate_t *subject,
1005 certificate_t *issuer)
1006 {
1007 return this->cache->issued_by(this->cache, subject, issuer);
1008 }
1009
1010 METHOD(credential_manager_t, add_set, void,
1011 private_credential_manager_t *this, credential_set_t *set)
1012 {
1013 this->lock->write_lock(this->lock);
1014 this->sets->insert_last(this->sets, set);
1015 this->lock->unlock(this->lock);
1016 }
1017
1018 METHOD(credential_manager_t, remove_set, void,
1019 private_credential_manager_t *this, credential_set_t *set)
1020 {
1021 this->lock->write_lock(this->lock);
1022 this->sets->remove(this->sets, set, NULL);
1023 this->lock->unlock(this->lock);
1024 }
1025
1026 METHOD(credential_manager_t, add_validator, void,
1027 private_credential_manager_t *this, cert_validator_t *vdtr)
1028 {
1029 this->lock->write_lock(this->lock);
1030 this->sets->insert_last(this->validators, vdtr);
1031 this->lock->unlock(this->lock);
1032 }
1033
1034 METHOD(credential_manager_t, remove_validator, void,
1035 private_credential_manager_t *this, cert_validator_t *vdtr)
1036 {
1037 this->lock->write_lock(this->lock);
1038 this->validators->remove(this->validators, vdtr, NULL);
1039 this->lock->unlock(this->lock);
1040 }
1041
1042 METHOD(credential_manager_t, destroy, void,
1043 private_credential_manager_t *this)
1044 {
1045 cache_queue(this);
1046 this->cache_queue->destroy(this->cache_queue);
1047 this->sets->remove(this->sets, this->cache, NULL);
1048 this->sets->destroy(this->sets);
1049 this->local_sets->destroy(this->local_sets);
1050 this->cache->destroy(this->cache);
1051 this->validators->destroy(this->validators);
1052 this->lock->destroy(this->lock);
1053 this->queue_mutex->destroy(this->queue_mutex);
1054 free(this);
1055 }
1056
1057 /*
1058 * see header file
1059 */
1060 credential_manager_t *credential_manager_create()
1061 {
1062 private_credential_manager_t *this;
1063
1064 INIT(this,
1065 .public = {
1066 .create_cert_enumerator = _create_cert_enumerator,
1067 .create_shared_enumerator = _create_shared_enumerator,
1068 .create_cdp_enumerator = _create_cdp_enumerator,
1069 .get_cert = _get_cert,
1070 .get_shared = _get_shared,
1071 .get_private = _get_private,
1072 .create_trusted_enumerator = _create_trusted_enumerator,
1073 .create_public_enumerator = _create_public_enumerator,
1074 .flush_cache = _flush_cache,
1075 .cache_cert = _cache_cert,
1076 .issued_by = _issued_by,
1077 .add_set = _add_set,
1078 .remove_set = _remove_set,
1079 .add_local_set = _add_local_set,
1080 .remove_local_set = _remove_local_set,
1081 .add_validator = _add_validator,
1082 .remove_validator = _remove_validator,
1083 .destroy = _destroy,
1084 },
1085 .sets = linked_list_create(),
1086 .validators = linked_list_create(),
1087 .cache = cert_cache_create(),
1088 .cache_queue = linked_list_create(),
1089 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1090 .queue_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
1091 );
1092
1093 this->local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy);
1094 this->sets->insert_first(this->sets, this->cache);
1095
1096 return &this->public;
1097 }