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