added -avoid-version to LDFLAGS, plugins are not versioned
[strongswan.git] / src / charon / plugins / stroke / stroke_ca.c
index 30a270e..fab06e6 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -11,8 +12,6 @@
  * 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 "stroke_ca.h"
@@ -20,6 +19,7 @@
 
 #include <utils/mutex.h>
 #include <utils/linked_list.h>
+#include <crypto/hashers/hasher.h>
 
 #include <daemon.h>
 
@@ -36,9 +36,9 @@ struct private_stroke_ca_t {
        stroke_ca_t public;
        
        /**
-        * mutex to lock access to list
+        * read-write lock to lists
         */
-       mutex_t *mutex;
+       rwlock_t *lock;
        
        /**
         * list of starters CA sections and its certificates (ca_section_t)
@@ -77,6 +77,16 @@ struct ca_section_t {
         * OCSP URIs
         */
        linked_list_t *ocsp;
+       
+       /**
+        * Hashes of certificates issued by this CA
+        */
+       linked_list_t *hashes;
+       
+       /**
+        * Base URI used for certificates from this CA
+        */
+       char *certuribase;
 };
 
 /**
@@ -90,6 +100,8 @@ static ca_section_t *ca_section_create(char *name, certificate_t *cert)
        ca->crl = linked_list_create();
        ca->ocsp = linked_list_create();
        ca->cert = cert;
+       ca->hashes = linked_list_create();
+       ca->certuribase = NULL;
        return ca;
 }
 
@@ -100,6 +112,8 @@ static void ca_section_destroy(ca_section_t *this)
 {
        this->crl->destroy_function(this->crl, free);
        this->ocsp->destroy_function(this->ocsp, free);
+       this->hashes->destroy_offset(this->hashes, offsetof(identification_t, destroy));
+       free(this->certuribase);
        free(this->name);
        free(this);
 }
@@ -118,7 +132,7 @@ typedef struct {
  */
 static void cdp_data_destroy(cdp_data_t *data)
 {
-       data->this->mutex->unlock(data->this->mutex);
+       data->this->lock->unlock(data->this->lock);
        free(data);
 }
 
@@ -162,6 +176,40 @@ static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data)
 }
 
 /**
+ * inner enumerator constructor for "Hash and URL"
+ */
+static enumerator_t *create_inner_cdp_hashandurl(ca_section_t *section, cdp_data_t *data)
+{
+       enumerator_t *enumerator = NULL, *hash_enum;
+       identification_t *current;
+       
+       if (!data->id || !section->certuribase)
+       {
+               return NULL;
+       }
+       
+       hash_enum = section->hashes->create_enumerator(section->hashes);
+       while (hash_enum->enumerate(hash_enum, &current))
+       {       
+               if (current->matches(current, data->id))
+               {
+                       char *url, *hash;
+                       
+                       url = malloc(strlen(section->certuribase) + 40 + 1);
+                       strcpy(url, section->certuribase);
+                       hash = chunk_to_hex(current->get_encoding(current), NULL, FALSE).ptr;
+                       strncat(url, hash, 40);
+                       free(hash);
+                       
+                       enumerator = enumerator_create_single(url, free);
+                       break;
+               }
+       }
+       hash_enum->destroy(hash_enum);
+       return enumerator;
+}
+
+/**
  * Implementation of credential_set_t.create_cdp_enumerator.
  */
 static enumerator_t *create_cdp_enumerator(private_stroke_ca_t *this,
@@ -170,7 +218,8 @@ static enumerator_t *create_cdp_enumerator(private_stroke_ca_t *this,
        cdp_data_t *data;
 
        switch (type)
-       {       /* we serve CRLs and OCSP responders */
+       {       /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
+               case CERT_X509:
                case CERT_X509_CRL:
                case CERT_X509_OCSP_RESPONSE:
                case CERT_ANY:
@@ -183,10 +232,10 @@ static enumerator_t *create_cdp_enumerator(private_stroke_ca_t *this,
        data->type = type;
        data->id = id;
        
-       this->mutex->lock(this->mutex);
+       this->lock->read_lock(this->lock);
        return enumerator_create_nested(this->sections->create_enumerator(this->sections),
-                                                                       (void*)create_inner_cdp, data,
-                                                                       (void*)cdp_data_destroy);
+                       (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : (void*)create_inner_cdp,
+                       data, (void*)cdp_data_destroy);
 }
 /**
  * Implementation of stroke_ca_t.add.
@@ -221,9 +270,13 @@ static void add(private_stroke_ca_t *this, stroke_msg_t *msg)
                {
                        ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2));
                }
-               this->mutex->lock(this->mutex);
+               if (msg->add_ca.certuribase)
+               {
+                       ca->certuribase = strdup(msg->add_ca.certuribase);
+               }
+               this->lock->write_lock(this->lock);
                this->sections->insert_last(this->sections, ca);
-               this->mutex->unlock(this->mutex);
+               this->lock->unlock(this->lock);
                DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
        }
 }
@@ -236,7 +289,7 @@ static void del(private_stroke_ca_t *this, stroke_msg_t *msg)
        enumerator_t *enumerator;
        ca_section_t *ca = NULL;
        
-       this->mutex->lock(this->mutex);
+       this->lock->write_lock(this->lock);
        enumerator = this->sections->create_enumerator(this->sections);
        while (enumerator->enumerate(enumerator, &ca))
        {
@@ -248,7 +301,7 @@ static void del(private_stroke_ca_t *this, stroke_msg_t *msg)
                ca = NULL;
        }
        enumerator->destroy(enumerator);
-       this->mutex->unlock(this->mutex);
+       this->lock->unlock(this->lock);
        if (ca == NULL)
        {
                DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name);
@@ -285,6 +338,42 @@ static void list_uris(linked_list_t *list, char *label, FILE *out)
 }
 
 /**
+ * Implementation of stroke_ca_t.check_for_hash_and_url.
+ */
+static void check_for_hash_and_url(private_stroke_ca_t *this, certificate_t* cert)
+{
+       ca_section_t *section;
+       enumerator_t *enumerator;
+       
+       hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+       if (hasher == NULL)
+       {
+               DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported");
+               return;
+       }
+       
+       this->lock->write_lock(this->lock);
+       enumerator = this->sections->create_enumerator(this->sections);
+       while (enumerator->enumerate(enumerator, (void**)&section))
+       {
+               if (section->certuribase && cert->issued_by(cert, section->cert))
+               {
+                       chunk_t hash, encoded = cert->get_encoding(cert);
+                       hasher->allocate_hash(hasher, encoded, &hash);
+                       section->hashes->insert_last(section->hashes,
+                                       identification_create_from_encoding(ID_CERT_DER_SHA1, hash));
+                       chunk_free(&hash);
+                       chunk_free(&encoded);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       this->lock->unlock(this->lock);
+       
+       hasher->destroy(hasher);
+}
+
+/**
  * Implementation of stroke_ca_t.list.
  */
 static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
@@ -293,7 +382,7 @@ static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
        ca_section_t *section;
        enumerator_t *enumerator;
        
-       this->mutex->lock(this->mutex);
+       this->lock->read_lock(this->lock);
        enumerator = this->sections->create_enumerator(this->sections);
        while (enumerator->enumerate(enumerator, (void**)&section))
        {
@@ -307,22 +396,26 @@ static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
                        first = FALSE;
                }
                fprintf(out, "\n");
-               fprintf(out, "  authname: \"%D\"\n", cert->get_subject(cert));
+               fprintf(out, "  authname:    \"%Y\"\n", cert->get_subject(cert));
 
                /* list authkey and keyid */
                if (public)
                {
-                       fprintf(out, "  authkey:   %D\n",
+                       fprintf(out, "  authkey:      %Y\n",
                                        public->get_id(public, ID_PUBKEY_SHA1));
-                       fprintf(out, "  keyid:     %D\n",
+                       fprintf(out, "  keyid:        %Y\n",
                                        public->get_id(public, ID_PUBKEY_INFO_SHA1));
                        public->destroy(public);
                }
-               list_uris(section->crl, "  crluris:  ", out);
-               list_uris(section->ocsp, "  ocspuris: ", out);
+               list_uris(section->crl, "  crluris:     ", out);
+               list_uris(section->ocsp, "  ocspuris:    ", out);
+               if (section->certuribase)
+               {
+                       fprintf(out, "  certuribase: '%s'\n", section->certuribase);
+               }
        }
        enumerator->destroy(enumerator);
-       this->mutex->unlock(this->mutex);
+       this->lock->unlock(this->lock);
 }
 
 /**
@@ -331,7 +424,7 @@ static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
 static void destroy(private_stroke_ca_t *this)
 {
        this->sections->destroy_function(this->sections, (void*)ca_section_destroy);
-       this->mutex->destroy(this->mutex);
+       this->lock->destroy(this->lock);
        free(this);
 }
 
@@ -350,10 +443,11 @@ stroke_ca_t *stroke_ca_create(stroke_cred_t *cred)
        this->public.add = (void(*)(stroke_ca_t*, stroke_msg_t *msg))add;
        this->public.del = (void(*)(stroke_ca_t*, stroke_msg_t *msg))del;
        this->public.list = (void(*)(stroke_ca_t*, stroke_msg_t *msg, FILE *out))list;
+       this->public.check_for_hash_and_url = (void(*)(stroke_ca_t*, certificate_t*))check_for_hash_and_url;
        this->public.destroy = (void(*)(stroke_ca_t*))destroy;
        
        this->sections = linked_list_create();
-       this->mutex = mutex_create(MUTEX_RECURSIVE);
+       this->lock = rwlock_create(RWLOCK_DEFAULT);
        this->cred = cred;
        
        return &this->public;