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