cert_cache_t caches subject-issuer relations and subject certificates
authorMartin Willi <martin@strongswan.org>
Thu, 20 Mar 2008 14:31:36 +0000 (14:31 -0000)
committerMartin Willi <martin@strongswan.org>
Thu, 20 Mar 2008 14:31:36 +0000 (14:31 -0000)
ocsp/crl do not benefit yet due missing lookup function

src/charon/Makefile.am
src/charon/credentials/credential_manager.c
src/charon/credentials/sets/cert_cache.c [new file with mode: 0644]
src/charon/credentials/sets/cert_cache.h [new file with mode: 0644]

index bbfe221..0c8650d 100644 (file)
@@ -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
index a7e3d43..934100c 100644 (file)
@@ -20,6 +20,7 @@
 #include <daemon.h>
 #include <utils/linked_list.h>
 #include <utils/mutex.h>
+#include <credentials/sets/cert_cache.h>
 #include <credentials/sets/auth_info_wrapper.h>
 #include <credentials/sets/ocsp_response_wrapper.h>
 #include <credentials/certificates/x509.h>
@@ -47,6 +48,11 @@ struct private_credential_manager_t {
        linked_list_t *sets;
        
        /**
+        * trust relationship and certificate cache
+        */
+       cert_cache_t *cache;
+       
+       /**
         * mutex to gain exclusive access
         */
        mutex_t *mutex;
@@ -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 (file)
index 0000000..17e6d35
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 <daemon.h>
+#include <utils/linked_list.h>
+
+#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, &current))
+       {
+               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 (file)
index 0000000..7e392ae
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 <credentials/credential_set.h>
+
+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_ @}*/