diff options
Diffstat (limited to 'src/charon')
77 files changed, 4472 insertions, 3660 deletions
diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 9da2b238a..cc1cffdaa 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -8,7 +8,8 @@ config/backend_manager.c config/backend_manager.h config/backend.h \ config/child_cfg.c config/child_cfg.h \ config/ike_cfg.c config/ike_cfg.h \ config/peer_cfg.c config/peer_cfg.h \ -config/proposal.c config/proposal.h \ +config/proposal.c config/proposal.h config/proposal_keywords.c config/proposal_keywords.h \ +config/auth_cfg.c config/auth_cfg.h \ config/traffic_selector.c config/traffic_selector.h \ config/attributes/attribute_provider.h \ config/attributes/attribute_manager.c config/attributes/attribute_manager.h \ @@ -93,8 +94,7 @@ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/task.c sa/tasks/task.h \ credentials/credential_manager.c credentials/credential_manager.h \ -credentials/auth_info.c credentials/auth_info.h \ -credentials/sets/auth_info_wrapper.c credentials/sets/auth_info_wrapper.h \ +credentials/sets/auth_cfg_wrapper.c credentials/sets/auth_cfg_wrapper.h \ credentials/sets/ocsp_response_wrapper.c credentials/sets/ocsp_response_wrapper.h \ credentials/sets/cert_cache.c credentials/sets/cert_cache.h \ credentials/credential_set.h @@ -108,6 +108,12 @@ AM_CFLAGS = -rdynamic \ -DRESOLV_CONF=\"${resolv_conf}\" charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lpthread -lm -ldl +EXTRA_DIST = config/proposal_keywords.txt +MAINTAINERCLEANFILES = config/proposal_keywords.c + +config/proposal_keywords.c: config/proposal_keywords.txt config/proposal_keywords.h + $(GPERF) -C -G -c -t < $< > $@ + # compile options ################# diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c index 670c535b0..c0b8e45e1 100644 --- a/src/charon/bus/bus.c +++ b/src/charon/bus/bus.c @@ -521,6 +521,45 @@ static void child_keys(private_bus_t *this, child_sa_t *child_sa, } /** + * Implementation of bus_t.authorize + */ +static bool authorize(private_bus_t *this, linked_list_t *auth, bool final) +{ + enumerator_t *enumerator; + ike_sa_t *ike_sa; + entry_t *entry; + bool keep, success = TRUE; + + ike_sa = pthread_getspecific(this->thread_sa); + + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->calling || !entry->listener->authorize) + { + continue; + } + entry->calling++; + keep = entry->listener->authorize(entry->listener, ike_sa, + auth, final, &success); + entry->calling--; + if (!keep) + { + unregister_listener(this, entry, enumerator); + break; + } + if (!success) + { + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return success; +} + +/** * Implementation of bus_t.destroy. */ static void destroy(private_bus_t *this) @@ -548,6 +587,7 @@ bus_t *bus_create() this->public.message = (void(*)(bus_t*, message_t *message, bool incoming))message; this->public.ike_keys = (void(*)(bus_t*, ike_sa_t *ike_sa, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey))ike_keys; this->public.child_keys = (void(*)(bus_t*, child_sa_t *child_sa, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r))child_keys; + this->public.authorize = (bool(*)(bus_t*, linked_list_t *auth, bool final))authorize; this->public.destroy = (void(*)(bus_t*)) destroy; this->listeners = linked_list_create(); diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h index 90ad2017f..5c479b6cb 100644 --- a/src/charon/bus/bus.h +++ b/src/charon/bus/bus.h @@ -210,6 +210,23 @@ struct listener_t { */ bool (*child_keys)(listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r); + + /** + * Hook called to invoke additional authorization rules. + * + * An authorization hook gets invoked several times: After each + * authentication round, the hook gets invoked with with final = FALSE. + * After authentication is complete and the peer configuration is selected, + * it is invoked again, but with final = TRUE. + * + * @param ike_sa IKE_SA to authorize + * @param auth list of auth_cfg_t, done in peers authentication rounds + * @param final TRUE if this is the final hook invocation + * @param success set to TRUE to complete IKE_SA, FALSE abort + * @return TRUE to stay registered, FALSE to unregister + */ + bool (*authorize)(listener_t *this, ike_sa_t *ike_sa, linked_list_t *auth, + bool final, bool *success); }; /** @@ -317,6 +334,15 @@ struct bus_t { void (*message)(bus_t *this, message_t *message, bool incoming); /** + * IKE_SA authorization hook. + * + * @param auth list of auth_cfg_t, containing peers authentication info + * @param final TRUE if this is the final invocation + * @return TRUE to establish IKE_SA, FALSE to send AUTH_FAILED + */ + bool (*authorize)(bus_t *this, linked_list_t *auth, bool final); + + /** * IKE_SA keymat hook. * * @param ike_sa IKE_SA this keymat belongs to diff --git a/src/charon/config/attributes/attribute_manager.c b/src/charon/config/attributes/attribute_manager.c index a069c954a..f0ae4ffa0 100644 --- a/src/charon/config/attributes/attribute_manager.c +++ b/src/charon/config/attributes/attribute_manager.c @@ -49,7 +49,7 @@ struct private_attribute_manager_t { */ static host_t* acquire_address(private_attribute_manager_t *this, char *pool, identification_t *id, - auth_info_t *auth, host_t *requested) + host_t *requested) { enumerator_t *enumerator; attribute_provider_t *current; @@ -59,7 +59,7 @@ static host_t* acquire_address(private_attribute_manager_t *this, enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, ¤t)) { - host = current->acquire_address(current, pool, id, auth, requested); + host = current->acquire_address(current, pool, id, requested); if (host) { break; @@ -143,7 +143,7 @@ attribute_manager_t *attribute_manager_create() { private_attribute_manager_t *this = malloc_thing(private_attribute_manager_t); - this->public.acquire_address = (host_t*(*)(attribute_manager_t*, char*, identification_t*,auth_info_t*,host_t*))acquire_address; + this->public.acquire_address = (host_t*(*)(attribute_manager_t*, char*, identification_t*,host_t*))acquire_address; this->public.release_address = (void(*)(attribute_manager_t*, char *, host_t*, identification_t*))release_address; this->public.add_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))add_provider; this->public.remove_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))remove_provider; diff --git a/src/charon/config/attributes/attribute_manager.h b/src/charon/config/attributes/attribute_manager.h index aef6e7b6e..0ac37e78a 100644 --- a/src/charon/config/attributes/attribute_manager.h +++ b/src/charon/config/attributes/attribute_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -36,14 +36,13 @@ struct attribute_manager_t { * Acquire a virtual IP address to assign to a peer. * * @param pool pool name to acquire address from - * @param id peer identity to get address for - * @param auth authorization infos of peer + * @param id peer identity to get address forua * @param requested IP in configuration request * @return allocated address, NULL to serve none */ host_t* (*acquire_address)(attribute_manager_t *this, char *pool, identification_t *id, - auth_info_t *auth, host_t *requested); + host_t *requested); /** * Release a previously acquired address. diff --git a/src/charon/config/attributes/attribute_provider.h b/src/charon/config/attributes/attribute_provider.h index 5d563e86b..cbd0075ad 100644 --- a/src/charon/config/attributes/attribute_provider.h +++ b/src/charon/config/attributes/attribute_provider.h @@ -25,7 +25,6 @@ #include <library.h> #include <utils/host.h> -#include <credentials/auth_info.h> typedef struct attribute_provider_t attribute_provider_t; @@ -39,13 +38,12 @@ struct attribute_provider_t { * * @param pool name of the pool to acquire address from * @param id peer ID - * @param auth authorization infos * @param requested IP in configuration request * @return allocated address, NULL to serve none */ host_t* (*acquire_address)(attribute_provider_t *this, char *pool, identification_t *id, - auth_info_t *auth, host_t *requested); + host_t *requested); /** * Release a previously acquired address. * diff --git a/src/charon/config/auth_cfg.c b/src/charon/config/auth_cfg.c new file mode 100644 index 000000000..90fe9877d --- /dev/null +++ b/src/charon/config/auth_cfg.c @@ -0,0 +1,770 @@ +/* + * 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. + * + * $Id$ + */ + +#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*)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*)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 '%D'.", 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 '%D'.", + 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 '%D'" + " 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; +} + diff --git a/src/charon/config/auth_cfg.h b/src/charon/config/auth_cfg.h new file mode 100644 index 000000000..c6bc1959b --- /dev/null +++ b/src/charon/config/auth_cfg.h @@ -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_ @}*/ diff --git a/src/charon/config/backend.h b/src/charon/config/backend.h index 4673d3984..42633f73b 100644 --- a/src/charon/config/backend.h +++ b/src/charon/config/backend.h @@ -28,7 +28,6 @@ typedef struct backend_t backend_t; #include <library.h> #include <config/ike_cfg.h> #include <config/peer_cfg.h> -#include <credentials/auth_info.h> #include <utils/linked_list.h> /** @@ -45,6 +44,10 @@ struct backend_t { * * 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 @@ -52,10 +55,17 @@ struct backend_t { enumerator_t* (*create_ike_cfg_enumerator)(backend_t *this, host_t *me, host_t *other); /** - * Create an enumerator over all Peer configs matching two IDs. + * 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 @@ -64,7 +74,7 @@ struct backend_t { identification_t *me, identification_t *other); /** - * Get a peer_cfg identified by it's name, or a name of its child. + * 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 diff --git a/src/charon/config/backend_manager.c b/src/charon/config/backend_manager.c index c31df8d04..28e50ef0a 100644 --- a/src/charon/config/backend_manager.c +++ b/src/charon/config/backend_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Martin Willi + * Copyright (C) 2007-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -68,15 +68,6 @@ typedef struct { } ike_data_t; /** - * data to pass nested peer enumerator - */ -typedef struct { - private_backend_manager_t *this; - identification_t *me; - identification_t *other; -} peer_data_t; - -/** * inner enumerator constructor for IKE cfgs */ static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data) @@ -85,59 +76,58 @@ static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data) } /** - * 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); -} -/** - * inner enumerator constructor for all Peer cfgs - */ -static enumerator_t *peer_enum_create_all(backend_t *backend) -{ - return backend->create_peer_cfg_enumerator(backend, NULL, NULL); -} - -/** * get a match of a candidate ike_cfg for two hosts */ -static ike_cfg_match_t get_match(ike_cfg_t *cand, host_t *me, host_t *other) +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; - 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)) + if (me) { - match += MATCH_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 if (me_cand->is_anyaddr(me_cand)) + else { match += MATCH_ANY; } - me_cand->destroy(me_cand); - 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)) + if (other) { - match += MATCH_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 if (other_cand->is_anyaddr(other_cand)) + else { match += MATCH_ANY; } - other_cand->destroy(other_cand); return match; } @@ -165,7 +155,7 @@ static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this, (void*)ike_enum_create, data, (void*)free); while (enumerator->enumerate(enumerator, (void**)¤t)) { - match = get_match(current, me, other); + match = get_ike_match(current, me, other); if (match) { @@ -191,87 +181,198 @@ static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this, 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; -static enumerator_t *create_peer_cfg_enumerator(private_backend_manager_t *this) +/** + * 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) { - this->lock->read_lock(this->lock); - return enumerator_create_nested( - this->backends->create_enumerator(this->backends), - (void*)peer_enum_create_all, this->lock, - (void*)this->lock->unlock); + 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.get_peer_cfg. + * Implements backend_manager_t.create_peer_cfg_enumerator. */ -static peer_cfg_t *get_peer_cfg(private_backend_manager_t *this, host_t *me, - host_t *other, identification_t *my_id, - identification_t *other_id, auth_info_t *auth) +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) { - peer_cfg_t *current, *found = NULL; enumerator_t *enumerator; - id_match_t best_peer = ID_MATCH_NONE; - ike_cfg_match_t best_ike = MATCH_NONE; peer_data_t *data; - - DBG2(DBG_CFG, "looking for a peer config for %H[%D]...%H[%D]", - me, my_id, other, other_id); + peer_cfg_t *cfg; + linked_list_t *configs, *helper; data = malloc_thing(peer_data_t); - data->this = this; + 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*)free); - while (enumerator->enumerate(enumerator, ¤t)) + 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[%D]...%H[%D]", + 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)) { - identification_t *my_cand, *other_cand; - id_match_t m1, m2, match_peer; + id_match_t match_peer_me, match_peer_other; ike_cfg_match_t match_ike; + match_entry_t *entry; - my_cand = current->get_my_id(current); - other_cand = current->get_other_id(current); - - /* own ID may have wildcards in both, config and request (missing IDr) */ - m1 = my_cand->matches(my_cand, my_id); - if (!m1) - { - m1 = my_id->matches(my_id, my_cand); - } - m2 = other_id->matches(other_id, other_cand); - - match_peer = m1 + m2; - match_ike = get_match(current->get_ike_cfg(current), me, other); + 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 (m1 && m2 && match_ike && - auth->complies(auth, current->get_auth(current))) + if (match_peer_me && match_peer_other && match_ike) { - DBG2(DBG_CFG, " candidate \"%s\": %D...%D with prio %d.%d", - current->get_name(current), my_cand, other_cand, - match_peer, match_ike); - if ((match_peer > best_peer && match_ike >= best_ike) || - (match_peer >= best_peer && match_ike > best_ike)) - { - DESTROY_IF(found); - found = current; - found->get_ref(found); - best_peer = match_peer; - best_ike = 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); } } - if (found) - { - DBG1(DBG_CFG, "found matching peer config \"%s\": %D...%D with prio %d.%d", - found->get_name(found), found->get_my_id(found), - found->get_other_id(found), best_peer, best_ike); - } enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return found; + helper->destroy(helper); + + return enumerator_create_filter(configs->create_enumerator(configs), + (void*)peer_enum_filter, configs, + (void*)peer_enum_filter_destroy); } /** @@ -332,9 +433,8 @@ 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 = (peer_cfg_t* (*)(backend_manager_t*,host_t*,host_t*,identification_t*,identification_t*,auth_info_t*))get_peer_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*))create_peer_cfg_enumerator; + 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; diff --git a/src/charon/config/backend_manager.h b/src/charon/config/backend_manager.h index 1fd921c48..b3c74fb7b 100644 --- a/src/charon/config/backend_manager.h +++ b/src/charon/config/backend_manager.h @@ -64,20 +64,6 @@ struct backend_manager_t { host_t *my_host, host_t *other_host); /** - * Get a peer_config identified by two IDs and authorization info. - * - * @param me own address - * @param other peer address - * @param my_id own ID - * @param other_id peer ID - * @param auth_info authorization info - * @return matching peer_config, or NULL if none found - */ - peer_cfg_t* (*get_peer_cfg)(backend_manager_t *this, host_t *me, - host_t *other, identification_t *my_id, - identification_t *other_id, auth_info_t *auth); - - /** * Get a peer_config identified by it's name. * * @param name name of the peer_config @@ -86,12 +72,20 @@ struct backend_manager_t { peer_cfg_t* (*get_peer_cfg_by_name)(backend_manager_t *this, char *name); /** - * Create an enumerator over all peer configs. + * 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). * - * @return enumerator over peer configs + * @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); - + 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. * diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c index 398244f6d..5d9db1b22 100644 --- a/src/charon/config/peer_cfg.c +++ b/src/charon/config/peer_cfg.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2007-2008 Tobias Brunner - * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -82,16 +82,6 @@ struct private_peer_cfg_t { mutex_t *mutex; /** - * id to use to identify us - */ - identification_t *my_id; - - /** - * allowed id for other - */ - identification_t *other_id; - - /** * should we send a certificate */ cert_policy_t cert_policy; @@ -147,10 +137,15 @@ struct private_peer_cfg_t { char *pool; /** - * required authorization constraints + * local authentication configs (rulesets) */ - auth_info_t *auth; - + linked_list_t *local_auth; + + /** + * remote authentication configs (constraints) + */ + linked_list_t *remote_auth; + #ifdef ME /** * Is this a mediation connection? @@ -287,22 +282,6 @@ static child_cfg_t* select_child_cfg(private_peer_cfg_t *this, } /** - * Implementation of peer_cfg_t.get_my_id - */ -static identification_t *get_my_id(private_peer_cfg_t *this) -{ - return this->my_id; -} - -/** - * Implementation of peer_cfg_t.get_other_id - */ -static identification_t *get_other_id(private_peer_cfg_t *this) -{ - return this->other_id; -} - -/** * Implementation of peer_cfg_t.get_cert_policy. */ static cert_policy_t get_cert_policy(private_peer_cfg_t *this) @@ -397,13 +376,34 @@ static char* get_pool(private_peer_cfg_t *this) { return this->pool; } - + /** - * Implementation of peer_cfg_t.get_auth. + * Implementation of peer_cfg_t.add_auth_cfg */ -static auth_info_t* get_auth(private_peer_cfg_t *this) +static void add_auth_cfg(private_peer_cfg_t *this, + auth_cfg_t *cfg, bool local) { - return this->auth; + 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 @@ -433,6 +433,60 @@ static identification_t* get_peer_id(private_peer_cfg_t *this) #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) @@ -448,8 +502,6 @@ static bool equals(private_peer_cfg_t *this, private_peer_cfg_t *other) return ( this->ike_version == other->ike_version && - this->my_id->equals(this->my_id, other->my_id) && - this->other_id->equals(this->other_id, other->other_id) && this->cert_policy == other->cert_policy && this->unique == other->unique && this->keyingtries == other->keyingtries && @@ -464,7 +516,7 @@ static bool equals(private_peer_cfg_t *this, private_peer_cfg_t *other) this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) && (this->pool == other->pool || (this->pool && other->pool && streq(this->pool, other->pool))) && - this->auth->equals(this->auth, other->auth) + auth_cfg_equal(this, other) #ifdef ME && this->mediation == other->mediation && this->mediated_by == other->mediated_by && @@ -492,11 +544,13 @@ 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)); - this->my_id->destroy(this->my_id); - this->other_id->destroy(this->other_id); + this->child_cfgs->destroy_offset(this->child_cfgs, + offsetof(child_cfg_t, destroy)); DESTROY_IF(this->virtual_ip); - this->auth->destroy(this->auth); + 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); @@ -512,7 +566,6 @@ static void destroy(private_peer_cfg_t *this) * Described in header-file */ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, - identification_t *my_id, identification_t *other_id, 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, @@ -531,8 +584,6 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_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_my_id = (identification_t* (*)(peer_cfg_t*))get_my_id; - this->public.get_other_id = (identification_t* (*)(peer_cfg_t *))get_other_id; 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; @@ -543,7 +594,8 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, 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.get_auth = (auth_info_t*(*)(peer_cfg_t*))get_auth; + 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; @@ -559,8 +611,6 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->ike_cfg = ike_cfg; this->child_cfgs = linked_list_create(); this->mutex = mutex_create(MUTEX_DEFAULT); - this->my_id = my_id; - this->other_id = other_id; this->cert_policy = cert_policy; this->unique = unique; this->keyingtries = keyingtries; @@ -580,7 +630,8 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->dpd = dpd; this->virtual_ip = virtual_ip; this->pool = pool ? strdup(pool) : NULL; - this->auth = auth_info_create(); + this->local_auth = linked_list_create(); + this->remote_auth = linked_list_create(); this->refcount = 1; #ifdef ME this->mediation = mediation; diff --git a/src/charon/config/peer_cfg.h b/src/charon/config/peer_cfg.h index 3a776927e..7cfe61207 100644 --- a/src/charon/config/peer_cfg.h +++ b/src/charon/config/peer_cfg.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007-2008 Tobias Brunner - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -38,7 +38,7 @@ typedef struct peer_cfg_t peer_cfg_t; #include <config/child_cfg.h> #include <sa/authenticators/authenticator.h> #include <sa/authenticators/eap/eap_method.h> -#include <credentials/auth_info.h> +#include <config/auth_cfg.h> /** * Certificate sending policy. This is also used for certificate @@ -87,27 +87,33 @@ extern enum_name_t *unique_policy_names; * 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 | | - ... |-+ - +---------------+ | - ... | +---------------+ - +-------------------+ - ^ - | - +-------------------+ - | auth_info | - +-------------------+ - | auth_items | - +-------------------+ + +-------------------+ +---------------+ + +---------------+ | 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 - * The auth_info_t object associated to the peer_cfg holds additional - * authorization constraints. A peer who wants to use a config needs to fullfil - * the requirements defined in auth_info. + * + * 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 { @@ -169,25 +175,20 @@ struct peer_cfg_t { host_t *other_host); /** - * Get the authentication constraint items. + * Add an authentication config to the peer configuration. * - * @return auth_info object to manipulate requirements + * @param config config to add + * @param local TRUE for local rules, FALSE for remote constraints */ - auth_info_t* (*get_auth)(peer_cfg_t *this); - - /** - * Get own ID. - * - * @return own id - */ - identification_t* (*get_my_id)(peer_cfg_t *this); + void (*add_auth_cfg)(peer_cfg_t *this, auth_cfg_t *cfg, bool local); /** - * Get peers ID. - * - * @return other id + * Create an enumerator over registered authentication configs. + * + * @param local TRUE for local rules, FALSE for remote constraints + * @return enumerator over auth_cfg_t* */ - identification_t* (*get_other_id)(peer_cfg_t *this); + enumerator_t* (*create_auth_cfg_enumerator)(peer_cfg_t *this, bool local); /** * Should be sent a certificate for this connection? @@ -331,8 +332,6 @@ struct peer_cfg_t { * @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 my_id identification_t for ourselves - * @param other_id identification_t for the remote guy * @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 @@ -350,7 +349,6 @@ struct peer_cfg_t { * @return peer_cfg_t object */ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, - identification_t *my_id, identification_t *other_id, 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, diff --git a/src/charon/config/proposal.c b/src/charon/config/proposal.c index da6973925..7bddff174 100644 --- a/src/charon/config/proposal.c +++ b/src/charon/config/proposal.c @@ -19,6 +19,7 @@ #include <string.h> #include "proposal.h" +#include "proposal_keywords.h" #include <daemon.h> #include <utils/linked_list.h> @@ -583,222 +584,59 @@ static void check_proposal(private_proposal_t *this) } } +struct proposal_token { + char *name; + transform_type_t type; + u_int16_t algorithm; + u_int16_t keysize; +}; + /** * add a algorithm identified by a string to the proposal. - * TODO: we could use gperf here. */ static status_t add_string_algo(private_proposal_t *this, chunk_t alg) { - if (strncmp(alg.ptr, "null", alg.len) == 0) - { - add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_NULL, 0); - } - else if (strncmp(alg.ptr, "aes128", alg.len) == 0) - { - add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128); - } - else if (strncmp(alg.ptr, "aes192", alg.len) == 0) - { - add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192); - } - else if (strncmp(alg.ptr, "aes256", alg.len) == 0) + const proposal_token_t *token = in_word_set(alg.ptr, alg.len); + + if (token == NULL) { - add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256); + return FAILED; } - else if (strstr(alg.ptr, "ccm")) - { - u_int16_t key_size, icv_size; - if (sscanf(alg.ptr, "aes%huccm%hu", &key_size, &icv_size) == 2) - { - if (key_size == 128 || key_size == 192 || key_size == 256) - { - switch (icv_size) - { - case 8: /* octets */ - case 64: /* bits */ - add_algorithm(this, ENCRYPTION_ALGORITHM, - ENCR_AES_CCM_ICV8, key_size); - break; - case 12: /* octets */ - case 96: /* bits */ - add_algorithm(this, ENCRYPTION_ALGORITHM, - ENCR_AES_CCM_ICV12, key_size); - break; - case 16: /* octets */ - case 128: /* bits */ - add_algorithm(this, ENCRYPTION_ALGORITHM, - ENCR_AES_CCM_ICV16, key_size); - break; - default: - /* invalid ICV size */ - break; - } - } - } - } - else if (strstr(alg.ptr, "gcm")) - { - u_int16_t key_size, icv_size; + add_algorithm(this, token->type, token->algorithm, token->keysize); - if (sscanf(alg.ptr, "aes%hugcm%hu", &key_size, &icv_size) == 2) - { - if (key_size == 128 || key_size == 192 || key_size == 256) - { - switch (icv_size) - { - case 8: /* octets */ - case 64: /* bits */ - add_algorithm(this, ENCRYPTION_ALGORITHM, - ENCR_AES_GCM_ICV8, key_size); - break; - case 12: /* octets */ - case 96: /* bits */ - add_algorithm(this, ENCRYPTION_ALGORITHM, - ENCR_AES_GCM_ICV12, key_size); - break; - case 16: /* octets */ - case 128: /* bits */ - add_algorithm(this, ENCRYPTION_ALGORITHM, - ENCR_AES_GCM_ICV16, key_size); - break; - default: - /* invalid ICV size */ - break; - } - } - } - } - else if (strncmp(alg.ptr, "3des", alg.len) == 0) - { - add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0); - } - /* blowfish only uses some predefined key sizes yet */ - else if (strncmp(alg.ptr, "blowfish128", alg.len) == 0) - { - add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128); - } - else if (strncmp(alg.ptr, "blowfish192", alg.len) == 0) - { - add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192); - } - else if (strncmp(alg.ptr, "blowfish256", alg.len) == 0) - { - add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256); - } - else if (strncmp(alg.ptr, "sha", alg.len) == 0 || - strncmp(alg.ptr, "sha1", alg.len) == 0) - { - /* sha means we use SHA for both, PRF and AUTH */ - add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); - if (this->protocol == PROTO_IKE) - { - add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0); - } - } - else if (strncmp(alg.ptr, "sha256", alg.len) == 0 || - strncmp(alg.ptr, "sha2_256", alg.len) == 0) + if (this->protocol == PROTO_IKE && token->type == INTEGRITY_ALGORITHM) { - add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0); - if (this->protocol == PROTO_IKE) - { - add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_256, 0); - } - } - else if (strncmp(alg.ptr, "sha384", alg.len) == 0 || - strncmp(alg.ptr, "sha2_384", alg.len) == 0) - { - add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0); - if (this->protocol == PROTO_IKE) - { - add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_384, 0); - } - } - else if (strncmp(alg.ptr, "sha512", alg.len) == 0 || - strncmp(alg.ptr, "sha2_512", alg.len) == 0) - { - add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0); - if (this->protocol == PROTO_IKE) - { - add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_512, 0); - } - } - else if (strncmp(alg.ptr, "md5", alg.len) == 0) - { - add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); - if (this->protocol == PROTO_IKE) + pseudo_random_function_t prf; + + switch (token->algorithm) { - add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0); + 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; } - } - else if (strncmp(alg.ptr, "aesxcbc", alg.len) == 0) - { - add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0); - if (this->protocol == PROTO_IKE) + if (prf != PRF_UNDEFINED) { - add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_AES128_XCBC, 0); + add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0); } } - else if (strncmp(alg.ptr, "modpnull", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_NULL, 0); - } - else if (strncmp(alg.ptr, "modp768", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0); - } - else if (strncmp(alg.ptr, "modp1024", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); - } - else if (strncmp(alg.ptr, "modp1536", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0); - } - else if (strncmp(alg.ptr, "modp2048", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); - } - else if (strncmp(alg.ptr, "modp3072", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_3072_BIT, 0); - } - else if (strncmp(alg.ptr, "modp4096", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0); - } - else if (strncmp(alg.ptr, "modp6144", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_6144_BIT, 0); - } - else if (strncmp(alg.ptr, "modp8192", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0); - } - else if (strncmp(alg.ptr, "ecp192", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, ECP_192_BIT, 0); - } - else if (strncmp(alg.ptr, "ecp224", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, ECP_224_BIT, 0); - } - else if (strncmp(alg.ptr, "ecp256", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, ECP_256_BIT, 0); - } - else if (strncmp(alg.ptr, "ecp384", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, ECP_384_BIT, 0); - } - else if (strncmp(alg.ptr, "ecp521", alg.len) == 0) - { - add_algorithm(this, DIFFIE_HELLMAN_GROUP, ECP_521_BIT, 0); - } - else - { - return FAILED; - } return SUCCESS; } diff --git a/src/charon/config/proposal_keywords.h b/src/charon/config/proposal_keywords.h new file mode 100644 index 000000000..ae10d3464 --- /dev/null +++ b/src/charon/config/proposal_keywords.h @@ -0,0 +1,26 @@ +/* proposal keywords + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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. + * + * RCSID $Id:$ + */ + +#ifndef _PROPOSAL_KEYWORDS_H_ +#define _PROPOSAL_KEYWORDS_H_ + +typedef struct proposal_token proposal_token_t; + +extern const proposal_token_t* in_word_set(register const char *str, register unsigned int len); + +#endif /* _PROPOSAL_KEYWORDS_H_ */ + diff --git a/src/charon/config/proposal_keywords.txt b/src/charon/config/proposal_keywords.txt new file mode 100644 index 000000000..e195b1f72 --- /dev/null +++ b/src/charon/config/proposal_keywords.txt @@ -0,0 +1,101 @@ +%{ +/* proposal keywords + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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. + * + * RCSID $Id:$ + */ + +#include <string.h> + +#include "proposal.h" + +#include <crypto/crypters/crypter.h> +#include <crypto/signers/signer.h> + +%} +struct proposal_token { + char *name; + transform_type_t type; + u_int16_t algorithm; + u_int16_t keysize; +}; +%% +null, ENCRYPTION_ALGORITHM, ENCR_NULL, 0 +aes128, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128 +aes192, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192 +aes256, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256 +aes128ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128 +aes128ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128 +aes128ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128 +aes128ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128 +aes128ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128 +aes128ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128 +aes192ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192 +aes192ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192 +aes192ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192 +aes192ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192 +aes192ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192 +aes192ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192 +aes256ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256 +aes256ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256 +aes256ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256 +aes256ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256 +aes256ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256 +aes256ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256 +aes128gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128 +aes128gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128 +aes128gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128 +aes128gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128 +aes128gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128 +aes128gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128 +aes192gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192 +aes192gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192 +aes192gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192 +aes192gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192 +aes192gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192 +aes192gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192 +aes256gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256 +aes256gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256 +aes256gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256 +aes256gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256 +aes256gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256 +aes256gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256 +3des, ENCRYPTION_ALGORITHM, ENCR_3DES, 0 +blowfish128, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128 +blowfish192, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192 +blowfish256, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256 +sha, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0 +sha1, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0 +sha256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0 +sha2_256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0 +sha384, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0 +sha2_384, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0 +sha512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0 +sha2_512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0 +md5, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0 +aesxcbc, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0 +modpnull, DIFFIE_HELLMAN_GROUP, MODP_NULL, 0 +modp768, DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0 +modp1024, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0 +modp1536, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0 +modp2048, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0 +modp3072, DIFFIE_HELLMAN_GROUP, MODP_3072_BIT, 0 +modp4096, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0 +modp6144, DIFFIE_HELLMAN_GROUP, MODP_6144_BIT, 0 +modp8192, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0 +ecp192, DIFFIE_HELLMAN_GROUP, ECP_192_BIT, 0 +ecp224, DIFFIE_HELLMAN_GROUP, ECP_224_BIT, 0 +ecp256, DIFFIE_HELLMAN_GROUP, ECP_256_BIT, 0 +ecp384, DIFFIE_HELLMAN_GROUP, ECP_384_BIT, 0 +ecp521, DIFFIE_HELLMAN_GROUP, ECP_521_BIT, 0 diff --git a/src/charon/credentials/auth_info.c b/src/charon/credentials/auth_info.c deleted file mode 100644 index 62d5ea9b3..000000000 --- a/src/charon/credentials/auth_info.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright (C) 2008 Tobias Brunner - * 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. - * - * $Id$ - */ - - -#include "auth_info.h" - -#include <daemon.h> -#include <utils/linked_list.h> -#include <utils/identification.h> -#include <credentials/certificates/certificate.h> - -ENUM(auth_item_names, AUTHN_CA_CERT, AUTHZ_AC_GROUP, - "AUTHN_AUTH_CLASS", - "AUTHN_EAP_TYPE", - "AUTHN_EAP_VENDOR", - "AUTHN_EAP_IDENTITY", - "AUTHN_CA_CERT", - "AUTHN_CA_CERT_KEYID", - "AUTHN_CA_CERT_NAME", - "AUTHN_IM_CERT", - "AUTHN_SUBJECT_CERT", - "AUTHN_IM_HASH_URL", - "AUTHN_SUBJECT_HASH_URL", - "AUTHZ_PUBKEY", - "AUTHZ_PSK", - "AUTHZ_EAP", - "AUTHZ_CA_CERT", - "AUTHZ_CA_CERT_NAME", - "AUTHZ_IM_CERT", - "AUTHZ_SUBJECT_CERT", - "AUTHZ_CRL_VALIDATION", - "AUTHZ_OCSP_VALIDATION", - "AUTHZ_AC_GROUP", -); - -typedef struct private_auth_info_t private_auth_info_t; - -/** - * private data of item_set - */ -struct private_auth_info_t { - - /** - * public functions - */ - auth_info_t public; - - /** - * list of item_t's - */ - linked_list_t *items; -}; - -typedef struct item_t item_t; - -struct item_t { - /** type of this item */ - auth_item_t type; - /** associated privlege value, if any */ - void *value; -}; - -/** - * enumerator for auth_info_wrapper_t.create_cert_enumerator() - */ -typedef struct { - /** implements enumerator_t */ - enumerator_t public; - /** inner enumerator from linked_list_t */ - enumerator_t *inner; - /** the current item */ - item_t *item; -} item_enumerator_t; - -/** - * enumerate function for item_enumerator_t - */ -static bool enumerate(item_enumerator_t *this, auth_item_t *type, void **value) -{ - if (this->inner->enumerate(this->inner, &this->item)) - { - *type = this->item->type; - *value = this->item->value; - return TRUE; - } - return FALSE; -} - -/** - * destroy function for item_enumerator_t - */ -static void item_enumerator_destroy(item_enumerator_t *this) -{ - this->inner->destroy(this->inner); - free(this); -} - -/** - * Implementation of auth_info_t.create_item_enumerator. - */ -static enumerator_t* create_item_enumerator(private_auth_info_t *this) -{ - item_enumerator_t *enumerator; - - enumerator = malloc_thing(item_enumerator_t); - enumerator->item = NULL; - enumerator->inner = this->items->create_enumerator(this->items); - enumerator->public.enumerate = (void*)enumerate; - enumerator->public.destroy = (void*)item_enumerator_destroy; - return &enumerator->public; -} - -static void destroy_item_value(item_t *item); - -/** - * Implementation of auth_info_t.replace_item. - */ -static void replace_item(item_enumerator_t *enumerator, auth_item_t type, void *value) -{ - destroy_item_value(enumerator->item); - enumerator->item->type = type; - enumerator->item->value = value; -} - -/** - * Implementation of auth_info_t.get_item. - */ -static bool get_item(private_auth_info_t *this, auth_item_t type, void** value) -{ - enumerator_t *enumerator; - void *current_value; - auth_item_t current_type; - bool found = FALSE; - - enumerator = create_item_enumerator(this); - while (enumerator->enumerate(enumerator, ¤t_type, ¤t_value)) - { - if (type == current_type) - { - *value = current_value; - found = TRUE; - break; - } - } - enumerator->destroy(enumerator); - return found; -} - -/** - * Implementation of auth_info_t.add_item. - */ -static void add_item(private_auth_info_t *this, auth_item_t type, void *value) -{ - item_t *item = malloc_thing(item_t); - - item->type = type; - switch (type) - { - case AUTHZ_PUBKEY: - { - public_key_t *key = (public_key_t*)value; - - item->value = key->get_ref(key); - break; - } - case AUTHZ_PSK: - { - shared_key_t *key = (shared_key_t*)value; - - item->value = key->get_ref(key); - break; - } - case AUTHN_IM_HASH_URL: - case AUTHN_SUBJECT_HASH_URL: - { - item->value = strdup(value); - break; - } - case AUTHN_CA_CERT: - case AUTHN_IM_CERT: - case AUTHN_SUBJECT_CERT: - case AUTHZ_CA_CERT: - case AUTHZ_IM_CERT: - case AUTHZ_SUBJECT_CERT: - { - certificate_t *cert = (certificate_t*)value; - - item->value = cert->get_ref(cert); - break; - } - case AUTHZ_CRL_VALIDATION: - case AUTHZ_OCSP_VALIDATION: - { - cert_validation_t *validation = malloc_thing(cert_validation_t); - - *validation = *(cert_validation_t*)value; - item->value = validation; - break; - } - case AUTHN_AUTH_CLASS: - case AUTHN_EAP_TYPE: - case AUTHN_EAP_VENDOR: - case AUTHZ_EAP: - { - u_int *intval = malloc_thing(u_int); - - *intval = *(u_int*)value; - item->value = intval; - break; - } - case AUTHN_EAP_IDENTITY: - case AUTHN_CA_CERT_KEYID: - case AUTHN_CA_CERT_NAME: - case AUTHZ_CA_CERT_NAME: - case AUTHZ_AC_GROUP: - { - identification_t *id = (identification_t*)value; - - item->value = id->clone(id); - break; - } - } - this->items->insert_last(this->items, item); -} - - -/** - * Implementation of auth_info_t.complies. - */ -static bool complies(private_auth_info_t *this, auth_info_t *constraints) -{ - enumerator_t *enumerator; - bool success = TRUE; - auth_item_t t1, t2; - void *value; - - enumerator = constraints->create_item_enumerator(constraints); - while (enumerator->enumerate(enumerator, &t1, &value)) - { - switch (t1) - { - case AUTHN_AUTH_CLASS: - case AUTHN_EAP_TYPE: - case AUTHN_EAP_VENDOR: - case AUTHN_EAP_IDENTITY: - case AUTHN_CA_CERT_KEYID: - case AUTHN_CA_CERT: - case AUTHN_CA_CERT_NAME: - case AUTHN_IM_CERT: - case AUTHN_SUBJECT_CERT: - case AUTHN_IM_HASH_URL: - case AUTHN_SUBJECT_HASH_URL: - { /* skip non-authorization tokens */ - continue; - } - case AUTHZ_CRL_VALIDATION: - case AUTHZ_OCSP_VALIDATION: - { - cert_validation_t *valid; - - /* OCSP validation is also sufficient for CRL constraint, but - * not vice-versa */ - if (!get_item(this, t1, (void**)&valid) && - t1 == AUTHZ_CRL_VALIDATION && - !get_item(this, AUTHZ_OCSP_VALIDATION, (void**)&valid)) - { - DBG1(DBG_CFG, "constraint check failed: %N requires at " - "least %N, but no check done", auth_item_names, t1, - cert_validation_names, *(cert_validation_t*)value); - success = FALSE; - break; - } - switch (*(cert_validation_t*)value) - { - case VALIDATION_SKIPPED: - if (*valid == VALIDATION_SKIPPED) - { - break; - } /* FALL */ - case VALIDATION_GOOD: - if (*valid == VALIDATION_GOOD) - { - break; - } /* FALL */ - default: - DBG1(DBG_CFG, "constraint check failed: %N is %N, but " - "requires at least %N", auth_item_names, t1, - cert_validation_names, *valid, - cert_validation_names, *(cert_validation_t*)value); - success = FALSE; - break; - } - break; - } - case AUTHZ_CA_CERT: - { - enumerator_t *enumerator; - certificate_t *c1, *c2; - - c1 = (certificate_t*)value; - - success = FALSE; - enumerator = create_item_enumerator(this); - while (enumerator->enumerate(enumerator, &t2, &c2)) - { - if ((t2 == AUTHZ_CA_CERT || t2 == AUTHZ_IM_CERT) && - c1->equals(c1, c2)) - { - success = TRUE; - } - } - enumerator->destroy(enumerator); - if (!success) - { - DBG1(DBG_CFG, "constraint check failed: peer not " - "authenticated by CA '%D'.", c1->get_subject(c1)); - } - break; - } - case AUTHZ_CA_CERT_NAME: - { - enumerator_t *enumerator; - certificate_t *cert; - identification_t *id; - - id = (identification_t*)value; - success = FALSE; - enumerator = create_item_enumerator(this); - while (enumerator->enumerate(enumerator, &t2, &cert)) - { - if ((t2 == AUTHZ_CA_CERT || t2 == AUTHZ_IM_CERT) && - cert->has_subject(cert, id)) - { - success = TRUE; - } - } - enumerator->destroy(enumerator); - if (!success) - { - DBG1(DBG_CFG, "constraint check failed: peer not " - "authenticated by CA '%D'.", id); - } - break; - } - case AUTHZ_PUBKEY: - case AUTHZ_PSK: - case AUTHZ_IM_CERT: - case AUTHZ_SUBJECT_CERT: - case AUTHZ_EAP: - case AUTHZ_AC_GROUP: - { - DBG1(DBG_CFG, "constraint check %N not implemented!", - auth_item_names, t1); - success = FALSE; - break; - } - } - if (!success) - { - break; - } - } - enumerator->destroy(enumerator); - return success; -} - -/** - * Implementation of auth_info_t.merge. - */ -static void merge(private_auth_info_t *this, private_auth_info_t *other) -{ - item_t *item; - - while (other->items->remove_first(other->items, (void**)&item) == SUCCESS) - { - this->items->insert_last(this->items, item); - } -} - -/** - * Implementation of auth_info_t.equals. - */ -static bool equals(private_auth_info_t *this, private_auth_info_t *other) -{ - enumerator_t *e1, *e2; - item_t *i1, *i2; - bool equal = TRUE, found; - - e1 = this->items->create_enumerator(this->items); - while (e1->enumerate(e1, &i1)) - { - found = FALSE; - e2 = other->items->create_enumerator(other->items); - while (e2->enumerate(e2, &i2)) - { - if (i1->type == i2->type) - { - switch (i1->type) - { - case AUTHZ_CRL_VALIDATION: - case AUTHZ_OCSP_VALIDATION: - { - cert_validation_t c1, c2; - - c1 = *(cert_validation_t*)i1->value; - c2 = *(cert_validation_t*)i2->value; - - if (c1 == c2) - { - found = TRUE; - break; - } - continue; - } - case AUTHN_IM_HASH_URL: - case AUTHN_SUBJECT_HASH_URL: - { - if (streq(i1->value, i2->value)) - { - found = TRUE; - break; - } - continue; - } - case AUTHN_CA_CERT: - case AUTHN_IM_CERT: - case AUTHN_SUBJECT_CERT: - case AUTHZ_CA_CERT: - case AUTHZ_IM_CERT: - case AUTHZ_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 AUTHN_EAP_IDENTITY: - case AUTHN_CA_CERT_KEYID: - case AUTHN_CA_CERT_NAME: - case AUTHZ_CA_CERT_NAME: - { - identification_t *c1, *c2; - - c1 = (identification_t*)i1->value; - c2 = (identification_t*)i2->value; - - if (c1->equals(c1, c2)) - { - found = TRUE; - break; - } - continue; - } - case AUTHN_AUTH_CLASS: - case AUTHN_EAP_TYPE: - case AUTHN_EAP_VENDOR: - { - if (*(u_int*)i1->value == *(u_int*)i2->value) - { - found = TRUE; - break; - } - } - case AUTHZ_PUBKEY: - case AUTHZ_PSK: - case AUTHZ_EAP: - case AUTHZ_AC_GROUP: - /* TODO: implement value comparison */ - break; - } - break; - } - } - e2->destroy(e2); - if (!found) - { - equal = FALSE; - break; - } - } - e1->destroy(e1); - return equal; -} - -/** - * Destroy the value associated with an item - */ -static void destroy_item_value(item_t *item) -{ - switch (item->type) - { - case AUTHZ_PUBKEY: - { - public_key_t *key = (public_key_t*)item->value; - key->destroy(key); - break; - } - case AUTHZ_PSK: - { - shared_key_t *key = (shared_key_t*)item->value; - key->destroy(key); - break; - } - case AUTHN_CA_CERT: - case AUTHN_IM_CERT: - case AUTHN_SUBJECT_CERT: - case AUTHZ_CA_CERT: - case AUTHZ_IM_CERT: - case AUTHZ_SUBJECT_CERT: - { - certificate_t *cert = (certificate_t*)item->value; - cert->destroy(cert); - break; - } - case AUTHN_AUTH_CLASS: - case AUTHN_EAP_TYPE: - case AUTHN_EAP_VENDOR: - case AUTHN_IM_HASH_URL: - case AUTHN_SUBJECT_HASH_URL: - case AUTHZ_CRL_VALIDATION: - case AUTHZ_OCSP_VALIDATION: - case AUTHZ_EAP: - { - free(item->value); - break; - } - case AUTHN_EAP_IDENTITY: - case AUTHN_CA_CERT_KEYID: - case AUTHN_CA_CERT_NAME: - case AUTHZ_CA_CERT_NAME: - case AUTHZ_AC_GROUP: - { - identification_t *id = (identification_t*)item->value; - id->destroy(id); - break; - } - } -} - -/** - * Implementation of auth_info_t.purge - */ -static void purge(private_auth_info_t *this) -{ - item_t *item; - - while (this->items->remove_last(this->items, (void**)&item) == SUCCESS) - { - destroy_item_value(item); - free(item); - } -} - -/** - * Implementation of auth_info_t.destroy - */ -static void destroy(private_auth_info_t *this) -{ - purge(this); - this->items->destroy(this->items); - free(this); -} - -/* - * see header file - */ -auth_info_t *auth_info_create() -{ - private_auth_info_t *this = malloc_thing(private_auth_info_t); - - this->public.add_item = (void(*)(auth_info_t*, auth_item_t type, void *value))add_item; - this->public.get_item = (bool(*)(auth_info_t*, auth_item_t type, void **value))get_item; - this->public.replace_item = (void(*)(enumerator_t*,auth_item_t,void*))replace_item; - this->public.create_item_enumerator = (enumerator_t*(*)(auth_info_t*))create_item_enumerator; - this->public.complies = (bool(*)(auth_info_t*, auth_info_t *))complies; - this->public.merge = (void(*)(auth_info_t*, auth_info_t *other))merge; - this->public.purge = (void(*)(auth_info_t*))purge; - this->public.equals = (bool(*)(auth_info_t*, auth_info_t *other))equals; - this->public.destroy = (void(*)(auth_info_t*))destroy; - - this->items = linked_list_create(); - - return &this->public; -} - diff --git a/src/charon/credentials/auth_info.h b/src/charon/credentials/auth_info.h deleted file mode 100644 index f480a6e08..000000000 --- a/src/charon/credentials/auth_info.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2008 Tobias Brunner - * 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 auth_info auth_info - * @{ @ingroup ccredentials - */ - -#ifndef AUTH_INFO_H_ -#define AUTH_INFO_H_ - -#include <utils/enumerator.h> - -typedef struct auth_info_t auth_info_t; -typedef enum auth_item_t auth_item_t; - -/** - * Authentication/Authorization process helper item. - * - * For the authentication process, further information may be needed. These - * items are defined as auth_item_t and have a AUTHN prefix. - * The authentication process returns important data for the authorization - * process, these items are defined with a AUTHZ prefix. - * Authentication uses AUTHN items and creates AUTHZ items during authentication, - * authorization reads AUTHZ values to give out privileges. - * - * +---+ +---------------------+ - * | A | | A | - * | u | | u +-----------+ | - * | t | | t | Required | | - * | h | | h | auth_info | | - * | e | | o +-----------+ | - * | n | | r | | - * +-----------+ | t | | i | | - * | Provided | | i | | z V | - * | auth_info |--| c |-------------| a ----> match? ----|-------> - * +-----------+ | a | | t | - * | t | | i | - * | i | | o | - * | o | | n | - * | n | | | - * +---+ +---------------------+ - */ -enum auth_item_t { - - /* - * items provided to authentication process - */ - - /** authentication class to use, value is auth_class_t* */ - AUTHN_AUTH_CLASS, - /** EAP method to request from peer, value is eap_type_t* */ - AUTHN_EAP_TYPE, - /** EAP vendor to used in conjunction with EAP method, value is u_int32_t* */ - AUTHN_EAP_VENDOR, - /** EAP identity to use within EAP-Identity exchange */ - AUTHN_EAP_IDENTITY, - /** CA certificate to use for authentication, value is certificate_t* */ - AUTHN_CA_CERT, - /** Keyid of a CA certificate to use, value is identification_t* */ - AUTHN_CA_CERT_KEYID, - /** subject DN of a CA certificate to use, value is identification_t* */ - AUTHN_CA_CERT_NAME, - /** intermediate certificate, value is certificate_t* */ - AUTHN_IM_CERT, - /** certificate for trustchain verification, value is certificate_t* */ - AUTHN_SUBJECT_CERT, - /** intermediate certificate supplied as hash and url */ - AUTHN_IM_HASH_URL, - /** end-entity certificate supplied as hash and url */ - AUTHN_SUBJECT_HASH_URL, - - /* - * item provided to authorization process - */ - - /** subject has been authenticated by public key, value is public_key_t* */ - AUTHZ_PUBKEY, - /** subject has ben authenticated using preshared secrets, value is shared_key_t* */ - AUTHZ_PSK, - /** subject has been authenticated using EAP, value is eap_type_t* */ - AUTHZ_EAP, - /** certificate authority, value is certificate_t* */ - AUTHZ_CA_CERT, - /** subject DN of a certificate authority, value is identification_t* */ - AUTHZ_CA_CERT_NAME, - /** intermediate certificate in trustchain, value is certificate_t* */ - AUTHZ_IM_CERT, - /** subject certificate, value is certificate_t* */ - AUTHZ_SUBJECT_CERT, - /** result of a CRL validation, value is cert_validation_t */ - AUTHZ_CRL_VALIDATION, - /** result of a OCSP validation, value is cert_validation_t */ - AUTHZ_OCSP_VALIDATION, - /** subject is in attribute certificate group, value is identification_t* */ - AUTHZ_AC_GROUP, -}; - - -/** - * enum name for auth_item_t. - */ -extern enum_name_t *auth_item_names; - -/** - * The auth_info class contains auth_item_t's used for AA. - * - * A auth_info allows the separation of authentication and authorization. - */ -struct auth_info_t { - - /** - * Add an item to the set. - * - * @param type auth_info type - * @param value associated value to auth_info type, if any - */ - void (*add_item)(auth_info_t *this, auth_item_t type, void *value); - - /** - * Get an item. - * - * @param type auth_info type to get - * @param value pointer to a pointer receiving item - * @return bool if item has been found - */ - bool (*get_item)(auth_info_t *this, auth_item_t type, void **value); - - /** - * Replace an item. - * - * @param type new auth_info type - * @param value pointer to the new value - */ - void (*replace_item)(enumerator_t *this, auth_item_t type, void *value); - - /** - * Create an enumerator over all items. - * - * @return enumerator over (auth_item_t type, void *value) - */ - enumerator_t* (*create_item_enumerator)(auth_info_t *this); - - /** - * Check if this fulfills a set of required constraints. - * - * @param constraints required authorization infos - * @return TRUE if this complies with constraints - */ - bool (*complies)(auth_info_t *this, auth_info_t *constraints); - - /** - * Merge items from other into this. - * - * Items do not get cloned, but moved from other to this. - * - * @param other items to read for merge - */ - void (*merge)(auth_info_t *this, auth_info_t *other); - - /** - * Purge all items in auth_info. - */ - void (*purge)(auth_info_t *this); - - /** - * Check two auth_infos for equality. - * - * @param other other item to compaire against this - * @return TRUE if auth infos identical - */ - bool (*equals)(auth_info_t *this, auth_info_t *other); - - /** - * Destroy a auth_info instance with all associated values. - */ - void (*destroy)(auth_info_t *this); -}; - -/** - * Create a auth_info instance. - */ -auth_info_t *auth_info_create(); - -#endif /** AUTH_INFO_H_ @}*/ diff --git a/src/charon/credentials/credential_manager.c b/src/charon/credentials/credential_manager.c index 2721edc4a..3cd4e35ed 100644 --- a/src/charon/credentials/credential_manager.c +++ b/src/charon/credentials/credential_manager.c @@ -23,7 +23,7 @@ #include <utils/mutex.h> #include <utils/linked_list.h> #include <credentials/sets/cert_cache.h> -#include <credentials/sets/auth_info_wrapper.h> +#include <credentials/sets/auth_cfg_wrapper.h> #include <credentials/sets/ocsp_response_wrapper.h> #include <credentials/certificates/x509.h> #include <credentials/certificates/crl.h> @@ -625,7 +625,7 @@ static certificate_t *get_better_ocsp(private_credential_manager_t *this, */ static cert_validation_t check_ocsp(private_credential_manager_t *this, x509_t *subject, x509_t *issuer, - auth_info_t *auth) + auth_cfg_t *auth) { enumerator_t *enumerator; cert_validation_t valid = VALIDATION_SKIPPED; @@ -706,7 +706,11 @@ static cert_validation_t check_ocsp(private_credential_manager_t *this, } if (auth) { - auth->add_item(auth, AUTHZ_OCSP_VALIDATION, &valid); + auth->add(auth, AUTH_RULE_OCSP_VALIDATION, valid); + if (valid == VALIDATION_GOOD) + { /* successful OCSP check fulfills also CRL constraint */ + auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD); + } } DESTROY_IF(best); return valid; @@ -728,6 +732,7 @@ static certificate_t* fetch_crl(private_credential_manager_t *this, char *url) } crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + chunk_free(&chunk); if (!crl) { DBG1(DBG_CFG, "crl fetched successfully but parsing failed"); @@ -833,7 +838,7 @@ static certificate_t *get_better_crl(private_credential_manager_t *this, */ static cert_validation_t check_crl(private_credential_manager_t *this, x509_t *subject, x509_t *issuer, - auth_info_t *auth) + auth_cfg_t *auth) { cert_validation_t valid = VALIDATION_SKIPPED; identification_t *keyid = NULL; @@ -841,7 +846,7 @@ static cert_validation_t check_crl(private_credential_manager_t *this, certificate_t *current; public_key_t *public; enumerator_t *enumerator; - char *uri; + char *uri = NULL; /* derive the authorityKeyIdentifier from the issuer's public key */ current = &issuer->interface; @@ -920,7 +925,16 @@ static cert_validation_t check_crl(private_credential_manager_t *this, } if (auth) { - auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid); + if (valid == VALIDATION_SKIPPED) + { /* if we skipped CRL validation, we use the result of OCSP for + * constraint checking */ + auth->add(auth, AUTH_RULE_CRL_VALIDATION, + auth->get(auth, AUTH_RULE_OCSP_VALIDATION)); + } + else + { + auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid); + } } DESTROY_IF(best); return valid; @@ -931,7 +945,7 @@ static cert_validation_t check_crl(private_credential_manager_t *this, */ static bool check_certificate(private_credential_manager_t *this, certificate_t *subject, certificate_t *issuer, - bool crl, bool ocsp, auth_info_t *auth) + bool crl, bool ocsp, auth_cfg_t *auth) { time_t not_before, not_after; @@ -963,7 +977,7 @@ static bool check_certificate(private_credential_manager_t *this, DBG1(DBG_CFG, "certificate status is good"); return TRUE; case VALIDATION_REVOKED: - /* has already been logged */ + /* has already been logged */ return FALSE; case VALIDATION_SKIPPED: DBG2(DBG_CFG, "ocsp check skipped, no ocsp found"); @@ -983,8 +997,8 @@ static bool check_certificate(private_credential_manager_t *this, case VALIDATION_GOOD: DBG1(DBG_CFG, "certificate status is good"); return TRUE; - case VALIDATION_REVOKED: - /* has already been logged */ + case VALIDATION_REVOKED: + /* has already been logged */ return FALSE; case VALIDATION_FAILED: case VALIDATION_SKIPPED: @@ -1050,14 +1064,14 @@ static certificate_t *get_issuer_cert(private_credential_manager_t *this, * try to verify the trust chain of subject, return TRUE if trusted */ static bool verify_trust_chain(private_credential_manager_t *this, - certificate_t *subject, auth_info_t *result, + certificate_t *subject, auth_cfg_t *result, bool trusted, bool crl, bool ocsp) { certificate_t *current, *issuer; - auth_info_t *auth; + auth_cfg_t *auth; u_int level = 0; - auth = auth_info_create(); + auth = auth_cfg_create(); current = subject->get_ref(subject); while (level++ < MAX_CA_LEVELS) { @@ -1067,14 +1081,14 @@ static bool verify_trust_chain(private_credential_manager_t *this, /* accept only self-signed CAs as trust anchor */ if (this->cache->issued_by(this->cache, issuer, issuer)) { - auth->add_item(auth, AUTHZ_CA_CERT, issuer); + auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer)); DBG1(DBG_CFG, " using trusted ca certificate \"%D\"", issuer->get_subject(issuer)); trusted = TRUE; } else { - auth->add_item(auth, AUTHZ_IM_CERT, issuer); + auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer)); DBG1(DBG_CFG, " using trusted intermediate ca certificate " "\"%D\"", issuer->get_subject(issuer)); } @@ -1091,7 +1105,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, issuer->destroy(issuer); break; } - auth->add_item(auth, AUTHZ_IM_CERT, issuer); + auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer)); DBG1(DBG_CFG, " using untrusted intermediate certificate " "\"%D\"", issuer->get_subject(issuer)); } @@ -1123,7 +1137,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, } if (trusted) { - result->merge(result, auth); + result->merge(result, auth, FALSE); } auth->destroy(auth); return trusted; @@ -1149,20 +1163,20 @@ typedef struct { bool ocsp; /** pretrusted certificate we have served at first invocation */ certificate_t *pretrusted; - /** currently enumerating auth info */ - auth_info_t *auth; + /** currently enumerating auth config */ + auth_cfg_t *auth; } trusted_enumerator_t; /** * Implements trusted_enumerator_t.enumerate */ static bool trusted_enumerate(trusted_enumerator_t *this, - certificate_t **cert, auth_info_t **auth) + certificate_t **cert, auth_cfg_t **auth) { certificate_t *current; DESTROY_IF(this->auth); - this->auth = auth_info_create(); + this->auth = auth_cfg_create(); if (!this->candidates) { @@ -1181,7 +1195,8 @@ static bool trusted_enumerate(trusted_enumerator_t *this, verify_trust_chain(this->this, this->pretrusted, this->auth, TRUE, this->crl, this->ocsp)) { - this->auth->add_item(this->auth, AUTHZ_CA_CERT, this->pretrusted); + this->auth->add(this->auth, AUTH_RULE_SUBJECT_CERT, + this->pretrusted->get_ref(this->pretrusted)); DBG1(DBG_CFG, " using trusted certificate \"%D\"", this->pretrusted->get_subject(this->pretrusted)); *cert = this->pretrusted; @@ -1264,15 +1279,15 @@ typedef struct { private_credential_manager_t *this; /** currently enumerating key */ public_key_t *current; - /** credset wrapper around auth */ - auth_info_wrapper_t *wrapper; + /** credset wrapper around auth config */ + auth_cfg_wrapper_t *wrapper; } public_enumerator_t; /** * Implements public_enumerator_t.enumerate */ static bool public_enumerate(public_enumerator_t *this, - public_key_t **key, auth_info_t **auth) + public_key_t **key, auth_cfg_t **auth) { certificate_t *cert; @@ -1312,7 +1327,7 @@ static void public_destroy(public_enumerator_t *this) * Implementation of credential_manager_t.create_public_enumerator. */ static enumerator_t* create_public_enumerator(private_credential_manager_t *this, - key_type_t type, identification_t *id, auth_info_t *auth) + key_type_t type, identification_t *id, auth_cfg_t *auth) { public_enumerator_t *enumerator = malloc_thing(public_enumerator_t); @@ -1324,7 +1339,7 @@ static enumerator_t* create_public_enumerator(private_credential_manager_t *this enumerator->wrapper = NULL; if (auth) { - enumerator->wrapper = auth_info_wrapper_create(auth); + enumerator->wrapper = auth_cfg_wrapper_create(auth); add_local_set(this, &enumerator->wrapper->set); } this->lock->read_lock(this->lock); @@ -1334,40 +1349,22 @@ static enumerator_t* create_public_enumerator(private_credential_manager_t *this /** * Check if a certificate's keyid is contained in the auth helper */ -static bool auth_contains_cacert(auth_info_t *auth, certificate_t *cert) +static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert) { enumerator_t *enumerator; identification_t *value; - auth_item_t type; + auth_rule_t type; bool found = FALSE; - enumerator = auth->create_item_enumerator(auth); + enumerator = auth->create_enumerator(auth); while (enumerator->enumerate(enumerator, &type, &value)) { - if (type == AUTHN_CA_CERT && cert->equals(cert, (certificate_t*)value)) + if (type == AUTH_RULE_CA_CERT && + cert->equals(cert, (certificate_t*)value)) { found = TRUE; break; } - if (type == AUTHN_CA_CERT_KEYID) - { - public_key_t *public; - identification_t *certid, *keyid; - - public = cert->get_public_key(cert); - if (public) - { - keyid = (identification_t*)value; - certid = public->get_id(public, keyid->get_type(keyid)); - if (certid && certid->equals(certid, keyid)) - { - public->destroy(public); - found = TRUE; - break; - } - public->destroy(public); - } - } } enumerator->destroy(enumerator); return found; @@ -1376,19 +1373,21 @@ static bool auth_contains_cacert(auth_info_t *auth, certificate_t *cert) /** * build a trustchain from subject up to a trust anchor in trusted */ -static auth_info_t *build_trustchain(private_credential_manager_t *this, - certificate_t *subject, auth_info_t *auth) +static auth_cfg_t *build_trustchain(private_credential_manager_t *this, + certificate_t *subject, auth_cfg_t *auth) { certificate_t *issuer, *current; - auth_info_t *trustchain; + auth_cfg_t *trustchain; u_int level = 0; - trustchain = auth_info_create(); + trustchain = auth_cfg_create(); - if (!auth->get_item(auth, AUTHN_CA_CERT, (void**)¤t)) + current = auth->get(auth, AUTH_RULE_CA_CERT); + if (!current) { /* no trust anchor specified, return this cert only */ - trustchain->add_item(trustchain, AUTHZ_SUBJECT_CERT, subject); + trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT, + subject->get_ref(subject)); return trustchain; } current = subject->get_ref(subject); @@ -1396,26 +1395,23 @@ static auth_info_t *build_trustchain(private_credential_manager_t *this, { if (auth_contains_cacert(auth, current)) { - trustchain->add_item(trustchain, AUTHZ_CA_CERT, current); - current->destroy(current); + trustchain->add(trustchain, AUTH_RULE_CA_CERT, current); return trustchain; } if (subject == current) { - trustchain->add_item(trustchain, AUTHZ_SUBJECT_CERT, current); + trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT, current); } else { - trustchain->add_item(trustchain, AUTHZ_IM_CERT, current); + trustchain->add(trustchain, AUTH_RULE_IM_CERT, current); } issuer = get_issuer_cert(this, current, FALSE); if (!issuer || issuer->equals(issuer, current) || level > MAX_CA_LEVELS) { DESTROY_IF(issuer); - current->destroy(current); break; } - current->destroy(current); current = issuer; level++; } @@ -1451,12 +1447,12 @@ static private_key_t *get_private_by_cert(private_credential_manager_t *this, */ static private_key_t *get_private(private_credential_manager_t *this, key_type_t type, identification_t *id, - auth_info_t *auth) + auth_cfg_t *auth) { enumerator_t *enumerator; certificate_t *cert; private_key_t *private = NULL; - auth_info_t *trustchain; + auth_cfg_t *trustchain; /* check if this is a lookup by key ID, and do it if so */ if (id) @@ -1471,8 +1467,25 @@ static private_key_t *get_private(private_credential_manager_t *this, break; } } - - /* try to build a trustchain for each certificate found */ + + /* if a specific certificate is preferred, check for a matching key */ + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (cert) + { + private = get_private_by_cert(this, cert, type); + if (private) + { + trustchain = build_trustchain(this, cert, auth); + if (trustchain) + { + auth->merge(auth, trustchain, FALSE); + trustchain->destroy(trustchain); + } + return private; + } + } + + /* try to build a trust chain for each certificate found */ enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); while (enumerator->enumerate(enumerator, &cert)) { @@ -1482,7 +1495,7 @@ static private_key_t *get_private(private_credential_manager_t *this, trustchain = build_trustchain(this, cert, auth); if (trustchain) { - auth->merge(auth, trustchain); + auth->merge(auth, trustchain, FALSE); trustchain->destroy(trustchain); break; } @@ -1491,6 +1504,7 @@ static private_key_t *get_private(private_credential_manager_t *this, } } enumerator->destroy(enumerator); + /* if no valid trustchain was found, fall back to the first usable cert */ if (!private) { @@ -1500,7 +1514,7 @@ static private_key_t *get_private(private_credential_manager_t *this, private = get_private_by_cert(this, cert, type); if (private) { - auth->add_item(auth, AUTHZ_SUBJECT_CERT, cert); + auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert)); break; } } @@ -1566,8 +1580,8 @@ credential_manager_t *credential_manager_create() this->public.create_cdp_enumerator = (enumerator_t *(*)(credential_manager_t*, certificate_type_t type, identification_t *id))create_cdp_enumerator; this->public.get_cert = (certificate_t *(*)(credential_manager_t *this,certificate_type_t cert, key_type_t key,identification_t *, bool))get_cert; this->public.get_shared = (shared_key_t *(*)(credential_manager_t *this,shared_key_type_t type,identification_t *me, identification_t *other))get_shared; - this->public.get_private = (private_key_t*(*)(credential_manager_t*, key_type_t type, identification_t *, auth_info_t*))get_private; - this->public.create_public_enumerator = (enumerator_t*(*)(credential_manager_t*, key_type_t type, identification_t *id, auth_info_t *aut))create_public_enumerator; + this->public.get_private = (private_key_t*(*)(credential_manager_t*, key_type_t type, identification_t *, auth_cfg_t*))get_private; + this->public.create_public_enumerator = (enumerator_t*(*)(credential_manager_t*, key_type_t type, identification_t *id, auth_cfg_t *aut))create_public_enumerator; this->public.flush_cache = (void(*)(credential_manager_t*, certificate_type_t type))flush_cache; this->public.cache_cert = (void(*)(credential_manager_t*, certificate_t *cert))cache_cert; this->public.add_set = (void(*)(credential_manager_t*, credential_set_t *set))add_set; diff --git a/src/charon/credentials/credential_manager.h b/src/charon/credentials/credential_manager.h index 23f43cf55..c628e7e10 100644 --- a/src/charon/credentials/credential_manager.h +++ b/src/charon/credentials/credential_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Martin Willi + * Copyright (C) 2007-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ #include <utils/identification.h> #include <utils/enumerator.h> -#include <credentials/auth_info.h> +#include <config/auth_cfg.h> #include <credentials/credential_set.h> #include <credentials/keys/private_key.h> #include <credentials/keys/shared_key.h> @@ -122,7 +122,6 @@ struct credential_manager_t { * @param type kind of requested shared key * @param me own identity * @param other peers identity - * @param auth auth_info helper * @return shared_key_t, NULL if none found */ shared_key_t *(*get_shared)(credential_manager_t *this, shared_key_type_t type, @@ -138,11 +137,11 @@ struct credential_manager_t { * * @param type type of the key to get * @param id identification the key belongs to - * @param auth auth_info helper, including trusted CA certificates + * @param auth auth config, including trusted CA certificates * @return private_key_t, NULL if none found */ private_key_t* (*get_private)(credential_manager_t *this, key_type_t type, - identification_t *id, auth_info_t *auth); + identification_t *id, auth_cfg_t *auth); /** * Create an enumerator over trusted public keys. @@ -150,9 +149,8 @@ struct credential_manager_t { * This method gets a an enumerator over trusted public keys to verify a * signature created by id. The auth parameter contains additional * authentication infos, e.g. peer and intermediate certificates. - * The resulting enumerator enumerates over public_key_t *, auth_info_t *, - * where the auth info contains gained privileges for the authorization - * process. + * The resulting enumerator enumerates over public_key_t *, auth_cfg_t *, + * where the auth config helper contains rules for constraint checks. * * @param type type of the key to get * @param id owner of the key, signer of the signature @@ -160,7 +158,7 @@ struct credential_manager_t { * @return enumerator */ enumerator_t* (*create_public_enumerator)(credential_manager_t *this, - key_type_t type, identification_t *id, auth_info_t *auth); + key_type_t type, identification_t *id, auth_cfg_t *auth); /** * Cache a certificate by invoking cache_cert() on all registerd sets. diff --git a/src/charon/credentials/sets/auth_info_wrapper.c b/src/charon/credentials/sets/auth_cfg_wrapper.c index 7ec75be15..2e93cc53a 100644 --- a/src/charon/credentials/sets/auth_info_wrapper.c +++ b/src/charon/credentials/sets/auth_cfg_wrapper.c @@ -1,6 +1,6 @@ /* + * Copyright (C) 2008-2009 Martin Willi * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,36 +18,36 @@ #include <daemon.h> -#include "auth_info_wrapper.h" +#include "auth_cfg_wrapper.h" -typedef struct private_auth_info_wrapper_t private_auth_info_wrapper_t; +typedef struct private_auth_cfg_wrapper_t private_auth_cfg_wrapper_t; /** - * private data of auth_info_wrapper + * private data of auth_cfg_wrapper */ -struct private_auth_info_wrapper_t { +struct private_auth_cfg_wrapper_t { /** * public functions */ - auth_info_wrapper_t public; + auth_cfg_wrapper_t public; /** * wrapped auth info */ - auth_info_t *auth; + auth_cfg_t *auth; }; /** - * enumerator for auth_info_wrapper_t.create_cert_enumerator() + * enumerator for auth_cfg_wrapper_t.create_cert_enumerator() */ typedef struct { /** implements enumerator_t */ enumerator_t public; - /** inner enumerator from auth_info */ + /** inner enumerator from auth_cfg */ enumerator_t *inner; - /** wrapped auth info */ - auth_info_t *auth; + /** wrapped auth round */ + auth_cfg_t *auth; /** enumerated cert type */ certificate_type_t cert; /** enumerated key type */ @@ -57,10 +57,11 @@ typedef struct { } wrapper_enumerator_t; /** - * Tries to fetch a certificate that was supplied as "Hash and URL" (replaces the - * item's type and value in place). + * Tries to fetch a certificate that was supplied as "Hash and URL" + * (replaces rule type and value in place). */ -static bool fetch_cert(wrapper_enumerator_t *enumerator, auth_item_t *type, void **value) +static bool fetch_cert(wrapper_enumerator_t *enumerator, + auth_rule_t *rule, void **value) { char *url = (char*)*value; if (!url) @@ -77,29 +78,38 @@ static bool fetch_cert(wrapper_enumerator_t *enumerator, auth_item_t *type, void { DBG1(DBG_CFG, " fetching certificate failed"); /* we set the item to NULL, so we can skip it */ - enumerator->auth->replace_item(enumerator->inner, *type, NULL); + enumerator->auth->replace(enumerator->auth, enumerator->inner, + *rule, NULL); return FALSE; } cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, data, BUILD_END); + BUILD_BLOB_ASN1_DER, data, BUILD_END); free(data.ptr); if (!cert) { DBG1(DBG_CFG, " parsing fetched certificate failed"); /* we set the item to NULL, so we can skip it */ - enumerator->auth->replace_item(enumerator->inner, *type, NULL); + enumerator->auth->replace(enumerator->auth, enumerator->inner, + *rule, NULL); return FALSE; } DBG1(DBG_CFG, " fetched certificate \"%D\"", cert->get_subject(cert)); charon->credentials->cache_cert(charon->credentials, cert); - *type = (*type == AUTHN_IM_HASH_URL) ? AUTHN_IM_CERT : AUTHN_SUBJECT_CERT; + if (*rule == AUTH_HELPER_IM_HASH_URL) + { + *rule = AUTH_HELPER_IM_CERT; + } + else + { + *rule = AUTH_HELPER_SUBJECT_CERT; + } *value = cert; - enumerator->auth->replace_item(enumerator->inner, *type, cert); - + enumerator->auth->replace(enumerator->auth, enumerator->inner, + *rule, cert->get_ref(cert)); return TRUE; } @@ -108,26 +118,25 @@ static bool fetch_cert(wrapper_enumerator_t *enumerator, auth_item_t *type, void */ static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert) { - auth_item_t type; + auth_rule_t rule; certificate_t *current; public_key_t *public; - while (this->inner->enumerate(this->inner, &type, ¤t)) + while (this->inner->enumerate(this->inner, &rule, ¤t)) { - if (type == AUTHN_IM_HASH_URL || - type == AUTHN_SUBJECT_HASH_URL) - { - if (!fetch_cert(this, &type, (void**)¤t)) + if (rule == AUTH_HELPER_IM_HASH_URL || + rule == AUTH_HELPER_SUBJECT_HASH_URL) + { /* on-demand fetching of hash and url certificates */ + if (!fetch_cert(this, &rule, (void**)¤t)) { continue; } } - else if (type != AUTHN_SUBJECT_CERT && - type != AUTHN_IM_CERT) - { + else if (rule != AUTH_HELPER_SUBJECT_CERT && + rule != AUTH_HELPER_IM_CERT) + { /* handle only HELPER certificates */ continue; } - if (this->cert != CERT_ANY && this->cert != current->get_type(current)) { /* CERT type requested, but does not match */ continue; @@ -164,9 +173,9 @@ static void wrapper_enumerator_destroy(wrapper_enumerator_t *this) } /** - * implementation of auth_info_wrapper_t.set.create_cert_enumerator + * implementation of auth_cfg_wrapper_t.set.create_cert_enumerator */ -static enumerator_t *create_enumerator(private_auth_info_wrapper_t *this, +static enumerator_t *create_enumerator(private_auth_cfg_wrapper_t *this, certificate_type_t cert, key_type_t key, identification_t *id, bool trusted) { @@ -181,16 +190,16 @@ static enumerator_t *create_enumerator(private_auth_info_wrapper_t *this, enumerator->cert = cert; enumerator->key = key; enumerator->id = id; - enumerator->inner = this->auth->create_item_enumerator(this->auth); + enumerator->inner = this->auth->create_enumerator(this->auth); enumerator->public.enumerate = (void*)enumerate; enumerator->public.destroy = (void*)wrapper_enumerator_destroy; return &enumerator->public; } /** - * Implementation of auth_info_wrapper_t.destroy + * Implementation of auth_cfg_wrapper_t.destroy */ -static void destroy(private_auth_info_wrapper_t *this) +static void destroy(private_auth_cfg_wrapper_t *this) { free(this); } @@ -198,16 +207,16 @@ static void destroy(private_auth_info_wrapper_t *this) /* * see header file */ -auth_info_wrapper_t *auth_info_wrapper_create(auth_info_t *auth) +auth_cfg_wrapper_t *auth_cfg_wrapper_create(auth_cfg_t *auth) { - private_auth_info_wrapper_t *this = malloc_thing(private_auth_info_wrapper_t); + private_auth_cfg_wrapper_t *this = malloc_thing(private_auth_cfg_wrapper_t); this->public.set.create_private_enumerator = (void*)return_null; this->public.set.create_cert_enumerator = (void*)create_enumerator; this->public.set.create_shared_enumerator = (void*)return_null; this->public.set.create_cdp_enumerator = (void*)return_null; this->public.set.cache_cert = (void*)nop; - this->public.destroy = (void(*)(auth_info_wrapper_t*))destroy; + this->public.destroy = (void(*)(auth_cfg_wrapper_t*))destroy; this->auth = auth; diff --git a/src/charon/credentials/sets/auth_info_wrapper.h b/src/charon/credentials/sets/auth_cfg_wrapper.h index 9186715f0..9baf064af 100644 --- a/src/charon/credentials/sets/auth_info_wrapper.h +++ b/src/charon/credentials/sets/auth_cfg_wrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -16,22 +16,22 @@ */ /** - * @defgroup auth_info_wrapper auth_info_wrapper + * @defgroup auth_cfg_wrapper auth_cfg_wrapper * @{ @ingroup sets */ -#ifndef AUTH_INFO_WRAPPER_H_ -#define AUTH_INFO_WRAPPER_H_ +#ifndef AUTH_CFG_WRAPPER_H_ +#define AUTH_CFG_WRAPPER_H_ +#include <config/auth_cfg.h> #include <credentials/credential_set.h> -#include <credentials/auth_info.h> -typedef struct auth_info_wrapper_t auth_info_wrapper_t; +typedef struct auth_cfg_wrapper_t auth_cfg_wrapper_t; /** - * A wrapper around auth_info_t to handle it like a credential set. + * A wrapper around auth_cfg_t to handle it as a credential set. */ -struct auth_info_wrapper_t { +struct auth_cfg_wrapper_t { /** * implements credential_set_t @@ -39,17 +39,17 @@ struct auth_info_wrapper_t { credential_set_t set; /** - * Destroy a auth_info_wrapper instance. + * Destroy a auth_cfg_wrapper instance. */ - void (*destroy)(auth_info_wrapper_t *this); + void (*destroy)(auth_cfg_wrapper_t *this); }; /** - * Create a auth_info_wrapper instance. + * Create a auth_cfg_wrapper instance. * * @param auth the wrapped auth info * @return wrapper around auth */ -auth_info_wrapper_t *auth_info_wrapper_create(auth_info_t *auth); +auth_cfg_wrapper_t *auth_cfg_wrapper_create(auth_cfg_t *auth); -#endif /** AUTH_INFO_WRAPPER_H_ @}*/ +#endif /** AUTH_CFG_WRAPPER_H_ @}*/ diff --git a/src/charon/encoding/generator.c b/src/charon/encoding/generator.c index ca7cb1e77..759f4ed55 100644 --- a/src/charon/encoding/generator.c +++ b/src/charon/encoding/generator.c @@ -523,17 +523,16 @@ static void generate_payload (private_generator_t *this,payload_t *payload) { int i; this->data_struct = payload; - size_t rule_count; + size_t rule_count, offset_start; encoding_rule_t *rules; payload_type_t payload_type; - u_int8_t *payload_start; /* get payload type */ payload_type = payload->get_type(payload); /* spi size has to get reseted */ this->last_spi_size = 0; - payload_start = this->out_position; + offset_start = this->out_position - this->buffer; DBG2(DBG_ENC, "generating payload of type %N", payload_type_names, payload_type); @@ -893,7 +892,8 @@ static void generate_payload (private_generator_t *this,payload_t *payload) DBG2(DBG_ENC, "generating %N payload finished", payload_type_names, payload_type); DBG3(DBG_ENC, "generated data for this payload %b", - payload_start, this->out_position-payload_start); + this->buffer + offset_start, + this->out_position - this->buffer - offset_start); } /** diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c index a605bd3fd..993d48b89 100644 --- a/src/charon/encoding/message.c +++ b/src/charon/encoding/message.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -208,7 +208,7 @@ static payload_rule_t ike_auth_i_payload_rules[] = { {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, {EXTENSIBLE_AUTHENTICATION, 0, 1, TRUE, TRUE}, {AUTHENTICATION, 0, 1, TRUE, TRUE}, - {ID_INITIATOR, 1, 1, TRUE, FALSE}, + {ID_INITIATOR, 0, 1, TRUE, FALSE}, {CERTIFICATE, 0, 4, TRUE, FALSE}, {CERTIFICATE_REQUEST, 0, 1, TRUE, FALSE}, {ID_RESPONDER, 0, 1, TRUE, FALSE}, @@ -217,9 +217,9 @@ static payload_rule_t ike_auth_i_payload_rules[] = { {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, #else - {SECURITY_ASSOCIATION, 1, 1, TRUE, FALSE}, - {TRAFFIC_SELECTOR_INITIATOR, 1, 1, TRUE, FALSE}, - {TRAFFIC_SELECTOR_RESPONDER, 1, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, #endif /* ME */ {CONFIGURATION, 0, 1, TRUE, FALSE}, {VENDOR_ID, 0, 10, TRUE, FALSE}, @@ -261,9 +261,9 @@ static payload_rule_t ike_auth_r_payload_rules[] = { /* payload type min max encr suff */ {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, {EXTENSIBLE_AUTHENTICATION, 0, 1, TRUE, TRUE}, + {AUTHENTICATION, 0, 1, TRUE, TRUE}, {CERTIFICATE, 0, 4, TRUE, FALSE}, {ID_RESPONDER, 0, 1, TRUE, FALSE}, - {AUTHENTICATION, 0, 1, TRUE, FALSE}, {SECURITY_ASSOCIATION, 0, 1, TRUE, FALSE}, {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, @@ -846,11 +846,11 @@ static host_t * get_destination(private_message_t *this) } /** - * Implementation of message_t.get_payload_iterator. + * Implementation of message_t.create_payload_enumerator. */ -static iterator_t *get_payload_iterator(private_message_t *this) +static enumerator_t *create_payload_enumerator(private_message_t *this) { - return this->payloads->create_iterator(this->payloads, TRUE); + return this->payloads->create_enumerator(this->payloads); } /** @@ -859,10 +859,10 @@ static iterator_t *get_payload_iterator(private_message_t *this) static payload_t *get_payload(private_message_t *this, payload_type_t type) { payload_t *current, *found = NULL; - iterator_t *iterator; + enumerator_t *enumerator; - iterator = this->payloads->create_iterator(this->payloads, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = create_payload_enumerator(this); + while (enumerator->enumerate(enumerator, ¤t)) { if (current->get_type(current) == type) { @@ -870,16 +870,42 @@ static payload_t *get_payload(private_message_t *this, payload_type_t type) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return found; } /** + * Implementation of message_t.get_notify + */ +static notify_payload_t* get_notify(private_message_t *this, notify_type_t type) +{ + enumerator_t *enumerator; + notify_payload_t *notify = NULL; + payload_t *payload; + + enumerator = create_payload_enumerator(this); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify = (notify_payload_t*)payload; + if (notify->get_notify_type(notify) == type) + { + break; + } + notify = NULL; + } + } + enumerator->destroy(enumerator); + return notify; +} + +/** * get a string representation of the message */ static char* get_string(private_message_t *this, char *buf, int len) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; int written; char *pos = buf; @@ -898,8 +924,8 @@ static char* get_string(private_message_t *this, char *buf, int len) pos += written; len -= written; - iterator = this->payloads->create_iterator(this->payloads, TRUE); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = create_payload_enumerator(this); + while (enumerator->enumerate(enumerator, &payload)) { written = snprintf(pos, len, " %N", payload_type_short_names, payload->get_type(payload)); @@ -922,7 +948,7 @@ static char* get_string(private_message_t *this, char *buf, int len) len -= written; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); /* remove last space */ snprintf(pos, len, " ]"); @@ -1076,7 +1102,7 @@ static status_t generate(private_message_t *this, crypter_t *crypter, generator_t *generator; ike_header_t *ike_header; payload_t *payload, *next_payload; - iterator_t *iterator; + enumerator_t *enumerator; status_t status; chunk_t packet_data; char str[256]; @@ -1131,21 +1157,20 @@ static status_t generate(private_message_t *this, crypter_t *crypter, ike_header->set_initiator_flag(ike_header, this->ike_sa_id->is_initiator(this->ike_sa_id)); ike_header->set_initiator_spi(ike_header, this->ike_sa_id->get_initiator_spi(this->ike_sa_id)); ike_header->set_responder_spi(ike_header, this->ike_sa_id->get_responder_spi(this->ike_sa_id)); - + generator = generator_create(); payload = (payload_t*)ike_header; - /* generate every payload expect last one, this is done later*/ - iterator = this->payloads->create_iterator(this->payloads, TRUE); - while(iterator->iterate(iterator, (void**)&next_payload)) + enumerator = create_payload_enumerator(this); + while (enumerator->enumerate(enumerator, &next_payload)) { payload->set_next_type(payload, next_payload->get_type(next_payload)); generator->generate_payload(generator, payload); payload = next_payload; } - iterator->destroy(iterator); + enumerator->destroy(enumerator); /* last payload has no next payload*/ payload->set_next_type(payload, NO_PAYLOAD); @@ -1411,72 +1436,78 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig static status_t verify(private_message_t *this) { int i; - iterator_t *iterator; + enumerator_t *enumerator; payload_t *current_payload; size_t total_found_payloads = 0; DBG2(DBG_ENC, "verifying message structure"); - iterator = this->payloads->create_iterator(this->payloads,TRUE); /* check for payloads with wrong count*/ - for (i = 0; i < this->message_rule->payload_rule_count;i++) + for (i = 0; i < this->message_rule->payload_rule_count; i++) { size_t found_payloads = 0; - - /* check all payloads for specific rule */ - iterator->reset(iterator); + payload_rule_t *rule; - while(iterator->iterate(iterator,(void **)¤t_payload)) + rule = &this->message_rule->payload_rules[i]; + enumerator = create_payload_enumerator(this); + + /* check all payloads for specific rule */ + while (enumerator->enumerate(enumerator, ¤t_payload)) { payload_type_t current_payload_type; + unknown_payload_t *unknown_payload; current_payload_type = current_payload->get_type(current_payload); if (current_payload_type == UNKNOWN_PAYLOAD) { /* unknown payloads are ignored, IF they are not critical */ - unknown_payload_t *unknown_payload = (unknown_payload_t*)current_payload; + unknown_payload = (unknown_payload_t*)current_payload; if (unknown_payload->is_critical(unknown_payload)) { DBG1(DBG_ENC, "%N is not supported, but its critical!", payload_type_names, current_payload_type); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return NOT_SUPPORTED; } } - else if (current_payload_type == this->message_rule->payload_rules[i].payload_type) + else if (current_payload_type == rule->payload_type) { found_payloads++; total_found_payloads++; - DBG2(DBG_ENC, "found payload of type %N", - payload_type_names, this->message_rule->payload_rules[i].payload_type); + DBG2(DBG_ENC, "found payload of type %N", payload_type_names, + rule->payload_type); - /* as soon as ohe payload occures more then specified, the verification fails */ - if (found_payloads > this->message_rule->payload_rules[i].max_occurence) + /* as soon as ohe payload occures more then specified, + * the verification fails */ + if (found_payloads > + rule->max_occurence) { - DBG1(DBG_ENC, "payload of type %N more than %d times (%d) occured in current message", - payload_type_names, current_payload_type, - this->message_rule->payload_rules[i].max_occurence, found_payloads); - iterator->destroy(iterator); + DBG1(DBG_ENC, "payload of type %N more than %d times (%d) " + "occured in current message", payload_type_names, + current_payload_type, rule->max_occurence, + found_payloads); + enumerator->destroy(enumerator); return VERIFY_ERROR; } } } - if (found_payloads < this->message_rule->payload_rules[i].min_occurence) + if (found_payloads < rule->min_occurence) { DBG1(DBG_ENC, "payload of type %N not occured %d times (%d)", - payload_type_names, this->message_rule->payload_rules[i].payload_type, - this->message_rule->payload_rules[i].min_occurence, found_payloads); - iterator->destroy(iterator); + payload_type_names, rule->payload_type, rule->min_occurence, + found_payloads); + enumerator->destroy(enumerator); return VERIFY_ERROR; } - if ((this->message_rule->payload_rules[i].sufficient) && (this->payloads->get_count(this->payloads) == total_found_payloads)) + if (rule->sufficient && + this->payloads->get_count(this->payloads) == total_found_payloads) { - iterator->destroy(iterator); + enumerator->destroy(enumerator); return SUCCESS; } + enumerator->destroy(enumerator); } - iterator->destroy(iterator); return SUCCESS; } @@ -1604,8 +1635,9 @@ message_t *message_create_from_packet(packet_t *packet) this->public.get_source = (host_t * (*) (message_t*)) get_source; this->public.set_destination = (void (*) (message_t*,host_t*)) set_destination; this->public.get_destination = (host_t * (*) (message_t*)) get_destination; - this->public.get_payload_iterator = (iterator_t * (*) (message_t *)) get_payload_iterator; + this->public.create_payload_enumerator = (enumerator_t * (*) (message_t *)) create_payload_enumerator; this->public.get_payload = (payload_t * (*) (message_t *, payload_type_t)) get_payload; + this->public.get_notify = (notify_payload_t*(*)(message_t*, notify_type_t type))get_notify; this->public.parse_header = (status_t (*) (message_t *)) parse_header; this->public.parse_body = (status_t (*) (message_t *,crypter_t*,signer_t*)) parse_body; this->public.get_packet = (packet_t * (*) (message_t*)) get_packet; diff --git a/src/charon/encoding/message.h b/src/charon/encoding/message.h index fcd206cb5..095371747 100644 --- a/src/charon/encoding/message.h +++ b/src/charon/encoding/message.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -286,14 +286,11 @@ struct message_t { void (*set_destination) (message_t *this, host_t *host); /** - * Returns an iterator on all stored payloads. - * - * @warning Don't insert payloads over this iterator. - * Use add_payload() instead. + * Create an enumerator over all payloads. * - * @return iterator_t object which has to get destroyd by the caller + * @return enumerator over payload_t */ - iterator_t * (*get_payload_iterator) (message_t *this); + enumerator_t * (*create_payload_enumerator) (message_t *this); /** * Find a payload of a specific type. @@ -306,6 +303,14 @@ struct message_t { payload_t* (*get_payload) (message_t *this, payload_type_t type); /** + * Get the first notify payload of a specific type. + * + * @param type type of notification payload + * @return notify payload, NULL if no such notify found + */ + notify_payload_t* (*get_notify)(message_t *this, notify_type_t type); + + /** * Returns a clone of the internal stored packet_t object. * * @return packet_t object as clone of internal one diff --git a/src/charon/plugins/eap_mschapv2/eap_mschapv2.c b/src/charon/plugins/eap_mschapv2/eap_mschapv2.c index 2f276eb0b..9bbff817a 100644 --- a/src/charon/plugins/eap_mschapv2/eap_mschapv2.c +++ b/src/charon/plugins/eap_mschapv2/eap_mschapv2.c @@ -17,6 +17,9 @@ #include "eap_mschapv2.h" +#include <ctype.h> +#include <unistd.h> + #include <daemon.h> #include <library.h> #include <utils/enumerator.h> @@ -141,7 +144,7 @@ ENUM_END(mschapv2_error_names, ERROR_CHANGING_PASSWORD); /* Name we send as authenticator */ #define MSCHAPV2_HOST_NAME "strongSwan" /* Message sent on success */ -#define SUCCESS_MESSAGE " M=Welcome to strongSwan" +#define SUCCESS_MESSAGE " M=Welcome2strongSwan" /* Message sent on failure */ #define FAILURE_MESSAGE "E=691 R=1 C=" /* Length of the complete failure message */ @@ -366,7 +369,6 @@ static status_t AuthenticatorResponse(chunk_t password_hash_hash, static const chunk_t magic1 = chunk_from_buf(magic1_data); static const chunk_t magic2 = chunk_from_buf(magic2_data); - status_t status = FAILED; chunk_t digest = chunk_empty, concat; hasher_t *hasher; @@ -527,6 +529,24 @@ static chunk_t ascii_to_unicode(chunk_t ascii) } /** + * sanitize a string for printing + */ +static char* sanitize(char *str) +{ + char *pos = str; + + while (pos && *pos) + { + if (!isprint(*pos)) + { + *pos = '?'; + } + pos++; + } + return str; +} + +/** * Returns a chunk of just the username part of the given user identity. * Note: the chunk points to internal data of the identification. */ @@ -535,7 +555,7 @@ static chunk_t extract_username(identification_t* identification) char *has_domain; chunk_t id; id = identification->get_encoding(identification); - has_domain = (char*)memrchr(id.ptr, '\\', id.len); + has_domain = (char*)memchr(id.ptr, '\\', id.len); if (has_domain) { int len; @@ -625,7 +645,8 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this, if (cha->value_size != CHALLENGE_LEN) { - DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid challenge size"); + DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: " + "invalid challenge size"); return FAILED; } @@ -643,11 +664,11 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this, rng->destroy(rng); shared = charon->credentials->get_shared(charon->credentials, - SHARED_EAP, this->peer, this->server); + SHARED_EAP, this->peer, this->server); if (shared == NULL) { DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'", - this->server, this->peer); + this->server, this->peer); return NOT_FOUND; } @@ -725,7 +746,8 @@ static status_t process_peer_success(private_eap_mschapv2_t *this, token += 2; if (strlen(token) != AUTH_RESPONSE_LEN - 2) { - DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid auth string"); + DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: " + "invalid auth string"); goto error; } hex = chunk_create(token, AUTH_RESPONSE_LEN - 2); @@ -741,7 +763,8 @@ static status_t process_peer_success(private_eap_mschapv2_t *this, if (auth_string.ptr == NULL) { - DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: auth string missing"); + DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: " + "auth string missing"); goto error; } @@ -751,7 +774,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this, goto error; } - DBG1(DBG_IKE, "EAP-MS-CHAPv2 succeeded: '%s'", msg); + DBG1(DBG_IKE, "EAP-MS-CHAPv2 succeeded: '%s'", sanitize(msg)); eap = alloca(len); eap->code = EAP_RESPONSE; @@ -780,7 +803,6 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this, char *message, *token, *msg = NULL; int message_len, error, retryable; chunk_t challenge = chunk_empty; - u_int16_t len = SHORT_HEADER_LEN; data = in->get_data(in); eap = (eap_mschapv2_header_t*)data.ptr; @@ -816,7 +838,8 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this, token += 2; if (strlen(token) != 2 * CHALLENGE_LEN) { - DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid challenge"); + DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message:" + "invalid challenge"); goto error; } hex = chunk_create(token, 2 * CHALLENGE_LEN); @@ -836,7 +859,8 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this, } enumerator->destroy(enumerator); - DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed with error %N: '%s'", mschapv2_error_names, error, msg); + DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed with error %N: '%s'", + mschapv2_error_names, error, sanitize(msg)); /** * at this point, if the error is retryable, we MAY retry the authentication @@ -898,8 +922,8 @@ static status_t process_peer(private_eap_mschapv2_t *this, eap_payload_t *in, } default: { - DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported OpCode (%N)!", - mschapv2_opcode_names, eap->opcode); + DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported " + "OpCode (%N)!", mschapv2_opcode_names, eap->opcode); break; } } @@ -925,7 +949,8 @@ static status_t process_server_retry(private_eap_mschapv2_t *this, * so, to clean up our state we just fail with an EAP-Failure. * this gives an unknown error on the windows side, but is also fine * with the standard. */ - DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed: maximum number of retries reached"); + DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed: " + "maximum number of retries reached"); return FAILED; } @@ -977,6 +1002,7 @@ static status_t process_server_response(private_eap_mschapv2_t *this, identification_t *userid; shared_key_t *shared; int name_len; + char buf[256]; data = in->get_data(in); eap = (eap_mschapv2_header_t*)data.ptr; @@ -991,10 +1017,10 @@ static status_t process_server_response(private_eap_mschapv2_t *this, peer_challenge = chunk_create(res->response.peer_challenge, CHALLENGE_LEN); name_len = min(data.len - RESPONSE_PAYLOAD_LEN, 255); - userid = identification_create_from_encoding(ID_EAP, - chunk_create(res->name, name_len)); + snprintf(buf, sizeof(buf), "%.*s", name_len, res->name); + userid = identification_create_from_string(buf); + DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%D'", userid); username = extract_username(userid); - DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%.*s'", name_len, res->name); shared = charon->credentials->get_shared(charon->credentials, SHARED_EAP, this->server, userid); @@ -1015,7 +1041,8 @@ static status_t process_server_response(private_eap_mschapv2_t *this, password = ascii_to_unicode(shared->get_key(shared)); shared->destroy(shared); - if (GenerateStuff(this, this->challenge, peer_challenge, username, password) != SUCCESS) + if (GenerateStuff(this, this->challenge, peer_challenge, + username, password) != SUCCESS) { DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed"); userid->destroy(userid); @@ -1063,7 +1090,8 @@ static status_t process_server(private_eap_mschapv2_t *this, eap_payload_t *in, if (this->identifier != in->get_identifier(in)) { - DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: unexpected identifier"); + DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: " + "unexpected identifier"); return FAILED; } @@ -1092,8 +1120,8 @@ static status_t process_server(private_eap_mschapv2_t *this, eap_payload_t *in, } default: { - DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported OpCode (%N)!", - mschapv2_opcode_names, eap->opcode); + DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported " + "OpCode (%N)!", mschapv2_opcode_names, eap->opcode); break; } } diff --git a/src/charon/plugins/eap_sim_file/eap_sim_file_card.c b/src/charon/plugins/eap_sim_file/eap_sim_file_card.c index 7969007d0..cd71adf5b 100644 --- a/src/charon/plugins/eap_sim_file/eap_sim_file_card.c +++ b/src/charon/plugins/eap_sim_file/eap_sim_file_card.c @@ -52,13 +52,13 @@ static bool get_triplet(private_eap_sim_file_card_t *this, identification_t *id; char *c_rand, *c_sres, *c_kc; - - DBG1(DBG_CFG, "looking for rand: %b", rand, RAND_LEN); + DBG2(DBG_CFG, "looking for rand: %b", rand, RAND_LEN); enumerator = this->triplets->create_enumerator(this->triplets); while (enumerator->enumerate(enumerator, &id, &c_rand, &c_sres, &c_kc)) { - DBG1(DBG_CFG, "found triplet: %b %b %b", c_rand, RAND_LEN, c_sres, SRES_LEN, c_kc, KC_LEN); + DBG2(DBG_CFG, "found triplet: rand %b\nsres %b\n kc %b", + c_rand, RAND_LEN, c_sres, SRES_LEN, c_kc, KC_LEN); if (memeq(c_rand, rand, RAND_LEN)) { memcpy(sres, c_sres, SRES_LEN); diff --git a/src/charon/plugins/eap_sim_file/eap_sim_file_triplets.c b/src/charon/plugins/eap_sim_file/eap_sim_file_triplets.c index 409e9cbd5..9d30f891c 100644 --- a/src/charon/plugins/eap_sim_file/eap_sim_file_triplets.c +++ b/src/charon/plugins/eap_sim_file/eap_sim_file_triplets.c @@ -196,8 +196,7 @@ static void read_triplets(private_eap_sim_file_triplets_t *this, char *path) switch (i++) { case 0: /* IMSI */ - triplet->imsi = identification_create_from_encoding(ID_EAP, - chunk_create(token, strlen(token))); + triplet->imsi = identification_create_from_string(token); continue; case 1: /* rand */ parse_token(triplet->rand, token, RAND_LEN); @@ -221,7 +220,7 @@ static void read_triplets(private_eap_sim_file_triplets_t *this, char *path) continue; }
- DBG1(DBG_CFG, "triplet: imsi %D\nrand %b\nsres %b\nkc %b",
+ DBG2(DBG_CFG, "triplet: imsi %D\nrand %b\nsres %b\nkc %b",
triplet->imsi, triplet->rand, RAND_LEN,
triplet->sres, SRES_LEN, triplet->kc, KC_LEN); diff --git a/src/charon/plugins/load_tester/load_tester_config.c b/src/charon/plugins/load_tester/load_tester_config.c index f3cd33b61..25055daef 100644 --- a/src/charon/plugins/load_tester/load_tester_config.c +++ b/src/charon/plugins/load_tester/load_tester_config.c @@ -57,9 +57,14 @@ struct private_load_tester_config_t { proposal_t *proposal; /** - * Authentication method to use + * Authentication method(s) to use/expect from initiator */ - auth_class_t class; + char *initiator_auth; + + /** + * Authentication method(s) use/expected from responder + */ + char *responder_auth; /** * incremental numbering of generated configs @@ -68,6 +73,97 @@ struct private_load_tester_config_t { }; /** + * Generate auth config from string + */ +static void generate_auth_cfg(private_load_tester_config_t *this, char *str, + peer_cfg_t *peer_cfg, bool local, int num) +{ + enumerator_t *enumerator; + auth_cfg_t *auth; + identification_t *id; + auth_class_t class; + eap_type_t type; + char buf[128]; + int rnd = 0; + + enumerator = enumerator_create_token(str, "|", " "); + while (enumerator->enumerate(enumerator, &str)) + { + auth = auth_cfg_create(); + rnd++; + + if (streq(str, "psk")) + { /* PSK authentication, use FQDNs */ + class = AUTH_CLASS_PSK; + if ((local && !num) || (!local && num)) + { + id = identification_create_from_string("srv.strongswan.org"); + } + else if (local) + { + snprintf(buf, sizeof(buf), "c%d-r%d.strongswan.org", num, rnd); + id = identification_create_from_string(buf); + } + else + { + id = identification_create_from_string("*.strongswan.org"); + } + } + else if (strneq(str, "eap", strlen("eap"))) + { /* EAP authentication, use a NAI */ + class = AUTH_CLASS_EAP; + if (*(str + strlen("eap")) == '-') + { + type = eap_type_from_string(str + strlen("eap-")); + if (type) + { + auth->add(auth, AUTH_RULE_EAP_TYPE, type); + } + } + if (local && num) + { + snprintf(buf, sizeof(buf), "1%.10d%.4d@strongswan.org", num, rnd); + id = identification_create_from_string(buf); + } + else + { + id = identification_create_from_encoding(ID_ANY, chunk_empty); + } + } + else + { + if (!streq(str, "pubkey")) + { + DBG1(DBG_CFG, "invalid authentication: '%s', fallback to pubkey", + str); + } + /* certificate authentication, use distinguished names */ + class = AUTH_CLASS_PUBKEY; + if ((local && !num) || (!local && num)) + { + id = identification_create_from_string( + "CN=srv, OU=load-test, O=strongSwan"); + } + else if (local) + { + snprintf(buf, sizeof(buf), + "CN=c%d-r%d, OU=load-test, O=strongSwan", num, rnd); + id = identification_create_from_string(buf); + } + else + { + id = identification_create_from_string( + "CN=*, OU=load-test, O=strongSwan"); + } + } + auth->add(auth, AUTH_RULE_AUTH_CLASS, class); + auth->add(auth, AUTH_RULE_IDENTITY, id); + peer_cfg->add_auth_cfg(peer_cfg, auth, local); + } + enumerator->destroy(enumerator); +} + +/** * Generate a new initiator config, num = 0 for responder config */ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) @@ -76,36 +172,26 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) child_cfg_t *child_cfg; peer_cfg_t *peer_cfg; traffic_selector_t *ts; - auth_info_t *auth; - identification_t *local, *remote; proposal_t *proposal; - char buf[128]; - - if (num) - { /* initiator */ - snprintf(buf, sizeof(buf), "CN=cli-%d, OU=load-test, O=strongSwan", num); - local = identification_create_from_string(buf); - snprintf(buf, sizeof(buf), "CN=srv, OU=load-test, O=strongSwan", num); - remote = identification_create_from_string(buf); - } - else - { /* responder */ - local = identification_create_from_string( - "CN=srv, OU=load-test, O=strongSwan"); - remote = identification_create_from_string( - "CN=*, OU=load-test, O=strongSwan"); - } ike_cfg = ike_cfg_create(FALSE, FALSE, "0.0.0.0", this->remote); ike_cfg->add_proposal(ike_cfg, this->proposal->clone(this->proposal)); - peer_cfg = peer_cfg_create("load-test", 2, ike_cfg, local, remote, + peer_cfg = peer_cfg_create("load-test", 2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, 1, 0, 0, /* keytries, rekey, reauth */ 0, 0, FALSE, 0, /* jitter, overtime, mobike, dpddelay */ this->vip ? this->vip->clone(this->vip) : NULL, this->pool, FALSE, NULL, NULL); - auth = peer_cfg->get_auth(peer_cfg); - auth->add_item(auth, AUTHN_AUTH_CLASS, &this->class); - child_cfg = child_cfg_create("load-test", 600, 400, 100, NULL, TRUE, + if (num) + { /* initiator */ + generate_auth_cfg(this, this->initiator_auth, peer_cfg, TRUE, num); + generate_auth_cfg(this, this->responder_auth, peer_cfg, FALSE, num); + } + else + { /* responder */ + generate_auth_cfg(this, this->responder_auth, peer_cfg, TRUE, num); + generate_auth_cfg(this, this->initiator_auth, peer_cfg, FALSE, num); + } + child_cfg = child_cfg_create("load-test", 1200, 600, 0, NULL, TRUE, MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE); proposal = proposal_create_from_string(PROTO_ESP, "aes128-sha1"); child_cfg->add_proposal(child_cfg, proposal); @@ -169,7 +255,6 @@ static void destroy(private_load_tester_config_t *this) load_tester_config_t *load_tester_config_create() { private_load_tester_config_t *this = malloc_thing(private_load_tester_config_t); - char *authstr; this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; @@ -195,16 +280,10 @@ load_tester_config_t *load_tester_config_create() this->proposal = proposal_create_from_string(PROTO_IKE, "aes128-sha1-modp768"); } - authstr = lib->settings->get_str(lib->settings, - "charon.plugins.load_tester.auth", "pubkey"); - if (streq(authstr, "psk")) - { - this->class = AUTH_CLASS_PSK; - } - else - { - this->class = AUTH_CLASS_PUBKEY; - } + this->initiator_auth = lib->settings->get_str(lib->settings, + "charon.plugins.load_tester.initiator_auth", "pubkey"); + this->responder_auth = lib->settings->get_str(lib->settings, + "charon.plugins.load_tester.responder_auth", "pubkey"); this->num = 1; this->peer_cfg = generate_config(this, 0); diff --git a/src/charon/plugins/nm/nm_creds.c b/src/charon/plugins/nm/nm_creds.c index e7cd640a7..de9eb3b1b 100644 --- a/src/charon/plugins/nm/nm_creds.c +++ b/src/charon/plugins/nm/nm_creds.c @@ -259,9 +259,7 @@ static void set_username_password(private_nm_creds_t *this, identification_t *id { this->lock->write_lock(this->lock); DESTROY_IF(this->user); - /* for EAP authentication, we use always use ID_EAP type */ - this->user = identification_create_from_encoding(ID_EAP, - id->get_encoding(id)); + this->user = id->clone(id); free(this->pass); this->pass = password ? strdup(password) : NULL; this->lock->unlock(this->lock); diff --git a/src/charon/plugins/nm/nm_service.c b/src/charon/plugins/nm/nm_service.c index 72744b784..abe55eb7d 100644 --- a/src/charon/plugins/nm/nm_service.c +++ b/src/charon/plugins/nm/nm_service.c @@ -151,7 +151,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, child_cfg_t *child_cfg; traffic_selector_t *ts; ike_sa_t *ike_sa; - auth_info_t *auth; + auth_cfg_t *auth; auth_class_t auth_class = AUTH_CLASS_EAP; certificate_t *cert = NULL; bool agent = FALSE; @@ -223,8 +223,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, str = nm_setting_vpn_get_data_item(settings, "user"); if (str) { - user = identification_create_from_encoding(ID_KEY_ID, - chunk_create(str, strlen(str))); + user = identification_create_from_string(str); str = nm_setting_vpn_get_secret(settings, "password"); creds->set_username_password(creds, user, (char*)str); } @@ -322,15 +321,21 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, ike_cfg = ike_cfg_create(TRUE, encap, "0.0.0.0", (char*)address); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create(CONFIG_NAME, 2, ike_cfg, - user, gateway->clone(gateway), CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ TRUE, 0, /* mobike, DPD */ virtual ? host_create_from_string("0.0.0.0", 0) : NULL, NULL, FALSE, NULL, NULL); /* pool, mediation */ - auth = peer_cfg->get_auth(peer_cfg); - auth->add_item(auth, AUTHN_AUTH_CLASS, &auth_class); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class); + auth->add(auth, AUTH_RULE_IDENTITY, user); + peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, gateway->clone(gateway)); + peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); + child_cfg = child_cfg_create(CONFIG_NAME, 10800, 10200, /* lifetime 3h, rekey 2h50min */ 300, /* jitter 5min */ diff --git a/src/charon/plugins/smp/smp.c b/src/charon/plugins/smp/smp.c index 1283873a4..33a2bb491 100644 --- a/src/charon/plugins/smp/smp.c +++ b/src/charon/plugins/smp/smp.c @@ -294,8 +294,9 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write /* <configlist> */ xmlTextWriterStartElement(writer, "configlist"); - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends); - while (enumerator->enumerate(enumerator, (void**)&peer_cfg)) + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + NULL, NULL, NULL, NULL); + while (enumerator->enumerate(enumerator, &peer_cfg)) { enumerator_t *children; child_cfg_t *child_cfg; @@ -310,8 +311,8 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write /* <peerconfig> */ xmlTextWriterStartElement(writer, "peerconfig"); xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg)); - write_id(writer, "local", peer_cfg->get_my_id(peer_cfg)); - write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg)); + + /* TODO: write auth_cfgs */ /* <ikeconfig> */ ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); diff --git a/src/charon/plugins/sql/pool.c b/src/charon/plugins/sql/pool.c index 9761e88e9..a1c67c691 100644 --- a/src/charon/plugins/sql/pool.c +++ b/src/charon/plugins/sql/pool.c @@ -401,11 +401,6 @@ static enumerator_t *create_lease_query(char *filter) { id = identification_create_from_string(value); } - if (!id) - { - fprintf(stderr, "invalid 'id' in filter string.\n"); - exit(-1); - } break; case FIL_ADDR: if (value) diff --git a/src/charon/plugins/sql/sql_attribute.c b/src/charon/plugins/sql/sql_attribute.c index 826aa8318..484085d11 100644 --- a/src/charon/plugins/sql/sql_attribute.c +++ b/src/charon/plugins/sql/sql_attribute.c @@ -179,7 +179,7 @@ static host_t *get_address(private_sql_attribute_t *this, char *name, */ static host_t* acquire_address(private_sql_attribute_t *this, char *name, identification_t *id, - auth_info_t *auth, host_t *requested) + host_t *requested) { enumerator_t *enumerator; u_int pool, timeout, identity; @@ -263,7 +263,7 @@ sql_attribute_t *sql_attribute_create(database_t *db) private_sql_attribute_t *this = malloc_thing(private_sql_attribute_t); time_t now = time(NULL); - this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address; + this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *, host_t *))acquire_address; this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *, identification_t*))release_address; this->public.destroy = (void(*)(sql_attribute_t*))destroy; diff --git a/src/charon/plugins/sql/sql_config.c b/src/charon/plugins/sql/sql_config.c index 8efa1cb2e..802bbe777 100644 --- a/src/charon/plugins/sql/sql_config.c +++ b/src/charon/plugins/sql/sql_config.c @@ -267,7 +267,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, peer_cfg_t *peer_cfg, *mediated_cfg; ike_cfg_t *ike; host_t *vip = NULL; - auth_info_t *auth; + auth_cfg_t *auth; local_id = identification_create_from_encoding(l_type, l_data); remote_id = identification_create_from_encoding(r_type, r_data); @@ -291,20 +291,26 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, if (ike) { peer_cfg = peer_cfg_create( - name, 2, ike, local_id, remote_id, cert_policy, uniqueid, + name, 2, ike, cert_policy, uniqueid, keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay, vip, pool, mediation, mediated_cfg, peer_id); - auth = peer_cfg->get_auth(peer_cfg); - auth->add_item(auth, AUTHN_AUTH_CLASS, &auth_method); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method); + auth->add(auth, AUTH_RULE_IDENTITY, local_id->clone(local_id)); + peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_IDENTITY, remote_id->clone(remote_id)); if (eap_type) { - auth->add_item(auth, AUTHN_EAP_TYPE, &eap_type); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); + auth->add(auth, AUTH_RULE_EAP_TYPE, eap_type); if (eap_vendor) { - auth->add_item(auth, AUTHN_EAP_VENDOR, &eap_vendor); + auth->add(auth, AUTH_RULE_EAP_VENDOR, eap_vendor); } } + peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); add_child_cfgs(this, peer_cfg, id); return peer_cfg; } diff --git a/src/charon/plugins/stroke/stroke_attribute.c b/src/charon/plugins/stroke/stroke_attribute.c index f850b5320..0ebc367fa 100644 --- a/src/charon/plugins/stroke/stroke_attribute.c +++ b/src/charon/plugins/stroke/stroke_attribute.c @@ -191,7 +191,7 @@ int host2offset(pool_t *pool, host_t *addr) */ static host_t* acquire_address(private_stroke_attribute_t *this, char *name, identification_t *id, - auth_info_t *auth, host_t *requested) + host_t *requested) { pool_t *pool; uintptr_t offset = 0; @@ -530,7 +530,7 @@ stroke_attribute_t *stroke_attribute_create() { private_stroke_attribute_t *this = malloc_thing(private_stroke_attribute_t); - this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address; + this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,host_t *))acquire_address; this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *, identification_t*))release_address; this->public.add_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))add_pool; this->public.del_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))del_pool; diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c index 59c58ca0d..4a0b1ff42 100644 --- a/src/charon/plugins/stroke/stroke_config.c +++ b/src/charon/plugins/stroke/stroke_config.c @@ -55,90 +55,21 @@ struct private_stroke_config_t { }; /** - * data to pass peer_filter - */ -typedef struct { - private_stroke_config_t *this; - identification_t *me; - identification_t *other; -} peer_data_t; - -/** - * destroy id enumerator data and unlock list - */ -static void peer_data_destroy(peer_data_t *data) -{ - data->this->mutex->unlock(data->this->mutex); - free(data); -} - -/** - * filter function for peer configs - */ -static bool peer_filter(peer_data_t *data, peer_cfg_t **in, peer_cfg_t **out) -{ - bool match_me = FALSE, match_other = FALSE; - identification_t *me, *other; - - me = (*in)->get_my_id(*in); - other = (*in)->get_other_id(*in); - - /* own ID may have wildcards in data (no IDr payload) or in config */ - match_me = (!data->me || data->me->matches(data->me, me) || - me->matches(me, data->me)); - /* others ID has wildcards in config only */ - match_other = (!data->other || data->other->matches(data->other, other)); - - if (match_me && match_other) - { - *out = *in; - return TRUE; - } - return FALSE; -} - -/** * Implementation of backend_t.create_peer_cfg_enumerator. */ static enumerator_t* create_peer_cfg_enumerator(private_stroke_config_t *this, identification_t *me, identification_t *other) { - peer_data_t *data; - - data = malloc_thing(peer_data_t); - data->this = this; - data->me = me; - data->other = other; - this->mutex->lock(this->mutex); - return enumerator_create_filter(this->list->create_enumerator(this->list), - (void*)peer_filter, data, - (void*)peer_data_destroy); -} - -/** - * data to pass ike_filter - */ -typedef struct { - private_stroke_config_t *this; - host_t *me; - host_t *other; -} ike_data_t; - -/** - * destroy id enumerator data and unlock list - */ -static void ike_data_destroy(ike_data_t *data) -{ - data->this->mutex->unlock(data->this->mutex); - free(data); + return enumerator_create_cleaner(this->list->create_enumerator(this->list), + (void*)this->mutex->unlock, this->mutex); } /** * filter function for ike configs */ -static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out) +static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out) { *out = (*in)->get_ike_cfg(*in); return TRUE; @@ -150,17 +81,10 @@ static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out) static enumerator_t* create_ike_cfg_enumerator(private_stroke_config_t *this, host_t *me, host_t *other) { - ike_data_t *data; - - data = malloc_thing(ike_data_t); - data->this = this; - data->me = me; - data->other = other; - this->mutex->lock(this->mutex); return enumerator_create_filter(this->list->create_enumerator(this->list), - (void*)ike_filter, data, - (void*)ike_data_destroy); + (void*)ike_filter, this->mutex, + (void*)this->mutex->unlock); } /** @@ -171,34 +95,34 @@ static peer_cfg_t *get_peer_cfg_by_name(private_stroke_config_t *this, char *nam enumerator_t *e1, *e2; peer_cfg_t *current, *found = NULL; child_cfg_t *child; - + this->mutex->lock(this->mutex); e1 = this->list->create_enumerator(this->list); while (e1->enumerate(e1, ¤t)) { - /* compare peer_cfgs name first */ - if (streq(current->get_name(current), name)) - { - found = current; - found->get_ref(found); - break; - } - /* compare all child_cfg names otherwise */ - e2 = current->create_child_cfg_enumerator(current); - while (e2->enumerate(e2, &child)) - { - if (streq(child->get_name(child), name)) - { - found = current; - found->get_ref(found); - break; - } - } - e2->destroy(e2); - if (found) - { - break; - } + /* compare peer_cfgs name first */ + if (streq(current->get_name(current), name)) + { + found = current; + found->get_ref(found); + break; + } + /* compare all child_cfg names otherwise */ + e2 = current->create_child_cfg_enumerator(current); + while (e2->enumerate(e2, &child)) + { + if (streq(child->get_name(child), name)) + { + found = current; + found->get_ref(found); + break; + } + } + e2->destroy(e2); + if (found) + { + break; + } } e1->destroy(e1); this->mutex->unlock(this->mutex); @@ -206,22 +130,6 @@ static peer_cfg_t *get_peer_cfg_by_name(private_stroke_config_t *this, char *nam } /** - * check if a certificate has an ID - */ -static identification_t *update_peerid(certificate_t *cert, identification_t *id) -{ - if (id->get_type(id) == ID_ANY || !cert->has_subject(cert, id)) - { - DBG1(DBG_CFG, " peerid %D not confirmed by certificate, " - "defaulting to subject DN", id); - id->destroy(id); - id = cert->get_subject(cert); - return id->clone(id); - } - return id; -} - -/** * parse a proposal string, either into ike_cfg or child_cfg */ static void add_proposals(private_stroke_config_t *this, char *string, @@ -332,45 +240,303 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL); return ike_cfg; } + /** - * build a peer_cfg from a stroke msg + * Add CRL constraint to config */ -static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, - stroke_msg_t *msg, ike_cfg_t *ike_cfg, - identification_t **my_issuer, - identification_t **other_issuer) +static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy) { - identification_t *me, *other, *peer_id = NULL; - peer_cfg_t *mediated_by = NULL; - host_t *vip = NULL; - certificate_t *cert; - unique_policy_t unique; - u_int32_t rekey = 0, reauth = 0, over, jitter; + /* CRL/OCSP policy, for remote config only */ + if (!local) + { + switch (policy) + { + case CRL_STRICT_YES: + /* if yes, we require a GOOD validation */ + cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD); + break; + case CRL_STRICT_IFURI: + /* for ifuri, a SKIPPED validation is sufficient */ + cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED); + break; + default: + break; + } + } +} + +/** + * build authentication config + */ +static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, + stroke_msg_t *msg, bool local, bool primary) +{ + identification_t *identity; + certificate_t *certificate; + char *auth, *id, *cert, *ca; + stroke_end_t *end, *other_end; + auth_cfg_t *cfg; + char eap_buf[32]; - me = identification_create_from_string(msg->add_conn.me.id ? - msg->add_conn.me.id : msg->add_conn.me.address); - if (!me) + /* select strings */ + if (local) { - DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id); - return NULL; + end = &msg->add_conn.me; + other_end = &msg->add_conn.other; } - other = identification_create_from_string(msg->add_conn.other.id ? - msg->add_conn.other.id : msg->add_conn.other.address); - if (!other) + else { - DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id); - me->destroy(me); - return NULL; + end = &msg->add_conn.other; + other_end = &msg->add_conn.me; + } + if (primary) + { + auth = end->auth; + id = end->id; + if (!id) + { /* leftid/rightid fallback to address */ + id = end->address; + } + cert = end->cert; + ca = end->ca; + if (ca && streq(ca, "%same")) + { + ca = other_end->ca; + } + } + else + { + auth = end->auth2; + id = end->id2; + if (local && !id) + { /* leftid2 falls back to leftid */ + id = end->id; + } + cert = end->cert2; + ca = end->ca2; + if (ca && streq(ca, "%same")) + { + ca = other_end->ca2; + } } + if (!auth) + { + if (primary) + { + if (local) + { /* "leftauth" not defined, fall back to deprecated "authby" */ + switch (msg->add_conn.auth_method) + { + default: + case AUTH_CLASS_PUBKEY: + auth = "pubkey"; + break; + case AUTH_CLASS_PSK: + auth = "psk"; + break; + case AUTH_CLASS_EAP: + auth = "eap"; + break; + } + } + else + { /* "rightauth" not defined, fall back to deprecated "eap" */ + if (msg->add_conn.eap_type) + { + if (msg->add_conn.eap_vendor) + { + snprintf(eap_buf, sizeof(eap_buf), "eap-%d-%d", + msg->add_conn.eap_type, + msg->add_conn.eap_vendor); + } + else + { + snprintf(eap_buf, sizeof(eap_buf), "eap-%d", + msg->add_conn.eap_type); + } + auth = eap_buf; + } + else + { /* not EAP => no constraints for this peer */ + auth = "any"; + } + } + } + else + { /* no second authentication round, fine */ + return NULL; + } + } + + cfg = auth_cfg_create(); + + /* add identity and peer certifcate */ + identity = identification_create_from_string(id); + if (cert) + { + certificate = this->cred->load_peer(this->cred, cert); + if (certificate) + { + if (local) + { + this->ca->check_for_hash_and_url(this->ca, certificate); + } + cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate); + if (identity->get_type(identity) == ID_ANY || + !certificate->has_subject(certificate, identity)) + { + DBG1(DBG_CFG, " peerid %D not confirmed by certificate, " + "defaulting to subject DN: %D", identity, + certificate->get_subject(certificate)); + identity->destroy(identity); + identity = certificate->get_subject(certificate); + identity = identity->clone(identity); + } + } + } + cfg->add(cfg, AUTH_RULE_IDENTITY, identity); + + /* CA constraint */ + if (ca) + { + identity = identification_create_from_string(ca); + certificate = charon->credentials->get_cert(charon->credentials, + CERT_X509, KEY_ANY, identity, TRUE); + identity->destroy(identity); + if (certificate) + { + cfg->add(cfg, AUTH_RULE_CA_CERT, certificate); + } + else + { + DBG1(DBG_CFG, "CA certificate %s not found, discarding CA " + "constraint", ca); + } + } + + /* AC groups */ + if (end->groups) + { + enumerator_t *enumerator; + char *group; + + enumerator = enumerator_create_token(end->groups, ",", " "); + while (enumerator->enumerate(enumerator, &group)) + { + identity = identification_create_from_encoding(ID_IETF_ATTR_STRING, + chunk_create(group, strlen(group))); + cfg->add(cfg, AUTH_RULE_AC_GROUP, identity); + } + enumerator->destroy(enumerator); + } + + /* authentication metod (class, actually) */ + if (streq(auth, "pubkey") || + streq(auth, "rsasig") || streq(auth, "rsa") || + streq(auth, "ecdsasig") || streq(auth, "ecdsa")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + build_crl_policy(cfg, local, msg->add_conn.crl_policy); + } + else if (streq(auth, "psk") || streq(auth, "secret")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); + } + else if (strneq(auth, "eap", 3)) + { + enumerator_t *enumerator; + char *str; + int i = 0, type = 0, vendor; + + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); + + /* parse EAP string, format: eap[-type[-vendor]] */ + enumerator = enumerator_create_token(auth, "-", " "); + while (enumerator->enumerate(enumerator, &str)) + { + switch (i) + { + case 1: + type = eap_type_from_string(str); + if (!type) + { + type = atoi(str); + if (!type) + { + DBG1(DBG_CFG, "unknown EAP method: %s", str); + break; + } + } + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); + break; + case 2: + if (type) + { + vendor = atoi(str); + if (vendor) + { + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); + } + else + { + DBG1(DBG_CFG, "unknown EAP vendor: %s", str); + } + } + break; + default: + break; + } + i++; + } + enumerator->destroy(enumerator); + + if (msg->add_conn.eap_identity) + { + if (streq(msg->add_conn.eap_identity, "%identity")) + { + identity = identification_create_from_encoding(ID_ANY, + chunk_empty); + } + else + { + identity = identification_create_from_string( + msg->add_conn.eap_identity); + } + cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity); + } + } + else + { + if (!streq(auth, "any")) + { + DBG1(DBG_CFG, "authentication method %s unknown, fallback to any", + auth); + } + build_crl_policy(cfg, local, msg->add_conn.crl_policy); + } + return cfg; +} + +/** + * build a peer_cfg from a stroke msg + */ +static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, + stroke_msg_t *msg, ike_cfg_t *ike_cfg) +{ + identification_t *peer_id = NULL; + peer_cfg_t *mediated_by = NULL; + host_t *vip = NULL; + unique_policy_t unique; + u_int32_t rekey = 0, reauth = 0, over, jitter; + peer_cfg_t *peer_cfg; + auth_cfg_t *auth_cfg; #ifdef ME if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by) { DBG1(DBG_CFG, "a mediation connection cannot be a" " mediated connection at the same time, aborting"); - me->destroy(me); - other->destroy(other); return NULL; } @@ -388,8 +554,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, { DBG1(DBG_CFG, "mediation connection '%s' not found, aborting", msg->add_conn.ikeme.mediated_by); - me->destroy(me); - other->destroy(other); return NULL; } @@ -399,56 +563,19 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, "no mediation connection, aborting", msg->add_conn.ikeme.mediated_by, msg->add_conn.name); mediated_by->destroy(mediated_by); - me->destroy(me); - other->destroy(other); return NULL; } - } - - if (msg->add_conn.ikeme.peerid) - { - peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid); - if (!peer_id) + if (msg->add_conn.ikeme.peerid) { - DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.ikeme.peerid); - mediated_by->destroy(mediated_by); - me->destroy(me); - other->destroy(other); - return NULL; + peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid); } - } - else - { - /* no peer ID supplied, assume right ID */ - peer_id = other->clone(other); - } -#endif /* ME */ - - if (msg->add_conn.me.cert) - { - cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert); - if (cert) + else if (msg->add_conn.other.id) { - identification_t *issuer = cert->get_issuer(cert); - - *my_issuer = issuer->clone(issuer); - this->ca->check_for_hash_and_url(this->ca, cert); - me = update_peerid(cert, me); - cert->destroy(cert); - } - } - if (msg->add_conn.other.cert) - { - cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert); - if (cert) - { - identification_t *issuer = cert->get_issuer(cert); - - *other_issuer = issuer->clone(issuer); - other = update_peerid(cert, other); - cert->destroy(cert); + peer_id = identification_create_from_string(msg->add_conn.other.id); } } +#endif /* ME */ + jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; over = msg->add_conn.rekey.margin; if (msg->add_conn.rekey.reauth) @@ -512,179 +639,45 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, /* other.sourceip is managed in stroke_attributes. If it is set, we define * the pool name as the connection name, which the attribute provider * uses to serve pool addresses. */ - return peer_cfg_create(msg->add_conn.name, - msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other, + peer_cfg = peer_cfg_create(msg->add_conn.name, + msg->add_conn.ikev2 ? 2 : 1, ike_cfg, msg->add_conn.me.sendcert, unique, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, msg->add_conn.mobike, msg->add_conn.dpd.delay, vip, msg->add_conn.other.sourceip_size ? msg->add_conn.name : msg->add_conn.other.sourceip, msg->add_conn.ikeme.mediation, mediated_by, peer_id); -} - -/** - * fill in auth_info from stroke message - */ -static void build_auth_info(private_stroke_config_t *this, - stroke_msg_t *msg, auth_info_t *auth, - identification_t *my_ca, - identification_t *other_ca) -{ - identification_t *id; - bool my_ca_same = FALSE; - bool other_ca_same = FALSE; - cert_validation_t valid; - - switch (msg->add_conn.crl_policy) - { - case CRL_STRICT_YES: - valid = VALIDATION_GOOD; - auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid); - break; - case CRL_STRICT_IFURI: - valid = VALIDATION_SKIPPED; - auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid); - break; - default: - break; - } - if (msg->add_conn.me.ca) + /* build leftauth= */ + auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE); + if (auth_cfg) { - if (my_ca) - { - my_ca->destroy(my_ca); - my_ca = NULL; - } - if (streq(msg->add_conn.me.ca, "%same")) - { - my_ca_same = TRUE; - } - else - { - my_ca = identification_create_from_string(msg->add_conn.me.ca); - } + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE); } - - if (msg->add_conn.other.ca) - { - if (other_ca) - { - other_ca->destroy(other_ca); - other_ca = NULL; - } - if (streq(msg->add_conn.other.ca, "%same")) - { - other_ca_same = TRUE; - } - else - { - other_ca = identification_create_from_string(msg->add_conn.other.ca); - } - } - - if (other_ca_same && my_ca) - { - other_ca = my_ca->clone(my_ca); - } - else if (my_ca_same && other_ca) - { - my_ca = other_ca->clone(other_ca); - } - - if (other_ca) - { - DBG2(DBG_CFG, " other ca: %D", other_ca); - certificate_t *cert = charon->credentials->get_cert(charon->credentials, - CERT_X509, KEY_ANY, other_ca, TRUE); - if (cert) - { - auth->add_item(auth, AUTHZ_CA_CERT, cert); - cert->destroy(cert); - } - else - { - auth->add_item(auth, AUTHZ_CA_CERT_NAME, other_ca); - } - other_ca->destroy(other_ca); - } - - if (my_ca) - { - DBG2(DBG_CFG, " my ca: %D", my_ca); - certificate_t *cert = charon->credentials->get_cert(charon->credentials, - CERT_X509, KEY_ANY, my_ca, TRUE); - if (cert) - { - auth->add_item(auth, AUTHN_CA_CERT, cert); - cert->destroy(cert); - } - else - { - auth->add_item(auth, AUTHN_CA_CERT_NAME, my_ca); - } - my_ca->destroy(my_ca); + else + { /* we require at least one config on our side */ + peer_cfg->destroy(peer_cfg); + return NULL; } - auth->add_item(auth, AUTHN_AUTH_CLASS, &msg->add_conn.auth_method); - if (msg->add_conn.eap_type) + /* build leftauth2= */ + auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE); + if (auth_cfg) { - auth->add_item(auth, AUTHN_EAP_TYPE, &msg->add_conn.eap_type); - if (msg->add_conn.eap_vendor) - { - auth->add_item(auth, AUTHN_EAP_VENDOR, &msg->add_conn.eap_vendor); - } + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE); } - - if (msg->add_conn.eap_identity) + /* build rightauth= */ + auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE); + if (auth_cfg) { - if (streq(msg->add_conn.eap_identity, "%identity")) - { - id = identification_create_from_encoding(ID_ANY, chunk_empty); - } - else - { - id = identification_create_from_encoding(ID_EAP, chunk_create( - msg->add_conn.eap_identity, - strlen(msg->add_conn.eap_identity))); - } - auth->add_item(auth, AUTHN_EAP_IDENTITY, id); - id->destroy(id); + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE); } - - if (msg->add_conn.other.groups) + /* build rightauth2= */ + auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE); + if (auth_cfg) { - chunk_t line = { msg->add_conn.other.groups, - strlen(msg->add_conn.other.groups) }; - - while (eat_whitespace(&line)) - { - chunk_t group; - - /* extract the next comma-separated group attribute */ - if (!extract_token(&group, ',', &line)) - { - group = line; - line.len = 0; - } - - /* remove any trailing spaces */ - while (group.len > 0 && *(group.ptr + group.len - 1) == ' ') - { - group.len--; - } - - /* add the group attribute to the list */ - if (group.len > 0) - { - identification_t *ac_group; - - ac_group = identification_create_from_encoding( - ID_IETF_ATTR_STRING, group); - auth->add_item(auth, AUTHZ_AC_GROUP, ac_group); - ac_group->destroy(ac_group); - } - } + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE); } + return peer_cfg; } /** @@ -799,7 +792,6 @@ static void add(private_stroke_config_t *this, stroke_msg_t *msg) ike_cfg_t *ike_cfg, *existing_ike; peer_cfg_t *peer_cfg, *existing; child_cfg_t *child_cfg; - identification_t *my_issuer = NULL, *other_issuer = NULL; enumerator_t *enumerator; bool use_existing = FALSE; @@ -808,15 +800,13 @@ static void add(private_stroke_config_t *this, stroke_msg_t *msg) { return; } - peer_cfg = build_peer_cfg(this, msg, ike_cfg, &my_issuer, &other_issuer); + peer_cfg = build_peer_cfg(this, msg, ike_cfg); if (!peer_cfg) { ike_cfg->destroy(ike_cfg); return; } - build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg), - my_issuer, other_issuer); enumerator = create_peer_cfg_enumerator(this, NULL, NULL); while (enumerator->enumerate(enumerator, &existing)) { @@ -850,9 +840,7 @@ static void add(private_stroke_config_t *this, stroke_msg_t *msg) else { /* add config to backend */ - DBG1(DBG_CFG, "added configuration '%s': %s[%D]...%s[%D]", msg->add_conn.name, - ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg), - ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg)); + DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name); this->mutex->lock(this->mutex); this->list->insert_last(this->list, peer_cfg); this->mutex->unlock(this->mutex); diff --git a/src/charon/plugins/stroke/stroke_cred.c b/src/charon/plugins/stroke/stroke_cred.c index 434aec22b..7fb33da9e 100644 --- a/src/charon/plugins/stroke/stroke_cred.c +++ b/src/charon/plugins/stroke/stroke_cred.c @@ -905,26 +905,13 @@ static void load_secrets(private_stroke_cred_t *this) continue; } - if (type == SHARED_EAP) + /* NULL terminate the ID string */ + *(id.ptr + id.len) = '\0'; + peer_id = identification_create_from_string(id.ptr); + if (peer_id->get_type(peer_id) == ID_ANY) { - /* we use a special EAP identity type for EAP secrets */ - peer_id = identification_create_from_encoding(ID_EAP, id); - } - else - { - /* NULL terminate the ID string */ - *(id.ptr + id.len) = '\0'; - peer_id = identification_create_from_string(id.ptr); - if (peer_id == NULL) - { - DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr); - goto error; - } - if (peer_id->get_type(peer_id) == ID_ANY) - { - peer_id->destroy(peer_id); - continue; - } + peer_id->destroy(peer_id); + continue; } shared_key->add_owner(shared_key, peer_id); diff --git a/src/charon/plugins/stroke/stroke_list.c b/src/charon/plugins/stroke/stroke_list.c index 94b3def3a..9c98770dd 100644 --- a/src/charon/plugins/stroke/stroke_list.c +++ b/src/charon/plugins/stroke/stroke_list.c @@ -55,23 +55,6 @@ struct private_stroke_list_t { }; /** - * get the authentication class of a config - */ -auth_class_t get_auth_class(peer_cfg_t *config) -{ - auth_class_t *class; - auth_info_t *auth_info; - - auth_info = config->get_auth(config); - if (auth_info->get_item(auth_info, AUTHN_AUTH_CLASS, (void**)&class)) - { - return *class; - } - /* fallback to pubkey authentication */ - return AUTH_CLASS_PUBKEY; -} - -/** * log an IKE_SA to out */ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) @@ -110,9 +93,11 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED) { time_t rekey, reauth; + peer_cfg_t *peer_cfg; rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY); reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH); + peer_cfg = ike_sa->get_peer_cfg(ike_sa); if (rekey) { @@ -120,9 +105,24 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) } if (reauth) { - fprintf(out, ", %N reauthentication in %V", auth_class_names, - get_auth_class(ike_sa->get_peer_cfg(ike_sa)), - &reauth, &now); + bool first = TRUE; + enumerator_t *enumerator; + auth_cfg_t *auth; + + fprintf(out, ", "); + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, TRUE); + while (enumerator->enumerate(enumerator, &auth)) + { + if (!first) + { + fprintf(out, "+"); + } + first = FALSE; + fprintf(out, "%N", auth_class_names, + auth->get(auth, AUTH_RULE_AUTH_CLASS)); + } + enumerator->destroy(enumerator); + fprintf(out, " reauthentication in %V", &reauth, &now); } if (!rekey && !reauth) { @@ -248,6 +248,107 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) } /** + * Log a configs local or remote authentication config to out + */ +static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local) +{ + enumerator_t *enumerator, *rules; + auth_rule_t rule; + auth_cfg_t *auth; + auth_class_t auth_class; + identification_t *id; + certificate_t *cert; + cert_validation_t valid; + char *name; + + name = peer_cfg->get_name(peer_cfg); + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); + while (enumerator->enumerate(enumerator, &auth)) + { + fprintf(out, "%12s: %s [%D] uses ", name, local ? "local: " : "remote:", + auth->get(auth, AUTH_RULE_IDENTITY)); + + auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + if (auth_class != AUTH_CLASS_EAP) + { + fprintf(out, "%N authentication\n", auth_class_names, auth_class); + } + else + { + if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE) == EAP_NAK) + { + fprintf(out, "EAP authentication"); + } + else + { + if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR)) + { + fprintf(out, "EAP_%d-%d authentication", + (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE), + (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR)); + } + else + { + fprintf(out, "%N authentication", eap_type_names, + (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE)); + } + } + id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); + if (id) + { + fprintf(out, " with EAP identity '%D'", id); + } + fprintf(out, "\n"); + } + + cert = auth->get(auth, AUTH_RULE_CA_CERT); + if (cert) + { + fprintf(out, "%12s: ca: \"%D\"\n", name, cert->get_subject(cert)); + } + + cert = auth->get(auth, AUTH_RULE_IM_CERT); + if (cert) + { + fprintf(out, "%12s: im-ca: \"%D\"\n", name, cert->get_subject(cert)); + } + + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (cert) + { + fprintf(out, "%12s: cert: \"%D\"\n", name, + cert->get_subject(cert)); + } + + valid = (uintptr_t)auth->get(auth, AUTH_RULE_OCSP_VALIDATION); + if (valid != VALIDATION_FAILED) + { + fprintf(out, "%12s: ocsp: status must be GOOD%s\n", name, + (valid == VALIDATION_SKIPPED) ? " or SKIPPED" : ""); + } + + valid = (uintptr_t)auth->get(auth, AUTH_RULE_CRL_VALIDATION); + if (valid != VALIDATION_FAILED) + { + fprintf(out, "%12s: crl: status must be GOOD%s\n", name, + (valid == VALIDATION_SKIPPED) ? " or SKIPPED" : ""); + } + + rules = auth->create_enumerator(auth); + while (rules->enumerate(rules, &rule, &id)) + { + if (rule == AUTH_RULE_AC_GROUP) + { + fprintf(out, "%12s: group: %D\n", name, id); + } + } + rules->destroy(rules); + } + enumerator->destroy(enumerator); +} + +/** * Implementation of stroke_list_t.status. */ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bool all) @@ -313,138 +414,42 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo enumerator->destroy(enumerator); fprintf(out, "Connections:\n"); - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends); - while (enumerator->enumerate(enumerator, (void**)&peer_cfg)) + enumerator = charon->backends->create_peer_cfg_enumerator( + charon->backends, NULL, NULL, NULL, NULL); + while (enumerator->enumerate(enumerator, &peer_cfg)) { - void *ptr; - certificate_t *cert; - auth_item_t item; - auth_info_t *auth; - enumerator_t *auth_enumerator; - identification_t *my_ca = NULL, *other_ca = NULL; - identification_t *eap_identity = NULL; - u_int32_t *eap_type = NULL; - bool ac_groups = FALSE; - if (peer_cfg->get_ike_version(peer_cfg) != 2 || (name && !streq(name, peer_cfg->get_name(peer_cfg)))) { continue; } - /* determine any required CAs, EAP type, EAP identity, - * and the presence of AC groups - */ - auth = peer_cfg->get_auth(peer_cfg); - auth_enumerator = auth->create_item_enumerator(auth); - while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr)) - { - switch (item) - { - case AUTHN_EAP_TYPE: - eap_type = (u_int32_t *)ptr; - break; - case AUTHN_EAP_IDENTITY: - eap_identity = (identification_t *)ptr; - break; - case AUTHN_CA_CERT: - cert = (certificate_t *)ptr; - my_ca = cert->get_subject(cert); - break; - case AUTHN_CA_CERT_NAME: - my_ca = (identification_t *)ptr; - break; - case AUTHZ_CA_CERT: - cert = (certificate_t *)ptr; - other_ca = cert->get_subject(cert); - break; - case AUTHZ_CA_CERT_NAME: - other_ca = (identification_t *)ptr; - break; - case AUTHZ_AC_GROUP: - ac_groups = TRUE; - break; - default: - break; - } - } - auth_enumerator->destroy(auth_enumerator); - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - fprintf(out, "%12s: %s[%D]...%s[%D]\n", peer_cfg->get_name(peer_cfg), - ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg), - ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg)); - if (my_ca || other_ca) - { - fprintf(out, "%12s: CAs: ", peer_cfg->get_name(peer_cfg)); - if (my_ca) - { - fprintf(out, "\"%D\"...", my_ca); - } - else - { - fprintf(out, "%%any..."); - } - if (other_ca) - { - fprintf(out, "\"%D\"\n", other_ca); - } - else - { - fprintf(out, "%%any\n"); - } - } - - if (ac_groups) - { - bool first = TRUE; - - fprintf(out, "%12s: groups: ", peer_cfg->get_name(peer_cfg)); - auth_enumerator = auth->create_item_enumerator(auth); - while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr)) - { - if (item == AUTHZ_AC_GROUP) - { - identification_t *group = (identification_t *)ptr; - - fprintf(out, "%s%D", first? "":", ", group); - first = FALSE; - } - } - auth_enumerator->destroy(auth_enumerator); - fprintf(out, "\n"); - } - - fprintf(out, "%12s: %N ", peer_cfg->get_name(peer_cfg), - auth_class_names, get_auth_class(peer_cfg)); - if (eap_type) - { - fprintf(out, "and %N ", eap_type_names, *eap_type); - } - fprintf(out, "authentication"); - if (eap_identity) - { - fprintf(out, ", EAP identity: '%D'", eap_identity); - } + fprintf(out, "%12s: %s...%s", peer_cfg->get_name(peer_cfg), + ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg)); + dpd = peer_cfg->get_dpd(peer_cfg); if (dpd) { fprintf(out, ", dpddelay=%us", dpd); } fprintf(out, "\n"); - + + log_auth_cfgs(out, peer_cfg, TRUE); + log_auth_cfgs(out, peer_cfg, FALSE); + children = peer_cfg->create_child_cfg_enumerator(peer_cfg); while (children->enumerate(children, &child_cfg)) { linked_list_t *my_ts, *other_ts; - + my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); - fprintf(out, "%12s: %#R=== %#R", child_cfg->get_name(child_cfg), + fprintf(out, "%12s: child: %#R=== %#R", child_cfg->get_name(child_cfg), my_ts, other_ts); my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); - + if (dpd) { fprintf(out, ", dpdaction=%N", action_names, diff --git a/src/charon/plugins/stroke/stroke_socket.c b/src/charon/plugins/stroke/stroke_socket.c index 53edde031..85f1e8f4e 100644 --- a/src/charon/plugins/stroke/stroke_socket.c +++ b/src/charon/plugins/stroke/stroke_socket.c @@ -143,18 +143,28 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) pop_string(msg, &end->address); pop_string(msg, &end->subnets); pop_string(msg, &end->sourceip); + pop_string(msg, &end->auth); + pop_string(msg, &end->auth2); pop_string(msg, &end->id); + pop_string(msg, &end->id2); pop_string(msg, &end->cert); + pop_string(msg, &end->cert2); pop_string(msg, &end->ca); + pop_string(msg, &end->ca2); pop_string(msg, &end->groups); pop_string(msg, &end->updown); DBG2(DBG_CFG, " %s=%s", label, end->address); DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets); DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip); + DBG2(DBG_CFG, " %sauth=%s", label, end->auth); + DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2); DBG2(DBG_CFG, " %sid=%s", label, end->id); + DBG2(DBG_CFG, " %sid2=%s", label, end->id2); DBG2(DBG_CFG, " %scert=%s", label, end->cert); + DBG2(DBG_CFG, " %scert2=%s", label, end->cert2); DBG2(DBG_CFG, " %sca=%s", label, end->ca); + DBG2(DBG_CFG, " %sca2=%s", label, end->ca2); DBG2(DBG_CFG, " %sgroups=%s", label, end->groups); DBG2(DBG_CFG, " %supdown=%s", label, end->updown); } diff --git a/src/charon/plugins/uci/uci_config.c b/src/charon/plugins/uci/uci_config.c index c9d54a532..d185476fd 100644 --- a/src/charon/plugins/uci/uci_config.c +++ b/src/charon/plugins/uci/uci_config.c @@ -83,24 +83,6 @@ static proposal_t *create_proposal(char *string, protocol_id_t proto) } /** - * create an identity, with fallback to %any - */ -static identification_t *create_id(char *string) -{ - identification_t *id = NULL; - - if (string) - { - id = identification_create_from_string(string); - } - if (!id) - { - id = identification_create_from_encoding(ID_ANY, chunk_empty); - } - return id; -} - -/** * create an traffic selector, fallback to dynamic */ static traffic_selector_t *create_ts(char *string) @@ -163,8 +145,7 @@ static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) char *remote_id, *remote_addr, *remote_net; child_cfg_t *child_cfg; ike_cfg_t *ike_cfg; - auth_info_t *auth; - auth_class_t class; + auth_cfg_t *auth; /* defaults */ name = "unnamed"; @@ -187,16 +168,26 @@ static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) ike_cfg = ike_cfg_create(FALSE, FALSE, local_addr, remote_addr); ike_cfg->add_proposal(ike_cfg, create_proposal(ike_proposal, PROTO_IKE)); this->peer_cfg = peer_cfg_create( - name, 2, ike_cfg, create_id(local_id), create_id(remote_id), - CERT_SEND_IF_ASKED, UNIQUE_NO, + name, 2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, 1, create_rekey(ike_rekey), 0, /* keytries, rekey, reauth */ 1800, 900, /* jitter, overtime */ TRUE, 60, /* mobike, dpddelay */ NULL, NULL, /* vip, pool */ FALSE, NULL, NULL); /* mediation, med by, peer id */ - auth = this->peer_cfg->get_auth(this->peer_cfg); - class = AUTH_CLASS_PSK; - auth->add_item(auth, AUTHN_AUTH_CLASS, &class); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_string(local_id)); + this->peer_cfg->add_auth_cfg(this->peer_cfg, auth, TRUE); + + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); + if (remote_id) + { + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_string(remote_id)); + } + this->peer_cfg->add_auth_cfg(this->peer_cfg, auth, FALSE); child_cfg = child_cfg_create(name, create_rekey(esp_rekey) + 300, create_rekey(ike_rekey), 300, NULL, TRUE, MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE); diff --git a/src/charon/plugins/uci/uci_control.c b/src/charon/plugins/uci/uci_control.c index 2ffdd2b7b..7a428afb0 100644 --- a/src/charon/plugins/uci/uci_control.c +++ b/src/charon/plugins/uci/uci_control.c @@ -39,15 +39,15 @@ typedef struct private_uci_control_t private_uci_control_t; * private data of uci_control_t */ struct private_uci_control_t { - + /** - * Public part - */ + * Public part + */ uci_control_t public; - + /** - * Job - */ + * Job + */ callback_job_t *job; }; @@ -86,13 +86,14 @@ static void status(private_uci_control_t *this, char *name) char buf[2048]; FILE *out = NULL; - configs = charon->backends->create_peer_cfg_enumerator(charon->backends); - while (configs->enumerate(configs, &peer_cfg)) - { - if (name && !streq(name, peer_cfg->get_name(peer_cfg))) - { - continue; - } + configs = charon->backends->create_peer_cfg_enumerator(charon->backends, + NULL, NULL, NULL, NULL); + while (configs->enumerate(configs, &peer_cfg)) + { + if (name && !streq(name, peer_cfg->get_name(peer_cfg))) + { + continue; + } sas = charon->controller->create_ike_sa_enumerator(charon->controller); while (sas->enumerate(sas, &ike_sa)) { @@ -108,9 +109,9 @@ static void status(private_uci_control_t *this, char *name) continue; } } - fprintf(out, "%-8s %-20D %-16H ", ike_sa->get_name(ike_sa), - ike_sa->get_other_id(ike_sa), ike_sa->get_other_host(ike_sa)); - + fprintf(out, "%-8s %-20D %-16H ", ike_sa->get_name(ike_sa), + ike_sa->get_other_id(ike_sa), ike_sa->get_other_host(ike_sa)); + children = ike_sa->create_child_sa_iterator(ike_sa); while (children->iterate(children, (void**)&child_sa)) { @@ -118,7 +119,7 @@ static void status(private_uci_control_t *this, char *name) child_sa->get_traffic_selectors(child_sa, FALSE)); } children->destroy(children); - fprintf(out, "\n"); + fprintf(out, "\n"); } sas->destroy(sas); } @@ -142,7 +143,7 @@ static void initiate(private_uci_control_t *this, char *name) peer_cfg_t *peer_cfg; child_cfg_t *child_cfg; enumerator_t *enumerator; - + peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name); if (peer_cfg) { @@ -174,7 +175,7 @@ static void terminate(private_uci_control_t *this, char *name) enumerator_t *enumerator; ike_sa_t *ike_sa; u_int id; - + enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); while (enumerator->enumerate(enumerator, &ike_sa)) { @@ -240,7 +241,7 @@ static job_requeue_t receive(private_uci_control_t *this) char message[128]; int oldstate, len; FILE *in; - + memset(message, 0, sizeof(message)); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); in = fopen(FIFO_FILE, "r"); @@ -281,9 +282,9 @@ static void destroy(private_uci_control_t *this) uci_control_t *uci_control_create() { private_uci_control_t *this = malloc_thing(private_uci_control_t); - + this->public.destroy = (void(*)(uci_control_t*))destroy; - + unlink(FIFO_FILE); if (mkfifo(FIFO_FILE, S_IRUSR|S_IWUSR) != 0) { diff --git a/src/charon/plugins/uci/uci_creds.c b/src/charon/plugins/uci/uci_creds.c index 60f6fc934..2813850e8 100644 --- a/src/charon/plugins/uci/uci_creds.c +++ b/src/charon/plugins/uci/uci_creds.c @@ -81,10 +81,6 @@ static bool shared_enumerator_enumerate(shared_enumerator_t *this, if (me) { local = identification_create_from_string(local_id); - if (!local) - { - continue; - } *me = this->me ? this->me->matches(this->me, local) : ID_MATCH_ANY; local->destroy(local); @@ -96,10 +92,6 @@ static bool shared_enumerator_enumerate(shared_enumerator_t *this, if (other) { remote = identification_create_from_string(remote_id); - if (!remote) - { - continue; - } *other = this->other ? this->other->matches(this->other, remote) : ID_MATCH_ANY; remote->destroy(remote); diff --git a/src/charon/plugins/unit_tester/tests/test_auth_info.c b/src/charon/plugins/unit_tester/tests/test_auth_info.c index 1719190b1..37bdd1087 100644 --- a/src/charon/plugins/unit_tester/tests/test_auth_info.c +++ b/src/charon/plugins/unit_tester/tests/test_auth_info.c @@ -15,7 +15,7 @@ #include <daemon.h> #include <library.h> -#include <credentials/auth_info.h> +#include <config/auth_cfg.h> char buf[] = {0x01,0x02,0x03,0x04}; @@ -75,14 +75,14 @@ chunk_t certchunk = chunk_from_buf(certbuf); /******************************************************************************* * auth info test ******************************************************************************/ -bool test_auth_info() +bool test_auth_cfg() { - auth_info_t *auth = auth_info_create(), *auth2; + auth_cfg_t *auth = auth_cfg_create(), *auth2; certificate_t *c1, *c2; enumerator_t *enumerator; int round = 0; void *value; - auth_item_t type; + auth_rule_t type; c1 = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB_ASN1_DER, certchunk, @@ -92,8 +92,9 @@ bool test_auth_info() return FALSE; } - auth->add_item(auth, AUTHN_SUBJECT_CERT, c1); - if (!auth->get_item(auth, AUTHN_SUBJECT_CERT, (void**)&c2)) + auth->add(auth, AUTH_RULE_SUBJECT_CERT, c1->get_ref(c1)); + c2 = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (!c2) { return FALSE; } @@ -102,11 +103,11 @@ bool test_auth_info() return FALSE; } - enumerator = auth->create_item_enumerator(auth); + enumerator = auth->create_enumerator(auth); while (enumerator->enumerate(enumerator, &type, &value)) { round++; - if (round == 1 && type == AUTHN_SUBJECT_CERT && value == c1) + if (round == 1 && type == AUTH_RULE_SUBJECT_CERT && value == c1) { continue; } @@ -114,20 +115,20 @@ bool test_auth_info() } enumerator->destroy(enumerator); - auth2 = auth_info_create(); - auth2->add_item(auth2, AUTHN_CA_CERT, c1); - auth2->merge(auth2, auth); + auth2 = auth_cfg_create(); + auth2->add(auth2, AUTH_RULE_CA_CERT, c1->get_ref(c1)); + auth2->merge(auth2, auth, FALSE); round = 0; - enumerator = auth2->create_item_enumerator(auth2); + enumerator = auth2->create_enumerator(auth2); while (enumerator->enumerate(enumerator, &type, &value)) { round++; - if (round == 1 && type == AUTHN_CA_CERT && value == c1) + if (round == 1 && type == AUTH_RULE_CA_CERT && value == c1) { continue; } - if (round == 2 && type == AUTHN_SUBJECT_CERT && value == c1) + if (round == 2 && type == AUTH_RULE_SUBJECT_CERT && value == c1) { continue; } diff --git a/src/charon/plugins/unit_tester/tests/test_med_db.c b/src/charon/plugins/unit_tester/tests/test_med_db.c index d65eb0cc4..7b4603bd7 100644 --- a/src/charon/plugins/unit_tester/tests/test_med_db.c +++ b/src/charon/plugins/unit_tester/tests/test_med_db.c @@ -33,8 +33,8 @@ bool test_med_db() chunk_t keyid = chunk_from_buf(keyid_buf); identification_t *id, *found; enumerator_t *enumerator; - auth_info_t *auth; public_key_t *public; + auth_cfg_t *auth; bool good = FALSE; id = identification_create_from_encoding(ID_KEY_ID, keyid); diff --git a/src/charon/plugins/unit_tester/tests/test_pool.c b/src/charon/plugins/unit_tester/tests/test_pool.c index b11f71704..3c792ef04 100644 --- a/src/charon/plugins/unit_tester/tests/test_pool.c +++ b/src/charon/plugins/unit_tester/tests/test_pool.c @@ -25,14 +25,10 @@ static void* testing(void *thread) { - int i; - auth_info_t *auth; + int i; host_t *addr[ALLOCS]; identification_t *id[ALLOCS]; - - auth = auth_info_create(); - /* prepare identities */ for (i = 0; i < ALLOCS; i++) { @@ -40,17 +36,13 @@ static void* testing(void *thread) snprintf(buf, sizeof(buf), "%d-%d@strongswan.org", (int)thread, i); id[i] = identification_create_from_string(buf); - if (!id[i]) - { - return (void*)FALSE; - } } /* allocate addresses */ for (i = 0; i < ALLOCS; i++) { addr[i] = charon->attributes->acquire_address(charon->attributes, - "test", id[i], auth, NULL); + "test", id[i], NULL); if (!addr[i]) { return (void*)FALSE; @@ -69,7 +61,6 @@ static void* testing(void *thread) addr[i]->destroy(addr[i]); id[i]->destroy(id[i]); } - auth->destroy(auth); return (void*)TRUE; } diff --git a/src/charon/processing/jobs/initiate_mediation_job.c b/src/charon/processing/jobs/initiate_mediation_job.c index db9e76e63..69eac3b21 100644 --- a/src/charon/processing/jobs/initiate_mediation_job.c +++ b/src/charon/processing/jobs/initiate_mediation_job.c @@ -75,6 +75,8 @@ static void initiate(private_initiate_mediation_job_t *this) { ike_sa_t *mediated_sa, *mediation_sa; peer_cfg_t *mediated_cfg, *mediation_cfg; + enumerator_t *enumerator; + auth_cfg_t *auth_cfg; mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->mediated_sa_id); @@ -88,8 +90,20 @@ static void initiate(private_initiate_mediation_job_t *this) mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg); mediation_cfg->get_ref(mediation_cfg); + enumerator = mediation_cfg->create_auth_cfg_enumerator(mediation_cfg, + TRUE); + if (!enumerator->enumerate(enumerator, &auth_cfg) || + auth_cfg->get(auth_cfg, AUTH_RULE_IDENTITY) == NULL) + { + mediated_cfg->destroy(mediated_cfg); + mediation_cfg->destroy(mediation_cfg); + enumerator->destroy(enumerator); + destroy(this); + return; + } + if (charon->connect_manager->check_and_register(charon->connect_manager, - mediation_cfg->get_my_id(mediation_cfg), + auth_cfg->get(auth_cfg, AUTH_RULE_IDENTITY), mediated_cfg->get_peer_id(mediated_cfg), this->mediated_sa_id)) { diff --git a/src/charon/sa/authenticators/authenticator.c b/src/charon/sa/authenticators/authenticator.c index cdd3245fe..0c33528a0 100644 --- a/src/charon/sa/authenticators/authenticator.c +++ b/src/charon/sa/authenticators/authenticator.c @@ -1,6 +1,6 @@ /* + * Copyright (C) 2006-2009 Martin Willi * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ #include <sa/authenticators/pubkey_authenticator.h> #include <sa/authenticators/psk_authenticator.h> #include <sa/authenticators/eap_authenticator.h> +#include <encoding/payloads/auth_payload.h> ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS, @@ -35,7 +36,8 @@ ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_ECDSA_521, AUTH_DSS, "ECDSA-521 signature"); ENUM_END(auth_method_names, AUTH_ECDSA_521); -ENUM(auth_class_names, AUTH_CLASS_PUBKEY, AUTH_CLASS_EAP, +ENUM(auth_class_names, AUTH_CLASS_ANY, AUTH_CLASS_EAP, + "any", "public key", "pre-shared key", "EAP", @@ -44,17 +46,23 @@ ENUM(auth_class_names, AUTH_CLASS_PUBKEY, AUTH_CLASS_EAP, /** * Described in header. */ -authenticator_t *authenticator_create_from_class(ike_sa_t *ike_sa, - auth_class_t class) +authenticator_t *authenticator_create_builder( + ike_sa_t *ike_sa, auth_cfg_t *cfg, + chunk_t received_nonce, chunk_t sent_init) { - switch (class) + switch ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS)) { + case AUTH_CLASS_ANY: + /* defaults to PUBKEY */ case AUTH_CLASS_PUBKEY: - return (authenticator_t*)pubkey_authenticator_create(ike_sa); + return (authenticator_t*)pubkey_authenticator_create_builder(ike_sa, + received_nonce, sent_init); case AUTH_CLASS_PSK: - return (authenticator_t*)psk_authenticator_create(ike_sa); + return (authenticator_t*)psk_authenticator_create_builder(ike_sa, + received_nonce, sent_init); case AUTH_CLASS_EAP: - return (authenticator_t*)eap_authenticator_create(ike_sa); + return (authenticator_t*)eap_authenticator_create_builder(ike_sa, + received_nonce, sent_init); default: return NULL; } @@ -63,19 +71,31 @@ authenticator_t *authenticator_create_from_class(ike_sa_t *ike_sa, /** * Described in header. */ -authenticator_t *authenticator_create_from_method(ike_sa_t *ike_sa, - auth_method_t method) +authenticator_t *authenticator_create_verifier( + ike_sa_t *ike_sa, message_t *message, + chunk_t sent_nonce, chunk_t received_init) { - switch (method) + auth_payload_t *auth_payload; + + auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + if (auth_payload == NULL) + { + return (authenticator_t*)eap_authenticator_create_verifier(ike_sa, + sent_nonce, received_init); + } + switch (auth_payload->get_auth_method(auth_payload)) { case AUTH_RSA: case AUTH_ECDSA_256: case AUTH_ECDSA_384: case AUTH_ECDSA_521: - return (authenticator_t*)pubkey_authenticator_create(ike_sa); + return (authenticator_t*)pubkey_authenticator_create_verifier(ike_sa, + sent_nonce, received_init); case AUTH_PSK: - return (authenticator_t*)psk_authenticator_create(ike_sa); + return (authenticator_t*)psk_authenticator_create_verifier(ike_sa, + sent_nonce, received_init); default: return NULL; } } + diff --git a/src/charon/sa/authenticators/authenticator.h b/src/charon/sa/authenticators/authenticator.h index cd42191e6..db3f110ca 100644 --- a/src/charon/sa/authenticators/authenticator.h +++ b/src/charon/sa/authenticators/authenticator.h @@ -1,6 +1,6 @@ /* + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -30,9 +30,8 @@ typedef enum auth_class_t auth_class_t; typedef struct authenticator_t authenticator_t; #include <library.h> +#include <config/auth_cfg.h> #include <sa/ike_sa.h> -#include <config/peer_cfg.h> -#include <encoding/payloads/auth_payload.h> /** * Method to use for authentication, as defined in IKEv2. @@ -84,6 +83,8 @@ extern enum_name_t *auth_method_names; * certificate finally dictates wich method is used. */ enum auth_class_t { + /** any class acceptable */ + AUTH_CLASS_ANY = 0, /** authentication using public keys (RSA, ECDSA) */ AUTH_CLASS_PUBKEY = 1, /** authentication using a pre-shared secrets */ @@ -100,66 +101,64 @@ extern enum_name_t *auth_class_names; /** * Authenticator interface implemented by the various authenticators. * - * Currently the following two AUTH methods are supported: - * - shared key message integrity code - * - RSA digital signature - * - EAP using the EAP framework and one of the EAP plugins - * - ECDSA is supported using OpenSSL + * An authenticator implementation handles AUTH and EAP payloads. Received + * messages are passed to the process() method, to send authentication data + * the message is passed to the build() method. */ struct authenticator_t { /** - * Verify a received authentication payload. + * Process an incoming message using the authenticator. * - * @param ike_sa_init binary representation of received ike_sa_init - * @param my_nonce the sent nonce - * @param auth_payload authentication payload to verify + * @param message message containing authentication payloads * @return - * - SUCCESS, - * - FAILED if verification failed - * - INVALID_ARG if auth_method does not match - * - NOT_FOUND if credentials not found + * - SUCCESS if authentication successful + * - FAILED if authentication failed + * - NEED_MORE if another exchange required */ - status_t (*verify) (authenticator_t *this, chunk_t ike_sa_init, - chunk_t my_nonce, auth_payload_t *auth_payload); - + status_t (*process)(authenticator_t *this, message_t *message); + /** - * Build an authentication payload to send to the other peer. + * Attach authentication data to an outgoing message. * - * @param ike_sa_init binary representation of sent ike_sa_init - * @param other_nonce the received nonce - * @param auth_payload the resulting authentication payload + * @param message message to add authentication data to * @return - * - SUCCESS, - * - NOT_FOUND if credentials not found + * - SUCCESS if authentication successful + * - FAILED if authentication failed + * - NEED_MORE if another exchange required */ - status_t (*build) (authenticator_t *this, chunk_t ike_sa_init, - chunk_t other_nonce, auth_payload_t **auth_payload); - + status_t (*build)(authenticator_t *this, message_t *message); + /** - * Destroys a authenticator_t object. + * Destroy authenticator instance. */ void (*destroy) (authenticator_t *this); }; /** - * Creates an authenticator for the specified auth class (as configured). + * Create an authenticator to build signatures. * - * @param ike_sa associated ike_sa - * @param class class of authentication to use - * @return authenticator_t object + * @param ike_sa associated ike_sa + * @param cfg authentication configuration + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_init sent IKE_SA_INIT message data + * @return authenticator, NULL if not supported */ -authenticator_t *authenticator_create_from_class(ike_sa_t *ike_sa, - auth_class_t class); +authenticator_t *authenticator_create_builder( + ike_sa_t *ike_sa, auth_cfg_t *cfg, + chunk_t received_nonce, chunk_t sent_init); /** - * Creates an authenticator for method (as received in payload). + * Create an authenticator to verify signatures. * - * @param ike_sa associated ike_sa - * @param method method as found in payload - * @return authenticator_t object + * @param ike_sa associated ike_sa + * @param message message containing authentication data + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @return authenticator, NULL if not supported */ -authenticator_t *authenticator_create_from_method(ike_sa_t *ike_sa, - auth_method_t method); +authenticator_t *authenticator_create_verifier( + ike_sa_t *ike_sa, message_t *message, + chunk_t sent_nonce, chunk_t received_init); #endif /** AUTHENTICATOR_H_ @}*/ diff --git a/src/charon/sa/authenticators/eap/eap_manager.c b/src/charon/sa/authenticators/eap/eap_manager.c index 578d302ea..ecb46c293 100644 --- a/src/charon/sa/authenticators/eap/eap_manager.c +++ b/src/charon/sa/authenticators/eap/eap_manager.c @@ -65,9 +65,9 @@ struct private_eap_manager_t { linked_list_t *methods; /** - * mutex to lock methods + * rwlock to lock methods */ - mutex_t *mutex; + rwlock_t *lock; }; /** @@ -84,9 +84,9 @@ static void add_method(private_eap_manager_t *this, eap_type_t type, entry->role = role; entry->constructor = constructor; - this->mutex->lock(this->mutex); + this->lock->write_lock(this->lock); this->methods->insert_last(this->methods, entry); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); } /** @@ -97,7 +97,7 @@ static void remove_method(private_eap_manager_t *this, eap_constructor_t constru enumerator_t *enumerator; eap_entry_t *entry; - this->mutex->lock(this->mutex); + this->lock->write_lock(this->lock); enumerator = this->methods->create_enumerator(this->methods); while (enumerator->enumerate(enumerator, &entry)) { @@ -108,7 +108,7 @@ static void remove_method(private_eap_manager_t *this, eap_constructor_t constru } } enumerator->destroy(enumerator); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); } /** @@ -123,7 +123,7 @@ static eap_method_t* create_instance(private_eap_manager_t *this, eap_entry_t *entry; eap_method_t *method = NULL; - this->mutex->lock(this->mutex); + this->lock->read_lock(this->lock); enumerator = this->methods->create_enumerator(this->methods); while (enumerator->enumerate(enumerator, &entry)) { @@ -138,7 +138,7 @@ static eap_method_t* create_instance(private_eap_manager_t *this, } } enumerator->destroy(enumerator); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); return method; } @@ -148,7 +148,7 @@ static eap_method_t* create_instance(private_eap_manager_t *this, static void destroy(private_eap_manager_t *this) { this->methods->destroy_function(this->methods, free); - this->mutex->destroy(this->mutex); + this->lock->destroy(this->lock); free(this); } @@ -165,7 +165,7 @@ eap_manager_t *eap_manager_create() this->public.destroy = (void(*)(eap_manager_t*))destroy; this->methods = linked_list_create(); - this->mutex = mutex_create(MUTEX_DEFAULT); + this->lock = rwlock_create(RWLOCK_DEFAULT); return &this->public; } diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c index d27a8ac2f..9aef352e2 100644 --- a/src/charon/sa/authenticators/eap/eap_method.c +++ b/src/charon/sa/authenticators/eap/eap_method.c @@ -36,6 +36,36 @@ ENUM_NEXT(eap_type_names, EAP_RADIUS, EAP_EXPERIMENTAL, EAP_MSCHAPV2, "EAP_EXPERIMENTAL"); ENUM_END(eap_type_names, EAP_EXPERIMENTAL); +/* + * See header + */ +eap_type_t eap_type_from_string(char *name) +{ + int i; + static struct { + char *name; + eap_type_t type; + } types[] = { + {"identity", EAP_IDENTITY}, + {"md5", EAP_MD5}, + {"otp", EAP_OTP}, + {"gtc", EAP_GTC}, + {"sim", EAP_SIM}, + {"aka", EAP_AKA}, + {"mschapv2", EAP_MSCHAPV2}, + {"radius", EAP_RADIUS}, + }; + + for (i = 0; i < countof(types); i++) + { + if (strcasecmp(name, types[i].name) == 0) + { + return types[i].type; + } + } + return 0; +} + ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE, "EAP_REQUEST", "EAP_RESPONSE", @@ -48,3 +78,6 @@ ENUM(eap_role_names, EAP_SERVER, EAP_PEER, "EAP_PEER", ); + + + diff --git a/src/charon/sa/authenticators/eap/eap_method.h b/src/charon/sa/authenticators/eap/eap_method.h index 1aa6162ee..43a336ada 100644 --- a/src/charon/sa/authenticators/eap/eap_method.h +++ b/src/charon/sa/authenticators/eap/eap_method.h @@ -69,6 +69,14 @@ enum eap_type_t { extern enum_name_t *eap_type_names; /** + * Lookup the EAP method type from a string. + * + * @param name EAP method name (such as "md5", "aka") + * @return method type, 0 if unkown + */ +eap_type_t eap_type_from_string(char *name); + +/** * EAP code, type of an EAP message */ enum eap_code_t { @@ -83,7 +91,6 @@ enum eap_code_t { */ extern enum_name_t *eap_code_names; - /** * Interface of an EAP method for server and client side. * diff --git a/src/charon/sa/authenticators/eap/sim_manager.h b/src/charon/sa/authenticators/eap/sim_manager.h index 69a2e4df9..3c6d66dfe 100644 --- a/src/charon/sa/authenticators/eap/sim_manager.h +++ b/src/charon/sa/authenticators/eap/sim_manager.h @@ -39,7 +39,7 @@ struct sim_card_t { * The returned identity owned by the sim_card and not destroyed outside. * The SIM card may return ID_ANY if it does not support/use an IMSI. * - * @return identity of type ID_EAP/ID_ANY + * @return identity */ identification_t* (*get_imsi)(sim_card_t *this); @@ -63,7 +63,7 @@ struct sim_provider_t { /** * Get a single triplet to authenticate a EAP client. * - * @param imsi client identity of type ID_EAP + * @param imsi client identity * @param rand RAND output buffer, fixed size 16 bytes * @param sres SRES output buffer, fixed size 4 byte * @param kc KC output buffer, fixed size 8 bytes diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c index 9d7113fd2..876cb7b74 100644 --- a/src/charon/sa/authenticators/eap_authenticator.c +++ b/src/charon/sa/authenticators/eap_authenticator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,13 +15,12 @@ * $Id$ */ -#include <string.h> - #include "eap_authenticator.h" #include <daemon.h> -#include <config/peer_cfg.h> #include <sa/authenticators/eap/eap_method.h> +#include <encoding/payloads/auth_payload.h> +#include <encoding/payloads/eap_payload.h> typedef struct private_eap_authenticator_t private_eap_authenticator_t; @@ -41,9 +40,14 @@ struct private_eap_authenticator_t { ike_sa_t *ike_sa; /** - * Role of this authenticator, PEER or SERVER + * nonce to include in AUTH calculation */ - eap_role_t role; + chunk_t nonce; + + /** + * IKE_SA_INIT message data to include in AUTH calculation + */ + chunk_t ike_sa_init; /** * Current EAP method processing @@ -56,442 +60,509 @@ struct private_eap_authenticator_t { chunk_t msk; /** - * should we do a EAP-Identity exchange as server? + * EAP authentication method completed successfully */ - bool do_eap_identity; + bool eap_complete; /** - * saved EAP type if we do eap_identity + * authentication payload verified successfully */ - eap_type_t type; + bool auth_complete; /** - * saved vendor id if we do eap_identity + * generated EAP payload */ - u_int32_t vendor; + eap_payload_t *eap_payload; + + /** + * EAP identity of peer + */ + identification_t *eap_identity; }; + /** - * Implementation of authenticator_t.verify. + * load an EAP method */ -static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init, - chunk_t my_nonce, auth_payload_t *auth_payload) +static eap_method_t *load_method(private_eap_authenticator_t *this, + eap_type_t type, u_int32_t vendor, eap_role_t role) { - chunk_t auth_data, recv_auth_data; - identification_t *other_id; - keymat_t *keymat; - - other_id = this->ike_sa->get_other_id(this->ike_sa); - keymat = this->ike_sa->get_keymat(this->ike_sa); - - auth_data = keymat->get_psk_sig(keymat, TRUE, ike_sa_init, my_nonce, - this->msk, other_id); + identification_t *server, *peer; - recv_auth_data = auth_payload->get_data(auth_payload); - if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data)) + if (role == EAP_SERVER) { - DBG1(DBG_IKE, "verification of AUTH payload created from EAP MSK failed"); - chunk_free(&auth_data); - return FAILED; + server = this->ike_sa->get_my_id(this->ike_sa); + peer = this->ike_sa->get_other_id(this->ike_sa); } - chunk_free(&auth_data); - - DBG1(DBG_IKE, "authentication of '%D' with %N successful", - other_id, auth_class_names, AUTH_CLASS_EAP); - return SUCCESS; -} - -/** - * Implementation of authenticator_t.build. - */ -static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init, - chunk_t other_nonce, auth_payload_t **auth_payload) -{ - identification_t *my_id; - chunk_t auth_data; - keymat_t *keymat; - - my_id = this->ike_sa->get_my_id(this->ike_sa); - keymat = this->ike_sa->get_keymat(this->ike_sa); - - DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", - my_id, auth_class_names, AUTH_CLASS_EAP); - - auth_data = keymat->get_psk_sig(keymat, FALSE, ike_sa_init, other_nonce, - this->msk, my_id); - - *auth_payload = auth_payload_create(); - (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK); - (*auth_payload)->set_data(*auth_payload, auth_data); - chunk_free(&auth_data); - - return SUCCESS; + else + { + server = this->ike_sa->get_other_id(this->ike_sa); + peer = this->ike_sa->get_my_id(this->ike_sa); + } + if (this->eap_identity) + { + peer = this->eap_identity; + } + return charon->eap->create_instance(charon->eap, type, vendor, + role, server, peer); } /** - * get the peers identity to use in the EAP method + * Initiate EAP conversation as server */ -static identification_t *get_peer_id(private_eap_authenticator_t *this) +static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, + bool do_identity) { + auth_cfg_t *auth; + eap_type_t type; identification_t *id; - peer_cfg_t *config; - auth_info_t *auth; + u_int32_t vendor; + eap_payload_t *out; - id = this->ike_sa->get_eap_identity(this->ike_sa); - if (!id) + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + + /* initiate EAP-Identity exchange if required */ + if (!this->eap_identity && do_identity) { - config = this->ike_sa->get_peer_cfg(this->ike_sa); - auth = config->get_auth(config); - if (!auth->get_item(auth, AUTHN_EAP_IDENTITY, (void**)&id) || - id->get_type(id) == ID_ANY) + id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); + if (id) { - if (this->role == EAP_PEER) - { - id = this->ike_sa->get_my_id(this->ike_sa); - } - else + this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER); + if (this->method) { - id = this->ike_sa->get_other_id(this->ike_sa); + if (this->method->initiate(this->method, &out) == NEED_MORE) + { + DBG1(DBG_IKE, "initiating EAP-Identity request"); + return out; + } + this->method->destroy(this->method); } + DBG1(DBG_IKE, "EAP-Identity request configured, but not supported"); } } - if (id->get_type(id) == ID_EAP) + /* invoke real EAP method */ + type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); + vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); + this->method = load_method(this, type, vendor, EAP_SERVER); + if (this->method && + this->method->initiate(this->method, &out) == NEED_MORE) { - return id->clone(id); + if (vendor) + { + DBG1(DBG_IKE, "initiating EAP vendor type %d-%d", type, vendor); + + } + else + { + DBG1(DBG_IKE, "initiating %N", eap_type_names, type); + } + return out; } - return identification_create_from_encoding(ID_EAP, id->get_encoding(id)); -} - -/** - * get the servers identity to use in the EAP method - */ -static identification_t *get_server_id(private_eap_authenticator_t *this) -{ - identification_t *id; - - if (this->role == EAP_SERVER) + if (vendor) { - id = this->ike_sa->get_my_id(this->ike_sa); + DBG1(DBG_IKE, "initiating EAP vendor type %d-%d failed", type, vendor); } else { - id = this->ike_sa->get_other_id(this->ike_sa); - } - if (id->get_type(id) == ID_EAP) - { - return id->clone(id); + DBG1(DBG_IKE, "initiating %N failed", eap_type_names, type); } - return identification_create_from_encoding(ID_EAP, id->get_encoding(id)); + return eap_payload_create_code(EAP_FAILURE, 0); } /** - * load an EAP method using the correct identities + * Handle EAP exchange as server */ -static eap_method_t *load_method(private_eap_authenticator_t *this, - eap_type_t type, u_int32_t vendor, eap_role_t role) +static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, + eap_payload_t *in) { - identification_t *server, *peer; - eap_method_t *method; + eap_type_t type, received_type; + u_int32_t vendor, received_vendor; + eap_payload_t *out; + auth_cfg_t *cfg; - server = get_server_id(this); - peer = get_peer_id(this); - method = charon->eap->create_instance(charon->eap, type, vendor, role, - server, peer); - server->destroy(server); - peer->destroy(peer); - return method; -} - -/** - * Implementation of eap_authenticator_t.initiate - */ -static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, - u_int32_t vendor, eap_payload_t **out) -{ - /* if initiate() is called, role is always server */ - this->role = EAP_SERVER; - - if (this->do_eap_identity) - { /* do an EAP-Identity request first */ - this->type = type; - this->vendor = vendor; - vendor = 0; - type = EAP_IDENTITY; - } - - if (type == 0) + if (in->get_code(in) != EAP_RESPONSE) { - DBG1(DBG_IKE, - "client requested EAP authentication, but configuration forbids it"); - *out = eap_payload_create_code(EAP_FAILURE, 0); - return FAILED; + DBG1(DBG_IKE, "received %N, sending %N", + eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE); + return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); } - if (vendor) - { - DBG1(DBG_IKE, "requesting vendor specific EAP method %d-%d", - type, vendor); - } - else - { - DBG1(DBG_IKE, "requesting EAP method %N", eap_type_names, type); - } - this->method = load_method(this, type, vendor, this->role); - if (this->method == NULL) + type = this->method->get_type(this->method, &vendor); + received_type = in->get_type(in, &received_vendor); + if (type != received_type || vendor != received_vendor) { - if (vendor == 0 && type == EAP_IDENTITY) + if (received_vendor == 0 && received_type == EAP_NAK) { - DBG1(DBG_IKE, "skipping %N, no implementation found", - eap_type_names, type); - this->do_eap_identity = FALSE; - return initiate(this, this->type, this->vendor, out); + DBG1(DBG_IKE, "received %N, sending %N", + eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE); } - DBG1(DBG_IKE, "configured EAP server method not supported, sending %N", - eap_code_names, EAP_FAILURE); - *out = eap_payload_create_code(EAP_FAILURE, 0); - return FAILED; + else + { + DBG1(DBG_IKE, "received invalid EAP response, sending %N", + eap_code_names, EAP_FAILURE); + } + return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); } - if (this->method->initiate(this->method, out) != NEED_MORE) + + switch (this->method->process(this->method, in, &out)) { - DBG1(DBG_IKE, "failed to initiate EAP exchange, sending %N", - eap_code_names, EAP_FAILURE); - *out = eap_payload_create_code(EAP_FAILURE, 0); - return FAILED; + case NEED_MORE: + return out; + case SUCCESS: + if (type == EAP_IDENTITY) + { + chunk_t data; + char buf[256]; + + if (this->method->get_msk(this->method, &data) == SUCCESS) + { + snprintf(buf, sizeof(buf), "%.*s", data.len, data.ptr); + this->eap_identity = identification_create_from_string(buf); + DBG1(DBG_IKE, "received EAP identity '%D'", + this->eap_identity); + } + /* restart EAP exchange, but with real method */ + this->method->destroy(this->method); + return server_initiate_eap(this, FALSE); + } + if (this->method->get_msk(this->method, &this->msk) == SUCCESS) + { + this->msk = chunk_clone(this->msk); + } + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, " + "%sMSK established", type, vendor, + this->msk.ptr ? "" : "no "); + } + else + { + DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established", + eap_type_names, type, this->msk.ptr ? "" : "no "); + } + this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, + TRUE); + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); + if (vendor) + { + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); + } + this->eap_complete = TRUE; + return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in)); + case FAILED: + default: + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for " + "peer %D", type, vendor, + this->ike_sa->get_other_id(this->ike_sa)); + } + else + { + DBG1(DBG_IKE, "EAP method %N failed for peer %D", + eap_type_names, type, + this->ike_sa->get_other_id(this->ike_sa)); + } + return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); } - return NEED_MORE; } /** * Processing method for a peer */ -static status_t process_peer(private_eap_authenticator_t *this, - eap_payload_t *in, eap_payload_t **out) +static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, + eap_payload_t *in) { eap_type_t type; u_int32_t vendor; + auth_cfg_t *auth; + eap_payload_t *out; + identification_t *id; type = in->get_type(in, &vendor); if (!vendor && type == EAP_IDENTITY) { - eap_method_t *method; + DESTROY_IF(this->eap_identity); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); + if (!id || id->get_type(id) == ID_ANY) + { + id = this->ike_sa->get_my_id(this->ike_sa); + } + DBG1(DBG_IKE, "server requested %N, sending '%D'", + eap_type_names, type, id); + this->eap_identity = id->clone(id); - method = load_method(this, type, 0, EAP_PEER); - if (method == NULL || method->process(method, in, out) != SUCCESS) + this->method = load_method(this, type, vendor, EAP_PEER); + if (this->method) { - DBG1(DBG_IKE, "EAP server requested %N, but unable to process", - eap_type_names, type); - DESTROY_IF(method); - return FAILED; + if (this->method->process(this->method, in, &out) == SUCCESS) + { + this->method->destroy(this->method); + this->method = NULL; + return out; + } + this->method->destroy(this->method); + this->method = NULL; } - DBG1(DBG_IKE, "EAP server requested %N", eap_type_names, type); - method->destroy(method); - return NEED_MORE; + DBG1(DBG_IKE, "%N not supported, sending EAP_NAK", + eap_type_names, type); + return eap_payload_create_nak(in->get_identifier(in)); } - - /* create an eap_method for the first call */ if (this->method == NULL) { if (vendor) { - DBG1(DBG_IKE, "EAP server requested vendor specific EAP method %d-%d", + DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d", type, vendor); } else { - DBG1(DBG_IKE, "EAP server requested %N authentication", + DBG1(DBG_IKE, "server requested %N authentication", eap_type_names, type); } this->method = load_method(this, type, vendor, EAP_PEER); - if (this->method == NULL) + if (!this->method) { - DBG1(DBG_IKE, "EAP server requested unsupported " - "EAP method, sending EAP_NAK"); - *out = eap_payload_create_nak(in->get_identifier(in)); - return NEED_MORE; + DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK"); + return eap_payload_create_nak(in->get_identifier(in)); } } type = this->method->get_type(this->method, &vendor); - switch (this->method->process(this->method, in, out)) + if (this->method->process(this->method, in, &out) == NEED_MORE) + { /* client methods should never return SUCCESS */ + return out; + } + + if (vendor) { - case NEED_MORE: - return NEED_MORE; - case SUCCESS: - if (vendor) - { - DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeded", - type, vendor); - } - else - { - DBG1(DBG_IKE, "EAP method %N succeeded", eap_type_names, type); - } - return SUCCESS; - case FAILED: - default: - if (vendor) - { - DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed", - type, vendor); - } - else - { - DBG1(DBG_IKE, "EAP method %N failed", - eap_type_names, type); - } - return FAILED; + DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor); + } + else + { + DBG1(DBG_IKE, "%N method failed", eap_type_names, type); } + return NULL; } /** - * handle an EAP-Identity response on the server + * Verify AUTH payload */ -static status_t process_eap_identity(private_eap_authenticator_t *this, - eap_payload_t **out) +static bool verify_auth(private_eap_authenticator_t *this, message_t *message) { - chunk_t data; - identification_t *id; - - if (this->method->get_msk(this->method, &data) == SUCCESS) + auth_payload_t *auth_payload; + chunk_t auth_data, recv_auth_data; + identification_t *other_id; + auth_cfg_t *auth; + keymat_t *keymat; + + auth_payload = (auth_payload_t*)message->get_payload(message, + AUTHENTICATION); + if (!auth_payload) { - id = identification_create_from_encoding(ID_EAP, data); - DBG1(DBG_IKE, "using EAP identity '%D'", id); - this->ike_sa->set_eap_identity(this->ike_sa, id); + DBG1(DBG_IKE, "AUTH payload missing"); + return FALSE; } - /* restart EAP exchange, but with real method */ - this->method->destroy(this->method); - this->method = NULL; - this->do_eap_identity = FALSE; - return initiate(this, this->type, this->vendor, out); + other_id = this->ike_sa->get_other_id(this->ike_sa); + keymat = this->ike_sa->get_keymat(this->ike_sa); + auth_data = keymat->get_psk_sig(keymat, TRUE, this->ike_sa_init, + this->nonce, this->msk, other_id); + recv_auth_data = auth_payload->get_data(auth_payload); + if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data)) + { + DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed", + this->msk.ptr ? "" : "out"); + chunk_free(&auth_data); + return FALSE; + } + chunk_free(&auth_data); + + DBG1(DBG_IKE, "authentication of '%D' with %N successful", + other_id, auth_class_names, AUTH_CLASS_EAP); + this->auth_complete = TRUE; + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); + return TRUE; +} + +/** + * Build AUTH payload + */ +static void build_auth(private_eap_authenticator_t *this, message_t *message) +{ + auth_payload_t *auth_payload; + identification_t *my_id; + chunk_t auth_data; + keymat_t *keymat; + + my_id = this->ike_sa->get_my_id(this->ike_sa); + keymat = this->ike_sa->get_keymat(this->ike_sa); + + DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", + my_id, auth_class_names, AUTH_CLASS_EAP); + + auth_data = keymat->get_psk_sig(keymat, FALSE, this->ike_sa_init, + this->nonce, this->msk, my_id); + auth_payload = auth_payload_create(); + auth_payload->set_auth_method(auth_payload, AUTH_PSK); + auth_payload->set_data(auth_payload, auth_data); + message->add_payload(message, (payload_t*)auth_payload); + chunk_free(&auth_data); } /** - * Processing method for a server + * Implementation of authenticator_t.process for a server */ static status_t process_server(private_eap_authenticator_t *this, - eap_payload_t *in, eap_payload_t **out) + message_t *message) { - eap_type_t type; - u_int32_t vendor; + eap_payload_t *eap_payload; - type = this->method->get_type(this->method, &vendor); + if (this->eap_complete) + { + if (!verify_auth(this, message)) + { + return FAILED; + } + return NEED_MORE; + } - switch (this->method->process(this->method, in, out)) + if (!this->method) { - case NEED_MORE: - return NEED_MORE; - case SUCCESS: - if (this->do_eap_identity) - { - return process_eap_identity(this, out); - } - if (this->method->get_msk(this->method, &this->msk) == SUCCESS) - { - this->msk = chunk_clone(this->msk); - } - if (vendor) - { - DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeded, " - "%sMSK established", type, vendor, - this->msk.ptr ? "" : "no "); - } - else - { - DBG1(DBG_IKE, "EAP method %N succeded, %sMSK established", - eap_type_names, type, this->msk.ptr ? "" : "no "); - } - *out = eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in)); - return SUCCESS; - case FAILED: - default: - if (vendor) - { - DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for " - "peer %D", type, vendor, - this->ike_sa->get_other_id(this->ike_sa)); - } - else - { - DBG1(DBG_IKE, "EAP method %N failed for peer '%D'", - eap_type_names, type, - this->ike_sa->get_other_id(this->ike_sa)); - } - *out = eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); + this->eap_payload = server_initiate_eap(this, TRUE); + } + else + { + eap_payload = (eap_payload_t*)message->get_payload(message, + EXTENSIBLE_AUTHENTICATION); + if (!eap_payload) + { return FAILED; + } + this->eap_payload = server_process_eap(this, eap_payload); } + return NEED_MORE; } /** - * Implementation of eap_authenticator_t.process + * Implementation of authenticator_t.build for a server */ -static status_t process(private_eap_authenticator_t *this, eap_payload_t *in, - eap_payload_t **out) +static status_t build_server(private_eap_authenticator_t *this, + message_t *message) { - eap_code_t code = in->get_code(in); + if (this->eap_payload) + { + eap_code_t code; + + code = this->eap_payload->get_code(this->eap_payload); + message->add_payload(message, (payload_t*)this->eap_payload); + this->eap_payload = NULL; + if (code == EAP_FAILURE) + { + return FAILED; + } + return NEED_MORE; + } + if (this->eap_complete && this->auth_complete) + { + build_auth(this, message); + return SUCCESS; + } + return FAILED; +} + +/** + * Implementation of authenticator_t.process for a client + */ +static status_t process_client(private_eap_authenticator_t *this, + message_t *message) +{ + eap_payload_t *eap_payload; - switch (this->role) + if (this->eap_complete) { - case EAP_SERVER: + if (!verify_auth(this, message)) { - switch (code) - { - case EAP_RESPONSE: - { - return process_server(this, in, out); - } - default: - { - DBG1(DBG_IKE, "received %N, sending %N", - eap_code_names, code, eap_code_names, EAP_FAILURE); - *out = eap_payload_create_code(EAP_FAILURE, - in->get_identifier(in)); - return FAILED; - } - } + return FAILED; } - case EAP_PEER: + return SUCCESS; + } + + eap_payload = (eap_payload_t*)message->get_payload(message, + EXTENSIBLE_AUTHENTICATION); + if (eap_payload) + { + switch (eap_payload->get_code(eap_payload)) { - switch (code) + case EAP_REQUEST: + { + this->eap_payload = client_process_eap(this, eap_payload); + return NEED_MORE; + } + case EAP_SUCCESS: { - case EAP_REQUEST: + eap_type_t type; + u_int32_t vendor; + auth_cfg_t *cfg; + + if (this->method->get_msk(this->method, &this->msk) == SUCCESS) { - return process_peer(this, in, out); + this->msk = chunk_clone(this->msk); } - case EAP_SUCCESS: + type = this->method->get_type(this->method, &vendor); + if (vendor) { - if (this->method->get_msk(this->method, &this->msk) == SUCCESS) - { - this->msk = chunk_clone(this->msk); - } - return SUCCESS; + DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, " + "%sMSK established", type, vendor, + this->msk.ptr ? "" : "no "); } - case EAP_FAILURE: - default: + else { - DBG1(DBG_IKE, "received %N, EAP authentication failed", - eap_code_names, code); - return FAILED; + DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established", + eap_type_names, type, this->msk.ptr ? "" : "no "); } + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); + if (vendor) + { + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); + } + this->eap_complete = TRUE; + return NEED_MORE; + } + case EAP_FAILURE: + default: + { + DBG1(DBG_IKE, "received %N, EAP authentication failed", + eap_code_names, eap_payload->get_code(eap_payload)); + return FAILED; } - } - default: - { - return FAILED; } } + return FAILED; } /** - * Implementation of authenticator_t.is_mutual. + * Implementation of authenticator_t.build for a client */ -static bool is_mutual(private_eap_authenticator_t *this) +static status_t build_client(private_eap_authenticator_t *this, + message_t *message) { - if (this->method) + if (this->eap_payload) { - return this->method->is_mutual(this->method); + message->add_payload(message, (payload_t*)this->eap_payload); + this->eap_payload = NULL; + return NEED_MORE; } - return FALSE; + if (this->eap_complete) + { + build_auth(this, message); + return NEED_MORE; + } + return NEED_MORE; } /** @@ -500,6 +571,8 @@ static bool is_mutual(private_eap_authenticator_t *this) static void destroy(private_eap_authenticator_t *this) { DESTROY_IF(this->method); + DESTROY_IF(this->eap_payload); + DESTROY_IF(this->eap_identity); chunk_free(&this->msk); free(this); } @@ -507,46 +580,50 @@ static void destroy(private_eap_authenticator_t *this) /* * Described in header. */ -eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa) +eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init) { - peer_cfg_t *config; - auth_info_t *auth; - identification_t *id; private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t); - /* public functions */ - this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify; - this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build; - this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy; - - this->public.is_mutual = (bool(*)(eap_authenticator_t*))is_mutual; - this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,u_int32_t,eap_payload_t**))initiate; - this->public.process = (status_t(*)(eap_authenticator_t*,eap_payload_t*,eap_payload_t**))process; + this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build_client; + this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_client; + this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - /* private data */ this->ike_sa = ike_sa; - this->role = EAP_PEER; + this->ike_sa_init = sent_init; + this->nonce = received_nonce; + this->msk = chunk_empty; this->method = NULL; + this->eap_payload = NULL; + this->eap_complete = FALSE; + this->auth_complete = FALSE; + this->eap_identity = NULL; + + return &this->public; +} + +/* + * Described in header. + */ +eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init) +{ + private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t); + + this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *messageh))build_server; + this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_server; + this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; + + this->ike_sa = ike_sa; + this->ike_sa_init = received_init; + this->nonce = sent_nonce; this->msk = chunk_empty; - this->do_eap_identity = FALSE; - this->type = 0; - this->vendor = 0; + this->method = NULL; + this->eap_payload = NULL; + this->eap_complete = FALSE; + this->auth_complete = FALSE; + this->eap_identity = NULL; - config = ike_sa->get_peer_cfg(ike_sa); - if (config) - { - auth = config->get_auth(config); - if (auth->get_item(auth, AUTHN_EAP_IDENTITY, (void**)&id)) - { - if (id->get_type(id) == ID_ANY) - { /* %any as configured EAP identity runs EAP-Identity first */ - this->do_eap_identity = TRUE; - } - else - { - ike_sa->set_eap_identity(ike_sa, id->clone(id)); - } - } - } return &this->public; } + diff --git a/src/charon/sa/authenticators/eap_authenticator.h b/src/charon/sa/authenticators/eap_authenticator.h index 0aaa07f35..ac01647b1 100644 --- a/src/charon/sa/authenticators/eap_authenticator.h +++ b/src/charon/sa/authenticators/eap_authenticator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -26,21 +26,13 @@ typedef struct eap_authenticator_t eap_authenticator_t; #include <sa/authenticators/authenticator.h> -#include <encoding/payloads/eap_payload.h> /** - * Implementation of the authenticator_t interface using AUTH_CLASS_EAP. + * Implementation of authenticator_t using EAP authentication. * * Authentication using EAP involves the most complex authenticator. It stays * alive over multiple ike_auth transactions and handles multiple EAP * messages. - * EAP authentication must be clearly distinguished between using - * mutual EAP methods and using methods not providing server authentication. - * If no mutual authentication is used, the server must prove it's identity - * by traditional AUTH methods (RSA, psk). Only when the EAP method is mutual, - * the client should accept an EAP-only authentication. - * RFC4306 does always use traditional authentiction, EAP only authentication - * is described in the internet draft draft-eronen-ipsec-ikev2-eap-auth-05.txt. * * @verbatim ike_sa_init @@ -49,12 +41,12 @@ typedef struct eap_authenticator_t eap_authenticator_t; followed by multiple ike_auth: +--------+ +--------+ - | EAP | ID, SA, TS, N(EAP_ONLY) | EAP | + | EAP | IDi, [IDr,] SA, TS | EAP | | client | ---------------------------> | server | - | | ID, [AUTH,] EAP | | AUTH payload is - | | <--------------------------- | | only included if - | | EAP | | authentication - | | ---------------------------> | | is not mutual. + | | ID, AUTH, EAP | | + | | <--------------------------- | | + | | EAP | | + | | ---------------------------> | | | | EAP | | | | <--------------------------- | | | | EAP | | @@ -74,74 +66,29 @@ struct eap_authenticator_t { /** * Implemented authenticator_t interface. */ - authenticator_t authenticator_interface; - - /** - * Check if the EAP method was/is mutual and secure. - * - * RFC4306 proposes to authenticate the EAP responder (server) by standard - * IKEv2 methods (RSA, psk). Not all, but some EAP methods - * provide mutual authentication, which would result in a redundant - * authentication. If the client supports EAP_ONLY_AUTHENTICATION, and - * the the server provides mutual authentication, authentication using - * RSA/PSK may be omitted. If the server did not include a traditional - * AUTH payload, the client must verify that the server initiated mutual - * EAP authentication before it can trust the server. - * - * @return TRUE, if no AUTH payload required, FALSE otherwise - */ - bool (*is_mutual) (eap_authenticator_t* this); - - /** - * Initiate the EAP exchange. - * - * The server initiates EAP exchanges, so the client never calls - * this method. If initiate() returns NEED_MORE, the EAP authentication - * process started. In any case, a payload is created in "out". - * - * @param type EAP method to use to authenticate client - * @param vendor EAP vendor identifier, if type is vendor specific, or 0 - * @param out created initiaal EAP message to send - * @return - * - FAILED, if initiation failed - * - NEED_MORE, if more EAP exchanges reqired - */ - status_t (*initiate) (eap_authenticator_t* this, eap_type_t type, - u_int32_t vendor, eap_payload_t **out); - - /** - * Process an EAP message. - * - * After receiving an EAP message "in", the peer/server processes - * the payload and creates a reply/subsequent request. - * The server side always returns NEED_MORE if another EAP message - * is expected from the client, SUCCESS if EAP exchange completed and - * "out" is EAP_SUCCES, or FAILED if the EAP exchange failed with - * a EAP_FAILURE payload in "out". Anyway, a payload in "out" is always - * created. - * The peer (client) side only creates a "out" payload if result is - * NEED_MORE, a SUCCESS/FAILED is returned whenever a - * EAP_SUCCESS/EAP_FAILURE message is received in "in". - * If a SUCCESS is returned (on any side), the EAP authentication was - * successful and the AUTH payload can be exchanged. - * - * @param in received EAP message - * @param out created EAP message to send - * @return - * - FAILED, if authentication/EAP exchange failed - * - SUCCESS, if authentication completed - * - NEED_MORE, if more EAP exchanges reqired - */ - status_t (*process) (eap_authenticator_t* this, - eap_payload_t *in, eap_payload_t **out); + authenticator_t authenticator; }; /** - * Creates an authenticator for AUTH_CLASS_EAP. + * Create an authenticator to authenticate against an EAP server. * - * @param ike_sa associated ike_sa - * @return eap_authenticator_t object + * @param ike_sa associated ike_sa + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_init sent IKE_SA_INIT message data + * @return EAP authenticator + */ +eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init); + +/** + * Create an authenticator to authenticate EAP clients. + * + * @param ike_sa associated ike_sa + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @return EAP authenticator */ -eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa); +eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init); #endif /** EAP_AUTHENTICATOR_H_ @}*/ diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c index a3c84c491..45baa8e9c 100644 --- a/src/charon/sa/authenticators/psk_authenticator.c +++ b/src/charon/sa/authenticators/psk_authenticator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -16,13 +16,10 @@ * $Id$ */ -#include <string.h> - #include "psk_authenticator.h" #include <daemon.h> -#include <credentials/auth_info.h> - +#include <encoding/payloads/auth_payload.h> typedef struct private_psk_authenticator_t private_psk_authenticator_t; @@ -40,22 +37,74 @@ struct private_psk_authenticator_t { * Assigned IKE_SA */ ike_sa_t *ike_sa; + + /** + * nonce to include in AUTH calculation + */ + chunk_t nonce; + + /** + * IKE_SA_INIT message data to include in AUTH calculation + */ + chunk_t ike_sa_init; }; +/* + * Implementation of authenticator_t.build for builder + */ +static status_t build(private_psk_authenticator_t *this, message_t *message) +{ + identification_t *my_id, *other_id; + auth_payload_t *auth_payload; + shared_key_t *key; + chunk_t auth_data; + keymat_t *keymat; + + keymat = this->ike_sa->get_keymat(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", + my_id, auth_method_names, AUTH_PSK); + key = charon->credentials->get_shared(charon->credentials, SHARED_IKE, + my_id, other_id); + if (key == NULL) + { + DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id); + return NOT_FOUND; + } + auth_data = keymat->get_psk_sig(keymat, FALSE, this->ike_sa_init, + this->nonce, key->get_key(key), my_id); + key->destroy(key); + DBG2(DBG_IKE, "successfully created shared key MAC"); + auth_payload = auth_payload_create(); + auth_payload->set_auth_method(auth_payload, AUTH_PSK); + auth_payload->set_data(auth_payload, auth_data); + chunk_free(&auth_data); + message->add_payload(message, (payload_t*)auth_payload); + + return SUCCESS; +} + /** - * Implementation of authenticator_t.verify. + * Implementation of authenticator_t.process for verifier */ -static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, - chunk_t my_nonce, auth_payload_t *auth_payload) +static status_t process(private_psk_authenticator_t *this, message_t *message) { chunk_t auth_data, recv_auth_data; identification_t *my_id, *other_id; + auth_payload_t *auth_payload; + auth_cfg_t *auth; shared_key_t *key; enumerator_t *enumerator; bool authenticated = FALSE; int keys_found = 0; keymat_t *keymat; + auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + if (!auth_payload) + { + return FAILED; + } keymat = this->ike_sa->get_keymat(this->ike_sa); recv_auth_data = auth_payload->get_data(auth_payload); my_id = this->ike_sa->get_my_id(this->ike_sa); @@ -66,8 +115,8 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, { keys_found++; - auth_data = keymat->get_psk_sig(keymat, TRUE, ike_sa_init, my_nonce, - key->get_key(key), other_id); + auth_data = keymat->get_psk_sig(keymat, TRUE, this->ike_sa_init, + this->nonce, key->get_key(key), other_id); if (auth_data.len && chunk_equals(auth_data, recv_auth_data)) { DBG1(DBG_IKE, "authentication of '%D' with %N successful", @@ -89,42 +138,19 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, keys_found, keys_found == 1 ? "" : "s", my_id, other_id); return FAILED; } + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); return SUCCESS; } /** - * Implementation of authenticator_t.build. + * Implementation of authenticator_t.process for builder + * Implementation of authenticator_t.build for verifier */ -static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init, - chunk_t other_nonce, auth_payload_t **auth_payload) +static status_t return_failed() { - identification_t *my_id, *other_id; - shared_key_t *key; - chunk_t auth_data; - keymat_t *keymat; - - keymat = this->ike_sa->get_keymat(this->ike_sa); - my_id = this->ike_sa->get_my_id(this->ike_sa); - other_id = this->ike_sa->get_other_id(this->ike_sa); - DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", - my_id, auth_method_names, AUTH_PSK); - key = charon->credentials->get_shared(charon->credentials, SHARED_IKE, - my_id, other_id); - if (key == NULL) - { - DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id); - return NOT_FOUND; - } - auth_data = keymat->get_psk_sig(keymat, FALSE, ike_sa_init, other_nonce, - key->get_key(key), my_id); - key->destroy(key); - DBG2(DBG_IKE, "successfully created shared key MAC"); - *auth_payload = auth_payload_create(); - (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK); - (*auth_payload)->set_data(*auth_payload, auth_data); - - chunk_free(&auth_data); - return SUCCESS; + return FAILED; } /** @@ -138,17 +164,38 @@ static void destroy(private_psk_authenticator_t *this) /* * Described in header. */ -psk_authenticator_t *psk_authenticator_create(ike_sa_t *ike_sa) +psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init) +{ + private_psk_authenticator_t *this = malloc_thing(private_psk_authenticator_t); + + this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build; + this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))return_failed; + this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; + + this->ike_sa = ike_sa; + this->ike_sa_init = sent_init; + this->nonce = received_nonce; + + return &this->public; +} + +/* + * Described in header. + */ +psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init) { private_psk_authenticator_t *this = malloc_thing(private_psk_authenticator_t); - /* public functions */ - this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify; - this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build; - this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy; + this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *messageh))return_failed; + this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process; + this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - /* private data */ this->ike_sa = ike_sa; + this->ike_sa_init = received_init; + this->nonce = sent_nonce; return &this->public; } + diff --git a/src/charon/sa/authenticators/psk_authenticator.h b/src/charon/sa/authenticators/psk_authenticator.h index 9849acdbc..c307aee52 100644 --- a/src/charon/sa/authenticators/psk_authenticator.h +++ b/src/charon/sa/authenticators/psk_authenticator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -28,22 +28,36 @@ typedef struct psk_authenticator_t psk_authenticator_t; #include <sa/authenticators/authenticator.h> /** - * Implementation of the authenticator_t interface using AUTH_PSK. + * Implementation of authenticator_t using pre-shared keys. */ struct psk_authenticator_t { /** * Implemented authenticator_t interface. */ - authenticator_t authenticator_interface; + authenticator_t authenticator; }; /** - * Creates an authenticator for AUTH_PSK. + * Create an authenticator to build PSK signatures. * - * @param ike_sa associated ike_sa - * @return psk_authenticator_t object + * @param ike_sa associated ike_sa + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_init sent IKE_SA_INIT message data + * @return PSK authenticator */ -psk_authenticator_t *psk_authenticator_create(ike_sa_t *ike_sa); +psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init); + +/** + * Create an authenticator to verify PSK signatures. + * + * @param ike_sa associated ike_sa + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @return PSK authenticator + */ +psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init); #endif /** PSK_AUTHENTICATOR_H_ @}*/ diff --git a/src/charon/sa/authenticators/pubkey_authenticator.c b/src/charon/sa/authenticators/pubkey_authenticator.c index 49a4283d2..482d6b91d 100644 --- a/src/charon/sa/authenticators/pubkey_authenticator.c +++ b/src/charon/sa/authenticators/pubkey_authenticator.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -17,13 +17,10 @@ * $Id$ */ -#include <string.h> - #include "pubkey_authenticator.h" #include <daemon.h> -#include <credentials/auth_info.h> - +#include <encoding/payloads/auth_payload.h> typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t; @@ -41,90 +38,35 @@ struct private_pubkey_authenticator_t { * Assigned IKE_SA */ ike_sa_t *ike_sa; -}; - -/** - * Implementation of authenticator_t.verify. - */ -static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init, - chunk_t my_nonce, auth_payload_t *auth_payload) -{ - public_key_t *public; - auth_method_t auth_method; - chunk_t auth_data, octets; - identification_t *id; - auth_info_t *auth, *current_auth; - enumerator_t *enumerator; - key_type_t key_type = KEY_ECDSA; - signature_scheme_t scheme; - status_t status = FAILED; - keymat_t *keymat; - id = this->ike_sa->get_other_id(this->ike_sa); - auth_method = auth_payload->get_auth_method(auth_payload); - switch (auth_method) - { - case AUTH_RSA: - /* We are currently fixed to SHA1 hashes. - * TODO: allow other hash algorithms and note it in "auth" */ - key_type = KEY_RSA; - scheme = SIGN_RSA_EMSA_PKCS1_SHA1; - break; - case AUTH_ECDSA_256: - scheme = SIGN_ECDSA_256; - break; - case AUTH_ECDSA_384: - scheme = SIGN_ECDSA_384; - break; - case AUTH_ECDSA_521: - scheme = SIGN_ECDSA_521; - break; - default: - return INVALID_ARG; - } - auth_data = auth_payload->get_data(auth_payload); - keymat = this->ike_sa->get_keymat(this->ike_sa); - octets = keymat->get_auth_octets(keymat, TRUE, ike_sa_init, my_nonce, id); - auth = this->ike_sa->get_other_auth(this->ike_sa); - enumerator = charon->credentials->create_public_enumerator( - charon->credentials, key_type, id, auth); - while (enumerator->enumerate(enumerator, &public, ¤t_auth)) - { - if (public->verify(public, scheme, octets, auth_data)) - { - DBG1(DBG_IKE, "authentication of '%D' with %N successful", - id, auth_method_names, auth_method); - status = SUCCESS; - auth->merge(auth, current_auth); - break; - } - else - { - DBG1(DBG_IKE, "signature validation failed, looking for another key"); - } - } - enumerator->destroy(enumerator); - chunk_free(&octets); - return status; -} + /** + * nonce to include in AUTH calculation + */ + chunk_t nonce; + + /** + * IKE_SA_INIT message data to include in AUTH calculation + */ + chunk_t ike_sa_init; +}; /** - * Implementation of authenticator_t.build. + * Implementation of authenticator_t.build for builder */ -static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init, - chunk_t other_nonce, auth_payload_t **auth_payload) +static status_t build(private_pubkey_authenticator_t *this, message_t *message) { chunk_t octets, auth_data; status_t status = FAILED; private_key_t *private; identification_t *id; - auth_info_t *auth; + auth_cfg_t *auth; + auth_payload_t *auth_payload; auth_method_t auth_method; signature_scheme_t scheme; keymat_t *keymat; id = this->ike_sa->get_my_id(this->ike_sa); - auth = this->ike_sa->get_my_auth(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); private = charon->credentials->get_private(charon->credentials, KEY_ANY, id, auth); if (private == NULL) @@ -169,15 +111,15 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init, return status; } keymat = this->ike_sa->get_keymat(this->ike_sa); - octets = keymat->get_auth_octets(keymat, FALSE, ike_sa_init, other_nonce, id); - + octets = keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init, + this->nonce, id); if (private->sign(private, scheme, octets, &auth_data)) { - auth_payload_t *payload = auth_payload_create(); - payload->set_auth_method(payload, auth_method); - payload->set_data(payload, auth_data); - *auth_payload = payload; + auth_payload = auth_payload_create(); + auth_payload->set_auth_method(auth_payload, auth_method); + auth_payload->set_data(auth_payload, auth_data); chunk_free(&auth_data); + message->add_payload(message, (payload_t*)auth_payload); status = SUCCESS; } DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", id, @@ -190,6 +132,93 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init, } /** + * Implementation of authenticator_t.process for verifier + */ +static status_t process(private_pubkey_authenticator_t *this, message_t *message) +{ + public_key_t *public; + auth_method_t auth_method; + auth_payload_t *auth_payload; + chunk_t auth_data, octets; + identification_t *id; + auth_cfg_t *auth, *current_auth; + enumerator_t *enumerator; + key_type_t key_type = KEY_ECDSA; + signature_scheme_t scheme; + status_t status = NOT_FOUND; + keymat_t *keymat; + + auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + if (!auth_payload) + { + return FAILED; + } + auth_method = auth_payload->get_auth_method(auth_payload); + switch (auth_method) + { + case AUTH_RSA: + /* We currently accept SHA1 signatures only + * TODO: allow other hash algorithms and note it in "auth" */ + key_type = KEY_RSA; + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case AUTH_ECDSA_256: + scheme = SIGN_ECDSA_256; + break; + case AUTH_ECDSA_384: + scheme = SIGN_ECDSA_384; + break; + case AUTH_ECDSA_521: + scheme = SIGN_ECDSA_521; + break; + default: + return INVALID_ARG; + } + auth_data = auth_payload->get_data(auth_payload); + id = this->ike_sa->get_other_id(this->ike_sa); + keymat = this->ike_sa->get_keymat(this->ike_sa); + octets = keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init, + this->nonce, id); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + enumerator = charon->credentials->create_public_enumerator( + charon->credentials, key_type, id, auth); + while (enumerator->enumerate(enumerator, &public, ¤t_auth)) + { + if (public->verify(public, scheme, octets, auth_data)) + { + DBG1(DBG_IKE, "authentication of '%D' with %N successful", + id, auth_method_names, auth_method); + status = SUCCESS; + auth->merge(auth, current_auth, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + break; + } + else + { + status = FAILED; + DBG1(DBG_IKE, "signature validation failed, looking for another key"); + } + } + enumerator->destroy(enumerator); + chunk_free(&octets); + if (status == NOT_FOUND) + { + DBG1(DBG_IKE, "no trusted %N public key found for '%D'", + key_type_names, key_type, id); + } + return status; +} + +/** + * Implementation of authenticator_t.process for builder + * Implementation of authenticator_t.build for verifier + */ +static status_t return_failed() +{ + return FAILED; +} + +/** * Implementation of authenticator_t.destroy. */ static void destroy(private_pubkey_authenticator_t *this) @@ -200,17 +229,37 @@ static void destroy(private_pubkey_authenticator_t *this) /* * Described in header. */ -pubkey_authenticator_t *pubkey_authenticator_create(ike_sa_t *ike_sa) +pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init) +{ + private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t); + + this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build; + this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))return_failed; + this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; + + this->ike_sa = ike_sa; + this->ike_sa_init = sent_init; + this->nonce = received_nonce; + + return &this->public; +} + +/* + * Described in header. + */ +pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init) { private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t); - /* public functions */ - this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify; - this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build; - this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy; + this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))return_failed; + this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process; + this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - /* private data */ this->ike_sa = ike_sa; + this->ike_sa_init = received_init; + this->nonce = sent_nonce; return &this->public; } diff --git a/src/charon/sa/authenticators/pubkey_authenticator.h b/src/charon/sa/authenticators/pubkey_authenticator.h index 4a2d9e219..997b1b593 100644 --- a/src/charon/sa/authenticators/pubkey_authenticator.h +++ b/src/charon/sa/authenticators/pubkey_authenticator.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -29,22 +29,36 @@ typedef struct pubkey_authenticator_t pubkey_authenticator_t; #include <sa/authenticators/authenticator.h> /** - * Implementation of the authenticator_t interface using AUTH_PUBKEY. + * Implementation of authenticator_t using public key authenitcation. */ struct pubkey_authenticator_t { /** * Implemented authenticator_t interface. */ - authenticator_t authenticator_interface; + authenticator_t authenticator; }; /** - * Creates an authenticator for AUTH_PUBKEY. + * Create an authenticator to build public key signatures. * - * @param ike_sa associated ike_sa - * @return pubkey_authenticator_t object + * @param ike_sa associated ike_sa + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_init sent IKE_SA_INIT message data + * @return public key authenticator */ -pubkey_authenticator_t *pubkey_authenticator_create(ike_sa_t *ike_sa); +pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init); + +/** + * Create an authenticator to verify public key signatures. + * + * @param ike_sa associated ike_sa + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @return public key authenticator + */ +pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init); #endif /** PUBKEY_AUTHENTICATOR_H_ @}*/ diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c index fa5824bf4..f597d3550 100644 --- a/src/charon/sa/connect_manager.c +++ b/src/charon/sa/connect_manager.c @@ -734,11 +734,11 @@ static void build_pairs(check_list_t *checklist) */ static status_t process_payloads(message_t *message, check_t *check) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) != NOTIFY) { @@ -796,7 +796,7 @@ static status_t process_payloads(message_t *message, check_t *check) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr) { diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 17ba15e27..2a1b96bbb 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2006-2008 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -109,14 +109,14 @@ struct private_ike_sa_t { peer_cfg_t *peer_cfg; /** - * associated authentication/authorization info for local peer + * currently used authentication ruleset, local (as auth_cfg_t) */ - auth_info_t *my_auth; + auth_cfg_t *my_auth; /** - * associated authentication/authorization info for remote peer + * currently used authentication constraints, remote (as auth_cfg_t) */ - auth_info_t *other_auth; + auth_cfg_t *other_auth; /** * Selected IKE proposal @@ -355,40 +355,23 @@ static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg) DESTROY_IF(this->peer_cfg); peer_cfg->get_ref(peer_cfg); this->peer_cfg = peer_cfg; - + if (this->ike_cfg == NULL) { this->ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); this->ike_cfg->get_ref(this->ike_cfg); } - /* apply IDs if they are not already set */ - if (this->my_id->contains_wildcards(this->my_id)) - { - DESTROY_IF(this->my_id); - this->my_id = this->peer_cfg->get_my_id(this->peer_cfg); - this->my_id = this->my_id->clone(this->my_id); - } - if (this->other_id->contains_wildcards(this->other_id)) - { - DESTROY_IF(this->other_id); - this->other_id = this->peer_cfg->get_other_id(this->peer_cfg); - this->other_id = this->other_id->clone(this->other_id); - } -} - -/** - * Implementation of ike_sa_t.get_my_auth. - */ -static auth_info_t* get_my_auth(private_ike_sa_t *this) -{ - return this->my_auth; } /** - * Implementation of ike_sa_t.get_other_auth. + * Implementation of ike_sa_t.get_auth_cfg */ -static auth_info_t* get_other_auth(private_ike_sa_t *this) +static auth_cfg_t* get_auth_cfg(private_ike_sa_t *this, bool local) { + if (local) + { + return this->my_auth; + } return this->other_auth; } @@ -1483,14 +1466,6 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) status = this->task_manager->process_message(this->task_manager, message); if (status != DESTROY_ME) { - if (message->get_exchange_type(message) == IKE_AUTH && - this->state == IKE_ESTABLISHED) - { - /* purge auth items if SA is up, as they contain certs - * and other memory wasting elements */ - this->my_auth->purge(this->my_auth); - this->other_auth->purge(this->other_auth); - } return status; } /* if IKE_SA gets closed for any reasons, reroute routed children */ @@ -2304,9 +2279,9 @@ static void destroy(private_ike_sa_t *this) DESTROY_IF(this->ike_cfg); DESTROY_IF(this->peer_cfg); - DESTROY_IF(this->my_auth); - DESTROY_IF(this->other_auth); DESTROY_IF(this->proposal); + this->my_auth->destroy(this->my_auth); + this->other_auth->destroy(this->other_auth); this->ike_sa_id->destroy(this->ike_sa_id); free(this); @@ -2334,8 +2309,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.set_ike_cfg = (void (*)(ike_sa_t*,ike_cfg_t*))set_ike_cfg; this->public.get_peer_cfg = (peer_cfg_t* (*)(ike_sa_t*))get_peer_cfg; this->public.set_peer_cfg = (void (*)(ike_sa_t*,peer_cfg_t*))set_peer_cfg; - this->public.get_my_auth = (auth_info_t*(*)(ike_sa_t*))get_my_auth; - this->public.get_other_auth = (auth_info_t*(*)(ike_sa_t*))get_other_auth; + this->public.get_auth_cfg = (auth_cfg_t*(*)(ike_sa_t*, bool local))get_auth_cfg; this->public.get_proposal = (proposal_t*(*)(ike_sa_t*))get_proposal; this->public.set_proposal = (void(*)(ike_sa_t*, proposal_t *proposal))set_proposal; this->public.get_id = (ike_sa_id_t* (*)(ike_sa_t*)) get_id; @@ -2416,8 +2390,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->stats[STAT_INBOUND] = this->stats[STAT_OUTBOUND] = time(NULL); this->ike_cfg = NULL; this->peer_cfg = NULL; - this->my_auth = auth_info_create(); - this->other_auth = auth_info_create(); + this->my_auth = auth_cfg_create(); + this->other_auth = auth_cfg_create(); this->proposal = NULL; this->task_manager = task_manager_create(&this->public); this->unique_id = ++unique_id; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 2430f00a0..6542ffa50 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2006-2008 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -41,7 +41,7 @@ typedef struct ike_sa_t ike_sa_t; #include <sa/keymat.h> #include <config/peer_cfg.h> #include <config/ike_cfg.h> -#include <credentials/auth_info.h> +#include <config/auth_cfg.h> /** * Timeout in milliseconds after that a half open IKE_SA gets deleted. @@ -82,6 +82,11 @@ enum ike_extension_t { * peer supports HTTP cert lookups as specified in RFC4306 */ EXT_HASH_AND_URL = (1<<2), + + /** + * peer supports multiple authentication exchanges, RFC4739 + */ + EXT_MULTIPLE_AUTH = (1<<3), }; /** @@ -110,7 +115,7 @@ enum ike_condition_t { COND_NAT_FAKE = (1<<3), /** - * peer has ben authenticated using EAP + * peer has been authenticated using EAP at least once */ COND_EAP_AUTHENTICATED = (1<<4), @@ -391,18 +396,12 @@ struct ike_sa_t { void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config); /** - * Get authentication/authorization info for local peer. - * - * @return auth_info for me - */ - auth_info_t* (*get_my_auth)(ike_sa_t *this); - - /** - * Get authentication/authorization info for remote peer. + * Get the authentication config with rules of the current auth round. * - * @return auth_info for me + * @param local TRUE for local rules, FALSE for remote constraints + * @return current cfg */ - auth_info_t* (*get_other_auth)(ike_sa_t *this); + auth_cfg_t* (*get_auth_cfg)(ike_sa_t *this, bool local); /** * Get the selected proposal of this IKE_SA. diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index 0528e8bbb..f9588c201 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -1042,9 +1042,7 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, enumerator_t *enumerator; entry_t *entry; ike_sa_t *ike_sa = NULL; - identification_t *my_id, *other_id; - host_t *my_host, *other_host; - ike_cfg_t *ike_cfg; + peer_cfg_t *current_cfg; u_int segment; if (!this->reuse_ikesa) @@ -1054,70 +1052,29 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, return ike_sa; } - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - my_id = peer_cfg->get_my_id(peer_cfg); - other_id = peer_cfg->get_other_id(peer_cfg); - my_host = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg), 0, 0); - other_host = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg), 0, 0); - - if (my_host && other_host) + enumerator = create_table_enumerator(this); + while (enumerator->enumerate(enumerator, &entry, &segment)) { - enumerator = create_table_enumerator(this); - while (enumerator->enumerate(enumerator, &entry, &segment)) + if (!wait_for_entry(this, entry, segment)) { - identification_t *found_my_id, *found_other_id; - host_t *found_my_host, *found_other_host; - - if (!wait_for_entry(this, entry, segment)) - { - continue; - } - - if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING) - { - /* skip IKE_SAs which are not usable */ - continue; - } - - found_my_id = entry->ike_sa->get_my_id(entry->ike_sa); - found_other_id = entry->ike_sa->get_other_id(entry->ike_sa); - found_my_host = entry->ike_sa->get_my_host(entry->ike_sa); - found_other_host = entry->ike_sa->get_other_host(entry->ike_sa); + continue; + } + if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING) + { /* skip IKE_SAs which are not usable */ + continue; + } - if (found_my_id->get_type(found_my_id) == ID_ANY && - found_other_id->get_type(found_other_id) == ID_ANY) - { - /* IKE_SA has no IDs yet, so we can't use it */ - continue; - } - DBG2(DBG_MGR, "candidate IKE_SA for \n" - " %H[%D]...%H[%D]\n" - " %H[%D]...%H[%D]", - my_host, my_id, other_host, other_id, - found_my_host, found_my_id, found_other_host, found_other_id); - /* compare ID and hosts. Supplied ID may contain wildcards, and IP - * may be %any. */ - if ((my_host->is_anyaddr(my_host) || - my_host->ip_equals(my_host, found_my_host)) && - (other_host->is_anyaddr(other_host) || - other_host->ip_equals(other_host, found_other_host)) && - found_my_id->matches(found_my_id, my_id) && - found_other_id->matches(found_other_id, other_id) && - streq(peer_cfg->get_name(peer_cfg), - entry->ike_sa->get_name(entry->ike_sa))) - { - /* looks good, we take this one */ - DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]", - my_host, my_id, other_host, other_id); - entry->checked_out = TRUE; - ike_sa = entry->ike_sa; - break; - } + current_cfg = entry->ike_sa->get_peer_cfg(entry->ike_sa); + if (current_cfg && current_cfg->equals(current_cfg, peer_cfg)) + { + DBG2(DBG_MGR, "found an existing IKE_SA with a '%s' config", + current_cfg->get_name(current_cfg)); + entry->checked_out = TRUE; + ike_sa = entry->ike_sa; + break; } - enumerator->destroy(enumerator); } - DESTROY_IF(my_host); - DESTROY_IF(other_host); + enumerator->destroy(enumerator); if (!ike_sa) { /* no IKE_SA using such a config, hand out a new */ @@ -1326,20 +1283,12 @@ static void checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) /* apply identities for duplicate test (only as responder) */ if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) && - (!entry->my_id || !entry->other_id)) + ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + entry->my_id == NULL && entry->other_id == NULL) { - if (!entry->my_id && my_id->get_type(my_id) != ID_ANY) - { - entry->my_id = my_id->clone(my_id); - } - if (!entry->other_id && other_id->get_type(other_id) != ID_ANY) - { - entry->other_id = other_id->clone(other_id); - } - if (entry->my_id && entry->other_id) - { - put_connected_peers(this, entry); - } + entry->my_id = my_id->clone(my_id); + entry->other_id = other_id->clone(other_id); + put_connected_peers(this, entry); } unlock_single_segment(this, segment); diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index 7258de5a5..88fb7984e 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -650,6 +650,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) static status_t process_request(private_task_manager_t *this, message_t *message) { + enumerator_t *enumerator; iterator_t *iterator; task_t *task = NULL; payload_t *payload; @@ -688,8 +689,8 @@ static status_t process_request(private_task_manager_t *this, case CREATE_CHILD_SA: { /* FIXME: we should prevent this on mediation connections */ bool notify_found = FALSE, ts_found = FALSE; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { switch (payload->get_type(payload)) { @@ -716,7 +717,7 @@ static status_t process_request(private_task_manager_t *this, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (ts_found) { @@ -739,8 +740,8 @@ static status_t process_request(private_task_manager_t *this, } case INFORMATIONAL: { - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { switch (payload->get_type(payload)) { @@ -793,7 +794,7 @@ static status_t process_request(private_task_manager_t *this, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (task == NULL) { diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index b3bb1840d..1e1624dca 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -570,7 +570,7 @@ static void handle_notify(private_child_create_t *this, notify_payload_t *notify */ static void process_payloads(private_child_create_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; sa_payload_t *sa_payload; ke_payload_t *ke_payload; @@ -579,8 +579,8 @@ static void process_payloads(private_child_create_t *this, message_t *message) /* defaults to TUNNEL mode */ this->mode = MODE_TUNNEL; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { switch (payload->get_type(payload)) { @@ -616,7 +616,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -643,9 +643,9 @@ static status_t build_i(private_child_create_t *this, message_t *message) } break; case IKE_AUTH: - if (!message->get_payload(message, ID_INITIATOR)) + if (message->get_message_id(message) != 1) { - /* send only in the first request, not in subsequent EAP */ + /* send only in the first request, not in subsequent rounds */ return NEED_MORE; } break; @@ -737,8 +737,6 @@ static status_t build_i(private_child_create_t *this, message_t *message) */ static status_t process_r(private_child_create_t *this, message_t *message) { - peer_cfg_t *peer_cfg; - switch (message->get_exchange_type(message)) { case IKE_SA_INIT: @@ -747,42 +745,17 @@ static status_t process_r(private_child_create_t *this, message_t *message) get_nonce(message, &this->other_nonce); break; case IKE_AUTH: - if (message->get_payload(message, ID_INITIATOR) == NULL) + if (message->get_message_id(message) != 1) { - /* wait until extensible authentication completed, if used */ + /* only handle first AUTH payload, not additional rounds */ return NEED_MORE; } default: break; } - + process_payloads(this, message); - if (this->tsi == NULL || this->tsr == NULL) - { - DBG1(DBG_IKE, "TS payload missing in message"); - return NEED_MORE; - } - - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg) - { - host_t *me, *other; - - me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (me == NULL) - { - me = this->ike_sa->get_my_host(this->ike_sa); - } - other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - if (other == NULL) - { - other = this->ike_sa->get_other_host(this->ike_sa); - } - - this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, - this->tsi, me, other); - } return NEED_MORE; } @@ -810,10 +783,11 @@ static void handle_child_sa_failure(private_child_create_t *this, */ static status_t build_r(private_child_create_t *this, message_t *message) { + peer_cfg_t *peer_cfg; payload_t *payload; - iterator_t *iterator; + enumerator_t *enumerator; bool no_dh = TRUE; - + switch (message->get_exchange_type(message)) { case IKE_SA_INIT: @@ -828,9 +802,8 @@ static status_t build_r(private_child_create_t *this, message_t *message) no_dh = FALSE; break; case IKE_AUTH: - if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) - { - /* wait until extensible authentication completed, if used */ + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* wait until all authentication round completed */ return NEED_MORE; } default: @@ -844,6 +817,25 @@ static status_t build_r(private_child_create_t *this, message_t *message) return SUCCESS; } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg && this->tsi && this->tsr) + { + host_t *me, *other; + + me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (me == NULL) + { + me = this->ike_sa->get_my_host(this->ike_sa); + } + other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); + if (other == NULL) + { + other = this->ike_sa->get_other_host(this->ike_sa); + } + this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, + this->tsi, me, other); + } + if (this->config == NULL) { DBG1(DBG_IKE, "traffic selectors %#R=== %#R inacceptable", @@ -854,8 +846,8 @@ static status_t build_r(private_child_create_t *this, message_t *message) } /* check if ike_config_t included non-critical error notifies */ - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == NOTIFY) { @@ -868,7 +860,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) { DBG1(DBG_IKE,"configuration payload negotation " "failed, no CHILD_SA built"); - iterator->destroy(iterator); + enumerator->destroy(enumerator); handle_child_sa_failure(this, message); return SUCCESS; } @@ -877,7 +869,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, @@ -938,7 +930,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) */ static status_t process_i(private_child_create_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; bool no_dh = TRUE; @@ -951,9 +943,8 @@ static status_t process_i(private_child_create_t *this, message_t *message) no_dh = FALSE; break; case IKE_AUTH: - if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) - { - /* wait until extensible authentication completed, if used */ + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* wait until all authentication round completed */ return NEED_MORE; } default: @@ -961,8 +952,8 @@ static status_t process_i(private_child_create_t *this, message_t *message) } /* check for erronous notifies */ - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == NOTIFY) { @@ -982,7 +973,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) { DBG1(DBG_IKE, "received %N notify, no CHILD_SA built", notify_type_names, type); - iterator->destroy(iterator); + enumerator->destroy(enumerator); handle_child_sa_failure(this, message); /* an error in CHILD_SA creation is not critical */ return SUCCESS; @@ -1000,7 +991,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) bad_group, diffie_hellman_group_names, this->dh_group); this->public.task.migrate(&this->public.task, this->ike_sa); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return NEED_MORE; } default: @@ -1008,7 +999,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); process_payloads(this, message); diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index 36d260f99..26e9695f9 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -114,15 +114,16 @@ static void build_payloads(private_child_delete_t *this, message_t *message) */ static void process_payloads(private_child_delete_t *this, message_t *message) { - iterator_t *payloads, *spis; + enumerator_t *payloads; + iterator_t *spis; payload_t *payload; delete_payload_t *delete_payload; u_int32_t *spi; protocol_id_t protocol; child_sa_t *child_sa; - payloads = message->get_payload_iterator(message); - while (payloads->iterate(payloads, (void**)&payload)) + payloads = message->create_payload_enumerator(message); + while (payloads->enumerate(payloads, &payload)) { if (payload->get_type(payload) == DELETE) { diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 127280efc..44a22575c 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -103,11 +103,11 @@ static status_t process_i_delete(private_child_rekey_t *this, message_t *message */ static void find_child(private_child_rekey_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { notify_payload_t *notify; u_int32_t spi; @@ -131,7 +131,7 @@ static void find_child(private_child_rekey_t *this, message_t *message) break; } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -220,12 +220,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) protocol_id_t protocol; u_int32_t spi; child_sa_t *to_delete; - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; /* handle NO_ADDITIONAL_SAS notify */ - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == NOTIFY) { @@ -239,12 +239,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) charon->processor->queue_job(charon->processor, (job_t*)rekey_ike_sa_job_create( this->ike_sa->get_id(this->ike_sa), TRUE)); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return SUCCESS; } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (this->child_create->task.process(&this->child_create->task, message) == NEED_MORE) { diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index ad1621714..d594e3baa 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -21,14 +21,12 @@ #include <string.h> #include <daemon.h> -#include <crypto/diffie_hellman.h> #include <encoding/payloads/id_payload.h> #include <encoding/payloads/auth_payload.h> #include <encoding/payloads/eap_payload.h> #include <encoding/payloads/nonce_payload.h> #include <sa/authenticators/eap_authenticator.h> - typedef struct private_ike_auth_t private_ike_auth_t; /** @@ -72,220 +70,65 @@ struct private_ike_auth_t { packet_t *other_packet; /** - * EAP authenticator when using EAP + * completed authentication configs initiated by us (auth_cfg_t) */ - eap_authenticator_t *eap_auth; + linked_list_t *my_cfgs; /** - * EAP payload received and ready to process + * completed authentication configs initiated by other (auth_cfg_t) */ - eap_payload_t *eap_payload; + linked_list_t *other_cfgs;; /** - * has the peer been authenticated successfully? + * currently active authenticator, to authenticate us */ - bool peer_authenticated; -}; - -/** - * get the authentication class of a config - */ -auth_class_t get_auth_class(peer_cfg_t *config) -{ - auth_class_t *class; - auth_info_t *auth_info; - - auth_info = config->get_auth(config); - if (auth_info->get_item(auth_info, AUTHN_AUTH_CLASS, (void**)&class)) - { - return *class; - } - /* fallback to pubkey authentication */ - return AUTH_CLASS_PUBKEY; -} - -/** - * get the eap type/vendor - */ -static eap_type_t get_eap_type(peer_cfg_t *config, u_int32_t *vendor) -{ - auth_info_t *auth_info; - u_int *ptr; - - *vendor = 0; - auth_info = config->get_auth(config); - if (auth_info->get_item(auth_info, AUTHN_EAP_VENDOR, (void**)&ptr)) - { - *vendor = *ptr; - } - if (auth_info->get_item(auth_info, AUTHN_EAP_TYPE, (void**)&ptr)) - { - return *ptr; - } - return EAP_NAK; -} - -/** - * build the AUTH payload - */ -static status_t build_auth(private_ike_auth_t *this, message_t *message) -{ - authenticator_t *auth; - auth_payload_t *auth_payload; - peer_cfg_t *config; - status_t status; + authenticator_t *my_auth; - /* create own authenticator and add auth payload */ - config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (!config) - { - DBG1(DBG_IKE, "unable to authenticate, no peer config found"); - return FAILED; - } - - auth = authenticator_create_from_class(this->ike_sa, get_auth_class(config)); - if (auth == NULL) - { - DBG1(DBG_IKE, "configured authentication class %N not supported", - auth_class_names, get_auth_class(config)); - return FAILED; - } - - status = auth->build(auth, this->my_packet->get_data(this->my_packet), - this->other_nonce, &auth_payload); - auth->destroy(auth); - if (status != SUCCESS) - { - DBG1(DBG_IKE, "generating authentication data failed"); - return FAILED; - } - message->add_payload(message, (payload_t*)auth_payload); - return SUCCESS; -} - -/** - * build ID payload(s) - */ -static status_t build_id(private_ike_auth_t *this, message_t *message) -{ - identification_t *me, *other; - id_payload_t *id; - peer_cfg_t *config; - - me = this->ike_sa->get_my_id(this->ike_sa); - other = this->ike_sa->get_other_id(this->ike_sa); - config = this->ike_sa->get_peer_cfg(this->ike_sa); - - if (me->contains_wildcards(me)) - { - me = config->get_my_id(config); - if (me->contains_wildcards(me)) - { - DBG1(DBG_IKE, "negotiation of own ID failed"); - return FAILED; - } - this->ike_sa->set_my_id(this->ike_sa, me->clone(me)); - } + /** + * currently active authenticator, to authenticate peer + */ + authenticator_t *other_auth; - id = id_payload_create_from_identification(this->initiator ? ID_INITIATOR : ID_RESPONDER, me); - message->add_payload(message, (payload_t*)id); + /** + * peer_cfg candidates, ordered by priority + */ + linked_list_t *candidates; - /* as initiator, include other ID if it does not contain wildcards */ - if (this->initiator && !other->contains_wildcards(other)) - { - id = id_payload_create_from_identification(ID_RESPONDER, other); - message->add_payload(message, (payload_t*)id); - } - return SUCCESS; -} - -/** - * process AUTH payload - */ -static status_t process_auth(private_ike_auth_t *this, message_t *message) -{ - auth_payload_t *auth_payload; - authenticator_t *auth; - auth_method_t auth_method; - status_t status; + /** + * selected peer config (might change when using multiple authentications) + */ + peer_cfg_t *peer_cfg; - auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + /** + * have we planned an(other) authentication exchange? + */ + bool do_another_auth; - if (auth_payload == NULL) - { - /* AUTH payload is missing, client wants to use EAP authentication */ - return NOT_FOUND; - } + /** + * has the peer announced another authentication exchange? + */ + bool expect_another_auth; - auth_method = auth_payload->get_auth_method(auth_payload); - auth = authenticator_create_from_method(this->ike_sa, - auth_payload->get_auth_method(auth_payload)); - if (auth == NULL) - { - DBG1(DBG_IKE, "authentication method %N used by '%D' not supported", - auth_method_names, auth_method, - this->ike_sa->get_other_id(this->ike_sa)); - return NOT_SUPPORTED; - } - status = auth->verify(auth, this->other_packet->get_data(this->other_packet), - this->my_nonce, auth_payload); - auth->destroy(auth); - if (status != SUCCESS) - { - DBG0(DBG_IKE, "authentication of '%D' with %N failed", - this->ike_sa->get_other_id(this->ike_sa), - auth_method_names, auth_method); - return FAILED; - } - return SUCCESS; -} + /** + * should we send a AUTHENTICATION_FAILED notify? + */ + bool authentication_failed; +}; /** - * process ID payload(s) + * check if multiple authentication extension is enabled, configuration-wise */ -static status_t process_id(private_ike_auth_t *this, message_t *message) +static bool multiple_auth_enabled() { - identification_t *id, *req; - id_payload_t *idr, *idi; - - idi = (id_payload_t*)message->get_payload(message, ID_INITIATOR); - idr = (id_payload_t*)message->get_payload(message, ID_RESPONDER); - - if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL)) - { - DBG1(DBG_IKE, "ID payload missing in message"); - return FAILED; - } - - if (this->initiator) - { - id = idr->get_identification(idr); - req = this->ike_sa->get_other_id(this->ike_sa); - if (!id->matches(id, req)) - { - DBG0(DBG_IKE, "peer ID '%D' unacceptable, '%D' required", id, req); - id->destroy(id); - return FAILED; - } - this->ike_sa->set_other_id(this->ike_sa, id); - } - else - { - id = idi->get_identification(idi); - this->ike_sa->set_other_id(this->ike_sa, id); - if (idr) - { - id = idr->get_identification(idr); - this->ike_sa->set_my_id(this->ike_sa, id); - } - } - return SUCCESS; + return lib->settings->get_bool(lib->settings, + "charon.multiple_authentication", TRUE); } /** * collect the needed information in the IKE_SA_INIT exchange from our message */ -static status_t collect_my_init_data(private_ike_auth_t *this, message_t *message) +static status_t collect_my_init_data(private_ike_auth_t *this, + message_t *message) { nonce_payload_t *nonce; @@ -297,7 +140,7 @@ static status_t collect_my_init_data(private_ike_auth_t *this, message_t *messag } this->my_nonce = nonce->get_nonce(nonce); - /* pre-generate the message, so we can store it for us */ + /* pre-generate the message, keep a copy */ if (this->ike_sa->generate_message(this->ike_sa, message, &this->my_packet) != SUCCESS) { @@ -309,7 +152,8 @@ static status_t collect_my_init_data(private_ike_auth_t *this, message_t *messag /** * collect the needed information in the IKE_SA_INIT exchange from others message */ -static status_t collect_other_init_data(private_ike_auth_t *this, message_t *message) +static status_t collect_other_init_data(private_ike_auth_t *this, + message_t *message) { /* we collect the needed information in the IKE_SA_INIT exchange */ nonce_payload_t *nonce; @@ -322,184 +166,186 @@ static status_t collect_other_init_data(private_ike_auth_t *this, message_t *mes } this->other_nonce = nonce->get_nonce(nonce); - /* pre-generate the message, so we can store it for us */ + /* keep a copy of the received packet */ this->other_packet = message->get_packet(message); return NEED_MORE; } - /** - * Implementation of task_t.build to create AUTH payload from EAP data + * Get the next authentication configuration */ -static status_t build_auth_eap(private_ike_auth_t *this, message_t *message) +static auth_cfg_t *get_auth_cfg(private_ike_auth_t *this, bool local) { - authenticator_t *auth; - auth_payload_t *auth_payload; + enumerator_t *e1, *e2; + auth_cfg_t *c1, *c2, *next = NULL; - if (!this->initiator && !this->peer_authenticated) + /* find an available config not already done */ + e1 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, local); + while (e1->enumerate(e1, &c1)) { - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; - } - - auth = (authenticator_t*)this->eap_auth; - if (auth->build(auth, this->my_packet->get_data(this->my_packet), - this->other_nonce, &auth_payload) != SUCCESS) - { - DBG1(DBG_IKE, "generating authentication data failed"); - if (!this->initiator) + bool found = FALSE; + + if (local) { - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); + e2 = this->my_cfgs->create_enumerator(this->my_cfgs); + } + else + { + e2 = this->other_cfgs->create_enumerator(this->other_cfgs); + } + while (e2->enumerate(e2, &c2)) + { + if (c2->complies(c2, c1, FALSE)) + { + found = TRUE; + break; + } + } + e2->destroy(e2); + if (!found) + { + next = c1; + break; } - return FAILED; - } - message->add_payload(message, (payload_t*)auth_payload); - if (!this->initiator) - { - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - return SUCCESS; } - return NEED_MORE; + e1->destroy(e1); + return next; } /** - * Implementation of task_t.process to verify AUTH payload after EAP + * Check if we have should initiate another authentication round */ -static status_t process_auth_eap(private_ike_auth_t *this, message_t *message) +static bool do_another_auth(private_ike_auth_t *this) { - auth_payload_t *auth_payload; - authenticator_t *auth; - - auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); - this->peer_authenticated = FALSE; + bool do_another = FALSE; + enumerator_t *done, *todo; + auth_cfg_t *done_cfg, *todo_cfg; - if (auth_payload) + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH)) { - auth = (authenticator_t*)this->eap_auth; - if (auth->verify(auth, this->other_packet->get_data(this->other_packet), - this->my_nonce, auth_payload) == SUCCESS) - { - this->peer_authenticated = TRUE; - } + return FALSE; } - - if (!this->peer_authenticated) + + done = this->my_cfgs->create_enumerator(this->my_cfgs); + todo = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, TRUE); + while (todo->enumerate(todo, &todo_cfg)) { - DBG0(DBG_IKE, "authentication of '%D' with %N failed", - this->ike_sa->get_other_id(this->ike_sa), - auth_class_names, AUTH_CLASS_EAP); - if (this->initiator) + if (!done->enumerate(done, &done_cfg)) { - return FAILED; + done_cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + } + if (!done_cfg->complies(done_cfg, todo_cfg, FALSE)) + { + do_another = TRUE; + break; } - return NEED_MORE; - } - if (this->initiator) - { - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - return SUCCESS; } - return NEED_MORE; + done->destroy(done); + todo->destroy(todo); + return do_another; } /** - * Implementation of task_t.process for EAP exchanges + * Get peer configuration candidates from backends */ -static status_t process_eap_i(private_ike_auth_t *this, message_t *message) +static bool load_cfg_candidates(private_ike_auth_t *this) { - eap_payload_t *eap; - - eap = (eap_payload_t*)message->get_payload(message, EXTENSIBLE_AUTHENTICATION); - if (eap == NULL) - { - DBG1(DBG_IKE, "EAP payload missing"); - return FAILED; + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + host_t *me, *other; + identification_t *my_id, *other_id; + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + me, other, my_id, other_id); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + peer_cfg->get_ref(peer_cfg); + if (this->peer_cfg == NULL) + { /* best match */ + this->peer_cfg = peer_cfg; + this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg); + } + else + { + this->candidates->insert_last(this->candidates, peer_cfg); + } } - switch (this->eap_auth->process(this->eap_auth, eap, &eap)) + enumerator->destroy(enumerator); + if (this->peer_cfg) { - case NEED_MORE: - this->eap_payload = eap; - return NEED_MORE; - case SUCCESS: - /* EAP exchange completed, now create and process AUTH */ - this->eap_payload = NULL; - this->public.task.build = (status_t(*)(task_t*,message_t*))build_auth_eap; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap; - return NEED_MORE; - default: - this->eap_payload = NULL; - DBG0(DBG_IKE, "failed to authenticate against '%D' using EAP", - this->ike_sa->get_other_id(this->ike_sa)); - return FAILED; + DBG1(DBG_CFG, "selected peer config '%s'", + this->peer_cfg->get_name(this->peer_cfg)); + return TRUE; } + DBG1(DBG_CFG, "no matching peer config found"); + return FALSE; } /** - * Implementation of task_t.process for EAP exchanges - */ -static status_t process_eap_r(private_ike_auth_t *this, message_t *message) -{ - this->eap_payload = (eap_payload_t*)message->get_payload(message, - EXTENSIBLE_AUTHENTICATION); - return NEED_MORE; -} - -/** - * Implementation of task_t.build for EAP exchanges - */ -static status_t build_eap_i(private_ike_auth_t *this, message_t *message) -{ - message->add_payload(message, (payload_t*)this->eap_payload); - return NEED_MORE; -} - -/** - * Implementation of task_t.build for EAP exchanges + * update the current peer candidate if necessary, using candidates */ -static status_t build_eap_r(private_ike_auth_t *this, message_t *message) +static bool update_cfg_candidates(private_ike_auth_t *this, bool strict) { - status_t status = NEED_MORE; - eap_payload_t *eap; - - if (this->eap_payload == NULL) - { - DBG1(DBG_IKE, "EAP payload missing"); - return FAILED; - } - - switch (this->eap_auth->process(this->eap_auth, this->eap_payload, &eap)) + do { - case NEED_MORE: + if (this->peer_cfg) + { + bool complies = TRUE; + enumerator_t *e1, *e2, *tmp; + auth_cfg_t *c1, *c2; - break; - case SUCCESS: - /* EAP exchange completed, now create and process AUTH */ - this->public.task.build = (status_t(*)(task_t*,message_t*))build_auth_eap; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap; - break; - default: - DBG0(DBG_IKE, "authentication of '%D' with %N failed", - this->ike_sa->get_other_id(this->ike_sa), - auth_class_names, AUTH_CLASS_EAP); - status = FAILED; - break; + e1 = this->other_cfgs->create_enumerator(this->other_cfgs); + e2 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, FALSE); + + if (strict) + { /* swap lists in strict mode: all configured rounds must be + * fulfilled. If !strict, we check only the rounds done so far. */ + tmp = e1; + e1 = e2; + e2 = tmp; + } + while (e1->enumerate(e1, &c1)) + { + /* check if done authentications comply to configured ones */ + if ((!e2->enumerate(e2, &c2)) || + (!strict && !c1->complies(c1, c2, TRUE)) || + (strict && !c2->complies(c2, c1, TRUE))) + { + complies = FALSE; + break; + } + } + e1->destroy(e1); + e2->destroy(e2); + if (complies) + { + break; + } + DBG1(DBG_CFG, "selected peer config '%s' inacceptable", + this->peer_cfg->get_name(this->peer_cfg)); + this->peer_cfg->destroy(this->peer_cfg); + } + if (this->candidates->remove_first(this->candidates, + (void**)&this->peer_cfg) != SUCCESS) + { + DBG1(DBG_CFG, "no alternative config found"); + this->peer_cfg = NULL; + } + else + { + DBG1(DBG_CFG, "switching to peer config '%s'", + this->peer_cfg->get_name(this->peer_cfg)); + this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); + } } - message->add_payload(message, (payload_t*)eap); - return status; + while (this->peer_cfg); + + return this->peer_cfg != NULL; } /** @@ -507,31 +353,103 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) */ static status_t build_i(private_ike_auth_t *this, message_t *message) { - peer_cfg_t *config; - + auth_cfg_t *cfg; + if (message->get_exchange_type(message) == IKE_SA_INIT) { return collect_my_init_data(this, message); } - - if (build_id(this, message) != SUCCESS) + + if (this->peer_cfg == NULL) { - return FAILED; + this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->peer_cfg->get_ref(this->peer_cfg); } - config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (get_auth_class(config) == AUTH_CLASS_EAP) - { - this->eap_auth = eap_authenticator_create(this->ike_sa); + if (message->get_message_id(message) == 1 && + this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH)) + { /* in the first IKE_AUTH, indicate support for multiple authentication */ + message->add_notify(message, FALSE, MULTIPLE_AUTH_SUPPORTED, chunk_empty); } - else + + if (!this->do_another_auth && !this->my_auth) + { /* we have done our rounds */ + return NEED_MORE; + } + + /* check if an authenticator is in progress */ + if (this->my_auth == NULL) { - if (build_auth(this, message) != SUCCESS) + identification_t *id; + id_payload_t *id_payload; + + /* clean up authentication config from a previous round */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->purge(cfg, TRUE); + + /* add (optional) IDr */ + cfg = get_auth_cfg(this, FALSE); + if (cfg) + { + id = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (id && !id->contains_wildcards(id)) + { + this->ike_sa->set_other_id(this->ike_sa, id->clone(id)); + id_payload = id_payload_create_from_identification( + ID_RESPONDER, id); + message->add_payload(message, (payload_t*)id_payload); + } + } + /* add IDi */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); + id = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (!id) + { + DBG1(DBG_CFG, "configuration misses IDi"); + return FAILED; + } + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + id_payload = id_payload_create_from_identification(ID_INITIATOR, id); + message->add_payload(message, (payload_t*)id_payload); + + /* build authentication data */ + this->my_auth = authenticator_create_builder( + this->ike_sa, cfg, this->other_nonce, + this->my_packet->get_data(this->my_packet)); + if (!this->my_auth) { return FAILED; } } - + switch (this->my_auth->build(this->my_auth, message)) + { + case SUCCESS: + /* authentication step complete, reset authenticator */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), TRUE); + this->my_cfgs->insert_last(this->my_cfgs, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + break; + case NEED_MORE: + break; + default: + return FAILED; + } + + /* check for additional authentication rounds */ + if (do_another_auth(this)) + { + if (message->get_payload(message, AUTHENTICATION)) + { + message->add_notify(message, FALSE, ANOTHER_AUTH_FOLLOWS, chunk_empty); + } + } + else + { + this->do_another_auth = FALSE; + } return NEED_MORE; } @@ -540,45 +458,135 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) */ static status_t process_r(private_ike_auth_t *this, message_t *message) { - peer_cfg_t *config; + auth_cfg_t *cfg, *cand; + id_payload_t *id_payload; + identification_t *id; if (message->get_exchange_type(message) == IKE_SA_INIT) { return collect_other_init_data(this, message); } - if (process_id(this, message) != SUCCESS) + if (this->my_auth == NULL && this->do_another_auth) + { + /* handle (optional) IDr payload, apply proposed identity */ + id_payload = (id_payload_t*)message->get_payload(message, ID_RESPONDER); + if (id_payload) + { + id = id_payload->get_identification(id_payload); + } + else + { + id = identification_create_from_encoding(ID_ANY, chunk_empty); + } + this->ike_sa->set_my_id(this->ike_sa, id); + } + + if (!this->expect_another_auth) { return NEED_MORE; } + if (message->get_notify(message, MULTIPLE_AUTH_SUPPORTED)) + { + this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); + } - switch (process_auth(this, message)) + if (this->other_auth == NULL) + { + /* handle IDi payload */ + id_payload = (id_payload_t*)message->get_payload(message, ID_INITIATOR); + if (!id_payload) + { + DBG1(DBG_IKE, "IDi payload missing"); + return FAILED; + } + id = id_payload->get_identification(id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id)); + + if (this->peer_cfg == NULL) + { + if (!load_cfg_candidates(this)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + } + if (message->get_payload(message, AUTHENTICATION) == NULL) + { /* before authenticating with EAP, we need a EAP config */ + cand = get_auth_cfg(this, FALSE); + while (!cand || ( + (uintptr_t)cand->get(cand, AUTH_RULE_EAP_TYPE) == EAP_NAK && + (uintptr_t)cand->get(cand, AUTH_RULE_EAP_VENDOR) == 0)) + { /* peer requested EAP, but current config does not match */ + this->peer_cfg->destroy(this->peer_cfg); + this->peer_cfg = NULL; + if (!update_cfg_candidates(this, FALSE)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + cand = get_auth_cfg(this, FALSE); + } + cfg->merge(cfg, cand, TRUE); + } + + /* verify authentication data */ + this->other_auth = authenticator_create_verifier( + this->ike_sa, message, this->my_nonce, + this->other_packet->get_data(this->other_packet)); + if (!this->other_auth) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + } + switch (this->other_auth->process(this->other_auth, message)) { case SUCCESS: - this->peer_authenticated = TRUE; - break; - case NOT_FOUND: - /* use EAP if no AUTH payload found */ - this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, TRUE); + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; break; + case NEED_MORE: + if (message->get_payload(message, AUTHENTICATION)) + { /* AUTH verification successful, but another build() needed */ + break; + } + return NEED_MORE; default: + this->authentication_failed = TRUE; return NEED_MORE; } - - config = charon->backends->get_peer_cfg(charon->backends, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_auth(this->ike_sa)); - if (config) + + /* store authentication information */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); + this->other_cfgs->insert_last(this->other_cfgs, cfg); + + /* another auth round done, invoke authorize hook */ + if (!charon->bus->authorize(charon->bus, this->other_cfgs, FALSE)) + { + DBG1(DBG_IKE, "round %d authorization hook forbids IKE_SA, cancelling", + this->other_cfgs->get_count(this->other_cfgs)); + this->authentication_failed = TRUE; + return NEED_MORE; + } + + if (!update_cfg_candidates(this, FALSE)) { - this->ike_sa->set_peer_cfg(this->ike_sa, config); - config->destroy(config); + this->authentication_failed = TRUE; + return NEED_MORE; } - if (!this->peer_authenticated) - { - this->eap_auth = eap_authenticator_create(this->ike_sa); + + if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL) + { + this->expect_another_auth = FALSE; + if (!update_cfg_candidates(this, TRUE)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } } return NEED_MORE; } @@ -588,52 +596,139 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) */ static status_t build_r(private_ike_auth_t *this, message_t *message) { - peer_cfg_t *config; - eap_type_t eap_type; - u_int32_t eap_vendor; - eap_payload_t *eap_payload; - status_t status; - + auth_cfg_t *cfg; + if (message->get_exchange_type(message) == IKE_SA_INIT) { + if (multiple_auth_enabled()) + { + message->add_notify(message, FALSE, MULTIPLE_AUTH_SUPPORTED, + chunk_empty); + } return collect_my_init_data(this, message); } - if (!this->peer_authenticated && this->eap_auth == NULL) + if (this->authentication_failed || this->peer_cfg == NULL) { - /* peer not authenticated, nor does it want to use EAP */ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); return FAILED; } - config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (config == NULL) + if (this->my_auth == NULL && this->do_another_auth) { - DBG1(DBG_IKE, "no matching config found for '%D'...'%D'", - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; + identification_t *id, *id_cfg; + id_payload_t *id_payload; + + /* add IDr */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->purge(cfg, TRUE); + cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); + + id_cfg = cfg->get(cfg, AUTH_RULE_IDENTITY); + id = this->ike_sa->get_my_id(this->ike_sa); + if (id->get_type(id) == ID_ANY) + { /* no IDr received, apply configured ID */ + if (!id_cfg || id_cfg->contains_wildcards(id_cfg)) + { + DBG1(DBG_CFG, "IDr not configured and negotiation failed"); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + this->ike_sa->set_my_id(this->ike_sa, id_cfg->clone(id_cfg)); + id = id_cfg; + } + else + { /* IDr received, check if it matches configuration */ + if (id_cfg && !id->matches(id, id_cfg)) + { + DBG1(DBG_CFG, "received IDr %D, but require %D", id, id_cfg); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + } + + id_payload = id_payload_create_from_identification(ID_RESPONDER, id); + message->add_payload(message, (payload_t*)id_payload); + + /* build authentication data */ + this->my_auth = authenticator_create_builder( + this->ike_sa, cfg, this->other_nonce, + this->my_packet->get_data(this->my_packet)); + if (!this->my_auth) + { + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); + return FAILED; + } } - if (build_id(this, message) != SUCCESS || - build_auth(this, message) != SUCCESS) + if (this->other_auth) { - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; + switch (this->other_auth->build(this->other_auth, message)) + { + case SUCCESS: + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; + break; + case NEED_MORE: + break; + default: + if (!message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) + { /* skip AUTHENTICATION_FAILED if we have EAP_FAILURE */ + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + } + return FAILED; + } } - - if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, - this->ike_sa)) + if (this->my_auth) { - DBG1(DBG_IKE, "cancelling IKE_SA setup due uniqueness policy"); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; + switch (this->my_auth->build(this->my_auth, message)) + { + case SUCCESS: + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), + TRUE); + this->my_cfgs->insert_last(this->my_cfgs, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + break; + case NEED_MORE: + break; + default: + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } } - /* use "traditional" authentication if we could authenticate peer */ - if (this->peer_authenticated) + /* check for additional authentication rounds */ + if (do_another_auth(this)) + { + message->add_notify(message, FALSE, ANOTHER_AUTH_FOLLOWS, chunk_empty); + } + else + { + this->do_another_auth = FALSE; + } + if (!this->do_another_auth && !this->expect_another_auth) { + if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, + this->ike_sa)) + { + DBG1(DBG_IKE, "cancelling IKE_SA setup due uniqueness policy"); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + if (!charon->bus->authorize(charon->bus, this->other_cfgs, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", this->ike_sa->get_name(this->ike_sa), @@ -644,21 +739,6 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) this->ike_sa->get_other_id(this->ike_sa)); return SUCCESS; } - - /* initiate EAP authenitcation */ - eap_type = get_eap_type(config, &eap_vendor); - status = this->eap_auth->initiate(this->eap_auth, eap_type, - eap_vendor, &eap_payload); - message->add_payload(message, (payload_t*)eap_payload); - if (status != NEED_MORE) - { - DBG1(DBG_IKE, "unable to initiate EAP authentication"); - return FAILED; - } - - /* switch to EAP methods */ - this->public.task.build = (status_t(*)(task_t*,message_t*))build_eap_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_eap_r; return NEED_MORE; } @@ -667,18 +747,22 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) */ static status_t process_i(private_ike_auth_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - peer_cfg_t *config; - auth_info_t *auth; + auth_cfg_t *cfg; if (message->get_exchange_type(message) == IKE_SA_INIT) { + if (message->get_notify(message, MULTIPLE_AUTH_SUPPORTED) && + multiple_auth_enabled()) + { + this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); + } return collect_other_init_data(this, message); } - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == NOTIFY) { @@ -714,7 +798,7 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) { DBG1(DBG_IKE, "received %N notify error", notify_type_names, type); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return FAILED; } DBG2(DBG_IKE, "received %N notify", @@ -724,39 +808,115 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); - if (process_id(this, message) != SUCCESS || - process_auth(this, message) != SUCCESS) + if (this->my_auth) { - return FAILED; + switch (this->my_auth->process(this->my_auth, message)) + { + case SUCCESS: + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), + TRUE); + this->my_cfgs->insert_last(this->my_cfgs, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + this->do_another_auth = do_another_auth(this); + break; + case NEED_MORE: + break; + default: + return FAILED; + } } - if (this->eap_auth) + if (this->expect_another_auth) { - /* switch to EAP authentication methods */ - this->public.task.build = (status_t(*)(task_t*,message_t*))build_eap_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_eap_i; - return process_eap_i(this, message); + if (this->other_auth == NULL) + { + id_payload_t *id_payload; + identification_t *id; + + /* responder is not allowed to do EAP */ + if (!message->get_payload(message, AUTHENTICATION)) + { + DBG1(DBG_IKE, "AUTH payload missing"); + return FAILED; + } + + /* handle IDr payload */ + id_payload = (id_payload_t*)message->get_payload(message, + ID_RESPONDER); + if (!id_payload) + { + DBG1(DBG_IKE, "IDr payload missing"); + return FAILED; + } + id = id_payload->get_identification(id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id)); + + /* verify authentication data */ + this->other_auth = authenticator_create_verifier( + this->ike_sa, message, this->my_nonce, + this->other_packet->get_data(this->other_packet)); + if (!this->other_auth) + { + return FAILED; + } + } + switch (this->other_auth->process(this->other_auth, message)) + { + case SUCCESS: + break; + case NEED_MORE: + return NEED_MORE; + default: + return FAILED; + } + /* store authentication information, reset authenticator */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); + this->other_cfgs->insert_last(this->other_cfgs, cfg); + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; + + /* another auth round done, invoke authorize hook */ + if (!charon->bus->authorize(charon->bus, this->other_cfgs, FALSE)) + { + DBG1(DBG_IKE, "round %d authorization forbids IKE_SA, cancelling", + this->other_cfgs->get_count(this->other_cfgs)); + return FAILED; + } } - config = this->ike_sa->get_peer_cfg(this->ike_sa); - auth = this->ike_sa->get_other_auth(this->ike_sa); - if (!auth->complies(auth, config->get_auth(config))) + if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL) { - DBG0(DBG_IKE, "authorization of '%D' for config %s failed", - this->ike_sa->get_other_id(this->ike_sa), config->get_name(config)); - return FAILED; + this->expect_another_auth = FALSE; } - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - return SUCCESS; + if (!this->expect_another_auth && !this->do_another_auth && !this->my_auth) + { + if (!update_cfg_candidates(this, TRUE)) + { + return FAILED; + } + if (!charon->bus->authorize(charon->bus, this->other_cfgs, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + return FAILED; + } + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + return SUCCESS; + } + return NEED_MORE; } /** @@ -776,28 +936,25 @@ static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa) chunk_free(&this->other_nonce); DESTROY_IF(this->my_packet); DESTROY_IF(this->other_packet); - if (this->eap_auth) - { - this->eap_auth->authenticator_interface.destroy( - &this->eap_auth->authenticator_interface); - } + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->my_auth); + DESTROY_IF(this->other_auth); + this->my_cfgs->destroy_offset(this->my_cfgs, offsetof(auth_cfg_t, destroy)); + this->other_cfgs->destroy_offset(this->other_cfgs, offsetof(auth_cfg_t, destroy)); + this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); this->my_packet = NULL; this->other_packet = NULL; - this->peer_authenticated = FALSE; - this->eap_auth = NULL; - this->eap_payload = NULL; this->ike_sa = ike_sa; - if (this->initiator) - { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; - } - else - { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; - } + this->peer_cfg = NULL; + this->my_auth = NULL; + this->other_auth = NULL; + this->do_another_auth = TRUE; + this->expect_another_auth = TRUE; + this->authentication_failed = FALSE; + this->my_cfgs = linked_list_create(); + this->other_cfgs = linked_list_create(); + this->candidates = linked_list_create(); } /** @@ -809,11 +966,12 @@ static void destroy(private_ike_auth_t *this) chunk_free(&this->other_nonce); DESTROY_IF(this->my_packet); DESTROY_IF(this->other_packet); - if (this->eap_auth) - { - this->eap_auth->authenticator_interface.destroy( - &this->eap_auth->authenticator_interface); - } + DESTROY_IF(this->my_auth); + DESTROY_IF(this->other_auth); + DESTROY_IF(this->peer_cfg); + this->my_cfgs->destroy_offset(this->my_cfgs, offsetof(auth_cfg_t, destroy)); + this->other_cfgs->destroy_offset(this->other_cfgs, offsetof(auth_cfg_t, destroy)); + this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); free(this); } @@ -823,7 +981,7 @@ static void destroy(private_ike_auth_t *this) ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator) { private_ike_auth_t *this = malloc_thing(private_ike_auth_t); - + this->public.task.get_type = (task_type_t(*)(task_t*))get_type; this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; this->public.task.destroy = (void(*)(task_t*))destroy; @@ -845,9 +1003,16 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator) this->other_nonce = chunk_empty; this->my_packet = NULL; this->other_packet = NULL; - this->peer_authenticated = FALSE; - this->eap_auth = NULL; - this->eap_payload = NULL; + this->peer_cfg = NULL; + this->my_cfgs = linked_list_create(); + this->other_cfgs = linked_list_create(); + this->candidates = linked_list_create(); + this->my_auth = NULL; + this->other_auth = NULL; + this->do_another_auth = TRUE; + this->expect_another_auth = TRUE; + this->authentication_failed = FALSE; return &this->public; } + diff --git a/src/charon/sa/tasks/ike_auth_lifetime.c b/src/charon/sa/tasks/ike_auth_lifetime.c index 328f11d2c..a175aa53a 100644 --- a/src/charon/sa/tasks/ike_auth_lifetime.c +++ b/src/charon/sa/tasks/ike_auth_lifetime.c @@ -64,12 +64,12 @@ static void add_auth_lifetime(private_ike_auth_lifetime_t *this, message_t *mess */ static void process_payloads(private_ike_auth_lifetime_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; notify_payload_t *notify; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == NOTIFY) { @@ -88,7 +88,7 @@ static void process_payloads(private_ike_auth_lifetime_t *this, message_t *messa } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** diff --git a/src/charon/sa/tasks/ike_cert_post.c b/src/charon/sa/tasks/ike_cert_post.c index 825cf0711..da3ee4dce 100644 --- a/src/charon/sa/tasks/ike_cert_post.c +++ b/src/charon/sa/tasks/ike_cert_post.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006-2008 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -98,70 +98,68 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, certifi } /** - * from ike_auth.c - */ -auth_class_t get_auth_class(peer_cfg_t *config); - -/** * add certificates to message */ static void build_certs(private_ike_cert_post_t *this, message_t *message) { peer_cfg_t *peer_cfg; + auth_cfg_t *auth; peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg && get_auth_class(peer_cfg) == AUTH_CLASS_PUBKEY) + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + if (!peer_cfg || + (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_PUBKEY) + { + return; + } + switch (peer_cfg->get_cert_policy(peer_cfg)) { - switch (peer_cfg->get_cert_policy(peer_cfg)) + case CERT_NEVER_SEND: + break; + case CERT_SEND_IF_ASKED: + if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) + { + break; + } + /* FALL */ + case CERT_ALWAYS_SEND: { - case CERT_NEVER_SEND: + cert_payload_t *payload; + enumerator_t *enumerator; + certificate_t *cert; + auth_rule_t type; + + /* get subject cert first, then issuing certificates */ + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (!cert) + { break; - case CERT_SEND_IF_ASKED: - if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) - { - break; - } - /* FALL */ - case CERT_ALWAYS_SEND: + } + payload = build_cert_payload(this, cert); + if (!payload) { - cert_payload_t *payload; - enumerator_t *enumerator; - certificate_t *cert; - auth_info_t *auth; - auth_item_t item; - - auth = this->ike_sa->get_my_auth(this->ike_sa); - /* get subject cert first, then issuing certificates */ - if (!auth->get_item(auth, AUTHZ_SUBJECT_CERT, (void**)&cert)) - { - break; - } - payload = build_cert_payload(this, cert); - if (!payload) - { - break; - } - DBG1(DBG_IKE, "sending end entity cert \"%D\"", - cert->get_subject(cert)); - message->add_payload(message, (payload_t*)payload); - - enumerator = auth->create_item_enumerator(auth); - while (enumerator->enumerate(enumerator, &item, &cert)) + break; + } + DBG1(DBG_IKE, "sending end entity cert \"%D\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &cert)) + { + if (type == AUTH_RULE_IM_CERT) { - if (item == AUTHZ_IM_CERT) + payload = cert_payload_create_from_cert(cert); + if (payload) { - payload = cert_payload_create_from_cert(cert); - if (payload) - { - DBG1(DBG_IKE, "sending issuer cert \"%D\"", - cert->get_subject(cert)); - message->add_payload(message, (payload_t*)payload); - } + DBG1(DBG_IKE, "sending issuer cert \"%D\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); } } - enumerator->destroy(enumerator); - } - } + } + enumerator->destroy(enumerator); + } } } @@ -170,12 +168,11 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) */ static status_t build_i(private_ike_cert_post_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return NEED_MORE; + if (message->get_payload(message, AUTHENTICATION)) + { /* CERT payloads are sended along AUTH payloads */ + build_certs(this, message); } - build_certs(this, message); - return SUCCESS; + return NEED_MORE; } /** @@ -191,11 +188,14 @@ static status_t process_r(private_ike_cert_post_t *this, message_t *message) */ static status_t build_r(private_ike_cert_post_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { + if (message->get_payload(message, AUTHENTICATION)) + { /* CERT payloads are sended along AUTH payloads */ + build_certs(this, message); + } + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* stay alive, we might have additional rounds with certs */ return NEED_MORE; } - build_certs(this, message); return SUCCESS; } @@ -204,8 +204,8 @@ static status_t build_r(private_ike_cert_post_t *this, message_t *message) */ static status_t process_i(private_ike_cert_post_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* stay alive, we might have additional rounds with CERTS */ return NEED_MORE; } return SUCCESS; diff --git a/src/charon/sa/tasks/ike_cert_pre.c b/src/charon/sa/tasks/ike_cert_pre.c index 79bc4f6e0..0ec7004c2 100644 --- a/src/charon/sa/tasks/ike_cert_pre.c +++ b/src/charon/sa/tasks/ike_cert_pre.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006-2007 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -48,9 +48,9 @@ struct private_ike_cert_pre_t { bool initiator; /** - * Did we send a HTTP_CERT_LOOKUP_SUPPORTED Notify? + * Do we accept HTTP certificate lookup requests */ - bool http_cert_lookup_supported_sent; + bool do_http_lookup; }; /** @@ -58,23 +58,22 @@ struct private_ike_cert_pre_t { */ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - auth_info_t *auth; - bool ca_found = FALSE; + auth_cfg_t *auth; - auth = this->ike_sa->get_my_auth(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { switch(payload->get_type(payload)) { case CERTIFICATE_REQUEST: { certreq_payload_t *certreq = (certreq_payload_t*)payload; - chunk_t keyid; enumerator_t *enumerator; + chunk_t keyid; this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE); @@ -98,15 +97,12 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) { DBG1(DBG_IKE, "received cert request for \"%D\"", cert->get_subject(cert)); - auth->add_item(auth, AUTHN_CA_CERT, cert); - cert->destroy(cert); - ca_found = TRUE; + auth->add(auth, AUTH_RULE_CA_CERT, cert); } else { DBG1(DBG_IKE, "received cert request for unknown ca " "with keyid %D", id); - auth->add_item(auth, AUTHN_CA_CERT_KEYID, id); } id->destroy(id); } @@ -129,7 +125,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -140,6 +136,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) static certificate_t *try_get_cert(cert_payload_t *cert_payload) { certificate_t *cert = NULL; + switch (cert_payload->get_cert_encoding(cert_payload)) { case ENC_X509_SIGNATURE: @@ -158,7 +155,7 @@ static certificate_t *try_get_cert(cert_payload_t *cert_payload) } id = identification_create_from_encoding(ID_CERT_DER_SHA1, hash); cert = charon->credentials->get_cert(charon->credentials, - CERT_X509, KEY_ANY, id, FALSE); + CERT_X509, KEY_ANY, id, FALSE); id->destroy(id); break; } @@ -175,78 +172,81 @@ static certificate_t *try_get_cert(cert_payload_t *cert_payload) */ static void process_certs(private_ike_cert_pre_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - auth_info_t *auth; + auth_cfg_t *auth; bool first = TRUE; - auth = this->ike_sa->get_other_auth(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == CERTIFICATE) { - cert_payload_t *cert_payload = (cert_payload_t*)payload; - cert_encoding_t type = cert_payload->get_cert_encoding(cert_payload); - switch (type) + cert_payload_t *cert_payload; + cert_encoding_t encoding; + certificate_t *cert; + char *url; + + cert_payload = (cert_payload_t*)payload; + encoding = cert_payload->get_cert_encoding(cert_payload); + + switch (encoding) { - case ENC_X509_SIGNATURE: case ENC_X509_HASH_AND_URL: { - if (type == ENC_X509_HASH_AND_URL && - !this->http_cert_lookup_supported_sent) + if (!this->do_http_lookup) { DBG1(DBG_IKE, "received hash-and-url encoded cert, but" " we don't accept them, ignore"); break; } - - certificate_t *cert = try_get_cert(cert_payload); - + /* FALL */ + } + case ENC_X509_SIGNATURE: + { + cert = try_get_cert(cert_payload); if (cert) { - /* we've got a certificate from the payload or the cache */ if (first) - { /* the first certificate MUST be an end entity one */ + { /* the first is an end entity certificate */ DBG1(DBG_IKE, "received end entity cert \"%D\"", cert->get_subject(cert)); - auth->add_item(auth, AUTHN_SUBJECT_CERT, cert); + auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert); first = FALSE; } else { DBG1(DBG_IKE, "received issuer cert \"%D\"", cert->get_subject(cert)); - auth->add_item(auth, AUTHN_IM_CERT, cert); + auth->add(auth, AUTH_HELPER_IM_CERT, cert); } - cert->destroy(cert); } - else if (type == ENC_X509_HASH_AND_URL) + else if (encoding == ENC_X509_HASH_AND_URL) { - /* we received a "Hash and URL" encoded certificate that - * we haven't fetched yet, we store the URL and fetch - * it later */ - char *url = cert_payload->get_url(cert_payload); + /* we fetch the certificate not yet, but only if + * it is really needed during authentication */ + url = cert_payload->get_url(cert_payload); if (!url) { - DBG1(DBG_IKE, "received invalid hash-and-url encoded" - " cert, ignore"); + DBG1(DBG_IKE, "received invalid hash-and-url " + "encoded cert, ignore"); break; } - + url = strdup(url); if (first) - { /* the first certificate MUST be an end entity one */ + { /* first URL is for an end entity certificate */ DBG1(DBG_IKE, "received hash-and-url for end" - " entity cert \"%s\"", url); - auth->add_item(auth, AUTHN_SUBJECT_HASH_URL, url); + " entity cert \"%s\"", url); + auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url); first = FALSE; } else { DBG1(DBG_IKE, "received hash-and-url for issuer" " cert \"%s\"", url); - auth->add_item(auth, AUTHN_IM_HASH_URL, url); + auth->add(auth, AUTH_HELPER_IM_HASH_URL, url); } } break; @@ -264,31 +264,23 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) case ENC_OCSP_CONTENT: default: DBG1(DBG_ENC, "certificate encoding %N not supported", - cert_encoding_names, cert_payload->get_cert_encoding(cert_payload)); + cert_encoding_names, encoding); } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** - * add a certificate request to the message, building request payload if required. + * add the keyid of a certificate to the certificate request payload */ -static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, - certificate_t *cert) +static void add_certreq(certreq_payload_t **req, certificate_t *cert) { - public_key_t *public; - certreq_payload_t *req; - - public = cert->get_public_key(cert); - if (!public) - { - return; - } switch (cert->get_type(cert)) { case CERT_X509: { + public_key_t *public; identification_t *keyid; x509_t *x509 = (x509_t*)cert; @@ -296,14 +288,18 @@ static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, { /* no CA cert, skip */ break; } - if (*reqp == NULL) + public = cert->get_public_key(cert); + if (!public) + { + break; + } + if (*req == NULL) { - *reqp = certreq_payload_create_type(CERT_X509); - message->add_payload(message, (payload_t*)*reqp); + *req = certreq_payload_create_type(CERT_X509); } - req = *reqp; keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); - req->add_keyid(req, keyid->get_encoding(keyid)); + (*req)->add_keyid(*req, keyid->get_encoding(keyid)); + public->destroy(public); DBG1(DBG_IKE, "sending cert request for \"%D\"", cert->get_subject(cert)); break; @@ -311,7 +307,30 @@ static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, default: break; } - public->destroy(public); +} + +/** + * add a auth_cfg's CA certificates to the certificate request + */ +static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth) +{ + enumerator_t *enumerator; + auth_rule_t type; + void *value; + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &value)) + { + switch (type) + { + case AUTH_RULE_CA_CERT: + add_certreq(req, (certificate_t*)value); + break; + default: + break; + } + } + enumerator->destroy(enumerator); } /** @@ -319,75 +338,53 @@ static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, */ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) { + enumerator_t *enumerator; ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; - enumerator_t *enumerator; certificate_t *cert; - bool restricted = FALSE; - certreq_payload_t *x509_req = NULL; + auth_cfg_t *auth; + certreq_payload_t *req = NULL; ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); if (!ike_cfg->send_certreq(ike_cfg)) { return; } - + /* check if we require a specific CA for that peer */ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); if (peer_cfg) { - void *ptr; - identification_t *id; - auth_item_t item; - auth_info_t *auth = peer_cfg->get_auth(peer_cfg); - enumerator_t *auth_enumerator = auth->create_item_enumerator(auth); - - while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr)) + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); + while (enumerator->enumerate(enumerator, &auth)) { - switch (item) - { - case AUTHZ_CA_CERT: - cert = (certificate_t *)ptr; - add_certreq_payload(message, &x509_req, cert); - restricted = TRUE; - break; - case AUTHZ_CA_CERT_NAME: - id = (identification_t *)ptr; - enumerator = charon->credentials->create_cert_enumerator( - charon->credentials, CERT_ANY, KEY_ANY, id, TRUE); - while (enumerator->enumerate(enumerator, &cert, TRUE)) - { - add_certreq_payload(message, &x509_req, cert); - restricted = TRUE; - } - enumerator->destroy(enumerator); - break; - default: - break; - } + add_certreqs(&req, auth); } - auth_enumerator->destroy(auth_enumerator); + enumerator->destroy(enumerator); } - - if (!restricted) + + if (!req) { - /* otherwise include all trusted CA certificates */ + /* otherwise add all trusted CA certificates */ enumerator = charon->credentials->create_cert_enumerator( charon->credentials, CERT_ANY, KEY_ANY, NULL, TRUE); - while (enumerator->enumerate(enumerator, &cert, TRUE)) + while (enumerator->enumerate(enumerator, &cert)) { - add_certreq_payload(message, &x509_req, cert); + add_certreq(&req, cert); } enumerator->destroy(enumerator); } - /* if we've added at least one certreq, we notify our peer that we support - * "Hash and URL" for the requested certificates */ - if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE) && - message->get_payload(message, CERTIFICATE_REQUEST)) + if (req) { - message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED, chunk_empty); - this->http_cert_lookup_supported_sent = TRUE; + message->add_payload(message, (payload_t*)req); + + if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE)) + { + message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED, + chunk_empty); + this->do_http_lookup = TRUE; + } } } @@ -396,11 +393,10 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) */ static status_t build_i(private_ike_cert_pre_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return NEED_MORE; + if (message->get_message_id(message) == 1) + { /* initiator sends CERTREQs in first IKE_AUTH */ + build_certreqs(this, message); } - build_certreqs(this, message); return NEED_MORE; } @@ -408,13 +404,12 @@ static status_t build_i(private_ike_cert_pre_t *this, message_t *message) * Implementation of task_t.process for responder */ static status_t process_r(private_ike_cert_pre_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return NEED_MORE; +{ + if (message->get_exchange_type(message) != IKE_SA_INIT) + { /* handle certreqs/certs in any IKE_AUTH, just in case */ + process_certreqs(this, message); + process_certs(this, message); } - process_certreqs(this, message); - process_certs(this, message); return NEED_MORE; } @@ -426,9 +421,12 @@ static status_t build_r(private_ike_cert_pre_t *this, message_t *message) if (message->get_exchange_type(message) == IKE_SA_INIT) { build_certreqs(this, message); - return NEED_MORE; } - return SUCCESS; + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + return SUCCESS; + } + return NEED_MORE; } /** @@ -439,10 +437,38 @@ static status_t process_i(private_ike_cert_pre_t *this, message_t *message) if (message->get_exchange_type(message) == IKE_SA_INIT) { process_certreqs(this, message); - return NEED_MORE; } process_certs(this, message); - return SUCCESS; + + /* as ike_auth is not processed yet, we don't know if authentication + * is complete (and we can return SUCCESS). Therefore we check for + * an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify. */ + if (message->get_payload(message, AUTHENTICATION)) + { + enumerator_t *enumerator; + payload_t *payload; + notify_payload_t *notify; + bool done = TRUE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify = (notify_payload_t*)payload; + if (notify->get_notify_type(notify) == ANOTHER_AUTH_FOLLOWS) + { + done = FALSE; + } + } + } + enumerator->destroy(enumerator); + if (done) + { + return SUCCESS; + } + } + return NEED_MORE; } /** @@ -493,7 +519,7 @@ ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator) this->ike_sa = ike_sa; this->initiator = initiator; - this->http_cert_lookup_supported_sent = FALSE; + this->do_http_lookup = FALSE; return &this->public; } diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c index 04c9e57b8..cb769f9b4 100644 --- a/src/charon/sa/tasks/ike_config.c +++ b/src/charon/sa/tasks/ike_config.c @@ -260,11 +260,12 @@ static void process_attribute(private_ike_config_t *this, */ static void process_payloads(private_ike_config_t *this, message_t *message) { - iterator_t *iterator, *attributes; + enumerator_t *enumerator; + iterator_t *attributes; payload_t *payload; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == CONFIGURATION) { @@ -290,7 +291,7 @@ static void process_payloads(private_ike_config_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -298,9 +299,8 @@ static void process_payloads(private_ike_config_t *this, message_t *message) */ static status_t build_i(private_ike_config_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, ID_INITIATOR)) - { + if (message->get_message_id(message) == 1) + { /* in first IKE_AUTH only */ peer_cfg_t *config; host_t *vip; @@ -327,9 +327,8 @@ static status_t build_i(private_ike_config_t *this, message_t *message) */ static status_t process_r(private_ike_config_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, ID_INITIATOR)) - { + if (message->get_message_id(message) == 1) + { /* in first IKE_AUTH only */ process_payloads(this, message); } return NEED_MORE; @@ -340,9 +339,8 @@ static status_t process_r(private_ike_config_t *this, message_t *message) */ static status_t build_r(private_ike_config_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, EXTENSIBLE_AUTHENTICATION) == NULL) - { + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { /* in last IKE_AUTH exchange */ peer_cfg_t *config = this->ike_sa->get_peer_cfg(this->ike_sa); if (config && this->virtual_ip) @@ -355,7 +353,6 @@ static status_t build_r(private_ike_config_t *this, message_t *message) ip = charon->attributes->acquire_address(charon->attributes, config->get_pool(config), this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_auth(this->ike_sa), this->virtual_ip); } if (ip == NULL) @@ -384,9 +381,8 @@ static status_t build_r(private_ike_config_t *this, message_t *message) */ static status_t process_i(private_ike_config_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - !message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) - { + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { /* in last IKE_AUTH exchange */ host_t *ip; peer_cfg_t *config; diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c index 4f28909da..2aac7b02e 100644 --- a/src/charon/sa/tasks/ike_init.c +++ b/src/charon/sa/tasks/ike_init.c @@ -170,11 +170,11 @@ static void build_payloads(private_ike_init_t *this, message_t *message) */ static void process_payloads(private_ike_init_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { switch (payload->get_type(payload)) { @@ -182,7 +182,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message) { sa_payload_t *sa_payload = (sa_payload_t*)payload; linked_list_t *proposal_list; - + proposal_list = sa_payload->get_proposals(sa_payload); this->proposal = this->config->select_proposal(this->config, proposal_list); @@ -225,7 +225,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -317,12 +317,12 @@ static status_t process_r(private_ike_init_t *this, message_t *message) #ifdef ME { chunk_t connect_id = chunk_empty; - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - + /* check for a ME_CONNECTID notify */ - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == NOTIFY) { @@ -353,7 +353,7 @@ static status_t process_r(private_ike_init_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (connect_id.ptr) { @@ -458,12 +458,12 @@ static status_t build_r(private_ike_init_t *this, message_t *message) */ static status_t process_i(private_ike_init_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - + /* check for erronous notifies */ - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == NOTIFY) { @@ -489,19 +489,22 @@ static status_t process_i(private_ike_init_t *this, message_t *message) this->ike_sa->reset(this->ike_sa); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return NEED_MORE; } case NAT_DETECTION_SOURCE_IP: case NAT_DETECTION_DESTINATION_IP: /* skip, handled in ike_natd_t */ break; + case MULTIPLE_AUTH_SUPPORTED: + /* handled in ike_auth_t */ + break; case COOKIE: { chunk_free(&this->cookie); this->cookie = chunk_clone(notify->get_notification_data(notify)); this->ike_sa->reset(this->ike_sa); - iterator->destroy(iterator); + enumerator->destroy(enumerator); DBG2(DBG_IKE, "received %N notify", notify_type_names, type); return NEED_MORE; } @@ -511,7 +514,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) { DBG1(DBG_IKE, "received %N notify error", notify_type_names, type); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return FAILED; } DBG2(DBG_IKE, "received %N notify", @@ -521,7 +524,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); process_payloads(this, message); diff --git a/src/charon/sa/tasks/ike_me.c b/src/charon/sa/tasks/ike_me.c index 32c264c43..07dfb20a5 100644 --- a/src/charon/sa/tasks/ike_me.c +++ b/src/charon/sa/tasks/ike_me.c @@ -166,11 +166,11 @@ static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message) */ static void process_payloads(private_ike_me_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) != NOTIFY) { @@ -237,7 +237,7 @@ static void process_payloads(private_ike_me_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index b2ef2731f..29bb61730 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -97,12 +97,12 @@ static void flush_additional_addresses(private_ike_mobike_t *this) */ static void process_payloads(private_ike_mobike_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; bool first = TRUE; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { int family = AF_INET; notify_payload_t *notify; @@ -181,7 +181,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -332,9 +332,8 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) */ static status_t build_i(private_ike_mobike_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, ID_INITIATOR)) - { + if (message->get_message_id(message) == 1) + { /* only in first IKE_AUTH */ message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); build_address_list(this, message); } @@ -381,9 +380,8 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) */ static status_t process_r(private_ike_mobike_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, ID_INITIATOR)) - { + if (message->get_message_id(message) == 1) + { /* only first IKE_AUTH */ process_payloads(this, message); } else if (message->get_exchange_type(message) == INFORMATIONAL) diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index a20af7ce7..f6bb2d43b 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -166,7 +166,7 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this, */ static void process_payloads(private_ike_natd_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; notify_payload_t *notify; chunk_t hash, src_hash, dst_hash; @@ -184,8 +184,8 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash); DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash); - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) != NOTIFY) { @@ -235,7 +235,7 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); chunk_free(&src_hash); chunk_free(&dst_hash); diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index 6dbad5ff6..3c49f329a 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -194,12 +194,12 @@ static status_t build_r(private_ike_rekey_t *this, message_t *message) static status_t process_i(private_ike_rekey_t *this, message_t *message) { ike_sa_id_t *to_delete; - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - + /* handle NO_ADDITIONAL_SAS notify */ - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == NOTIFY) { @@ -213,12 +213,12 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) charon->processor->queue_job(charon->processor, (job_t*)rekey_ike_sa_job_create( this->ike_sa->get_id(this->ike_sa), TRUE)); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return SUCCESS; } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); switch (this->ike_init->task.process(&this->ike_init->task, message)) { |