Cache trustchain lifetimes for export
authorMartin Willi <martin@revosec.ch>
Thu, 4 Aug 2011 13:09:55 +0000 (15:09 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 22 Aug 2011 16:42:33 +0000 (18:42 +0200)
src/libcharon/plugins/certexpire/Makefile.am
src/libcharon/plugins/certexpire/certexpire_export.c [new file with mode: 0644]
src/libcharon/plugins/certexpire/certexpire_export.h [new file with mode: 0644]
src/libcharon/plugins/certexpire/certexpire_listener.c
src/libcharon/plugins/certexpire/certexpire_listener.h
src/libcharon/plugins/certexpire/certexpire_plugin.c

index af20490..9aac708 100644 (file)
@@ -12,6 +12,7 @@ plugin_LTLIBRARIES = libstrongswan-certexpire.la
 endif
 
 libstrongswan_certexpire_la_SOURCES = certexpire_plugin.h certexpire_plugin.c \
-       certexpire_listener.h certexpire_listener.c
+       certexpire_listener.h certexpire_listener.c \
+       certexpire_export.h certexpire_export.c
 
 libstrongswan_certexpire_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/certexpire/certexpire_export.c b/src/libcharon/plugins/certexpire/certexpire_export.c
new file mode 100644 (file)
index 0000000..d9b4907
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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.
+ */
+
+#include "certexpire_export.h"
+
+#include <debug.h>
+#include <utils/hashtable.h>
+#include <threading/mutex.h>
+#include <credentials/certificates/x509.h>
+
+typedef struct private_certexpire_export_t private_certexpire_export_t;
+
+/**
+ * Private data of an certexpire_export_t object.
+ */
+struct private_certexpire_export_t {
+
+       /**
+        * Public certexpire_export_t interface.
+        */
+       certexpire_export_t public;
+
+       /**
+        * hashtable caching local trustchains, mapping entry_t => entry_t
+        */
+       hashtable_t *local;
+
+       /**
+        * hashtable caching remote trustchains, mapping entry_t => entry_t
+        */
+       hashtable_t *remote;
+
+       /**
+        * Mutex to lock hashtables
+        */
+       mutex_t *mutex;
+};
+
+/**
+ * Maximum number of expiration dates we store (for subject + IM CAs + CA)
+ */
+#define MAX_TRUSTCHAIN_LENGTH 7
+
+/**
+ * Hashtable entry
+ */
+typedef struct {
+       /** certificate subject as subjectAltName or CN of a DN */
+       char id[128];
+       /** list of expiration dates, 0 if no certificate */
+       time_t expire[MAX_TRUSTCHAIN_LENGTH];
+} entry_t;
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(entry_t *key)
+{
+       return chunk_hash(chunk_create(key->id, strlen(key->id)));
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(entry_t *a, entry_t *b)
+{
+       return streq(a->id, b->id);
+}
+
+METHOD(certexpire_export_t, add, void,
+       private_certexpire_export_t *this, linked_list_t *trustchain, bool local)
+{
+       enumerator_t *enumerator;
+       certificate_t *cert;
+       int count;
+
+       count = min(trustchain->get_count(trustchain), MAX_TRUSTCHAIN_LENGTH) - 1;
+
+       enumerator = trustchain->create_enumerator(trustchain);
+       /* get subject cert */
+       if (enumerator->enumerate(enumerator, &cert))
+       {
+               identification_t *id;
+               entry_t *entry;
+               int i;
+
+               INIT(entry);
+
+               /* prefer FQDN subjectAltName... */
+               if (cert->get_type(cert) == CERT_X509)
+               {
+                       x509_t *x509 = (x509_t*)cert;
+                       enumerator_t *sans;
+
+                       sans = x509->create_subjectAltName_enumerator(x509);
+                       while (sans->enumerate(sans, &id))
+                       {
+                               if (id->get_type(id) == ID_FQDN)
+                               {
+                                       snprintf(entry->id, sizeof(entry->id), "%Y", id);
+                                       break;
+                               }
+                       }
+                       sans->destroy(sans);
+               }
+               /* fallback to CN of DN */
+               if (!entry->id[0])
+               {
+                       enumerator_t *parts;
+                       id_part_t part;
+                       chunk_t data;
+
+                       id = cert->get_subject(cert);
+                       parts = id->create_part_enumerator(id);
+                       while (parts->enumerate(parts, &part, &data))
+                       {
+                               if (part == ID_PART_RDN_CN)
+                               {
+                                       snprintf(entry->id, sizeof(entry->id), "%.*s",
+                                                        (int)data.len, data.ptr);
+                                       break;
+                               }
+                       }
+                       parts->destroy(parts);
+               }
+               /* no usable identity? skip */
+               if (!entry->id[0])
+               {
+                       enumerator->destroy(enumerator);
+                       free(entry);
+                       return;
+               }
+
+               /* get intermediate CA expiration dates */
+               cert->get_validity(cert, NULL, NULL, &entry->expire[0]);
+               for (i = 1; i < count && enumerator->enumerate(enumerator, &cert); i++)
+               {
+                       cert->get_validity(cert, NULL, NULL, &entry->expire[i]);
+               }
+               /* get CA expiration date, as last array entry */
+               if (enumerator->enumerate(enumerator, &cert))
+               {
+                       cert->get_validity(cert, NULL, NULL,
+                                                          &entry->expire[MAX_TRUSTCHAIN_LENGTH - 1]);
+               }
+               this->mutex->lock(this->mutex);
+               if (local)
+               {
+                       entry = this->local->put(this->local, entry, entry);
+               }
+               else
+               {
+                       entry = this->remote->put(this->remote, entry, entry);
+               }
+               this->mutex->unlock(this->mutex);
+               if (entry)
+               {
+                       free(entry);
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+METHOD(certexpire_export_t, destroy, void,
+       private_certexpire_export_t *this)
+{
+       entry_t *key, *value;
+       enumerator_t *enumerator;
+
+       enumerator = this->local->create_enumerator(this->local);
+       while (enumerator->enumerate(enumerator, &key, &value))
+       {
+               free(value);
+       }
+       enumerator->destroy(enumerator);
+       enumerator = this->remote->create_enumerator(this->remote);
+       while (enumerator->enumerate(enumerator, &key, &value))
+       {
+               free(value);
+       }
+       enumerator->destroy(enumerator);
+
+       this->local->destroy(this->local);
+       this->remote->destroy(this->remote);
+       this->mutex->destroy(this->mutex);
+       free(this);
+}
+
+/**
+ * See header
+ */
+certexpire_export_t *certexpire_export_create()
+{
+       private_certexpire_export_t *this;
+
+       INIT(this,
+               .public = {
+                       .add = _add,
+                       .destroy = _destroy,
+               },
+               .local = hashtable_create((hashtable_hash_t)hash,
+                                                                 (hashtable_equals_t)equals, 4),
+               .remote = hashtable_create((hashtable_hash_t)hash,
+                                                                  (hashtable_equals_t)equals, 32),
+               .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/certexpire/certexpire_export.h b/src/libcharon/plugins/certexpire/certexpire_export.h
new file mode 100644 (file)
index 0000000..64281d0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup certexpire_export certexpire_export
+ * @{ @ingroup certexpire
+ */
+
+#ifndef CERTEXPIRE_EXPORT_H_
+#define CERTEXPIRE_EXPORT_H_
+
+typedef struct certexpire_export_t certexpire_export_t;
+
+#include <utils/linked_list.h>
+
+/**
+ * Caches and exports trustchain information to CSV files.
+ */
+struct certexpire_export_t {
+
+       /**
+        * Add trustchain to cache for export.
+        *
+        * @param trustchain            trustchain, sorted list of certificate_t
+        * @param local                         TRUE for own chain, FALSE for remote chain
+        */
+       void (*add)(certexpire_export_t *this, linked_list_t *trustchain, bool local);
+
+       /**
+        * Destroy a certexpire_export_t.
+        */
+       void (*destroy)(certexpire_export_t *this);
+};
+
+/**
+ * Create a certexpire_export instance.
+ */
+certexpire_export_t *certexpire_export_create();
+
+#endif /** CERTEXPIRE_EXPORT_H_ @}*/
index 67a9a65..4c9c6ff 100644 (file)
@@ -28,6 +28,11 @@ struct private_certexpire_listener_t {
         * Public certexpire_listener_t interface.
         */
        certexpire_listener_t public;
+
+       /**
+        * Export facility
+        */
+       certexpire_export_t *export;
 };
 
 METHOD(listener_t, authorize, bool,
@@ -80,7 +85,7 @@ METHOD(listener_t, authorize, bool,
                }
        }
        rounds->destroy(rounds);
-       /* TODO: handle trustchain expiry information */
+       this->export->add(this->export, trustchain, TRUE);
        trustchain->destroy(trustchain);
 
        /* collect remote certificates */
@@ -111,7 +116,7 @@ METHOD(listener_t, authorize, bool,
                }
        }
        rounds->destroy(rounds);
-       /* TODO: handle trustchain expiry information */
+       this->export->add(this->export, trustchain, FALSE);
        trustchain->destroy(trustchain);
        return TRUE;
 }
@@ -125,7 +130,7 @@ METHOD(certexpire_listener_t, destroy, void,
 /**
  * See header
  */
-certexpire_listener_t *certexpire_listener_create()
+certexpire_listener_t *certexpire_listener_create(certexpire_export_t *export)
 {
        private_certexpire_listener_t *this;
 
@@ -136,6 +141,7 @@ certexpire_listener_t *certexpire_listener_create()
                        },
                        .destroy = _destroy,
                },
+               .export = export,
        );
 
        return &this->public;
index 7187435..8601ff5 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <bus/listeners/listener.h>
 
+#include "certexpire_export.h"
+
 typedef struct certexpire_listener_t certexpire_listener_t;
 
 /**
@@ -43,7 +45,10 @@ struct certexpire_listener_t {
 
 /**
  * Create a certexpire_listener instance.
+ *
+ * @param export               facility exporting collected trustchains
+ * @return                             listener instance
  */
-certexpire_listener_t *certexpire_listener_create();
+certexpire_listener_t *certexpire_listener_create(certexpire_export_t *export);
 
 #endif /** CERTEXPIRE_LISTENER_H_ @}*/
index 795e8a1..2b4c0b6 100644 (file)
@@ -16,6 +16,7 @@
 #include "certexpire_plugin.h"
 
 #include "certexpire_listener.h"
+#include "certexpire_export.h"
 
 #include <daemon.h>
 
@@ -35,6 +36,11 @@ struct private_certexpire_plugin_t {
         * Listener collecting expire information
         */
        certexpire_listener_t *listener;
+
+       /**
+        * Cache and export trustchain expire information
+        */
+       certexpire_export_t *export;
 };
 
 METHOD(plugin_t, get_name, char*,
@@ -48,6 +54,7 @@ METHOD(plugin_t, destroy, void,
 {
        charon->bus->remove_listener(charon->bus, &this->listener->listener);
        this->listener->destroy(this->listener);
+       this->export->destroy(this->export);
        free(this);
 }
 
@@ -66,8 +73,9 @@ plugin_t *certexpire_plugin_create()
                                .destroy = _destroy,
                        },
                },
-               .listener = certexpire_listener_create(),
+               .export = certexpire_export_create(),
        );
+       this->listener = certexpire_listener_create(this->export),
        charon->bus->add_listener(charon->bus, &this->listener->listener);
 
        return &this->public.plugin;