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