Merge branch 'mbb-reauth-online-revocation'
[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 /* check for delayed certificate cache queue */
922 cache_queue(this->this);
923 free(this);
924 }
925
926 METHOD(credential_manager_t, create_trusted_enumerator, enumerator_t*,
927 private_credential_manager_t *this, key_type_t type,
928 identification_t *id, bool online)
929 {
930 trusted_enumerator_t *enumerator;
931
932 INIT(enumerator,
933 .public = {
934 .enumerate = (void*)_trusted_enumerate,
935 .destroy = _trusted_destroy,
936 },
937 .this = this,
938 .type = type,
939 .id = id,
940 .online = online,
941 .failed = linked_list_create(),
942 );
943 return &enumerator->public;
944 }
945
946 /**
947 * enumerator for public keys
948 */
949 typedef struct {
950 /** implements enumerator_t interface */
951 enumerator_t public;
952 /** enumerator over candidate peer certificates */
953 enumerator_t *inner;
954 /** reference to the credential_manager */
955 private_credential_manager_t *this;
956 /** currently enumerating key */
957 public_key_t *current;
958 /** credset wrapper around auth config */
959 auth_cfg_wrapper_t *wrapper;
960 } public_enumerator_t;
961
962 METHOD(enumerator_t, public_enumerate, bool,
963 public_enumerator_t *this, public_key_t **key, auth_cfg_t **auth)
964 {
965 certificate_t *cert;
966
967 while (this->inner->enumerate(this->inner, &cert, auth))
968 {
969 DESTROY_IF(this->current);
970 this->current = cert->get_public_key(cert);
971 if (this->current)
972 {
973 *key = this->current;
974 return TRUE;
975 }
976 }
977 return FALSE;
978 }
979
980 METHOD(enumerator_t, public_destroy, void,
981 public_enumerator_t *this)
982 {
983 DESTROY_IF(this->current);
984 this->inner->destroy(this->inner);
985 if (this->wrapper)
986 {
987 remove_local_set(this->this, &this->wrapper->set);
988 this->wrapper->destroy(this->wrapper);
989 }
990 this->this->lock->unlock(this->this->lock);
991 /* check for delayed certificate cache queue */
992 cache_queue(this->this);
993 free(this);
994 }
995
996 METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
997 private_credential_manager_t *this, key_type_t type, identification_t *id,
998 auth_cfg_t *auth, bool online)
999 {
1000 public_enumerator_t *enumerator;
1001
1002 INIT(enumerator,
1003 .public = {
1004 .enumerate = (void*)_public_enumerate,
1005 .destroy = _public_destroy,
1006 },
1007 .inner = create_trusted_enumerator(this, type, id, online),
1008 .this = this,
1009 );
1010 if (auth)
1011 {
1012 enumerator->wrapper = auth_cfg_wrapper_create(auth);
1013 add_local_set(this, &enumerator->wrapper->set, FALSE);
1014 }
1015 this->lock->read_lock(this->lock);
1016 return &enumerator->public;
1017 }
1018
1019 /**
1020 * Check if a helper contains a certificate as trust anchor
1021 */
1022 static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert)
1023 {
1024 enumerator_t *enumerator;
1025 identification_t *value;
1026 auth_rule_t type;
1027 bool found = FALSE;
1028
1029 enumerator = auth->create_enumerator(auth);
1030 while (enumerator->enumerate(enumerator, &type, &value))
1031 {
1032 if (type == AUTH_RULE_CA_CERT &&
1033 cert->equals(cert, (certificate_t*)value))
1034 {
1035 found = TRUE;
1036 break;
1037 }
1038 }
1039 enumerator->destroy(enumerator);
1040 return found;
1041 }
1042
1043 /**
1044 * build a trustchain from subject up to a trust anchor in trusted
1045 */
1046 static auth_cfg_t *build_trustchain(private_credential_manager_t *this,
1047 certificate_t *subject, auth_cfg_t *auth)
1048 {
1049 certificate_t *issuer, *current;
1050 auth_cfg_t *trustchain;
1051 int pathlen = 0;
1052 bool has_anchor;
1053
1054 trustchain = auth_cfg_create();
1055 has_anchor = auth->get(auth, AUTH_RULE_CA_CERT) != NULL;
1056 current = subject->get_ref(subject);
1057 while (TRUE)
1058 {
1059 if (auth_contains_cacert(auth, current))
1060 {
1061 trustchain->add(trustchain, AUTH_RULE_CA_CERT, current);
1062 return trustchain;
1063 }
1064 if (subject == current)
1065 {
1066 trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT, current);
1067 }
1068 else
1069 {
1070 if (!has_anchor && issued_by(this, current, current, NULL))
1071 { /* If no trust anchor specified, accept any CA */
1072 trustchain->add(trustchain, AUTH_RULE_CA_CERT, current);
1073 return trustchain;
1074 }
1075 trustchain->add(trustchain, AUTH_RULE_IM_CERT, current);
1076 }
1077 if (pathlen++ > MAX_TRUST_PATH_LEN)
1078 {
1079 break;
1080 }
1081 issuer = get_issuer_cert(this, current, FALSE, NULL);
1082 if (!issuer)
1083 {
1084 if (!has_anchor)
1085 { /* If no trust anchor specified, accept incomplete chains */
1086 return trustchain;
1087 }
1088 break;
1089 }
1090 if (has_anchor && issuer->equals(issuer, current))
1091 {
1092 issuer->destroy(issuer);
1093 break;
1094 }
1095 current = issuer;
1096 }
1097 trustchain->destroy(trustchain);
1098 return NULL;
1099 }
1100
1101 /**
1102 * find a private key of a given certificate
1103 */
1104 static private_key_t *get_private_by_cert(private_credential_manager_t *this,
1105 certificate_t *cert, key_type_t type)
1106 {
1107 private_key_t *private = NULL;
1108 identification_t *keyid;
1109 chunk_t chunk;
1110 public_key_t *public;
1111
1112 public = cert->get_public_key(cert);
1113 if (public)
1114 {
1115 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
1116 {
1117 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
1118 private = get_private_by_keyid(this, type, keyid);
1119 keyid->destroy(keyid);
1120 }
1121 public->destroy(public);
1122 }
1123 return private;
1124 }
1125
1126 /**
1127 * Move the actually used certificate to front, so it gets returned with get()
1128 */
1129 static void prefer_cert(auth_cfg_t *auth, certificate_t *cert)
1130 {
1131 enumerator_t *enumerator;
1132 auth_rule_t rule;
1133 certificate_t *current;
1134
1135 enumerator = auth->create_enumerator(auth);
1136 while (enumerator->enumerate(enumerator, &rule, &current))
1137 {
1138 if (rule == AUTH_RULE_SUBJECT_CERT)
1139 {
1140 current->get_ref(current);
1141 auth->replace(auth, enumerator, AUTH_RULE_SUBJECT_CERT, cert);
1142 cert = current;
1143 }
1144 }
1145 enumerator->destroy(enumerator);
1146 auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert);
1147 }
1148
1149 METHOD(credential_manager_t, get_private, private_key_t*,
1150 private_credential_manager_t *this, key_type_t type, identification_t *id,
1151 auth_cfg_t *auth)
1152 {
1153 enumerator_t *enumerator;
1154 certificate_t *cert;
1155 private_key_t *private = NULL;
1156 auth_cfg_t *trustchain;
1157 auth_rule_t rule;
1158
1159 /* check if this is a lookup by key ID, and do it if so */
1160 if (id && id->get_type(id) == ID_KEY_ID)
1161 {
1162 private = get_private_by_keyid(this, type, id);
1163 if (private)
1164 {
1165 return private;
1166 }
1167 }
1168
1169 if (auth)
1170 {
1171 /* try to find a trustchain with one of the configured subject certs */
1172 enumerator = auth->create_enumerator(auth);
1173 while (enumerator->enumerate(enumerator, &rule, &cert))
1174 {
1175 if (rule == AUTH_RULE_SUBJECT_CERT)
1176 {
1177 private = get_private_by_cert(this, cert, type);
1178 if (private)
1179 {
1180 trustchain = build_trustchain(this, cert, auth);
1181 if (trustchain)
1182 {
1183 auth->merge(auth, trustchain, FALSE);
1184 prefer_cert(auth, cert->get_ref(cert));
1185 trustchain->destroy(trustchain);
1186 break;
1187 }
1188 private->destroy(private);
1189 private = NULL;
1190 }
1191 }
1192 }
1193 enumerator->destroy(enumerator);
1194 if (private)
1195 {
1196 return private;
1197 }
1198
1199 /* if none yielded a trustchain, enforce the first configured cert */
1200 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
1201 if (cert)
1202 {
1203 private = get_private_by_cert(this, cert, type);
1204 if (private)
1205 {
1206 trustchain = build_trustchain(this, cert, auth);
1207 if (trustchain)
1208 {
1209 auth->merge(auth, trustchain, FALSE);
1210 trustchain->destroy(trustchain);
1211 }
1212 return private;
1213 }
1214 }
1215
1216 /* try to build a trust chain for each certificate found */
1217 enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
1218 while (enumerator->enumerate(enumerator, &cert))
1219 {
1220 private = get_private_by_cert(this, cert, type);
1221 if (private)
1222 {
1223 trustchain = build_trustchain(this, cert, auth);
1224 if (trustchain)
1225 {
1226 auth->merge(auth, trustchain, FALSE);
1227 trustchain->destroy(trustchain);
1228 break;
1229 }
1230 private->destroy(private);
1231 private = NULL;
1232 }
1233 }
1234 enumerator->destroy(enumerator);
1235 }
1236
1237 /* if no valid trustchain was found, fall back to the first usable cert */
1238 if (!private)
1239 {
1240 enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
1241 while (enumerator->enumerate(enumerator, &cert))
1242 {
1243 private = get_private_by_cert(this, cert, type);
1244 if (private)
1245 {
1246 if (auth)
1247 {
1248 auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert));
1249 }
1250 break;
1251 }
1252 }
1253 enumerator->destroy(enumerator);
1254 }
1255 return private;
1256 }
1257
1258 METHOD(credential_manager_t, flush_cache, void,
1259 private_credential_manager_t *this, certificate_type_t type)
1260 {
1261 if (this->cache)
1262 {
1263 this->cache->flush(this->cache, type);
1264 }
1265 }
1266
1267 METHOD(credential_manager_t, add_set, void,
1268 private_credential_manager_t *this, credential_set_t *set)
1269 {
1270 this->lock->write_lock(this->lock);
1271 this->sets->insert_last(this->sets, set);
1272 this->lock->unlock(this->lock);
1273 }
1274
1275 METHOD(credential_manager_t, remove_set, void,
1276 private_credential_manager_t *this, credential_set_t *set)
1277 {
1278 this->lock->write_lock(this->lock);
1279 this->sets->remove(this->sets, set, NULL);
1280 this->lock->unlock(this->lock);
1281 }
1282
1283 METHOD(credential_manager_t, add_validator, void,
1284 private_credential_manager_t *this, cert_validator_t *vdtr)
1285 {
1286 this->lock->write_lock(this->lock);
1287 this->validators->insert_last(this->validators, vdtr);
1288 this->lock->unlock(this->lock);
1289 }
1290
1291 METHOD(credential_manager_t, remove_validator, void,
1292 private_credential_manager_t *this, cert_validator_t *vdtr)
1293 {
1294 this->lock->write_lock(this->lock);
1295 this->validators->remove(this->validators, vdtr, NULL);
1296 this->lock->unlock(this->lock);
1297 }
1298
1299 METHOD(credential_manager_t, destroy, void,
1300 private_credential_manager_t *this)
1301 {
1302 cache_queue(this);
1303 this->cache_queue->destroy(this->cache_queue);
1304 if (this->cache)
1305 {
1306 this->sets->remove(this->sets, this->cache, NULL);
1307 this->cache->destroy(this->cache);
1308 }
1309 this->sets->destroy(this->sets);
1310 this->local_sets->destroy(this->local_sets);
1311 this->exclusive_local_sets->destroy(this->exclusive_local_sets);
1312 this->validators->destroy(this->validators);
1313 this->lock->destroy(this->lock);
1314 this->queue_mutex->destroy(this->queue_mutex);
1315 free(this);
1316 }
1317
1318 /*
1319 * see header file
1320 */
1321 credential_manager_t *credential_manager_create()
1322 {
1323 private_credential_manager_t *this;
1324
1325 INIT(this,
1326 .public = {
1327 .create_cert_enumerator = _create_cert_enumerator,
1328 .create_shared_enumerator = _create_shared_enumerator,
1329 .create_cdp_enumerator = _create_cdp_enumerator,
1330 .get_cert = _get_cert,
1331 .get_shared = _get_shared,
1332 .get_private = _get_private,
1333 .create_trusted_enumerator = _create_trusted_enumerator,
1334 .create_public_enumerator = _create_public_enumerator,
1335 .flush_cache = _flush_cache,
1336 .cache_cert = _cache_cert,
1337 .issued_by = _issued_by,
1338 .add_set = _add_set,
1339 .remove_set = _remove_set,
1340 .add_local_set = _add_local_set,
1341 .remove_local_set = _remove_local_set,
1342 .add_validator = _add_validator,
1343 .remove_validator = _remove_validator,
1344 .set_hook = _set_hook,
1345 .call_hook = _call_hook,
1346 .destroy = _destroy,
1347 },
1348 .sets = linked_list_create(),
1349 .validators = linked_list_create(),
1350 .cache_queue = linked_list_create(),
1351 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1352 .queue_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
1353 );
1354
1355 this->local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy);
1356 this->exclusive_local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy);
1357 if (lib->settings->get_bool(lib->settings, "%s.cert_cache", TRUE, lib->ns))
1358 {
1359 this->cache = cert_cache_create();
1360 this->sets->insert_first(this->sets, this->cache);
1361 }
1362
1363 return &this->public;
1364 }