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