support for hash and URL encoded certificate payloads in charon
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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, ¤t))
|
||||
{
|
||||
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**)¤t))
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -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_ @} */
|
||||
|
||||
@@ -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, ¤t))
|
||||
{
|
||||
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**)§ion))
|
||||
{
|
||||
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();
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_ @}*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -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 */ },
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -233,6 +233,7 @@ struct stroke_msg_t {
|
||||
char *crluri2;
|
||||
char *ocspuri;
|
||||
char *ocspuri2;
|
||||
char *certuribase;
|
||||
} add_ca;
|
||||
|
||||
/* data for STR_LOGLEVEL */
|
||||
|
||||
Reference in New Issue
Block a user