Moved credential manager to libstrongswan
This commit is contained in:
@@ -0,0 +1,830 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 Martin Willi
|
||||
* Copyright (C) 2008 Tobias Brunner
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "auth_cfg.h"
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/identification.h>
|
||||
#include <credentials/certificates/certificate.h>
|
||||
|
||||
ENUM(auth_class_names, AUTH_CLASS_ANY, AUTH_CLASS_EAP,
|
||||
"any",
|
||||
"public key",
|
||||
"pre-shared key",
|
||||
"EAP",
|
||||
);
|
||||
|
||||
ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_GTC,
|
||||
"EAP_IDENTITY",
|
||||
"EAP_NOTIFICATION",
|
||||
"EAP_NAK",
|
||||
"EAP_MD5",
|
||||
"EAP_OTP",
|
||||
"EAP_GTC");
|
||||
ENUM_NEXT(eap_type_names, EAP_SIM, EAP_SIM, EAP_GTC,
|
||||
"EAP_SIM");
|
||||
ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM,
|
||||
"EAP_AKA");
|
||||
ENUM_NEXT(eap_type_names, EAP_MSCHAPV2, EAP_MSCHAPV2, EAP_AKA,
|
||||
"EAP_MSCHAPV2");
|
||||
ENUM_NEXT(eap_type_names, EAP_RADIUS, EAP_EXPERIMENTAL, EAP_MSCHAPV2,
|
||||
"EAP_RADIUS",
|
||||
"EAP_EXPANDED",
|
||||
"EAP_EXPERIMENTAL");
|
||||
ENUM_END(eap_type_names, EAP_EXPERIMENTAL);
|
||||
|
||||
ENUM_BEGIN(eap_type_short_names, EAP_IDENTITY, EAP_GTC,
|
||||
"ID",
|
||||
"NTF",
|
||||
"NAK",
|
||||
"MD5",
|
||||
"OTP",
|
||||
"GTC");
|
||||
ENUM_NEXT(eap_type_short_names, EAP_SIM, EAP_SIM, EAP_GTC,
|
||||
"SIM");
|
||||
ENUM_NEXT(eap_type_short_names, EAP_AKA, EAP_AKA, EAP_SIM,
|
||||
"AKA");
|
||||
ENUM_NEXT(eap_type_short_names, EAP_MSCHAPV2, EAP_MSCHAPV2, EAP_AKA,
|
||||
"MSCHAPV2");
|
||||
ENUM_NEXT(eap_type_short_names, EAP_RADIUS, EAP_EXPERIMENTAL, EAP_MSCHAPV2,
|
||||
"RAD",
|
||||
"EXP",
|
||||
"XP");
|
||||
ENUM_END(eap_type_short_names, EAP_EXPERIMENTAL);
|
||||
|
||||
ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_SUBJECT_HASH_URL,
|
||||
"RULE_IDENTITY",
|
||||
"RULE_AUTH_CLASS",
|
||||
"RULE_EAP_IDENTITY",
|
||||
"RULE_EAP_TYPE",
|
||||
"RULE_EAP_VENDOR",
|
||||
"RULE_CA_CERT",
|
||||
"RULE_IM_CERT",
|
||||
"RULE_SUBJECT_CERT",
|
||||
"RULE_CRL_VALIDATION",
|
||||
"RULE_OCSP_VALIDATION",
|
||||
"RULE_GROUP",
|
||||
"HELPER_IM_CERT",
|
||||
"HELPER_SUBJECT_CERT",
|
||||
"HELPER_IM_HASH_URL",
|
||||
"HELPER_SUBJECT_HASH_URL",
|
||||
);
|
||||
|
||||
typedef struct private_auth_cfg_t private_auth_cfg_t;
|
||||
|
||||
/**
|
||||
* private data of item_set
|
||||
*/
|
||||
struct private_auth_cfg_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
auth_cfg_t public;
|
||||
|
||||
/**
|
||||
* list of entry_t
|
||||
*/
|
||||
linked_list_t *entries;
|
||||
};
|
||||
|
||||
typedef struct entry_t entry_t;
|
||||
|
||||
struct entry_t {
|
||||
/** rule type */
|
||||
auth_rule_t type;
|
||||
/** associated value */
|
||||
void *value;
|
||||
};
|
||||
|
||||
/**
|
||||
* enumerator for auth_cfg_t.create_enumerator()
|
||||
*/
|
||||
typedef struct {
|
||||
/** implements enumerator_t */
|
||||
enumerator_t public;
|
||||
/** inner enumerator from linked_list_t */
|
||||
enumerator_t *inner;
|
||||
/** current entry */
|
||||
entry_t *current;
|
||||
} entry_enumerator_t;
|
||||
|
||||
/**
|
||||
* enumerate function for item_enumerator_t
|
||||
*/
|
||||
static bool enumerate(entry_enumerator_t *this, auth_rule_t *type, void **value)
|
||||
{
|
||||
entry_t *entry;
|
||||
|
||||
if (this->inner->enumerate(this->inner, &entry))
|
||||
{
|
||||
this->current = entry;
|
||||
*type = entry->type;
|
||||
*value = entry->value;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy function for item_enumerator_t
|
||||
*/
|
||||
static void entry_enumerator_destroy(entry_enumerator_t *this)
|
||||
{
|
||||
this->inner->destroy(this->inner);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.create_enumerator.
|
||||
*/
|
||||
static enumerator_t* create_enumerator(private_auth_cfg_t *this)
|
||||
{
|
||||
entry_enumerator_t *enumerator;
|
||||
|
||||
enumerator = malloc_thing(entry_enumerator_t);
|
||||
enumerator->inner = this->entries->create_enumerator(this->entries);
|
||||
enumerator->public.enumerate = (void*)enumerate;
|
||||
enumerator->public.destroy = (void*)entry_enumerator_destroy;
|
||||
enumerator->current = NULL;
|
||||
return &enumerator->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the value associated with an entry
|
||||
*/
|
||||
static void destroy_entry_value(entry_t *entry)
|
||||
{
|
||||
switch (entry->type)
|
||||
{
|
||||
case AUTH_RULE_IDENTITY:
|
||||
case AUTH_RULE_EAP_IDENTITY:
|
||||
case AUTH_RULE_GROUP:
|
||||
{
|
||||
identification_t *id = (identification_t*)entry->value;
|
||||
id->destroy(id);
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_CA_CERT:
|
||||
case AUTH_RULE_IM_CERT:
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_CERT:
|
||||
case AUTH_HELPER_SUBJECT_CERT:
|
||||
{
|
||||
certificate_t *cert = (certificate_t*)entry->value;
|
||||
cert->destroy(cert);
|
||||
break;
|
||||
}
|
||||
case AUTH_HELPER_IM_HASH_URL:
|
||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||
{
|
||||
free(entry->value);
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_AUTH_CLASS:
|
||||
case AUTH_RULE_EAP_TYPE:
|
||||
case AUTH_RULE_EAP_VENDOR:
|
||||
case AUTH_RULE_CRL_VALIDATION:
|
||||
case AUTH_RULE_OCSP_VALIDATION:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.replace.
|
||||
*/
|
||||
static void replace(auth_cfg_t *this, entry_enumerator_t *enumerator,
|
||||
auth_rule_t type, ...)
|
||||
{
|
||||
if (enumerator->current)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, type);
|
||||
|
||||
destroy_entry_value(enumerator->current);
|
||||
enumerator->current->type = type;
|
||||
switch (type)
|
||||
{
|
||||
case AUTH_RULE_AUTH_CLASS:
|
||||
case AUTH_RULE_EAP_TYPE:
|
||||
case AUTH_RULE_EAP_VENDOR:
|
||||
case AUTH_RULE_CRL_VALIDATION:
|
||||
case AUTH_RULE_OCSP_VALIDATION:
|
||||
/* integer type */
|
||||
enumerator->current->value = (void*)(uintptr_t)va_arg(args, u_int);
|
||||
break;
|
||||
case AUTH_RULE_IDENTITY:
|
||||
case AUTH_RULE_EAP_IDENTITY:
|
||||
case AUTH_RULE_GROUP:
|
||||
case AUTH_RULE_CA_CERT:
|
||||
case AUTH_RULE_IM_CERT:
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_CERT:
|
||||
case AUTH_HELPER_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_HASH_URL:
|
||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||
/* pointer type */
|
||||
enumerator->current->value = va_arg(args, void*);
|
||||
break;
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.get.
|
||||
*/
|
||||
static void* get(private_auth_cfg_t *this, auth_rule_t type)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
void *current_value, *best_value = NULL;
|
||||
auth_rule_t current_type;
|
||||
bool found = FALSE;
|
||||
|
||||
enumerator = create_enumerator(this);
|
||||
while (enumerator->enumerate(enumerator, ¤t_type, ¤t_value))
|
||||
{
|
||||
if (type == current_type)
|
||||
{
|
||||
if (type == AUTH_RULE_CRL_VALIDATION ||
|
||||
type == AUTH_RULE_OCSP_VALIDATION)
|
||||
{ /* for CRL/OCSP validation, always get() the highest value */
|
||||
if (!found || current_value > best_value)
|
||||
{
|
||||
best_value = current_value;
|
||||
}
|
||||
found = TRUE;
|
||||
continue;
|
||||
}
|
||||
best_value = current_value;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
if (found)
|
||||
{
|
||||
return best_value;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
/* use some sane defaults if we don't find an entry */
|
||||
case AUTH_RULE_AUTH_CLASS:
|
||||
return (void*)AUTH_CLASS_ANY;
|
||||
case AUTH_RULE_EAP_TYPE:
|
||||
return (void*)EAP_NAK;
|
||||
case AUTH_RULE_EAP_VENDOR:
|
||||
return (void*)0;
|
||||
case AUTH_RULE_CRL_VALIDATION:
|
||||
case AUTH_RULE_OCSP_VALIDATION:
|
||||
return (void*)VALIDATION_FAILED;
|
||||
case AUTH_RULE_IDENTITY:
|
||||
case AUTH_RULE_EAP_IDENTITY:
|
||||
case AUTH_RULE_GROUP:
|
||||
case AUTH_RULE_CA_CERT:
|
||||
case AUTH_RULE_IM_CERT:
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_CERT:
|
||||
case AUTH_HELPER_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_HASH_URL:
|
||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.add.
|
||||
*/
|
||||
static void add(private_auth_cfg_t *this, auth_rule_t type, ...)
|
||||
{
|
||||
entry_t *entry = malloc_thing(entry_t);
|
||||
va_list args;
|
||||
|
||||
va_start(args, type);
|
||||
entry->type = type;
|
||||
switch (type)
|
||||
{
|
||||
case AUTH_RULE_AUTH_CLASS:
|
||||
case AUTH_RULE_EAP_TYPE:
|
||||
case AUTH_RULE_EAP_VENDOR:
|
||||
case AUTH_RULE_CRL_VALIDATION:
|
||||
case AUTH_RULE_OCSP_VALIDATION:
|
||||
/* integer type */
|
||||
entry->value = (void*)(uintptr_t)va_arg(args, u_int);
|
||||
break;
|
||||
case AUTH_RULE_IDENTITY:
|
||||
case AUTH_RULE_EAP_IDENTITY:
|
||||
case AUTH_RULE_GROUP:
|
||||
case AUTH_RULE_CA_CERT:
|
||||
case AUTH_RULE_IM_CERT:
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_CERT:
|
||||
case AUTH_HELPER_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_HASH_URL:
|
||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||
/* pointer type */
|
||||
entry->value = va_arg(args, void*);
|
||||
break;
|
||||
}
|
||||
va_end(args);
|
||||
this->entries->insert_last(this->entries, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.complies.
|
||||
*/
|
||||
static bool complies(private_auth_cfg_t *this, auth_cfg_t *constraints,
|
||||
bool log_error)
|
||||
{
|
||||
enumerator_t *e1, *e2;
|
||||
bool success = TRUE, has_group = FALSE, group_match = FALSE;
|
||||
auth_rule_t t1, t2;
|
||||
void *value;
|
||||
|
||||
e1 = constraints->create_enumerator(constraints);
|
||||
while (e1->enumerate(e1, &t1, &value))
|
||||
{
|
||||
switch (t1)
|
||||
{
|
||||
case AUTH_RULE_CA_CERT:
|
||||
case AUTH_RULE_IM_CERT:
|
||||
{
|
||||
certificate_t *c1, *c2;
|
||||
|
||||
c1 = (certificate_t*)value;
|
||||
|
||||
success = FALSE;
|
||||
e2 = create_enumerator(this);
|
||||
while (e2->enumerate(e2, &t2, &c2))
|
||||
{
|
||||
if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
|
||||
c1->equals(c1, c2))
|
||||
{
|
||||
success = TRUE;
|
||||
}
|
||||
}
|
||||
e2->destroy(e2);
|
||||
if (!success && log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint check failed: peer not "
|
||||
"authenticated by CA '%Y'.", c1->get_subject(c1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
{
|
||||
certificate_t *c1, *c2;
|
||||
|
||||
c1 = (certificate_t*)value;
|
||||
c2 = get(this, AUTH_RULE_SUBJECT_CERT);
|
||||
if (!c2 || !c1->equals(c1, c2))
|
||||
{
|
||||
success = FALSE;
|
||||
if (log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint check failed: peer not "
|
||||
"authenticated with peer cert '%Y'.",
|
||||
c1->get_subject(c1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_CRL_VALIDATION:
|
||||
case AUTH_RULE_OCSP_VALIDATION:
|
||||
{
|
||||
cert_validation_t validated, required;
|
||||
|
||||
required = (uintptr_t)value;
|
||||
validated = (uintptr_t)get(this, t1);
|
||||
switch (required)
|
||||
{
|
||||
case VALIDATION_FAILED:
|
||||
/* no constraint */
|
||||
break;
|
||||
case VALIDATION_SKIPPED:
|
||||
if (validated == VALIDATION_SKIPPED)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* FALL */
|
||||
case VALIDATION_GOOD:
|
||||
if (validated == VALIDATION_GOOD)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* FALL */
|
||||
default:
|
||||
success = FALSE;
|
||||
if (log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint check failed: %N is %N, "
|
||||
"but requires at least %N", auth_rule_names,
|
||||
t1, cert_validation_names, validated,
|
||||
cert_validation_names, required);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_IDENTITY:
|
||||
case AUTH_RULE_EAP_IDENTITY:
|
||||
{
|
||||
identification_t *id1, *id2;
|
||||
|
||||
id1 = (identification_t*)value;
|
||||
id2 = get(this, t1);
|
||||
if (!id2 || !id2->matches(id2, id1))
|
||||
{
|
||||
success = FALSE;
|
||||
if (log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint check failed: %sidentity '%Y'"
|
||||
" required ", t1 == AUTH_RULE_IDENTITY ? "" :
|
||||
"EAP ", id1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_AUTH_CLASS:
|
||||
{
|
||||
if ((uintptr_t)value != AUTH_CLASS_ANY &&
|
||||
(uintptr_t)value != (uintptr_t)get(this, t1))
|
||||
{
|
||||
success = FALSE;
|
||||
if (log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint requires %N authentication, "
|
||||
"but %N was used", auth_class_names, (uintptr_t)value,
|
||||
auth_class_names, (uintptr_t)get(this, t1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_EAP_TYPE:
|
||||
{
|
||||
if ((uintptr_t)value != (uintptr_t)get(this, t1))
|
||||
{
|
||||
success = FALSE;
|
||||
if (log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint requires %N, "
|
||||
"but %N was used", eap_type_names, (uintptr_t)value,
|
||||
eap_type_names, (uintptr_t)get(this, t1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_EAP_VENDOR:
|
||||
{
|
||||
if ((uintptr_t)value != (uintptr_t)get(this, t1))
|
||||
{
|
||||
success = FALSE;
|
||||
if (log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint requires EAP vendor %d, "
|
||||
"but %d was used", (uintptr_t)value,
|
||||
(uintptr_t)get(this, t1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_GROUP:
|
||||
{
|
||||
identification_t *id1, *id2;
|
||||
|
||||
/* for groups, a match of a single group is sufficient */
|
||||
has_group = TRUE;
|
||||
id1 = (identification_t*)value;
|
||||
e2 = create_enumerator(this);
|
||||
while (e2->enumerate(e2, &t2, &id2))
|
||||
{
|
||||
if (t2 == AUTH_RULE_GROUP && id2->matches(id2, id1))
|
||||
{
|
||||
group_match = TRUE;
|
||||
}
|
||||
}
|
||||
e2->destroy(e2);
|
||||
break;
|
||||
}
|
||||
case AUTH_HELPER_IM_CERT:
|
||||
case AUTH_HELPER_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_HASH_URL:
|
||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||
/* skip helpers */
|
||||
continue;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
e1->destroy(e1);
|
||||
|
||||
if (has_group && !group_match)
|
||||
{
|
||||
if (log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint check failed: group membership required");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.merge.
|
||||
*/
|
||||
static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy)
|
||||
{
|
||||
if (!other)
|
||||
{ /* nothing to merge */
|
||||
return;
|
||||
}
|
||||
if (copy)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
auth_rule_t type;
|
||||
void *value;
|
||||
|
||||
enumerator = create_enumerator(other);
|
||||
while (enumerator->enumerate(enumerator, &type, &value))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AUTH_RULE_CA_CERT:
|
||||
case AUTH_RULE_IM_CERT:
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_CERT:
|
||||
case AUTH_HELPER_SUBJECT_CERT:
|
||||
{
|
||||
certificate_t *cert = (certificate_t*)value;
|
||||
|
||||
add(this, type, cert->get_ref(cert));
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_CRL_VALIDATION:
|
||||
case AUTH_RULE_OCSP_VALIDATION:
|
||||
case AUTH_RULE_AUTH_CLASS:
|
||||
case AUTH_RULE_EAP_TYPE:
|
||||
case AUTH_RULE_EAP_VENDOR:
|
||||
{
|
||||
add(this, type, (uintptr_t)value);
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_IDENTITY:
|
||||
case AUTH_RULE_EAP_IDENTITY:
|
||||
case AUTH_RULE_GROUP:
|
||||
{
|
||||
identification_t *id = (identification_t*)value;
|
||||
|
||||
add(this, type, id->clone(id));
|
||||
break;
|
||||
}
|
||||
case AUTH_HELPER_IM_HASH_URL:
|
||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||
{
|
||||
add(this, type, strdup((char*)value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry_t *entry;
|
||||
|
||||
while (other->entries->remove_first(other->entries,
|
||||
(void**)&entry) == SUCCESS)
|
||||
{
|
||||
this->entries->insert_last(this->entries, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.equals.
|
||||
*/
|
||||
static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
|
||||
{
|
||||
enumerator_t *e1, *e2;
|
||||
entry_t *i1, *i2;
|
||||
bool equal = TRUE, found;
|
||||
|
||||
if (this->entries->get_count(this->entries) !=
|
||||
other->entries->get_count(other->entries))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
e1 = this->entries->create_enumerator(this->entries);
|
||||
while (e1->enumerate(e1, &i1))
|
||||
{
|
||||
found = FALSE;
|
||||
e2 = other->entries->create_enumerator(other->entries);
|
||||
while (e2->enumerate(e2, &i2))
|
||||
{
|
||||
if (i1->type == i2->type)
|
||||
{
|
||||
switch (i1->type)
|
||||
{
|
||||
case AUTH_RULE_AUTH_CLASS:
|
||||
case AUTH_RULE_EAP_TYPE:
|
||||
case AUTH_RULE_EAP_VENDOR:
|
||||
case AUTH_RULE_CRL_VALIDATION:
|
||||
case AUTH_RULE_OCSP_VALIDATION:
|
||||
{
|
||||
if (i1->value == i2->value)
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case AUTH_RULE_CA_CERT:
|
||||
case AUTH_RULE_IM_CERT:
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_CERT:
|
||||
case AUTH_HELPER_SUBJECT_CERT:
|
||||
{
|
||||
certificate_t *c1, *c2;
|
||||
|
||||
c1 = (certificate_t*)i1->value;
|
||||
c2 = (certificate_t*)i2->value;
|
||||
|
||||
if (c1->equals(c1, c2))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case AUTH_RULE_IDENTITY:
|
||||
case AUTH_RULE_EAP_IDENTITY:
|
||||
case AUTH_RULE_GROUP:
|
||||
{
|
||||
identification_t *id1, *id2;
|
||||
|
||||
id1 = (identification_t*)i1->value;
|
||||
id2 = (identification_t*)i2->value;
|
||||
|
||||
if (id1->equals(id1, id2))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case AUTH_HELPER_IM_HASH_URL:
|
||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||
{
|
||||
if (streq(i1->value, i2->value))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
e2->destroy(e2);
|
||||
if (!found)
|
||||
{
|
||||
equal = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e1->destroy(e1);
|
||||
return equal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.purge
|
||||
*/
|
||||
static void purge(private_auth_cfg_t *this, bool keep_ca)
|
||||
{
|
||||
entry_t *entry;
|
||||
linked_list_t *cas;
|
||||
|
||||
cas = linked_list_create();
|
||||
while (this->entries->remove_last(this->entries, (void**)&entry) == SUCCESS)
|
||||
{
|
||||
if (keep_ca && entry->type == AUTH_RULE_CA_CERT)
|
||||
{
|
||||
cas->insert_first(cas, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
destroy_entry_value(entry);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
while (cas->remove_last(cas, (void**)&entry) == SUCCESS)
|
||||
{
|
||||
this->entries->insert_first(this->entries, entry);
|
||||
}
|
||||
cas->destroy(cas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.clone
|
||||
*/
|
||||
static auth_cfg_t* clone_(private_auth_cfg_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
auth_cfg_t *clone;
|
||||
entry_t *entry;
|
||||
|
||||
clone = auth_cfg_create();
|
||||
enumerator = this->entries->create_enumerator(this->entries);
|
||||
while (enumerator->enumerate(enumerator, &entry))
|
||||
{
|
||||
switch (entry->type)
|
||||
{
|
||||
case AUTH_RULE_IDENTITY:
|
||||
case AUTH_RULE_EAP_IDENTITY:
|
||||
case AUTH_RULE_GROUP:
|
||||
{
|
||||
identification_t *id = (identification_t*)entry->value;
|
||||
clone->add(clone, entry->type, id->clone(id));
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_CA_CERT:
|
||||
case AUTH_RULE_IM_CERT:
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
case AUTH_HELPER_IM_CERT:
|
||||
case AUTH_HELPER_SUBJECT_CERT:
|
||||
{
|
||||
certificate_t *cert = (certificate_t*)entry->value;
|
||||
clone->add(clone, entry->type, cert->get_ref(cert));
|
||||
break;
|
||||
}
|
||||
case AUTH_HELPER_IM_HASH_URL:
|
||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||
{
|
||||
clone->add(clone, entry->type, strdup(entry->value));
|
||||
break;
|
||||
}
|
||||
case AUTH_RULE_AUTH_CLASS:
|
||||
case AUTH_RULE_EAP_TYPE:
|
||||
case AUTH_RULE_EAP_VENDOR:
|
||||
case AUTH_RULE_CRL_VALIDATION:
|
||||
case AUTH_RULE_OCSP_VALIDATION:
|
||||
clone->add(clone, entry->type, (uintptr_t)entry->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_t.destroy
|
||||
*/
|
||||
static void destroy(private_auth_cfg_t *this)
|
||||
{
|
||||
purge(this, FALSE);
|
||||
this->entries->destroy(this->entries);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
auth_cfg_t *auth_cfg_create()
|
||||
{
|
||||
private_auth_cfg_t *this = malloc_thing(private_auth_cfg_t);
|
||||
|
||||
this->public.add = (void(*)(auth_cfg_t*, auth_rule_t type, ...))add;
|
||||
this->public.get = (void*(*)(auth_cfg_t*, auth_rule_t type))get;
|
||||
this->public.create_enumerator = (enumerator_t*(*)(auth_cfg_t*))create_enumerator;
|
||||
this->public.replace = (void(*)(auth_cfg_t*,enumerator_t*,auth_rule_t,...))replace;
|
||||
this->public.complies = (bool(*)(auth_cfg_t*, auth_cfg_t *,bool))complies;
|
||||
this->public.merge = (void(*)(auth_cfg_t*, auth_cfg_t *other,bool))merge;
|
||||
this->public.purge = (void(*)(auth_cfg_t*,bool))purge;
|
||||
this->public.equals = (bool(*)(auth_cfg_t*, auth_cfg_t *other))equals;
|
||||
this->public.clone = (auth_cfg_t*(*)(auth_cfg_t*))clone_;
|
||||
this->public.destroy = (void(*)(auth_cfg_t*))destroy;
|
||||
|
||||
this->entries = linked_list_create();
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 Martin Willi
|
||||
* Copyright (C) 2008 Tobias Brunner
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup auth_cfg auth_cfg
|
||||
* @{ @ingroup credentials
|
||||
*/
|
||||
|
||||
#ifndef AUTH_CFG_H_
|
||||
#define AUTH_CFG_H_
|
||||
|
||||
#include <utils/enumerator.h>
|
||||
|
||||
typedef struct auth_cfg_t auth_cfg_t;
|
||||
typedef enum auth_rule_t auth_rule_t;
|
||||
typedef enum auth_class_t auth_class_t;
|
||||
typedef enum eap_type_t eap_type_t;
|
||||
|
||||
/**
|
||||
* Class of authentication to use. This is different to auth_method_t in that
|
||||
* it does not specify a method, but a class of acceptable methods. The found
|
||||
* certificate finally dictates wich method is used.
|
||||
*/
|
||||
enum auth_class_t {
|
||||
/** any class acceptable */
|
||||
AUTH_CLASS_ANY = 0,
|
||||
/** authentication using public keys (RSA, ECDSA) */
|
||||
AUTH_CLASS_PUBKEY = 1,
|
||||
/** authentication using a pre-shared secrets */
|
||||
AUTH_CLASS_PSK = 2,
|
||||
/** authentication using EAP */
|
||||
AUTH_CLASS_EAP = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum strings for auth_class_t
|
||||
*/
|
||||
extern enum_name_t *auth_class_names;
|
||||
|
||||
/**
|
||||
* EAP types, defines the EAP method implementation
|
||||
*/
|
||||
enum eap_type_t {
|
||||
EAP_IDENTITY = 1,
|
||||
EAP_NOTIFICATION = 2,
|
||||
EAP_NAK = 3,
|
||||
EAP_MD5 = 4,
|
||||
EAP_OTP = 5,
|
||||
EAP_GTC = 6,
|
||||
EAP_SIM = 18,
|
||||
EAP_AKA = 23,
|
||||
EAP_MSCHAPV2 = 26,
|
||||
/** not a method, but an implementation providing different methods */
|
||||
EAP_RADIUS = 253,
|
||||
EAP_EXPANDED = 254,
|
||||
EAP_EXPERIMENTAL = 255,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum names for eap_type_t.
|
||||
*/
|
||||
extern enum_name_t *eap_type_names;
|
||||
|
||||
/**
|
||||
* short string enum names for eap_type_t.
|
||||
*/
|
||||
extern enum_name_t *eap_type_short_names;
|
||||
|
||||
/**
|
||||
* Authentication config to use during authentication process.
|
||||
*
|
||||
* Each authentication config contains a set of rules. These rule-sets are used
|
||||
* in two ways:
|
||||
* - For configs specifying local authentication behavior, the rules define
|
||||
* which authentication method in which way.
|
||||
* - For configs specifying remote peer authentication, the rules define
|
||||
* constraints the peer has to fullfill.
|
||||
*
|
||||
* Additionally to the rules, there is a set of helper items. These are used
|
||||
* to transport credentials during the authentication process.
|
||||
*/
|
||||
enum auth_rule_t {
|
||||
|
||||
/** identity to use for IKEv2 authentication exchange, identification_t* */
|
||||
AUTH_RULE_IDENTITY,
|
||||
/** authentication class, auth_class_t */
|
||||
AUTH_RULE_AUTH_CLASS,
|
||||
/** EAP identity to use within EAP-Identity exchange, identification_t* */
|
||||
AUTH_RULE_EAP_IDENTITY,
|
||||
/** EAP type to propose for peer authentication, eap_type_t */
|
||||
AUTH_RULE_EAP_TYPE,
|
||||
/** EAP vendor for vendor specific type, u_int32_t */
|
||||
AUTH_RULE_EAP_VENDOR,
|
||||
/** certificate authority, certificate_t* */
|
||||
AUTH_RULE_CA_CERT,
|
||||
/** intermediate certificate in trustchain, certificate_t* */
|
||||
AUTH_RULE_IM_CERT,
|
||||
/** subject certificate, certificate_t* */
|
||||
AUTH_RULE_SUBJECT_CERT,
|
||||
/** result of a CRL validation, cert_validation_t */
|
||||
AUTH_RULE_CRL_VALIDATION,
|
||||
/** result of a OCSP validation, cert_validation_t */
|
||||
AUTH_RULE_OCSP_VALIDATION,
|
||||
/** subject is member of a group, identification_t*
|
||||
* The group membership constraint is fulfilled if the subject is member of
|
||||
* one group defined in the constraints. */
|
||||
AUTH_RULE_GROUP,
|
||||
|
||||
/** intermediate certificate, certificate_t* */
|
||||
AUTH_HELPER_IM_CERT,
|
||||
/** subject certificate, certificate_t* */
|
||||
AUTH_HELPER_SUBJECT_CERT,
|
||||
/** Hash and URL of a intermediate certificate, char* */
|
||||
AUTH_HELPER_IM_HASH_URL,
|
||||
/** Hash and URL of a end-entity certificate, char* */
|
||||
AUTH_HELPER_SUBJECT_HASH_URL,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum name for auth_rule_t.
|
||||
*/
|
||||
extern enum_name_t *auth_rule_names;
|
||||
|
||||
/**
|
||||
* Authentication/Authorization round.
|
||||
*
|
||||
* RFC4739 defines multiple authentication rounds. This class defines such
|
||||
* a round from a configuration perspective, either for the local or the remote
|
||||
* peer. Local config are called "rulesets", as they define how we authenticate.
|
||||
* Remote peer configs are called "constraits", they define what is needed to
|
||||
* complete the authentication round successfully.
|
||||
*
|
||||
* @verbatim
|
||||
|
||||
[Repeat for each configuration]
|
||||
+--------------------------------------------------+
|
||||
| |
|
||||
| |
|
||||
| +----------+ IKE_AUTH +--------- + |
|
||||
| | config | -----------> | | |
|
||||
| | ruleset | | | |
|
||||
| +----------+ [ <----------- ] | | |
|
||||
| [ optional EAP ] | Peer | |
|
||||
| +----------+ [ -----------> ] | | |
|
||||
| | config | | | |
|
||||
| | constr. | <----------- | | |
|
||||
| +----------+ IKE_AUTH +--------- + |
|
||||
| |
|
||||
| |
|
||||
+--------------------------------------------------+
|
||||
|
||||
@endverbatim
|
||||
*
|
||||
* Values for each items are either pointers (casted to void*) or short
|
||||
* integers (use uintptr_t cast).
|
||||
*/
|
||||
struct auth_cfg_t {
|
||||
|
||||
/**
|
||||
* Add an rule to the set.
|
||||
*
|
||||
* @param rule rule type
|
||||
* @param ... associated value to rule
|
||||
*/
|
||||
void (*add)(auth_cfg_t *this, auth_rule_t rule, ...);
|
||||
|
||||
/**
|
||||
* Get an rule value.
|
||||
*
|
||||
* @param rule rule type
|
||||
* @return bool if item has been found
|
||||
*/
|
||||
void* (*get)(auth_cfg_t *this, auth_rule_t rule);
|
||||
|
||||
/**
|
||||
* Create an enumerator over added rules.
|
||||
*
|
||||
* @return enumerator over (auth_rule_t, union{void*,uintpr_t})
|
||||
*/
|
||||
enumerator_t* (*create_enumerator)(auth_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Replace an rule at enumerator position.
|
||||
*
|
||||
* @param pos enumerator position position
|
||||
* @param rule rule type
|
||||
* @param ... associated value to rule
|
||||
*/
|
||||
void (*replace)(auth_cfg_t *this, enumerator_t *pos,
|
||||
auth_rule_t rule, ...);
|
||||
|
||||
/**
|
||||
* Check if a used config fulfills a set of configured constraints.
|
||||
*
|
||||
* @param constraints required authorization rules
|
||||
* @param log_error wheter to log compliance errors
|
||||
* @return TRUE if this complies with constraints
|
||||
*/
|
||||
bool (*complies)(auth_cfg_t *this, auth_cfg_t *constraints, bool log_error);
|
||||
|
||||
/**
|
||||
* Merge items from other into this.
|
||||
*
|
||||
* @param other items to read for merge
|
||||
* @param copy TRUE to copy items, FALSE to move them
|
||||
*/
|
||||
void (*merge)(auth_cfg_t *this, auth_cfg_t *other, bool copy);
|
||||
|
||||
/**
|
||||
* Purge all rules in a config.
|
||||
*
|
||||
* @param keep_ca wheter to keep AUTH_RULE_CA_CERT entries
|
||||
*/
|
||||
void (*purge)(auth_cfg_t *this, bool keep_ca);
|
||||
|
||||
/**
|
||||
* Check two configs for equality.
|
||||
*
|
||||
* @param other other config to compaire against this
|
||||
* @return TRUE if auth infos identical
|
||||
*/
|
||||
bool (*equals)(auth_cfg_t *this, auth_cfg_t *other);
|
||||
|
||||
/**
|
||||
* Clone a authentication config, including all rules.
|
||||
*
|
||||
* @return cloned configuration
|
||||
*/
|
||||
auth_cfg_t* (*clone)(auth_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Destroy a config with all associated rules/values.
|
||||
*/
|
||||
void (*destroy)(auth_cfg_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a authentication config.
|
||||
*/
|
||||
auth_cfg_t *auth_cfg_create();
|
||||
|
||||
#endif /** AUTH_CFG_H_ @}*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup credential_manager credential_manager
|
||||
* @{ @ingroup credentials
|
||||
*/
|
||||
|
||||
#ifndef CREDENTIAL_MANAGER_H_
|
||||
#define CREDENTIAL_MANAGER_H_
|
||||
|
||||
typedef struct credential_manager_t credential_manager_t;
|
||||
|
||||
#include <utils/identification.h>
|
||||
#include <utils/enumerator.h>
|
||||
#include <credentials/auth_cfg.h>
|
||||
#include <credentials/credential_set.h>
|
||||
#include <credentials/keys/private_key.h>
|
||||
#include <credentials/keys/shared_key.h>
|
||||
#include <credentials/certificates/certificate.h>
|
||||
|
||||
/**
|
||||
* Manages credentials using credential_sets.
|
||||
*
|
||||
* The credential manager is the entry point of the credential framework. It
|
||||
* uses so called "sets" to access credentials in a modular fashion, these
|
||||
* are implemented through the credential_set_t interface.
|
||||
* The manager additionally does trust chain verification and trust status
|
||||
* chaching. A set may call the managers methods if it needs credentials itself,
|
||||
* the manager uses recursive locking.
|
||||
*
|
||||
* @verbatim
|
||||
|
||||
+-------+ +----------------+
|
||||
| A | | | +------------------+
|
||||
| u | -----> | | ------> | +------------------+
|
||||
| t | | credential- | | | +------------------+
|
||||
| h | -----> | manager | ------> +--| | credential- | => IPC
|
||||
| e | | | +--| sets |
|
||||
| n | +--> | | ------> +------------------+
|
||||
| t | | | | |
|
||||
| i | | | | |
|
||||
| c | | +----------------+ |
|
||||
| a | | |
|
||||
| t | +----------------------------------------------+
|
||||
| o | may be recursive
|
||||
| r |
|
||||
+-------+
|
||||
|
||||
@endverbatim
|
||||
*
|
||||
* The credential manager uses rwlocks for performance reasons, credential
|
||||
* sets must be fully thread save.
|
||||
*/
|
||||
struct credential_manager_t {
|
||||
|
||||
/**
|
||||
* Create an enumerator over all certificates.
|
||||
*
|
||||
* @param cert kind of certificate
|
||||
* @param key kind of key in certificate
|
||||
* @param id subject this certificate belongs to
|
||||
* @param trusted TRUE to list trusted certificates only
|
||||
* @return enumerator over the certificates
|
||||
*/
|
||||
enumerator_t *(*create_cert_enumerator)(credential_manager_t *this,
|
||||
certificate_type_t cert, key_type_t key,
|
||||
identification_t *id, bool trusted);
|
||||
/**
|
||||
* Create an enumerator over all shared keys.
|
||||
*
|
||||
* The enumerator enumerates over:
|
||||
* shared_key_t*, id_match_t me, id_match_t other
|
||||
* But must accepts values for the id_matches.
|
||||
*
|
||||
* @param type kind of requested shared key
|
||||
* @param first first subject between key is shared
|
||||
* @param second second subject between key is shared
|
||||
* @return enumerator over shared keys
|
||||
*/
|
||||
enumerator_t *(*create_shared_enumerator)(credential_manager_t *this,
|
||||
shared_key_type_t type,
|
||||
identification_t *first, identification_t *second);
|
||||
/**
|
||||
* Create an enumerator over all Certificate Distribution Points.
|
||||
*
|
||||
* @param type kind of certificate the point distributes
|
||||
* @param id identification of the distributed certificate
|
||||
* @return enumerator of CDPs as char*
|
||||
*/
|
||||
enumerator_t *(*create_cdp_enumerator)(credential_manager_t *this,
|
||||
certificate_type_t type, identification_t *id);
|
||||
/**
|
||||
* Get a trusted or untrusted certificate.
|
||||
*
|
||||
* @param cert kind of certificate
|
||||
* @param key kind of key in certificate
|
||||
* @param id subject this certificate belongs to
|
||||
* @param trusted TRUE to get a trusted certificate only
|
||||
* @return certificate, if found, NULL otherwise
|
||||
*/
|
||||
certificate_t *(*get_cert)(credential_manager_t *this,
|
||||
certificate_type_t cert, key_type_t key,
|
||||
identification_t *id, bool trusted);
|
||||
/**
|
||||
* Get the best matching shared key for two IDs.
|
||||
*
|
||||
* @param type kind of requested shared key
|
||||
* @param me own identity
|
||||
* @param other peers identity
|
||||
* @return shared_key_t, NULL if none found
|
||||
*/
|
||||
shared_key_t *(*get_shared)(credential_manager_t *this, shared_key_type_t type,
|
||||
identification_t *me, identification_t *other);
|
||||
/**
|
||||
* Get a private key to create a signature.
|
||||
*
|
||||
* The get_private() method gets a secret private key identified by either
|
||||
* the keyid itself or an id the key belongs to.
|
||||
* The auth parameter contains additional information, such as receipients
|
||||
* trusted CA certs. Auth gets filled with subject and CA certificates
|
||||
* needed to validate a created signature.
|
||||
*
|
||||
* @param type type of the key to get
|
||||
* @param id identification the key belongs to
|
||||
* @param auth auth config, including trusted CA certificates
|
||||
* @return private_key_t, NULL if none found
|
||||
*/
|
||||
private_key_t* (*get_private)(credential_manager_t *this, key_type_t type,
|
||||
identification_t *id, auth_cfg_t *auth);
|
||||
|
||||
/**
|
||||
* Create an enumerator over trusted public keys.
|
||||
*
|
||||
* This method gets a an enumerator over trusted public keys to verify a
|
||||
* signature created by id. The auth parameter contains additional
|
||||
* authentication infos, e.g. peer and intermediate certificates.
|
||||
* The resulting enumerator enumerates over public_key_t *, auth_cfg_t *,
|
||||
* where the auth config helper contains rules for constraint checks.
|
||||
*
|
||||
* @param type type of the key to get
|
||||
* @param id owner of the key, signer of the signature
|
||||
* @param auth authentication infos
|
||||
* @return enumerator
|
||||
*/
|
||||
enumerator_t* (*create_public_enumerator)(credential_manager_t *this,
|
||||
key_type_t type, identification_t *id, auth_cfg_t *auth);
|
||||
|
||||
/**
|
||||
* Cache a certificate by invoking cache_cert() on all registerd sets.
|
||||
*
|
||||
* @param cert certificate to cache
|
||||
*/
|
||||
void (*cache_cert)(credential_manager_t *this, certificate_t *cert);
|
||||
|
||||
/**
|
||||
* Flush the certificate cache.
|
||||
*
|
||||
* Only the managers local cache is flushed, but not the sets cache filled
|
||||
* by the cache_cert() method.
|
||||
*
|
||||
* @param type type of certificate to flush, or CERT_ANY
|
||||
*/
|
||||
void (*flush_cache)(credential_manager_t *this, certificate_type_t type);
|
||||
|
||||
/**
|
||||
* Register a credential set to the manager.
|
||||
*
|
||||
* @param set set to register
|
||||
*/
|
||||
void (*add_set)(credential_manager_t *this, credential_set_t *set);
|
||||
|
||||
/**
|
||||
* Unregister a credential set from the manager.
|
||||
*
|
||||
* @param set set to unregister
|
||||
*/
|
||||
void (*remove_set)(credential_manager_t *this, credential_set_t *set);
|
||||
|
||||
/**
|
||||
* Destroy a credential_manager instance.
|
||||
*/
|
||||
void (*destroy)(credential_manager_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a credential_manager instance.
|
||||
*/
|
||||
credential_manager_t *credential_manager_create();
|
||||
|
||||
#endif /** CREDENTIAL_MANAGER_H_ @}*/
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup credential_set credential_set
|
||||
* @{ @ingroup credentials
|
||||
*/
|
||||
|
||||
#ifndef CREDENTIAL_SET_H_
|
||||
#define CREDENTIAL_SET_H_
|
||||
|
||||
typedef struct credential_set_t credential_set_t;
|
||||
|
||||
#include <credentials/keys/public_key.h>
|
||||
#include <credentials/keys/shared_key.h>
|
||||
#include <credentials/certificates/certificate.h>
|
||||
|
||||
/**
|
||||
* A set of credentials.
|
||||
*
|
||||
* Contains private keys, shared keys and different kinds of certificates.
|
||||
* Enumerators are used because queries might return multiple matches.
|
||||
* Filter parameters restrict enumeration over specific items only.
|
||||
* See credential_manager_t for an overview of the credential framework.
|
||||
*
|
||||
* A credential set enumerator may not block the credential set, i.e. multiple
|
||||
* threads must be able to hold multiple enumerators, as the credential manager
|
||||
* is higly parallelized. The best way to achieve this is by using shared
|
||||
* read locks for the enumerators only. Otherwiese deadlocks will occur.
|
||||
* The writing cache_cert() routine is called by the manager only if no
|
||||
* enumerator is alive, so it is save to use a write lock there.
|
||||
*/
|
||||
struct credential_set_t {
|
||||
|
||||
/**
|
||||
* Create an enumerator over private keys (private_key_t).
|
||||
*
|
||||
* The id is either a key identifier of the requested key, or an identity
|
||||
* of the key owner.
|
||||
*
|
||||
* @param type type of requested private key
|
||||
* @param id key identifier/owner
|
||||
* @return enumerator over private_key_t's.
|
||||
*/
|
||||
enumerator_t *(*create_private_enumerator)(credential_set_t *this,
|
||||
key_type_t type, identification_t *id);
|
||||
/**
|
||||
* Create an enumerator over certificates (certificate_t).
|
||||
*
|
||||
* @param cert kind of certificate
|
||||
* @param key kind of key in certificate
|
||||
* @param id identity (subject) this certificate belongs to
|
||||
* @param trusted whether the certificate must be trustworthy
|
||||
* @return enumerator as described above
|
||||
*/
|
||||
enumerator_t *(*create_cert_enumerator)(credential_set_t *this,
|
||||
certificate_type_t cert, key_type_t key,
|
||||
identification_t *id, bool trusted);
|
||||
/**
|
||||
* Create an enumerator over shared keys (shared_key_t).
|
||||
*
|
||||
* The enumerator enumerates over:
|
||||
* shared_key_t*, id_match_t me, id_match_t other
|
||||
* But must accept NULL values for the id_matches.
|
||||
*
|
||||
* @param type kind of requested shared key
|
||||
* @param me own identity
|
||||
* @param other other identity who owns that secret
|
||||
* @return enumerator as described above
|
||||
*/
|
||||
enumerator_t *(*create_shared_enumerator)(credential_set_t *this,
|
||||
shared_key_type_t type,
|
||||
identification_t *me, identification_t *other);
|
||||
|
||||
/**
|
||||
* Create an enumerator over certificate distribution points.
|
||||
*
|
||||
* @param type type of the certificate to get a CDP
|
||||
* @param id identification of the distributed certificate
|
||||
* @return an enumerator over CDPs as char*
|
||||
*/
|
||||
enumerator_t *(*create_cdp_enumerator)(credential_set_t *this,
|
||||
certificate_type_t type, identification_t *id);
|
||||
|
||||
/**
|
||||
* Cache a certificate in the credential set.
|
||||
*
|
||||
* The caching policy is implementation dependent, the sets may cache the
|
||||
* certificate in-memory, persistent on disk or not at all.
|
||||
*
|
||||
* @param cert certificate to cache
|
||||
*/
|
||||
void (*cache_cert)(credential_set_t *this, certificate_t *cert);
|
||||
};
|
||||
|
||||
#endif /** CREDENTIAL_SET_H_ @}*/
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
typedef struct private_key_t private_key_t;
|
||||
|
||||
#include <credentials/keys/key_encoding.h>
|
||||
#include <credentials/keys/public_key.h>
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2009 Martin Willi
|
||||
* Copyright (C) 2008 Tobias Brunner
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "auth_cfg_wrapper.h"
|
||||
|
||||
typedef struct private_auth_cfg_wrapper_t private_auth_cfg_wrapper_t;
|
||||
|
||||
/**
|
||||
* private data of auth_cfg_wrapper
|
||||
*/
|
||||
struct private_auth_cfg_wrapper_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
auth_cfg_wrapper_t public;
|
||||
|
||||
/**
|
||||
* wrapped auth info
|
||||
*/
|
||||
auth_cfg_t *auth;
|
||||
};
|
||||
|
||||
/**
|
||||
* enumerator for auth_cfg_wrapper_t.create_cert_enumerator()
|
||||
*/
|
||||
typedef struct {
|
||||
/** implements enumerator_t */
|
||||
enumerator_t public;
|
||||
/** inner enumerator from auth_cfg */
|
||||
enumerator_t *inner;
|
||||
/** wrapped auth round */
|
||||
auth_cfg_t *auth;
|
||||
/** enumerated cert type */
|
||||
certificate_type_t cert;
|
||||
/** enumerated key type */
|
||||
key_type_t key;
|
||||
/** enumerated id */
|
||||
identification_t *id;
|
||||
} wrapper_enumerator_t;
|
||||
|
||||
/**
|
||||
* Tries to fetch a certificate that was supplied as "Hash and URL"
|
||||
* (replaces rule type and value in place).
|
||||
*/
|
||||
static bool fetch_cert(wrapper_enumerator_t *enumerator,
|
||||
auth_rule_t *rule, 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, FETCH_END) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_CFG, " fetching certificate failed");
|
||||
/* we set the item to NULL, so we can skip it */
|
||||
enumerator->auth->replace(enumerator->auth, enumerator->inner,
|
||||
*rule, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_BLOB_ASN1_DER, data, BUILD_END);
|
||||
free(data.ptr);
|
||||
|
||||
if (!cert)
|
||||
{
|
||||
DBG1(DBG_CFG, " parsing fetched certificate failed");
|
||||
/* we set the item to NULL, so we can skip it */
|
||||
enumerator->auth->replace(enumerator->auth, enumerator->inner,
|
||||
*rule, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBG1(DBG_CFG, " fetched certificate \"%Y\"", cert->get_subject(cert));
|
||||
lib->credmgr->cache_cert(lib->credmgr, cert);
|
||||
|
||||
if (*rule == AUTH_HELPER_IM_HASH_URL)
|
||||
{
|
||||
*rule = AUTH_HELPER_IM_CERT;
|
||||
}
|
||||
else
|
||||
{
|
||||
*rule = AUTH_HELPER_SUBJECT_CERT;
|
||||
}
|
||||
*value = cert;
|
||||
enumerator->auth->replace(enumerator->auth, enumerator->inner,
|
||||
*rule, cert->get_ref(cert));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* enumerate function for wrapper_enumerator_t
|
||||
*/
|
||||
static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
|
||||
{
|
||||
auth_rule_t rule;
|
||||
certificate_t *current;
|
||||
public_key_t *public;
|
||||
|
||||
while (this->inner->enumerate(this->inner, &rule, ¤t))
|
||||
{
|
||||
if (rule == AUTH_HELPER_IM_HASH_URL ||
|
||||
rule == AUTH_HELPER_SUBJECT_HASH_URL)
|
||||
{ /* on-demand fetching of hash and url certificates */
|
||||
if (!fetch_cert(this, &rule, (void**)¤t))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (rule != AUTH_HELPER_SUBJECT_CERT &&
|
||||
rule != AUTH_HELPER_IM_CERT)
|
||||
{ /* handle only HELPER certificates */
|
||||
continue;
|
||||
}
|
||||
if (this->cert != CERT_ANY && this->cert != current->get_type(current))
|
||||
{ /* CERT type requested, but does not match */
|
||||
continue;
|
||||
}
|
||||
public = current->get_public_key(current);
|
||||
if (this->key != KEY_ANY && !public)
|
||||
{ /* key type requested, but no public key */
|
||||
DESTROY_IF(public);
|
||||
continue;
|
||||
}
|
||||
if (this->key != KEY_ANY && public && this->key != public->get_type(public))
|
||||
{ /* key type requested, but public key has another type */
|
||||
DESTROY_IF(public);
|
||||
continue;
|
||||
}
|
||||
DESTROY_IF(public);
|
||||
if (this->id && !current->has_subject(current, this->id))
|
||||
{ /* subject requested, but does not match */
|
||||
continue;
|
||||
}
|
||||
*cert = current;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy function for wrapper_enumerator_t
|
||||
*/
|
||||
static void wrapper_enumerator_destroy(wrapper_enumerator_t *this)
|
||||
{
|
||||
this->inner->destroy(this->inner);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* implementation of auth_cfg_wrapper_t.set.create_cert_enumerator
|
||||
*/
|
||||
static enumerator_t *create_enumerator(private_auth_cfg_wrapper_t *this,
|
||||
certificate_type_t cert, key_type_t key,
|
||||
identification_t *id, bool trusted)
|
||||
{
|
||||
wrapper_enumerator_t *enumerator;
|
||||
|
||||
if (trusted)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
enumerator = malloc_thing(wrapper_enumerator_t);
|
||||
enumerator->auth = this->auth;
|
||||
enumerator->cert = cert;
|
||||
enumerator->key = key;
|
||||
enumerator->id = id;
|
||||
enumerator->inner = this->auth->create_enumerator(this->auth);
|
||||
enumerator->public.enumerate = (void*)enumerate;
|
||||
enumerator->public.destroy = (void*)wrapper_enumerator_destroy;
|
||||
return &enumerator->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of auth_cfg_wrapper_t.destroy
|
||||
*/
|
||||
static void destroy(private_auth_cfg_wrapper_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
auth_cfg_wrapper_t *auth_cfg_wrapper_create(auth_cfg_t *auth)
|
||||
{
|
||||
private_auth_cfg_wrapper_t *this = malloc_thing(private_auth_cfg_wrapper_t);
|
||||
|
||||
this->public.set.create_private_enumerator = (void*)return_null;
|
||||
this->public.set.create_cert_enumerator = (void*)create_enumerator;
|
||||
this->public.set.create_shared_enumerator = (void*)return_null;
|
||||
this->public.set.create_cdp_enumerator = (void*)return_null;
|
||||
this->public.set.cache_cert = (void*)nop;
|
||||
this->public.destroy = (void(*)(auth_cfg_wrapper_t*))destroy;
|
||||
|
||||
this->auth = auth;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2009 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup auth_cfg_wrapper auth_cfg_wrapper
|
||||
* @{ @ingroup sets
|
||||
*/
|
||||
|
||||
#ifndef AUTH_CFG_WRAPPER_H_
|
||||
#define AUTH_CFG_WRAPPER_H_
|
||||
|
||||
#include <credentials/auth_cfg.h>
|
||||
#include <credentials/credential_set.h>
|
||||
|
||||
typedef struct auth_cfg_wrapper_t auth_cfg_wrapper_t;
|
||||
|
||||
/**
|
||||
* A wrapper around auth_cfg_t to handle it as a credential set.
|
||||
*/
|
||||
struct auth_cfg_wrapper_t {
|
||||
|
||||
/**
|
||||
* implements credential_set_t
|
||||
*/
|
||||
credential_set_t set;
|
||||
|
||||
/**
|
||||
* Destroy a auth_cfg_wrapper instance.
|
||||
*/
|
||||
void (*destroy)(auth_cfg_wrapper_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a auth_cfg_wrapper instance.
|
||||
*
|
||||
* @param auth the wrapped auth info
|
||||
* @return wrapper around auth
|
||||
*/
|
||||
auth_cfg_wrapper_t *auth_cfg_wrapper_create(auth_cfg_t *auth);
|
||||
|
||||
#endif /** AUTH_CFG_WRAPPER_H_ @}*/
|
||||
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "cert_cache.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <threading/rwlock.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
/** cache size, a power of 2 for fast modulo */
|
||||
#define CACHE_SIZE 32
|
||||
|
||||
/** attempts to acquire a cache lock */
|
||||
#define REPLACE_TRIES 5
|
||||
|
||||
typedef struct private_cert_cache_t private_cert_cache_t;
|
||||
typedef struct relation_t relation_t;
|
||||
|
||||
/**
|
||||
* A trusted relation between subject and issuer
|
||||
*/
|
||||
struct relation_t {
|
||||
|
||||
/**
|
||||
* subject of this relation
|
||||
*/
|
||||
certificate_t *subject;
|
||||
|
||||
/**
|
||||
* issuer of this relation
|
||||
*/
|
||||
certificate_t *issuer;
|
||||
|
||||
/**
|
||||
* Cache hits
|
||||
*/
|
||||
u_int hits;
|
||||
|
||||
/**
|
||||
* Lock for this relation
|
||||
*/
|
||||
rwlock_t *lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* private data of cert_cache
|
||||
*/
|
||||
struct private_cert_cache_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
cert_cache_t public;
|
||||
|
||||
/**
|
||||
* array of trusted subject-issuer relations
|
||||
*/
|
||||
relation_t relations[CACHE_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache relation in a free slot/replace an other
|
||||
*/
|
||||
static void cache(private_cert_cache_t *this,
|
||||
certificate_t *subject, certificate_t *issuer)
|
||||
{
|
||||
relation_t *rel;
|
||||
int i, offset, try;
|
||||
u_int total_hits = 0;
|
||||
|
||||
/* check for a unused relation slot first */
|
||||
for (i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
rel = &this->relations[i];
|
||||
|
||||
if (!rel->subject && rel->lock->try_write_lock(rel->lock))
|
||||
{
|
||||
/* double-check having lock */
|
||||
if (!rel->subject)
|
||||
{
|
||||
rel->subject = subject->get_ref(subject);
|
||||
rel->issuer = issuer->get_ref(issuer);
|
||||
return rel->lock->unlock(rel->lock);
|
||||
}
|
||||
rel->lock->unlock(rel->lock);
|
||||
}
|
||||
total_hits += rel->hits;
|
||||
}
|
||||
/* run several attempts to replace a random slot, never block. */
|
||||
for (try = 0; try < REPLACE_TRIES; try++)
|
||||
{
|
||||
/* replace a random relation */
|
||||
offset = random();
|
||||
for (i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
rel = &this->relations[(i + offset) % CACHE_SIZE];
|
||||
|
||||
if (rel->hits > total_hits / CACHE_SIZE)
|
||||
{ /* skip often used slots */
|
||||
continue;
|
||||
}
|
||||
if (rel->lock->try_write_lock(rel->lock))
|
||||
{
|
||||
if (rel->subject)
|
||||
{
|
||||
rel->subject->destroy(rel->subject);
|
||||
rel->issuer->destroy(rel->issuer);
|
||||
}
|
||||
rel->subject = subject->get_ref(subject);
|
||||
rel->issuer = issuer->get_ref(issuer);
|
||||
rel->hits = 0;
|
||||
return rel->lock->unlock(rel->lock);
|
||||
}
|
||||
}
|
||||
/* give other threads a chance to release locks */
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of cert_cache_t.issued_by.
|
||||
*/
|
||||
static bool issued_by(private_cert_cache_t *this,
|
||||
certificate_t *subject, certificate_t *issuer)
|
||||
{
|
||||
relation_t *found = NULL, *current;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
current = &this->relations[i];
|
||||
|
||||
current->lock->read_lock(current->lock);
|
||||
if (current->subject)
|
||||
{
|
||||
/* check for equal issuer */
|
||||
if (issuer->equals(issuer, current->issuer))
|
||||
{
|
||||
/* reuse issuer instance in cache() */
|
||||
issuer = current->issuer;
|
||||
if (subject->equals(subject, current->subject))
|
||||
{
|
||||
/* write hit counter is not locked, but not critical */
|
||||
current->hits++;
|
||||
found = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
current->lock->unlock(current->lock);
|
||||
if (found)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
/* no cache hit, check and cache signature */
|
||||
if (subject->issued_by(subject, issuer))
|
||||
{
|
||||
cache(this, subject, issuer);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* certificate enumerator implemenation
|
||||
*/
|
||||
typedef struct {
|
||||
/** implements enumerator_t interface */
|
||||
enumerator_t public;
|
||||
/** type of requested certificate */
|
||||
certificate_type_t cert;
|
||||
/** type of requested key */
|
||||
key_type_t key;
|
||||
/** ID to get a cert for */
|
||||
identification_t *id;
|
||||
/** cache */
|
||||
relation_t *relations;
|
||||
/** current position in array cache */
|
||||
int index;
|
||||
/** currently locked relation */
|
||||
int locked;
|
||||
} cert_enumerator_t;
|
||||
|
||||
/**
|
||||
* filter function for certs enumerator
|
||||
*/
|
||||
static bool cert_enumerate(cert_enumerator_t *this, certificate_t **out)
|
||||
{
|
||||
public_key_t *public;
|
||||
relation_t *rel;
|
||||
|
||||
if (this->locked >= 0)
|
||||
{
|
||||
rel = &this->relations[this->locked];
|
||||
rel->lock->unlock(rel->lock);
|
||||
this->locked = -1;
|
||||
}
|
||||
|
||||
while (++this->index < CACHE_SIZE)
|
||||
{
|
||||
rel = &this->relations[this->index];
|
||||
rel->lock->read_lock(rel->lock);
|
||||
this->locked = this->index;
|
||||
if (rel->subject)
|
||||
{
|
||||
/* CRL lookup is done using issuer/authkeyidentifier */
|
||||
if (this->key == KEY_ANY && this->id &&
|
||||
(this->cert == CERT_ANY || this->cert == CERT_X509_CRL) &&
|
||||
rel->subject->get_type(rel->subject) == CERT_X509_CRL &&
|
||||
rel->subject->has_issuer(rel->subject, this->id))
|
||||
{
|
||||
*out = rel->subject;
|
||||
return TRUE;
|
||||
}
|
||||
if ((this->cert == CERT_ANY ||
|
||||
rel->subject->get_type(rel->subject) == this->cert) &&
|
||||
(!this->id || rel->subject->has_subject(rel->subject, this->id)))
|
||||
{
|
||||
if (this->key == KEY_ANY)
|
||||
{
|
||||
*out = rel->subject;
|
||||
return TRUE;
|
||||
}
|
||||
public = rel->subject->get_public_key(rel->subject);
|
||||
if (public)
|
||||
{
|
||||
if (public->get_type(public) == this->key)
|
||||
{
|
||||
public->destroy(public);
|
||||
*out = rel->subject;
|
||||
return TRUE;
|
||||
}
|
||||
public->destroy(public);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->locked = -1;
|
||||
rel->lock->unlock(rel->lock);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up enumeration data
|
||||
*/
|
||||
static void cert_enumerator_destroy(cert_enumerator_t *this)
|
||||
{
|
||||
relation_t *rel;
|
||||
|
||||
if (this->locked >= 0)
|
||||
{
|
||||
rel = &this->relations[this->locked];
|
||||
rel->lock->unlock(rel->lock);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* implementation of credential_set_t.create_cert_enumerator
|
||||
*/
|
||||
static enumerator_t *create_enumerator(private_cert_cache_t *this,
|
||||
certificate_type_t cert, key_type_t key,
|
||||
identification_t *id, bool trusted)
|
||||
{
|
||||
cert_enumerator_t *enumerator;
|
||||
|
||||
if (trusted)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
enumerator = malloc_thing(cert_enumerator_t);
|
||||
enumerator->public.enumerate = (void*)cert_enumerate;
|
||||
enumerator->public.destroy = (void*)cert_enumerator_destroy;
|
||||
enumerator->cert = cert;
|
||||
enumerator->key = key;
|
||||
enumerator->id = id;
|
||||
enumerator->relations = this->relations;
|
||||
enumerator->index = -1;
|
||||
enumerator->locked = -1;
|
||||
|
||||
return &enumerator->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of cert_cache_t.flush.
|
||||
*/
|
||||
static void flush(private_cert_cache_t *this, certificate_type_t type)
|
||||
{
|
||||
relation_t *rel;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
rel = &this->relations[i];
|
||||
if (!rel->subject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* check with cheap read lock first */
|
||||
if (type != CERT_ANY)
|
||||
{
|
||||
rel->lock->read_lock(rel->lock);
|
||||
if (!rel->subject || type != rel->subject->get_type(rel->subject))
|
||||
{
|
||||
rel->lock->unlock(rel->lock);
|
||||
continue;
|
||||
}
|
||||
rel->lock->unlock(rel->lock);
|
||||
}
|
||||
/* double check in write lock */
|
||||
rel->lock->write_lock(rel->lock);
|
||||
if (rel->subject)
|
||||
{
|
||||
if (type == CERT_ANY || type == rel->subject->get_type(rel->subject))
|
||||
{
|
||||
rel->subject->destroy(rel->subject);
|
||||
rel->issuer->destroy(rel->issuer);
|
||||
rel->subject = NULL;
|
||||
rel->issuer = NULL;
|
||||
rel->hits = 0;
|
||||
}
|
||||
}
|
||||
rel->lock->unlock(rel->lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of cert_cache_t.destroy
|
||||
*/
|
||||
static void destroy(private_cert_cache_t *this)
|
||||
{
|
||||
relation_t *rel;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
rel = &this->relations[i];
|
||||
if (rel->subject)
|
||||
{
|
||||
rel->subject->destroy(rel->subject);
|
||||
rel->issuer->destroy(rel->issuer);
|
||||
}
|
||||
rel->lock->destroy(rel->lock);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
cert_cache_t *cert_cache_create()
|
||||
{
|
||||
private_cert_cache_t *this;
|
||||
int i;
|
||||
|
||||
this = malloc_thing(private_cert_cache_t);
|
||||
this->public.set.create_private_enumerator = (void*)return_null;
|
||||
this->public.set.create_cert_enumerator = (void*)create_enumerator;
|
||||
this->public.set.create_shared_enumerator = (void*)return_null;
|
||||
this->public.set.create_cdp_enumerator = (void*)return_null;
|
||||
this->public.set.cache_cert = (void*)nop;
|
||||
this->public.issued_by = (bool(*)(cert_cache_t*, certificate_t *subject, certificate_t *issuer))issued_by;
|
||||
this->public.flush = (void(*)(cert_cache_t*, certificate_type_t type))flush;
|
||||
this->public.destroy = (void(*)(cert_cache_t*))destroy;
|
||||
|
||||
for (i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
this->relations[i].subject = NULL;
|
||||
this->relations[i].issuer = NULL;
|
||||
this->relations[i].hits = 0;
|
||||
this->relations[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup cert_cache cert_cache
|
||||
* @{ @ingroup sets
|
||||
*/
|
||||
|
||||
#ifndef CERT_CACHE_H_
|
||||
#define CERT_CACHE_H_
|
||||
|
||||
#include <credentials/credential_set.h>
|
||||
|
||||
typedef struct cert_cache_t cert_cache_t;
|
||||
|
||||
/**
|
||||
* Certificate signature verification and certificate cache.
|
||||
*
|
||||
* This cache serves all certificates seen in its issued_by method
|
||||
* and serves them as untrusted through the credential set interface. Further,
|
||||
* it caches valid subject-issuer relationships to speed up the issued_by
|
||||
* method.
|
||||
*/
|
||||
struct cert_cache_t {
|
||||
|
||||
/**
|
||||
* Implements credential_set_t.
|
||||
*/
|
||||
credential_set_t set;
|
||||
|
||||
/**
|
||||
* Caching wrapper around certificate_t.issued_by.
|
||||
*
|
||||
* @param subject certificate to verify
|
||||
* @param issuer issuing certificate to verify subject
|
||||
* @return TRUE if subject issued by issuer
|
||||
*/
|
||||
bool (*issued_by)(cert_cache_t *this,
|
||||
certificate_t *subject, certificate_t *issuer);
|
||||
|
||||
/**
|
||||
* Flush the certificate cache.
|
||||
*
|
||||
* @param type type of certificate to flush, or CERT_ANY
|
||||
*/
|
||||
void (*flush)(cert_cache_t *this, certificate_type_t type);
|
||||
|
||||
/**
|
||||
* Destroy a cert_cache instance.
|
||||
*/
|
||||
void (*destroy)(cert_cache_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a cert_cache instance.
|
||||
*/
|
||||
cert_cache_t *cert_cache_create();
|
||||
|
||||
#endif /** CERT_CACHE_H_ @}*/
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "ocsp_response_wrapper.h"
|
||||
|
||||
typedef struct private_ocsp_response_wrapper_t private_ocsp_response_wrapper_t;
|
||||
|
||||
/**
|
||||
* private data of ocsp_response_wrapper
|
||||
*/
|
||||
struct private_ocsp_response_wrapper_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
ocsp_response_wrapper_t public;
|
||||
|
||||
/**
|
||||
* wrapped OCSP response
|
||||
*/
|
||||
ocsp_response_t *response;
|
||||
};
|
||||
|
||||
/**
|
||||
* enumerator for ocsp_response_wrapper_t.create_cert_enumerator()
|
||||
*/
|
||||
typedef struct {
|
||||
/** implements enumerator_t */
|
||||
enumerator_t public;
|
||||
/** enumerator over ocsp response */
|
||||
enumerator_t *inner;
|
||||
/** type of cert */
|
||||
certificate_type_t cert;
|
||||
/** type of key */
|
||||
key_type_t key;
|
||||
/** filtering identity */
|
||||
identification_t *id;
|
||||
} wrapper_enumerator_t;
|
||||
|
||||
/**
|
||||
* enumerate function wrapper_enumerator_t
|
||||
*/
|
||||
static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
|
||||
{
|
||||
certificate_t *current;
|
||||
public_key_t *public;
|
||||
|
||||
while (this->inner->enumerate(this->inner, ¤t))
|
||||
{
|
||||
if (this->cert != CERT_ANY && this->cert != current->get_type(current))
|
||||
{ /* CERT type requested, but does not match */
|
||||
continue;
|
||||
}
|
||||
public = current->get_public_key(current);
|
||||
if (this->key != KEY_ANY && !public)
|
||||
{ /* key type requested, but no public key */
|
||||
DESTROY_IF(public);
|
||||
continue;
|
||||
}
|
||||
if (this->key != KEY_ANY && public && this->key != public->get_type(public))
|
||||
{ /* key type requested, but public key has another type */
|
||||
DESTROY_IF(public);
|
||||
continue;
|
||||
}
|
||||
DESTROY_IF(public);
|
||||
if (this->id && !current->has_subject(current, this->id))
|
||||
{ /* subject requested, but does not match */
|
||||
continue;
|
||||
}
|
||||
*cert = current;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy function for wrapper_enumerator_t
|
||||
*/
|
||||
static void enumerator_destroy(wrapper_enumerator_t *this)
|
||||
{
|
||||
this->inner->destroy(this->inner);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* implementation of ocsp_response_wrapper_t.set.create_cert_enumerator
|
||||
*/
|
||||
static enumerator_t *create_enumerator(private_ocsp_response_wrapper_t *this,
|
||||
certificate_type_t cert, key_type_t key,
|
||||
identification_t *id, bool trusted)
|
||||
{
|
||||
wrapper_enumerator_t *enumerator;
|
||||
|
||||
if (trusted)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enumerator = malloc_thing(wrapper_enumerator_t);
|
||||
enumerator->cert = cert;
|
||||
enumerator->key = key;
|
||||
enumerator->id = id;
|
||||
enumerator->inner = this->response->create_cert_enumerator(this->response);
|
||||
enumerator->public.enumerate = (void*)enumerate;
|
||||
enumerator->public.destroy = (void*)enumerator_destroy;
|
||||
return &enumerator->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ocsp_response_wrapper_t.destroy
|
||||
*/
|
||||
static void destroy(private_ocsp_response_wrapper_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
ocsp_response_wrapper_t *ocsp_response_wrapper_create(ocsp_response_t *response)
|
||||
{
|
||||
private_ocsp_response_wrapper_t *this = malloc_thing(private_ocsp_response_wrapper_t);
|
||||
|
||||
this->public.set.create_private_enumerator = (void*)return_null;
|
||||
this->public.set.create_cert_enumerator = (void*)create_enumerator;
|
||||
this->public.set.create_shared_enumerator = (void*)return_null;
|
||||
this->public.set.create_cdp_enumerator = (void*)return_null;
|
||||
this->public.set.cache_cert = (void*)nop;
|
||||
this->public.destroy = (void(*)(ocsp_response_wrapper_t*))destroy;
|
||||
|
||||
this->response = response;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ocsp_response_wrapper ocsp_response_wrapper
|
||||
* @{ @ingroup sets
|
||||
*/
|
||||
|
||||
#ifndef OCSP_RESPONSE_WRAPPER_H_
|
||||
#define OCSP_RESPONSE_WRAPPER_H_
|
||||
|
||||
#include <credentials/credential_set.h>
|
||||
#include <credentials/certificates/ocsp_response.h>
|
||||
|
||||
typedef struct ocsp_response_wrapper_t ocsp_response_wrapper_t;
|
||||
|
||||
/**
|
||||
* A wrapper around ocsp_response_t to handle it like a credential set.
|
||||
*/
|
||||
struct ocsp_response_wrapper_t {
|
||||
|
||||
/**
|
||||
* implements credential_set_t
|
||||
*/
|
||||
credential_set_t set;
|
||||
|
||||
/**
|
||||
* Destroy a ocsp_response_wrapper instance.
|
||||
*/
|
||||
void (*destroy)(ocsp_response_wrapper_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a ocsp_response_wrapper instance.
|
||||
*
|
||||
* @param response the wrapped OCSP response
|
||||
* @return wrapper around response
|
||||
*/
|
||||
ocsp_response_wrapper_t *ocsp_response_wrapper_create(ocsp_response_t *response);
|
||||
|
||||
#endif /** OCSP_RESPONSE_WRAPPER_H_ @}*/
|
||||
Reference in New Issue
Block a user