Coverage Report

Created: 2024-02-29 06:05

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