support for hash and URL encoded certificate payloads in charon

This commit is contained in:
Tobias Brunner
2008-04-18 11:24:45 +00:00
parent eed87e1d76
commit 6439267a8c
23 changed files with 760 additions and 160 deletions
+124 -50
View 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:
@@ -418,6 +481,57 @@ static bool equals(private_auth_info_t *this, private_auth_info_t *other)
return equal;
}
/**
* 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
*/
@@ -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;
+13
View 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
@@ -126,6 +131,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.
*
@@ -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 */
@@ -51,6 +56,52 @@ typedef struct {
identification_t *id;
} 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
*/
@@ -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;
+108 -24
View 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;
}
@@ -168,40 +211,59 @@ static size_t get_length(private_cert_payload_t *this)
return this->payload_length;
}
/**
* 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.
*/
@@ -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;
}
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -79,6 +80,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.
*/
@@ -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_ @} */
+100 -8
View 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);
}
@@ -161,6 +177,39 @@ static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data)
return enumerator;
}
/**
* 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.
*/
@@ -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);
@@ -284,6 +338,42 @@ static void list_uris(linked_list_t *list, char *label, FILE *out)
enumerator->destroy(enumerator);
}
/**
* 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.
*/
@@ -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();
+8
View File
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -60,6 +61,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.
*/
+8 -1
View File
@@ -42,6 +42,11 @@ struct private_stroke_config_t {
*/
mutex_t *mutex;
/**
* ca sections
*/
stroke_ca_t *ca;
/**
* credentials
*/
@@ -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;
+2 -1
View 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_ @}*/
+9 -7
View 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();
+5
View 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),
};
/**
+51 -1
View File
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2006-2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -47,6 +48,55 @@ struct private_ike_cert_post_t {
bool initiator;
};
/**
* 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
*/
@@ -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;
+179 -50
View 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,52 +68,108 @@ 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;
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)
this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
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))
{
DBG1(DBG_IKE, "received cert request for unknown ca "
"with keyid %D", id);
auth->add_item(auth, AUTHN_CA_CERT_KEYID, id);
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);
}
id->destroy(id);
enumerator->destroy(enumerator);
break;
}
enumerator->destroy(enumerator);
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)
{
this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL);
}
break;
}
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
*/
@@ -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;
}