From: Martin Willi Date: Thu, 20 Mar 2008 14:31:36 +0000 (-0000) Subject: cert_cache_t caches subject-issuer relations and subject certificates X-Git-Tag: 4.2.0~105 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dfd5cdcb88689b23fe13998402099572d58f5f34;p=thirdparty%2Fstrongswan.git cert_cache_t caches subject-issuer relations and subject certificates ocsp/crl do not benefit yet due missing lookup function --- diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index bbfe221688..0c8650d44a 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -88,6 +88,7 @@ credentials/credential_manager.c credentials/credential_manager.h \ credentials/auth_info.c credentials/auth_info.h \ credentials/sets/auth_info_wrapper.c credentials/sets/auth_info_wrapper.h \ credentials/sets/ocsp_response_wrapper.c credentials/sets/ocsp_response_wrapper.h \ +credentials/sets/cert_cache.c credentials/sets/cert_cache.h \ credentials/credential_set.h # Use RAW socket if pluto gets built diff --git a/src/charon/credentials/credential_manager.c b/src/charon/credentials/credential_manager.c index a7e3d43b65..934100c202 100644 --- a/src/charon/credentials/credential_manager.c +++ b/src/charon/credentials/credential_manager.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,11 @@ struct private_credential_manager_t { */ linked_list_t *sets; + /** + * trust relationship and certificate cache + */ + cert_cache_t *cache; + /** * mutex to gain exclusive access */ @@ -356,7 +362,9 @@ static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url, auth = auth_info_create(); wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response); + this->sets->remove(this->sets, this->cache, NULL); this->sets->insert_first(this->sets, wrapper); + this->sets->insert_first(this->sets, this->cache); responder = response->get_issuer(response); DBG1(DBG_CFG, "ocsp signer is \"%D\"", responder); issuer_cert = get_trusted_cert(this, KEY_ANY, responder, auth, FALSE, FALSE); @@ -370,7 +378,7 @@ static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url, response->destroy(response); return NULL; } - if (response->issued_by(response, issuer_cert, TRUE)) + if (this->cache->issued_by(this->cache, response, issuer_cert)) { DBG1(DBG_CFG, "ocsp response correctly signed by \"%D\"", issuer_cert->get_subject(issuer_cert)); @@ -601,7 +609,7 @@ static certificate_t* fetch_crl(private_credential_manager_t *this, char *url) return NULL; } - if (crl_cert->issued_by(crl_cert, issuer_cert, TRUE)) + if (this->cache->issued_by(this->cache, crl_cert, issuer_cert)) { DBG1(DBG_CFG, "crl correctly signed by \"%D\"", issuer_cert->get_subject(issuer_cert)); @@ -892,7 +900,7 @@ static certificate_t *get_issuer_cert(private_credential_manager_t *this, subject->get_issuer(subject), trusted); while (enumerator->enumerate(enumerator, &candidate)) { - if (subject->issued_by(subject, candidate, TRUE)) + if (this->cache->issued_by(this->cache, subject, candidate)) { issuer = candidate->get_ref(candidate); break; @@ -1031,7 +1039,9 @@ static public_key_t *get_public(private_credential_manager_t *this, wrapper = auth_info_wrapper_create(auth); this->mutex->lock(this->mutex); + this->sets->remove(this->sets, this->cache, NULL); this->sets->insert_first(this->sets, wrapper); + this->sets->insert_first(this->sets, this->cache); cert = get_trusted_cert(this, type, id, auth, TRUE, TRUE); if (cert) @@ -1250,7 +1260,9 @@ static void remove_set(private_credential_manager_t *this, credential_set_t *set */ static void destroy(private_credential_manager_t *this) { + this->sets->remove(this->sets, this->cache, NULL); this->sets->destroy(this->sets); + this->cache->destroy(this->cache); this->mutex->destroy(this->mutex); free(this); } @@ -1274,6 +1286,8 @@ credential_manager_t *credential_manager_create() this->public.destroy = (void(*)(credential_manager_t*))destroy; this->sets = linked_list_create(); + this->cache = cert_cache_create(); + this->sets->insert_first(this->sets, this->cache); this->mutex = mutex_create(MUTEX_RECURSIVE); return &this->public; diff --git a/src/charon/credentials/sets/cert_cache.c b/src/charon/credentials/sets/cert_cache.c new file mode 100644 index 0000000000..17e6d357cb --- /dev/null +++ b/src/charon/credentials/sets/cert_cache.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "cert_cache.h" + +#include +#include + +#define CACHE_LIMIT 30 + +typedef struct private_cert_cache_t private_cert_cache_t; +typedef struct relation_t relation_t; + +/** + * private data of cert_cache + */ +struct private_cert_cache_t { + + /** + * public functions + */ + cert_cache_t public; + + /** + * list of trusted subject-issuer relations, as relation_t + */ + linked_list_t *relations; +}; + +/** + * A trusted relation between subject and issuer + */ +struct relation_t { + /** subject of this relation */ + certificate_t *subject; + /** issuer of this relation */ + certificate_t *issuer; + /** time of last use */ + time_t last_use; +}; + +/** + * destroy a relation_t structure + */ +static void relation_destroy(relation_t *this) +{ + this->subject->destroy(this->subject); + this->issuer->destroy(this->issuer); + free(this); +} + +/** + * Implementation of cert_cache_t.issued_by. + */ +static bool issued_by(private_cert_cache_t *this, + certificate_t *subject, certificate_t *issuer) +{ + relation_t *found = NULL, *current, *oldest = NULL; + enumerator_t *enumerator; + + /* lookup cache */ + enumerator = this->relations->create_enumerator(this->relations); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->subject == subject && current->issuer == issuer) + { + current->last_use = time(NULL); + found = current; + break; + } + if (oldest == NULL || oldest->last_use <= current->last_use) + { + oldest = current; + } + } + enumerator->destroy(enumerator); + if (found) + { + return TRUE; + } + /* no cache hit, check signature */ + if (!subject->issued_by(subject, issuer, TRUE)) + { + return FALSE; + } + /* cache if good, respect cache limit */ + found = malloc_thing(relation_t); + found->subject = subject->get_ref(subject); + found->issuer = issuer->get_ref(issuer); + found->last_use = time(NULL); + if (this->relations->get_count(this->relations) > CACHE_LIMIT && oldest) + { + this->relations->remove(this->relations, oldest, NULL); + relation_destroy(oldest); + } + this->relations->insert_last(this->relations, found); + return TRUE; +} + +/** + * data associated to a cert enumeration + */ +typedef struct { + /** type of requested certificate */ + certificate_type_t cert; + /** type of requested key */ + key_type_t key; + /** ID to get a cert from */ + identification_t *id; +} cert_data_t; + +/** + * filter function for certs enumerator + */ +static bool certs_filter(cert_data_t *data, relation_t **in, certificate_t **out) +{ + public_key_t *public; + certificate_t *cert; + + /* serve all subjects, but only if an ID is requestd (no listing) */ + cert = (*in)->subject; + if ((data->cert == CERT_ANY || cert->get_type(cert) == data->cert) && + data->id && cert->has_subject(cert, data->id)) + { + if (data->key == KEY_ANY) + { + *out = cert; + return TRUE; + } + public = cert->get_public_key(cert); + if (public) + { + if (public->get_type(public) == data->key) + { + public->destroy(public); + *out = cert; + return TRUE; + } + public->destroy(public); + } + } + return FALSE; +} + +/** + * implementation of credential_set_t.create_cert_enumerator + */ +static enumerator_t *create_enumerator(private_cert_cache_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + cert_data_t *data; + + if (trusted) + { + return NULL; + } + data = malloc_thing(cert_data_t); + data->cert = cert; + data->key = key; + data->id = id; + + return enumerator_create_filter( + this->relations->create_enumerator(this->relations), + (void*)certs_filter, data, (void*)free); +} + +/** + * Implementation of cert_cache_t.destroy + */ +static void destroy(private_cert_cache_t *this) +{ + this->relations->destroy_function(this->relations, (void*)relation_destroy); + free(this); +} + +/* + * see header file + */ +cert_cache_t *cert_cache_create() +{ + private_cert_cache_t *this = malloc_thing(private_cert_cache_t); + + this->public.set.create_private_enumerator = (void*)return_null; + this->public.set.create_cert_enumerator = (void*)create_enumerator; + this->public.set.create_shared_enumerator = (void*)return_null; + this->public.set.create_cdp_enumerator = (void*)return_null; + this->public.issued_by = (bool(*)(cert_cache_t*, certificate_t *subject, certificate_t *issuer))issued_by; + this->public.destroy = (void(*)(cert_cache_t*))destroy; + + this->relations = linked_list_create(); + + return &this->public; +} + diff --git a/src/charon/credentials/sets/cert_cache.h b/src/charon/credentials/sets/cert_cache.h new file mode 100644 index 0000000000..7e392ae87a --- /dev/null +++ b/src/charon/credentials/sets/cert_cache.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup cert_cache cert_cache + * @{ @ingroup sets + */ + +#ifndef CERT_CACHE_H_ +#define CERT_CACHE_H_ + +#include + +typedef struct cert_cache_t cert_cache_t; + +/** + * Certificate signature verification and certificate cache. + * + * This cache serves all certificates seen in its issued_by method + * and serves them as untrusted through the credential set interface. Further, + * it caches valid subject-issuer relationships to speed up the issued_by + * method. + */ +struct cert_cache_t { + + /** + * Implements credential_set_t. + */ + credential_set_t set; + + /** + * Caching wrapper around certificate_t.issued_by. + * + * @param subject certificate to verify + * @param issuer issuing certificate to verify subject + * @return TRUE if subject issued by issuer + */ + bool (*issued_by)(cert_cache_t *this, + certificate_t *subject, certificate_t *issuer); + + /** + * Destroy a cert_cache instance. + */ + void (*destroy)(cert_cache_t *this); +}; + +/** + * Create a cert_cache instance. + */ +cert_cache_t *cert_cache_create(); + +#endif /* CERT_CACHE_H_ @}*/