aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2008-04-18 11:24:45 +0000
committerTobias Brunner <tobias@strongswan.org>2008-04-18 11:24:45 +0000
commit6439267a8c7f22d2a4a221457fea2a26e2a7ff6d (patch)
treecc3b714d0831a09f701d2b64d350e75890d78dbf /src
parenteed87e1d766a2f74ae0017b01a8fd026dddb7156 (diff)
downloadstrongswan-6439267a8c7f22d2a4a221457fea2a26e2a7ff6d.tar.bz2
strongswan-6439267a8c7f22d2a4a221457fea2a26e2a7ff6d.tar.xz
support for hash and URL encoded certificate payloads in charon
Diffstat (limited to 'src')
-rw-r--r--src/charon/credentials/auth_info.c174
-rw-r--r--src/charon/credentials/auth_info.h13
-rw-r--r--src/charon/credentials/sets/auth_info_wrapper.c64
-rw-r--r--src/charon/encoding/payloads/cert_payload.c132
-rw-r--r--src/charon/encoding/payloads/cert_payload.h36
-rw-r--r--src/charon/plugins/stroke/stroke_ca.c108
-rw-r--r--src/charon/plugins/stroke/stroke_ca.h8
-rw-r--r--src/charon/plugins/stroke/stroke_config.c9
-rw-r--r--src/charon/plugins/stroke/stroke_config.h3
-rw-r--r--src/charon/plugins/stroke/stroke_socket.c16
-rw-r--r--src/charon/sa/ike_sa.h5
-rw-r--r--src/charon/sa/tasks/ike_cert_post.c52
-rw-r--r--src/charon/sa/tasks/ike_cert_pre.c229
-rw-r--r--src/libstrongswan/plugins/x509/x509_cert.c26
-rw-r--r--src/libstrongswan/utils/identification.c9
-rw-r--r--src/libstrongswan/utils/identification.h5
-rw-r--r--src/starter/args.c2
-rw-r--r--src/starter/confread.h3
-rw-r--r--src/starter/ipsec.conf.55
-rw-r--r--src/starter/keywords.h4
-rw-r--r--src/starter/keywords.txt2
-rw-r--r--src/starter/starterstroke.c14
-rw-r--r--src/stroke/stroke_msg.h1
23 files changed, 760 insertions, 160 deletions
diff --git a/src/charon/credentials/auth_info.c b/src/charon/credentials/auth_info.c
index 8839925fc..5d4a0f24e 100644
--- a/src/charon/credentials/auth_info.c
+++ b/src/charon/credentials/auth_info.c
@@ -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;
diff --git a/src/charon/credentials/auth_info.h b/src/charon/credentials/auth_info.h
index 5a4ecf90e..5fe2919f8 100644
--- a/src/charon/credentials/auth_info.h
+++ b/src/charon/credentials/auth_info.h
@@ -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)
diff --git a/src/charon/credentials/sets/auth_info_wrapper.c b/src/charon/credentials/sets/auth_info_wrapper.c
index b7576a5a7..cdbe2bc57 100644
--- a/src/charon/credentials/sets/auth_info_wrapper.c
+++ b/src/charon/credentials/sets/auth_info_wrapper.c
@@ -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;
diff --git a/src/charon/encoding/payloads/cert_payload.c b/src/charon/encoding/payloads/cert_payload.c
index e641cfb0e..c482b7a40 100644
--- a/src/charon/encoding/payloads/cert_payload.c
+++ b/src/charon/encoding/payloads/cert_payload.c
@@ -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_t* get_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;
+}
+
diff --git a/src/charon/encoding/payloads/cert_payload.h b/src/charon/encoding/payloads/cert_payload.h
index 6b8228bb6..5a084cdb0 100644
--- a/src/charon/encoding/payloads/cert_payload.h
+++ b/src/charon/encoding/payloads/cert_payload.h
@@ -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_ @} */
diff --git a/src/charon/plugins/stroke/stroke_ca.c b/src/charon/plugins/stroke/stroke_ca.c
index 30a270ee1..ba969b962 100644
--- a/src/charon/plugins/stroke/stroke_ca.c
+++ b/src/charon/plugins/stroke/stroke_ca.c
@@ -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();
diff --git a/src/charon/plugins/stroke/stroke_ca.h b/src/charon/plugins/stroke/stroke_ca.h
index 5633196cd..882446afe 100644
--- a/src/charon/plugins/stroke/stroke_ca.h
+++ b/src/charon/plugins/stroke/stroke_ca.h
@@ -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);
diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c
index 622fa33b1..931dc9c39 100644
--- a/src/charon/plugins/stroke/stroke_config.c
+++ b/src/charon/plugins/stroke/stroke_config.c
@@ -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;
diff --git a/src/charon/plugins/stroke/stroke_config.h b/src/charon/plugins/stroke/stroke_config.h
index 478fa3843..22b493cd2 100644
--- a/src/charon/plugins/stroke/stroke_config.h
+++ b/src/charon/plugins/stroke/stroke_config.h
@@ -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_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_socket.c b/src/charon/plugins/stroke/stroke_socket.c
index 03bc470ea..53148b9c0 100644
--- a/src/charon/plugins/stroke/stroke_socket.c
+++ b/src/charon/plugins/stroke/stroke_socket.c
@@ -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();
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index 60e499d2c..4f760b532 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -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),
};
/**
diff --git a/src/charon/sa/tasks/ike_cert_post.c b/src/charon/sa/tasks/ike_cert_post.c
index 3ec4ceca7..2532f2db8 100644
--- a/src/charon/sa/tasks/ike_cert_post.c
+++ b/src/charon/sa/tasks/ike_cert_post.c
@@ -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;
diff --git a/src/charon/sa/tasks/ike_cert_pre.c b/src/charon/sa/tasks/ike_cert_pre.c
index 34a5792ae..26ddb6e43 100644
--- a/src/charon/sa/tasks/ike_cert_pre.c
+++ b/src/charon/sa/tasks/ike_cert_pre.c
@@ -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;
}
diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c
index 9b6bdb630..0b3ea68f5 100644
--- a/src/libstrongswan/plugins/x509/x509_cert.c
+++ b/src/libstrongswan/plugins/x509/x509_cert.c
@@ -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;
}
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
index 4eead4a9f..e44ba7d6f 100644
--- a/src/libstrongswan/utils/identification.c
+++ b/src/libstrongswan/utils/identification.c
@@ -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;
}
diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h
index 31c49c269..29318ce47 100644
--- a/src/libstrongswan/utils/identification.h
+++ b/src/libstrongswan/utils/identification.h
@@ -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,
};
/**
diff --git a/src/starter/args.c b/src/starter/args.c
index f9e307ed7..84179b673 100644
--- a/src/starter/args.c
+++ b/src/starter/args.c
@@ -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 */ },
diff --git a/src/starter/confread.h b/src/starter/confread.h
index ae25a0843..5c0b714d8 100644
--- a/src/starter/confread.h
+++ b/src/starter/confread.h
@@ -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;
diff --git a/src/starter/ipsec.conf.5 b/src/starter/ipsec.conf.5
index 335042fb5..eefd216fb 100644
--- a/src/starter/ipsec.conf.5
+++ b/src/starter/ipsec.conf.5
@@ -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
diff --git a/src/starter/keywords.h b/src/starter/keywords.h
index 84c5ab79a..3ffe0a9dc 100644
--- a/src/starter/keywords.h
+++ b/src/starter/keywords.h
@@ -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,
diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt
index 470397a9c..79914133d 100644
--- a/src/starter/keywords.txt
+++ b/src/starter/keywords.txt
@@ -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
diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c
index 1ee7ddc60..d75d25a72 100644
--- a/src/starter/starterstroke.c
+++ b/src/starter/starterstroke.c
@@ -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);
}
diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h
index 12df24570..96d13ae84 100644
--- a/src/stroke/stroke_msg.h
+++ b/src/stroke/stroke_msg.h
@@ -233,6 +233,7 @@ struct stroke_msg_t {
char *crluri2;
char *ocspuri;
char *ocspuri2;
+ char *certuribase;
} add_ca;
/* data for STR_LOGLEVEL */