support for hash and URL encoded certificate payloads in charon
authorTobias Brunner <tobias@strongswan.org>
Fri, 18 Apr 2008 11:24:45 +0000 (11:24 -0000)
committerTobias Brunner <tobias@strongswan.org>
Fri, 18 Apr 2008 11:24:45 +0000 (11:24 -0000)
23 files changed:
src/charon/credentials/auth_info.c
src/charon/credentials/auth_info.h
src/charon/credentials/sets/auth_info_wrapper.c
src/charon/encoding/payloads/cert_payload.c
src/charon/encoding/payloads/cert_payload.h
src/charon/plugins/stroke/stroke_ca.c
src/charon/plugins/stroke/stroke_ca.h
src/charon/plugins/stroke/stroke_config.c
src/charon/plugins/stroke/stroke_config.h
src/charon/plugins/stroke/stroke_socket.c
src/charon/sa/ike_sa.h
src/charon/sa/tasks/ike_cert_post.c
src/charon/sa/tasks/ike_cert_pre.c
src/libstrongswan/plugins/x509/x509_cert.c
src/libstrongswan/utils/identification.c
src/libstrongswan/utils/identification.h
src/starter/args.c
src/starter/confread.h
src/starter/ipsec.conf.5
src/starter/keywords.h
src/starter/keywords.txt
src/starter/starterstroke.c
src/stroke/stroke_msg.h

index 8839925..5d4a0f2 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2007 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -29,6 +30,8 @@ ENUM(auth_item_names, AUTHN_CA_CERT, AUTHZ_AC_GROUP,
        "AUTHN_CA_CERT_NAME",
        "AUTHN_IM_CERT",
        "AUTHN_SUBJECT_CERT",
+       "AUTHN_IM_HASH_URL",
+       "AUTHN_SUBJECT_HASH_URL",
        "AUTHZ_PUBKEY",
        "AUTHZ_PSK",
        "AUTHZ_EAP",
@@ -69,14 +72,38 @@ struct item_t {
 };
 
 /**
- * implements item_enumerator_t.enumerate
+ * enumerator for auth_info_wrapper_t.create_cert_enumerator()
  */
-static bool item_filter(void *data, item_t **item, auth_item_t *type,
-                                                                       void *unused, void **value)
+typedef struct {
+       /** implements enumerator_t */
+       enumerator_t public;
+       /** inner enumerator from linked_list_t */
+       enumerator_t *inner;
+       /** the current item */
+       item_t *item;
+} item_enumerator_t;
+
+/**
+ * enumerate function for item_enumerator_t
+ */
+static bool enumerate(item_enumerator_t *this, auth_item_t *type, void **value)
 {
-       *type = (*item)->type;
-       *value = (*item)->value;
-       return TRUE;
+       if (this->inner->enumerate(this->inner, &this->item))
+       {
+               *type = this->item->type;
+               *value = this->item->value;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * destroy function for item_enumerator_t
+ */
+static void item_enumerator_destroy(item_enumerator_t *this)
+{
+       this->inner->destroy(this->inner);
+       free(this);
 }
 
 /**
@@ -84,8 +111,26 @@ static bool item_filter(void *data, item_t **item, auth_item_t *type,
  */
 static enumerator_t* create_item_enumerator(private_auth_info_t *this)
 {
-       return enumerator_create_filter(this->items->create_enumerator(this->items),
-                                                                       (void*)item_filter, NULL, NULL);
+       item_enumerator_t *enumerator;
+       
+       enumerator = malloc_thing(item_enumerator_t);
+       enumerator->item = NULL;
+       enumerator->inner = this->items->create_enumerator(this->items);
+       enumerator->public.enumerate = (void*)enumerate;
+       enumerator->public.destroy = (void*)item_enumerator_destroy;
+       return &enumerator->public;
+}
+
+static void destroy_item_value(item_t *item);
+
+/**
+ * Implementation of auth_info_t.replace_item.
+ */
+static void replace_item(item_enumerator_t *enumerator, auth_item_t type, void *value)
+{
+       destroy_item_value(enumerator->item);
+       enumerator->item->type = type;
+       enumerator->item->value = value;
 }
 
 /**
@@ -136,6 +181,12 @@ static void add_item(private_auth_info_t *this, auth_item_t type, void *value)
                        item->value = key->get_ref(key);
                        break;
                }
+               case AUTHN_IM_HASH_URL:
+               case AUTHN_SUBJECT_HASH_URL:
+               {
+                       item->value = strdup(value);
+                       break;
+               }
                case AUTHN_CA_CERT:
                case AUTHN_IM_CERT:
                case AUTHN_SUBJECT_CERT:
@@ -200,6 +251,8 @@ static bool complies(private_auth_info_t *this, auth_info_t *constraints)
                        case AUTHN_CA_CERT_NAME:
                        case AUTHN_IM_CERT:
                        case AUTHN_SUBJECT_CERT:
+                       case AUTHN_IM_HASH_URL:
+                       case AUTHN_SUBJECT_HASH_URL:
                        {       /* skip non-authorization tokens */
                                continue;
                        }
@@ -362,6 +415,16 @@ static bool equals(private_auth_info_t *this, private_auth_info_t *other)
                                                }
                                                continue;
                                        }
+                                       case AUTHN_IM_HASH_URL:
+                                       case AUTHN_SUBJECT_HASH_URL:
+                                       {
+                                               if (streq(i1->value, i2->value))
+                                               {
+                                                       found = TRUE;
+                                                       break;
+                                               }
+                                               continue;
+                                       }
                                        case AUTHN_CA_CERT:
                                        case AUTHN_IM_CERT:
                                        case AUTHN_SUBJECT_CERT:
@@ -419,6 +482,57 @@ static bool equals(private_auth_info_t *this, private_auth_info_t *other)
 }
 
 /**
+ * Destroy the value associated with an item
+ */
+static void destroy_item_value(item_t *item)
+{
+       switch (item->type)
+       {
+               case AUTHZ_PUBKEY:
+               {
+                       public_key_t *key = (public_key_t*)item->value;
+                       key->destroy(key);
+                       break;
+               }
+               case AUTHZ_PSK:
+               {
+                       shared_key_t *key = (shared_key_t*)item->value;
+                       key->destroy(key);
+                       break;
+               }
+               case AUTHN_CA_CERT:
+               case AUTHN_IM_CERT:
+               case AUTHN_SUBJECT_CERT:
+               case AUTHZ_CA_CERT:
+               case AUTHZ_IM_CERT:
+               case AUTHZ_SUBJECT_CERT:
+               {
+                       certificate_t *cert = (certificate_t*)item->value;
+                       cert->destroy(cert);
+                       break;
+               }
+               case AUTHN_IM_HASH_URL:
+               case AUTHN_SUBJECT_HASH_URL:
+               case AUTHZ_CRL_VALIDATION:
+               case AUTHZ_OCSP_VALIDATION:
+               case AUTHZ_EAP:
+               {
+                       free(item->value);
+                       break;
+               }
+               case AUTHN_CA_CERT_KEYID:
+               case AUTHN_CA_CERT_NAME:
+               case AUTHZ_CA_CERT_NAME:
+               case AUTHZ_AC_GROUP:
+               {
+                       identification_t *id = (identification_t*)item->value;
+                       id->destroy(id);
+                       break;
+               }
+       }
+}
+
+/**
  * Implementation of auth_info_t.destroy
  */
 static void destroy(private_auth_info_t *this)
@@ -427,48 +541,7 @@ static void destroy(private_auth_info_t *this)
        
        while (this->items->remove_last(this->items, (void**)&item) == SUCCESS)
        {
-               switch (item->type)
-               {
-                       case AUTHZ_PUBKEY:
-                       {
-                               public_key_t *key = (public_key_t*)item->value;
-                               key->destroy(key);
-                               break;
-                       }
-                       case AUTHZ_PSK:
-                       {
-                               shared_key_t *key = (shared_key_t*)item->value;
-                               key->destroy(key);
-                               break;
-                       }
-                       case AUTHN_CA_CERT:
-                       case AUTHN_IM_CERT:
-                       case AUTHN_SUBJECT_CERT:
-                       case AUTHZ_CA_CERT:
-                       case AUTHZ_IM_CERT:
-                       case AUTHZ_SUBJECT_CERT:
-                       {
-                               certificate_t *cert = (certificate_t*)item->value;
-                               cert->destroy(cert);
-                               break;
-                       }
-                       case AUTHZ_CRL_VALIDATION:
-                       case AUTHZ_OCSP_VALIDATION:
-                       case AUTHZ_EAP:
-                       {
-                               free(item->value);
-                               break;
-                       }
-                       case AUTHN_CA_CERT_KEYID:
-                       case AUTHN_CA_CERT_NAME:
-                       case AUTHZ_CA_CERT_NAME:
-                       case AUTHZ_AC_GROUP:
-                       {
-                               identification_t *id = (identification_t*)item->value;
-                               id->destroy(id);
-                               break;
-                       }
-               }
+               destroy_item_value(item);
                free(item);
        }
        this->items->destroy(this->items);
@@ -484,6 +557,7 @@ auth_info_t *auth_info_create()
        
        this->public.add_item = (void(*)(auth_info_t*, auth_item_t type, void *value))add_item;
        this->public.get_item = (bool(*)(auth_info_t*, auth_item_t type, void **value))get_item;
+       this->public.replace_item = (void(*)(enumerator_t*,auth_item_t,void*))replace_item;
        this->public.create_item_enumerator = (enumerator_t*(*)(auth_info_t*))create_item_enumerator;
        this->public.complies = (bool(*)(auth_info_t*, auth_info_t *))complies;
        this->public.merge = (void(*)(auth_info_t*, auth_info_t *other))merge;
index 5a4ecf9..5fe2919 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2007 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -69,6 +70,10 @@ enum auth_item_t {
        AUTHN_IM_CERT,
        /** certificate for trustchain verification, value is certificate_t* */
        AUTHN_SUBJECT_CERT,
+       /** intermediate certificate supplied as hash and url */
+       AUTHN_IM_HASH_URL,
+       /** end-entity certificate supplied as hash and url */
+       AUTHN_SUBJECT_HASH_URL,
        
        /*
         * item provided to authorization process
@@ -127,6 +132,14 @@ struct auth_info_t {
        bool (*get_item)(auth_info_t *this, auth_item_t type, void **value);
        
        /**
+        * Replace an item.
+        * 
+        * @param type          new auth_info type
+        * @param value         pointer to the new value
+        */
+       void (*replace_item)(enumerator_t *this, auth_item_t type, void *value);
+       
+       /**
         * Create an enumerator over all items.
         *
         * @return                      enumerator over (auth_item_t type, void *value)
index b7576a5..cdbe2bc 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -15,6 +16,8 @@
  * $Id$
  */
 
+#include <daemon.h>
+
 #include "auth_info_wrapper.h"
 
 typedef struct private_auth_info_wrapper_t private_auth_info_wrapper_t;
@@ -43,6 +46,8 @@ typedef struct {
        enumerator_t public;
        /** inner enumerator from auth_info */
        enumerator_t *inner;
+       /** wrapped auth info */
+       auth_info_t *auth;
        /** enumerated cert type */
        certificate_type_t cert;
        /** enumerated key type */
@@ -52,6 +57,52 @@ typedef struct {
 } wrapper_enumerator_t;
 
 /**
+ * Tries to fetch a certificate that was supplied as hash and URL (replaces the
+ * item's type and value in place).
+ */
+static bool fetch_cert(wrapper_enumerator_t *enumerator, auth_item_t *type, void **value)
+{
+       char *url = (char*)*value;
+       if (!url)
+       {
+               /* fetching the certificate previously failed */
+               return FALSE;
+       }
+       
+       chunk_t data;
+       certificate_t *cert;
+       
+       DBG1(DBG_CFG, "fetching certificate from '%s' ...", url);
+       if (lib->fetcher->fetch(lib->fetcher, url, &data) != SUCCESS)
+       {
+               DBG1(DBG_CFG, "fetching certificate from '%s' failed", url);
+               /* we set the item to NULL, so we can skip it */
+               enumerator->auth->replace_item(enumerator->inner, *type, NULL);
+               return FALSE;
+       }
+       
+       cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+                                         BUILD_BLOB_ASN1_DER, data, BUILD_END);
+       
+       if (!cert)
+       {
+               DBG1(DBG_CFG, "parsing fetched certificate failed");
+               /* we set the item to NULL, so we can skip it */
+               enumerator->auth->replace_item(enumerator->inner, *type, NULL);
+               return FALSE;
+       }
+       
+       DBG1(DBG_CFG, "fetched certificate \"%D\"", cert->get_subject(cert));
+       charon->credentials->cache_cert(charon->credentials, cert);
+       
+       *type = (*type == AUTHN_IM_HASH_URL) ? AUTHN_IM_CERT : AUTHN_SUBJECT_CERT;
+       *value = cert;
+       enumerator->auth->replace_item(enumerator->inner, *type, cert);
+       
+       return TRUE;
+}
+
+/**
  * enumerate function for wrapper_enumerator_t
  */
 static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
@@ -62,8 +113,16 @@ static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
 
        while (this->inner->enumerate(this->inner, &type, &current))
        {
-               if (type != AUTHN_SUBJECT_CERT && 
-                       type != AUTHN_IM_CERT)
+               if (type == AUTHN_IM_HASH_URL ||
+                       type == AUTHN_SUBJECT_HASH_URL)
+               {
+                       if (!fetch_cert(this, &type, (void**)&current))
+                       {
+                               continue;
+                       }
+               }
+               else if (type != AUTHN_SUBJECT_CERT && 
+                                type != AUTHN_IM_CERT)
                {
                        continue;
                }
@@ -117,6 +176,7 @@ static enumerator_t *create_enumerator(private_auth_info_wrapper_t *this,
                return NULL;
        }
        enumerator = malloc_thing(wrapper_enumerator_t);
+       enumerator->auth = this->auth;
        enumerator->cert = cert;
        enumerator->key = key;
        enumerator->id = id;
index e641cfb..c482b7a 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -17,6 +18,7 @@
  */
 
 #include <stddef.h>
+#include <ctype.h>
 
 #include <daemon.h>
 
@@ -75,6 +77,11 @@ struct private_cert_payload_t {
         * The contained cert data value.
         */
        chunk_t data;
+       
+       /**
+        * TRUE if the hash and URL data is invalid
+        */
+       bool invalid_hash_and_url;
 };
 
 /**
@@ -123,6 +130,42 @@ encoding_rule_t cert_payload_encodings[] = {
  */
 static status_t verify(private_cert_payload_t *this)
 {
+       if (this->encoding == ENC_X509_HASH_AND_URL ||
+               this->encoding == ENC_X509_HASH_AND_URL_BUNDLE)
+       {
+               /* rough verification of hash and URL encoded certificates */
+               if (this->data.len <= 20)
+               {
+                       DBG1(DBG_ENC, "invalid payload length for hash and URL (%d), ignore",
+                                       this->data.len);
+                       this->invalid_hash_and_url = TRUE;
+                       return SUCCESS;
+               }
+               
+               int i = 20; /* skipping the hash */
+               for (; i < this->data.len; ++i)
+               {
+                       if (this->data.ptr[i] == '\0')
+                       {
+                               /* null terminated, fine */
+                               return SUCCESS;
+                       }
+                       else if (!isprint(this->data.ptr[i]))
+                       {
+                               DBG1(DBG_ENC, "non printable characters in URL of hash and URL"
+                                               " encoded certificate payload, ignore");
+                               this->invalid_hash_and_url = TRUE;
+                               return SUCCESS;
+                       }
+               }
+               
+               /* URL is not null terminated, correct that */
+               chunk_t data = chunk_alloc(this->data.len + 1);
+               memcpy(data.ptr, this->data.ptr, this->data.len);
+               data.ptr[this->data.len] = '\0';
+               chunk_free(&this->data);
+               this->data = data;
+       }
        return SUCCESS;
 }
 
@@ -169,40 +212,59 @@ static size_t get_length(private_cert_payload_t *this)
 }
 
 /**
+ * Implementation of cert_payload_t.get_cert_encoding.
+ */
+static cert_encoding_t get_cert_encoding(private_cert_payload_t *this)
+{
+       return this->encoding;
+}
+
+/**
  * Implementation of cert_payload_t.get_cert.
  */
-static certificate_tget_cert(private_cert_payload_t *this)
+static certificate_t *get_cert(private_cert_payload_t *this)
 {
-       certificate_type_t type;
-       
-       switch (this->encoding)
+       if (this->encoding != ENC_X509_SIGNATURE)
        {
-               case ENC_X509_SIGNATURE:
-                       type = CERT_X509;
-                       break;
-               case ENC_PKCS7_WRAPPED_X509:
-               case ENC_PGP:
-               case ENC_DNS_SIGNED_KEY:
-               case ENC_KERBEROS_TOKEN:
-               case ENC_CRL:
-               case ENC_ARL:
-               case ENC_SPKI:
-               case ENC_X509_ATTRIBUTE:
-               case ENC_RAW_RSA_KEY:
-               case ENC_X509_HASH_AND_URL:
-               case ENC_X509_HASH_AND_URL_BUNDLE:
-               case ENC_OCSP_CONTENT:
-               default:
-                       DBG1(DBG_ENC, "certificate encoding %N not supported",
-                                cert_encoding_names, this->encoding);
-                       return NULL;
+               return NULL;
        }
-       return lib->creds->create(lib->creds, CRED_CERTIFICATE, type,
+       return lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                                                          BUILD_BLOB_ASN1_DER, chunk_clone(this->data),
                                                          BUILD_END);
 }
 
 /**
+ * Implementation of cert_payload_t.get_hash.
+ */
+static chunk_t get_hash(private_cert_payload_t *this)
+{
+       chunk_t hash = chunk_empty;
+       if ((this->encoding != ENC_X509_HASH_AND_URL &&
+               this->encoding != ENC_X509_HASH_AND_URL_BUNDLE) ||
+               this->invalid_hash_and_url)
+       {
+               return hash;
+       }
+       hash.ptr = this->data.ptr;
+       hash.len = 20;
+       return hash;
+}
+
+/**
+ * Implementation of cert_payload_t.get_url.
+ */
+static char *get_url(private_cert_payload_t *this)
+{
+       if ((this->encoding != ENC_X509_HASH_AND_URL &&
+               this->encoding != ENC_X509_HASH_AND_URL_BUNDLE) ||
+               this->invalid_hash_and_url)
+       {
+               return NULL;
+       }
+       return (char*)this->data.ptr + 20;
+}
+
+/**
  * Implementation of payload_t.destroy and cert_payload_t.destroy.
  */
 static void destroy(private_cert_payload_t *this)
@@ -228,12 +290,16 @@ cert_payload_t *cert_payload_create()
        
        this->public.destroy = (void (*) (cert_payload_t*))destroy;
        this->public.get_cert = (certificate_t* (*) (cert_payload_t*))get_cert;
+       this->public.get_cert_encoding = (cert_encoding_t (*) (cert_payload_t*))get_cert_encoding;
+       this->public.get_hash = (chunk_t (*) (cert_payload_t*))get_hash;
+       this->public.get_url = (char* (*) (cert_payload_t*))get_url;
        
        this->critical = FALSE;
        this->next_payload = NO_PAYLOAD;
        this->payload_length = CERT_PAYLOAD_HEADER_LENGTH;
        this->data = chunk_empty;
        this->encoding = 0;
+       this->invalid_hash_and_url = FALSE;
 
        return &this->public;
 }
@@ -261,3 +327,21 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert)
        return &this->public;
 }
 
+/*
+ * Described in header
+ */
+cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url)
+{
+       private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create();
+       chunk_t url_chunk;
+       
+       this->encoding = ENC_X509_HASH_AND_URL;
+       
+       url_chunk.ptr = url;
+       url_chunk.len = strlen(url) + 1;
+       
+       this->data = chunk_cat("cc", hash, url_chunk);
+       this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len;
+       return &this->public;
+}
+
index 6b8228b..5a084cd 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -80,6 +81,32 @@ struct cert_payload_t {
        certificate_t *(*get_cert)(cert_payload_t *this);
        
        /**
+        * Get the encoding of the certificate.
+        * 
+        * @return                              encoding
+        */
+       cert_encoding_t (*get_cert_encoding)(cert_payload_t *this);
+       
+       /**
+        * Get the hash if this is a hash and URL encoded certificate.
+        * 
+        * This function returns internal data, do not free.
+        * 
+        * @return                              hash
+        */
+       chunk_t (*get_hash)(cert_payload_t *this);
+       
+       /**
+        * Get the URL if this is a hash and URL encoded certificate.
+        * 
+        * This function returns internal data, do not free.
+        * 
+        * @return                              url
+        */
+       char *(*get_url)(cert_payload_t *this);
+       
+       
+       /**
         * Destroys the cert_payload object.
         */
        void (*destroy) (cert_payload_t *this);
@@ -101,4 +128,13 @@ cert_payload_t *cert_payload_create(void);
  */
 cert_payload_t *cert_payload_create_from_cert(certificate_t *cert);
 
+/**
+ * Creates a certificate payload with hash and URL encoding of a certificate.
+ * 
+ * @param hash                         hash of the DER encoded certificate (get's cloned)
+ * @param url                          the URL to locate the certificate (get's cloned)
+ * @return                                     cert_payload_t object
+ */
+cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url);
+
 #endif /* CERT_PAYLOAD_H_ @} */
index 30a270e..ba969b9 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -20,6 +21,7 @@
 
 #include <utils/mutex.h>
 #include <utils/linked_list.h>
+#include <crypto/hashers/hasher.h>
 
 #include <daemon.h>
 
@@ -77,6 +79,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 +102,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 +114,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);
 }
@@ -162,6 +178,39 @@ 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))
+               {
+                       chunk_t hash = current->get_encoding(current);
+                       char *hash_str = chunk_to_hex(hash, FALSE);
+                       char *url = malloc(strlen(section->certuribase) + 40 + 1);
+                       strcpy(url, section->certuribase);
+                       strncat(url, hash_str, 40);
+                       free(hash_str);
+                       
+                       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 +219,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:
@@ -185,8 +235,8 @@ static enumerator_t *create_cdp_enumerator(private_stroke_ca_t *this,
        
        this->mutex->lock(this->mutex);
        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,6 +271,10 @@ static void add(private_stroke_ca_t *this, stroke_msg_t *msg)
                {
                        ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2));
                }
+               if (msg->add_ca.certuribase)
+               {
+                       ca->certuribase = strdup(msg->add_ca.certuribase);
+               }
                this->mutex->lock(this->mutex);
                this->sections->insert_last(this->sections, ca);
                this->mutex->unlock(this->mutex);
@@ -285,6 +339,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->mutex->lock(this->mutex);
+       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->mutex->unlock(this->mutex);
+       
+       hasher->destroy(hasher);
+}
+
+/**
  * Implementation of stroke_ca_t.list.
  */
 static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
@@ -307,19 +397,20 @@ 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:   \"%D\"\n", cert->get_subject(cert));
 
                /* list authkey and keyid */
                if (public)
                {
-                       fprintf(out, "  authkey:   %D\n",
+                       fprintf(out, "  authkey:     %D\n",
                                        public->get_id(public, ID_PUBKEY_SHA1));
-                       fprintf(out, "  keyid:     %D\n",
+                       fprintf(out, "  keyid:       %D\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);
+               fprintf(out, "  certuribase: '%s'\n", section->certuribase);
        }
        enumerator->destroy(enumerator);
        this->mutex->unlock(this->mutex);
@@ -350,6 +441,7 @@ 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();
index 5633196..882446a 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -61,6 +62,13 @@ struct stroke_ca_t {
        void (*list)(stroke_ca_t *this, stroke_msg_t *msg, FILE *out);
        
        /**
+        * Check if a certificate can be made available through hash and URL.
+        * 
+        * @param cert          peer certificate
+        */
+       void (*check_for_hash_and_url)(stroke_ca_t *this, certificate_t* cert);
+       
+       /**
      * Destroy a stroke_ca instance.
      */
     void (*destroy)(stroke_ca_t *this);
index 622fa33..931dc9c 100644 (file)
@@ -43,6 +43,11 @@ struct private_stroke_config_t {
        mutex_t *mutex;
        
        /**
+        * ca sections
+        */
+       stroke_ca_t *ca;
+       
+       /**
         * credentials
         */
        stroke_cred_t *cred;
@@ -435,6 +440,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
                cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert);
                if (cert)
                {
+                       this->ca->check_for_hash_and_url(this->ca, cert);
                        me = update_peerid(cert, me);
                        cert->destroy(cert);
                }
@@ -805,7 +811,7 @@ static void destroy(private_stroke_config_t *this)
 /*
  * see header file
  */
-stroke_config_t *stroke_config_create(stroke_cred_t *cred)
+stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
 {
        private_stroke_config_t *this = malloc_thing(private_stroke_config_t);
        
@@ -818,6 +824,7 @@ stroke_config_t *stroke_config_create(stroke_cred_t *cred)
        
        this->list = linked_list_create();
        this->mutex = mutex_create(MUTEX_RECURSIVE);
+       this->ca = ca;
        this->cred = cred;
        
        return &this->public;
index 478fa38..22b493c 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <config/backend.h>
 #include <stroke_msg.h>
+#include "stroke_ca.h"
 #include "stroke_cred.h"
 
 typedef struct stroke_config_t stroke_config_t;
@@ -62,6 +63,6 @@ struct stroke_config_t {
 /**
  * Create a stroke_config instance.
  */
-stroke_config_t *stroke_config_create(stroke_cred_t *cred);
+stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred);
 
 #endif /* STROKE_CONFIG_H_ @}*/
index 03bc470..53148b9 100644 (file)
@@ -250,13 +250,15 @@ static void stroke_add_ca(private_stroke_socket_t *this,
        pop_string(msg, &msg->add_ca.crluri2);
        pop_string(msg, &msg->add_ca.ocspuri);
        pop_string(msg, &msg->add_ca.ocspuri2);
+       pop_string(msg, &msg->add_ca.certuribase);
 
-       DBG2(DBG_CFG, "ca %s",        msg->add_ca.name);
-       DBG2(DBG_CFG, "  cacert=%s",  msg->add_ca.cacert);
-       DBG2(DBG_CFG, "  crluri=%s",  msg->add_ca.crluri);
-       DBG2(DBG_CFG, "  crluri2=%s", msg->add_ca.crluri2);
-       DBG2(DBG_CFG, "  ocspuri=%s", msg->add_ca.ocspuri);
-       DBG2(DBG_CFG, "  ocspuri2=%s", msg->add_ca.ocspuri2);
+       DBG2(DBG_CFG, "ca %s",            msg->add_ca.name);
+       DBG2(DBG_CFG, "  cacert=%s",      msg->add_ca.cacert);
+       DBG2(DBG_CFG, "  crluri=%s",      msg->add_ca.crluri);
+       DBG2(DBG_CFG, "  crluri2=%s",     msg->add_ca.crluri2);
+       DBG2(DBG_CFG, "  ocspuri=%s",     msg->add_ca.ocspuri);
+       DBG2(DBG_CFG, "  ocspuri2=%s",    msg->add_ca.ocspuri2);
+       DBG2(DBG_CFG, "  certuribase=%s", msg->add_ca.certuribase);
        
        DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
        
@@ -588,7 +590,7 @@ stroke_socket_t *stroke_socket_create()
        this->cred = stroke_cred_create();
        this->attribute = stroke_attribute_create();
        this->ca = stroke_ca_create(this->cred);
-       this->config = stroke_config_create(this->cred);
+       this->config = stroke_config_create(this->ca, this->cred);
        this->control = stroke_control_create();
        this->list = stroke_list_create();
        
index 60e499d..4f760b5 100644 (file)
@@ -79,6 +79,11 @@ enum ike_extension_t {
         * peer supports MOBIKE (RFC4555)
         */
        EXT_MOBIKE = (1<<1),
+       
+       /**
+        * peer supports HTTP cert lookups as specified in RFC4306
+        */
+       EXT_HASH_AND_URL = (1<<2),
 };
 
 /**
index 3ec4cec..2532f2d 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2006-2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -48,6 +49,55 @@ struct private_ike_cert_post_t {
 };
 
 /**
+ * Generates the cert payload, if possible with hash and url
+ */
+static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, certificate_t *cert)
+{
+       cert_payload_t *payload = NULL;
+       
+       if (this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL))
+       {
+               /* ok, our peer sent us a HTTP_CERT_LOOKUP_SUPPORTED Notify */
+               hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+               if (hasher != NULL)
+               {       
+                       chunk_t hash, encoded = cert->get_encoding(cert);
+                       enumerator_t *enumerator;
+                       char *url;
+                       
+                       hasher->allocate_hash(hasher, encoded, &hash);
+                       identification_t *id = identification_create_from_encoding(ID_CERT_DER_SHA1, hash);
+                       
+                       enumerator = charon->credentials->create_cdp_enumerator(charon->credentials, CERT_X509, id);
+                       if (enumerator->enumerate(enumerator, &url))
+                       {
+                               /* if we have an URL available we send that to our peer */
+                               payload = cert_payload_create_from_hash_and_url(hash, url);
+                       }
+                       enumerator->destroy(enumerator);
+                       
+                       id->destroy(id);
+                       chunk_free(&hash);
+                       chunk_free(&encoded);
+                       hasher->destroy(hasher);
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "unable to use hash and URL, SHA1 not supported");
+               }
+       }
+       
+       if (!payload)
+       {
+               /* our peer does not support hash and URL or we do not have an URL
+                * to send to our peer, just create a normal cert payload */
+               payload = cert_payload_create_from_cert(cert);
+       }
+       
+       return payload;
+}
+
+/**
  * add certificates to message
  */
 static void build_certs(private_ike_cert_post_t *this, message_t *message)
@@ -81,7 +131,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message)
                                {
                                        break;
                                }
-                               payload = cert_payload_create_from_cert(cert);
+                               payload = build_cert_payload(this, cert);
                                if (!payload)
                                {
                                        break;
index 34a5792..26ddb6e 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2008 Tobias Brunner
  * Copyright (C) 2006-2007 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -45,6 +46,11 @@ struct private_ike_cert_pre_t {
         * Are we the initiator?
         */
        bool initiator;
+       
+       /**
+        * Did we send a HTTP_CERT_LOOKUP_SUPPORTED Notify?
+        */
+       bool http_cert_lookup_supported_sent;
 };
 
 /**
@@ -62,53 +68,109 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
        iterator = message->get_payload_iterator(message);
        while (iterator->iterate(iterator, (void**)&payload))
        {
-               if (payload->get_type(payload) == CERTIFICATE_REQUEST)
+               switch(payload->get_type(payload))
                {
-                       certreq_payload_t *certreq = (certreq_payload_t*)payload;
-                       chunk_t keyid;
-                       enumerator_t *enumerator;
-                       
-                       this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
-                       
-                       if (certreq->get_cert_type(certreq) != CERT_X509)
+                       case CERTIFICATE_REQUEST:
                        {
-                               DBG1(DBG_IKE, "cert payload %N not supported - ignored",
-                                        certificate_type_names, certreq->get_cert_type(certreq));
-                               continue;
-                       }
-                       enumerator = certreq->create_keyid_enumerator(certreq);
-                       while (enumerator->enumerate(enumerator, &keyid))
-                       {
-                               identification_t *id;
-                               certificate_t *cert;
+                               certreq_payload_t *certreq = (certreq_payload_t*)payload;
+                               chunk_t keyid;
+                               enumerator_t *enumerator;
+                               
+                               this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
                                
-                               id = identification_create_from_encoding(
-                                                                               ID_PUBKEY_INFO_SHA1, keyid);
-                               cert = charon->credentials->get_cert(charon->credentials, 
-                                                                               CERT_X509, KEY_ANY, id, TRUE);
-                               if (cert)
+                               if (certreq->get_cert_type(certreq) != CERT_X509)
                                {
-                                       DBG1(DBG_IKE, "received cert request for \"%D\"",
-                                                cert->get_subject(cert));
-                                       auth->add_item(auth, AUTHN_CA_CERT, cert);
-                                       cert->destroy(cert);
-                                       ca_found = TRUE;
+                                       DBG1(DBG_IKE, "cert payload %N not supported - ignored",
+                                                certificate_type_names, certreq->get_cert_type(certreq));
+                                       break;
                                }
-                               else
+                               enumerator = certreq->create_keyid_enumerator(certreq);
+                               while (enumerator->enumerate(enumerator, &keyid))
+                               {
+                                       identification_t *id;
+                                       certificate_t *cert;
+                                       
+                                       id = identification_create_from_encoding(
+                                                                                       ID_PUBKEY_INFO_SHA1, keyid);
+                                       cert = charon->credentials->get_cert(charon->credentials, 
+                                                                                       CERT_X509, KEY_ANY, id, TRUE);
+                                       if (cert)
+                                       {
+                                               DBG1(DBG_IKE, "received cert request for \"%D\"",
+                                                        cert->get_subject(cert));
+                                               auth->add_item(auth, AUTHN_CA_CERT, cert);
+                                               cert->destroy(cert);
+                                               ca_found = TRUE;
+                                       }
+                                       else
+                                       {
+                                               DBG1(DBG_IKE, "received cert request for unknown ca "
+                                                                         "with keyid %D", id);
+                                               auth->add_item(auth, AUTHN_CA_CERT_KEYID, id);
+                                       }
+                                       id->destroy(id);
+                               }
+                               enumerator->destroy(enumerator);
+                               break;
+                       }
+                       case NOTIFY:
+                       {
+                               notify_payload_t *notify = (notify_payload_t*)payload;
+                               
+                               /* we only handle one type of notify here */
+                               if (notify->get_notify_type(notify) == HTTP_CERT_LOOKUP_SUPPORTED)
                                {
-                                       DBG1(DBG_IKE, "received cert request for unknown ca "
-                                                                 "with keyid %D", id);
-                                       auth->add_item(auth, AUTHN_CA_CERT_KEYID, id);
+                                       this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL);
                                }
-                               id->destroy(id);
+                               break;
                        }
-                       enumerator->destroy(enumerator);
+                       default:
+                               /* ignore other payloads here, these are handled elsewhere */
+                               break;
                }
        }
        iterator->destroy(iterator);
 }
 
 /**
+ * tries to extract a certificate from the cert payload or the credential
+ * manager (based on the hash of a hash and URL encoded cert).
+ * Note: the returned certificate (if any) has to be destroyed
+ */ 
+static certificate_t *try_get_cert(cert_payload_t *cert_payload)
+{
+       certificate_t *cert = NULL;
+       switch (cert_payload->get_cert_encoding(cert_payload))
+       {
+               case ENC_X509_SIGNATURE:
+               {
+                       cert = cert_payload->get_cert(cert_payload);
+                       break;
+               }
+               case ENC_X509_HASH_AND_URL:
+               {
+                       identification_t *id;
+                       chunk_t hash = cert_payload->get_hash(cert_payload);
+                       if (!hash.ptr)
+                       {
+                               /* invalid hash and URL data (logged elsewhere) */
+                               break;
+                       }
+                       id = identification_create_from_encoding(ID_CERT_DER_SHA1, hash);
+                       cert = charon->credentials->get_cert(charon->credentials, 
+                                                                       CERT_X509, KEY_ANY, id, FALSE);
+                       id->destroy(id);
+                       break;
+               }
+               default:
+               {
+                       break;
+               }
+       }
+       return cert;
+}
+
+/**
  * import certificates
  */
 static void process_certs(private_ike_cert_pre_t *this, message_t *message)
@@ -125,28 +187,85 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
        {
                if (payload->get_type(payload) == CERTIFICATE)
                {
-                       certificate_t *cert;
                        cert_payload_t *cert_payload = (cert_payload_t*)payload;
-                       
-                       cert = cert_payload->get_cert(cert_payload);
-                       if (cert)
+                       cert_encoding_t type = cert_payload->get_cert_encoding(cert_payload);
+                       switch (type)
                        {
-                               if (first)
-                               {       /* the first certificate MUST be an end entity one */
-                               
-                                       DBG1(DBG_IKE, "received end entity cert \"%D\"",
-                                                cert->get_subject(cert));
-                                       auth->add_item(auth, AUTHN_SUBJECT_CERT, cert);
-                                       first = FALSE;
-                               }
-                               else
+                               case ENC_X509_SIGNATURE:
+                               case ENC_X509_HASH_AND_URL:
                                {
-                                       DBG1(DBG_IKE, "received issuer cert \"%D\"",
-                                                cert->get_subject(cert));
-                                       auth->add_item(auth, AUTHN_IM_CERT, cert);
+                                       if (type == ENC_X509_HASH_AND_URL &&
+                                               !this->http_cert_lookup_supported_sent)
+                                       {
+                                               DBG1(DBG_IKE, "received hash and URL encoded cert, but"
+                                                               " we don't accept them, ignore");
+                                               break;
+                                       }
+                                       
+                                       certificate_t *cert = try_get_cert(cert_payload);
+                                       
+                                       if (cert)
+                                       {
+                                               /* we've got a certificate from the payload or the cache */ 
+                                               if (first)
+                                               {       /* the first certificate MUST be an end entity one */
+                                                       DBG1(DBG_IKE, "received end entity cert \"%D\"",
+                                                                cert->get_subject(cert));
+                                                       auth->add_item(auth, AUTHN_SUBJECT_CERT, cert);
+                                                       first = FALSE;
+                                               }
+                                               else
+                                               {
+                                                       DBG1(DBG_IKE, "received issuer cert \"%D\"",
+                                                                cert->get_subject(cert));
+                                                       auth->add_item(auth, AUTHN_IM_CERT, cert);
+                                               }
+                                               cert->destroy(cert);
+                                       }
+                                       else if (type == ENC_X509_HASH_AND_URL)
+                                       {
+                                               /* we received a hash and URL encoded certificate that
+                                                * we haven't fetched yet, we store the URL and fetch
+                                                * it later */
+                                               char *url = cert_payload->get_url(cert_payload);
+                                               if (!url)
+                                               {
+                                                       DBG1(DBG_IKE, "received invalid hash and URL encoded"
+                                                                       " cert, ignore");
+                                                       break;
+                                               }
+                                               
+                                               if (first)
+                                               {       /* the first certificate MUST be an end entity one */
+                                                       DBG1(DBG_IKE, "received hash and URL for end"
+                                                                       " entity cert \"%s\"", url);
+                                                       auth->add_item(auth, AUTHN_SUBJECT_HASH_URL, url);
+                                                       first = FALSE;
+                                               }
+                                               else
+                                               {
+                                                       DBG1(DBG_IKE, "received hash and URL for issuer"
+                                                                       " cert \"%s\"", url);
+                                                       auth->add_item(auth, AUTHN_IM_HASH_URL, url);
+                                               }
+                                       }
+                                       break;
                                }
+                               case ENC_PKCS7_WRAPPED_X509:
+                               case ENC_PGP:
+                               case ENC_DNS_SIGNED_KEY:
+                               case ENC_KERBEROS_TOKEN:
+                               case ENC_CRL:
+                               case ENC_ARL:
+                               case ENC_SPKI:
+                               case ENC_X509_ATTRIBUTE:
+                               case ENC_RAW_RSA_KEY:
+                               case ENC_X509_HASH_AND_URL_BUNDLE:
+                               case ENC_OCSP_CONTENT:
+                               default:
+                                       DBG1(DBG_ENC, "certificate encoding %N not supported",
+                                                cert_encoding_names, cert_payload->get_cert_encoding(cert_payload));
                        }
-                       cert->destroy(cert);
                }
        }
        iterator->destroy(iterator);
@@ -238,6 +357,15 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
                }
                enumerator->destroy(enumerator);
        }
+       
+       /* if we've added at least one certreq, we notify our peer that we support
+        * hash and URL for the requested certificates */
+       if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE) &&
+               message->get_payload(message, CERTIFICATE_REQUEST))
+       {
+               message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED, chunk_empty);
+               this->http_cert_lookup_supported_sent = TRUE;
+       }
 }
 
 /**
@@ -342,6 +470,7 @@ ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
        
        this->ike_sa = ike_sa;
        this->initiator = initiator;
+       this->http_cert_lookup_supported_sent = FALSE;
        
        return &this->public;
 }
index 9b6bdb6..0b3ea68 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2002 Mario Strasser
  * Copyright (C) 2000-2006 Andreas Steffen
  * Copyright (C) 2006-2008 Martin Willi
+ * Copyright (C) 2008 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -68,6 +69,11 @@ struct private_x509_cert_t {
         * X.509 certificate encoding in ASN.1 DER format
         */
        chunk_t encoding;
+       
+       /**
+        * SHA1 hash of the DER encoding of this X.509 certificate
+        */
+       chunk_t encoding_hash;
 
        /**
         * X.509 certificate body over which signature is computed
@@ -904,6 +910,12 @@ static id_match_t has_subject(private_x509_cert_t *this, identification_t *subje
        identification_t *current;
        enumerator_t *enumerator;
        id_match_t match, best;
+       
+       if (this->encoding_hash.ptr && subject->get_type(subject) == ID_CERT_DER_SHA1 &&
+               chunk_equals(this->encoding_hash, subject->get_encoding(subject)))
+       {
+               return ID_MATCH_PERFECT;
+       }
 
        best = this->subject->matches(this->subject, subject);
        enumerator = this->subjectAltNames->create_enumerator(this->subjectAltNames);
@@ -1152,6 +1164,7 @@ static void destroy(private_x509_cert_t *this)
                DESTROY_IF(this->public_key);
                DESTROY_IF(this->authKeyIdentifier);
                chunk_free(&this->encoding);
+               chunk_free(&this->encoding_hash);
                free(this);
        }
 }
@@ -1184,6 +1197,7 @@ static private_x509_cert_t* create_empty(void)
        this->public.interface.create_ocsp_uri_enumerator = (enumerator_t* (*)(x509_t*))create_ocsp_uri_enumerator;
 
        this->encoding = chunk_empty;
+       this->encoding_hash = chunk_empty;
        this->public_key = NULL;
        this->subject = NULL;
        this->issuer = NULL;
@@ -1218,6 +1232,18 @@ static private_x509_cert_t *create_from_chunk(chunk_t chunk)
        {
                this->flags |= X509_SELF_SIGNED;
        }
+       
+       hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+       if (hasher != NULL)
+       {
+               hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash);
+               hasher->destroy(hasher);
+       }
+       else
+       {
+               DBG1("  unable to create hash of certificate, SHA1 not supported");             
+       }
+       
        return this;
 }
 
index 4eead4a..e44ba7d 100644 (file)
@@ -50,11 +50,12 @@ ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID,
        "ID_DER_ASN1_DN",
        "ID_DER_ASN1_GN",
        "ID_KEY_ID");
-ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_PUBKEY_SHA1, ID_KEY_ID,
+ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_CERT_DER_SHA1, ID_KEY_ID,
        "ID_DER_ASN1_GN_URI",
        "ID_PUBKEY_INFO_SHA1",
-       "ID_PUBKEY_SHA1");
-ENUM_END(id_type_names, ID_PUBKEY_SHA1);
+       "ID_PUBKEY_SHA1",
+       "ID_CERT_DER_SHA1");
+ENUM_END(id_type_names, ID_CERT_DER_SHA1);
 
 /**
  * X.501 acronyms for well known object identifiers (OIDs)
@@ -941,6 +942,7 @@ static int print(FILE *stream, const struct printf_info *info,
                case ID_KEY_ID:
                case ID_PUBKEY_INFO_SHA1:
                case ID_PUBKEY_SHA1:
+               case ID_CERT_DER_SHA1:
                        return fprintf(stream, "%#B", &this->encoded);
                case ID_DER_ASN1_GN_URI:
                {
@@ -1175,6 +1177,7 @@ identification_t *identification_create_from_encoding(id_type_t type, chunk_t en
                case ID_DER_ASN1_GN_URI:
                case ID_PUBKEY_INFO_SHA1:
                case ID_PUBKEY_SHA1:
+               case ID_CERT_DER_SHA1:
                default:
                        break;
        }
index 31c49c2..29318ce 100644 (file)
@@ -137,6 +137,11 @@ enum id_type_t {
         * SHA1 hash over PKCS#1 subjectPublicKey
         */
        ID_PUBKEY_SHA1,
+       
+       /**
+        * SHA1 hash of the binary DER encoding of a certificate
+        */
+       ID_CERT_DER_SHA1,
 };
 
 /**
index f9e307e..84179b6 100644 (file)
@@ -1,5 +1,4 @@
 /* automatic handling of confread struct arguments
- * Copyright (C) 2007 Tobias Brunner
  * Copyright (C) 2006 Andreas Steffen
  * Hochschule fuer Technik Rapperswil, Switzerland
  *
@@ -233,6 +232,7 @@ static const token_info_t token_info[] =
     { ARG_STR,  offsetof(starter_ca_t, crluri2), NULL                              },
     { ARG_STR,  offsetof(starter_ca_t, ocspuri), NULL                              },
     { ARG_STR,  offsetof(starter_ca_t, ocspuri2), NULL                             },
+    { ARG_STR,  offsetof(starter_ca_t, certuribase), NULL                          },
 
     /* end keywords */
     { ARG_MISC, 0, NULL  /* KW_HOST */                                             },
index ae25a08..5c0b714 100644 (file)
@@ -1,6 +1,4 @@
 /* strongSwan IPsec config file parser
- * Copyright (C) 2007 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
  * Copyright (C) 2001-2002 Mathieu Lafon
  * Arkoon Network Security
  *
@@ -154,6 +152,7 @@ struct starter_ca {
        char            *crluri2;
        char            *ocspuri;
        char            *ocspuri2;
+       char        *certuribase;
 
        bool            strict;
 
index 335042f..eefd216 100644 (file)
@@ -858,6 +858,11 @@ synonym for
 .TP
 .B ocspuri2
 defines an alternative OCSP URI. Currently used by IKEv2 only.
+.B certuribase
+defines the base URI for the Hash and URL feature supported by IKEv2.
+Instead of exchanging complete certificates, IKEv2 allows to send an URI
+that resolves to the DER encoded certificate. The certificate URIs are built
+by appending the SHA1 hash of the DER encoded certificates to this base URI.
 .SH "CONFIG SECTIONS"
 At present, the only
 .B config
index 84c5ab7..3ffe0a9 100644 (file)
@@ -1,5 +1,4 @@
 /* strongSwan keywords
- * Copyright (C) 2007 Tobias Brunner
  * Copyright (C) 2005 Andreas Steffen
  * Hochschule fuer Technik Rapperswil, Switzerland
  *
@@ -105,9 +104,10 @@ typedef enum {
     KW_CRLURI2,
     KW_OCSPURI,
     KW_OCSPURI2,
+    KW_CERTURIBASE,
 
 #define KW_CA_FIRST    KW_CA_SETUP
-#define KW_CA_LAST     KW_OCSPURI2
+#define KW_CA_LAST     KW_CERTURIBASE
 
    /* end keywords */
     KW_HOST,
index 470397a..7991413 100644 (file)
@@ -1,6 +1,5 @@
 %{
 /* strongSwan keywords
- * Copyright (C) 2007 Tobias Brunner
  * Copyright (C) 2005 Andreas Steffen
  * Hochschule fuer Technik Rapperswil, Switzerland
  *
@@ -89,6 +88,7 @@ crluri2,           KW_CRLURI2
 ocspuri,           KW_OCSPURI
 ocspuri1,          KW_OCSPURI
 ocspuri2,          KW_OCSPURI2
+certuribase,       KW_CERTURIBASE
 left,              KW_LEFT
 leftnexthop,       KW_LEFTNEXTHOP
 leftsubnet,        KW_LEFTSUBNET
index 1ee7ddc..d75d25a 100644 (file)
@@ -1,5 +1,4 @@
 /* Stroke for charon is the counterpart to whack from pluto
- * Copyright (C) 2007 Tobias Brunner
  * Copyright (C) 2006 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -308,12 +307,13 @@ int starter_stroke_add_ca(starter_ca_t *ca)
 
        msg.type = STR_ADD_CA;
        msg.length = offsetof(stroke_msg_t, buffer);
-       msg.add_ca.name =     push_string(&msg, ca->name);
-       msg.add_ca.cacert =   push_string(&msg, ca->cacert);
-       msg.add_ca.crluri =   push_string(&msg, ca->crluri);
-       msg.add_ca.crluri2 =  push_string(&msg, ca->crluri2);
-       msg.add_ca.ocspuri =  push_string(&msg, ca->ocspuri);
-       msg.add_ca.ocspuri2 = push_string(&msg, ca->ocspuri2);
+       msg.add_ca.name =        push_string(&msg, ca->name);
+       msg.add_ca.cacert =      push_string(&msg, ca->cacert);
+       msg.add_ca.crluri =      push_string(&msg, ca->crluri);
+       msg.add_ca.crluri2 =     push_string(&msg, ca->crluri2);
+       msg.add_ca.ocspuri =     push_string(&msg, ca->ocspuri);
+       msg.add_ca.ocspuri2 =    push_string(&msg, ca->ocspuri2);
+       msg.add_ca.certuribase = push_string(&msg, ca->certuribase);
        return send_stroke_msg(&msg);
 }
 
index 12df245..96d13ae 100644 (file)
@@ -233,6 +233,7 @@ struct stroke_msg_t {
                        char *crluri2;
                        char *ocspuri;
                        char *ocspuri2;
+                       char *certuribase;
                } add_ca;
 
                /* data for STR_LOGLEVEL */