Made some useful methods in the credential manager public
[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 METHOD(credential_manager_t, add_local_set, void,
379 private_credential_manager_t *this, credential_set_t *set)
380 {
381 linked_list_t *sets;
382
383 sets = this->local_sets->get(this->local_sets);
384 if (!sets)
385 { /* first invocation */
386 sets = linked_list_create();
387 this->local_sets->set(this->local_sets, sets);
388 }
389 sets->insert_last(sets, set);
390 }
391
392 METHOD(credential_manager_t, remove_local_set, void,
393 private_credential_manager_t *this, credential_set_t *set)
394 {
395 linked_list_t *sets;
396
397 sets = this->local_sets->get(this->local_sets);
398 sets->remove(sets, set, NULL);
399 }
400
401 METHOD(credential_manager_t, cache_cert, void,
402 private_credential_manager_t *this, certificate_t *cert)
403 {
404 credential_set_t *set;
405 enumerator_t *enumerator;
406
407 if (this->lock->try_write_lock(this->lock))
408 {
409 enumerator = this->sets->create_enumerator(this->sets);
410 while (enumerator->enumerate(enumerator, &set))
411 {
412 set->cache_cert(set, cert);
413 }
414 enumerator->destroy(enumerator);
415 this->lock->unlock(this->lock);
416 }
417 else
418 { /* we can't cache now as other threads are active, queue for later */
419 this->queue_mutex->lock(this->queue_mutex);
420 this->cache_queue->insert_last(this->cache_queue, cert->get_ref(cert));
421 this->queue_mutex->unlock(this->queue_mutex);
422 }
423 }
424
425 /**
426 * Try to cache certificates queued for caching
427 */
428 static void cache_queue(private_credential_manager_t *this)
429 {
430 credential_set_t *set;
431 certificate_t *cert;
432 enumerator_t *enumerator;
433
434 this->queue_mutex->lock(this->queue_mutex);
435 if (this->cache_queue->get_count(this->cache_queue) > 0 &&
436 this->lock->try_write_lock(this->lock))
437 {
438 while (this->cache_queue->remove_last(this->cache_queue,
439 (void**)&cert) == SUCCESS)
440 {
441 enumerator = this->sets->create_enumerator(this->sets);
442 while (enumerator->enumerate(enumerator, &set))
443 {
444 set->cache_cert(set, cert);
445 }
446 enumerator->destroy(enumerator);
447 cert->destroy(cert);
448 }
449 this->lock->unlock(this->lock);
450 }
451 this->queue_mutex->unlock(this->queue_mutex);
452 }
453
454 /**
455 * forward declaration
456 */
457 static enumerator_t *create_trusted_enumerator(private_credential_manager_t *this,
458 key_type_t type, identification_t *id, bool online);
459
460 /**
461 * Do an OCSP request
462 */
463 static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url,
464 certificate_t *subject, certificate_t *issuer)
465 {
466 certificate_t *request, *response;
467 chunk_t send, receive;
468
469 /* TODO: requestor name, signature */
470 request = lib->creds->create(lib->creds,
471 CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
472 BUILD_CA_CERT, issuer,
473 BUILD_CERT, subject, BUILD_END);
474 if (!request)
475 {
476 DBG1(DBG_CFG, "generating ocsp request failed");
477 return NULL;
478 }
479
480 send = request->get_encoding(request);
481 request->destroy(request);
482
483 DBG1(DBG_CFG, " requesting ocsp status from '%s' ...", url);
484 if (lib->fetcher->fetch(lib->fetcher, url, &receive,
485 FETCH_REQUEST_DATA, send,
486 FETCH_REQUEST_TYPE, "application/ocsp-request",
487 FETCH_END) != SUCCESS)
488 {
489 DBG1(DBG_CFG, "ocsp request to %s failed", url);
490 chunk_free(&send);
491 return NULL;
492 }
493 chunk_free(&send);
494
495 response = lib->creds->create(lib->creds,
496 CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
497 BUILD_BLOB_ASN1_DER, receive, BUILD_END);
498 chunk_free(&receive);
499 if (!response)
500 {
501 DBG1(DBG_CFG, "parsing ocsp response failed");
502 return NULL;
503 }
504 return response;
505 }
506
507 /**
508 * check the signature of an OCSP response
509 */
510 static bool verify_ocsp(private_credential_manager_t *this,
511 ocsp_response_t *response)
512 {
513 certificate_t *issuer, *subject;
514 identification_t *responder;
515 ocsp_response_wrapper_t *wrapper;
516 enumerator_t *enumerator;
517 bool verified = FALSE;
518
519 wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
520 add_local_set(this, &wrapper->set);
521
522 subject = &response->certificate;
523 responder = subject->get_issuer(subject);
524 enumerator = create_trusted_enumerator(this, KEY_ANY, responder, FALSE);
525 while (enumerator->enumerate(enumerator, &issuer, NULL))
526 {
527 if (this->cache->issued_by(this->cache, subject, issuer))
528 {
529 DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
530 issuer->get_subject(issuer));
531 verified = TRUE;
532 break;
533 }
534 }
535 enumerator->destroy(enumerator);
536
537 remove_local_set(this, &wrapper->set);
538 wrapper->destroy(wrapper);
539 return verified;
540 }
541
542 /**
543 * Get the better of two OCSP responses, and check for usable OCSP info
544 */
545 static certificate_t *get_better_ocsp(private_credential_manager_t *this,
546 certificate_t *cand, certificate_t *best,
547 x509_t *subject, x509_t *issuer,
548 cert_validation_t *valid, bool cache)
549 {
550 ocsp_response_t *response;
551 time_t revocation, this_update, next_update, valid_until;
552 crl_reason_t reason;
553 bool revoked = FALSE;
554
555 response = (ocsp_response_t*)cand;
556
557 /* check ocsp signature */
558 if (!verify_ocsp(this, response))
559 {
560 DBG1(DBG_CFG, "ocsp response verification failed");
561 cand->destroy(cand);
562 return best;
563 }
564 /* check if response contains our certificate */
565 switch (response->get_status(response, subject, issuer, &revocation, &reason,
566 &this_update, &next_update))
567 {
568 case VALIDATION_REVOKED:
569 /* subject has been revoked by a valid OCSP response */
570 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
571 &revocation, TRUE, crl_reason_names, reason);
572 revoked = TRUE;
573 break;
574 case VALIDATION_GOOD:
575 /* results in either good or stale */
576 break;
577 default:
578 case VALIDATION_FAILED:
579 /* candidate unusable, does not contain our cert */
580 DBG1(DBG_CFG, " ocsp response contains no status on our certificate");
581 cand->destroy(cand);
582 return best;
583 }
584
585 /* select the better of the two responses */
586 if (best == NULL || certificate_is_newer(cand, best))
587 {
588 DESTROY_IF(best);
589 best = cand;
590 if (best->get_validity(best, NULL, NULL, &valid_until))
591 {
592 DBG1(DBG_CFG, " ocsp response is valid: until %T",
593 &valid_until, FALSE);
594 *valid = VALIDATION_GOOD;
595 if (cache)
596 { /* cache non-stale only, stale certs get refetched */
597 cache_cert(this, best);
598 }
599 }
600 else
601 {
602 DBG1(DBG_CFG, " ocsp response is stale: since %T",
603 &valid_until, FALSE);
604 *valid = VALIDATION_STALE;
605 }
606 }
607 else
608 {
609 *valid = VALIDATION_STALE;
610 cand->destroy(cand);
611 }
612 if (revoked)
613 { /* revoked always counts, even if stale */
614 *valid = VALIDATION_REVOKED;
615 }
616 return best;
617 }
618
619 /**
620 * validate a x509 certificate using OCSP
621 */
622 static cert_validation_t check_ocsp(private_credential_manager_t *this,
623 x509_t *subject, x509_t *issuer,
624 auth_cfg_t *auth)
625 {
626 enumerator_t *enumerator;
627 cert_validation_t valid = VALIDATION_SKIPPED;
628 certificate_t *best = NULL, *current;
629 identification_t *keyid = NULL;
630 public_key_t *public;
631 chunk_t chunk;
632 char *uri = NULL;
633
634 /** lookup cache for valid OCSP responses */
635 enumerator = create_cert_enumerator(this, CERT_X509_OCSP_RESPONSE,
636 KEY_ANY, NULL, FALSE);
637 while (enumerator->enumerate(enumerator, &current))
638 {
639 current->get_ref(current);
640 best = get_better_ocsp(this, current, best, subject, issuer,
641 &valid, FALSE);
642 if (best && valid != VALIDATION_STALE)
643 {
644 DBG1(DBG_CFG, " using cached ocsp response");
645 break;
646 }
647 }
648 enumerator->destroy(enumerator);
649
650 /* derive the authorityKeyIdentifier from the issuer's public key */
651 current = &issuer->interface;
652 public = current->get_public_key(current);
653 if (public && public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
654 {
655 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
656 }
657 /** fetch from configured OCSP responder URLs */
658 if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
659 {
660 enumerator = create_cdp_enumerator(this, CERT_X509_OCSP_RESPONSE, keyid);
661 while (enumerator->enumerate(enumerator, &uri))
662 {
663 current = fetch_ocsp(this, uri, &subject->interface,
664 &issuer->interface);
665 if (current)
666 {
667 best = get_better_ocsp(this, current, best, subject, issuer,
668 &valid, TRUE);
669 if (best && valid != VALIDATION_STALE)
670 {
671 break;
672 }
673 }
674 }
675 enumerator->destroy(enumerator);
676 }
677 DESTROY_IF(public);
678 DESTROY_IF(keyid);
679
680 /* fallback to URL fetching from subject certificate's URIs */
681 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
682 {
683 enumerator = subject->create_ocsp_uri_enumerator(subject);
684 while (enumerator->enumerate(enumerator, &uri))
685 {
686 current = fetch_ocsp(this, uri, &subject->interface,
687 &issuer->interface);
688 if (current)
689 {
690 best = get_better_ocsp(this, current, best, subject, issuer,
691 &valid, TRUE);
692 if (best && valid != VALIDATION_STALE)
693 {
694 break;
695 }
696 }
697 }
698 enumerator->destroy(enumerator);
699 }
700 /* an uri was found, but no result. switch validation state to failed */
701 if (valid == VALIDATION_SKIPPED && uri)
702 {
703 valid = VALIDATION_FAILED;
704 }
705 if (auth)
706 {
707 auth->add(auth, AUTH_RULE_OCSP_VALIDATION, valid);
708 if (valid == VALIDATION_GOOD)
709 { /* successful OCSP check fulfills also CRL constraint */
710 auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
711 }
712 }
713 DESTROY_IF(best);
714 return valid;
715 }
716
717 /**
718 * fetch a CRL from an URL
719 */
720 static certificate_t* fetch_crl(private_credential_manager_t *this, char *url)
721 {
722 certificate_t *crl;
723 chunk_t chunk;
724
725 DBG1(DBG_CFG, " fetching crl from '%s' ...", url);
726 if (lib->fetcher->fetch(lib->fetcher, url, &chunk, FETCH_END) != SUCCESS)
727 {
728 DBG1(DBG_CFG, "crl fetching failed");
729 return NULL;
730 }
731 crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
732 BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
733 chunk_free(&chunk);
734 if (!crl)
735 {
736 DBG1(DBG_CFG, "crl fetched successfully but parsing failed");
737 return NULL;
738 }
739 return crl;
740 }
741
742 /**
743 * check the signature of an CRL
744 */
745 static bool verify_crl(private_credential_manager_t *this, certificate_t *crl)
746 {
747 certificate_t *issuer;
748 enumerator_t *enumerator;
749 bool verified = FALSE;
750
751 enumerator = create_trusted_enumerator(this, KEY_ANY, crl->get_issuer(crl),
752 FALSE);
753 while (enumerator->enumerate(enumerator, &issuer, NULL))
754 {
755 if (this->cache->issued_by(this->cache, crl, issuer))
756 {
757 DBG1(DBG_CFG, " crl correctly signed by \"%Y\"",
758 issuer->get_subject(issuer));
759 verified = TRUE;
760 break;
761 }
762 }
763 enumerator->destroy(enumerator);
764
765 return verified;
766 }
767
768 /**
769 * Get the better of two CRLs, and check for usable CRL info
770 */
771 static certificate_t *get_better_crl(private_credential_manager_t *this,
772 certificate_t *cand, certificate_t *best,
773 x509_t *subject, x509_t *issuer,
774 cert_validation_t *valid, bool cache)
775 {
776 enumerator_t *enumerator;
777 time_t revocation, valid_until;
778 crl_reason_t reason;
779 chunk_t serial;
780 crl_t *crl;
781
782 /* check CRL signature */
783 if (!verify_crl(this, cand))
784 {
785 DBG1(DBG_CFG, "crl response verification failed");
786 cand->destroy(cand);
787 return best;
788 }
789
790 crl = (crl_t*)cand;
791 enumerator = crl->create_enumerator(crl);
792 while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
793 {
794 if (chunk_equals(serial, subject->get_serial(subject)))
795 {
796 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
797 &revocation, TRUE, crl_reason_names, reason);
798 *valid = VALIDATION_REVOKED;
799 enumerator->destroy(enumerator);
800 DESTROY_IF(best);
801 return cand;
802 }
803 }
804 enumerator->destroy(enumerator);
805
806 /* select the better of the two CRLs */
807 if (best == NULL || crl_is_newer(crl, (crl_t*)best))
808 {
809 DESTROY_IF(best);
810 best = cand;
811 if (best->get_validity(best, NULL, NULL, &valid_until))
812 {
813 DBG1(DBG_CFG, " crl is valid: until %T", &valid_until, FALSE);
814 *valid = VALIDATION_GOOD;
815 if (cache)
816 { /* we cache non-stale crls only, as a stale crls are refetched */
817 cache_cert(this, best);
818 }
819 }
820 else
821 {
822 DBG1(DBG_CFG, " crl is stale: since %T", &valid_until, FALSE);
823 *valid = VALIDATION_STALE;
824 }
825 }
826 else
827 {
828 *valid = VALIDATION_STALE;
829 cand->destroy(cand);
830 }
831 return best;
832 }
833
834 /**
835 * validate a x509 certificate using CRL
836 */
837 static cert_validation_t check_crl(private_credential_manager_t *this,
838 x509_t *subject, x509_t *issuer,
839 auth_cfg_t *auth)
840 {
841 cert_validation_t valid = VALIDATION_SKIPPED;
842 identification_t *keyid = NULL;
843 certificate_t *best = NULL;
844 certificate_t *current;
845 public_key_t *public;
846 enumerator_t *enumerator;
847 chunk_t chunk;
848 char *uri = NULL;
849
850 /* derive the authorityKeyIdentifier from the issuer's public key */
851 current = &issuer->interface;
852 public = current->get_public_key(current);
853 if (public && public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
854 {
855 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
856
857 /* find a cached crl by authorityKeyIdentifier */
858 enumerator = create_cert_enumerator(this, CERT_X509_CRL, KEY_ANY,
859 keyid, FALSE);
860 while (enumerator->enumerate(enumerator, &current))
861 {
862 current->get_ref(current);
863 best = get_better_crl(this, current, best, subject, issuer,
864 &valid, FALSE);
865 if (best && valid != VALIDATION_STALE)
866 {
867 DBG1(DBG_CFG, " using cached crl");
868 break;
869 }
870 }
871 enumerator->destroy(enumerator);
872
873 /* fallback to fetching crls from credential sets cdps */
874 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
875 {
876 enumerator = create_cdp_enumerator(this, CERT_X509_CRL, keyid);
877
878 while (enumerator->enumerate(enumerator, &uri))
879 {
880 current = fetch_crl(this, uri);
881 if (current)
882 {
883 best = get_better_crl(this, current, best, subject, issuer,
884 &valid, TRUE);
885 if (best && valid != VALIDATION_STALE)
886 {
887 break;
888 }
889 }
890 }
891 enumerator->destroy(enumerator);
892 }
893 keyid->destroy(keyid);
894 }
895 DESTROY_IF(public);
896
897 /* fallback to fetching crls from cdps from subject's certificate */
898 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
899 {
900 enumerator = subject->create_crl_uri_enumerator(subject);
901
902 while (enumerator->enumerate(enumerator, &uri))
903 {
904 current = fetch_crl(this, uri);
905 if (current)
906 {
907 best = get_better_crl(this, current, best, subject, issuer,
908 &valid, TRUE);
909 if (best && valid != VALIDATION_STALE)
910 {
911 break;
912 }
913 }
914 }
915 enumerator->destroy(enumerator);
916 }
917
918 /* an uri was found, but no result. switch validation state to failed */
919 if (valid == VALIDATION_SKIPPED && uri)
920 {
921 valid = VALIDATION_FAILED;
922 }
923 if (auth)
924 {
925 if (valid == VALIDATION_SKIPPED)
926 { /* if we skipped CRL validation, we use the result of OCSP for
927 * constraint checking */
928 auth->add(auth, AUTH_RULE_CRL_VALIDATION,
929 auth->get(auth, AUTH_RULE_OCSP_VALIDATION));
930 }
931 else
932 {
933 auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid);
934 }
935 }
936 DESTROY_IF(best);
937 return valid;
938 }
939
940 /**
941 * check a certificate for its lifetime
942 */
943 static bool check_certificate(private_credential_manager_t *this,
944 certificate_t *subject, certificate_t *issuer,
945 bool online, int pathlen, auth_cfg_t *auth)
946 {
947 time_t not_before, not_after;
948 cert_validator_t *validator;
949 enumerator_t *enumerator;
950
951 if (!subject->get_validity(subject, NULL, &not_before, &not_after))
952 {
953 DBG1(DBG_CFG, "subject certificate invalid (valid from %T to %T)",
954 &not_before, FALSE, &not_after, FALSE);
955 return FALSE;
956 }
957 if (!issuer->get_validity(issuer, NULL, &not_before, &not_after))
958 {
959 DBG1(DBG_CFG, "issuer certificate invalid (valid from %T to %T)",
960 &not_before, FALSE, &not_after, FALSE);
961 return FALSE;
962 }
963 if (issuer->get_type(issuer) == CERT_X509 &&
964 subject->get_type(subject) == CERT_X509)
965 {
966 int pathlen_constraint;
967 x509_t *x509;
968
969 /* check path length constraint */
970 x509 = (x509_t*)issuer;
971 pathlen_constraint = x509->get_pathLenConstraint(x509);
972 if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT &&
973 pathlen > pathlen_constraint)
974 {
975 DBG1(DBG_CFG, "path length of %d violates constraint of %d",
976 pathlen, pathlen_constraint);
977 return FALSE;
978 }
979
980 if (online)
981 {
982 DBG1(DBG_CFG, "checking certificate status of \"%Y\"",
983 subject->get_subject(subject));
984 switch (check_ocsp(this, (x509_t*)subject, (x509_t*)issuer, auth))
985 {
986 case VALIDATION_GOOD:
987 DBG1(DBG_CFG, "certificate status is good");
988 return TRUE;
989 case VALIDATION_REVOKED:
990 /* has already been logged */
991 return FALSE;
992 case VALIDATION_SKIPPED:
993 DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
994 break;
995 case VALIDATION_STALE:
996 DBG1(DBG_CFG, "ocsp information stale, fallback to crl");
997 break;
998 case VALIDATION_FAILED:
999 DBG1(DBG_CFG, "ocsp check failed, fallback to crl");
1000 break;
1001 }
1002 switch (check_crl(this, (x509_t*)subject, (x509_t*)issuer, auth))
1003 {
1004 case VALIDATION_GOOD:
1005 DBG1(DBG_CFG, "certificate status is good");
1006 return TRUE;
1007 case VALIDATION_REVOKED:
1008 /* has already been logged */
1009 return FALSE;
1010 case VALIDATION_FAILED:
1011 case VALIDATION_SKIPPED:
1012 DBG1(DBG_CFG, "certificate status is not available");
1013 break;
1014 case VALIDATION_STALE:
1015 DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
1016 break;
1017 }
1018 }
1019 }
1020
1021 enumerator = this->validators->create_enumerator(this->validators);
1022 while (enumerator->enumerate(enumerator, &validator))
1023 {
1024 if (!validator->validate(validator, subject, issuer,
1025 online, pathlen, auth))
1026 {
1027 enumerator->destroy(enumerator);
1028 return FALSE;
1029 }
1030 }
1031 enumerator->destroy(enumerator);
1032 return TRUE;
1033 }
1034
1035 /**
1036 * Get a trusted certificate from a credential set
1037 */
1038 static certificate_t *get_pretrusted_cert(private_credential_manager_t *this,
1039 key_type_t type, identification_t *id)
1040 {
1041 certificate_t *subject;
1042 public_key_t *public;
1043
1044 subject = get_cert(this, CERT_ANY, type, id, TRUE);
1045 if (!subject)
1046 {
1047 return NULL;
1048 }
1049 public = subject->get_public_key(subject);
1050 if (!public)
1051 {
1052 subject->destroy(subject);
1053 return NULL;
1054 }
1055 public->destroy(public);
1056 return subject;
1057 }
1058
1059 /**
1060 * Get the issuing certificate of a subject certificate
1061 */
1062 static certificate_t *get_issuer_cert(private_credential_manager_t *this,
1063 certificate_t *subject, bool trusted)
1064 {
1065 enumerator_t *enumerator;
1066 certificate_t *issuer = NULL, *candidate;
1067
1068 enumerator = create_cert_enumerator(this, subject->get_type(subject), KEY_ANY,
1069 subject->get_issuer(subject), trusted);
1070 while (enumerator->enumerate(enumerator, &candidate))
1071 {
1072 if (this->cache->issued_by(this->cache, subject, candidate))
1073 {
1074 issuer = candidate->get_ref(candidate);
1075 break;
1076 }
1077 }
1078 enumerator->destroy(enumerator);
1079 return issuer;
1080 }
1081
1082 /**
1083 * try to verify the trust chain of subject, return TRUE if trusted
1084 */
1085 static bool verify_trust_chain(private_credential_manager_t *this,
1086 certificate_t *subject, auth_cfg_t *result,
1087 bool trusted, bool online)
1088 {
1089 certificate_t *current, *issuer;
1090 auth_cfg_t *auth;
1091 int pathlen;
1092
1093 auth = auth_cfg_create();
1094 current = subject->get_ref(subject);
1095
1096 for (pathlen = 0; pathlen <= MAX_TRUST_PATH_LEN; pathlen++)
1097 {
1098 issuer = get_issuer_cert(this, current, TRUE);
1099 if (issuer)
1100 {
1101 /* accept only self-signed CAs as trust anchor */
1102 if (this->cache->issued_by(this->cache, issuer, issuer))
1103 {
1104 auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer));
1105 DBG1(DBG_CFG, " using trusted ca certificate \"%Y\"",
1106 issuer->get_subject(issuer));
1107 trusted = TRUE;
1108 }
1109 else
1110 {
1111 auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
1112 DBG1(DBG_CFG, " using trusted intermediate ca certificate "
1113 "\"%Y\"", issuer->get_subject(issuer));
1114 }
1115 }
1116 else
1117 {
1118 issuer = get_issuer_cert(this, current, FALSE);
1119 if (issuer)
1120 {
1121 if (current->equals(current, issuer))
1122 {
1123 DBG1(DBG_CFG, " self-signed certificate \"%Y\" is not trusted",
1124 current->get_subject(current));
1125 issuer->destroy(issuer);
1126 break;
1127 }
1128 auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
1129 DBG1(DBG_CFG, " using untrusted intermediate certificate "
1130 "\"%Y\"", issuer->get_subject(issuer));
1131 }
1132 else
1133 {
1134 DBG1(DBG_CFG, "no issuer certificate found for \"%Y\"",
1135 current->get_subject(current));
1136 break;
1137 }
1138 }
1139 if (!check_certificate(this, current, issuer, online, pathlen,
1140 current == subject ? auth : NULL))
1141 {
1142 trusted = FALSE;
1143 issuer->destroy(issuer);
1144 break;
1145 }
1146 current->destroy(current);
1147 current = issuer;
1148 if (trusted)
1149 {
1150 DBG1(DBG_CFG, " reached self-signed root ca with a path length of %d",
1151 pathlen);
1152 break;
1153 }
1154 }
1155 current->destroy(current);
1156 if (pathlen > MAX_TRUST_PATH_LEN)
1157 {
1158 DBG1(DBG_CFG, "maximum path length of %d exceeded", MAX_TRUST_PATH_LEN);
1159 }
1160 if (trusted)
1161 {
1162 result->merge(result, auth, FALSE);
1163 }
1164 auth->destroy(auth);
1165 return trusted;
1166 }
1167
1168 /**
1169 * enumerator for trusted certificates
1170 */
1171 typedef struct {
1172 /** implements enumerator_t interface */
1173 enumerator_t public;
1174 /** enumerator over candidate peer certificates */
1175 enumerator_t *candidates;
1176 /** reference to the credential_manager */
1177 private_credential_manager_t *this;
1178 /** type of the requested key */
1179 key_type_t type;
1180 /** identity the requested key belongs to */
1181 identification_t *id;
1182 /** TRUE to do CRL/OCSP checking */
1183 bool online;
1184 /** pretrusted certificate we have served at first invocation */
1185 certificate_t *pretrusted;
1186 /** currently enumerating auth config */
1187 auth_cfg_t *auth;
1188 } trusted_enumerator_t;
1189
1190 METHOD(enumerator_t, trusted_enumerate, bool,
1191 trusted_enumerator_t *this, certificate_t **cert, auth_cfg_t **auth)
1192 {
1193 certificate_t *current;
1194
1195 DESTROY_IF(this->auth);
1196 this->auth = auth_cfg_create();
1197
1198 if (!this->candidates)
1199 {
1200 /* first invocation, build enumerator for next one */
1201 this->candidates = create_cert_enumerator(this->this, CERT_ANY,
1202 this->type, this->id, FALSE);
1203 /* check if we have a trusted certificate for that peer */
1204 this->pretrusted = get_pretrusted_cert(this->this, this->type, this->id);
1205 if (this->pretrusted)
1206 {
1207 /* if we find a trusted self signed certificate, we just accept it.
1208 * However, in order to fulfill authorization rules, we try to build
1209 * the trust chain if it is not self signed */
1210 if (this->this->cache->issued_by(this->this->cache,
1211 this->pretrusted, this->pretrusted) ||
1212 verify_trust_chain(this->this, this->pretrusted, this->auth,
1213 TRUE, this->online))
1214 {
1215 this->auth->add(this->auth, AUTH_RULE_SUBJECT_CERT,
1216 this->pretrusted->get_ref(this->pretrusted));
1217 DBG1(DBG_CFG, " using trusted certificate \"%Y\"",
1218 this->pretrusted->get_subject(this->pretrusted));
1219 *cert = this->pretrusted;
1220 if (auth)
1221 {
1222 *auth = this->auth;
1223 }
1224 return TRUE;
1225 }
1226 }
1227 }
1228 /* try to verify the trust chain for each certificate found */
1229 while (this->candidates->enumerate(this->candidates, &current))
1230 {
1231 if (this->pretrusted &&
1232 this->pretrusted->equals(this->pretrusted, current))
1233 { /* skip pretrusted certificate we already served */
1234 continue;
1235 }
1236
1237 DBG1(DBG_CFG, " using certificate \"%Y\"",
1238 current->get_subject(current));
1239 if (verify_trust_chain(this->this, current, this->auth, FALSE,
1240 this->online))
1241 {
1242 *cert = current;
1243 if (auth)
1244 {
1245 *auth = this->auth;
1246 }
1247 return TRUE;
1248 }
1249 }
1250 return FALSE;
1251 }
1252
1253 METHOD(enumerator_t, trusted_destroy, void,
1254 trusted_enumerator_t *this)
1255 {
1256 DESTROY_IF(this->pretrusted);
1257 DESTROY_IF(this->auth);
1258 DESTROY_IF(this->candidates);
1259 free(this);
1260 }
1261
1262 METHOD(credential_manager_t, create_trusted_enumerator, enumerator_t*,
1263 private_credential_manager_t *this, key_type_t type,
1264 identification_t *id, bool online)
1265 {
1266 trusted_enumerator_t *enumerator;
1267
1268 INIT(enumerator,
1269 .public = {
1270 .enumerate = (void*)_trusted_enumerate,
1271 .destroy = _trusted_destroy,
1272 },
1273 .this = this,
1274 .type = type,
1275 .id = id,
1276 .online = online,
1277 );
1278 return &enumerator->public;
1279 }
1280
1281 /**
1282 * enumerator for public keys
1283 */
1284 typedef struct {
1285 /** implements enumerator_t interface */
1286 enumerator_t public;
1287 /** enumerator over candidate peer certificates */
1288 enumerator_t *inner;
1289 /** reference to the credential_manager */
1290 private_credential_manager_t *this;
1291 /** currently enumerating key */
1292 public_key_t *current;
1293 /** credset wrapper around auth config */
1294 auth_cfg_wrapper_t *wrapper;
1295 } public_enumerator_t;
1296
1297 METHOD(enumerator_t, public_enumerate, bool,
1298 public_enumerator_t *this, public_key_t **key, auth_cfg_t **auth)
1299 {
1300 certificate_t *cert;
1301
1302 while (this->inner->enumerate(this->inner, &cert, auth))
1303 {
1304 DESTROY_IF(this->current);
1305 this->current = cert->get_public_key(cert);
1306 if (this->current)
1307 {
1308 *key = this->current;
1309 return TRUE;
1310 }
1311 }
1312 return FALSE;
1313 }
1314
1315 METHOD(enumerator_t, public_destroy, void,
1316 public_enumerator_t *this)
1317 {
1318 DESTROY_IF(this->current);
1319 this->inner->destroy(this->inner);
1320 if (this->wrapper)
1321 {
1322 remove_local_set(this->this, &this->wrapper->set);
1323 this->wrapper->destroy(this->wrapper);
1324 }
1325 this->this->lock->unlock(this->this->lock);
1326
1327 /* check for delayed certificate cache queue */
1328 cache_queue(this->this);
1329 free(this);
1330 }
1331
1332 METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
1333 private_credential_manager_t *this, key_type_t type, identification_t *id,
1334 auth_cfg_t *auth)
1335 {
1336 public_enumerator_t *enumerator;
1337
1338 INIT(enumerator,
1339 .public = {
1340 .enumerate = (void*)_public_enumerate,
1341 .destroy = _public_destroy,
1342 },
1343 .inner = create_trusted_enumerator(this, type, id, TRUE),
1344 .this = this,
1345 );
1346 if (auth)
1347 {
1348 enumerator->wrapper = auth_cfg_wrapper_create(auth);
1349 add_local_set(this, &enumerator->wrapper->set);
1350 }
1351 this->lock->read_lock(this->lock);
1352 return &enumerator->public;
1353 }
1354
1355 /**
1356 * Check if a certificate's keyid is contained in the auth helper
1357 */
1358 static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert)
1359 {
1360 enumerator_t *enumerator;
1361 identification_t *value;
1362 auth_rule_t type;
1363 bool found = FALSE;
1364
1365 enumerator = auth->create_enumerator(auth);
1366 while (enumerator->enumerate(enumerator, &type, &value))
1367 {
1368 if (type == AUTH_RULE_CA_CERT &&
1369 cert->equals(cert, (certificate_t*)value))
1370 {
1371 found = TRUE;
1372 break;
1373 }
1374 }
1375 enumerator->destroy(enumerator);
1376 return found;
1377 }
1378
1379 /**
1380 * build a trustchain from subject up to a trust anchor in trusted
1381 */
1382 static auth_cfg_t *build_trustchain(private_credential_manager_t *this,
1383 certificate_t *subject, auth_cfg_t *auth)
1384 {
1385 certificate_t *issuer, *current;
1386 auth_cfg_t *trustchain;
1387 int pathlen = 0;
1388
1389 trustchain = auth_cfg_create();
1390
1391 current = auth->get(auth, AUTH_RULE_CA_CERT);
1392 if (!current)
1393 {
1394 /* no trust anchor specified, return this cert only */
1395 trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT,
1396 subject->get_ref(subject));
1397 return trustchain;
1398 }
1399 current = subject->get_ref(subject);
1400 while (TRUE)
1401 {
1402 if (auth_contains_cacert(auth, current))
1403 {
1404 trustchain->add(trustchain, AUTH_RULE_CA_CERT, current);
1405 return trustchain;
1406 }
1407 if (subject == current)
1408 {
1409 trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT, current);
1410 }
1411 else
1412 {
1413 trustchain->add(trustchain, AUTH_RULE_IM_CERT, current);
1414 }
1415 issuer = get_issuer_cert(this, current, FALSE);
1416 if (!issuer || issuer->equals(issuer, current) ||
1417 pathlen > MAX_TRUST_PATH_LEN)
1418 {
1419 DESTROY_IF(issuer);
1420 break;
1421 }
1422 current = issuer;
1423 pathlen++;
1424 }
1425 trustchain->destroy(trustchain);
1426 return NULL;
1427 }
1428
1429 /**
1430 * find a private key of a give certificate
1431 */
1432 static private_key_t *get_private_by_cert(private_credential_manager_t *this,
1433 certificate_t *cert, key_type_t type)
1434 {
1435 private_key_t *private = NULL;
1436 identification_t *keyid;
1437 chunk_t chunk;
1438 public_key_t *public;
1439
1440 public = cert->get_public_key(cert);
1441 if (public)
1442 {
1443 if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
1444 {
1445 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
1446 private = get_private_by_keyid(this, type, keyid);
1447 keyid->destroy(keyid);
1448 }
1449 public->destroy(public);
1450 }
1451 return private;
1452 }
1453
1454 METHOD(credential_manager_t, get_private, private_key_t*,
1455 private_credential_manager_t *this, key_type_t type, identification_t *id,
1456 auth_cfg_t *auth)
1457 {
1458 enumerator_t *enumerator;
1459 certificate_t *cert;
1460 private_key_t *private = NULL;
1461 auth_cfg_t *trustchain;
1462
1463 /* check if this is a lookup by key ID, and do it if so */
1464 if (id && id->get_type(id) == ID_KEY_ID)
1465 {
1466 private = get_private_by_keyid(this, type, id);
1467 if (private)
1468 {
1469 return private;
1470 }
1471 }
1472
1473 /* if a specific certificate is preferred, check for a matching key */
1474 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
1475 if (cert)
1476 {
1477 private = get_private_by_cert(this, cert, type);
1478 if (private)
1479 {
1480 trustchain = build_trustchain(this, cert, auth);
1481 if (trustchain)
1482 {
1483 auth->merge(auth, trustchain, FALSE);
1484 trustchain->destroy(trustchain);
1485 }
1486 return private;
1487 }
1488 }
1489
1490 /* try to build a trust chain for each certificate found */
1491 enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
1492 while (enumerator->enumerate(enumerator, &cert))
1493 {
1494 private = get_private_by_cert(this, cert, type);
1495 if (private)
1496 {
1497 trustchain = build_trustchain(this, cert, auth);
1498 if (trustchain)
1499 {
1500 auth->merge(auth, trustchain, FALSE);
1501 trustchain->destroy(trustchain);
1502 break;
1503 }
1504 private->destroy(private);
1505 private = NULL;
1506 }
1507 }
1508 enumerator->destroy(enumerator);
1509
1510 /* if no valid trustchain was found, fall back to the first usable cert */
1511 if (!private)
1512 {
1513 enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
1514 while (enumerator->enumerate(enumerator, &cert))
1515 {
1516 private = get_private_by_cert(this, cert, type);
1517 if (private)
1518 {
1519 auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert));
1520 break;
1521 }
1522 }
1523 enumerator->destroy(enumerator);
1524 }
1525 return private;
1526 }
1527
1528 METHOD(credential_manager_t, flush_cache, void,
1529 private_credential_manager_t *this, certificate_type_t type)
1530 {
1531 this->cache->flush(this->cache, type);
1532 }
1533
1534 METHOD(credential_manager_t, issued_by, bool,
1535 private_credential_manager_t *this, certificate_t *subject,
1536 certificate_t *issuer)
1537 {
1538 return this->cache->issued_by(this->cache, subject, issuer);
1539 }
1540
1541 METHOD(credential_manager_t, add_set, void,
1542 private_credential_manager_t *this, credential_set_t *set)
1543 {
1544 this->lock->write_lock(this->lock);
1545 this->sets->insert_last(this->sets, set);
1546 this->lock->unlock(this->lock);
1547 }
1548
1549 METHOD(credential_manager_t, remove_set, void,
1550 private_credential_manager_t *this, credential_set_t *set)
1551 {
1552 this->lock->write_lock(this->lock);
1553 this->sets->remove(this->sets, set, NULL);
1554 this->lock->unlock(this->lock);
1555 }
1556
1557 METHOD(credential_manager_t, add_validator, void,
1558 private_credential_manager_t *this, cert_validator_t *vdtr)
1559 {
1560 this->lock->write_lock(this->lock);
1561 this->sets->insert_last(this->validators, vdtr);
1562 this->lock->unlock(this->lock);
1563 }
1564
1565 METHOD(credential_manager_t, remove_validator, void,
1566 private_credential_manager_t *this, cert_validator_t *vdtr)
1567 {
1568 this->lock->write_lock(this->lock);
1569 this->validators->remove(this->validators, vdtr, NULL);
1570 this->lock->unlock(this->lock);
1571 }
1572
1573 METHOD(credential_manager_t, destroy, void,
1574 private_credential_manager_t *this)
1575 {
1576 cache_queue(this);
1577 this->cache_queue->destroy(this->cache_queue);
1578 this->sets->remove(this->sets, this->cache, NULL);
1579 this->sets->destroy(this->sets);
1580 this->local_sets->destroy(this->local_sets);
1581 this->cache->destroy(this->cache);
1582 this->validators->destroy(this->validators);
1583 this->lock->destroy(this->lock);
1584 this->queue_mutex->destroy(this->queue_mutex);
1585 free(this);
1586 }
1587
1588 /*
1589 * see header file
1590 */
1591 credential_manager_t *credential_manager_create()
1592 {
1593 private_credential_manager_t *this;
1594
1595 INIT(this,
1596 .public = {
1597 .create_cert_enumerator = _create_cert_enumerator,
1598 .create_shared_enumerator = _create_shared_enumerator,
1599 .create_cdp_enumerator = _create_cdp_enumerator,
1600 .get_cert = _get_cert,
1601 .get_shared = _get_shared,
1602 .get_private = _get_private,
1603 .create_trusted_enumerator = _create_trusted_enumerator,
1604 .create_public_enumerator = _create_public_enumerator,
1605 .flush_cache = _flush_cache,
1606 .cache_cert = _cache_cert,
1607 .issued_by = _issued_by,
1608 .add_set = _add_set,
1609 .remove_set = _remove_set,
1610 .add_local_set = _add_local_set,
1611 .remove_local_set = _remove_local_set,
1612 .add_validator = _add_validator,
1613 .remove_validator = _remove_validator,
1614 .destroy = _destroy,
1615 },
1616 .sets = linked_list_create(),
1617 .validators = linked_list_create(),
1618 .cache = cert_cache_create(),
1619 .cache_queue = linked_list_create(),
1620 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1621 .queue_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
1622 );
1623
1624 this->local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy);
1625 this->sets->insert_first(this->sets, this->cache);
1626
1627 return &this->public;
1628 }