Moving charon to libcharon.
This commit is contained in:
@@ -0,0 +1,768 @@
|
||||
/*
|
||||
* 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 <daemon.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/identification.h>
|
||||
#include <credentials/certificates/certificate.h>
|
||||
|
||||
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_AC_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_AC_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_AC_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_AC_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_AC_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;
|
||||
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_AC_GROUP:
|
||||
{
|
||||
success = FALSE;
|
||||
if (log_error)
|
||||
{
|
||||
DBG1(DBG_CFG, "constraint check %N not implemented!",
|
||||
auth_rule_names, t1);
|
||||
}
|
||||
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);
|
||||
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_AC_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_AC_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_AC_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,201 @@
|
||||
/*
|
||||
* 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 config
|
||||
*/
|
||||
|
||||
#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;
|
||||
|
||||
/**
|
||||
* 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 in attribute certificate group, identification_t* */
|
||||
AUTH_RULE_AC_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_ @}*/
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2007-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 backend backend
|
||||
* @{ @ingroup config
|
||||
*/
|
||||
|
||||
#ifndef BACKEND_H_
|
||||
#define BACKEND_H_
|
||||
|
||||
typedef struct backend_t backend_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <config/ike_cfg.h>
|
||||
#include <config/peer_cfg.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
/**
|
||||
* The interface for a configuration backend.
|
||||
*
|
||||
* A configuration backend is loaded into the backend_manager. It does the actual
|
||||
* configuration lookup for the method it implements. See backend_manager_t for
|
||||
* more information.
|
||||
*/
|
||||
struct backend_t {
|
||||
|
||||
/**
|
||||
* Create an enumerator over all IKE configs matching two hosts.
|
||||
*
|
||||
* Hosts may be NULL to get all.
|
||||
*
|
||||
* There is no requirement for the backend to filter the configurations
|
||||
* using the supplied hosts; but it may do so if it increases lookup times
|
||||
* (e.g. include hosts in SQL query).
|
||||
*
|
||||
* @param me address of local host
|
||||
* @param other address of remote host
|
||||
* @return enumerator over ike_cfg_t's
|
||||
*/
|
||||
enumerator_t* (*create_ike_cfg_enumerator)(backend_t *this,
|
||||
host_t *me, host_t *other);
|
||||
/**
|
||||
* Create an enumerator over all peer configs matching two identities.
|
||||
*
|
||||
* IDs may be NULL to get all.
|
||||
*
|
||||
* As configurations are looked up in the first authentication round (when
|
||||
* multiple authentication), the backend implementation should compare
|
||||
* the identities to the first auth_cfgs only.
|
||||
* There is no requirement for the backend to filter the configurations
|
||||
* using the supplied identities; but it may do so if it increases lookup
|
||||
* times (e.g. include hosts in SQL query).
|
||||
*
|
||||
* @param me identity of ourself
|
||||
* @param other identity of remote host
|
||||
* @return enumerator over peer_cfg_t
|
||||
*/
|
||||
enumerator_t* (*create_peer_cfg_enumerator)(backend_t *this,
|
||||
identification_t *me,
|
||||
identification_t *other);
|
||||
/**
|
||||
* Get a peer_cfg identified by it's name, or a name of its children.
|
||||
*
|
||||
* @param name name of peer/child cfg
|
||||
* @return matching peer_config, or NULL if none found
|
||||
*/
|
||||
peer_cfg_t *(*get_peer_cfg_by_name)(backend_t *this, char *name);
|
||||
};
|
||||
|
||||
#endif /** BACKEND_H_ @}*/
|
||||
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "backend_manager.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <threading/rwlock.h>
|
||||
|
||||
|
||||
typedef struct private_backend_manager_t private_backend_manager_t;
|
||||
|
||||
/**
|
||||
* Private data of an backend_manager_t object.
|
||||
*/
|
||||
struct private_backend_manager_t {
|
||||
|
||||
/**
|
||||
* Public part of backend_manager_t object.
|
||||
*/
|
||||
backend_manager_t public;
|
||||
|
||||
/**
|
||||
* list of registered backends
|
||||
*/
|
||||
linked_list_t *backends;
|
||||
|
||||
/**
|
||||
* rwlock for backends
|
||||
*/
|
||||
rwlock_t *lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* match of an ike_cfg
|
||||
*/
|
||||
typedef enum ike_cfg_match_t {
|
||||
MATCH_NONE = 0x00,
|
||||
MATCH_ANY = 0x01,
|
||||
MATCH_ME = 0x04,
|
||||
MATCH_OTHER = 0x08,
|
||||
} ike_cfg_match_t;
|
||||
|
||||
/**
|
||||
* data to pass nested IKE enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
private_backend_manager_t *this;
|
||||
host_t *me;
|
||||
host_t *other;
|
||||
} ike_data_t;
|
||||
|
||||
/**
|
||||
* inner enumerator constructor for IKE cfgs
|
||||
*/
|
||||
static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data)
|
||||
{
|
||||
return backend->create_ike_cfg_enumerator(backend, data->me, data->other);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a match of a candidate ike_cfg for two hosts
|
||||
*/
|
||||
static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other)
|
||||
{
|
||||
host_t *me_cand, *other_cand;
|
||||
ike_cfg_match_t match = MATCH_NONE;
|
||||
|
||||
if (me)
|
||||
{
|
||||
me_cand = host_create_from_dns(cand->get_my_addr(cand),
|
||||
me->get_family(me), 0);
|
||||
if (!me_cand)
|
||||
{
|
||||
return MATCH_NONE;
|
||||
}
|
||||
if (me_cand->ip_equals(me_cand, me))
|
||||
{
|
||||
match += MATCH_ME;
|
||||
}
|
||||
else if (me_cand->is_anyaddr(me_cand))
|
||||
{
|
||||
match += MATCH_ANY;
|
||||
}
|
||||
me_cand->destroy(me_cand);
|
||||
}
|
||||
else
|
||||
{
|
||||
match += MATCH_ANY;
|
||||
}
|
||||
|
||||
if (other)
|
||||
{
|
||||
other_cand = host_create_from_dns(cand->get_other_addr(cand),
|
||||
other->get_family(other), 0);
|
||||
if (!other_cand)
|
||||
{
|
||||
return MATCH_NONE;
|
||||
}
|
||||
if (other_cand->ip_equals(other_cand, other))
|
||||
{
|
||||
match += MATCH_OTHER;
|
||||
}
|
||||
else if (other_cand->is_anyaddr(other_cand))
|
||||
{
|
||||
match += MATCH_ANY;
|
||||
}
|
||||
other_cand->destroy(other_cand);
|
||||
}
|
||||
else
|
||||
{
|
||||
match += MATCH_ANY;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* implements backend_manager_t.get_ike_cfg.
|
||||
*/
|
||||
static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this,
|
||||
host_t *me, host_t *other)
|
||||
{
|
||||
ike_cfg_t *current, *found = NULL;
|
||||
enumerator_t *enumerator;
|
||||
ike_cfg_match_t match, best = MATCH_ANY;
|
||||
ike_data_t *data;
|
||||
|
||||
data = malloc_thing(ike_data_t);
|
||||
data->this = this;
|
||||
data->me = me;
|
||||
data->other = other;
|
||||
|
||||
DBG2(DBG_CFG, "looking for an ike config for %H...%H", me, other);
|
||||
|
||||
this->lock->read_lock(this->lock);
|
||||
enumerator = enumerator_create_nested(
|
||||
this->backends->create_enumerator(this->backends),
|
||||
(void*)ike_enum_create, data, (void*)free);
|
||||
while (enumerator->enumerate(enumerator, (void**)¤t))
|
||||
{
|
||||
match = get_ike_match(current, me, other);
|
||||
|
||||
if (match)
|
||||
{
|
||||
DBG2(DBG_CFG, " candidate: %s...%s, prio %d",
|
||||
current->get_my_addr(current),
|
||||
current->get_other_addr(current), match);
|
||||
if (match > best)
|
||||
{
|
||||
DESTROY_IF(found);
|
||||
found = current;
|
||||
found->get_ref(found);
|
||||
best = match;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
this->lock->unlock(this->lock);
|
||||
if (found)
|
||||
{
|
||||
DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d",
|
||||
found->get_my_addr(found), found->get_other_addr(found), best);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the best ID match in one of the configs auth_cfg
|
||||
*/
|
||||
static id_match_t get_peer_match(identification_t *id,
|
||||
peer_cfg_t *cfg, bool local)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
auth_cfg_t *auth;
|
||||
identification_t *candidate;
|
||||
id_match_t match = ID_MATCH_NONE;
|
||||
|
||||
if (!id)
|
||||
{
|
||||
return ID_MATCH_ANY;
|
||||
}
|
||||
|
||||
/* compare first auth config only */
|
||||
enumerator = cfg->create_auth_cfg_enumerator(cfg, local);
|
||||
if (enumerator->enumerate(enumerator, &auth))
|
||||
{
|
||||
candidate = auth->get(auth, AUTH_RULE_IDENTITY);
|
||||
if (candidate)
|
||||
{
|
||||
match = id->matches(id, candidate);
|
||||
/* match vice-versa, as the proposed IDr might be ANY */
|
||||
if (!match)
|
||||
{
|
||||
match = candidate->matches(candidate, id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match = ID_MATCH_ANY;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* data to pass nested peer enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
rwlock_t *lock;
|
||||
identification_t *me;
|
||||
identification_t *other;
|
||||
} peer_data_t;
|
||||
|
||||
/**
|
||||
* list element to help sorting
|
||||
*/
|
||||
typedef struct {
|
||||
id_match_t match_peer;
|
||||
ike_cfg_match_t match_ike;
|
||||
peer_cfg_t *cfg;
|
||||
} match_entry_t;
|
||||
|
||||
/**
|
||||
* inner enumerator constructor for peer cfgs
|
||||
*/
|
||||
static enumerator_t *peer_enum_create(backend_t *backend, peer_data_t *data)
|
||||
{
|
||||
return backend->create_peer_cfg_enumerator(backend, data->me, data->other);
|
||||
}
|
||||
|
||||
/**
|
||||
* unlock/cleanup peer enumerator
|
||||
*/
|
||||
static void peer_enum_destroy(peer_data_t *data)
|
||||
{
|
||||
data->lock->unlock(data->lock);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert enumerator value from match_entry to config
|
||||
*/
|
||||
static bool peer_enum_filter(linked_list_t *configs,
|
||||
match_entry_t **in, peer_cfg_t **out)
|
||||
{
|
||||
*out = (*in)->cfg;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up temporary config list
|
||||
*/
|
||||
static void peer_enum_filter_destroy(linked_list_t *configs)
|
||||
{
|
||||
match_entry_t *entry;
|
||||
|
||||
while (configs->remove_last(configs, (void**)&entry) == SUCCESS)
|
||||
{
|
||||
entry->cfg->destroy(entry->cfg);
|
||||
free(entry);
|
||||
}
|
||||
configs->destroy(configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert entry into match-sorted list, using helper
|
||||
*/
|
||||
static void insert_sorted(match_entry_t *entry, linked_list_t *list,
|
||||
linked_list_t *helper)
|
||||
{
|
||||
match_entry_t *current;
|
||||
|
||||
while (list->remove_first(list, (void**)¤t) == SUCCESS)
|
||||
{
|
||||
helper->insert_last(helper, current);
|
||||
}
|
||||
while (helper->remove_first(helper, (void**)¤t) == SUCCESS)
|
||||
{
|
||||
if (entry && (
|
||||
(entry->match_ike > current->match_ike &&
|
||||
entry->match_peer >= current->match_peer) ||
|
||||
(entry->match_ike >= current->match_ike &&
|
||||
entry->match_peer > current->match_peer)))
|
||||
{
|
||||
list->insert_last(list, entry);
|
||||
entry = NULL;
|
||||
}
|
||||
list->insert_last(list, current);
|
||||
}
|
||||
if (entry)
|
||||
{
|
||||
list->insert_last(list, entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements backend_manager_t.create_peer_cfg_enumerator.
|
||||
*/
|
||||
static enumerator_t *create_peer_cfg_enumerator(private_backend_manager_t *this,
|
||||
host_t *me, host_t *other, identification_t *my_id,
|
||||
identification_t *other_id)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
peer_data_t *data;
|
||||
peer_cfg_t *cfg;
|
||||
linked_list_t *configs, *helper;
|
||||
|
||||
data = malloc_thing(peer_data_t);
|
||||
data->lock = this->lock;
|
||||
data->me = my_id;
|
||||
data->other = other_id;
|
||||
|
||||
/* create a sorted list with all matches */
|
||||
this->lock->read_lock(this->lock);
|
||||
enumerator = enumerator_create_nested(
|
||||
this->backends->create_enumerator(this->backends),
|
||||
(void*)peer_enum_create, data, (void*)peer_enum_destroy);
|
||||
|
||||
if (!me && !other && !my_id && !other_id)
|
||||
{ /* shortcut if we are doing a "listall" */
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]",
|
||||
me, my_id, other, other_id);
|
||||
|
||||
configs = linked_list_create();
|
||||
/* only once allocated helper list for sorting */
|
||||
helper = linked_list_create();
|
||||
while (enumerator->enumerate(enumerator, &cfg))
|
||||
{
|
||||
id_match_t match_peer_me, match_peer_other;
|
||||
ike_cfg_match_t match_ike;
|
||||
match_entry_t *entry;
|
||||
|
||||
match_peer_me = get_peer_match(my_id, cfg, TRUE);
|
||||
match_peer_other = get_peer_match(other_id, cfg, FALSE);
|
||||
match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other);
|
||||
|
||||
if (match_peer_me && match_peer_other && match_ike)
|
||||
{
|
||||
DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)",
|
||||
cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike);
|
||||
|
||||
entry = malloc_thing(match_entry_t);
|
||||
entry->match_peer = match_peer_me + match_peer_other;
|
||||
entry->match_ike = match_ike;
|
||||
entry->cfg = cfg->get_ref(cfg);
|
||||
insert_sorted(entry, configs, helper);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
helper->destroy(helper);
|
||||
|
||||
return enumerator_create_filter(configs->create_enumerator(configs),
|
||||
(void*)peer_enum_filter, configs,
|
||||
(void*)peer_enum_filter_destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* implements backend_manager_t.get_peer_cfg_by_name.
|
||||
*/
|
||||
static peer_cfg_t *get_peer_cfg_by_name(private_backend_manager_t *this, char *name)
|
||||
{
|
||||
backend_t *backend;
|
||||
peer_cfg_t *config = NULL;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
this->lock->read_lock(this->lock);
|
||||
enumerator = this->backends->create_enumerator(this->backends);
|
||||
while (config == NULL && enumerator->enumerate(enumerator, (void**)&backend))
|
||||
{
|
||||
config = backend->get_peer_cfg_by_name(backend, name);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
this->lock->unlock(this->lock);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of backend_manager_t.remove_backend.
|
||||
*/
|
||||
static void remove_backend(private_backend_manager_t *this, backend_t *backend)
|
||||
{
|
||||
this->lock->write_lock(this->lock);
|
||||
this->backends->remove(this->backends, backend, NULL);
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of backend_manager_t.add_backend.
|
||||
*/
|
||||
static void add_backend(private_backend_manager_t *this, backend_t *backend)
|
||||
{
|
||||
this->lock->write_lock(this->lock);
|
||||
this->backends->insert_last(this->backends, backend);
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of backend_manager_t.destroy.
|
||||
*/
|
||||
static void destroy(private_backend_manager_t *this)
|
||||
{
|
||||
this->backends->destroy(this->backends);
|
||||
this->lock->destroy(this->lock);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header-file
|
||||
*/
|
||||
backend_manager_t *backend_manager_create()
|
||||
{
|
||||
private_backend_manager_t *this = malloc_thing(private_backend_manager_t);
|
||||
|
||||
this->public.get_ike_cfg = (ike_cfg_t* (*)(backend_manager_t*, host_t*, host_t*))get_ike_cfg;
|
||||
this->public.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_manager_t*,char*))get_peer_cfg_by_name;
|
||||
this->public.create_peer_cfg_enumerator = (enumerator_t* (*)(backend_manager_t*,host_t*,host_t*,identification_t*,identification_t*))create_peer_cfg_enumerator;
|
||||
this->public.add_backend = (void(*)(backend_manager_t*, backend_t *backend))add_backend;
|
||||
this->public.remove_backend = (void(*)(backend_manager_t*, backend_t *backend))remove_backend;
|
||||
this->public.destroy = (void (*)(backend_manager_t*))destroy;
|
||||
|
||||
this->backends = linked_list_create();
|
||||
this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 backend_manager backend_manager
|
||||
* @{ @ingroup config
|
||||
*/
|
||||
|
||||
#ifndef BACKEND_MANAGER_H_
|
||||
#define BACKEND_MANAGER_H_
|
||||
|
||||
typedef struct backend_manager_t backend_manager_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/host.h>
|
||||
#include <utils/identification.h>
|
||||
#include <config/ike_cfg.h>
|
||||
#include <config/peer_cfg.h>
|
||||
#include <config/backend.h>
|
||||
|
||||
|
||||
/**
|
||||
* A loader and multiplexer to use multiple backends.
|
||||
*
|
||||
* Charon allows the use of multiple configuration backends simultaneously. To
|
||||
* access all this backends by a single call, this class wraps multiple
|
||||
* backends behind a single object.
|
||||
* @verbatim
|
||||
|
||||
+---------+ +-----------+ +--------------+ |
|
||||
| | | | +--------------+ | |
|
||||
| daemon |----->| backend_- | +--------------+ |-+ <==|==> IPC
|
||||
| core | | manager |---->| backends |-+ |
|
||||
| |----->| | +--------------+ |
|
||||
| | | | |
|
||||
+---------+ +-----------+ |
|
||||
|
||||
@endverbatim
|
||||
*/
|
||||
struct backend_manager_t {
|
||||
|
||||
/**
|
||||
* Get an ike_config identified by two hosts.
|
||||
*
|
||||
* @param my_host address of own host
|
||||
* @param other_host address of remote host
|
||||
* @return matching ike_config, or NULL if none found
|
||||
*/
|
||||
ike_cfg_t* (*get_ike_cfg)(backend_manager_t *this,
|
||||
host_t *my_host, host_t *other_host);
|
||||
|
||||
/**
|
||||
* Get a peer_config identified by it's name.
|
||||
*
|
||||
* @param name name of the peer_config
|
||||
* @return matching peer_config, or NULL if none found
|
||||
*/
|
||||
peer_cfg_t* (*get_peer_cfg_by_name)(backend_manager_t *this, char *name);
|
||||
|
||||
/**
|
||||
* Create an enumerator over all matching peer configs.
|
||||
*
|
||||
* Pass NULL as parameters to match any. The enumerator enumerates over
|
||||
* peer_cfgs, ordered by priority (best match first).
|
||||
*
|
||||
* @param me local address
|
||||
* @param other remote address
|
||||
* @param my_id IDr in first authentication round
|
||||
* @param other_id IDi in first authentication round
|
||||
* @return enumerator over peer_cfg_t
|
||||
*/
|
||||
enumerator_t* (*create_peer_cfg_enumerator)(backend_manager_t *this,
|
||||
host_t *me, host_t *other, identification_t *my_id,
|
||||
identification_t *other_id);
|
||||
/**
|
||||
* Register a backend on the manager.
|
||||
*
|
||||
* @param backend backend to register
|
||||
*/
|
||||
void (*add_backend)(backend_manager_t *this, backend_t *backend);
|
||||
|
||||
/**
|
||||
* Unregister a backend.
|
||||
*
|
||||
* @param backend backend to unregister
|
||||
*/
|
||||
void (*remove_backend)(backend_manager_t *this, backend_t *backend);
|
||||
|
||||
/**
|
||||
* Destroys a backend_manager_t object.
|
||||
*/
|
||||
void (*destroy) (backend_manager_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an instance of the backend manager
|
||||
*
|
||||
* @return backend_manager instance
|
||||
*/
|
||||
backend_manager_t* backend_manager_create(void);
|
||||
|
||||
#endif /** BACKEND_MANAGER_H_ @}*/
|
||||
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2009 Tobias Brunner
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 "child_cfg.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
ENUM(action_names, ACTION_NONE, ACTION_RESTART,
|
||||
"clear",
|
||||
"hold",
|
||||
"restart",
|
||||
);
|
||||
|
||||
ENUM_BEGIN(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_NONE,
|
||||
"IPCOMP_NONE");
|
||||
ENUM_NEXT(ipcomp_transform_names, IPCOMP_OUI, IPCOMP_LZJH, IPCOMP_NONE,
|
||||
"IPCOMP_OUI",
|
||||
"IPCOMP_DEFLATE",
|
||||
"IPCOMP_LZS",
|
||||
"IPCOMP_LZJH");
|
||||
ENUM_END(ipcomp_transform_names, IPCOMP_LZJH);
|
||||
|
||||
typedef struct private_child_cfg_t private_child_cfg_t;
|
||||
|
||||
/**
|
||||
* Private data of an child_cfg_t object
|
||||
*/
|
||||
struct private_child_cfg_t {
|
||||
|
||||
/**
|
||||
* Public part
|
||||
*/
|
||||
child_cfg_t public;
|
||||
|
||||
/**
|
||||
* Number of references hold by others to this child_cfg
|
||||
*/
|
||||
refcount_t refcount;
|
||||
|
||||
/**
|
||||
* Name of the child_cfg, used to query it
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* list for all proposals
|
||||
*/
|
||||
linked_list_t *proposals;
|
||||
|
||||
/**
|
||||
* list for traffic selectors for my site
|
||||
*/
|
||||
linked_list_t *my_ts;
|
||||
|
||||
/**
|
||||
* list for traffic selectors for others site
|
||||
*/
|
||||
linked_list_t *other_ts;
|
||||
|
||||
/**
|
||||
* updown script
|
||||
*/
|
||||
char *updown;
|
||||
|
||||
/**
|
||||
* allow host access
|
||||
*/
|
||||
bool hostaccess;
|
||||
|
||||
/**
|
||||
* Mode to propose for a initiated CHILD: tunnel/transport
|
||||
*/
|
||||
ipsec_mode_t mode;
|
||||
|
||||
/**
|
||||
* action to take on DPD
|
||||
*/
|
||||
action_t dpd_action;
|
||||
|
||||
/**
|
||||
* action to take on CHILD_SA close
|
||||
*/
|
||||
action_t close_action;
|
||||
|
||||
/**
|
||||
* CHILD_SA lifetime config
|
||||
*/
|
||||
lifetime_cfg_t lifetime;
|
||||
|
||||
/**
|
||||
* enable IPComp
|
||||
*/
|
||||
bool use_ipcomp;
|
||||
|
||||
/**
|
||||
* Inactivity timeout
|
||||
*/
|
||||
u_int32_t inactivity;
|
||||
|
||||
/**
|
||||
* set up IPsec transport SA in MIPv6 proxy mode
|
||||
*/
|
||||
bool proxy_mode;
|
||||
|
||||
/**
|
||||
* enable installation and removal of kernel IPsec policies
|
||||
*/
|
||||
bool install_policy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_name.
|
||||
*/
|
||||
static char *get_name(private_child_cfg_t *this)
|
||||
{
|
||||
return this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.add_proposal.
|
||||
*/
|
||||
static void add_proposal(private_child_cfg_t *this, proposal_t *proposal)
|
||||
{
|
||||
this->proposals->insert_last(this->proposals, proposal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_proposals.
|
||||
*/
|
||||
static linked_list_t* get_proposals(private_child_cfg_t *this, bool strip_dh)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
proposal_t *current;
|
||||
linked_list_t *proposals = linked_list_create();
|
||||
|
||||
enumerator = this->proposals->create_enumerator(this->proposals);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
current = current->clone(current);
|
||||
if (strip_dh)
|
||||
{
|
||||
current->strip_dh(current);
|
||||
}
|
||||
proposals->insert_last(proposals, current);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return proposals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.select_proposal.
|
||||
*/
|
||||
static proposal_t* select_proposal(private_child_cfg_t*this,
|
||||
linked_list_t *proposals, bool strip_dh,
|
||||
bool private)
|
||||
{
|
||||
enumerator_t *stored_enum, *supplied_enum;
|
||||
proposal_t *stored, *supplied, *selected = NULL;
|
||||
|
||||
stored_enum = this->proposals->create_enumerator(this->proposals);
|
||||
supplied_enum = proposals->create_enumerator(proposals);
|
||||
|
||||
/* compare all stored proposals with all supplied. Stored ones are preferred. */
|
||||
while (stored_enum->enumerate(stored_enum, &stored))
|
||||
{
|
||||
stored = stored->clone(stored);
|
||||
while (supplied_enum->enumerate(supplied_enum, &supplied))
|
||||
{
|
||||
if (strip_dh)
|
||||
{
|
||||
stored->strip_dh(stored);
|
||||
}
|
||||
selected = stored->select(stored, supplied, private);
|
||||
if (selected)
|
||||
{
|
||||
DBG2(DBG_CFG, "received proposals: %#P", proposals);
|
||||
DBG2(DBG_CFG, "configured proposals: %#P", this->proposals);
|
||||
DBG2(DBG_CFG, "selected proposal: %P", selected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
stored->destroy(stored);
|
||||
if (selected)
|
||||
{
|
||||
break;
|
||||
}
|
||||
supplied_enum->destroy(supplied_enum);
|
||||
supplied_enum = proposals->create_enumerator(proposals);
|
||||
}
|
||||
stored_enum->destroy(stored_enum);
|
||||
supplied_enum->destroy(supplied_enum);
|
||||
if (selected == NULL)
|
||||
{
|
||||
DBG1(DBG_CFG, "received proposals: %#P", proposals);
|
||||
DBG1(DBG_CFG, "configured proposals: %#P", this->proposals);
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.add_traffic_selector.
|
||||
*/
|
||||
static void add_traffic_selector(private_child_cfg_t *this, bool local,
|
||||
traffic_selector_t *ts)
|
||||
{
|
||||
if (local)
|
||||
{
|
||||
this->my_ts->insert_last(this->my_ts, ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->other_ts->insert_last(this->other_ts, ts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_traffic_selectors.
|
||||
*/
|
||||
static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool local,
|
||||
linked_list_t *supplied,
|
||||
host_t *host)
|
||||
{
|
||||
enumerator_t *e1, *e2;
|
||||
traffic_selector_t *ts1, *ts2, *selected;
|
||||
linked_list_t *result = linked_list_create();
|
||||
|
||||
if (local)
|
||||
{
|
||||
e1 = this->my_ts->create_enumerator(this->my_ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
e1 = this->other_ts->create_enumerator(this->other_ts);
|
||||
}
|
||||
|
||||
/* no list supplied, just fetch the stored traffic selectors */
|
||||
if (supplied == NULL)
|
||||
{
|
||||
DBG2(DBG_CFG, "proposing traffic selectors for %s:",
|
||||
local ? "us" : "other");
|
||||
while (e1->enumerate(e1, &ts1))
|
||||
{
|
||||
/* we make a copy of the TS, this allows us to update dynamic TS' */
|
||||
selected = ts1->clone(ts1);
|
||||
if (host)
|
||||
{
|
||||
selected->set_address(selected, host);
|
||||
}
|
||||
DBG2(DBG_CFG, " %R (derived from %R)", selected, ts1);
|
||||
result->insert_last(result, selected);
|
||||
}
|
||||
e1->destroy(e1);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG2(DBG_CFG, "selecting traffic selectors for %s:",
|
||||
local ? "us" : "other");
|
||||
e2 = supplied->create_enumerator(supplied);
|
||||
/* iterate over all stored selectors */
|
||||
while (e1->enumerate(e1, &ts1))
|
||||
{
|
||||
/* we make a copy of the TS, as we have to update dynamic TS' */
|
||||
ts1 = ts1->clone(ts1);
|
||||
if (host)
|
||||
{
|
||||
ts1->set_address(ts1, host);
|
||||
}
|
||||
|
||||
/* iterate over all supplied traffic selectors */
|
||||
while (e2->enumerate(e2, &ts2))
|
||||
{
|
||||
selected = ts1->get_subset(ts1, ts2);
|
||||
if (selected)
|
||||
{
|
||||
DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
|
||||
ts1, ts2, selected);
|
||||
result->insert_last(result, selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG2(DBG_CFG, " config: %R, received: %R => no match",
|
||||
ts1, ts2);
|
||||
}
|
||||
}
|
||||
e2->destroy(e2);
|
||||
e2 = supplied->create_enumerator(supplied);
|
||||
ts1->destroy(ts1);
|
||||
}
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
}
|
||||
|
||||
/* remove any redundant traffic selectors in the list */
|
||||
e1 = result->create_enumerator(result);
|
||||
e2 = result->create_enumerator(result);
|
||||
while (e1->enumerate(e1, &ts1))
|
||||
{
|
||||
while (e2->enumerate(e2, &ts2))
|
||||
{
|
||||
if (ts1 != ts2)
|
||||
{
|
||||
if (ts2->is_contained_in(ts2, ts1))
|
||||
{
|
||||
result->remove_at(result, e2);
|
||||
ts2->destroy(ts2);
|
||||
e1->destroy(e1);
|
||||
e1 = result->create_enumerator(result);
|
||||
break;
|
||||
}
|
||||
if (ts1->is_contained_in(ts1, ts2))
|
||||
{
|
||||
result->remove_at(result, e1);
|
||||
ts1->destroy(ts1);
|
||||
e2->destroy(e2);
|
||||
e2 = result->create_enumerator(result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_updown.
|
||||
*/
|
||||
static char* get_updown(private_child_cfg_t *this)
|
||||
{
|
||||
return this->updown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_hostaccess.
|
||||
*/
|
||||
static bool get_hostaccess(private_child_cfg_t *this)
|
||||
{
|
||||
return this->hostaccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies jitter to the rekey value. Returns the new rekey value.
|
||||
* Note: The distribution of random values is not perfect, but it
|
||||
* should get the job done.
|
||||
*/
|
||||
static u_int64_t apply_jitter(u_int64_t rekey, u_int64_t jitter)
|
||||
{
|
||||
if (jitter == 0)
|
||||
{
|
||||
return rekey;
|
||||
}
|
||||
jitter = (jitter == UINT64_MAX) ? jitter : jitter + 1;
|
||||
return rekey - jitter * (random() / (RAND_MAX + 1.0));
|
||||
}
|
||||
#define APPLY_JITTER(l) l.rekey = apply_jitter(l.rekey, l.jitter)
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_lifetime.
|
||||
*/
|
||||
static lifetime_cfg_t *get_lifetime(private_child_cfg_t *this)
|
||||
{
|
||||
lifetime_cfg_t *lft = malloc_thing(lifetime_cfg_t);
|
||||
memcpy(lft, &this->lifetime, sizeof(lifetime_cfg_t));
|
||||
APPLY_JITTER(lft->time);
|
||||
APPLY_JITTER(lft->bytes);
|
||||
APPLY_JITTER(lft->packets);
|
||||
return lft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_mode.
|
||||
*/
|
||||
static ipsec_mode_t get_mode(private_child_cfg_t *this)
|
||||
{
|
||||
return this->mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_dpd_action.
|
||||
*/
|
||||
static action_t get_dpd_action(private_child_cfg_t *this)
|
||||
{
|
||||
return this->dpd_action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_close_action.
|
||||
*/
|
||||
static action_t get_close_action(private_child_cfg_t *this)
|
||||
{
|
||||
return this->close_action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_dh_group.
|
||||
*/
|
||||
static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
proposal_t *proposal;
|
||||
u_int16_t dh_group = MODP_NONE;
|
||||
|
||||
enumerator = this->proposals->create_enumerator(this->proposals);
|
||||
while (enumerator->enumerate(enumerator, &proposal))
|
||||
{
|
||||
if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return dh_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.use_ipcomp.
|
||||
*/
|
||||
static bool use_ipcomp(private_child_cfg_t *this)
|
||||
{
|
||||
return this->use_ipcomp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_inactivity.
|
||||
*/
|
||||
static u_int32_t get_inactivity(private_child_cfg_t *this)
|
||||
{
|
||||
return this->inactivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.set_mipv6_options.
|
||||
*/
|
||||
static void set_mipv6_options(private_child_cfg_t *this, bool proxy_mode,
|
||||
bool install_policy)
|
||||
{
|
||||
this->proxy_mode = proxy_mode;
|
||||
this->install_policy = install_policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.use_proxy_mode.
|
||||
*/
|
||||
static bool use_proxy_mode(private_child_cfg_t *this)
|
||||
{
|
||||
return this->proxy_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.install_policy.
|
||||
*/
|
||||
static bool install_policy(private_child_cfg_t *this)
|
||||
{
|
||||
return this->install_policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_t.get_ref.
|
||||
*/
|
||||
static child_cfg_t* get_ref(private_child_cfg_t *this)
|
||||
{
|
||||
ref_get(&this->refcount);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements child_cfg_t.destroy.
|
||||
*/
|
||||
static void destroy(private_child_cfg_t *this)
|
||||
{
|
||||
if (ref_put(&this->refcount))
|
||||
{
|
||||
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
|
||||
this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
|
||||
this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
|
||||
if (this->updown)
|
||||
{
|
||||
free(this->updown);
|
||||
}
|
||||
free(this->name);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header-file
|
||||
*/
|
||||
child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime,
|
||||
char *updown, bool hostaccess,
|
||||
ipsec_mode_t mode, action_t dpd_action,
|
||||
action_t close_action, bool ipcomp,
|
||||
u_int32_t inactivity)
|
||||
{
|
||||
private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
|
||||
|
||||
this->public.get_name = (char* (*) (child_cfg_t*))get_name;
|
||||
this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
|
||||
this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
|
||||
this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
|
||||
this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
|
||||
this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool,bool))select_proposal;
|
||||
this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
|
||||
this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
|
||||
this->public.get_mode = (ipsec_mode_t (*) (child_cfg_t *))get_mode;
|
||||
this->public.get_dpd_action = (action_t (*) (child_cfg_t *))get_dpd_action;
|
||||
this->public.get_close_action = (action_t (*) (child_cfg_t *))get_close_action;
|
||||
this->public.get_lifetime = (lifetime_cfg_t* (*) (child_cfg_t *))get_lifetime;
|
||||
this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
|
||||
this->public.set_mipv6_options = (void (*) (child_cfg_t*,bool,bool))set_mipv6_options;
|
||||
this->public.use_ipcomp = (bool (*) (child_cfg_t *))use_ipcomp;
|
||||
this->public.get_inactivity = (u_int32_t (*) (child_cfg_t *))get_inactivity;
|
||||
this->public.use_proxy_mode = (bool (*) (child_cfg_t *))use_proxy_mode;
|
||||
this->public.install_policy = (bool (*) (child_cfg_t *))install_policy;
|
||||
this->public.get_ref = (child_cfg_t* (*) (child_cfg_t*))get_ref;
|
||||
this->public.destroy = (void (*) (child_cfg_t*))destroy;
|
||||
|
||||
this->name = strdup(name);
|
||||
this->updown = updown ? strdup(updown) : NULL;
|
||||
this->hostaccess = hostaccess;
|
||||
this->mode = mode;
|
||||
this->dpd_action = dpd_action;
|
||||
this->close_action = close_action;
|
||||
this->use_ipcomp = ipcomp;
|
||||
this->inactivity = inactivity;
|
||||
this->proxy_mode = FALSE;
|
||||
this->install_policy = TRUE;
|
||||
this->refcount = 1;
|
||||
this->proposals = linked_list_create();
|
||||
this->my_ts = linked_list_create();
|
||||
this->other_ts = linked_list_create();
|
||||
memcpy(&this->lifetime, lifetime, sizeof(lifetime_cfg_t));
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2009 Tobias Brunner
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 child_cfg child_cfg
|
||||
* @{ @ingroup config
|
||||
*/
|
||||
|
||||
#ifndef CHILD_CFG_H_
|
||||
#define CHILD_CFG_H_
|
||||
|
||||
typedef enum action_t action_t;
|
||||
typedef enum ipcomp_transform_t ipcomp_transform_t;
|
||||
typedef struct lifetime_cfg_t lifetime_cfg_t;
|
||||
typedef struct child_cfg_t child_cfg_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <selectors/traffic_selector.h>
|
||||
#include <config/proposal.h>
|
||||
#include <kernel/kernel_ipsec.h>
|
||||
|
||||
/**
|
||||
* Action to take when DPD detected/connection gets closed by peer.
|
||||
*/
|
||||
enum action_t {
|
||||
/** No action */
|
||||
ACTION_NONE,
|
||||
/** Route config to reestablish on demand */
|
||||
ACTION_ROUTE,
|
||||
/** Restart config immediately */
|
||||
ACTION_RESTART,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum names for action_t.
|
||||
*/
|
||||
extern enum_name_t *action_names;
|
||||
|
||||
/**
|
||||
* IPComp transform IDs, as in RFC 4306
|
||||
*/
|
||||
enum ipcomp_transform_t {
|
||||
IPCOMP_NONE = 241,
|
||||
IPCOMP_OUI = 1,
|
||||
IPCOMP_DEFLATE = 2,
|
||||
IPCOMP_LZS = 3,
|
||||
IPCOMP_LZJH = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum strings for ipcomp_transform_t.
|
||||
*/
|
||||
extern enum_name_t *ipcomp_transform_names;
|
||||
|
||||
/**
|
||||
* A lifetime_cfg_t defines the lifetime limits of a CHILD_SA.
|
||||
*
|
||||
* Set any of these values to 0 to ignore.
|
||||
*/
|
||||
struct lifetime_cfg_t {
|
||||
struct {
|
||||
/** Limit before the CHILD_SA gets invalid. */
|
||||
u_int64_t life;
|
||||
/** Limit before the CHILD_SA gets rekeyed. */
|
||||
u_int64_t rekey;
|
||||
/** The range of a random value subtracted from rekey. */
|
||||
u_int64_t jitter;
|
||||
} time, bytes, packets;
|
||||
};
|
||||
|
||||
/**
|
||||
* A child_cfg_t defines the config template for a CHILD_SA.
|
||||
*
|
||||
* After creation, proposals and traffic selectors may be added to the config.
|
||||
* A child_cfg object is referenced multiple times, and is not thread save.
|
||||
* Reading from the object is save, adding things is not allowed while other
|
||||
* threads may access the object.
|
||||
* A reference counter handles the number of references hold to this config.
|
||||
*
|
||||
* @see peer_cfg_t to get an overview over the configurations.
|
||||
*/
|
||||
struct child_cfg_t {
|
||||
|
||||
/**
|
||||
* Get the name of the child_cfg.
|
||||
*
|
||||
* @return child_cfg's name
|
||||
*/
|
||||
char *(*get_name) (child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Add a proposal to the list.
|
||||
*
|
||||
* The proposals are stored by priority, first added
|
||||
* is the most prefered.
|
||||
* After add, proposal is owned by child_cfg.
|
||||
*
|
||||
* @param proposal proposal to add
|
||||
*/
|
||||
void (*add_proposal) (child_cfg_t *this, proposal_t *proposal);
|
||||
|
||||
/**
|
||||
* Get the list of proposals for the CHILD_SA.
|
||||
*
|
||||
* Resulting list and all of its proposals must be freed after use.
|
||||
*
|
||||
* @param strip_dh TRUE strip out diffie hellman groups
|
||||
* @return list of proposals
|
||||
*/
|
||||
linked_list_t* (*get_proposals)(child_cfg_t *this, bool strip_dh);
|
||||
|
||||
/**
|
||||
* Select a proposal from a supplied list.
|
||||
*
|
||||
* Returned propsal is newly created and must be destroyed after usage.
|
||||
*
|
||||
* @param proposals list from from wich proposals are selected
|
||||
* @param strip_dh TRUE strip out diffie hellman groups
|
||||
* @param private accept algorithms from a private range
|
||||
* @return selected proposal, or NULL if nothing matches
|
||||
*/
|
||||
proposal_t* (*select_proposal)(child_cfg_t*this, linked_list_t *proposals,
|
||||
bool strip_dh, bool private);
|
||||
|
||||
/**
|
||||
* Add a traffic selector to the config.
|
||||
*
|
||||
* Use the "local" parameter to add it for the local or the remote side.
|
||||
* After add, traffic selector is owned by child_cfg.
|
||||
*
|
||||
* @param local TRUE for local side, FALSE for remote
|
||||
* @param ts traffic_selector to add
|
||||
*/
|
||||
void (*add_traffic_selector)(child_cfg_t *this, bool local,
|
||||
traffic_selector_t *ts);
|
||||
|
||||
/**
|
||||
* Get a list of traffic selectors to use for the CHILD_SA.
|
||||
*
|
||||
* The config contains two set of traffic selectors, one for the local
|
||||
* side, one for the remote side.
|
||||
* If a list with traffic selectors is supplied, these are used to narrow
|
||||
* down the traffic selector list to the greatest common divisor.
|
||||
* Some traffic selector may be "dymamic", meaning they are narrowed down
|
||||
* to a specific address (host-to-host or virtual-IP setups). Use
|
||||
* the "host" parameter to narrow such traffic selectors to that address.
|
||||
* Resulted list and its traffic selectors must be destroyed after use.
|
||||
*
|
||||
* @param local TRUE for TS on local side, FALSE for remote
|
||||
* @param supplied list with TS to select from, or NULL
|
||||
* @param host address to use for narrowing "dynamic" TS', or NULL
|
||||
* @return list containing the traffic selectors
|
||||
*/
|
||||
linked_list_t *(*get_traffic_selectors)(child_cfg_t *this, bool local,
|
||||
linked_list_t *supplied,
|
||||
host_t *host);
|
||||
/**
|
||||
* Get the updown script to run for the CHILD_SA.
|
||||
*
|
||||
* @return path to updown script
|
||||
*/
|
||||
char* (*get_updown)(child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Should we allow access to the local host (gateway)?
|
||||
*
|
||||
* @return value of hostaccess flag
|
||||
*/
|
||||
bool (*get_hostaccess) (child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the lifetime configuration of a CHILD_SA.
|
||||
*
|
||||
* The rekey limits automatically contain a jitter to avoid simultaneous
|
||||
* rekeying. These values will change with each call to this function.
|
||||
*
|
||||
* @return lifetime_cfg_t (has to be freed)
|
||||
*/
|
||||
lifetime_cfg_t* (*get_lifetime) (child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the mode to use for the CHILD_SA.
|
||||
*
|
||||
* The mode is either tunnel, transport or BEET. The peer must agree
|
||||
* on the method, fallback is tunnel mode.
|
||||
*
|
||||
* @return ipsec mode
|
||||
*/
|
||||
ipsec_mode_t (*get_mode) (child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Action to take on DPD.
|
||||
*
|
||||
* @return DPD action
|
||||
*/
|
||||
action_t (*get_dpd_action) (child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Action to take if CHILD_SA gets closed.
|
||||
*
|
||||
* @return close action
|
||||
*/
|
||||
action_t (*get_close_action) (child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the DH group to use for CHILD_SA setup.
|
||||
*
|
||||
* @return dh group to use
|
||||
*/
|
||||
diffie_hellman_group_t (*get_dh_group)(child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Check whether IPComp should be used, if the other peer supports it.
|
||||
*
|
||||
* @return TRUE, if IPComp should be used
|
||||
* FALSE, otherwise
|
||||
*/
|
||||
bool (*use_ipcomp)(child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the inactivity timeout value.
|
||||
*
|
||||
* @return inactivity timeout in s
|
||||
*/
|
||||
u_int32_t (*get_inactivity)(child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Sets two options needed for Mobile IPv6 interoperability
|
||||
*
|
||||
* @param proxy_mode use IPsec transport proxy mode (default FALSE)
|
||||
* @param install_policy install IPsec kernel policies (default TRUE)
|
||||
*/
|
||||
void (*set_mipv6_options)(child_cfg_t *this, bool proxy_mode,
|
||||
bool install_policy);
|
||||
|
||||
/**
|
||||
* Check whether IPsec transport SA should be set up in proxy mode
|
||||
*
|
||||
* @return TRUE, if proxy mode should be used
|
||||
* FALSE, otherwise
|
||||
*/
|
||||
bool (*use_proxy_mode)(child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Check whether IPsec policies should be installed in the kernel
|
||||
*
|
||||
* @return TRUE, if IPsec kernel policies should be installed
|
||||
* FALSE, otherwise
|
||||
*/
|
||||
bool (*install_policy)(child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Increase the reference count.
|
||||
*
|
||||
* @return reference to this
|
||||
*/
|
||||
child_cfg_t* (*get_ref) (child_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Destroys the child_cfg object.
|
||||
*
|
||||
* Decrements the internal reference counter and
|
||||
* destroys the child_cfg when it reaches zero.
|
||||
*/
|
||||
void (*destroy) (child_cfg_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a configuration template for CHILD_SA setup.
|
||||
*
|
||||
* The "name" string gets cloned.
|
||||
*
|
||||
* The lifetime_cfg_t object gets cloned.
|
||||
* To prevent two peers to start rekeying at the same time, a jitter may be
|
||||
* specified. Rekeying of an SA starts at (x.rekey - random(0, x.jitter)).
|
||||
*
|
||||
* After a call to create, a reference is obtained (refcount = 1).
|
||||
*
|
||||
* @param name name of the child_cfg
|
||||
* @param lifetime lifetime_cfg_t for this child_cfg
|
||||
* @param updown updown script to execute on up/down event
|
||||
* @param hostaccess TRUE to allow access to the local host
|
||||
* @param mode mode to propose for CHILD_SA, transport, tunnel or BEET
|
||||
* @param dpd_action DPD action
|
||||
* @param close_action close action
|
||||
* @param ipcomp use IPComp, if peer supports it
|
||||
* @param inactivity inactivity timeout in s before closing a CHILD_SA
|
||||
* @return child_cfg_t object
|
||||
*/
|
||||
child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime,
|
||||
char *updown, bool hostaccess,
|
||||
ipsec_mode_t mode, action_t dpd_action,
|
||||
action_t close_action, bool ipcomp,
|
||||
u_int32_t inactivity);
|
||||
|
||||
#endif /** CHILD_CFG_H_ @}*/
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 "ike_cfg.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
|
||||
typedef struct private_ike_cfg_t private_ike_cfg_t;
|
||||
|
||||
/**
|
||||
* Private data of an ike_cfg_t object
|
||||
*/
|
||||
struct private_ike_cfg_t {
|
||||
|
||||
/**
|
||||
* Public part
|
||||
*/
|
||||
ike_cfg_t public;
|
||||
|
||||
/**
|
||||
* Number of references hold by others to this ike_cfg
|
||||
*/
|
||||
refcount_t refcount;
|
||||
|
||||
/**
|
||||
* Address of local host
|
||||
*/
|
||||
char *me;
|
||||
|
||||
/**
|
||||
* Address of remote host
|
||||
*/
|
||||
char *other;
|
||||
|
||||
/**
|
||||
* our source port
|
||||
*/
|
||||
u_int16_t my_port;
|
||||
|
||||
/**
|
||||
* destination port
|
||||
*/
|
||||
u_int16_t other_port;
|
||||
|
||||
/**
|
||||
* should we send a certificate request?
|
||||
*/
|
||||
bool certreq;
|
||||
|
||||
/**
|
||||
* enforce UDP encapsulation
|
||||
*/
|
||||
bool force_encap;
|
||||
|
||||
/**
|
||||
* List of proposals to use
|
||||
*/
|
||||
linked_list_t *proposals;
|
||||
};
|
||||
|
||||
METHOD(ike_cfg_t, send_certreq, bool,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
return this->certreq;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, force_encap_, bool,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
return this->force_encap;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, get_my_addr, char*,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
return this->me;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, get_other_addr, char*,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
return this->other;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, get_my_port, u_int16_t,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
return this->my_port;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, get_other_port, u_int16_t,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
return this->other_port;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, add_proposal, void,
|
||||
private_ike_cfg_t *this, proposal_t *proposal)
|
||||
{
|
||||
this->proposals->insert_last(this->proposals, proposal);
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, get_proposals, linked_list_t*,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
proposal_t *current;
|
||||
linked_list_t *proposals;
|
||||
|
||||
proposals = linked_list_create();
|
||||
enumerator = this->proposals->create_enumerator(this->proposals);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
current = current->clone(current);
|
||||
proposals->insert_last(proposals, current);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return proposals;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, select_proposal, proposal_t*,
|
||||
private_ike_cfg_t *this, linked_list_t *proposals, bool private)
|
||||
{
|
||||
iterator_t *stored_iter, *supplied_iter;
|
||||
proposal_t *stored, *supplied, *selected;
|
||||
|
||||
stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
|
||||
supplied_iter = proposals->create_iterator(proposals, TRUE);
|
||||
|
||||
|
||||
/* compare all stored proposals with all supplied. Stored ones are preferred.*/
|
||||
while (stored_iter->iterate(stored_iter, (void**)&stored))
|
||||
{
|
||||
supplied_iter->reset(supplied_iter);
|
||||
|
||||
while (supplied_iter->iterate(supplied_iter, (void**)&supplied))
|
||||
{
|
||||
selected = stored->select(stored, supplied, private);
|
||||
if (selected)
|
||||
{
|
||||
/* they match, return */
|
||||
stored_iter->destroy(stored_iter);
|
||||
supplied_iter->destroy(supplied_iter);
|
||||
DBG2(DBG_CFG, "received proposals: %#P", proposals);
|
||||
DBG2(DBG_CFG, "configured proposals: %#P", this->proposals);
|
||||
DBG2(DBG_CFG, "selected proposal: %P", selected);
|
||||
return selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
|
||||
stored_iter->destroy(stored_iter);
|
||||
supplied_iter->destroy(supplied_iter);
|
||||
DBG1(DBG_CFG, "received proposals: %#P", proposals);
|
||||
DBG1(DBG_CFG, "configured proposals: %#P", this->proposals);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, get_dh_group, diffie_hellman_group_t,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
proposal_t *proposal;
|
||||
u_int16_t dh_group = MODP_NONE;
|
||||
|
||||
enumerator = this->proposals->create_enumerator(this->proposals);
|
||||
while (enumerator->enumerate(enumerator, &proposal))
|
||||
{
|
||||
if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return dh_group;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, equals, bool,
|
||||
private_ike_cfg_t *this, ike_cfg_t *other_public)
|
||||
{
|
||||
private_ike_cfg_t *other = (private_ike_cfg_t*)other_public;
|
||||
enumerator_t *e1, *e2;
|
||||
proposal_t *p1, *p2;
|
||||
bool eq = TRUE;
|
||||
|
||||
if (this == other)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (this->public.equals != other->public.equals)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (this->proposals->get_count(this->proposals) !=
|
||||
other->proposals->get_count(other->proposals))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
e1 = this->proposals->create_enumerator(this->proposals);
|
||||
e2 = this->proposals->create_enumerator(this->proposals);
|
||||
while (e1->enumerate(e1, &p1) && e2->enumerate(e2, &p2))
|
||||
{
|
||||
if (!p1->equals(p1, p2))
|
||||
{
|
||||
eq = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
|
||||
return (eq &&
|
||||
this->certreq == other->certreq &&
|
||||
this->force_encap == other->force_encap &&
|
||||
streq(this->me, other->me) &&
|
||||
streq(this->other, other->other) &&
|
||||
this->my_port == other->my_port &&
|
||||
this->other_port == other->other_port);
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, get_ref, ike_cfg_t*,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
ref_get(&this->refcount);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
METHOD(ike_cfg_t, destroy, void,
|
||||
private_ike_cfg_t *this)
|
||||
{
|
||||
if (ref_put(&this->refcount))
|
||||
{
|
||||
this->proposals->destroy_offset(this->proposals,
|
||||
offsetof(proposal_t, destroy));
|
||||
free(this->me);
|
||||
free(this->other);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap,
|
||||
char *me, u_int16_t my_port, char *other, u_int16_t other_port)
|
||||
{
|
||||
private_ike_cfg_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.send_certreq = _send_certreq,
|
||||
.force_encap = _force_encap_,
|
||||
.get_my_addr = _get_my_addr,
|
||||
.get_other_addr = _get_other_addr,
|
||||
.get_my_port = _get_my_port,
|
||||
.get_other_port = _get_other_port,
|
||||
.add_proposal = _add_proposal,
|
||||
.get_proposals = _get_proposals,
|
||||
.select_proposal = _select_proposal,
|
||||
.get_dh_group = _get_dh_group,
|
||||
.equals = _equals,
|
||||
.get_ref = _get_ref,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.refcount = 1,
|
||||
.certreq = certreq,
|
||||
.force_encap = force_encap,
|
||||
.me = strdup(me),
|
||||
.other = strdup(other),
|
||||
.my_port = my_port,
|
||||
.other_port = other_port,
|
||||
.proposals = linked_list_create(),
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 ike_cfg ike_cfg
|
||||
* @{ @ingroup config
|
||||
*/
|
||||
|
||||
#ifndef IKE_CFG_H_
|
||||
#define IKE_CFG_H_
|
||||
|
||||
typedef struct ike_cfg_t ike_cfg_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/host.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/identification.h>
|
||||
#include <config/proposal.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
|
||||
/**
|
||||
* An ike_cfg_t defines the rules to set up an IKE_SA.
|
||||
*
|
||||
* @see peer_cfg_t to get an overview over the configurations.
|
||||
*/
|
||||
struct ike_cfg_t {
|
||||
|
||||
/**
|
||||
* Get own address.
|
||||
*
|
||||
* @return string of address/DNS name
|
||||
*/
|
||||
char* (*get_my_addr) (ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get peers address.
|
||||
*
|
||||
* @return string of address/DNS name
|
||||
*/
|
||||
char* (*get_other_addr) (ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the port to use as our source port.
|
||||
*
|
||||
* @return source address port, host order
|
||||
*/
|
||||
u_int16_t (*get_my_port)(ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the port to use as destination port.
|
||||
*
|
||||
* @return destination address, host order
|
||||
*/
|
||||
u_int16_t (*get_other_port)(ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Adds a proposal to the list.
|
||||
*
|
||||
* The first added proposal has the highest priority, the last
|
||||
* added the lowest.
|
||||
*
|
||||
* @param proposal proposal to add
|
||||
*/
|
||||
void (*add_proposal) (ike_cfg_t *this, proposal_t *proposal);
|
||||
|
||||
/**
|
||||
* Returns a list of all supported proposals.
|
||||
*
|
||||
* Returned list and its proposals must be destroyed after use.
|
||||
*
|
||||
* @return list containing all the proposals
|
||||
*/
|
||||
linked_list_t* (*get_proposals) (ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Select a proposed from suggested proposals.
|
||||
*
|
||||
* Returned proposal must be destroyed after use.
|
||||
*
|
||||
* @param proposals list of proposals to select from
|
||||
* @param private accept algorithms from a private range
|
||||
* @return selected proposal, or NULL if none matches.
|
||||
*/
|
||||
proposal_t *(*select_proposal) (ike_cfg_t *this, linked_list_t *proposals,
|
||||
bool private);
|
||||
|
||||
/**
|
||||
* Should we send a certificate request in IKE_SA_INIT?
|
||||
*
|
||||
* @return certificate request sending policy
|
||||
*/
|
||||
bool (*send_certreq) (ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Enforce UDP encapsulation by faking NATD notifies?
|
||||
*
|
||||
* @return TRUE to enfoce UDP encapsulation
|
||||
*/
|
||||
bool (*force_encap) (ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the DH group to use for IKE_SA setup.
|
||||
*
|
||||
* @return dh group to use for initialization
|
||||
*/
|
||||
diffie_hellman_group_t (*get_dh_group)(ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Check if two IKE configs are equal.
|
||||
*
|
||||
* @param other other to check for equality
|
||||
* @return TRUE if other equal to this
|
||||
*/
|
||||
bool (*equals)(ike_cfg_t *this, ike_cfg_t *other);
|
||||
|
||||
/**
|
||||
* Increase reference count.
|
||||
*
|
||||
* @return reference to this
|
||||
*/
|
||||
ike_cfg_t* (*get_ref) (ike_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Destroys a ike_cfg_t object.
|
||||
*
|
||||
* Decrements the internal reference counter and
|
||||
* destroys the ike_cfg when it reaches zero.
|
||||
*/
|
||||
void (*destroy) (ike_cfg_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a ike_cfg_t object.
|
||||
*
|
||||
* Supplied hosts become owned by ike_cfg, the name gets cloned.
|
||||
*
|
||||
* @param certreq TRUE to send a certificate request
|
||||
* @param force_encap enforce UDP encapsulation by faking NATD notify
|
||||
* @param me address/DNS name of local peer
|
||||
* @param my_port IKE port to use as source, 500 uses IKEv2 port floating
|
||||
* @param other address/DNS name of remote peer
|
||||
* @param other_port IKE port to use as dest, 500 uses IKEv2 port floating
|
||||
* @return ike_cfg_t object.
|
||||
*/
|
||||
ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap,
|
||||
char *me, u_int16_t my_port, char *other, u_int16_t other_port);
|
||||
|
||||
#endif /** IKE_CFG_H_ @}*/
|
||||
@@ -0,0 +1,699 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Tobias Brunner
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 <string.h>
|
||||
|
||||
#include "peer_cfg.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
#include <threading/mutex.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/identification.h>
|
||||
|
||||
ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
|
||||
"CERT_ALWAYS_SEND",
|
||||
"CERT_SEND_IF_ASKED",
|
||||
"CERT_NEVER_SEND",
|
||||
);
|
||||
|
||||
ENUM(unique_policy_names, UNIQUE_NO, UNIQUE_KEEP,
|
||||
"UNIQUE_NO",
|
||||
"UNIQUE_REPLACE",
|
||||
"UNIQUE_KEEP",
|
||||
);
|
||||
|
||||
typedef struct private_peer_cfg_t private_peer_cfg_t;
|
||||
|
||||
/**
|
||||
* Private data of an peer_cfg_t object
|
||||
*/
|
||||
struct private_peer_cfg_t {
|
||||
|
||||
/**
|
||||
* Public part
|
||||
*/
|
||||
peer_cfg_t public;
|
||||
|
||||
/**
|
||||
* Number of references hold by others to this peer_cfg
|
||||
*/
|
||||
refcount_t refcount;
|
||||
|
||||
/**
|
||||
* Name of the peer_cfg, used to query it
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* IKE version to use for initiation
|
||||
*/
|
||||
u_int ike_version;
|
||||
|
||||
/**
|
||||
* IKE config associated to this peer config
|
||||
*/
|
||||
ike_cfg_t *ike_cfg;
|
||||
|
||||
/**
|
||||
* list of child configs associated to this peer config
|
||||
*/
|
||||
linked_list_t *child_cfgs;
|
||||
|
||||
/**
|
||||
* mutex to lock access to list of child_cfgs
|
||||
*/
|
||||
mutex_t *mutex;
|
||||
|
||||
/**
|
||||
* should we send a certificate
|
||||
*/
|
||||
cert_policy_t cert_policy;
|
||||
|
||||
/**
|
||||
* uniqueness of an IKE_SA
|
||||
*/
|
||||
unique_policy_t unique;
|
||||
|
||||
/**
|
||||
* number of tries after giving up if peer does not respond
|
||||
*/
|
||||
u_int32_t keyingtries;
|
||||
|
||||
/**
|
||||
* enable support for MOBIKE
|
||||
*/
|
||||
bool use_mobike;
|
||||
|
||||
/**
|
||||
* Time before starting rekeying
|
||||
*/
|
||||
u_int32_t rekey_time;
|
||||
|
||||
/**
|
||||
* Time before starting reauthentication
|
||||
*/
|
||||
u_int32_t reauth_time;
|
||||
|
||||
/**
|
||||
* Time, which specifies the range of a random value substracted from above.
|
||||
*/
|
||||
u_int32_t jitter_time;
|
||||
|
||||
/**
|
||||
* Delay before deleting a rekeying/reauthenticating SA
|
||||
*/
|
||||
u_int32_t over_time;
|
||||
|
||||
/**
|
||||
* DPD check intervall
|
||||
*/
|
||||
u_int32_t dpd;
|
||||
|
||||
/**
|
||||
* virtual IP to use locally
|
||||
*/
|
||||
host_t *virtual_ip;
|
||||
|
||||
/**
|
||||
* pool to acquire configuration attributes from
|
||||
*/
|
||||
char *pool;
|
||||
|
||||
/**
|
||||
* local authentication configs (rulesets)
|
||||
*/
|
||||
linked_list_t *local_auth;
|
||||
|
||||
/**
|
||||
* remote authentication configs (constraints)
|
||||
*/
|
||||
linked_list_t *remote_auth;
|
||||
|
||||
#ifdef ME
|
||||
/**
|
||||
* Is this a mediation connection?
|
||||
*/
|
||||
bool mediation;
|
||||
|
||||
/**
|
||||
* Name of the mediation connection to mediate through
|
||||
*/
|
||||
peer_cfg_t *mediated_by;
|
||||
|
||||
/**
|
||||
* ID of our peer at the mediation server (= leftid of the peer's conn with
|
||||
* the mediation server)
|
||||
*/
|
||||
identification_t *peer_id;
|
||||
#endif /* ME */
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_name
|
||||
*/
|
||||
static char *get_name(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_ike_version
|
||||
*/
|
||||
static u_int get_ike_version(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->ike_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_ike_cfg
|
||||
*/
|
||||
static ike_cfg_t* get_ike_cfg(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->ike_cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.add_child_cfg.
|
||||
*/
|
||||
static void add_child_cfg(private_peer_cfg_t *this, child_cfg_t *child_cfg)
|
||||
{
|
||||
this->mutex->lock(this->mutex);
|
||||
this->child_cfgs->insert_last(this->child_cfgs, child_cfg);
|
||||
this->mutex->unlock(this->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* child_cfg enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
enumerator_t public;
|
||||
enumerator_t *wrapped;
|
||||
mutex_t *mutex;
|
||||
} child_cfg_enumerator_t;
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.remove_child_cfg.
|
||||
*/
|
||||
static void remove_child_cfg(private_peer_cfg_t *this,
|
||||
child_cfg_enumerator_t *enumerator)
|
||||
{
|
||||
this->child_cfgs->remove_at(this->child_cfgs, enumerator->wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_enumerator_t.destroy
|
||||
*/
|
||||
static void child_cfg_enumerator_destroy(child_cfg_enumerator_t *this)
|
||||
{
|
||||
this->mutex->unlock(this->mutex);
|
||||
this->wrapped->destroy(this->wrapped);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of child_cfg_enumerator_t.enumerate
|
||||
*/
|
||||
static bool child_cfg_enumerate(child_cfg_enumerator_t *this, child_cfg_t **chd)
|
||||
{
|
||||
return this->wrapped->enumerate(this->wrapped, chd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.create_child_cfg_enumerator.
|
||||
*/
|
||||
static enumerator_t* create_child_cfg_enumerator(private_peer_cfg_t *this)
|
||||
{
|
||||
child_cfg_enumerator_t *enumerator = malloc_thing(child_cfg_enumerator_t);
|
||||
|
||||
enumerator->public.enumerate = (void*)child_cfg_enumerate;
|
||||
enumerator->public.destroy = (void*)child_cfg_enumerator_destroy;
|
||||
enumerator->mutex = this->mutex;
|
||||
enumerator->wrapped = this->child_cfgs->create_enumerator(this->child_cfgs);
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
return &enumerator->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how good a list of TS matches a given child config
|
||||
*/
|
||||
static int get_ts_match(child_cfg_t *cfg, bool local,
|
||||
linked_list_t *sup_list, host_t *host)
|
||||
{
|
||||
linked_list_t *cfg_list;
|
||||
enumerator_t *sup_enum, *cfg_enum;
|
||||
traffic_selector_t *sup_ts, *cfg_ts;
|
||||
int match = 0, round;
|
||||
|
||||
/* fetch configured TS list, narrowing dynamic TS */
|
||||
cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, host);
|
||||
|
||||
/* use a round counter to rate leading TS with higher priority */
|
||||
round = sup_list->get_count(sup_list);
|
||||
|
||||
sup_enum = sup_list->create_enumerator(sup_list);
|
||||
while (sup_enum->enumerate(sup_enum, &sup_ts))
|
||||
{
|
||||
cfg_enum = cfg_list->create_enumerator(cfg_list);
|
||||
while (cfg_enum->enumerate(cfg_enum, &cfg_ts))
|
||||
{
|
||||
if (cfg_ts->equals(cfg_ts, sup_ts))
|
||||
{ /* equality is honored better than matches */
|
||||
match += round * 5;
|
||||
}
|
||||
else if (cfg_ts->is_contained_in(cfg_ts, sup_ts) ||
|
||||
sup_ts->is_contained_in(sup_ts, cfg_ts))
|
||||
{
|
||||
match += round * 1;
|
||||
}
|
||||
}
|
||||
cfg_enum->destroy(cfg_enum);
|
||||
round--;
|
||||
}
|
||||
sup_enum->destroy(sup_enum);
|
||||
|
||||
cfg_list->destroy_offset(cfg_list, offsetof(traffic_selector_t, destroy));
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.select_child_cfg
|
||||
*/
|
||||
static child_cfg_t* select_child_cfg(private_peer_cfg_t *this,
|
||||
linked_list_t *my_ts,
|
||||
linked_list_t *other_ts,
|
||||
host_t *my_host, host_t *other_host)
|
||||
{
|
||||
child_cfg_t *current, *found = NULL;
|
||||
enumerator_t *enumerator;
|
||||
int best = 0;
|
||||
|
||||
DBG2(DBG_CFG, "looking for a child config for %#R=== %#R", my_ts, other_ts);
|
||||
enumerator = create_child_cfg_enumerator(this);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
int my_prio, other_prio;
|
||||
|
||||
my_prio = get_ts_match(current, TRUE, my_ts, my_host);
|
||||
other_prio = get_ts_match(current, FALSE, other_ts, other_host);
|
||||
|
||||
if (my_prio && other_prio)
|
||||
{
|
||||
DBG2(DBG_CFG, " candidate \"%s\" with prio %d+%d",
|
||||
current->get_name(current), my_prio, other_prio);
|
||||
if (my_prio + other_prio > best)
|
||||
{
|
||||
best = my_prio + other_prio;
|
||||
DESTROY_IF(found);
|
||||
found = current->get_ref(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
if (found)
|
||||
{
|
||||
DBG2(DBG_CFG, "found matching child config \"%s\" with prio %d",
|
||||
found->get_name(found), best);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_cert_policy.
|
||||
*/
|
||||
static cert_policy_t get_cert_policy(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->cert_policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_unique_policy.
|
||||
*/
|
||||
static unique_policy_t get_unique_policy(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->unique;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_keyingtries.
|
||||
*/
|
||||
static u_int32_t get_keyingtries(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->keyingtries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_rekey_time.
|
||||
*/
|
||||
static u_int32_t get_rekey_time(private_peer_cfg_t *this)
|
||||
{
|
||||
if (this->rekey_time == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (this->jitter_time == 0)
|
||||
{
|
||||
return this->rekey_time;
|
||||
}
|
||||
return this->rekey_time - (random() % this->jitter_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_reauth_time.
|
||||
*/
|
||||
static u_int32_t get_reauth_time(private_peer_cfg_t *this)
|
||||
{
|
||||
if (this->reauth_time == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (this->jitter_time == 0)
|
||||
{
|
||||
return this->reauth_time;
|
||||
}
|
||||
return this->reauth_time - (random() % this->jitter_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_over_time.
|
||||
*/
|
||||
static u_int32_t get_over_time(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->over_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.use_mobike.
|
||||
*/
|
||||
static bool use_mobike(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->use_mobike;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements peer_cfg_t.get_dpd
|
||||
*/
|
||||
static u_int32_t get_dpd(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->dpd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_virtual_ip.
|
||||
*/
|
||||
static host_t* get_virtual_ip(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->virtual_ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_pool.
|
||||
*/
|
||||
static char* get_pool(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.add_auth_cfg
|
||||
*/
|
||||
static void add_auth_cfg(private_peer_cfg_t *this,
|
||||
auth_cfg_t *cfg, bool local)
|
||||
{
|
||||
if (local)
|
||||
{
|
||||
this->local_auth->insert_last(this->local_auth, cfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->remote_auth->insert_last(this->remote_auth, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.create_auth_cfg_enumerator
|
||||
*/
|
||||
static enumerator_t* create_auth_cfg_enumerator(private_peer_cfg_t *this,
|
||||
bool local)
|
||||
{
|
||||
if (local)
|
||||
{
|
||||
return this->local_auth->create_enumerator(this->local_auth);
|
||||
}
|
||||
return this->remote_auth->create_enumerator(this->remote_auth);
|
||||
}
|
||||
|
||||
#ifdef ME
|
||||
/**
|
||||
* Implementation of peer_cfg_t.is_mediation.
|
||||
*/
|
||||
static bool is_mediation(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->mediation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_mediated_by.
|
||||
*/
|
||||
static peer_cfg_t* get_mediated_by(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->mediated_by;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.get_peer_id.
|
||||
*/
|
||||
static identification_t* get_peer_id(private_peer_cfg_t *this)
|
||||
{
|
||||
return this->peer_id;
|
||||
}
|
||||
#endif /* ME */
|
||||
|
||||
/**
|
||||
* check auth configs for equality
|
||||
*/
|
||||
static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other)
|
||||
{
|
||||
enumerator_t *e1, *e2;
|
||||
auth_cfg_t *cfg1, *cfg2;
|
||||
bool equal = TRUE;
|
||||
|
||||
if (this->local_auth->get_count(this->local_auth) !=
|
||||
other->local_auth->get_count(other->local_auth))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (this->remote_auth->get_count(this->remote_auth) !=
|
||||
other->remote_auth->get_count(other->remote_auth))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
e1 = this->local_auth->create_enumerator(this->local_auth);
|
||||
e2 = other->local_auth->create_enumerator(other->local_auth);
|
||||
while (e1->enumerate(e1, &cfg1) && e2->enumerate(e2, &cfg2))
|
||||
{
|
||||
if (!cfg1->equals(cfg1, cfg2))
|
||||
{
|
||||
equal = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
|
||||
if (!equal)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
e1 = this->remote_auth->create_enumerator(this->remote_auth);
|
||||
e2 = other->remote_auth->create_enumerator(other->remote_auth);
|
||||
while (e1->enumerate(e1, &cfg1) && e2->enumerate(e2, &cfg2))
|
||||
{
|
||||
if (!cfg1->equals(cfg1, cfg2))
|
||||
{
|
||||
equal = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of peer_cfg_t.equals.
|
||||
*/
|
||||
static bool equals(private_peer_cfg_t *this, private_peer_cfg_t *other)
|
||||
{
|
||||
if (this == other)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (this->public.equals != other->public.equals)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (
|
||||
this->ike_version == other->ike_version &&
|
||||
this->cert_policy == other->cert_policy &&
|
||||
this->unique == other->unique &&
|
||||
this->keyingtries == other->keyingtries &&
|
||||
this->use_mobike == other->use_mobike &&
|
||||
this->rekey_time == other->rekey_time &&
|
||||
this->reauth_time == other->reauth_time &&
|
||||
this->jitter_time == other->jitter_time &&
|
||||
this->over_time == other->over_time &&
|
||||
this->dpd == other->dpd &&
|
||||
(this->virtual_ip == other->virtual_ip ||
|
||||
(this->virtual_ip && other->virtual_ip &&
|
||||
this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) &&
|
||||
(this->pool == other->pool ||
|
||||
(this->pool && other->pool && streq(this->pool, other->pool))) &&
|
||||
auth_cfg_equal(this, other)
|
||||
#ifdef ME
|
||||
&& this->mediation == other->mediation &&
|
||||
this->mediated_by == other->mediated_by &&
|
||||
(this->peer_id == other->peer_id ||
|
||||
(this->peer_id && other->peer_id &&
|
||||
this->peer_id->equals(this->peer_id, other->peer_id)))
|
||||
#endif /* ME */
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements peer_cfg_t.get_ref.
|
||||
*/
|
||||
static peer_cfg_t* get_ref(private_peer_cfg_t *this)
|
||||
{
|
||||
ref_get(&this->refcount);
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements peer_cfg_t.destroy.
|
||||
*/
|
||||
static void destroy(private_peer_cfg_t *this)
|
||||
{
|
||||
if (ref_put(&this->refcount))
|
||||
{
|
||||
this->ike_cfg->destroy(this->ike_cfg);
|
||||
this->child_cfgs->destroy_offset(this->child_cfgs,
|
||||
offsetof(child_cfg_t, destroy));
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
this->local_auth->destroy_offset(this->local_auth,
|
||||
offsetof(auth_cfg_t, destroy));
|
||||
this->remote_auth->destroy_offset(this->remote_auth,
|
||||
offsetof(auth_cfg_t, destroy));
|
||||
#ifdef ME
|
||||
DESTROY_IF(this->mediated_by);
|
||||
DESTROY_IF(this->peer_id);
|
||||
#endif /* ME */
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this->name);
|
||||
free(this->pool);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header-file
|
||||
*/
|
||||
peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
|
||||
cert_policy_t cert_policy, unique_policy_t unique,
|
||||
u_int32_t keyingtries, u_int32_t rekey_time,
|
||||
u_int32_t reauth_time, u_int32_t jitter_time,
|
||||
u_int32_t over_time, bool mobike, u_int32_t dpd,
|
||||
host_t *virtual_ip, char *pool,
|
||||
bool mediation, peer_cfg_t *mediated_by,
|
||||
identification_t *peer_id)
|
||||
{
|
||||
private_peer_cfg_t *this = malloc_thing(private_peer_cfg_t);
|
||||
|
||||
/* public functions */
|
||||
this->public.get_name = (char* (*) (peer_cfg_t *))get_name;
|
||||
this->public.get_ike_version = (u_int(*) (peer_cfg_t *))get_ike_version;
|
||||
this->public.get_ike_cfg = (ike_cfg_t* (*) (peer_cfg_t *))get_ike_cfg;
|
||||
this->public.add_child_cfg = (void (*) (peer_cfg_t *, child_cfg_t*))add_child_cfg;
|
||||
this->public.remove_child_cfg = (void(*)(peer_cfg_t*, enumerator_t*))remove_child_cfg;
|
||||
this->public.create_child_cfg_enumerator = (enumerator_t* (*) (peer_cfg_t *))create_child_cfg_enumerator;
|
||||
this->public.select_child_cfg = (child_cfg_t* (*) (peer_cfg_t *,linked_list_t*,linked_list_t*,host_t*,host_t*))select_child_cfg;
|
||||
this->public.get_cert_policy = (cert_policy_t (*) (peer_cfg_t *))get_cert_policy;
|
||||
this->public.get_unique_policy = (unique_policy_t (*) (peer_cfg_t *))get_unique_policy;
|
||||
this->public.get_keyingtries = (u_int32_t (*) (peer_cfg_t *))get_keyingtries;
|
||||
this->public.get_rekey_time = (u_int32_t(*)(peer_cfg_t*))get_rekey_time;
|
||||
this->public.get_reauth_time = (u_int32_t(*)(peer_cfg_t*))get_reauth_time;
|
||||
this->public.get_over_time = (u_int32_t(*)(peer_cfg_t*))get_over_time;
|
||||
this->public.use_mobike = (bool (*) (peer_cfg_t *))use_mobike;
|
||||
this->public.get_dpd = (u_int32_t (*) (peer_cfg_t *))get_dpd;
|
||||
this->public.get_virtual_ip = (host_t* (*) (peer_cfg_t *))get_virtual_ip;
|
||||
this->public.get_pool = (char*(*)(peer_cfg_t*))get_pool;
|
||||
this->public.add_auth_cfg = (void(*)(peer_cfg_t*, auth_cfg_t *cfg, bool local))add_auth_cfg;
|
||||
this->public.create_auth_cfg_enumerator = (enumerator_t*(*)(peer_cfg_t*, bool local))create_auth_cfg_enumerator;
|
||||
this->public.equals = (bool(*)(peer_cfg_t*, peer_cfg_t *other))equals;
|
||||
this->public.get_ref = (peer_cfg_t*(*)(peer_cfg_t *))get_ref;
|
||||
this->public.destroy = (void(*)(peer_cfg_t *))destroy;
|
||||
#ifdef ME
|
||||
this->public.is_mediation = (bool (*) (peer_cfg_t *))is_mediation;
|
||||
this->public.get_mediated_by = (peer_cfg_t* (*) (peer_cfg_t *))get_mediated_by;
|
||||
this->public.get_peer_id = (identification_t* (*) (peer_cfg_t *))get_peer_id;
|
||||
#endif /* ME */
|
||||
|
||||
/* apply init values */
|
||||
this->name = strdup(name);
|
||||
this->ike_version = ike_version;
|
||||
this->ike_cfg = ike_cfg;
|
||||
this->child_cfgs = linked_list_create();
|
||||
this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
|
||||
this->cert_policy = cert_policy;
|
||||
this->unique = unique;
|
||||
this->keyingtries = keyingtries;
|
||||
this->rekey_time = rekey_time;
|
||||
this->reauth_time = reauth_time;
|
||||
if (rekey_time && jitter_time > rekey_time)
|
||||
{
|
||||
jitter_time = rekey_time;
|
||||
}
|
||||
if (reauth_time && jitter_time > reauth_time)
|
||||
{
|
||||
jitter_time = reauth_time;
|
||||
}
|
||||
this->jitter_time = jitter_time;
|
||||
this->over_time = over_time;
|
||||
this->use_mobike = mobike;
|
||||
this->dpd = dpd;
|
||||
this->virtual_ip = virtual_ip;
|
||||
this->pool = pool ? strdup(pool) : NULL;
|
||||
this->local_auth = linked_list_create();
|
||||
this->remote_auth = linked_list_create();
|
||||
this->refcount = 1;
|
||||
#ifdef ME
|
||||
this->mediation = mediation;
|
||||
this->mediated_by = mediated_by;
|
||||
this->peer_id = peer_id;
|
||||
#else /* ME */
|
||||
DESTROY_IF(mediated_by);
|
||||
DESTROY_IF(peer_id);
|
||||
#endif /* ME */
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Tobias Brunner
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 peer_cfg peer_cfg
|
||||
* @{ @ingroup config
|
||||
*/
|
||||
|
||||
#ifndef PEER_CFG_H_
|
||||
#define PEER_CFG_H_
|
||||
|
||||
typedef enum cert_policy_t cert_policy_t;
|
||||
typedef enum unique_policy_t unique_policy_t;
|
||||
typedef struct peer_cfg_t peer_cfg_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/identification.h>
|
||||
#include <utils/enumerator.h>
|
||||
#include <selectors/traffic_selector.h>
|
||||
#include <config/proposal.h>
|
||||
#include <config/ike_cfg.h>
|
||||
#include <config/child_cfg.h>
|
||||
#include <sa/authenticators/authenticator.h>
|
||||
#include <sa/authenticators/eap/eap_method.h>
|
||||
#include <config/auth_cfg.h>
|
||||
|
||||
/**
|
||||
* Certificate sending policy. This is also used for certificate
|
||||
* requests when using this definition for the other peer. If
|
||||
* it is CERT_NEVER_SEND, a certreq is omitted, otherwise its
|
||||
* included.
|
||||
*
|
||||
* @warning These definitions must be the same as in pluto/starter,
|
||||
* as they are sent over the stroke socket.
|
||||
*/
|
||||
enum cert_policy_t {
|
||||
/** always send certificates, even when not requested */
|
||||
CERT_ALWAYS_SEND = 0,
|
||||
/** send certificate upon cert request */
|
||||
CERT_SEND_IF_ASKED = 1,
|
||||
/** never send a certificate, even when requested */
|
||||
CERT_NEVER_SEND = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum strings for cert_policy_t
|
||||
*/
|
||||
extern enum_name_t *cert_policy_names;
|
||||
|
||||
/**
|
||||
* Uniqueness of an IKE_SA, used to drop multiple connections with one peer.
|
||||
*/
|
||||
enum unique_policy_t {
|
||||
/** do not check for client uniqueness */
|
||||
UNIQUE_NO,
|
||||
/** replace unique IKE_SAs if new ones get established */
|
||||
UNIQUE_REPLACE,
|
||||
/** keep existing IKE_SAs, close the new ones on connection attept */
|
||||
UNIQUE_KEEP,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum strings for unique_policy_t
|
||||
*/
|
||||
extern enum_name_t *unique_policy_names;
|
||||
|
||||
/**
|
||||
* Configuration of a peer, specified by IDs.
|
||||
*
|
||||
* The peer config defines a connection between two given IDs. It contains
|
||||
* exactly one ike_cfg_t, which is use for initiation. Additionally, it contains
|
||||
* multiple child_cfg_t defining which CHILD_SAs are allowed for this peer.
|
||||
* @verbatim
|
||||
+-------------------+ +---------------+
|
||||
+---------------+ | peer_cfg | +---------------+ |
|
||||
| ike_cfg | +-------------------+ | child_cfg | |
|
||||
+---------------+ | - ids | +---------------+ |
|
||||
| - hosts | 1 1 | - cas | 1 n | - proposals | |
|
||||
| - proposals |<-----| - auth info |----->| - traffic sel | |
|
||||
| - ... | | - dpd config | | - ... |-+
|
||||
+---------------+ | - ... | +---------------+
|
||||
+-------------------+
|
||||
| 1 0 |
|
||||
| |
|
||||
v n n V
|
||||
+-------------------+ +-------------------+
|
||||
+-------------------+ | +-------------------+ |
|
||||
| auth_cfg | | | auth_cfg | |
|
||||
+-------------------+ | +-------------------+ |
|
||||
| - local rules |-+ | - remote constr. |-+
|
||||
+-------------------+ +-------------------+
|
||||
@endverbatim
|
||||
*
|
||||
* Each peer_cfg has two lists of authentication config attached. Local
|
||||
* authentication configs define how to authenticate ourself against the remote
|
||||
* peer. Each config is enforced using the multiple authentication extension
|
||||
* (RFC4739).
|
||||
* The remote authentication configs are handled as constraints. The peer has
|
||||
* to fullfill each of these rules (using multiple authentication, in any order)
|
||||
* to gain access to the configuration.
|
||||
*/
|
||||
struct peer_cfg_t {
|
||||
|
||||
/**
|
||||
* Get the name of the peer_cfg.
|
||||
*
|
||||
* Returned object is not getting cloned.
|
||||
*
|
||||
* @return peer_cfg's name
|
||||
*/
|
||||
char* (*get_name) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the IKE version to use for initiating.
|
||||
*
|
||||
* @return IKE major version
|
||||
*/
|
||||
u_int (*get_ike_version)(peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the IKE config to use for initiaton.
|
||||
*
|
||||
* @return the IKE config to use
|
||||
*/
|
||||
ike_cfg_t* (*get_ike_cfg) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Attach a CHILD config.
|
||||
*
|
||||
* @param child_cfg CHILD config to add
|
||||
*/
|
||||
void (*add_child_cfg) (peer_cfg_t *this, child_cfg_t *child_cfg);
|
||||
|
||||
/**
|
||||
* Detach a CHILD config, pointed to by an enumerator.
|
||||
*
|
||||
* @param enumerator enumerator indicating element position
|
||||
*/
|
||||
void (*remove_child_cfg)(peer_cfg_t *this, enumerator_t *enumerator);
|
||||
|
||||
/**
|
||||
* Create an enumerator for all attached CHILD configs.
|
||||
*
|
||||
* @return an enumerator over all CHILD configs.
|
||||
*/
|
||||
enumerator_t* (*create_child_cfg_enumerator) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Select a CHILD config from traffic selectors.
|
||||
*
|
||||
* @param my_ts TS for local side
|
||||
* @param other_ts TS for remote side
|
||||
* @param my_host host to narrow down dynamic TS for local side
|
||||
* @param other_host host to narrow down dynamic TS for remote side
|
||||
* @return selected CHILD config, or NULL if no match found
|
||||
*/
|
||||
child_cfg_t* (*select_child_cfg) (peer_cfg_t *this, linked_list_t *my_ts,
|
||||
linked_list_t *other_ts, host_t *my_host,
|
||||
host_t *other_host);
|
||||
|
||||
/**
|
||||
* Add an authentication config to the peer configuration.
|
||||
*
|
||||
* @param config config to add
|
||||
* @param local TRUE for local rules, FALSE for remote constraints
|
||||
*/
|
||||
void (*add_auth_cfg)(peer_cfg_t *this, auth_cfg_t *cfg, bool local);
|
||||
|
||||
/**
|
||||
* Create an enumerator over registered authentication configs.
|
||||
*
|
||||
* @param local TRUE for local rules, FALSE for remote constraints
|
||||
* @return enumerator over auth_cfg_t*
|
||||
*/
|
||||
enumerator_t* (*create_auth_cfg_enumerator)(peer_cfg_t *this, bool local);
|
||||
|
||||
/**
|
||||
* Should be sent a certificate for this connection?
|
||||
*
|
||||
* @return certificate sending policy
|
||||
*/
|
||||
cert_policy_t (*get_cert_policy) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* How to handle uniqueness of IKE_SAs?
|
||||
*
|
||||
* @return unique policy
|
||||
*/
|
||||
unique_policy_t (*get_unique_policy) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the max number of retries after timeout.
|
||||
*
|
||||
* @return max number retries
|
||||
*/
|
||||
u_int32_t (*get_keyingtries) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get a time to start rekeying (is randomized with jitter).
|
||||
*
|
||||
* @return time in s when to start rekeying, 0 disables rekeying
|
||||
*/
|
||||
u_int32_t (*get_rekey_time)(peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get a time to start reauthentication (is randomized with jitter).
|
||||
*
|
||||
* @return time in s when to start reauthentication, 0 disables it
|
||||
*/
|
||||
u_int32_t (*get_reauth_time)(peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the timeout of a rekeying/reauthenticating SA.
|
||||
*
|
||||
* @return timeout in s
|
||||
*/
|
||||
u_int32_t (*get_over_time)(peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Use MOBIKE (RFC4555) if peer supports it?
|
||||
*
|
||||
* @return TRUE to enable MOBIKE support
|
||||
*/
|
||||
bool (*use_mobike) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the DPD check interval.
|
||||
*
|
||||
* @return dpd_delay in seconds
|
||||
*/
|
||||
u_int32_t (*get_dpd) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get a virtual IP for the local peer.
|
||||
*
|
||||
* If no virtual IP should be used, NULL is returned. %any means to request
|
||||
* a virtual IP using configuration payloads. A specific address is also
|
||||
* used for a request and may be changed by the server.
|
||||
*
|
||||
* @param suggestion NULL, %any or specific
|
||||
* @return virtual IP, %any or NULL
|
||||
*/
|
||||
host_t* (*get_virtual_ip) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the name of the pool to acquire configuration attributes from.
|
||||
*
|
||||
* @return pool name, NULL if none defined
|
||||
*/
|
||||
char* (*get_pool)(peer_cfg_t *this);
|
||||
|
||||
#ifdef ME
|
||||
/**
|
||||
* Is this a mediation connection?
|
||||
*
|
||||
* @return TRUE, if this is a mediation connection
|
||||
*/
|
||||
bool (*is_mediation) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get peer_cfg of the connection this one is mediated through.
|
||||
*
|
||||
* @return the peer_cfg of the mediation connection
|
||||
*/
|
||||
peer_cfg_t* (*get_mediated_by) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the id of the other peer at the mediation server.
|
||||
*
|
||||
* This is the leftid of the peer's connection with the mediation server.
|
||||
*
|
||||
* If it is not configured, it is assumed to be the same as the right id
|
||||
* of this connection.
|
||||
*
|
||||
* @return the id of the other peer
|
||||
*/
|
||||
identification_t* (*get_peer_id) (peer_cfg_t *this);
|
||||
#endif /* ME */
|
||||
|
||||
/**
|
||||
* Check if two peer configurations are equal.
|
||||
*
|
||||
* This method does not compare associated ike/child_cfg.
|
||||
*
|
||||
* @param other candidate to check for equality against this
|
||||
* @return TRUE if peer_cfg and ike_cfg are equal
|
||||
*/
|
||||
bool (*equals)(peer_cfg_t *this, peer_cfg_t *other);
|
||||
|
||||
/**
|
||||
* Increase reference count.
|
||||
*
|
||||
* @return reference to this
|
||||
*/
|
||||
peer_cfg_t* (*get_ref) (peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Destroys the peer_cfg object.
|
||||
*
|
||||
* Decrements the internal reference counter and
|
||||
* destroys the peer_cfg when it reaches zero.
|
||||
*/
|
||||
void (*destroy) (peer_cfg_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a configuration object for IKE_AUTH and later.
|
||||
*
|
||||
* name-string gets cloned, ID's not.
|
||||
* Virtual IPs are used if they are != NULL. A %any host means the virtual
|
||||
* IP should be obtained from the other peer.
|
||||
* Lifetimes are in seconds. To prevent to peers to start rekeying at the
|
||||
* same time, a jitter may be specified. Rekeying of an SA starts at
|
||||
* (rekeylifetime - random(0, jitter)).
|
||||
*
|
||||
* @param name name of the peer_cfg
|
||||
* @param ike_version which IKE version we sould use for this peer
|
||||
* @param ike_cfg IKE config to use when acting as initiator
|
||||
* @param cert_policy should we send a certificate payload?
|
||||
* @param unique uniqueness of an IKE_SA
|
||||
* @param keyingtries how many keying tries should be done before giving up
|
||||
* @param rekey_time timeout before starting rekeying
|
||||
* @param reauth_time timeout before starting reauthentication
|
||||
* @param jitter_time timerange to randomly substract from rekey/reauth time
|
||||
* @param over_time maximum overtime before closing a rekeying/reauth SA
|
||||
* @param mobike use MOBIKE (RFC4555) if peer supports it
|
||||
* @param dpd DPD check interval, 0 to disable
|
||||
* @param virtual_ip virtual IP for local host, or NULL
|
||||
* @param pool pool name to get configuration attributes from, or NULL
|
||||
* @param mediation TRUE if this is a mediation connection
|
||||
* @param mediated_by peer_cfg_t of the mediation connection to mediate through
|
||||
* @param peer_id ID that identifies our peer at the mediation server
|
||||
* @return peer_cfg_t object
|
||||
*/
|
||||
peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
|
||||
cert_policy_t cert_policy, unique_policy_t unique,
|
||||
u_int32_t keyingtries, u_int32_t rekey_time,
|
||||
u_int32_t reauth_time, u_int32_t jitter_time,
|
||||
u_int32_t over_time, bool mobike, u_int32_t dpd,
|
||||
host_t *virtual_ip, char *pool,
|
||||
bool mediation, peer_cfg_t *mediated_by,
|
||||
identification_t *peer_id);
|
||||
|
||||
#endif /** PEER_CFG_H_ @}*/
|
||||
@@ -0,0 +1,946 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2009 Tobias Brunner
|
||||
* Copyright (C) 2006 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 <string.h>
|
||||
|
||||
#include "proposal.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/identification.h>
|
||||
#include <utils/lexparser.h>
|
||||
#include <crypto/transform.h>
|
||||
#include <crypto/prfs/prf.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
#include <crypto/proposal/proposal_keywords.h>
|
||||
|
||||
ENUM(protocol_id_names, PROTO_NONE, PROTO_ESP,
|
||||
"PROTO_NONE",
|
||||
"IKE",
|
||||
"AH",
|
||||
"ESP",
|
||||
);
|
||||
|
||||
ENUM(extended_sequence_numbers_names, NO_EXT_SEQ_NUMBERS, EXT_SEQ_NUMBERS,
|
||||
"NO_EXT_SEQ",
|
||||
"EXT_SEQ",
|
||||
);
|
||||
|
||||
typedef struct private_proposal_t private_proposal_t;
|
||||
typedef struct algorithm_t algorithm_t;
|
||||
|
||||
/**
|
||||
* Private data of an proposal_t object
|
||||
*/
|
||||
struct private_proposal_t {
|
||||
|
||||
/**
|
||||
* Public part
|
||||
*/
|
||||
proposal_t public;
|
||||
|
||||
/**
|
||||
* protocol (ESP or AH)
|
||||
*/
|
||||
protocol_id_t protocol;
|
||||
|
||||
/**
|
||||
* priority ordered list of encryption algorithms
|
||||
*/
|
||||
linked_list_t *encryption_algos;
|
||||
|
||||
/**
|
||||
* priority ordered list of integrity algorithms
|
||||
*/
|
||||
linked_list_t *integrity_algos;
|
||||
|
||||
/**
|
||||
* priority ordered list of pseudo random functions
|
||||
*/
|
||||
linked_list_t *prf_algos;
|
||||
|
||||
/**
|
||||
* priority ordered list of dh groups
|
||||
*/
|
||||
linked_list_t *dh_groups;
|
||||
|
||||
/**
|
||||
* priority ordered list of extended sequence number flags
|
||||
*/
|
||||
linked_list_t *esns;
|
||||
|
||||
/**
|
||||
* senders SPI
|
||||
*/
|
||||
u_int64_t spi;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct used to store different kinds of algorithms.
|
||||
*/
|
||||
struct algorithm_t {
|
||||
/**
|
||||
* Value from an encryption_algorithm_t/integrity_algorithm_t/...
|
||||
*/
|
||||
u_int16_t algorithm;
|
||||
|
||||
/**
|
||||
* the associated key size in bits, or zero if not needed
|
||||
*/
|
||||
u_int16_t key_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add algorithm/keysize to a algorithm list
|
||||
*/
|
||||
static void add_algo(linked_list_t *list, u_int16_t algo, u_int16_t key_size)
|
||||
{
|
||||
algorithm_t *algo_key;
|
||||
|
||||
algo_key = malloc_thing(algorithm_t);
|
||||
algo_key->algorithm = algo;
|
||||
algo_key->key_size = key_size;
|
||||
list->insert_last(list, (void*)algo_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.add_algorithm
|
||||
*/
|
||||
static void add_algorithm(private_proposal_t *this, transform_type_t type,
|
||||
u_int16_t algo, u_int16_t key_size)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ENCRYPTION_ALGORITHM:
|
||||
add_algo(this->encryption_algos, algo, key_size);
|
||||
break;
|
||||
case INTEGRITY_ALGORITHM:
|
||||
add_algo(this->integrity_algos, algo, key_size);
|
||||
break;
|
||||
case PSEUDO_RANDOM_FUNCTION:
|
||||
add_algo(this->prf_algos, algo, key_size);
|
||||
break;
|
||||
case DIFFIE_HELLMAN_GROUP:
|
||||
add_algo(this->dh_groups, algo, 0);
|
||||
break;
|
||||
case EXTENDED_SEQUENCE_NUMBERS:
|
||||
add_algo(this->esns, algo, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* filter function for peer configs
|
||||
*/
|
||||
static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg,
|
||||
void **unused, u_int16_t *key_size)
|
||||
{
|
||||
algorithm_t *algo = *in;
|
||||
*alg = algo->algorithm;
|
||||
if (key_size)
|
||||
{
|
||||
*key_size = algo->key_size;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.create_enumerator.
|
||||
*/
|
||||
static enumerator_t *create_enumerator(private_proposal_t *this,
|
||||
transform_type_t type)
|
||||
{
|
||||
linked_list_t *list;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ENCRYPTION_ALGORITHM:
|
||||
list = this->encryption_algos;
|
||||
break;
|
||||
case INTEGRITY_ALGORITHM:
|
||||
list = this->integrity_algos;
|
||||
break;
|
||||
case PSEUDO_RANDOM_FUNCTION:
|
||||
list = this->prf_algos;
|
||||
break;
|
||||
case DIFFIE_HELLMAN_GROUP:
|
||||
list = this->dh_groups;
|
||||
break;
|
||||
case EXTENDED_SEQUENCE_NUMBERS:
|
||||
list = this->esns;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
return enumerator_create_filter(list->create_enumerator(list),
|
||||
(void*)alg_filter, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.get_algorithm.
|
||||
*/
|
||||
static bool get_algorithm(private_proposal_t *this, transform_type_t type,
|
||||
u_int16_t *alg, u_int16_t *key_size)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
bool found = FALSE;
|
||||
|
||||
enumerator = create_enumerator(this, type);
|
||||
if (enumerator->enumerate(enumerator, alg, key_size))
|
||||
{
|
||||
found = TRUE;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.has_dh_group
|
||||
*/
|
||||
static bool has_dh_group(private_proposal_t *this, diffie_hellman_group_t group)
|
||||
{
|
||||
bool result = FALSE;
|
||||
|
||||
if (this->dh_groups->get_count(this->dh_groups))
|
||||
{
|
||||
algorithm_t *current;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
enumerator = this->dh_groups->create_enumerator(this->dh_groups);
|
||||
while (enumerator->enumerate(enumerator, (void**)¤t))
|
||||
{
|
||||
if (current->algorithm == group)
|
||||
{
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
else if (group == MODP_NONE)
|
||||
{
|
||||
result = TRUE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of proposal_t.strip_dh.
|
||||
*/
|
||||
static void strip_dh(private_proposal_t *this)
|
||||
{
|
||||
algorithm_t *alg;
|
||||
|
||||
while (this->dh_groups->remove_last(this->dh_groups, (void**)&alg) == SUCCESS)
|
||||
{
|
||||
free(alg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given alg is an authenticated encryption algorithm
|
||||
*/
|
||||
static bool is_authenticated_encryption(u_int16_t alg)
|
||||
{
|
||||
switch(alg)
|
||||
{
|
||||
case ENCR_AES_CCM_ICV8:
|
||||
case ENCR_AES_CCM_ICV12:
|
||||
case ENCR_AES_CCM_ICV16:
|
||||
case ENCR_AES_GCM_ICV8:
|
||||
case ENCR_AES_GCM_ICV12:
|
||||
case ENCR_AES_GCM_ICV16:
|
||||
case ENCR_CAMELLIA_CCM_ICV8:
|
||||
case ENCR_CAMELLIA_CCM_ICV12:
|
||||
case ENCR_CAMELLIA_CCM_ICV16:
|
||||
case ENCR_NULL_AUTH_AES_GMAC:
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a matching alg/keysize in two linked lists
|
||||
*/
|
||||
static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv,
|
||||
bool *add, u_int16_t *alg, size_t *key_size)
|
||||
{
|
||||
enumerator_t *e1, *e2;
|
||||
algorithm_t *alg1, *alg2;
|
||||
|
||||
/* if in both are zero algorithms specified, we HAVE a match */
|
||||
if (first->get_count(first) == 0 && second->get_count(second) == 0)
|
||||
{
|
||||
*add = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
e1 = first->create_enumerator(first);
|
||||
e2 = second->create_enumerator(second);
|
||||
/* compare algs, order of algs in "first" is preferred */
|
||||
while (e1->enumerate(e1, &alg1))
|
||||
{
|
||||
e2->destroy(e2);
|
||||
e2 = second->create_enumerator(second);
|
||||
while (e2->enumerate(e2, &alg2))
|
||||
{
|
||||
if (alg1->algorithm == alg2->algorithm &&
|
||||
alg1->key_size == alg2->key_size)
|
||||
{
|
||||
if (!priv && alg1->algorithm >= 1024)
|
||||
{
|
||||
/* accept private use algorithms only if requested */
|
||||
DBG1(DBG_CFG, "an algorithm from private space would match, "
|
||||
"but peer implementation is unknown, skipped");
|
||||
continue;
|
||||
}
|
||||
/* ok, we have an algorithm */
|
||||
*alg = alg1->algorithm;
|
||||
*key_size = alg1->key_size;
|
||||
*add = TRUE;
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no match in all comparisons */
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.select.
|
||||
*/
|
||||
static proposal_t *select_proposal(private_proposal_t *this,
|
||||
private_proposal_t *other, bool private)
|
||||
{
|
||||
proposal_t *selected;
|
||||
u_int16_t algo;
|
||||
size_t key_size;
|
||||
bool add;
|
||||
|
||||
DBG2(DBG_CFG, "selecting proposal:");
|
||||
|
||||
/* check protocol */
|
||||
if (this->protocol != other->protocol)
|
||||
{
|
||||
DBG2(DBG_CFG, " protocol mismatch, skipping");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
selected = proposal_create(this->protocol);
|
||||
|
||||
/* select encryption algorithm */
|
||||
if (select_algo(this->encryption_algos, other->encryption_algos, private,
|
||||
&add, &algo, &key_size))
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
selected->add_algorithm(selected, ENCRYPTION_ALGORITHM,
|
||||
algo, key_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selected->destroy(selected);
|
||||
DBG2(DBG_CFG, " no acceptable %N found",
|
||||
transform_type_names, ENCRYPTION_ALGORITHM);
|
||||
return NULL;
|
||||
}
|
||||
/* select integrity algorithm */
|
||||
if (!is_authenticated_encryption(algo))
|
||||
{
|
||||
if (select_algo(this->integrity_algos, other->integrity_algos, private,
|
||||
&add, &algo, &key_size))
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
selected->add_algorithm(selected, INTEGRITY_ALGORITHM,
|
||||
algo, key_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selected->destroy(selected);
|
||||
DBG2(DBG_CFG, " no acceptable %N found",
|
||||
transform_type_names, INTEGRITY_ALGORITHM);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* select prf algorithm */
|
||||
if (select_algo(this->prf_algos, other->prf_algos, private,
|
||||
&add, &algo, &key_size))
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION,
|
||||
algo, key_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selected->destroy(selected);
|
||||
DBG2(DBG_CFG, " no acceptable %N found",
|
||||
transform_type_names, PSEUDO_RANDOM_FUNCTION);
|
||||
return NULL;
|
||||
}
|
||||
/* select a DH-group */
|
||||
if (select_algo(this->dh_groups, other->dh_groups, private,
|
||||
&add, &algo, &key_size))
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selected->destroy(selected);
|
||||
DBG2(DBG_CFG, " no acceptable %N found",
|
||||
transform_type_names, DIFFIE_HELLMAN_GROUP);
|
||||
return NULL;
|
||||
}
|
||||
/* select if we use ESNs (has no private use space) */
|
||||
if (select_algo(this->esns, other->esns, TRUE, &add, &algo, &key_size))
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selected->destroy(selected);
|
||||
DBG2(DBG_CFG, " no acceptable %N found",
|
||||
transform_type_names, EXTENDED_SEQUENCE_NUMBERS);
|
||||
return NULL;
|
||||
}
|
||||
DBG2(DBG_CFG, " proposal matches");
|
||||
|
||||
/* apply SPI from "other" */
|
||||
selected->set_spi(selected, other->spi);
|
||||
|
||||
/* everything matched, return new proposal */
|
||||
return selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.get_protocols.
|
||||
*/
|
||||
static protocol_id_t get_protocol(private_proposal_t *this)
|
||||
{
|
||||
return this->protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.set_spi.
|
||||
*/
|
||||
static void set_spi(private_proposal_t *this, u_int64_t spi)
|
||||
{
|
||||
this->spi = spi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.get_spi.
|
||||
*/
|
||||
static u_int64_t get_spi(private_proposal_t *this)
|
||||
{
|
||||
return this->spi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone a algorithm list
|
||||
*/
|
||||
static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list)
|
||||
{
|
||||
algorithm_t *algo, *clone_algo;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
enumerator = list->create_enumerator(list);
|
||||
while (enumerator->enumerate(enumerator, &algo))
|
||||
{
|
||||
clone_algo = malloc_thing(algorithm_t);
|
||||
memcpy(clone_algo, algo, sizeof(algorithm_t));
|
||||
clone_list->insert_last(clone_list, (void*)clone_algo);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if an algorithm list equals
|
||||
*/
|
||||
static bool algo_list_equals(linked_list_t *l1, linked_list_t *l2)
|
||||
{
|
||||
enumerator_t *e1, *e2;
|
||||
algorithm_t *alg1, *alg2;
|
||||
bool equals = TRUE;
|
||||
|
||||
if (l1->get_count(l1) != l2->get_count(l2))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
e1 = l1->create_enumerator(l1);
|
||||
e2 = l2->create_enumerator(l2);
|
||||
while (e1->enumerate(e1, &alg1) && e2->enumerate(e2, &alg2))
|
||||
{
|
||||
if (alg1->algorithm != alg2->algorithm ||
|
||||
alg1->key_size != alg2->key_size)
|
||||
{
|
||||
equals = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e1->destroy(e1);
|
||||
e2->destroy(e2);
|
||||
return equals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of proposal_t.equals.
|
||||
*/
|
||||
static bool equals(private_proposal_t *this, private_proposal_t *other)
|
||||
{
|
||||
if (this == other)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (this->public.equals != other->public.equals)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return (
|
||||
algo_list_equals(this->encryption_algos, other->encryption_algos) &&
|
||||
algo_list_equals(this->integrity_algos, other->integrity_algos) &&
|
||||
algo_list_equals(this->prf_algos, other->prf_algos) &&
|
||||
algo_list_equals(this->dh_groups, other->dh_groups) &&
|
||||
algo_list_equals(this->esns, other->esns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.clone
|
||||
*/
|
||||
static proposal_t *clone_(private_proposal_t *this)
|
||||
{
|
||||
private_proposal_t *clone = (private_proposal_t*)proposal_create(this->protocol);
|
||||
|
||||
clone_algo_list(this->encryption_algos, clone->encryption_algos);
|
||||
clone_algo_list(this->integrity_algos, clone->integrity_algos);
|
||||
clone_algo_list(this->prf_algos, clone->prf_algos);
|
||||
clone_algo_list(this->dh_groups, clone->dh_groups);
|
||||
clone_algo_list(this->esns, clone->esns);
|
||||
|
||||
clone->spi = this->spi;
|
||||
|
||||
return &clone->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the proposal read from a string.
|
||||
*/
|
||||
static void check_proposal(private_proposal_t *this)
|
||||
{
|
||||
enumerator_t *e;
|
||||
algorithm_t *alg;
|
||||
bool all_aead = TRUE;
|
||||
|
||||
e = this->encryption_algos->create_enumerator(this->encryption_algos);
|
||||
while (e->enumerate(e, &alg))
|
||||
{
|
||||
if (!is_authenticated_encryption(alg->algorithm))
|
||||
{
|
||||
all_aead = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e->destroy(e);
|
||||
|
||||
if (all_aead)
|
||||
{
|
||||
/* if all encryption algorithms in the proposal are authenticated encryption
|
||||
* algorithms we MUST NOT propose any integrity algorithms */
|
||||
while (this->integrity_algos->remove_last(this->integrity_algos,
|
||||
(void**)&alg) == SUCCESS)
|
||||
{
|
||||
free(alg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add a algorithm identified by a string to the proposal.
|
||||
*/
|
||||
static status_t add_string_algo(private_proposal_t *this, chunk_t alg)
|
||||
{
|
||||
const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len);
|
||||
|
||||
if (token == NULL)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
add_algorithm(this, token->type, token->algorithm, token->keysize);
|
||||
|
||||
if (this->protocol == PROTO_IKE && token->type == INTEGRITY_ALGORITHM)
|
||||
{
|
||||
pseudo_random_function_t prf;
|
||||
|
||||
switch (token->algorithm)
|
||||
{
|
||||
case AUTH_HMAC_SHA1_96:
|
||||
prf = PRF_HMAC_SHA1;
|
||||
break;
|
||||
case AUTH_HMAC_SHA2_256_128:
|
||||
prf = PRF_HMAC_SHA2_256;
|
||||
break;
|
||||
case AUTH_HMAC_SHA2_384_192:
|
||||
prf = PRF_HMAC_SHA2_384;
|
||||
break;
|
||||
case AUTH_HMAC_SHA2_512_256:
|
||||
prf = PRF_HMAC_SHA2_512;
|
||||
break;
|
||||
case AUTH_HMAC_MD5_96:
|
||||
prf = PRF_HMAC_MD5;
|
||||
break;
|
||||
case AUTH_AES_XCBC_96:
|
||||
prf = PRF_AES128_XCBC;
|
||||
break;
|
||||
default:
|
||||
prf = PRF_UNDEFINED;
|
||||
}
|
||||
if (prf != PRF_UNDEFINED)
|
||||
{
|
||||
add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* print all algorithms of a kind to buffer
|
||||
*/
|
||||
static int print_alg(private_proposal_t *this, char **dst, size_t *len,
|
||||
u_int kind, void *names, bool *first)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
size_t written = 0;
|
||||
u_int16_t alg, size;
|
||||
|
||||
enumerator = create_enumerator(this, kind);
|
||||
while (enumerator->enumerate(enumerator, &alg, &size))
|
||||
{
|
||||
if (*first)
|
||||
{
|
||||
written += print_in_hook(*dst, *len, "%N", names, alg);
|
||||
*first = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
written += print_in_hook(*dst, *len, "/%N", names, alg);
|
||||
}
|
||||
if (size)
|
||||
{
|
||||
written += print_in_hook(*dst, *len, "_%u", size);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
|
||||
const void *const *args)
|
||||
{
|
||||
private_proposal_t *this = *((private_proposal_t**)(args[0]));
|
||||
linked_list_t *list = *((linked_list_t**)(args[0]));
|
||||
enumerator_t *enumerator;
|
||||
size_t written = 0;
|
||||
bool first = TRUE;
|
||||
|
||||
if (this == NULL)
|
||||
{
|
||||
return print_in_hook(dst, len, "(null)");
|
||||
}
|
||||
|
||||
if (spec->hash)
|
||||
{
|
||||
enumerator = list->create_enumerator(list);
|
||||
while (enumerator->enumerate(enumerator, &this))
|
||||
{ /* call recursivly */
|
||||
if (first)
|
||||
{
|
||||
written += print_in_hook(dst, len, "%P", this);
|
||||
first = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
written += print_in_hook(dst, len, ", %P", this);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return written;
|
||||
}
|
||||
|
||||
written = print_in_hook(dst, len, "%N:", protocol_id_names, this->protocol);
|
||||
written += print_alg(this, &dst, &len, ENCRYPTION_ALGORITHM,
|
||||
encryption_algorithm_names, &first);
|
||||
written += print_alg(this, &dst, &len, INTEGRITY_ALGORITHM,
|
||||
integrity_algorithm_names, &first);
|
||||
written += print_alg(this, &dst, &len, PSEUDO_RANDOM_FUNCTION,
|
||||
pseudo_random_function_names, &first);
|
||||
written += print_alg(this, &dst, &len, DIFFIE_HELLMAN_GROUP,
|
||||
diffie_hellman_group_names, &first);
|
||||
written += print_alg(this, &dst, &len, EXTENDED_SEQUENCE_NUMBERS,
|
||||
extended_sequence_numbers_names, &first);
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements proposal_t.destroy.
|
||||
*/
|
||||
static void destroy(private_proposal_t *this)
|
||||
{
|
||||
this->encryption_algos->destroy_function(this->encryption_algos, free);
|
||||
this->integrity_algos->destroy_function(this->integrity_algos, free);
|
||||
this->prf_algos->destroy_function(this->prf_algos, free);
|
||||
this->dh_groups->destroy_function(this->dh_groups, free);
|
||||
this->esns->destroy_function(this->esns, free);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Describtion in header-file
|
||||
*/
|
||||
proposal_t *proposal_create(protocol_id_t protocol)
|
||||
{
|
||||
private_proposal_t *this = malloc_thing(private_proposal_t);
|
||||
|
||||
this->public.add_algorithm = (void (*)(proposal_t*,transform_type_t,u_int16_t,u_int16_t))add_algorithm;
|
||||
this->public.create_enumerator = (enumerator_t* (*)(proposal_t*,transform_type_t))create_enumerator;
|
||||
this->public.get_algorithm = (bool (*)(proposal_t*,transform_type_t,u_int16_t*,u_int16_t*))get_algorithm;
|
||||
this->public.has_dh_group = (bool (*)(proposal_t*,diffie_hellman_group_t))has_dh_group;
|
||||
this->public.strip_dh = (void(*)(proposal_t*))strip_dh;
|
||||
this->public.select = (proposal_t* (*)(proposal_t*,proposal_t*,bool))select_proposal;
|
||||
this->public.get_protocol = (protocol_id_t(*)(proposal_t*))get_protocol;
|
||||
this->public.set_spi = (void(*)(proposal_t*,u_int64_t))set_spi;
|
||||
this->public.get_spi = (u_int64_t(*)(proposal_t*))get_spi;
|
||||
this->public.equals = (bool(*)(proposal_t*, proposal_t *other))equals;
|
||||
this->public.clone = (proposal_t*(*)(proposal_t*))clone_;
|
||||
this->public.destroy = (void(*)(proposal_t*))destroy;
|
||||
|
||||
this->spi = 0;
|
||||
this->protocol = protocol;
|
||||
|
||||
this->encryption_algos = linked_list_create();
|
||||
this->integrity_algos = linked_list_create();
|
||||
this->prf_algos = linked_list_create();
|
||||
this->dh_groups = linked_list_create();
|
||||
this->esns = linked_list_create();
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add supported IKE algorithms to proposal
|
||||
*/
|
||||
static void proposal_add_supported_ike(private_proposal_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
encryption_algorithm_t encryption;
|
||||
integrity_algorithm_t integrity;
|
||||
pseudo_random_function_t prf;
|
||||
diffie_hellman_group_t group;
|
||||
|
||||
enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
|
||||
while (enumerator->enumerate(enumerator, &encryption))
|
||||
{
|
||||
switch (encryption)
|
||||
{
|
||||
case ENCR_AES_CBC:
|
||||
/* we assume that we support all AES sizes */
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
|
||||
break;
|
||||
case ENCR_3DES:
|
||||
case ENCR_AES_CTR:
|
||||
case ENCR_AES_CCM_ICV8:
|
||||
case ENCR_AES_CCM_ICV12:
|
||||
case ENCR_AES_CCM_ICV16:
|
||||
case ENCR_AES_GCM_ICV8:
|
||||
case ENCR_AES_GCM_ICV12:
|
||||
case ENCR_AES_GCM_ICV16:
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
|
||||
break;
|
||||
case ENCR_DES:
|
||||
/* no, thanks */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
|
||||
while (enumerator->enumerate(enumerator, &integrity))
|
||||
{
|
||||
switch (integrity)
|
||||
{
|
||||
case AUTH_HMAC_SHA1_96:
|
||||
case AUTH_HMAC_SHA2_256_128:
|
||||
case AUTH_HMAC_SHA2_384_192:
|
||||
case AUTH_HMAC_SHA2_512_256:
|
||||
case AUTH_HMAC_MD5_96:
|
||||
case AUTH_AES_XCBC_96:
|
||||
add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
|
||||
while (enumerator->enumerate(enumerator, &prf))
|
||||
{
|
||||
switch (prf)
|
||||
{
|
||||
case PRF_HMAC_SHA1:
|
||||
case PRF_HMAC_SHA2_256:
|
||||
case PRF_HMAC_SHA2_384:
|
||||
case PRF_HMAC_SHA2_512:
|
||||
case PRF_HMAC_MD5:
|
||||
case PRF_AES128_XCBC:
|
||||
add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
|
||||
while (enumerator->enumerate(enumerator, &group))
|
||||
{
|
||||
switch (group)
|
||||
{
|
||||
case MODP_NULL:
|
||||
/* only for testing purposes */
|
||||
break;
|
||||
case MODP_768_BIT:
|
||||
/* weak */
|
||||
break;
|
||||
case MODP_1024_BIT:
|
||||
case MODP_1536_BIT:
|
||||
case MODP_2048_BIT:
|
||||
case MODP_4096_BIT:
|
||||
case MODP_8192_BIT:
|
||||
case ECP_256_BIT:
|
||||
case ECP_384_BIT:
|
||||
case ECP_521_BIT:
|
||||
case ECP_192_BIT:
|
||||
case ECP_224_BIT:
|
||||
add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Describtion in header-file
|
||||
*/
|
||||
proposal_t *proposal_create_default(protocol_id_t protocol)
|
||||
{
|
||||
private_proposal_t *this = (private_proposal_t*)proposal_create(protocol);
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case PROTO_IKE:
|
||||
proposal_add_supported_ike(this);
|
||||
break;
|
||||
case PROTO_ESP:
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
|
||||
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
|
||||
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
|
||||
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
|
||||
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
|
||||
add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
|
||||
break;
|
||||
case PROTO_AH:
|
||||
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
|
||||
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
|
||||
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
|
||||
add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/*
|
||||
* Describtion in header-file
|
||||
*/
|
||||
proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
|
||||
{
|
||||
private_proposal_t *this = (private_proposal_t*)proposal_create(protocol);
|
||||
chunk_t string = {(void*)algs, strlen(algs)};
|
||||
chunk_t alg;
|
||||
status_t status = SUCCESS;
|
||||
|
||||
eat_whitespace(&string);
|
||||
if (string.len < 1)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get all tokens, separated by '-' */
|
||||
while (extract_token(&alg, '-', &string))
|
||||
{
|
||||
status |= add_string_algo(this, alg);
|
||||
}
|
||||
if (string.len)
|
||||
{
|
||||
status |= add_string_algo(this, string);
|
||||
}
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
check_proposal(this);
|
||||
|
||||
if (protocol == PROTO_AH || protocol == PROTO_ESP)
|
||||
{
|
||||
add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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 proposal proposal
|
||||
* @{ @ingroup config
|
||||
*/
|
||||
|
||||
#ifndef PROPOSAL_H_
|
||||
#define PROPOSAL_H_
|
||||
|
||||
typedef enum protocol_id_t protocol_id_t;
|
||||
typedef enum extended_sequence_numbers_t extended_sequence_numbers_t;
|
||||
typedef struct proposal_t proposal_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/identification.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/host.h>
|
||||
#include <crypto/transform.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
#include <crypto/diffie_hellman.h>
|
||||
#include <selectors/traffic_selector.h>
|
||||
|
||||
/**
|
||||
* Protocol ID of a proposal.
|
||||
*/
|
||||
enum protocol_id_t {
|
||||
PROTO_NONE = 0,
|
||||
PROTO_IKE = 1,
|
||||
PROTO_AH = 2,
|
||||
PROTO_ESP = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum names for protocol_id_t
|
||||
*/
|
||||
extern enum_name_t *protocol_id_names;
|
||||
|
||||
/**
|
||||
* Extended sequence numbers, as in IKEv2 RFC 3.3.2.
|
||||
*/
|
||||
enum extended_sequence_numbers_t {
|
||||
NO_EXT_SEQ_NUMBERS = 0,
|
||||
EXT_SEQ_NUMBERS = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum strings for extended_sequence_numbers_t.
|
||||
*/
|
||||
extern enum_name_t *extended_sequence_numbers_names;
|
||||
|
||||
/**
|
||||
* Stores a set of algorithms used for an SA.
|
||||
*
|
||||
* A proposal stores algorithms for a specific
|
||||
* protocol. It can store algorithms for one protocol.
|
||||
* Proposals with multiple protocols are not supported,
|
||||
* as it's not specified in RFC4301 anymore.
|
||||
*/
|
||||
struct proposal_t {
|
||||
|
||||
/**
|
||||
* Add an algorithm to the proposal.
|
||||
*
|
||||
* The algorithms are stored by priority, first added
|
||||
* is the most preferred.
|
||||
* Key size is only needed for encryption algorithms
|
||||
* with variable key size (such as AES). Must be set
|
||||
* to zero if key size is not specified.
|
||||
* The alg parameter accepts encryption_algorithm_t,
|
||||
* integrity_algorithm_t, dh_group_number_t and
|
||||
* extended_sequence_numbers_t.
|
||||
*
|
||||
* @param type kind of algorithm
|
||||
* @param alg identifier for algorithm
|
||||
* @param key_size key size to use
|
||||
*/
|
||||
void (*add_algorithm) (proposal_t *this, transform_type_t type,
|
||||
u_int16_t alg, u_int16_t key_size);
|
||||
|
||||
/**
|
||||
* Get an enumerator over algorithms for a specifc algo type.
|
||||
*
|
||||
* @param type kind of algorithm
|
||||
* @return enumerator over u_int16_t alg, u_int16_t key_size
|
||||
*/
|
||||
enumerator_t *(*create_enumerator) (proposal_t *this, transform_type_t type);
|
||||
|
||||
/**
|
||||
* Get the algorithm for a type to use.
|
||||
*
|
||||
* If there are multiple algorithms, only the first is returned.
|
||||
*
|
||||
* @param type kind of algorithm
|
||||
* @param alg pointer which receives algorithm
|
||||
* @param key_size pointer which receives the key size
|
||||
* @return TRUE if algorithm of this kind available
|
||||
*/
|
||||
bool (*get_algorithm) (proposal_t *this, transform_type_t type,
|
||||
u_int16_t *alg, u_int16_t *key_size);
|
||||
|
||||
/**
|
||||
* Check if the proposal has a specific DH group.
|
||||
*
|
||||
* @param group group to check for
|
||||
* @return TRUE if algorithm included
|
||||
*/
|
||||
bool (*has_dh_group) (proposal_t *this, diffie_hellman_group_t group);
|
||||
|
||||
/**
|
||||
* Strip DH groups from proposal to use it without PFS.
|
||||
*/
|
||||
void (*strip_dh)(proposal_t *this);
|
||||
|
||||
/**
|
||||
* Compare two proposal, and select a matching subset.
|
||||
*
|
||||
* If the proposals are for the same protocols (AH/ESP), they are
|
||||
* compared. If they have at least one algorithm of each type
|
||||
* in common, a resulting proposal of this kind is created.
|
||||
*
|
||||
* @param other proposal to compair agains
|
||||
* @param private accepts algorithms allocated in a private range
|
||||
* @return selected proposal, NULL if proposals don't match
|
||||
*/
|
||||
proposal_t *(*select) (proposal_t *this, proposal_t *other, bool private);
|
||||
|
||||
/**
|
||||
* Get the protocol ID of the proposal.
|
||||
*
|
||||
* @return protocol of the proposal
|
||||
*/
|
||||
protocol_id_t (*get_protocol) (proposal_t *this);
|
||||
|
||||
/**
|
||||
* Get the SPI of the proposal.
|
||||
*
|
||||
* @return spi for proto
|
||||
*/
|
||||
u_int64_t (*get_spi) (proposal_t *this);
|
||||
|
||||
/**
|
||||
* Set the SPI of the proposal.
|
||||
*
|
||||
* @param spi spi to set for proto
|
||||
*/
|
||||
void (*set_spi) (proposal_t *this, u_int64_t spi);
|
||||
|
||||
/**
|
||||
* Check for the eqality of two proposals.
|
||||
*
|
||||
* @param other other proposal to check for equality
|
||||
* @return TRUE if other equal to this
|
||||
*/
|
||||
bool (*equals)(proposal_t *this, proposal_t *other);
|
||||
|
||||
/**
|
||||
* Clone a proposal.
|
||||
*
|
||||
* @return clone of proposal
|
||||
*/
|
||||
proposal_t *(*clone) (proposal_t *this);
|
||||
|
||||
/**
|
||||
* Destroys the proposal object.
|
||||
*/
|
||||
void (*destroy) (proposal_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a child proposal for AH, ESP or IKE.
|
||||
*
|
||||
* @param protocol protocol, such as PROTO_ESP
|
||||
* @return proposal_t object
|
||||
*/
|
||||
proposal_t *proposal_create(protocol_id_t protocol);
|
||||
|
||||
/**
|
||||
* Create a default proposal if nothing further specified.
|
||||
*
|
||||
* @param protocol protocol, such as PROTO_ESP
|
||||
* @return proposal_t object
|
||||
*/
|
||||
proposal_t *proposal_create_default(protocol_id_t protocol);
|
||||
|
||||
/**
|
||||
* Create a proposal from a string identifying the algorithms.
|
||||
*
|
||||
* The string is in the same form as a in the ipsec.conf file.
|
||||
* E.g.: aes128-sha2_256-modp2048
|
||||
* 3des-md5
|
||||
* An additional '!' at the end of the string forces this proposal,
|
||||
* without it the peer may choose another algorithm we support.
|
||||
*
|
||||
* @param protocol protocol, such as PROTO_ESP
|
||||
* @param algs algorithms as string
|
||||
* @return proposal_t object
|
||||
*/
|
||||
proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs);
|
||||
|
||||
/**
|
||||
* printf hook function for proposal_t.
|
||||
*
|
||||
* Arguments are:
|
||||
* proposal_t *proposal
|
||||
* With the #-specifier, arguments are:
|
||||
* linked_list_t *list containing proposal_t*
|
||||
*/
|
||||
int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
|
||||
const void *const *args);
|
||||
|
||||
#endif /** PROPOSAL_H_ @}*/
|
||||
Reference in New Issue
Block a user