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