Added a certificate validation hook to the credential manager
[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 <selectors/traffic_selector.h>
24 #include <utils/linked_list.h>
25 #include <credentials/sets/cert_cache.h>
26 #include <credentials/sets/auth_cfg_wrapper.h>
27 #include <credentials/sets/ocsp_response_wrapper.h>
28 #include <credentials/certificates/x509.h>
29 #include <credentials/certificates/crl.h>
30 #include <credentials/certificates/ocsp_request.h>
31 #include <credentials/certificates/ocsp_response.h>
32
33 /**
34 * Maximum length of a certificate trust chain
35 */
36 #define MAX_TRUST_PATH_LEN 7
37
38 typedef struct private_credential_manager_t private_credential_manager_t;
39
40 /**
41 * private data of credential_manager
42 */
43 struct private_credential_manager_t {
44
45 /**
46 * public functions
47 */
48 credential_manager_t public;
49
50 /**
51 * list of credential sets
52 */
53 linked_list_t *sets;
54
55 /**
56 * thread local set of credentials, linked_list_t with credential_set_t's
57 */
58 thread_value_t *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 /** data to pass to create_private_enumerator */
87 typedef struct {
88 private_credential_manager_t *this;
89 key_type_t type;
90 identification_t* keyid;
91 } private_data_t;
92
93 /** data to pass to create_cert_enumerator */
94 typedef struct {
95 private_credential_manager_t *this;
96 certificate_type_t cert;
97 key_type_t key;
98 identification_t *id;
99 bool trusted;
100 } cert_data_t;
101
102 /** data to pass to create_cdp_enumerator */
103 typedef struct {
104 private_credential_manager_t *this;
105 certificate_type_t type;
106 identification_t *id;
107 } cdp_data_t;
108
109 /** data to pass to create_shared_enumerator */
110 typedef struct {
111 private_credential_manager_t *this;
112 shared_key_type_t type;
113 identification_t *me;
114 identification_t *other;
115 } shared_data_t;
116
117 /** enumerator over local and global sets */
118 typedef struct {
119 /** implements enumerator_t */
120 enumerator_t public;
121 /** enumerator over global sets */
122 enumerator_t *global;
123 /** enumerator over local sets */
124 enumerator_t *local;
125 } sets_enumerator_t;
126
127
128 METHOD(enumerator_t, sets_enumerate, bool,
129 sets_enumerator_t *this, credential_set_t **set)
130 {
131 if (this->global)
132 {
133 if (this->global->enumerate(this->global, set))
134 {
135 return TRUE;
136 }
137 /* end of global sets, look for local */
138 this->global->destroy(this->global);
139 this->global = NULL;
140 }
141 if (this->local)
142 {
143 return this->local->enumerate(this->local, set);
144 }
145 return FALSE;
146 }
147
148 METHOD(enumerator_t, sets_destroy, void,
149 sets_enumerator_t *this)
150 {
151 DESTROY_IF(this->global);
152 DESTROY_IF(this->local);
153 free(this);
154 }
155
156 /**
157 * create an enumerator over both, global and local sets
158 */
159 static enumerator_t *create_sets_enumerator(private_credential_manager_t *this)
160 {
161 sets_enumerator_t *enumerator;
162 linked_list_t *local;
163
164 INIT(enumerator,
165 .public.enumerate = (void*)_sets_enumerate,
166 .public.destroy = _sets_destroy,
167 .global = this->sets->create_enumerator(this->sets),
168 );
169 local = this->local_sets->get(this->local_sets);
170 if (local)
171 {
172 enumerator->local = local->create_enumerator(local);
173 }
174 return &enumerator->public;
175 }
176
177 /**
178 * cleanup function for cert data
179 */
180 static void destroy_cert_data(cert_data_t *data)
181 {
182 data->this->lock->unlock(data->this->lock);
183 free(data);
184 }
185
186 /**
187 * enumerator constructor for certificates
188 */
189 static enumerator_t *create_cert(credential_set_t *set, cert_data_t *data)
190 {
191 return set->create_cert_enumerator(set, data->cert, data->key,
192 data->id, data->trusted);
193 }
194
195 METHOD(credential_manager_t, create_cert_enumerator, enumerator_t*,
196 private_credential_manager_t *this, certificate_type_t certificate,
197 key_type_t key, identification_t *id, bool trusted)
198 {
199 cert_data_t *data = malloc_thing(cert_data_t);
200 data->this = this;
201 data->cert = certificate;
202 data->key = key;
203 data->id = id;
204 data->trusted = trusted;
205
206 this->lock->read_lock(this->lock);
207 return enumerator_create_nested(create_sets_enumerator(this),
208 (void*)create_cert, data,
209 (void*)destroy_cert_data);
210 }
211
212 METHOD(credential_manager_t, get_cert, certificate_t*,
213 private_credential_manager_t *this, certificate_type_t cert, key_type_t key,
214 identification_t *id, bool trusted)
215 {
216 certificate_t *current, *found = NULL;
217 enumerator_t *enumerator;
218
219 enumerator = create_cert_enumerator(this, cert, key, id, trusted);
220 if (enumerator->enumerate(enumerator, &current))
221 {
222 /* TODO: best match? order by keyid, subject, sualtname */
223 found = current->get_ref(current);
224 }
225 enumerator->destroy(enumerator);
226 return found;
227 }
228
229
230 /**
231 * cleanup function for cdp data
232 */
233 static void destroy_cdp_data(cdp_data_t *data)
234 {
235 data->this->lock->unlock(data->this->lock);
236 free(data);
237 }
238
239 /**
240 * enumerator constructor for CDPs
241 */
242 static enumerator_t *create_cdp(credential_set_t *set, cdp_data_t *data)
243 {
244 return set->create_cdp_enumerator(set, data->type, data->id);
245 }
246
247 METHOD(credential_manager_t, create_cdp_enumerator, enumerator_t*,
248 private_credential_manager_t *this, certificate_type_t type,
249 identification_t *id)
250 {
251 cdp_data_t *data;
252
253 INIT(data,
254 .this = this,
255 .type = type,
256 .id = id,
257 );
258 this->lock->read_lock(this->lock);
259 return enumerator_create_nested(create_sets_enumerator(this),
260 (void*)create_cdp, data,
261 (void*)destroy_cdp_data);
262 }
263
264 /**
265 * cleanup function for private data
266 */
267 static void destroy_private_data(private_data_t *data)
268 {
269 data->this->lock->unlock(data->this->lock);
270 free(data);
271 }
272
273 /**
274 * enumerator constructor for private keys
275 */
276 static enumerator_t *create_private(credential_set_t *set, private_data_t *data)
277 {
278 return set->create_private_enumerator(set, data->type, data->keyid);
279 }
280
281 /**
282 * Create an enumerator over private keys
283 */
284 static enumerator_t *create_private_enumerator(
285 private_credential_manager_t *this, key_type_t key, identification_t *keyid)
286 {
287 private_data_t *data;
288
289 INIT(data,
290 .this = this,
291 .type = key,
292 .keyid = keyid,
293 );
294 this->lock->read_lock(this->lock);
295 return enumerator_create_nested(create_sets_enumerator(this),
296 (void*)create_private, data,
297 (void*)destroy_private_data);
298 }
299
300 /**
301 * Look up a private key by its key identifier
302 */
303 static private_key_t* get_private_by_keyid(private_credential_manager_t *this,
304 key_type_t key, identification_t *keyid)
305 {
306 private_key_t *found = NULL;
307 enumerator_t *enumerator;
308
309 enumerator = create_private_enumerator(this, key, keyid);
310 if (enumerator->enumerate(enumerator, &found))
311 {
312 found->get_ref(found);
313 }
314 enumerator->destroy(enumerator);
315 return found;
316 }
317
318 /**
319 * cleanup function for shared data
320 */
321 static void destroy_shared_data(shared_data_t *data)
322 {
323 data->this->lock->unlock(data->this->lock);
324 free(data);
325 }
326
327 /**
328 * enumerator constructor for shared keys
329 */
330 static enumerator_t *create_shared(credential_set_t *set, shared_data_t *data)
331 {
332 return set->create_shared_enumerator(set, data->type, data->me, data->other);
333 }
334
335 METHOD(credential_manager_t, create_shared_enumerator, enumerator_t*,
336 private_credential_manager_t *this, shared_key_type_t type,
337 identification_t *me, identification_t *other)
338 {
339 shared_data_t *data;
340
341 INIT(data,
342 .this = this,
343 .type = type,
344 .me = me,
345 .other = other,
346 );
347 this->lock->read_lock(this->lock);
348 return enumerator_create_nested(create_sets_enumerator(this),
349 (void*)create_shared, data,
350 (void*)destroy_shared_data);
351 }
352
353 METHOD(credential_manager_t, get_shared, shared_key_t*,
354 private_credential_manager_t *this, shared_key_type_t type,
355 identification_t *me, identification_t *other)
356 {
357 shared_key_t *current, *found = NULL;
358 id_match_t *best_me = ID_MATCH_NONE, *best_other = ID_MATCH_NONE;
359 id_match_t *match_me, *match_other;
360 enumerator_t *enumerator;
361
362 enumerator = create_shared_enumerator(this, type, me, other);
363 while (enumerator->enumerate(enumerator, &current, &match_me, &match_other))
364 {
365 if (match_other > best_other ||
366 (match_other == best_other && match_me > best_me))
367 {
368 DESTROY_IF(found);
369 found = current->get_ref(current);
370 best_me = match_me;
371 best_other = match_other;
372 }
373 }
374 enumerator->destroy(enumerator);
375 return found;
376 }
377
378 /**
379 * add a credential set to the thread local list
380 */
381 static void add_local_set(private_credential_manager_t *this,
382 credential_set_t *set)
383 {
384 linked_list_t *sets;
385
386 sets = this->local_sets->get(this->local_sets);
387 if (!sets)
388 { /* first invocation */
389 sets = linked_list_create();
390 this->local_sets->set(this->local_sets, sets);
391 }
392 sets->insert_last(sets, set);
393 }
394
395 /**
396 * remove a credential set from the thread local list
397 */
398 static void remove_local_set(private_credential_manager_t *this,
399 credential_set_t *set)
400 {
401 linked_list_t *sets;
402
403 sets = this->local_sets->get(this->local_sets);
404 sets->remove(sets, set, NULL);
405 }
406
407 METHOD(credential_manager_t, cache_cert, void,
408 private_credential_manager_t *this, certificate_t *cert)
409 {
410 credential_set_t *set;
411 enumerator_t *enumerator;
412
413 if (this->lock->try_write_lock(this->lock))
414 {
415 enumerator = this->sets->create_enumerator(this->sets);
416 while (enumerator->enumerate(enumerator, &set))
417 {
418 set->cache_cert(set, cert);
419 }
420 enumerator->destroy(enumerator);
421 this->lock->unlock(this->lock);
422 }
423 else
424 { /* we can't cache now as other threads are active, queue for later */
425 this->queue_mutex->lock(this->queue_mutex);
426 this->cache_queue->insert_last(this->cache_queue, cert->get_ref(cert));
427 this->queue_mutex->unlock(this->queue_mutex);
428 }
429 }
430
431 /**
432 * Try to cache certificates queued for caching
433 */
434 static void cache_queue(private_credential_manager_t *this)
435 {
436 credential_set_t *set;
437 certificate_t *cert;
438 enumerator_t *enumerator;
439
440 this->queue_mutex->lock(this->queue_mutex);
441 if (this->cache_queue->get_count(this->cache_queue) > 0 &&
442 this->lock->try_write_lock(this->lock))
443 {
444 while (this->cache_queue->remove_last(this->cache_queue,
445 (void**)&cert) == SUCCESS)
446 {
447 enumerator = this->sets->create_enumerator(this->sets);
448 while (enumerator->enumerate(enumerator, &set))
449 {
450 set->cache_cert(set, cert);
451 }
452 enumerator->destroy(enumerator);
453 cert->destroy(cert);
454 }
455 this->lock->unlock(this->lock);
456 }
457 this->queue_mutex->unlock(this->queue_mutex);
458 }
459
460 /**
461 * forward declaration
462 */
463 static enumerator_t *create_trusted_enumerator(private_credential_manager_t *this,
464 key_type_t type, identification_t *id, bool online);
465
466 /**
467 * Do an OCSP request
468 */
469 static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url,
470 certificate_t *subject, certificate_t *issuer)
471 {
472 certificate_t *request, *response;
473 chunk_t send, receive;
474
475 /* TODO: requestor name, signature */
476 request = lib->creds->create(lib->creds,
477 CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
478 BUILD_CA_CERT, issuer,
479 BUILD_CERT, subject, BUILD_END);
480 if (!request)
481 {
482 DBG1(DBG_CFG, "generating ocsp request failed");
483 return NULL;
484 }
485
486 send = request->get_encoding(request);
487 request->destroy(request);
488
489 DBG1(DBG_CFG, " requesting ocsp status from '%s' ...", url);
490 if (lib->fetcher->fetch(lib->fetcher, url, &receive,
491 FETCH_REQUEST_DATA, send,
492 FETCH_REQUEST_TYPE, "application/ocsp-request",
493 FETCH_END) != SUCCESS)
494 {
495 DBG1(DBG_CFG, "ocsp request to %s failed", url);
496 chunk_free(&send);
497 return NULL;
498 }
499 chunk_free(&send);
500
501 response = lib->creds->create(lib->creds,
502 CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
503 BUILD_BLOB_ASN1_DER, receive, BUILD_END);
504 chunk_free(&receive);
505 if (!response)
506 {
507 DBG1(DBG_CFG, "parsing ocsp response failed");
508 return NULL;
509 }
510 return response;
511 }
512
513 /**
514 * check the signature of an OCSP response
515 */
516 static bool verify_ocsp(private_credential_manager_t *this,
517 ocsp_response_t *response)
518 {
519 certificate_t *issuer, *subject;
520 identification_t *responder;
521 ocsp_response_wrapper_t *wrapper;
522 enumerator_t *enumerator;
523 bool verified = FALSE;
524
525 wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
526 add_local_set(this, &wrapper->set);
527
528 subject = &response->certificate;
529 responder = subject->get_issuer(subject);
530 enumerator = create_trusted_enumerator(this, KEY_ANY, responder, FALSE);
531 while (enumerator->enumerate(enumerator, &issuer, NULL))
532 {
533 if (this->cache->issued_by(this->cache, subject, issuer))
534 {
535 DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
536 issuer->get_subject(issuer));
537 verified = TRUE;
538 break;
539 }
540 }
541 enumerator->destroy(enumerator);
542
543 remove_local_set(this, &wrapper->set);
544 wrapper->destroy(wrapper);
545 return verified;
546 }
547
548 /**
549 * Get the better of two OCSP responses, and check for usable OCSP info
550 */
551 static certificate_t *get_better_ocsp(private_credential_manager_t *this,
552 certificate_t *cand, certificate_t *best,
553 x509_t *subject, x509_t *issuer,
554 cert_validation_t *valid, bool cache)
555 {
556 ocsp_response_t *response;
557 time_t revocation, this_update, next_update, valid_until;
558 crl_reason_t reason;
559 bool revoked = FALSE;
560
561 response = (ocsp_response_t*)cand;
562
563 /* check ocsp signature */
564 if (!verify_ocsp(this, response))
565 {
566 DBG1(DBG_CFG, "ocsp response verification failed");
567 cand->destroy(cand);
568 return best;
569 }
570 /* check if response contains our certificate */
571 switch (response->get_status(response, subject, issuer, &revocation, &reason,
572 &this_update, &next_update))
573 {
574 case VALIDATION_REVOKED:
575 /* subject has been revoked by a valid OCSP response */
576 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
577 &revocation, TRUE, crl_reason_names, reason);
578 revoked = TRUE;
579 break;
580 case VALIDATION_GOOD:
581 /* results in either good or stale */
582 break;
583 default:
584 case VALIDATION_FAILED:
585 /* candidate unusable, does not contain our cert */
586 DBG1(DBG_CFG, " ocsp response contains no status on our certificate");
587 cand->destroy(cand);
588 return best;
589 }
590
591 /* select the better of the two responses */
592 if (best == NULL || certificate_is_newer(cand, best))
593 {
594 DESTROY_IF(best);
595 best = cand;
596 if (best->get_validity(best, NULL, NULL, &valid_until))
597 {
598 DBG1(DBG_CFG, " ocsp response is valid: until %T",
599 &valid_until, FALSE);
600 *valid = VALIDATION_GOOD;
601 if (cache)
602 { /* cache non-stale only, stale certs get refetched */
603 cache_cert(this, best);
604 }
605 }
606 else
607 {
608 DBG1(DBG_CFG, " ocsp response is stale: since %T",
609 &valid_until, FALSE);
610 *valid = VALIDATION_STALE;
611 }
612 }
613 else
614 {
615 *valid = VALIDATION_STALE;
616 cand->destroy(cand);
617 }
618 if (revoked)
619 { /* revoked always counts, even if stale */
620 *valid = VALIDATION_REVOKED;
621 }
622 return best;
623 }
624
625 /**
626 * validate a x509 certificate using OCSP
627 */
628 static cert_validation_t check_ocsp(private_credential_manager_t *this,
629 x509_t *subject, x509_t *issuer,
630 auth_cfg_t *auth)
631 {
632 enumerator_t *enumerator;
633 cert_validation_t valid = VALIDATION_SKIPPED;
634 certificate_t *best = NULL, *current;
635 identification_t *keyid = NULL;
636 public_key_t *public;
637 chunk_t chunk;
638 char *uri = NULL;
639
640 /** lookup cache for valid OCSP responses */
641 enumerator = create_cert_enumerator(this, CERT_X509_OCSP_RESPONSE,
642 KEY_ANY, NULL, FALSE);
643 while (enumerator->enumerate(enumerator, &current))
644 {
645 current->get_ref(current);
646 best = get_better_ocsp(this, current, best, subject, issuer,
647 &valid, FALSE);
648 if (best && valid != VALIDATION_STALE)
649 {
650 DBG1(DBG_CFG, " using cached ocsp response");
651 break;
652 }
653 }
654 enumerator->destroy(enumerator);
655
656 /* derive the authorityKeyIdentifier from the issuer's public key */
657 current = &issuer->interface;
658 public = current->get_public_key(current);
659 if (public && public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
660 {
661 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
662 }
663 /** fetch from configured OCSP responder URLs */
664 if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
665 {
666 enumerator = create_cdp_enumerator(this, CERT_X509_OCSP_RESPONSE, keyid);
667 while (enumerator->enumerate(enumerator, &uri))
668 {
669 current = fetch_ocsp(this, uri, &subject->interface,
670 &issuer->interface);
671 if (current)
672 {
673 best = get_better_ocsp(this, current, best, subject, issuer,
674 &valid, TRUE);
675 if (best && valid != VALIDATION_STALE)
676 {
677 break;
678 }
679 }
680 }
681 enumerator->destroy(enumerator);
682 }
683 DESTROY_IF(public);
684 DESTROY_IF(keyid);
685
686 /* fallback to URL fetching from subject certificate's URIs */
687 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
688 {
689 enumerator = subject->create_ocsp_uri_enumerator(subject);
690 while (enumerator->enumerate(enumerator, &uri))
691 {
692 current = fetch_ocsp(this, uri, &subject->interface,
693 &issuer->interface);
694 if (current)
695 {
696 best = get_better_ocsp(this, current, best, subject, issuer,
697 &valid, TRUE);
698 if (best && valid != VALIDATION_STALE)
699 {
700 break;
701 }
702 }
703 }
704 enumerator->destroy(enumerator);
705 }
706 /* an uri was found, but no result. switch validation state to failed */
707 if (valid == VALIDATION_SKIPPED && uri)
708 {
709 valid = VALIDATION_FAILED;
710 }
711 if (auth)
712 {
713 auth->add(auth, AUTH_RULE_OCSP_VALIDATION, valid);
714 if (valid == VALIDATION_GOOD)
715 { /* successful OCSP check fulfills also CRL constraint */
716 auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
717 }
718 }
719 DESTROY_IF(best);
720 return valid;
721 }
722
723 /**
724 * fetch a CRL from an URL
725 */
726 static certificate_t* fetch_crl(private_credential_manager_t *this, char *url)
727 {
728 certificate_t *crl;
729 chunk_t chunk;
730
731 DBG1(DBG_CFG, " fetching crl from '%s' ...", url);
732 if (lib->fetcher->fetch(lib->fetcher, url, &chunk, FETCH_END) != SUCCESS)
733 {
734 DBG1(DBG_CFG, "crl fetching failed");
735 return NULL;
736 }
737 crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
738 BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
739 chunk_free(&chunk);
740 if (!crl)
741 {
742 DBG1(DBG_CFG, "crl fetched successfully but parsing failed");
743 return NULL;
744 }
745 return crl;
746 }
747
748 /**
749 * check the signature of an CRL
750 */
751 static bool verify_crl(private_credential_manager_t *this, certificate_t *crl)
752 {
753 certificate_t *issuer;
754 enumerator_t *enumerator;
755 bool verified = FALSE;
756
757 enumerator = create_trusted_enumerator(this, KEY_ANY, crl->get_issuer(crl),
758 FALSE);
759 while (enumerator->enumerate(enumerator, &issuer, NULL))
760 {
761 if (this->cache->issued_by(this->cache, crl, issuer))
762 {
763 DBG1(DBG_CFG, " crl correctly signed by \"%Y\"",
764 issuer->get_subject(issuer));
765 verified = TRUE;
766 break;
767 }
768 }
769 enumerator->destroy(enumerator);
770
771 return verified;
772 }
773
774 /**
775 * Get the better of two CRLs, and check for usable CRL info
776 */
777 static certificate_t *get_better_crl(private_credential_manager_t *this,
778 certificate_t *cand, certificate_t *best,
779 x509_t *subject, x509_t *issuer,
780 cert_validation_t *valid, bool cache)
781 {
782 enumerator_t *enumerator;
783 time_t revocation, valid_until;
784 crl_reason_t reason;
785 chunk_t serial;
786 crl_t *crl;
787
788 /* check CRL signature */
789 if (!verify_crl(this, cand))
790 {
791 DBG1(DBG_CFG, "crl response verification failed");
792 cand->destroy(cand);
793 return best;
794 }
795
796 crl = (crl_t*)cand;
797 enumerator = crl->create_enumerator(crl);
798 while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
799 {
800 if (chunk_equals(serial, subject->get_serial(subject)))
801 {
802 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
803 &revocation, TRUE, crl_reason_names, reason);
804 *valid = VALIDATION_REVOKED;
805 enumerator->destroy(enumerator);
806 DESTROY_IF(best);
807 return cand;
808 }
809 }
810 enumerator->destroy(enumerator);
811
812 /* select the better of the two CRLs */
813 if (best == NULL || crl_is_newer(crl, (crl_t*)best))
814 {
815 DESTROY_IF(best);
816 best = cand;
817 if (best->get_validity(best, NULL, NULL, &valid_until))
818 {
819 DBG1(DBG_CFG, " crl is valid: until %T", &valid_until, FALSE);
820 *valid = VALIDATION_GOOD;
821 if (cache)
822 { /* we cache non-stale crls only, as a stale crls are refetched */
823 cache_cert(this, best);
824 }
825 }
826 else
827 {
828 DBG1(DBG_CFG, " crl is stale: since %T", &valid_until, FALSE);
829 *valid = VALIDATION_STALE;
830 }
831 }
832 else
833 {
834 *valid = VALIDATION_STALE;
835 cand->destroy(cand);
836 }
837 return best;
838 }
839
840 /**
841 * validate a x509 certificate using CRL
842 */
843 static cert_validation_t check_crl(private_credential_manager_t *this,
844 x509_t *subject, x509_t *issuer,
845 auth_cfg_t *auth)
846 {
847 cert_validation_t valid = VALIDATION_SKIPPED;
848 identification_t *keyid = NULL;
849 certificate_t *best = NULL;
850 certificate_t *current;
851 public_key_t *public;
852 enumerator_t *enumerator;
853 chunk_t chunk;
854 char *uri = NULL;
855
856 /* derive the authorityKeyIdentifier from the issuer's public key */
857 current = &issuer->interface;
858 public = current->get_public_key(current);
859 if (public && public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
860 {
861 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
862
863 /* find a cached crl by authorityKeyIdentifier */
864 enumerator = create_cert_enumerator(this, CERT_X509_CRL, KEY_ANY,
865 keyid, FALSE);
866 while (enumerator->enumerate(enumerator, &current))
867 {
868 current->get_ref(current);
869 best = get_better_crl(this, current, best, subject, issuer,
870 &valid, FALSE);
871 if (best && valid != VALIDATION_STALE)
872 {
873 DBG1(DBG_CFG, " using cached crl");
874 break;
875 }
876 }
877 enumerator->destroy(enumerator);
878
879 /* fallback to fetching crls from credential sets cdps */
880 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
881 {
882 enumerator = create_cdp_enumerator(this, CERT_X509_CRL, keyid);
883
884 while (enumerator->enumerate(enumerator, &uri))
885 {
886 current = fetch_crl(this, uri);
887 if (current)
888 {
889 best = get_better_crl(this, current, best, subject, issuer,
890 &valid, TRUE);
891 if (best && valid != VALIDATION_STALE)
892 {
893 break;
894 }
895 }
896 }
897 enumerator->destroy(enumerator);
898 }
899 keyid->destroy(keyid);
900 }
901 DESTROY_IF(public);
902
903 /* fallback to fetching crls from cdps from subject's certificate */
904 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
905 {
906 enumerator = subject->create_crl_uri_enumerator(subject);
907
908 while (enumerator->enumerate(enumerator, &uri))
909 {
910 current = fetch_crl(this, uri);
911 if (current)
912 {
913 best = get_better_crl(this, current, best, subject, issuer,
914 &valid, TRUE);
915 if (best && valid != VALIDATION_STALE)
916 {
917 break;
918 }
919 }
920 }
921 enumerator->destroy(enumerator);
922 }
923
924 /* an uri was found, but no result. switch validation state to failed */
925 if (valid == VALIDATION_SKIPPED && uri)
926 {
927 valid = VALIDATION_FAILED;
928 }
929 if (auth)
930 {
931 if (valid == VALIDATION_SKIPPED)
932 { /* if we skipped CRL validation, we use the result of OCSP for
933 * constraint checking */
934 auth->add(auth, AUTH_RULE_CRL_VALIDATION,
935 auth->get(auth, AUTH_RULE_OCSP_VALIDATION));
936 }
937 else
938 {
939 auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid);
940 }
941 }
942 DESTROY_IF(best);
943 return valid;
944 }
945
946 /**
947 * check a certificate for optional IP address block constraints
948 */
949 static bool check_ip_addr_block_constraints(x509_t *subject, x509_t *issuer)
950 {
951 bool subject_constraint = subject->get_flags(subject) & X509_IP_ADDR_BLOCKS;
952 bool issuer_constraint = issuer->get_flags(issuer) & X509_IP_ADDR_BLOCKS;
953 bool contained = TRUE;
954
955 enumerator_t *subject_enumerator, *issuer_enumerator;
956 traffic_selector_t *subject_ts, *issuer_ts;
957
958 if (!subject_constraint && !issuer_constraint)
959 {
960 return TRUE;
961 }
962 if (!subject_constraint)
963 {
964 DBG1(DBG_CFG, "subject certficate lacks ipAddrBlocks extension");
965 return FALSE;
966 }
967 if (!issuer_constraint)
968 {
969 DBG1(DBG_CFG, "issuer certficate lacks ipAddrBlocks extension");
970 return FALSE;
971 }
972 subject_enumerator = subject->create_ipAddrBlock_enumerator(subject);
973 while (subject_enumerator->enumerate(subject_enumerator, &subject_ts))
974 {
975 contained = FALSE;
976
977 issuer_enumerator = issuer->create_ipAddrBlock_enumerator(issuer);
978 while (issuer_enumerator->enumerate(issuer_enumerator, &issuer_ts))
979 {
980 if (subject_ts->is_contained_in(subject_ts, issuer_ts))
981 {
982 DBG2(DBG_CFG, " subject address block %R is contained in "
983 "issuer address block %R", subject_ts, issuer_ts);
984 contained = TRUE;
985 break;
986 }
987 }
988 issuer_enumerator->destroy(issuer_enumerator);
989 if (!contained)
990 {
991 DBG1(DBG_CFG, "subject address block %R is not contained in any "
992 "issuer address block", subject_ts);
993 break;
994 }
995 }
996 subject_enumerator->destroy(subject_enumerator);
997 return contained;
998 }
999
1000 /**
1001 * check a certificate for its lifetime
1002 */
1003 static bool check_certificate(private_credential_manager_t *this,
1004 certificate_t *subject, certificate_t *issuer,
1005 bool online, int pathlen, auth_cfg_t *auth)
1006 {
1007 time_t not_before, not_after;
1008 cert_validator_t *validator;
1009 enumerator_t *enumerator;
1010
1011 if (!subject->get_validity(subject, NULL, &not_before, &not_after))
1012 {
1013 DBG1(DBG_CFG, "subject certificate invalid (valid from %T to %T)",
1014 &not_before, FALSE, &not_after, FALSE);
1015 return FALSE;
1016 }
1017 if (!issuer->get_validity(issuer, NULL, &not_before, &not_after))
1018 {
1019 DBG1(DBG_CFG, "issuer certificate invalid (valid from %T to %T)",
1020 &not_before, FALSE, &not_after, FALSE);
1021 return FALSE;
1022 }
1023 if (issuer->get_type(issuer) == CERT_X509 &&
1024 subject->get_type(subject) == CERT_X509)
1025 {
1026 int pathlen_constraint;
1027 x509_t *x509;
1028
1029 if (!check_ip_addr_block_constraints((x509_t*)subject, (x509_t*)issuer))
1030 {
1031 return FALSE;
1032 }
1033
1034 /* check path length constraint */
1035 x509 = (x509_t*)issuer;
1036 pathlen_constraint = x509->get_pathLenConstraint(x509);
1037 if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT &&
1038 pathlen > pathlen_constraint)
1039 {
1040 DBG1(DBG_CFG, "path length of %d violates constraint of %d",
1041 pathlen, pathlen_constraint);
1042 return FALSE;
1043 }
1044
1045 if (online)
1046 {
1047 DBG1(DBG_CFG, "checking certificate status of \"%Y\"",
1048 subject->get_subject(subject));
1049 switch (check_ocsp(this, (x509_t*)subject, (x509_t*)issuer, auth))
1050 {
1051 case VALIDATION_GOOD:
1052 DBG1(DBG_CFG, "certificate status is good");
1053 return TRUE;
1054 case VALIDATION_REVOKED:
1055 /* has already been logged */
1056 return FALSE;
1057 case VALIDATION_SKIPPED:
1058 DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
1059 break;
1060 case VALIDATION_STALE:
1061 DBG1(DBG_CFG, "ocsp information stale, fallback to crl");
1062 break;
1063 case VALIDATION_FAILED:
1064 DBG1(DBG_CFG, "ocsp check failed, fallback to crl");
1065 break;
1066 }
1067 switch (check_crl(this, (x509_t*)subject, (x509_t*)issuer, auth))
1068 {
1069 case VALIDATION_GOOD:
1070 DBG1(DBG_CFG, "certificate status is good");
1071 return TRUE;
1072 case VALIDATION_REVOKED:
1073 /* has already been logged */
1074 return FALSE;
1075 case VALIDATION_FAILED:
1076 case VALIDATION_SKIPPED:
1077 DBG1(DBG_CFG, "certificate status is not available");
1078 break;
1079 case VALIDATION_STALE:
1080 DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
1081 break;
1082 }
1083 }
1084 }
1085
1086 enumerator = this->validators->create_enumerator(this->validators);
1087 while (enumerator->enumerate(enumerator, &validator))
1088 {
1089 if (!validator->validate(validator, subject, issuer,
1090 online, pathlen, auth))
1091 {
1092 enumerator->destroy(enumerator);
1093 return FALSE;
1094 }
1095 }
1096 enumerator->destroy(enumerator);
1097 return TRUE;
1098 }
1099
1100 /**
1101 * Get a trusted certificate from a credential set
1102 */
1103 static certificate_t *get_pretrusted_cert(private_credential_manager_t *this,
1104 key_type_t type, identification_t *id)
1105 {
1106 certificate_t *subject;
1107 public_key_t *public;
1108
1109 subject = get_cert(this, CERT_ANY, type, id, TRUE);
1110 if (!subject)
1111 {
1112 return NULL;
1113 }
1114 public = subject->get_public_key(subject);
1115 if (!public)
1116 {
1117 subject->destroy(subject);
1118 return NULL;
1119 }
1120 public->destroy(public);
1121 return subject;
1122 }
1123
1124 /**
1125 * Get the issuing certificate of a subject certificate
1126 */
1127 static certificate_t *get_issuer_cert(private_credential_manager_t *this,
1128 certificate_t *subject, bool trusted)
1129 {
1130 enumerator_t *enumerator;
1131 certificate_t *issuer = NULL, *candidate;
1132
1133 enumerator = create_cert_enumerator(this, subject->get_type(subject), KEY_ANY,
1134 subject->get_issuer(subject), trusted);
1135 while (enumerator->enumerate(enumerator, &candidate))
1136 {
1137 if (this->cache->issued_by(this->cache, subject, candidate))
1138 {
1139 issuer = candidate->get_ref(candidate);
1140 break;
1141 }
1142 }
1143 enumerator->destroy(enumerator);
1144 return issuer;
1145 }
1146
1147 /**
1148 * try to verify the trust chain of subject, return TRUE if trusted
1149 */
1150 static bool verify_trust_chain(private_credential_manager_t *this,
1151 certificate_t *subject, auth_cfg_t *result,
1152 bool trusted, bool online)
1153 {
1154 certificate_t *current, *issuer;
1155 auth_cfg_t *auth;
1156 int pathlen;
1157
1158 auth = auth_cfg_create();
1159 current = subject->get_ref(subject);
1160
1161 for (pathlen = 0; pathlen <= MAX_TRUST_PATH_LEN; pathlen++)
1162 {
1163 issuer = get_issuer_cert(this, current, TRUE);
1164 if (issuer)
1165 {
1166 /* accept only self-signed CAs as trust anchor */
1167 if (this->cache->issued_by(this->cache, issuer, issuer))
1168 {
1169 auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer));
1170 DBG1(DBG_CFG, " using trusted ca certificate \"%Y\"",
1171 issuer->get_subject(issuer));
1172 trusted = TRUE;
1173 }
1174 else
1175 {
1176 auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
1177 DBG1(DBG_CFG, " using trusted intermediate ca certificate "
1178 "\"%Y\"", issuer->get_subject(issuer));
1179 }
1180 }
1181 else
1182 {
1183 issuer = get_issuer_cert(this, current, FALSE);
1184 if (issuer)
1185 {
1186 if (current->equals(current, issuer))
1187 {
1188 DBG1(DBG_CFG, " self-signed certificate \"%Y\" is not trusted",
1189 current->get_subject(current));
1190 issuer->destroy(issuer);
1191 break;
1192 }
1193 auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
1194 DBG1(DBG_CFG, " using untrusted intermediate certificate "
1195 "\"%Y\"", issuer->get_subject(issuer));
1196 }
1197 else
1198 {
1199 DBG1(DBG_CFG, "no issuer certificate found for \"%Y\"",
1200 current->get_subject(current));
1201 break;
1202 }
1203 }
1204 if (!check_certificate(this, current, issuer, online, pathlen,
1205 current == subject ? auth : NULL))
1206 {
1207 trusted = FALSE;
1208 issuer->destroy(issuer);
1209 break;
1210 }
1211 current->destroy(current);
1212 current = issuer;
1213 if (trusted)
1214 {
1215 DBG1(DBG_CFG, " reached self-signed root ca with a path length of %d",
1216 pathlen);
1217 break;
1218 }
1219 }
1220 current->destroy(current);
1221 if (pathlen > MAX_TRUST_PATH_LEN)
1222 {
1223 DBG1(DBG_CFG, "maximum path length of %d exceeded", MAX_TRUST_PATH_LEN);
1224 }
1225 if (trusted)
1226 {
1227 result->merge(result, auth, FALSE);
1228 }
1229 auth->destroy(auth);
1230 return trusted;
1231 }
1232
1233 /**
1234 * enumerator for trusted certificates
1235 */
1236 typedef struct {
1237 /** implements enumerator_t interface */
1238 enumerator_t public;
1239 /** enumerator over candidate peer certificates */
1240 enumerator_t *candidates;
1241 /** reference to the credential_manager */
1242 private_credential_manager_t *this;
1243 /** type of the requested key */
1244 key_type_t type;
1245 /** identity the requested key belongs to */
1246 identification_t *id;
1247 /** TRUE to do CRL/OCSP checking */
1248 bool online;
1249 /** pretrusted certificate we have served at first invocation */
1250 certificate_t *pretrusted;
1251 /** currently enumerating auth config */
1252 auth_cfg_t *auth;
1253 } trusted_enumerator_t;
1254
1255 METHOD(enumerator_t, trusted_enumerate, bool,
1256 trusted_enumerator_t *this, certificate_t **cert, auth_cfg_t **auth)
1257 {
1258 certificate_t *current;
1259
1260 DESTROY_IF(this->auth);
1261 this->auth = auth_cfg_create();
1262
1263 if (!this->candidates)
1264 {
1265 /* first invocation, build enumerator for next one */
1266 this->candidates = create_cert_enumerator(this->this, CERT_ANY,
1267 this->type, this->id, FALSE);
1268 /* check if we have a trusted certificate for that peer */
1269 this->pretrusted = get_pretrusted_cert(this->this, this->type, this->id);
1270 if (this->pretrusted)
1271 {
1272 /* if we find a trusted self signed certificate, we just accept it.
1273 * However, in order to fulfill authorization rules, we try to build
1274 * the trust chain if it is not self signed */
1275 if (this->this->cache->issued_by(this->this->cache,
1276 this->pretrusted, this->pretrusted) ||
1277 verify_trust_chain(this->this, this->pretrusted, this->auth,
1278 TRUE, this->online))
1279 {
1280 this->auth->add(this->auth, AUTH_RULE_SUBJECT_CERT,
1281 this->pretrusted->get_ref(this->pretrusted));
1282 DBG1(DBG_CFG, " using trusted certificate \"%Y\"",
1283 this->pretrusted->get_subject(this->pretrusted));
1284 *cert = this->pretrusted;
1285 if (auth)
1286 {
1287 *auth = this->auth;
1288 }
1289 return TRUE;
1290 }
1291 }
1292 }
1293 /* try to verify the trust chain for each certificate found */
1294 while (this->candidates->enumerate(this->candidates, &current))
1295 {
1296 if (this->pretrusted &&
1297 this->pretrusted->equals(this->pretrusted, current))
1298 { /* skip pretrusted certificate we already served */
1299 continue;
1300 }
1301
1302 DBG1(DBG_CFG, " using certificate \"%Y\"",
1303 current->get_subject(current));
1304 if (verify_trust_chain(this->this, current, this->auth, FALSE,
1305 this->online))
1306 {
1307 *cert = current;
1308 if (auth)
1309 {
1310 *auth = this->auth;
1311 }
1312 return TRUE;
1313 }
1314 }
1315 return FALSE;
1316 }
1317
1318 METHOD(enumerator_t, trusted_destroy, void,
1319 trusted_enumerator_t *this)
1320 {
1321 DESTROY_IF(this->pretrusted);
1322 DESTROY_IF(this->auth);
1323 DESTROY_IF(this->candidates);
1324 free(this);
1325 }
1326
1327 /**
1328 * create an enumerator over trusted certificates and their trustchain
1329 */
1330 static enumerator_t *create_trusted_enumerator(private_credential_manager_t *this,
1331 key_type_t type, identification_t *id, bool online)
1332 {
1333 trusted_enumerator_t *enumerator;
1334
1335 INIT(enumerator,
1336 .public = {
1337 .enumerate = (void*)_trusted_enumerate,
1338 .destroy = _trusted_destroy,
1339 },
1340 .this = this,
1341 .type = type,
1342 .id = id,
1343 .online = online,
1344 );
1345 return &enumerator->public;
1346 }
1347
1348 /**
1349 * enumerator for public keys
1350 */
1351 typedef struct {
1352 /** implements enumerator_t interface */
1353 enumerator_t public;
1354 /** enumerator over candidate peer certificates */
1355 enumerator_t *inner;
1356 /** reference to the credential_manager */
1357 private_credential_manager_t *this;
1358 /** currently enumerating key */
1359 public_key_t *current;
1360 /** credset wrapper around auth config */
1361 auth_cfg_wrapper_t *wrapper;
1362 } public_enumerator_t;
1363
1364 METHOD(enumerator_t, public_enumerate, bool,
1365 public_enumerator_t *this, public_key_t **key, auth_cfg_t **auth)
1366 {
1367 certificate_t *cert;
1368
1369 while (this->inner->enumerate(this->inner, &cert, auth))
1370 {
1371 DESTROY_IF(this->current);
1372 this->current = cert->get_public_key(cert);
1373 if (this->current)
1374 {
1375 *key = this->current;
1376 return TRUE;
1377 }
1378 }
1379 return FALSE;
1380 }
1381
1382 METHOD(enumerator_t, public_destroy, void,
1383 public_enumerator_t *this)
1384 {
1385 DESTROY_IF(this->current);
1386 this->inner->destroy(this->inner);
1387 if (this->wrapper)
1388 {
1389 remove_local_set(this->this, &this->wrapper->set);
1390 this->wrapper->destroy(this->wrapper);
1391 }
1392 this->this->lock->unlock(this->this->lock);
1393
1394 /* check for delayed certificate cache queue */
1395 cache_queue(this->this);
1396 free(this);
1397 }
1398
1399 METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
1400 private_credential_manager_t *this, key_type_t type, identification_t *id,
1401 auth_cfg_t *auth)
1402 {
1403 public_enumerator_t *enumerator;
1404
1405 INIT(enumerator,
1406 .public = {
1407 .enumerate = (void*)_public_enumerate,
1408 .destroy = _public_destroy,
1409 },
1410 .inner = create_trusted_enumerator(this, type, id, TRUE),
1411 .this = this,
1412 );
1413 if (auth)
1414 {
1415 enumerator->wrapper = auth_cfg_wrapper_create(auth);
1416 add_local_set(this, &enumerator->wrapper->set);
1417 }
1418 this->lock->read_lock(this->lock);
1419 return &enumerator->public;
1420 }
1421
1422 /**
1423 * Check if a certificate's keyid is contained in the auth helper
1424 */
1425 static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert)
1426 {
1427 enumerator_t *enumerator;
1428 identification_t *value;
1429 auth_rule_t type;
1430 bool found = FALSE;
1431
1432 enumerator = auth->create_enumerator(auth);
1433 while (enumerator->enumerate(enumerator, &type, &value))
1434 {
1435 if (type == AUTH_RULE_CA_CERT &&
1436 cert->equals(cert, (certificate_t*)value))
1437 {
1438 found = TRUE;
1439 break;
1440 }
1441 }
1442 enumerator->destroy(enumerator);
1443 return found;
1444 }
1445
1446 /**
1447 * build a trustchain from subject up to a trust anchor in trusted
1448 */
1449 static auth_cfg_t *build_trustchain(private_credential_manager_t *this,
1450 certificate_t *subject, auth_cfg_t *auth)
1451 {
1452 certificate_t *issuer, *current;
1453 auth_cfg_t *trustchain;
1454 int pathlen = 0;
1455
1456 trustchain = auth_cfg_create();
1457
1458 current = auth->get(auth, AUTH_RULE_CA_CERT);
1459 if (!current)
1460 {
1461 /* no trust anchor specified, return this cert only */
1462 trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT,
1463 subject->get_ref(subject));
1464 return trustchain;
1465 }
1466 current = subject->get_ref(subject);
1467 while (TRUE)
1468 {
1469 if (auth_contains_cacert(auth, current))
1470 {
1471 trustchain->add(trustchain, AUTH_RULE_CA_CERT, current);
1472 return trustchain;
1473 }
1474 if (subject == current)
1475 {
1476 trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT, current);
1477 }
1478 else
1479 {
1480 trustchain->add(trustchain, AUTH_RULE_IM_CERT, current);
1481 }
1482 issuer = get_issuer_cert(this, current, FALSE);
1483 if (!issuer || issuer->equals(issuer, current) ||
1484 pathlen > MAX_TRUST_PATH_LEN)
1485 {
1486 DESTROY_IF(issuer);
1487 break;
1488 }
1489 current = issuer;
1490 pathlen++;
1491 }
1492 trustchain->destroy(trustchain);
1493 return NULL;
1494 }
1495
1496 /**
1497 * find a private key of a give certificate
1498 */
1499 static private_key_t *get_private_by_cert(private_credential_manager_t *this,
1500 certificate_t *cert, key_type_t type)
1501 {
1502 private_key_t *private = NULL;
1503 identification_t *keyid;
1504 chunk_t chunk;
1505 public_key_t *public;
1506
1507 public = cert->get_public_key(cert);
1508 if (public)
1509 {
1510 if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
1511 {
1512 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
1513 private = get_private_by_keyid(this, type, keyid);
1514 keyid->destroy(keyid);
1515 }
1516 public->destroy(public);
1517 }
1518 return private;
1519 }
1520
1521 METHOD(credential_manager_t, get_private, private_key_t*,
1522 private_credential_manager_t *this, key_type_t type, identification_t *id,
1523 auth_cfg_t *auth)
1524 {
1525 enumerator_t *enumerator;
1526 certificate_t *cert;
1527 private_key_t *private = NULL;
1528 auth_cfg_t *trustchain;
1529
1530 /* check if this is a lookup by key ID, and do it if so */
1531 if (id && id->get_type(id) == ID_KEY_ID)
1532 {
1533 private = get_private_by_keyid(this, type, id);
1534 if (private)
1535 {
1536 return private;
1537 }
1538 }
1539
1540 /* if a specific certificate is preferred, check for a matching key */
1541 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
1542 if (cert)
1543 {
1544 private = get_private_by_cert(this, cert, type);
1545 if (private)
1546 {
1547 trustchain = build_trustchain(this, cert, auth);
1548 if (trustchain)
1549 {
1550 auth->merge(auth, trustchain, FALSE);
1551 trustchain->destroy(trustchain);
1552 }
1553 return private;
1554 }
1555 }
1556
1557 /* try to build a trust chain for each certificate found */
1558 enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
1559 while (enumerator->enumerate(enumerator, &cert))
1560 {
1561 private = get_private_by_cert(this, cert, type);
1562 if (private)
1563 {
1564 trustchain = build_trustchain(this, cert, auth);
1565 if (trustchain)
1566 {
1567 auth->merge(auth, trustchain, FALSE);
1568 trustchain->destroy(trustchain);
1569 break;
1570 }
1571 private->destroy(private);
1572 private = NULL;
1573 }
1574 }
1575 enumerator->destroy(enumerator);
1576
1577 /* if no valid trustchain was found, fall back to the first usable cert */
1578 if (!private)
1579 {
1580 enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
1581 while (enumerator->enumerate(enumerator, &cert))
1582 {
1583 private = get_private_by_cert(this, cert, type);
1584 if (private)
1585 {
1586 auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert));
1587 break;
1588 }
1589 }
1590 enumerator->destroy(enumerator);
1591 }
1592 return private;
1593 }
1594
1595 METHOD(credential_manager_t, flush_cache, void,
1596 private_credential_manager_t *this, certificate_type_t type)
1597 {
1598 this->cache->flush(this->cache, type);
1599 }
1600
1601 METHOD(credential_manager_t, add_set, void,
1602 private_credential_manager_t *this, credential_set_t *set)
1603 {
1604 this->lock->write_lock(this->lock);
1605 this->sets->insert_last(this->sets, set);
1606 this->lock->unlock(this->lock);
1607 }
1608
1609 METHOD(credential_manager_t, remove_set, void,
1610 private_credential_manager_t *this, credential_set_t *set)
1611 {
1612 this->lock->write_lock(this->lock);
1613 this->sets->remove(this->sets, set, NULL);
1614 this->lock->unlock(this->lock);
1615 }
1616
1617 METHOD(credential_manager_t, add_validator, void,
1618 private_credential_manager_t *this, cert_validator_t *vdtr)
1619 {
1620 this->lock->write_lock(this->lock);
1621 this->sets->insert_last(this->validators, vdtr);
1622 this->lock->unlock(this->lock);
1623 }
1624
1625 METHOD(credential_manager_t, remove_validator, void,
1626 private_credential_manager_t *this, cert_validator_t *vdtr)
1627 {
1628 this->lock->write_lock(this->lock);
1629 this->validators->remove(this->validators, vdtr, NULL);
1630 this->lock->unlock(this->lock);
1631 }
1632
1633 METHOD(credential_manager_t, destroy, void,
1634 private_credential_manager_t *this)
1635 {
1636 cache_queue(this);
1637 this->cache_queue->destroy(this->cache_queue);
1638 this->sets->remove(this->sets, this->cache, NULL);
1639 this->sets->destroy(this->sets);
1640 this->local_sets->destroy(this->local_sets);
1641 this->cache->destroy(this->cache);
1642 this->validators->destroy(this->validators);
1643 this->lock->destroy(this->lock);
1644 this->queue_mutex->destroy(this->queue_mutex);
1645 free(this);
1646 }
1647
1648 /*
1649 * see header file
1650 */
1651 credential_manager_t *credential_manager_create()
1652 {
1653 private_credential_manager_t *this;
1654
1655 INIT(this,
1656 .public = {
1657 .create_cert_enumerator = _create_cert_enumerator,
1658 .create_shared_enumerator = _create_shared_enumerator,
1659 .create_cdp_enumerator = _create_cdp_enumerator,
1660 .get_cert = _get_cert,
1661 .get_shared = _get_shared,
1662 .get_private = _get_private,
1663 .create_public_enumerator = _create_public_enumerator,
1664 .flush_cache = _flush_cache,
1665 .cache_cert = _cache_cert,
1666 .add_set = _add_set,
1667 .remove_set = _remove_set,
1668 .add_validator = _add_validator,
1669 .remove_validator = _remove_validator,
1670 .destroy = _destroy,
1671 },
1672 .sets = linked_list_create(),
1673 .validators = linked_list_create(),
1674 .cache = cert_cache_create(),
1675 .cache_queue = linked_list_create(),
1676 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1677 .queue_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
1678 );
1679
1680 this->local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy);
1681 this->sets->insert_first(this->sets, this->cache);
1682
1683 return &this->public;
1684 }