diff options
Diffstat (limited to 'src/libstrongswan/credentials/credential_manager.c')
-rw-r--r-- | src/libstrongswan/credentials/credential_manager.c | 200 |
1 files changed, 139 insertions, 61 deletions
diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index b3461b810..a96abdc69 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -53,6 +53,11 @@ struct private_credential_manager_t { thread_value_t *local_sets; /** + * Exclusive local sets, linked_list_t with credential_set_t + */ + thread_value_t *exclusive_local_sets; + + /** * trust relationship and certificate cache */ cert_cache_t *cache; @@ -117,12 +122,23 @@ typedef struct { enumerator_t *global; /** enumerator over local sets */ enumerator_t *local; + /** enumerator over exclusive local sets */ + enumerator_t *exclusive; } sets_enumerator_t; METHOD(enumerator_t, sets_enumerate, bool, sets_enumerator_t *this, credential_set_t **set) { + if (this->exclusive) + { + if (this->exclusive->enumerate(this->exclusive, set)) + { /* only enumerate last added */ + this->exclusive->destroy(this->exclusive); + this->exclusive = NULL; + return TRUE; + } + } if (this->global) { if (this->global->enumerate(this->global, set)) @@ -145,6 +161,7 @@ METHOD(enumerator_t, sets_destroy, void, { DESTROY_IF(this->global); DESTROY_IF(this->local); + DESTROY_IF(this->exclusive); free(this); } @@ -154,19 +171,28 @@ METHOD(enumerator_t, sets_destroy, void, static enumerator_t *create_sets_enumerator(private_credential_manager_t *this) { sets_enumerator_t *enumerator; - linked_list_t *local; + linked_list_t *list; INIT(enumerator, .public = { .enumerate = (void*)_sets_enumerate, .destroy = _sets_destroy, }, - .global = this->sets->create_enumerator(this->sets), ); - local = this->local_sets->get(this->local_sets); - if (local) + + list = this->exclusive_local_sets->get(this->exclusive_local_sets); + if (list && list->get_count(list)) + { + enumerator->exclusive = list->create_enumerator(list); + } + else { - enumerator->local = local->create_enumerator(local); + enumerator->global = this->sets->create_enumerator(this->sets); + list = this->local_sets->get(this->local_sets); + if (list) + { + enumerator->local = list->create_enumerator(list); + } } return &enumerator->public; } @@ -373,26 +399,66 @@ METHOD(credential_manager_t, get_shared, shared_key_t*, } METHOD(credential_manager_t, add_local_set, void, - private_credential_manager_t *this, credential_set_t *set) + private_credential_manager_t *this, credential_set_t *set, bool exclusive) { linked_list_t *sets; + thread_value_t *tv; - sets = this->local_sets->get(this->local_sets); + if (exclusive) + { + tv = this->exclusive_local_sets; + } + else + { + tv = this->local_sets; + } + sets = tv->get(tv); if (!sets) - { /* first invocation */ + { sets = linked_list_create(); - this->local_sets->set(this->local_sets, sets); + tv->set(tv, sets); + } + if (exclusive) + { + sets->insert_first(sets, set); + } + else + { + sets->insert_last(sets, set); } - sets->insert_last(sets, set); } METHOD(credential_manager_t, remove_local_set, void, private_credential_manager_t *this, credential_set_t *set) { linked_list_t *sets; + thread_value_t *tv; - sets = this->local_sets->get(this->local_sets); - sets->remove(sets, set, NULL); + tv = this->local_sets; + sets = tv->get(tv); + if (sets && sets->remove(sets, set, NULL) && sets->get_count(sets) == 0) + { + tv->set(tv, NULL); + sets->destroy(sets); + } + tv = this->exclusive_local_sets; + sets = tv->get(tv); + if (sets && sets->remove(sets, set, NULL) && sets->get_count(sets) == 0) + { + tv->set(tv, NULL); + sets->destroy(sets); + } +} + +METHOD(credential_manager_t, issued_by, bool, + private_credential_manager_t *this, certificate_t *subject, + certificate_t *issuer, signature_scheme_t *scheme) +{ + if (this->cache) + { + return this->cache->issued_by(this->cache, subject, issuer, scheme); + } + return subject->issued_by(subject, issuer, scheme); } METHOD(credential_manager_t, cache_cert, void, @@ -514,7 +580,8 @@ static certificate_t *get_pretrusted_cert(private_credential_manager_t *this, * Get the issuing certificate of a subject certificate */ static certificate_t *get_issuer_cert(private_credential_manager_t *this, - certificate_t *subject, bool trusted) + certificate_t *subject, bool trusted, + signature_scheme_t *scheme) { enumerator_t *enumerator; certificate_t *issuer = NULL, *candidate; @@ -523,7 +590,7 @@ static certificate_t *get_issuer_cert(private_credential_manager_t *this, subject->get_issuer(subject), trusted); while (enumerator->enumerate(enumerator, &candidate)) { - if (this->cache->issued_by(this->cache, subject, candidate)) + if (issued_by(this, subject, candidate, scheme)) { issuer = candidate->get_ref(candidate); break; @@ -573,6 +640,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, { certificate_t *current, *issuer; auth_cfg_t *auth; + signature_scheme_t scheme; int pathlen; auth = auth_cfg_create(); @@ -582,11 +650,11 @@ static bool verify_trust_chain(private_credential_manager_t *this, for (pathlen = 0; pathlen <= MAX_TRUST_PATH_LEN; pathlen++) { - issuer = get_issuer_cert(this, current, TRUE); + issuer = get_issuer_cert(this, current, TRUE, &scheme); if (issuer) { /* accept only self-signed CAs as trust anchor */ - if (this->cache->issued_by(this->cache, issuer, issuer)) + if (issued_by(this, issuer, issuer, NULL)) { auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer)); DBG1(DBG_CFG, " using trusted ca certificate \"%Y\"", @@ -599,10 +667,11 @@ static bool verify_trust_chain(private_credential_manager_t *this, DBG1(DBG_CFG, " using trusted intermediate ca certificate " "\"%Y\"", issuer->get_subject(issuer)); } + auth->add(auth, AUTH_RULE_SIGNATURE_SCHEME, scheme); } else { - issuer = get_issuer_cert(this, current, FALSE); + issuer = get_issuer_cert(this, current, FALSE, &scheme); if (issuer) { if (current->equals(current, issuer)) @@ -615,6 +684,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer)); DBG1(DBG_CFG, " using untrusted intermediate certificate " "\"%Y\"", issuer->get_subject(issuer)); + auth->add(auth, AUTH_RULE_SIGNATURE_SCHEME, scheme); } else { @@ -708,8 +778,7 @@ METHOD(enumerator_t, trusted_enumerate, bool, /* if we find a trusted self signed certificate, we just accept it. * However, in order to fulfill authorization rules, we try to build * the trust chain if it is not self signed */ - if (this->this->cache->issued_by(this->this->cache, - this->pretrusted, this->pretrusted) || + if (issued_by(this->this, this->pretrusted, this->pretrusted, NULL) || verify_trust_chain(this->this, this->pretrusted, this->auth, TRUE, this->online)) { @@ -859,7 +928,7 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*, if (auth) { enumerator->wrapper = auth_cfg_wrapper_create(auth); - add_local_set(this, &enumerator->wrapper->set); + add_local_set(this, &enumerator->wrapper->set, FALSE); } this->lock->read_lock(this->lock); return &enumerator->public; @@ -916,8 +985,7 @@ static auth_cfg_t *build_trustchain(private_credential_manager_t *this, } else { - if (!has_anchor && - this->cache->issued_by(this->cache, current, current)) + if (!has_anchor && issued_by(this, current, current, NULL)) { /* If no trust anchor specified, accept any CA */ trustchain->add(trustchain, AUTH_RULE_CA_CERT, current); return trustchain; @@ -928,7 +996,7 @@ static auth_cfg_t *build_trustchain(private_credential_manager_t *this, { break; } - issuer = get_issuer_cert(this, current, FALSE); + issuer = get_issuer_cert(this, current, FALSE, NULL); if (!issuer) { if (!has_anchor) @@ -992,42 +1060,45 @@ METHOD(credential_manager_t, get_private, private_key_t*, } } - /* if a specific certificate is preferred, check for a matching key */ - cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); - if (cert) + if (auth) { - private = get_private_by_cert(this, cert, type); - if (private) + /* if a specific certificate is preferred, check for a matching key */ + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (cert) { - trustchain = build_trustchain(this, cert, auth); - if (trustchain) + private = get_private_by_cert(this, cert, type); + if (private) { - auth->merge(auth, trustchain, FALSE); - trustchain->destroy(trustchain); + trustchain = build_trustchain(this, cert, auth); + if (trustchain) + { + auth->merge(auth, trustchain, FALSE); + trustchain->destroy(trustchain); + } + return private; } - return private; } - } - /* try to build a trust chain for each certificate found */ - enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); - while (enumerator->enumerate(enumerator, &cert)) - { - private = get_private_by_cert(this, cert, type); - if (private) + /* try to build a trust chain for each certificate found */ + enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); + while (enumerator->enumerate(enumerator, &cert)) { - trustchain = build_trustchain(this, cert, auth); - if (trustchain) + private = get_private_by_cert(this, cert, type); + if (private) { - auth->merge(auth, trustchain, FALSE); - trustchain->destroy(trustchain); - break; + trustchain = build_trustchain(this, cert, auth); + if (trustchain) + { + auth->merge(auth, trustchain, FALSE); + trustchain->destroy(trustchain); + break; + } + private->destroy(private); + private = NULL; } - private->destroy(private); - private = NULL; } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); /* if no valid trustchain was found, fall back to the first usable cert */ if (!private) @@ -1038,7 +1109,10 @@ METHOD(credential_manager_t, get_private, private_key_t*, private = get_private_by_cert(this, cert, type); if (private) { - auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert)); + if (auth) + { + auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert)); + } break; } } @@ -1050,14 +1124,10 @@ METHOD(credential_manager_t, get_private, private_key_t*, METHOD(credential_manager_t, flush_cache, void, private_credential_manager_t *this, certificate_type_t type) { - this->cache->flush(this->cache, type); -} - -METHOD(credential_manager_t, issued_by, bool, - private_credential_manager_t *this, certificate_t *subject, - certificate_t *issuer) -{ - return this->cache->issued_by(this->cache, subject, issuer); + if (this->cache) + { + this->cache->flush(this->cache, type); + } } METHOD(credential_manager_t, add_set, void, @@ -1097,10 +1167,14 @@ METHOD(credential_manager_t, destroy, void, { cache_queue(this); this->cache_queue->destroy(this->cache_queue); - this->sets->remove(this->sets, this->cache, NULL); + if (this->cache) + { + this->sets->remove(this->sets, this->cache, NULL); + this->cache->destroy(this->cache); + } this->sets->destroy(this->sets); this->local_sets->destroy(this->local_sets); - this->cache->destroy(this->cache); + this->exclusive_local_sets->destroy(this->exclusive_local_sets); this->validators->destroy(this->validators); this->lock->destroy(this->lock); this->queue_mutex->destroy(this->queue_mutex); @@ -1137,14 +1211,18 @@ credential_manager_t *credential_manager_create() }, .sets = linked_list_create(), .validators = linked_list_create(), - .cache = cert_cache_create(), .cache_queue = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .queue_mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); this->local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy); - this->sets->insert_first(this->sets, this->cache); + this->exclusive_local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy); + if (lib->settings->get_bool(lib->settings, "libstrongswan.cert_cache", TRUE)) + { + this->cache = cert_cache_create(); + this->sets->insert_first(this->sets, this->cache); + } return &this->public; } |