--- embedaddon/strongswan/src/libcharon/plugins/vici/vici_authority.c 2020/06/03 09:46:45 1.1.1.1 +++ embedaddon/strongswan/src/libcharon/plugins/vici/vici_authority.c 2021/03/17 00:20:09 1.1.1.2 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2019 Tobias Brunner + * Copyright (C) 2016-2020 Tobias Brunner * Copyright (C) 2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * @@ -44,14 +44,14 @@ struct private_vici_authority_t { vici_dispatcher_t *dispatcher; /** - * credential backend managed by VICI used for our ca certificates + * List of certification authorities (authority_t*) */ - vici_cred_t *cred; + linked_list_t *authorities; /** - * List of certification authorities + * List of CA certificates (ca_cert_t*) */ - linked_list_t *authorities; + linked_list_t *certs; /** * rwlock to lock access to certification authorities @@ -109,10 +109,8 @@ static authority_t *authority_create(char *name) return authority; } -/** - * destroy a certification authority - */ -static void authority_destroy(authority_t *this) +CALLBACK(authority_destroy, void, + authority_t *this) { this->crl_uris->destroy_function(this->crl_uris, free); this->ocsp_uris->destroy_function(this->ocsp_uris, free); @@ -122,8 +120,110 @@ static void authority_destroy(authority_t *this) free(this); } +typedef struct ca_cert_t ca_cert_t; /** + * Loaded CA certificate. + */ +struct ca_cert_t { + + /** + * Reference to certificate. + */ + certificate_t *cert; + + /** + * The number of authority sections referring to this certificate. + */ + u_int count; + + /** + * TRUE if this certificate was (also) added externally. + */ + bool external; +}; + +/** + * Destroy a CA certificate entry + */ +CALLBACK(ca_cert_destroy, void, + ca_cert_t *this) +{ + this->cert->destroy(this->cert); + free(this); +} + +CALLBACK(match_cert, bool, + ca_cert_t *item, va_list args) +{ + certificate_t *cert; + + VA_ARGS_VGET(args, cert); + return cert->equals(cert, item->cert); +} + +/** + * Add a CA certificate to the local store + */ +static certificate_t *add_cert_internal(private_vici_authority_t *this, + certificate_t *cert, bool external) +{ + ca_cert_t *found; + + if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert)) + { + cert->destroy(cert); + cert = found->cert->get_ref(found->cert); + } + else + { + INIT(found, + .cert = cert->get_ref(cert) + ); + this->certs->insert_first(this->certs, found); + } + if (external) + { + found->external = TRUE; + } + else + { + found->count++; + } + return cert; +} + +CALLBACK(remove_external_certs, bool, + ca_cert_t *item, void *unused) +{ + if (item->external) + { + item->external = FALSE; + + if (!item->count) + { + ca_cert_destroy(item); + return TRUE; + } + } + return FALSE; +} + +CALLBACK2(remove_cert, bool, + ca_cert_t *item, certificate_t *cert) +{ + if (cert == item->cert) + { + if (--item->count == 0 && !item->external) + { + ca_cert_destroy(item); + return TRUE; + } + } + return FALSE; +} + +/** * Create a (error) reply message */ static vici_message_t* create_reply(char *fmt, ...) @@ -379,7 +479,6 @@ CALLBACK(authority_sn, bool, enumerator_t *enumerator; linked_list_t *authorities; authority_t *authority; - vici_cred_t *cred; load_data_t *data; chunk_t handle; @@ -437,6 +536,9 @@ CALLBACK(authority_sn, bool, request->this->lock->write_lock(request->this->lock); + data->authority->cert = add_cert_internal(request->this, + data->authority->cert, FALSE); + authorities = request->this->authorities; enumerator = authorities->create_enumerator(authorities); while (enumerator->enumerate(enumerator, &authority)) @@ -445,6 +547,8 @@ CALLBACK(authority_sn, bool, { /* remove the old authority definition */ authorities->remove_at(authorities, enumerator); + request->this->certs->remove(request->this->certs, authority->cert, + remove_cert); authority_destroy(authority); break; } @@ -452,11 +556,8 @@ CALLBACK(authority_sn, bool, enumerator->destroy(enumerator); authorities->insert_last(authorities, data->authority); - cred = request->this->cred; - data->authority->cert = cred->add_cert(cred, data->authority->cert); - data->authority = NULL; - request->this->lock->unlock(request->this->lock); + data->authority = NULL; free_load_data(data); return TRUE; @@ -501,6 +602,7 @@ CALLBACK(unload_authority, vici_message_t*, if (streq(authority->name, authority_name)) { this->authorities->remove_at(this->authorities, enumerator); + this->certs->remove(this->certs, authority->cert, remove_cert); authority_destroy(authority); found = TRUE; break; @@ -513,6 +615,7 @@ CALLBACK(unload_authority, vici_message_t*, { return create_reply("unload: authority '%s' not found", authority_name); } + lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); return create_reply(NULL); } @@ -627,28 +730,64 @@ static void manage_commands(private_vici_authority_t * } /** - * data to pass to create_inner_cdp + * Data for the certificate and CDP enumerator */ typedef struct { private_vici_authority_t *this; certificate_type_t type; + key_type_t key; identification_t *id; -} cdp_data_t; +} cert_data_t; -/** - * destroy cdp enumerator data and unlock list - */ -static void cdp_data_destroy(cdp_data_t *data) +CALLBACK(cert_data_destroy, void, + cert_data_t *data) { data->this->lock->unlock(data->this->lock); free(data); } -/** - * inner enumerator constructor for CDP URIs - */ -static enumerator_t *create_inner_cdp(authority_t *authority, cdp_data_t *data) +CALLBACK(certs_filter, bool, + cert_data_t *data, enumerator_t *orig, va_list args) { + ca_cert_t *ca; + certificate_t **out; + + VA_ARGS_VGET(args, out); + + while (orig->enumerate(orig, &ca)) + { + if (certificate_matches(ca->cert, data->type, data->key, data->id)) + { + *out = ca->cert; + return TRUE; + } + } + return FALSE; +} + +METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, + private_vici_authority_t *this, certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + enumerator_t *enumerator; + cert_data_t *data; + + INIT(data, + .this = this, + .type = cert, + .key = key, + .id = id, + ); + + this->lock->read_lock(this->lock); + enumerator = this->certs->create_enumerator(this->certs); + return enumerator_create_filter(enumerator, certs_filter, data, + cert_data_destroy); +} + +CALLBACK(create_inner_cdp, enumerator_t*, + authority_t *authority, cert_data_t *data) +{ public_key_t *public; enumerator_t *enumerator = NULL; linked_list_t *list; @@ -671,7 +810,8 @@ static enumerator_t *create_inner_cdp(authority_t *aut } else { - if (public->has_fingerprint(public, data->id->get_encoding(data->id))) + if (public->has_fingerprint(public, + data->id->get_encoding(data->id))) { enumerator = list->create_enumerator(list); } @@ -681,11 +821,8 @@ static enumerator_t *create_inner_cdp(authority_t *aut return enumerator; } -/** - * inner enumerator constructor for "Hash and URL" - */ -static enumerator_t *create_inner_cdp_hashandurl(authority_t *authority, - cdp_data_t *data) +CALLBACK(create_inner_cdp_hashandurl, enumerator_t*, + authority_t *authority, cert_data_t *data) { enumerator_t *enumerator = NULL; @@ -694,7 +831,8 @@ static enumerator_t *create_inner_cdp_hashandurl(autho return NULL; } - if (authority->cert->has_subject(authority->cert, data->id) != ID_MATCH_NONE) + if (authority->cert->has_subject(authority->cert, + data->id) != ID_MATCH_NONE) { enumerator = enumerator_create_single(strdup(authority->cert_uri_base), free); @@ -706,7 +844,7 @@ METHOD(credential_set_t, create_cdp_enumerator, enumer private_vici_authority_t *this, certificate_type_t type, identification_t *id) { - cdp_data_t *data; + cert_data_t *data; switch (type) { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */ @@ -718,19 +856,37 @@ METHOD(credential_set_t, create_cdp_enumerator, enumer default: return NULL; } - data = malloc_thing(cdp_data_t); - data->this = this; - data->type = type; - data->id = id; - this->lock->read_lock(this->lock); + INIT(data, + .this = this, + .type = type, + .id = id, + ); + this->lock->read_lock(this->lock); return enumerator_create_nested( this->authorities->create_enumerator(this->authorities), (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : - (void*)create_inner_cdp, data, (void*)cdp_data_destroy); + (void*)create_inner_cdp, data, cert_data_destroy); } +METHOD(vici_authority_t, add_ca_cert, certificate_t*, + private_vici_authority_t *this, certificate_t *cert) +{ + this->lock->write_lock(this->lock); + cert = add_cert_internal(this, cert, TRUE); + this->lock->unlock(this->lock); + return cert; +} + +METHOD(vici_authority_t, clear_ca_certs, void, + private_vici_authority_t *this) +{ + this->lock->write_lock(this->lock); + this->certs->remove(this->certs, NULL, remove_external_certs); + this->lock->unlock(this->lock); +} + METHOD(vici_authority_t, destroy, void, private_vici_authority_t *this) { @@ -738,6 +894,7 @@ METHOD(vici_authority_t, destroy, void, this->authorities->destroy_function(this->authorities, (void*)authority_destroy); + this->certs->destroy_function(this->certs, ca_cert_destroy); this->lock->destroy(this->lock); free(this); } @@ -745,8 +902,7 @@ METHOD(vici_authority_t, destroy, void, /** * See header */ -vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher, - vici_cred_t *cred) +vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher) { private_vici_authority_t *this; @@ -754,16 +910,18 @@ vici_authority_t *vici_authority_create(vici_dispatche .public = { .set = { .create_private_enumerator = (void*)return_null, - .create_cert_enumerator = (void*)return_null, + .create_cert_enumerator = _create_cert_enumerator, .create_shared_enumerator = (void*)return_null, .create_cdp_enumerator = _create_cdp_enumerator, .cache_cert = (void*)nop, }, + .add_ca_cert = _add_ca_cert, + .clear_ca_certs = _clear_ca_certs, .destroy = _destroy, }, .dispatcher = dispatcher, - .cred = cred, .authorities = linked_list_create(), + .certs = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), );