diff options
Diffstat (limited to 'src/charon/sa')
66 files changed, 2819 insertions, 2561 deletions
diff --git a/src/charon/sa/authenticators/authenticator.c b/src/charon/sa/authenticators/authenticator.c index 827c7a69a..ea8a16279 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 @@ -12,8 +12,6 @@ * 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: authenticator.c 4276 2008-08-22 10:44:51Z martin $ */ #include <string.h> @@ -23,6 +21,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 +34,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 +44,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_nonce, + chunk_t received_init, 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_nonce, received_init, sent_init); default: return NULL; } @@ -63,19 +69,32 @@ 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 received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_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, + received_nonce, sent_nonce, received_init, sent_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 345cc7deb..c60881629 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 * @@ -13,8 +13,6 @@ * 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: authenticator.h 5003 2009-03-24 17:43:01Z martin $ */ /** @@ -30,9 +28,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 +81,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 +99,70 @@ 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_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @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_nonce, + chunk_t received_init, 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 received_nonce nonce received in IKE_SA_INIT + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @param sent_init sent 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 received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_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 c1c2d6fce..b8316036e 100644 --- a/src/charon/sa/authenticators/eap/eap_manager.c +++ b/src/charon/sa/authenticators/eap/eap_manager.c @@ -11,8 +11,6 @@ * 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: eap_manager.c 4579 2008-11-05 11:29:56Z martin $ */ #include "eap_manager.h" @@ -65,9 +63,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 +82,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 +95,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 +106,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 +121,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 +136,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 +146,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 +163,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_manager.h b/src/charon/sa/authenticators/eap/eap_manager.h index db5535a81..667c54a8e 100644 --- a/src/charon/sa/authenticators/eap/eap_manager.h +++ b/src/charon/sa/authenticators/eap/eap_manager.h @@ -11,8 +11,6 @@ * 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: eap_manager.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c index 2e4307eb4..1d1900301 100644 --- a/src/charon/sa/authenticators/eap/eap_method.c +++ b/src/charon/sa/authenticators/eap/eap_method.c @@ -11,8 +11,6 @@ * 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: eap_method.c 4997 2009-03-24 10:24:58Z martin $ */ #include "eap_method.h" @@ -36,6 +34,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 (strcaseeq(name, types[i].name)) + { + return types[i].type; + } + } + return 0; +} + ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE, "EAP_REQUEST", "EAP_RESPONSE", @@ -48,3 +76,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 6f3da1ba7..578b89e96 100644 --- a/src/charon/sa/authenticators/eap/eap_method.h +++ b/src/charon/sa/authenticators/eap/eap_method.h @@ -11,8 +11,6 @@ * 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: eap_method.h 5003 2009-03-24 17:43:01Z martin $ */ /** @@ -69,6 +67,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 +89,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.c b/src/charon/sa/authenticators/eap/sim_manager.c index e6817ca20..51cd4fb3f 100644 --- a/src/charon/sa/authenticators/eap/sim_manager.c +++ b/src/charon/sa/authenticators/eap/sim_manager.c @@ -11,8 +11,6 @@ * 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 "sim_manager.h" 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 7b97fe56c..2abdf7a02 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 @@ -11,17 +11,14 @@ * 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: eap_authenticator.c 5037 2009-03-26 13:58:17Z andreas $ */ -#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 +38,24 @@ struct private_eap_authenticator_t { ike_sa_t *ike_sa; /** - * Role of this authenticator, PEER or SERVER + * others nonce to include in AUTH calculation + */ + chunk_t received_nonce; + + /** + * our nonce to include in AUTH calculation + */ + chunk_t sent_nonce; + + /** + * others IKE_SA_INIT message data to include in AUTH calculation + */ + chunk_t received_init; + + /** + * our IKE_SA_INIT message data to include in AUTH calculation */ - eap_role_t role; + chunk_t sent_init; /** * Current EAP method processing @@ -56,442 +68,514 @@ 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; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - id = this->ike_sa->get_eap_identity(this->ike_sa); - if (!id) + /* 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) + this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER); + if (this->method) { - id = this->ike_sa->get_my_id(this->ike_sa); - } - else - { - 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); + DBG1(DBG_IKE, "initiating %N failed", eap_type_names, type); } - if (id->get_type(id) == ID_EAP) - { - return id->clone(id); - } - return identification_create_from_encoding(ID_EAP, id->get_encoding(id)); -} - -/** - * load an EAP method using the correct identities - */ -static eap_method_t *load_method(private_eap_authenticator_t *this, - eap_type_t type, u_int32_t vendor, eap_role_t role) -{ - identification_t *server, *peer; - eap_method_t *method; - - 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; + return eap_payload_create_code(EAP_FAILURE, 0); } /** - * Implementation of eap_authenticator_t.initiate + * Handle EAP exchange as server */ -static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, - u_int32_t vendor, eap_payload_t **out) +static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, + eap_payload_t *in) { - /* 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; - } + eap_type_t type, received_type; + u_int32_t vendor, received_vendor; + eap_payload_t *out; + auth_cfg_t *cfg; - 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); + } + else + { + DBG1(DBG_IKE, "received invalid EAP response, sending %N", + 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; + 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 '%Y'", + 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 %Y", type, vendor, + this->ike_sa->get_other_id(this->ike_sa)); + } + else + { + DBG1(DBG_IKE, "EAP method %N failed for peer %Y", + 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 '%Y'", + 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 nonce, chunk_t init) { - 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, init, 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 '%Y' 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, + chunk_t nonce, chunk_t init) +{ + 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 '%Y' (myself) with %N", + my_id, auth_class_names, AUTH_CLASS_EAP); + + auth_data = keymat->get_psk_sig(keymat, FALSE, init, 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, this->sent_nonce, this->received_init)) + { + 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, this->received_nonce, this->sent_init); + 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, this->sent_nonce, this->received_init)) { - switch (code) + return FAILED; + } + return SUCCESS; + } + + eap_payload = (eap_payload_t*)message->get_payload(message, + EXTENSIBLE_AUTHENTICATION); + if (eap_payload) + { + switch (eap_payload->get_code(eap_payload)) + { + case EAP_REQUEST: { - case EAP_RESPONSE: + this->eap_payload = client_process_eap(this, eap_payload); + if (this->eap_payload) { - 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 NEED_MORE; } + return FAILED; } - } - case EAP_PEER: - { - switch (code) + 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, this->received_nonce, this->sent_init); + return NEED_MORE; + } + return NEED_MORE; } /** @@ -500,6 +584,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 +593,56 @@ 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_nonce, + chunk_t received_init, 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->received_init = received_init; + this->received_nonce = received_nonce; + this->sent_init = sent_init; + this->sent_nonce = sent_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 received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_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->received_init = received_init; + this->received_nonce = received_nonce; + this->sent_init = sent_init; + this->sent_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 3ee6839fa..b90a6f4df 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 @@ -11,8 +11,6 @@ * 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: eap_authenticator.h 5003 2009-03-24 17:43:01Z martin $ */ /** @@ -26,21 +24,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 +39,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 +64,35 @@ 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_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @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_nonce, + chunk_t received_init, chunk_t sent_init); + +/** + * Create an authenticator to authenticate EAP clients. + * + * @param ike_sa associated ike_sa + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @param sent_init sent 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 received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init); #endif /** EAP_AUTHENTICATOR_H_ @}*/ diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c index ae5a66479..742b67789 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 * @@ -12,17 +12,12 @@ * 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: psk_authenticator.c 4495 2008-10-28 16:07:06Z martin $ */ -#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 +35,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 '%Y' (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 '%Y' - '%Y'", 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,11 +113,11 @@ 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", + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", other_id, auth_method_names, AUTH_PSK); authenticated = TRUE; } @@ -82,49 +129,26 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, { if (keys_found == 0) { - DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id); + DBG1(DBG_IKE, "no shared key found for '%Y' - '%Y'", my_id, other_id); return NOT_FOUND; } - DBG1(DBG_IKE, "tried %d shared key%s for '%D' - '%D', but MAC mismatched", + DBG1(DBG_IKE, "tried %d shared key%s for '%Y' - '%Y', but MAC mismatched", 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 +162,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); - /* 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))build; + this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))return_failed; + this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - /* private data */ 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); + + 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; + + 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 df65076a4..5bb743d93 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 @@ -11,8 +11,6 @@ * 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: psk_authenticator.h 5003 2009-03-24 17:43:01Z martin $ */ /** @@ -28,22 +26,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_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(ike_sa_t *ike_sa); +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 c16f3b888..44cabfb94 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 * @@ -13,17 +13,12 @@ * 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: pubkey_authenticator.c 4495 2008-10-28 16:07:06Z martin $ */ -#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,95 +36,40 @@ 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) { - DBG1(DBG_IKE, "no private key found for '%D'", id); + DBG1(DBG_IKE, "no private key found for '%Y'", id); return NOT_FOUND; } @@ -169,18 +109,18 @@ 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, + DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id, auth_method_names, auth_method, (status == SUCCESS)? "successful":"failed"); chunk_free(&octets); @@ -190,6 +130,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 '%Y' 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 '%Y'", + 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 +227,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 d2189fa97..e67f020ff 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 @@ -12,8 +12,6 @@ * 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: pubkey_authenticator.h 5003 2009-03-24 17:43:01Z martin $ */ /** @@ -29,22 +27,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_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(ike_sa_t *ike_sa); +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/child_sa.c b/src/charon/sa/child_sa.c index 022b9149a..9202e972e 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -14,8 +14,6 @@ * 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: child_sa.c 4677 2008-11-19 15:31:27Z martin $ */ #define _GNU_SOURCE @@ -412,26 +410,11 @@ static u_int32_t get_lifetime(private_child_sa_t *this, bool hard) */ static u_int32_t alloc_spi(private_child_sa_t *this, protocol_id_t protocol) { - switch (protocol) - { - case PROTO_AH: - if (charon->kernel_interface->get_spi(charon->kernel_interface, - this->other_addr, this->my_addr, PROTO_AH, - this->reqid, &this->my_spi) == SUCCESS) - { - return this->my_spi; - } - break; - case PROTO_ESP: - if (charon->kernel_interface->get_spi(charon->kernel_interface, - this->other_addr, this->my_addr, PROTO_ESP, + if (charon->kernel_interface->get_spi(charon->kernel_interface, + this->other_addr, this->my_addr, protocol, this->reqid, &this->my_spi) == SUCCESS) - { - return this->my_spi; - } - break; - default: - break; + { + return this->my_spi; } return 0; } @@ -504,8 +487,14 @@ static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ, this->mode, this->ipcomp, cpi, this->encap, update); now = time(NULL); - this->rekey_time = now + soft; - this->expire_time = now + hard; + if (soft) + { + this->rekey_time = now + soft; + } + if (hard) + { + this->expire_time = now + hard; + } return status; } @@ -724,14 +713,14 @@ static void destroy(private_child_sa_t *this) if (this->my_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->my_addr, this->my_spi, this->protocol, - this->my_cpi); + this->other_addr, this->my_addr, this->my_spi, + this->protocol, this->my_cpi); } if (this->other_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->other_addr, this->other_spi, this->protocol, - this->other_cpi); + this->my_addr, this->other_addr, this->other_spi, + this->protocol, this->other_cpi); } if (this->config->install_policy(this->config)) @@ -816,6 +805,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->protocol = PROTO_NONE; this->mode = MODE_TUNNEL; this->proposal = NULL; + this->rekey_time = 0; + this->expire_time = 0; this->config = config; config->get_ref(config); diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 70169f515..ec9b36dab 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -13,8 +13,6 @@ * 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: child_sa.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c index b9141ffc1..a1b037de4 100644 --- a/src/charon/sa/connect_manager.c +++ b/src/charon/sa/connect_manager.c @@ -11,8 +11,6 @@ * 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: connect_manager.c 4579 2008-11-05 11:29:56Z martin $ */ #include "connect_manager.h" @@ -734,11 +732,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 +794,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) { @@ -904,7 +902,7 @@ static void update_checklist_state(private_connect_manager_t *this, check_list_t callback_data_t *data = callback_data_create(this, checklist->connect_id); job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, data, (callback_job_cleanup_t)callback_data_destroy, NULL); - charon->scheduler->schedule_job(charon->scheduler, job, ME_WAIT_TO_FINISH); + charon->scheduler->schedule_job_ms(charon->scheduler, job, ME_WAIT_TO_FINISH); checklist->is_finishing = TRUE; } @@ -1002,7 +1000,7 @@ static void queue_retransmission(private_connect_manager_t *this, check_list_t * } DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", retransmission, pair->id, rto); - charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, rto); + charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*)job, rto); } /** @@ -1139,7 +1137,7 @@ static void schedule_checks(private_connect_manager_t *this, check_list_t *check { callback_data_t *data = callback_data_create(this, checklist->connect_id); checklist->sender = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)callback_data_destroy, NULL); - charon->scheduler->schedule_job(charon->scheduler, checklist->sender, time); + charon->scheduler->schedule_job_ms(charon->scheduler, checklist->sender, time); } /** @@ -1196,8 +1194,8 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli } else { - DBG1(DBG_IKE, "there is no mediated connection waiting between '%D' " - "and '%D'", checklist->initiator.id, checklist->responder.id); + DBG1(DBG_IKE, "there is no mediated connection waiting between '%Y' " + "and '%Y'", checklist->initiator.id, checklist->responder.id); } } } @@ -1396,7 +1394,7 @@ static bool check_and_register(private_connect_manager_t *this, if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) { - DBG2(DBG_IKE, "registered waiting mediated connection with '%D'", peer_id); + DBG2(DBG_IKE, "registered waiting mediated connection with '%Y'", peer_id); initiated = initiated_create(id, peer_id); this->initiated->insert_last(this->initiated, initiated); already_there = FALSE; @@ -1425,7 +1423,7 @@ static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *med if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) { - DBG2(DBG_IKE, "no waiting mediated connections with '%D'", peer_id); + DBG2(DBG_IKE, "no waiting mediated connections with '%Y'", peer_id); this->mutex->unlock(this->mutex); return; } diff --git a/src/charon/sa/connect_manager.h b/src/charon/sa/connect_manager.h index c16f87352..b5abc853c 100644 --- a/src/charon/sa/connect_manager.h +++ b/src/charon/sa/connect_manager.h @@ -11,8 +11,6 @@ * 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: connect_manager.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index bebd74160..6b7fa3582 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 * @@ -14,8 +14,6 @@ * 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: ike_sa.c 4945 2009-03-16 14:23:36Z martin $ */ #include <sys/time.h> @@ -57,10 +55,6 @@ #include <processing/jobs/initiate_mediation_job.h> #endif -#ifndef RESOLV_CONF -#define RESOLV_CONF "/etc/resolv.conf" -#endif - ENUM(ike_sa_state_names, IKE_CREATED, IKE_DESTROYING, "CREATED", "CONNECTING", @@ -72,17 +66,18 @@ ENUM(ike_sa_state_names, IKE_CREATED, IKE_DESTROYING, ); typedef struct private_ike_sa_t private_ike_sa_t; +typedef struct attribute_entry_t attribute_entry_t; /** * Private data of an ike_sa_t object. */ struct private_ike_sa_t { - + /** * Public members */ ike_sa_t public; - + /** * Identifier for the current IKE_SA. */ @@ -96,7 +91,7 @@ struct private_ike_sa_t { /** * Current state of the IKE_SA */ - ike_sa_state_t state; + ike_sa_state_t state; /** * IKE configuration used to set up this IKE_SA @@ -109,14 +104,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 @@ -179,7 +174,7 @@ struct private_ike_sa_t { * set of condition flags currently enabled for this IKE_SA */ ike_condition_t conditions; - + /** * Linked List containing the child sa's of the current IKE_SA. */ @@ -201,9 +196,9 @@ struct private_ike_sa_t { host_t *other_virtual_ip; /** - * List of DNS servers installed by us + * List of configuration attributes (attribute_entry_t) */ - linked_list_t *dns_servers; + linked_list_t *attributes; /** * list of peers additional addresses, transmitted via MOBIKE @@ -219,7 +214,7 @@ struct private_ike_sa_t { * number pending UPDATE_SA_ADDRESS (MOBIKE) */ u_int32_t pending_updates; - + /** * NAT keep alive interval */ @@ -234,12 +229,12 @@ struct private_ike_sa_t { * how many times we have retried so far (keyingtries) */ u_int32_t keyingtry; - + /** * local host address to be used for IKE, set via MIGRATE kernel message */ host_t *local_host; - + /** * remote host address to be used for IKE, set via MIGRATE kernel message */ @@ -247,6 +242,18 @@ struct private_ike_sa_t { }; /** + * Entry to maintain install configuration attributes during IKE_SA lifetime + */ +struct attribute_entry_t { + /** handler used to install this attribute */ + attribute_handler_t *handler; + /** attribute type */ + configuration_attribute_type_t type; + /** attribute data */ + chunk_t data; +}; + +/** * get the time of the latest traffic processed by the kernel */ static time_t get_use_time(private_ike_sa_t* this, bool inbound) @@ -355,40 +362,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; } @@ -460,7 +450,7 @@ static void send_keepalive(private_ike_sa_t *this) } job = send_keepalive_job_create(this->ike_sa_id); charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, - (this->keepalive_interval - diff) * 1000); + this->keepalive_interval - diff); } /** @@ -559,7 +549,7 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition, */ static status_t send_dpd(private_ike_sa_t *this) { - send_dpd_job_t *job; + job_t *job; time_t diff, delay; delay = this->peer_cfg->get_dpd(this->peer_cfg); @@ -608,9 +598,8 @@ static status_t send_dpd(private_ike_sa_t *this) } } /* recheck in "interval" seconds */ - job = send_dpd_job_create(this->ike_sa_id); - charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, - (delay - diff) * 1000); + job = (job_t*)send_dpd_job_create(this->ike_sa_id); + charon->scheduler->schedule_job(charon->scheduler, job, delay - diff); return SUCCESS; } @@ -653,8 +642,7 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) { this->stats[STAT_REKEY] = t + this->stats[STAT_ESTABLISHED]; job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, FALSE); - charon->scheduler->schedule_job(charon->scheduler, - job, t * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, t); DBG1(DBG_IKE, "scheduling rekeying in %ds", t); } t = this->peer_cfg->get_reauth_time(this->peer_cfg); @@ -663,8 +651,7 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) { this->stats[STAT_REAUTH] = t + this->stats[STAT_ESTABLISHED]; job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, - job, t * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, t); DBG1(DBG_IKE, "scheduling reauthentication in %ds", t); } t = this->peer_cfg->get_over_time(this->peer_cfg); @@ -686,8 +673,7 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) this->stats[STAT_DELETE] += t; t = this->stats[STAT_DELETE] - this->stats[STAT_ESTABLISHED]; job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); - charon->scheduler->schedule_job(charon->scheduler, job, - t * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, t); DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t); } @@ -1117,9 +1103,11 @@ static void resolve_hosts(private_ike_sa_t *this) } /** - * Initiates a CHILD_SA using the appropriate reqid + * Implementation of ike_sa_t.initiate */ -static status_t initiate_with_reqid(private_ike_sa_t *this, child_cfg_t *child_cfg, u_int32_t reqid) +static status_t initiate(private_ike_sa_t *this, + child_cfg_t *child_cfg, u_int32_t reqid, + traffic_selector_t *tsi, traffic_selector_t *tsr) { task_t *task; @@ -1181,7 +1169,7 @@ static status_t initiate_with_reqid(private_ike_sa_t *this, child_cfg_t *child_c #endif /* ME */ { /* normal IKE_SA with CHILD_SA */ - task = (task_t*)child_create_create(&this->public, child_cfg); + task = (task_t*)child_create_create(&this->public, child_cfg, tsi, tsr); child_cfg->destroy(child_cfg); if (reqid) { @@ -1205,176 +1193,6 @@ static status_t initiate_with_reqid(private_ike_sa_t *this, child_cfg_t *child_c } /** - * Implementation of ike_sa_t.initiate. - */ -static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) -{ - return initiate_with_reqid(this, child_cfg, 0); -} - -/** - * Implementation of ike_sa_t.acquire. - */ -static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) -{ - child_cfg_t *child_cfg; - iterator_t *iterator; - child_sa_t *current, *child_sa = NULL; - - switch (this->state) - { - case IKE_DELETING: - DBG1(DBG_IKE, "acquiring CHILD_SA {reqid %d} failed: " - "IKE_SA is deleting", reqid); - return FAILED; - case IKE_PASSIVE: - /* do not process acquires if passive */ - return FAILED; - default: - break; - } - - /* find CHILD_SA */ - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (current->get_reqid(current) == reqid) - { - child_sa = current; - break; - } - } - iterator->destroy(iterator); - if (!child_sa) - { - DBG1(DBG_IKE, "acquiring CHILD_SA {reqid %d} failed: " - "CHILD_SA not found", reqid); - return FAILED; - } - - child_cfg = child_sa->get_config(child_sa); - child_cfg->get_ref(child_cfg); - - return initiate_with_reqid(this, child_cfg, reqid); -} - -/** - * Implementation of ike_sa_t.route. - */ -static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) -{ - child_sa_t *child_sa; - iterator_t *iterator; - linked_list_t *my_ts, *other_ts; - host_t *me, *other; - status_t status; - - /* check if not already routed*/ - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) - { - if (child_sa->get_state(child_sa) == CHILD_ROUTED && - streq(child_sa->get_name(child_sa), child_cfg->get_name(child_cfg))) - { - iterator->destroy(iterator); - DBG1(DBG_IKE, "routing CHILD_SA failed: already routed"); - return FAILED; - } - } - iterator->destroy(iterator); - - switch (this->state) - { - case IKE_DELETING: - case IKE_REKEYING: - DBG1(DBG_IKE, "routing CHILD_SA failed: IKE_SA is %N", - ike_sa_state_names, this->state); - return FAILED; - case IKE_CREATED: - case IKE_CONNECTING: - case IKE_ESTABLISHED: - case IKE_PASSIVE: - default: - break; - } - - resolve_hosts(this); - - /* install kernel policies */ - child_sa = child_sa_create(this->my_host, this->other_host, - child_cfg, 0, FALSE); - me = this->my_host; - if (this->my_virtual_ip) - { - me = this->my_virtual_ip; - } - other = this->other_host; - if (this->other_virtual_ip) - { - other = this->other_virtual_ip; - } - - my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, me); - other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, other); - - child_sa->set_mode(child_sa, child_cfg->get_mode(child_cfg)); - status = child_sa->add_policies(child_sa, 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 (status == SUCCESS) - { - this->child_sas->insert_last(this->child_sas, child_sa); - DBG1(DBG_IKE, "CHILD_SA routed"); - } - else - { - child_sa->destroy(child_sa); - DBG1(DBG_IKE, "routing CHILD_SA failed"); - } - return status; -} - -/** - * Implementation of ike_sa_t.unroute. - */ -static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) -{ - iterator_t *iterator; - child_sa_t *child_sa; - bool found = FALSE; - - /* find CHILD_SA in ROUTED state */ - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) - { - if (child_sa->get_state(child_sa) == CHILD_ROUTED && - child_sa->get_reqid(child_sa) == reqid) - { - iterator->remove(iterator); - DBG1(DBG_IKE, "CHILD_SA unrouted"); - child_sa->destroy(child_sa); - found = TRUE; - break; - } - } - iterator->destroy(iterator); - - if (!found) - { - DBG1(DBG_IKE, "unrouting CHILD_SA failed: reqid %d not found", reqid); - return FAILED; - } - /* if we are not established, and we have no more routed childs, remove whole SA */ - if (this->state == IKE_CREATED && - this->child_sas->get_count(this->child_sas) == 0) - { - return DESTROY_ME; - } - return SUCCESS; -} - -/** * Implementation of ike_sa_t.process_message. */ static status_t process_message(private_ike_sa_t *this, message_t *message) @@ -1448,14 +1266,10 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) else { host_t *me, *other; - private_ike_sa_t *new; - iterator_t *iterator; - child_sa_t *child; - bool has_routed = FALSE; me = message->get_destination(message); other = message->get_source(message); - + /* if this IKE_SA is virgin, we check for a config */ if (this->ike_cfg == NULL) { @@ -1485,59 +1299,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) update_hosts(this, me, other); } } - 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 */ - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child)) - { - if (child->get_state(child) == CHILD_ROUTED) - { - has_routed = TRUE; - break; - } - } - iterator->destroy(iterator); - if (!has_routed) - { - return status; - } - /* move routed children to a new IKE_SA, apply connection info */ - new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new( - charon->ike_sa_manager, TRUE); - set_peer_cfg(new, this->peer_cfg); - new->other_host->destroy(new->other_host); - new->other_host = this->other_host->clone(this->other_host); - if (!has_condition(this, COND_NAT_THERE)) - { - new->other_host->set_port(new->other_host, IKEV2_UDP_PORT); - } - if (this->my_virtual_ip) - { - set_virtual_ip(new, TRUE, this->my_virtual_ip); - } - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child)) - { - if (child->get_state(child) == CHILD_ROUTED) - { - route(new, child->get_config(child)); - } - } - iterator->destroy(iterator); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public); - return status; + return this->task_manager->process_message(this->task_manager, message); } } @@ -1846,7 +1608,7 @@ static status_t reestablish(private_ike_sa_t *this) #ifdef ME if (this->peer_cfg->is_mediation(this->peer_cfg)) { - status = new->initiate(new, NULL); + status = new->initiate(new, NULL, 0, NULL, NULL); } else #endif /* ME */ @@ -1869,10 +1631,11 @@ static status_t reestablish(private_ike_sa_t *this) DBG1(DBG_IKE, "restarting CHILD_SA %s", child_cfg->get_name(child_cfg)); child_cfg->get_ref(child_cfg); - status = new->initiate(new, child_cfg); + status = new->initiate(new, child_cfg, 0, NULL, NULL); break; case ACTION_ROUTE: - status = new->route(new, child_cfg); + charon->traps->install(charon->traps, + this->peer_cfg, child_cfg); break; default: continue; @@ -1888,13 +1651,15 @@ static status_t reestablish(private_ike_sa_t *this) if (status == DESTROY_ME) { charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new); - return FAILED; + status = FAILED; } else { charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); - return SUCCESS; + status = SUCCESS; } + charon->bus->set_sa(charon->bus, &this->public); + return status; } /** @@ -1960,8 +1725,8 @@ static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime) DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" " in %ds", lifetime, lifetime - reduction); charon->scheduler->schedule_job(charon->scheduler, - (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), - (lifetime - reduction) * 1000); + (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), + lifetime - reduction); } else { @@ -2030,12 +1795,34 @@ static status_t roam(private_ike_sa_t *this, bool address) } /** + * Implementation of ike_sa_t.add_configuration_attribute + */ +static void add_configuration_attribute(private_ike_sa_t *this, + configuration_attribute_type_t type, chunk_t data) +{ + attribute_entry_t *entry; + attribute_handler_t *handler; + + handler = charon->attributes->handle(charon->attributes, + &this->public, type, data); + if (handler) + { + entry = malloc_thing(attribute_entry_t); + entry->handler = handler; + entry->type = type; + entry->data = chunk_clone(data); + + this->attributes->insert_last(this->attributes, entry); + } +} + +/** * Implementation of ike_sa_t.inherit. */ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) { child_sa_t *child_sa; - host_t *ip; + attribute_entry_t *entry; /* apply hosts and ids */ this->my_host->destroy(this->my_host); @@ -2059,11 +1846,11 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) other->other_virtual_ip = NULL; } - /* ... and DNS servers */ - while (other->dns_servers->remove_last(other->dns_servers, - (void**)&ip) == SUCCESS) + /* ... and configuration attributes */ + while (other->attributes->remove_last(other->attributes, + (void**)&entry) == SUCCESS) { - this->dns_servers->insert_first(this->dns_servers, ip); + this->attributes->insert_first(this->attributes, entry); } /* inherit all conditions */ @@ -2107,158 +1894,36 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) DBG1(DBG_IKE, "rescheduling reauthentication in %ds after rekeying, " "lifetime reduced to %ds", reauth, delete); charon->scheduler->schedule_job(charon->scheduler, - (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), - reauth * 1000); + (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), reauth); charon->scheduler->schedule_job(charon->scheduler, - (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE), - delete * 1000); + (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE), delete); } /* we have to initate here, there may be new tasks to handle */ return this->task_manager->initiate(this->task_manager); } /** - * Implementation of ike_sa_t.remove_dns_server - */ -static void remove_dns_servers(private_ike_sa_t *this) -{ - FILE *file; - struct stat stats; - chunk_t contents, line, orig_line, token; - char string[INET6_ADDRSTRLEN]; - host_t *ip; - iterator_t *iterator; - - if (this->dns_servers->get_count(this->dns_servers) == 0) - { - /* don't touch anything if we have no nameservers installed */ - return; - } - - file = fopen(RESOLV_CONF, "r"); - if (file == NULL || stat(RESOLV_CONF, &stats) != 0) - { - DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s", - RESOLV_CONF, strerror(errno)); - return; - } - - contents = chunk_alloca((size_t)stats.st_size); - - if (fread(contents.ptr, 1, contents.len, file) != contents.len) - { - DBG1(DBG_IKE, "unable to read DNS configuration file: %s", strerror(errno)); - fclose(file); - return; - } - - fclose(file); - file = fopen(RESOLV_CONF, "w"); - if (file == NULL) - { - DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s", - RESOLV_CONF, strerror(errno)); - return; - } - - iterator = this->dns_servers->create_iterator(this->dns_servers, TRUE); - while (fetchline(&contents, &line)) - { - bool found = FALSE; - orig_line = line; - if (extract_token(&token, ' ', &line) && - strncasecmp(token.ptr, "nameserver", token.len) == 0) - { - if (!extract_token(&token, ' ', &line)) - { - token = line; - } - iterator->reset(iterator); - while (iterator->iterate(iterator, (void**)&ip)) - { - snprintf(string, sizeof(string), "%H", ip); - if (strlen(string) == token.len && - strncmp(token.ptr, string, token.len) == 0) - { - iterator->remove(iterator); - ip->destroy(ip); - found = TRUE; - break; - } - } - } - - if (!found) - { - /* write line untouched back to file */ - ignore_result(fwrite(orig_line.ptr, orig_line.len, 1, file)); - fprintf(file, "\n"); - } - } - iterator->destroy(iterator); - fclose(file); -} - -/** - * Implementation of ike_sa_t.add_dns_server - */ -static void add_dns_server(private_ike_sa_t *this, host_t *dns) -{ - FILE *file; - struct stat stats; - chunk_t contents; - - DBG1(DBG_IKE, "installing DNS server %H", dns); - - file = fopen(RESOLV_CONF, "a+"); - if (file == NULL || stat(RESOLV_CONF, &stats) != 0) - { - DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s", - RESOLV_CONF, strerror(errno)); - return; - } - - contents = chunk_alloca(stats.st_size); - - if (fread(contents.ptr, 1, contents.len, file) != contents.len) - { - DBG1(DBG_IKE, "unable to read DNS configuration file: %s", strerror(errno)); - fclose(file); - return; - } - - fclose(file); - file = fopen(RESOLV_CONF, "w"); - if (file == NULL) - { - DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s", - RESOLV_CONF, strerror(errno)); - return; - } - - if (fprintf(file, "nameserver %H # added by strongSwan, assigned by %D\n", - dns, this->other_id) < 0) - { - DBG1(DBG_IKE, "unable to write DNS configuration: %s", strerror(errno)); - } - else - { - this->dns_servers->insert_last(this->dns_servers, dns->clone(dns)); - } - ignore_result(fwrite(contents.ptr, contents.len, 1, file)); - - fclose(file); -} - -/** * Implementation of ike_sa_t.destroy. */ static void destroy(private_ike_sa_t *this) { + attribute_entry_t *entry; + charon->bus->set_sa(charon->bus, &this->public); set_state(this, IKE_DESTROYING); + /* remove attributes first, as we pass the IKE_SA to the handler */ + while (this->attributes->remove_last(this->attributes, + (void**)&entry) == SUCCESS) + { + charon->attributes->release(charon->attributes, entry->handler, + &this->public, entry->type, entry->data); + free(entry->data.ptr); + free(entry); + } + this->attributes->destroy(this->attributes); + this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy)); /* unset SA after here to avoid usage by the listeners */ @@ -2283,10 +1948,6 @@ static void destroy(private_ike_sa_t *this) } this->other_virtual_ip->destroy(this->other_virtual_ip); } - - remove_dns_servers(this); - this->dns_servers->destroy_offset(this->dns_servers, - offsetof(host_t, destroy)); this->additional_addresses->destroy_offset(this->additional_addresses, offsetof(host_t, destroy)); #ifdef ME @@ -2309,9 +1970,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); @@ -2331,16 +1992,12 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.get_name = (char* (*)(ike_sa_t*))get_name; this->public.get_statistic = (u_int32_t(*)(ike_sa_t*, statistic_t kind))get_statistic; this->public.process_message = (status_t (*)(ike_sa_t*, message_t*)) process_message; - this->public.initiate = (status_t (*)(ike_sa_t*,child_cfg_t*)) initiate; - this->public.route = (status_t (*)(ike_sa_t*,child_cfg_t*)) route; - this->public.unroute = (status_t (*)(ike_sa_t*,u_int32_t)) unroute; - this->public.acquire = (status_t (*)(ike_sa_t*,u_int32_t)) acquire; + this->public.initiate = (status_t (*)(ike_sa_t*,child_cfg_t*,u_int32_t,traffic_selector_t*,traffic_selector_t*)) initiate; this->public.get_ike_cfg = (ike_cfg_t* (*)(ike_sa_t*))get_ike_cfg; 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; @@ -2388,7 +2045,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.get_unique_id = (u_int32_t (*)(ike_sa_t*))get_unique_id; this->public.set_virtual_ip = (void (*)(ike_sa_t*,bool,host_t*))set_virtual_ip; this->public.get_virtual_ip = (host_t* (*)(ike_sa_t*,bool))get_virtual_ip; - this->public.add_dns_server = (void (*)(ike_sa_t*,host_t*))add_dns_server; + this->public.add_configuration_attribute = (void(*)(ike_sa_t*, configuration_attribute_type_t type, chunk_t data))add_configuration_attribute; this->public.set_kmaddress = (void (*)(ike_sa_t*,host_t*,host_t*))set_kmaddress; #ifdef ME this->public.act_as_mediation_server = (void (*)(ike_sa_t*)) act_as_mediation_server; @@ -2421,15 +2078,15 @@ 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; this->my_virtual_ip = NULL; this->other_virtual_ip = NULL; - this->dns_servers = linked_list_create(); this->additional_addresses = linked_list_create(); + this->attributes = linked_list_create(); this->nat_detection_dest = chunk_empty; this->pending_updates = 0; this->keyingtry = 0; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 3ca8d9521..b751bda0c 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 * @@ -14,8 +14,6 @@ * 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: ike_sa.h 5003 2009-03-24 17:43:01Z martin $ */ /** @@ -35,18 +33,19 @@ typedef struct ike_sa_t ike_sa_t; #include <library.h> #include <encoding/message.h> #include <encoding/payloads/proposal_substructure.h> +#include <encoding/payloads/configuration_attribute.h> #include <sa/ike_sa_id.h> #include <sa/child_sa.h> #include <sa/tasks/task.h> #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. + * Timeout in seconds after that a half open IKE_SA gets deleted. */ -#define HALF_OPEN_IKE_SA_TIMEOUT 30000 +#define HALF_OPEN_IKE_SA_TIMEOUT 30 /** * Interval to send keepalives when NATed, in seconds. @@ -82,6 +81,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 +114,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 +395,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. @@ -602,51 +600,21 @@ struct ike_sa_t { /** * Initiate a new connection. * - * The configs are owned by the IKE_SA after the call. + * The configs are owned by the IKE_SA after the call. If the initiate + * is triggered by a packet, traffic selectors of the packet can be added + * to the CHILD_SA. * * @param child_cfg child config to create CHILD from + * @param reqid reqid to use for CHILD_SA, 0 assigne uniquely + * @param tsi source of triggering packet + * @param tsr destination of triggering packet. * @return * - SUCCESS if initialization started * - DESTROY_ME if initialization failed */ - status_t (*initiate) (ike_sa_t *this, child_cfg_t *child_cfg); - - /** - * Route a policy in the kernel. - * - * Installs the policies in the kernel. If traffic matches, - * the kernel requests connection setup from the IKE_SA via acquire(). - * - * @param child_cfg child config to route - * @return - * - SUCCESS if routed successfully - * - FAILED if routing failed - */ - status_t (*route) (ike_sa_t *this, child_cfg_t *child_cfg); - - /** - * Unroute a policy in the kernel previously routed. - * - * @param reqid reqid of CHILD_SA to unroute - * @return - * - SUCCESS if route removed - * - NOT_FOUND if CHILD_SA not found - * - DESTROY_ME if last CHILD_SA was unrouted - */ - status_t (*unroute) (ike_sa_t *this, u_int32_t reqid); - - /** - * Acquire connection setup for an installed kernel policy. - * - * If an installed policy raises an acquire, the kernel calls - * this function to establish the CHILD_SA (and maybe the IKE_SA). - * - * @param reqid reqid of the CHILD_SA the policy belongs to. - * @return - * - SUCCESS if initialization started - * - DESTROY_ME if initialization failed - */ - status_t (*acquire) (ike_sa_t *this, u_int32_t reqid); + status_t (*initiate) (ike_sa_t *this, child_cfg_t *child_cfg, + u_int32_t reqid, traffic_selector_t *tsi, + traffic_selector_t *tsr); /** * Initiates the deletion of an IKE_SA. @@ -869,14 +837,18 @@ struct ike_sa_t { host_t* (*get_virtual_ip) (ike_sa_t *this, bool local); /** - * Add a DNS server to the system. + * Register a configuration attribute to the IKE_SA. * - * An IRAS may send a DNS server. To use it, it is installed on the - * system. The DNS entry has a lifetime until the IKE_SA gets closed. + * If an IRAS sends a configuration attribute it is installed and + * registered at the IKE_SA. Attributes are inherit()ed and get released + * when the IKE_SA is closed. * - * @param dns DNS server to install on the system + * @param handler handler installed the attribute, use for release() + * @param type configuration attribute type + * @param data associated attribute data */ - void (*add_dns_server) (ike_sa_t *this, host_t *dns); + void (*add_configuration_attribute)(ike_sa_t *this, + configuration_attribute_type_t type, chunk_t data); /** * Set local and remote host addresses to be used for IKE. @@ -888,7 +860,7 @@ struct ike_sa_t { * @param remote remote kmaddress */ void (*set_kmaddress) (ike_sa_t *this, host_t *local, host_t *remote); - + /** * Inherit all attributes of other to this after rekeying. * diff --git a/src/charon/sa/ike_sa_id.c b/src/charon/sa/ike_sa_id.c index e012d5944..94c5405f2 100644 --- a/src/charon/sa/ike_sa_id.c +++ b/src/charon/sa/ike_sa_id.c @@ -12,8 +12,6 @@ * 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: ike_sa_id.c 3589 2008-03-13 14:14:44Z martin $ */ #include "ike_sa_id.h" diff --git a/src/charon/sa/ike_sa_id.h b/src/charon/sa/ike_sa_id.h index db36fda95..377e64e8a 100644 --- a/src/charon/sa/ike_sa_id.h +++ b/src/charon/sa/ike_sa_id.h @@ -12,8 +12,6 @@ * 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: ike_sa_id.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index e2aacddd5..efe7c228c 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -13,8 +13,6 @@ * 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: ike_sa_manager.c 5035 2009-03-26 13:18:19Z andreas $ */ #include <string.h> @@ -901,25 +899,35 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id */ static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator) { + ike_sa_id_t *ike_sa_id; + ike_sa_t *ike_sa; entry_t *entry; u_int segment; - entry = entry_create(); if (initiator) { - entry->ike_sa_id = ike_sa_id_create(get_next_spi(this), 0, TRUE); + ike_sa_id = ike_sa_id_create(get_next_spi(this), 0, TRUE); } else { - entry->ike_sa_id = ike_sa_id_create(0, get_next_spi(this), FALSE); + ike_sa_id = ike_sa_id_create(0, get_next_spi(this), FALSE); + } + ike_sa = ike_sa_create(ike_sa_id); + + DBG2(DBG_MGR, "created IKE_SA"); + + if (!initiator) + { + ike_sa_id->destroy(ike_sa_id); + return ike_sa; } - entry->ike_sa = ike_sa_create(entry->ike_sa_id); - segment = put_entry(this, entry); + entry = entry_create(); + entry->ike_sa_id = ike_sa_id; + entry->ike_sa = ike_sa; + segment = put_entry(this, entry); entry->checked_out = TRUE; unlock_single_segment(this, segment); - - DBG2(DBG_MGR, "created IKE_SA"); return entry->ike_sa; } @@ -1042,9 +1050,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 +1060,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 +1291,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); @@ -1477,7 +1434,7 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) { case UNIQUE_REPLACE: DBG1(DBG_IKE, "deleting duplicate IKE_SA for peer " - "'%D' due to uniqueness policy", other); + "'%Y' due to uniqueness policy", other); status = duplicate->delete(duplicate); break; case UNIQUE_KEEP: diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index 8fe991521..6da768080 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -13,8 +13,6 @@ * 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: ike_sa_manager.h 5003 2009-03-24 17:43:01Z martin $ */ /** @@ -53,6 +51,9 @@ struct ike_sa_manager_t { /** * Create and check out a new IKE_SA. + * + * @note If initiator equals FALSE, the returned IKE_SA is not registered + * in the manager. * * @param initiator TRUE for initiator, FALSE otherwise * @returns created and checked out IKE_SA diff --git a/src/charon/sa/keymat.c b/src/charon/sa/keymat.c index b2e646c93..117d260ba 100644 --- a/src/charon/sa/keymat.c +++ b/src/charon/sa/keymat.c @@ -11,8 +11,6 @@ * 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 "keymat.h" @@ -415,17 +413,18 @@ static bool derive_child_keys(private_keymat_t *this, /* to bytes */ enc_size /= 8; - /* CCM/GCM needs additional bytes */ + /* CCM/GCM/CTR needs additional bytes */ switch (enc_alg) { case ENCR_AES_CCM_ICV8: case ENCR_AES_CCM_ICV12: case ENCR_AES_CCM_ICV16: enc_size += 3; - break; + break; case ENCR_AES_GCM_ICV8: case ENCR_AES_GCM_ICV12: case ENCR_AES_GCM_ICV16: + case ENCR_AES_CTR: enc_size += 4; break; default: @@ -463,6 +462,16 @@ static bool derive_child_keys(private_keymat_t *this, prf_plus->destroy(prf_plus); + if (enc_size) + { + DBG4(DBG_CHD, "encryption initiator key %B", encr_i); + DBG4(DBG_CHD, "encryption responder key %B", encr_r); + } + if (int_size) + { + DBG4(DBG_CHD, "integrity initiator key %B", integ_i); + DBG4(DBG_CHD, "integrity responder key %B", integ_r); + } return TRUE; } diff --git a/src/charon/sa/keymat.h b/src/charon/sa/keymat.h index 659e4dff2..43b9dd113 100644 --- a/src/charon/sa/keymat.h +++ b/src/charon/sa/keymat.h @@ -11,8 +11,6 @@ * 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$ */ /** diff --git a/src/charon/sa/mediation_manager.c b/src/charon/sa/mediation_manager.c index b508c48c3..890e567c7 100644 --- a/src/charon/sa/mediation_manager.c +++ b/src/charon/sa/mediation_manager.c @@ -11,8 +11,6 @@ * 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: mediation_manager.c 4579 2008-11-05 11:29:56Z martin $ */ #include "mediation_manager.h" @@ -227,12 +225,12 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe if (!found) { - DBG2(DBG_IKE, "adding peer '%D'", peer_id); + DBG2(DBG_IKE, "adding peer '%Y'", peer_id); peer = peer_create(peer_id, NULL); this->peers->insert_last(this->peers, peer); } - DBG2(DBG_IKE, "changing registered IKE_SA ID of peer '%D'", peer_id); + DBG2(DBG_IKE, "changing registered IKE_SA ID of peer '%Y'", peer_id); peer->ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL; /* send callbacks to registered peers */ @@ -284,7 +282,7 @@ static ike_sa_id_t *check_and_register(private_mediation_manager_t *this, if (get_peer_by_id(this, peer_id, &peer) != SUCCESS) { - DBG2(DBG_IKE, "adding peer %D", peer_id); + DBG2(DBG_IKE, "adding peer %Y", peer_id); peer = peer_create(peer_id, NULL); this->peers->insert_last(this->peers, peer); } @@ -292,7 +290,7 @@ static ike_sa_id_t *check_and_register(private_mediation_manager_t *this, if (!peer->ike_sa_id) { /* the peer is not online */ - DBG2(DBG_IKE, "requested peer '%D' is offline, registering peer '%D'", peer_id, requester); + DBG2(DBG_IKE, "requested peer '%Y' is offline, registering peer '%Y'", peer_id, requester); register_peer(peer, requester); this->mutex->unlock(this->mutex); return NULL; diff --git a/src/charon/sa/mediation_manager.h b/src/charon/sa/mediation_manager.h index 7eee09d67..29e16d84f 100644 --- a/src/charon/sa/mediation_manager.h +++ b/src/charon/sa/mediation_manager.h @@ -11,8 +11,6 @@ * 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: mediation_manager.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index e5c5fe178..2cd9532eb 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -12,8 +12,6 @@ * 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: task_manager.c 4857 2009-02-09 10:45:51Z martin $ */ #include "task_manager.h" @@ -259,7 +257,7 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id) this->initiating.retransmitted++; job = (job_t*)retransmit_job_create(this->initiating.mid, this->ike_sa->get_id(this->ike_sa)); - charon->scheduler->schedule_job(charon->scheduler, job, timeout); + charon->scheduler->schedule_job_ms(charon->scheduler, job, timeout); } return SUCCESS; } @@ -626,6 +624,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /* message complete, send it */ DESTROY_IF(this->responding.packet); + this->responding.packet = NULL; status = this->ike_sa->generate_message(this->ike_sa, message, &this->responding.packet); charon->bus->message(charon->bus, message, FALSE); @@ -650,167 +649,170 @@ 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; notify_payload_t *notify; delete_payload_t *delete; - /* create tasks depending on request type */ - switch (message->get_exchange_type(message)) - { - case IKE_SA_INIT: + if (this->passive_tasks->get_count(this->passive_tasks) == 0) + { /* create tasks depending on request type, if not already some queued */ + switch (message->get_exchange_type(message)) { - task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_natd_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + case IKE_SA_INIT: + { + task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_natd_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); #ifdef ME - task = (task_t*)ike_me_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_me_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); #endif /* ME */ - task = (task_t*)ike_auth_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_config_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)child_create_create(this->ike_sa, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - break; - } - 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)) - { - switch (payload->get_type(payload)) + task = (task_t*)ike_auth_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_config_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)child_create_create(this->ike_sa, NULL, NULL, NULL); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + break; + } + case CREATE_CHILD_SA: + { /* FIXME: we should prevent this on mediation connections */ + bool notify_found = FALSE, ts_found = FALSE; + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { - case NOTIFY: + switch (payload->get_type(payload)) { - /* if we find a rekey notify, its CHILD_SA rekeying */ - notify = (notify_payload_t*)payload; - if (notify->get_notify_type(notify) == REKEY_SA && - (notify->get_protocol_id(notify) == PROTO_AH || - notify->get_protocol_id(notify) == PROTO_ESP)) - { - notify_found = TRUE; + case NOTIFY: + { /* if we find a rekey notify, its CHILD_SA rekeying */ + notify = (notify_payload_t*)payload; + if (notify->get_notify_type(notify) == REKEY_SA && + (notify->get_protocol_id(notify) == PROTO_AH || + notify->get_protocol_id(notify) == PROTO_ESP)) + { + notify_found = TRUE; + } + break; } - break; - } - case TRAFFIC_SELECTOR_INITIATOR: - case TRAFFIC_SELECTOR_RESPONDER: - { - /* if we don't find a TS, its IKE rekeying */ - ts_found = TRUE; - break; + case TRAFFIC_SELECTOR_INITIATOR: + case TRAFFIC_SELECTOR_RESPONDER: + { /* if we don't find a TS, its IKE rekeying */ + ts_found = TRUE; + break; + } + default: + break; } - default: - break; } - } - iterator->destroy(iterator); - - if (ts_found) - { - if (notify_found) + enumerator->destroy(enumerator); + + if (ts_found) { - task = (task_t*)child_rekey_create(this->ike_sa, - PROTO_NONE, 0); + if (notify_found) + { + task = (task_t*)child_rekey_create(this->ike_sa, + PROTO_NONE, 0); + } + else + { + task = (task_t*)child_create_create(this->ike_sa, + NULL, NULL, NULL); + } } else { - task = (task_t*)child_create_create(this->ike_sa, NULL); + task = (task_t*)ike_rekey_create(this->ike_sa, FALSE); } + this->passive_tasks->insert_last(this->passive_tasks, task); + break; } - else - { - task = (task_t*)ike_rekey_create(this->ike_sa, FALSE); - } - this->passive_tasks->insert_last(this->passive_tasks, task); - break; - } - case INFORMATIONAL: - { - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + case INFORMATIONAL: { - switch (payload->get_type(payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { - case NOTIFY: + switch (payload->get_type(payload)) { - notify = (notify_payload_t*)payload; - switch (notify->get_notify_type(notify)) + case NOTIFY: { - case ADDITIONAL_IP4_ADDRESS: - case ADDITIONAL_IP6_ADDRESS: - case NO_ADDITIONAL_ADDRESSES: - case UPDATE_SA_ADDRESSES: - case NO_NATS_ALLOWED: - case UNACCEPTABLE_ADDRESSES: - case UNEXPECTED_NAT_DETECTED: - case COOKIE2: - case NAT_DETECTION_SOURCE_IP: - case NAT_DETECTION_DESTINATION_IP: - task = (task_t*)ike_mobike_create( - this->ike_sa, FALSE); - break; - case AUTH_LIFETIME: - task = (task_t*)ike_auth_lifetime_create( - this->ike_sa, FALSE); - break; - default: - break; + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case ADDITIONAL_IP4_ADDRESS: + case ADDITIONAL_IP6_ADDRESS: + case NO_ADDITIONAL_ADDRESSES: + case UPDATE_SA_ADDRESSES: + case NO_NATS_ALLOWED: + case UNACCEPTABLE_ADDRESSES: + case UNEXPECTED_NAT_DETECTED: + case COOKIE2: + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: + task = (task_t*)ike_mobike_create( + this->ike_sa, FALSE); + break; + case AUTH_LIFETIME: + task = (task_t*)ike_auth_lifetime_create( + this->ike_sa, FALSE); + break; + default: + break; + } + break; } - break; - } - case DELETE: - { - delete = (delete_payload_t*)payload; - if (delete->get_protocol_id(delete) == PROTO_IKE) - { - task = (task_t*)ike_delete_create(this->ike_sa, FALSE); - } - else + case DELETE: { - task = (task_t*)child_delete_create(this->ike_sa, + delete = (delete_payload_t*)payload; + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + task = (task_t*)ike_delete_create(this->ike_sa, + FALSE); + } + else + { + task = (task_t*)child_delete_create(this->ike_sa, PROTO_NONE, 0); + } + break; } - break; + default: + break; } - default: + if (task) + { break; + } } - if (task) + enumerator->destroy(enumerator); + + if (task == NULL) { - break; + task = (task_t*)ike_dpd_create(FALSE); } + this->passive_tasks->insert_last(this->passive_tasks, task); + break; } - iterator->destroy(iterator); - - if (task == NULL) +#ifdef ME + case ME_CONNECT: { - task = (task_t*)ike_dpd_create(FALSE); + task = (task_t*)ike_me_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); } - this->passive_tasks->insert_last(this->passive_tasks, task); - break; - } -#ifdef ME - case ME_CONNECT: - { - task = (task_t*)ike_me_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - } #endif /* ME */ - default: - break; + default: + break; + } } /* let the tasks process the message */ @@ -941,15 +943,6 @@ static void adopt_tasks(private_task_manager_t *this, private_task_manager_t *ot task->migrate(task, this->ike_sa); this->queued_tasks->insert_first(this->queued_tasks, task); } - - /* reset active tasks and move them to others queued tasks */ - while (other->active_tasks->remove_last(other->active_tasks, - (void**)&task) == SUCCESS) - { - DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); - task->migrate(task, this->ike_sa); - this->queued_tasks->insert_first(this->queued_tasks, task); - } } /** diff --git a/src/charon/sa/task_manager.h b/src/charon/sa/task_manager.h index db21684c3..9c3b2cc87 100644 --- a/src/charon/sa/task_manager.h +++ b/src/charon/sa/task_manager.h @@ -11,8 +11,6 @@ * 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: task_manager.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index c07cd37b8..f51443738 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -13,8 +13,6 @@ * 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: child_create.c 4860 2009-02-11 13:09:52Z martin $ */ #include "child_create.h" @@ -87,6 +85,16 @@ struct private_child_create_t { linked_list_t *tsr; /** + * source of triggering packet + */ + traffic_selector_t *packet_tsi; + + /** + * destination of triggering packet + */ + traffic_selector_t *packet_tsr; + + /** * optional diffie hellman exchange */ diffie_hellman_t *dh; @@ -570,7 +578,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 +587,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 +624,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -643,9 +651,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; @@ -694,7 +702,17 @@ static status_t build_i(private_child_create_t *this, message_t *message) } this->tsr = this->config->get_traffic_selectors(this->config, FALSE, NULL, other); - + + if (this->packet_tsi) + { + this->tsi->insert_first(this->tsi, + this->packet_tsi->clone(this->packet_tsi)); + } + if (this->packet_tsr) + { + this->tsr->insert_first(this->tsr, + this->packet_tsr->clone(this->packet_tsr)); + } this->proposals = this->config->get_proposals(this->config, this->dh_group == MODP_NONE); this->mode = this->config->get_mode(this->config); @@ -737,8 +755,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 +763,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; } @@ -799,7 +790,7 @@ static void handle_child_sa_failure(private_child_create_t *this, /* we delay the delete for 100ms, as the IKE_AUTH response must arrive * first */ DBG1(DBG_IKE, "closing IKE_SA due CHILD_SA setup failure"); - charon->scheduler->schedule_job(charon->scheduler, (job_t*) + charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*) delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE), 100); } @@ -810,10 +801,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 +820,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 +835,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 +864,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 +878,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 +887,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 +948,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 +961,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 +970,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 +991,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 +1009,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 +1017,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); process_payloads(this, message); @@ -1149,6 +1158,8 @@ static void destroy(private_child_create_t *this) { DESTROY_IF(this->child_sa); } + DESTROY_IF(this->packet_tsi); + DESTROY_IF(this->packet_tsr); DESTROY_IF(this->proposal); DESTROY_IF(this->dh); if (this->proposals) @@ -1163,7 +1174,8 @@ static void destroy(private_child_create_t *this) /* * Described in header. */ -child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config) +child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config, + traffic_selector_t *tsi, traffic_selector_t *tsr) { private_child_create_t *this = malloc_thing(private_child_create_t); @@ -1195,6 +1207,8 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config) this->proposal = NULL; this->tsi = NULL; this->tsr = NULL; + this->packet_tsi = tsi ? tsi->clone(tsi) : NULL; + this->packet_tsr = tsr ? tsr->clone(tsr) : NULL; this->dh = NULL; this->dh_group = MODP_NONE; this->keymat = ike_sa->get_keymat(ike_sa); diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h index d01baa594..ce2829a9a 100644 --- a/src/charon/sa/tasks/child_create.h +++ b/src/charon/sa/tasks/child_create.h @@ -11,8 +11,6 @@ * 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: child_create.h 5003 2009-03-24 17:43:01Z martin $ */ /** @@ -73,8 +71,11 @@ struct child_create_t { * * @param ike_sa IKE_SA this task works for * @param config child_cfg if task initiator, NULL if responder - * @return child_create task to handle by the task_manager + * @param tsi source of triggering packet, or NULL + * @param tsr destination of triggering packet, or NULL + * @return child_create task to handle by the task_manager */ -child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config); +child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config, + traffic_selector_t *tsi, traffic_selector_t *tsr); #endif /** CHILD_CREATE_H_ @}*/ diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index 0fd4a056b..0d89c148e 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -11,8 +11,6 @@ * 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: child_delete.c 4730 2008-12-01 18:38:28Z martin $ */ #include "child_delete.h" @@ -114,15 +112,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) { @@ -202,10 +201,12 @@ static status_t destroy_and_reestablish(private_child_delete_t *this) { case ACTION_RESTART: child_cfg->get_ref(child_cfg); - status = this->ike_sa->initiate(this->ike_sa, child_cfg); + status = this->ike_sa->initiate(this->ike_sa, child_cfg, 0, + NULL, NULL); break; - case ACTION_ROUTE: - status = this->ike_sa->route(this->ike_sa, child_cfg); + case ACTION_ROUTE: + charon->traps->install(charon->traps, + this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg); break; default: break; diff --git a/src/charon/sa/tasks/child_delete.h b/src/charon/sa/tasks/child_delete.h index 8886ff4a1..27d847035 100644 --- a/src/charon/sa/tasks/child_delete.h +++ b/src/charon/sa/tasks/child_delete.h @@ -11,8 +11,6 @@ * 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: child_delete.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 0d8cf2db7..6ab00dc5b 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -12,8 +12,6 @@ * 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: child_rekey.c 4730 2008-12-01 18:38:28Z martin $ */ #include "child_rekey.h" @@ -103,11 +101,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 +129,7 @@ static void find_child(private_child_rekey_t *this, message_t *message) break; } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -159,7 +157,7 @@ static status_t build_i(private_child_rekey_t *this, message_t *message) /* ... our CHILD_CREATE task does the hard work for us. */ reqid = this->child_sa->get_reqid(this->child_sa); - this->child_create = child_create_create(this->ike_sa, config); + this->child_create = child_create_create(this->ike_sa, config, NULL, NULL); this->child_create->use_reqid(this->child_create, reqid); this->child_create->task.build(&this->child_create->task, message); @@ -220,12 +218,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 +237,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) { @@ -269,7 +267,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) DBG1(DBG_IKE, "CHILD_SA rekeying failed, " "trying again in %d seconds", retry); this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - charon->scheduler->schedule_job(charon->scheduler, job, retry * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, retry); } return SUCCESS; } @@ -418,7 +416,7 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, 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->initiator = FALSE; - this->child_create = child_create_create(ike_sa, NULL); + this->child_create = child_create_create(ike_sa, NULL, NULL, NULL); } this->ike_sa = ike_sa; diff --git a/src/charon/sa/tasks/child_rekey.h b/src/charon/sa/tasks/child_rekey.h index 42fce0742..5aae2fb39 100644 --- a/src/charon/sa/tasks/child_rekey.h +++ b/src/charon/sa/tasks/child_rekey.h @@ -11,8 +11,6 @@ * 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: child_rekey.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index 93b145755..8d6cd56bd 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 * @@ -12,8 +12,6 @@ * 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: ike_auth.c 4858 2009-02-10 17:21:44Z martin $ */ #include "ike_auth.h" @@ -21,14 +19,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 +68,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; - - /* 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; + authenticator_t *my_auth; - 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 +138,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 +150,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 +164,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 +351,104 @@ 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_nonce, + this->other_packet->get_data(this->other_packet), + 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 +457,136 @@ 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->other_nonce, this->my_nonce, + this->other_packet->get_data(this->other_packet), + this->my_packet->get_data(this->my_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)) { - this->ike_sa->set_peer_cfg(this->ike_sa, config); - config->destroy(config); + 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 (!this->peer_authenticated) - { - this->eap_auth = eap_authenticator_create(this->ike_sa); + + if (!update_cfg_candidates(this, FALSE)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + + 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,54 +596,142 @@ 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 %Y, but require %Y", 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_nonce, + this->other_packet->get_data(this->other_packet), + 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]", + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", 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), @@ -644,21 +740,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 +748,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 +799,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 +809,116 @@ 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->other_nonce, this->my_nonce, + this->other_packet->get_data(this->other_packet), + this->my_packet->get_data(this->my_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[%Y]...%H[%Y]", + 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 +938,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 +968,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 +983,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 +1005,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.h b/src/charon/sa/tasks/ike_auth.h index a4719ec24..bba46d961 100644 --- a/src/charon/sa/tasks/ike_auth.h +++ b/src/charon/sa/tasks/ike_auth.h @@ -11,8 +11,6 @@ * 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: ike_auth.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_auth_lifetime.c b/src/charon/sa/tasks/ike_auth_lifetime.c index cb17cc2dc..a047e6b81 100644 --- a/src/charon/sa/tasks/ike_auth_lifetime.c +++ b/src/charon/sa/tasks/ike_auth_lifetime.c @@ -11,8 +11,6 @@ * 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: ike_auth_lifetime.c 4576 2008-11-05 08:32:38Z martin $ */ #include "ike_auth_lifetime.h" @@ -64,12 +62,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 +86,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_auth_lifetime.h b/src/charon/sa/tasks/ike_auth_lifetime.h index 46595e6ed..812caaf43 100644 --- a/src/charon/sa/tasks/ike_auth_lifetime.h +++ b/src/charon/sa/tasks/ike_auth_lifetime.h @@ -11,8 +11,6 @@ * 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: ike_auth_lifetime.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_cert_post.c b/src/charon/sa/tasks/ike_cert_post.c index cb533236e..70e87c2e7 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 @@ -12,8 +12,6 @@ * 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: ike_cert_post.c 4276 2008-08-22 10:44:51Z martin $ */ #include "ike_cert_post.h" @@ -22,6 +20,7 @@ #include <sa/ike_sa.h> #include <encoding/payloads/cert_payload.h> #include <encoding/payloads/certreq_payload.h> +#include <encoding/payloads/auth_payload.h> #include <credentials/certificates/x509.h> @@ -98,70 +97,71 @@ 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_payload_t *payload; + payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg && get_auth_class(peer_cfg) == AUTH_CLASS_PUBKEY) + if (!peer_cfg || !payload || payload->get_auth_method(payload) == AUTH_PSK) + { /* no CERT payload for EAP/PSK */ + 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; + auth_cfg_t *auth; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + + /* 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 \"%Y\"", + 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 \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); } } - enumerator->destroy(enumerator); - } - } + } + enumerator->destroy(enumerator); + } } } @@ -170,12 +170,9 @@ 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; - } build_certs(this, message); - return SUCCESS; + + return NEED_MORE; } /** @@ -191,11 +188,12 @@ 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) - { + 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 +202,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_post.h b/src/charon/sa/tasks/ike_cert_post.h index ec9d172e1..fa555eac7 100644 --- a/src/charon/sa/tasks/ike_cert_post.h +++ b/src/charon/sa/tasks/ike_cert_post.h @@ -11,8 +11,6 @@ * 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: ike_cert_post.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_cert_pre.c b/src/charon/sa/tasks/ike_cert_pre.c index 353b76a22..1c72f289f 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 @@ -12,8 +12,6 @@ * 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: ike_cert_pre.c 4285 2008-08-26 05:15:34Z andreas $ */ #include "ike_cert_pre.h" @@ -48,9 +46,14 @@ 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 do_http_lookup; + + /** + * wheter this is the final authentication round */ - bool http_cert_lookup_supported_sent; + bool final; }; /** @@ -58,23 +61,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); @@ -96,17 +98,14 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) CERT_X509, KEY_ANY, id, TRUE); if (cert) { - DBG1(DBG_IKE, "received cert request for \"%D\"", + DBG1(DBG_IKE, "received cert request for \"%Y\"", 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); + "with keyid %Y", id); } id->destroy(id); } @@ -129,7 +128,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -140,6 +139,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 +158,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 +175,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 */ - DBG1(DBG_IKE, "received end entity cert \"%D\"", + { /* the first is an end entity certificate */ + DBG1(DBG_IKE, "received end entity cert \"%Y\"", 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\"", + DBG1(DBG_IKE, "received issuer cert \"%Y\"", 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 +267,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,22 +291,49 @@ 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) { - *reqp = certreq_payload_create_type(CERT_X509); - message->add_payload(message, (payload_t*)*reqp); + break; + } + if (*req == NULL) + { + *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)); - DBG1(DBG_IKE, "sending cert request for \"%D\"", + (*req)->add_keyid(*req, keyid->get_encoding(keyid)); + public->destroy(public); + DBG1(DBG_IKE, "sending cert request for \"%Y\"", cert->get_subject(cert)); break; } 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,88 +341,96 @@ 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; + } } } /** + * Check if this is the final authentication round + */ +static bool final_auth(message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + notify_payload_t *notify; + + /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */ + if (message->get_payload(message, AUTHENTICATION) == NULL) + { + return FALSE; + } + 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) + { + enumerator->destroy(enumerator); + return FALSE; + } + } + } + enumerator->destroy(enumerator); + return TRUE; +} + +/** * Implementation of task_t.process for initiator */ 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 +438,13 @@ 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); + this->final = final_auth(message); return NEED_MORE; } @@ -426,9 +456,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->final) + { + return SUCCESS; + } + return NEED_MORE; } /** @@ -439,10 +472,14 @@ 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; + + if (final_auth(message)) + { + return SUCCESS; + } + return NEED_MORE; } /** @@ -493,7 +530,8 @@ 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; + this->final = FALSE; return &this->public; } diff --git a/src/charon/sa/tasks/ike_cert_pre.h b/src/charon/sa/tasks/ike_cert_pre.h index d6d06b04f..d49005e68 100644 --- a/src/charon/sa/tasks/ike_cert_pre.h +++ b/src/charon/sa/tasks/ike_cert_pre.h @@ -11,8 +11,6 @@ * 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: ike_cert_pre.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c index b890e93ba..1f75521b6 100644 --- a/src/charon/sa/tasks/ike_config.c +++ b/src/charon/sa/tasks/ike_config.c @@ -12,8 +12,6 @@ * 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: ike_config.c 4867 2009-02-13 11:57:50Z andreas $ */ #include "ike_config.h" @@ -50,54 +48,34 @@ struct private_ike_config_t { * virtual ip */ host_t *virtual_ip; - - /** - * list of DNS servers - */ - linked_list_t *dns; - - /** - * list of WINS servers - */ - linked_list_t *nbns; }; /** - * build configuration payloads and attributes + * build INTERNAL_IPV4/6_ADDRESS from virtual ip */ -static void build_payloads(private_ike_config_t *this, message_t *message, - config_type_t type) +static void build_vip(private_ike_config_t *this, host_t *vip, cp_payload_t *cp) { - cp_payload_t *cp; configuration_attribute_t *ca; chunk_t chunk, prefix; - if (!this->virtual_ip) - { - return; - } - - cp = cp_payload_create(); - cp->set_config_type(cp, type); - ca = configuration_attribute_create(); - if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET) + if (vip->get_family(vip) == AF_INET) { ca->set_type(ca, INTERNAL_IP4_ADDRESS); - if (this->virtual_ip->is_anyaddr(this->virtual_ip)) + if (vip->is_anyaddr(vip)) { chunk = chunk_empty; } else { - chunk = this->virtual_ip->get_address(this->virtual_ip); + chunk = vip->get_address(vip); } } else { ca->set_type(ca, INTERNAL_IP6_ADDRESS); - if (this->virtual_ip->is_anyaddr(this->virtual_ip)) + if (vip->is_anyaddr(vip)) { chunk = chunk_empty; } @@ -105,71 +83,12 @@ static void build_payloads(private_ike_config_t *this, message_t *message, { prefix = chunk_alloca(1); *prefix.ptr = 64; - chunk = this->virtual_ip->get_address(this->virtual_ip); + chunk = vip->get_address(vip); chunk = chunk_cata("cc", chunk, prefix); } } ca->set_value(ca, chunk); cp->add_configuration_attribute(cp, ca); - - /* we currently always add a DNS request if we request an IP */ - if (this->initiator) - { - ca = configuration_attribute_create(); - if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET) - { - ca->set_type(ca, INTERNAL_IP4_DNS); - } - else - { - ca->set_type(ca, INTERNAL_IP6_DNS); - } - cp->add_configuration_attribute(cp, ca); - } - else - { - host_t *ip; - iterator_t *iterator; - - /* Add internal DNS servers */ - iterator = this->dns->create_iterator(this->dns, TRUE); - while (iterator->iterate(iterator, (void**)&ip)) - { - ca = configuration_attribute_create(); - if (ip->get_family(ip) == AF_INET) - { - ca->set_type(ca, INTERNAL_IP4_DNS); - } - else - { - ca->set_type(ca, INTERNAL_IP6_DNS); - } - chunk = ip->get_address(ip); - ca->set_value(ca, chunk); - cp->add_configuration_attribute(cp, ca); - } - iterator->destroy(iterator); - - /* Add internal WINS servers */ - iterator = this->nbns->create_iterator(this->nbns, TRUE); - while (iterator->iterate(iterator, (void**)&ip)) - { - ca = configuration_attribute_create(); - if (ip->get_family(ip) == AF_INET) - { - ca->set_type(ca, INTERNAL_IP4_NBNS); - } - else - { - ca->set_type(ca, INTERNAL_IP6_NBNS); - } - chunk = ip->get_address(ip); - ca->set_value(ca, chunk); - cp->add_configuration_attribute(cp, ca); - } - iterator->destroy(iterator); - } - message->add_payload(message, (payload_t*)cp); } /** @@ -203,55 +122,23 @@ static void process_attribute(private_ike_config_t *this, } ip = host_create_from_chunk(family, addr, 0); } - if (ip && !this->virtual_ip) - { - this->virtual_ip = ip; - } - break; - } - case INTERNAL_IP4_DNS: - family = AF_INET; - /* fall */ - case INTERNAL_IP6_DNS: - { - addr = ca->get_value(ca); - if (addr.len == 0) - { - ip = host_create_any(family); - } - else - { - ip = host_create_from_chunk(family, addr, 0); - } if (ip) { - this->dns->insert_last(this->dns, ip); + DESTROY_IF(this->virtual_ip); + this->virtual_ip = ip; } break; } - case INTERNAL_IP4_NBNS: - case INTERNAL_IP6_NBNS: - { - addr = ca->get_value(ca); - if (addr.len == 0) + default: + if (this->initiator) { - ip = host_create_any(family); + this->ike_sa->add_configuration_attribute(this->ike_sa, + ca->get_type(ca), ca->get_value(ca)); } else { - ip = host_create_from_chunk(family, addr, 0); + /* we do not handle attribute requests other than for VIPs */ } - if (ip) - { - this->nbns->insert_last(this->nbns, ip); - } - break; - } - default: - DBG1(DBG_IKE, "ignoring %N config attribute", - configuration_attribute_type_names, - ca->get_type(ca)); - break; } } @@ -260,11 +147,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 +178,7 @@ static void process_payloads(private_ike_config_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -298,9 +186,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; @@ -313,12 +200,28 @@ static status_t build_i(private_ike_config_t *this, message_t *message) } if (vip) { - this->virtual_ip = vip->clone(vip); + configuration_attribute_t *ca; + cp_payload_t *cp; + + cp = cp_payload_create(); + cp->set_config_type(cp, CFG_REQUEST); + + build_vip(this, vip, cp); + + /* we currently always add a DNS request if we request an IP */ + ca = configuration_attribute_create(); + if (vip->get_family(vip) == AF_INET) + { + ca->set_type(ca, INTERNAL_IP4_DNS); + } + else + { + ca->set_type(ca, INTERNAL_IP6_DNS); + } + cp->add_configuration_attribute(cp, ca); + message->add_payload(message, (payload_t*)cp); } - - build_payloads(this, message, CFG_REQUEST); } - return NEED_MORE; } @@ -327,9 +230,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,25 +242,28 @@ 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) { - host_t *ip = NULL; + enumerator_t *enumerator; + configuration_attribute_type_t type; + configuration_attribute_t *ca; + chunk_t value; + cp_payload_t *cp; + host_t *vip = NULL; DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip); if (config->get_pool(config)) { - ip = charon->attributes->acquire_address(charon->attributes, + vip = 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) + if (vip == NULL) { DBG1(DBG_IKE, "no virtual IP found, sending %N", notify_type_names, INTERNAL_ADDRESS_FAILURE); @@ -366,13 +271,28 @@ static status_t build_r(private_ike_config_t *this, message_t *message) chunk_empty); return SUCCESS; } - DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip); - this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, ip); + DBG1(DBG_IKE, "assigning virtual IP %H to peer", vip); + this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); + + cp = cp_payload_create(); + cp->set_config_type(cp, CFG_REPLY); - this->virtual_ip->destroy(this->virtual_ip); - this->virtual_ip = ip; + build_vip(this, vip, cp); + vip->destroy(vip); - build_payloads(this, message, CFG_REPLY); + /* if we add an IP, we also look for other attributes */ + enumerator = charon->attributes->create_attribute_enumerator( + charon->attributes, this->ike_sa->get_other_id(this->ike_sa)); + while (enumerator->enumerate(enumerator, &type, &value)) + { + ca = configuration_attribute_create(); + ca->set_type(ca, type); + ca->set_value(ca, value); + cp->add_configuration_attribute(cp, ca); + } + enumerator->destroy(enumerator); + + message->add_payload(message, (payload_t*)cp); } return SUCCESS; } @@ -384,39 +304,14 @@ 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)) - { - host_t *ip; - peer_cfg_t *config; + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { /* in last IKE_AUTH exchange */ - DESTROY_IF(this->virtual_ip); - this->virtual_ip = NULL; - process_payloads(this, message); - if (this->virtual_ip == NULL) - { /* force a configured virtual IP, even if server didn't return one */ - config = this->ike_sa->get_peer_cfg(this->ike_sa); - this->virtual_ip = config->get_virtual_ip(config); - if (this->virtual_ip) - { - this->virtual_ip = this->virtual_ip->clone(this->virtual_ip); - } - } - - if (this->virtual_ip && !this->virtual_ip->is_anyaddr(this->virtual_ip)) + if (this->virtual_ip) { this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); - - while (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS) - { - if (!ip->is_anyaddr(ip)) - { - this->ike_sa->add_dns_server(this->ike_sa, ip); - } - ip->destroy(ip); - } } return SUCCESS; } @@ -437,11 +332,9 @@ static task_type_t get_type(private_ike_config_t *this) static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa) { DESTROY_IF(this->virtual_ip); - this->dns->destroy_offset(this->dns, offsetof(host_t, destroy)); this->ike_sa = ike_sa; this->virtual_ip = NULL; - this->dns = linked_list_create(); } /** @@ -450,8 +343,6 @@ static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa) static void destroy(private_ike_config_t *this) { DESTROY_IF(this->virtual_ip); - this->dns->destroy_offset(this->dns, offsetof(host_t, destroy)); - this->nbns->destroy_offset(this->nbns, offsetof(host_t, destroy)); free(this); } @@ -461,7 +352,7 @@ static void destroy(private_ike_config_t *this) ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) { private_ike_config_t *this = malloc_thing(private_ike_config_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; @@ -469,9 +360,7 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) this->initiator = initiator; this->ike_sa = ike_sa; this->virtual_ip = NULL; - this->dns = linked_list_create(); - this->nbns = linked_list_create(); - + if (initiator) { this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; @@ -479,49 +368,10 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) } else { - int i; - - /* assign DNS servers */ - for (i = 1; i <= DNS_SERVER_MAX; i++) - { - char dns_key[16], *dns_str; - - snprintf(dns_key, sizeof(dns_key), "charon.dns%d", i); - dns_str = lib->settings->get_str(lib->settings, dns_key, NULL); - if (dns_str) - { - host_t *dns = host_create_from_string(dns_str, 0); - - if (dns) - { - DBG2(DBG_CFG, "assigning DNS server %H to peer", dns); - this->dns->insert_last(this->dns, dns); - } - } - } - - /* assign WINS servers */ - for (i = 1; i <= NBNS_SERVER_MAX; i++) - { - char nbns_key[16], *nbns_str; - - snprintf(nbns_key, sizeof(nbns_key), "charon.nbns%d", i); - nbns_str = lib->settings->get_str(lib->settings, nbns_key, NULL); - if (nbns_str) - { - host_t *nbns = host_create_from_string(nbns_str, 0); - - if (nbns) - { - DBG2(DBG_CFG, "assigning NBNS server %H to peer", nbns); - this->nbns->insert_last(this->nbns, nbns); - } - } - } - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; } - + return &this->public; } + diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h index cc709f4d6..32635e85e 100644 --- a/src/charon/sa/tasks/ike_config.h +++ b/src/charon/sa/tasks/ike_config.h @@ -11,8 +11,6 @@ * 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: ike_config.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c index 1c051853c..f308a6358 100644 --- a/src/charon/sa/tasks/ike_delete.c +++ b/src/charon/sa/tasks/ike_delete.c @@ -11,8 +11,6 @@ * 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: ike_delete.c 4458 2008-10-17 03:44:06Z andreas $ */ #include "ike_delete.h" @@ -56,7 +54,7 @@ static status_t build_i(private_ike_delete_t *this, message_t *message) { delete_payload_t *delete_payload; - DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%D]...%H[%D]", + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", 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), @@ -95,7 +93,7 @@ static status_t process_r(private_ike_delete_t *this, message_t *message) DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa)); - DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%D]...%H[%D]", + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", 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), diff --git a/src/charon/sa/tasks/ike_delete.h b/src/charon/sa/tasks/ike_delete.h index ea4e9832b..82782f393 100644 --- a/src/charon/sa/tasks/ike_delete.h +++ b/src/charon/sa/tasks/ike_delete.h @@ -11,8 +11,6 @@ * 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: ike_delete.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_dpd.c b/src/charon/sa/tasks/ike_dpd.c index 9f1d43cbf..3aa714049 100644 --- a/src/charon/sa/tasks/ike_dpd.c +++ b/src/charon/sa/tasks/ike_dpd.c @@ -11,8 +11,6 @@ * 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: ike_dpd.c 3589 2008-03-13 14:14:44Z martin $ */ #include "ike_dpd.h" diff --git a/src/charon/sa/tasks/ike_dpd.h b/src/charon/sa/tasks/ike_dpd.h index 0eadd0db7..36388d15b 100644 --- a/src/charon/sa/tasks/ike_dpd.h +++ b/src/charon/sa/tasks/ike_dpd.h @@ -11,8 +11,6 @@ * 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: ike_dpd.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c index 139107480..2705f5886 100644 --- a/src/charon/sa/tasks/ike_init.c +++ b/src/charon/sa/tasks/ike_init.c @@ -13,8 +13,6 @@ * 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: ike_init.c 4717 2008-11-28 09:51:44Z martin $ */ #include "ike_init.h" @@ -170,11 +168,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 +180,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 +223,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -317,12 +315,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 +351,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 +456,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 +487,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 +512,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 +522,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_init.h b/src/charon/sa/tasks/ike_init.h index 84f28a98d..8d3810ef2 100644 --- a/src/charon/sa/tasks/ike_init.h +++ b/src/charon/sa/tasks/ike_init.h @@ -11,8 +11,6 @@ * 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: ike_init.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_me.c b/src/charon/sa/tasks/ike_me.c index f58d51341..d359aa339 100644 --- a/src/charon/sa/tasks/ike_me.c +++ b/src/charon/sa/tasks/ike_me.c @@ -11,8 +11,6 @@ * 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: ike_me.c 4640 2008-11-12 16:07:17Z martin $ */ #include "ike_me.h" @@ -166,11 +164,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 +235,7 @@ static void process_payloads(private_ike_me_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -339,7 +337,7 @@ static status_t process_r(private_ike_me_t *this, message_t *message) if (this->callback) { - DBG1(DBG_IKE, "received ME_CALLBACK for '%D'", this->peer_id); + DBG1(DBG_IKE, "received ME_CALLBACK for '%Y'", this->peer_id); break; } @@ -471,7 +469,7 @@ static status_t process_i(private_ike_me_t *this, message_t *message) if (this->failed) { - DBG1(DBG_IKE, "peer '%D' is not online", this->peer_id); + DBG1(DBG_IKE, "peer '%Y' is not online", this->peer_id); /* FIXME: notify the mediated connection (job?) */ } else diff --git a/src/charon/sa/tasks/ike_me.h b/src/charon/sa/tasks/ike_me.h index 3bef0a7f1..4b35c313c 100644 --- a/src/charon/sa/tasks/ike_me.h +++ b/src/charon/sa/tasks/ike_me.h @@ -11,8 +11,6 @@ * 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: ike_me.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index b5e065081..9a1afe744 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -11,8 +11,6 @@ * 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: ike_mobike.c 4816 2008-12-19 14:34:40Z martin $ */ #include "ike_mobike.h" @@ -97,12 +95,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 +179,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -332,9 +330,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 +378,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_mobike.h b/src/charon/sa/tasks/ike_mobike.h index 4a2006a80..919b5ddd3 100644 --- a/src/charon/sa/tasks/ike_mobike.h +++ b/src/charon/sa/tasks/ike_mobike.h @@ -11,8 +11,6 @@ * 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: ike_mobike.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index eb84c876f..bb18e7bda 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -12,8 +12,6 @@ * 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: ike_natd.c 5029 2009-03-26 11:49:07Z martin $ */ #include "ike_natd.h" @@ -166,7 +164,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 +182,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 +233,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_natd.h b/src/charon/sa/tasks/ike_natd.h index 155ae4b4c..698394842 100644 --- a/src/charon/sa/tasks/ike_natd.h +++ b/src/charon/sa/tasks/ike_natd.h @@ -11,8 +11,6 @@ * 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: ike_natd.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c index 61701075f..80f1b7b8c 100644 --- a/src/charon/sa/tasks/ike_reauth.c +++ b/src/charon/sa/tasks/ike_reauth.c @@ -11,8 +11,6 @@ * 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: ike_reauth.c 4495 2008-10-28 16:07:06Z martin $ */ #include "ike_reauth.h" @@ -100,7 +98,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message) /* we initiate the new IKE_SA of the mediation connection without CHILD_SA */ if (peer_cfg->is_mediation(peer_cfg)) { - if (new->initiate(new, NULL) == DESTROY_ME) + if (new->initiate(new, NULL, 0, NULL, NULL) == DESTROY_ME) { charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, new); @@ -128,7 +126,7 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message) /* initiate/queue all child SAs */ child_cfg_t *child_cfg = child_sa->get_config(child_sa); child_cfg->get_ref(child_cfg); - if (new->initiate(new, child_cfg) == DESTROY_ME) + if (new->initiate(new, child_cfg, 0, NULL, NULL) == DESTROY_ME) { iterator->destroy(iterator); charon->ike_sa_manager->checkin_and_destroy( diff --git a/src/charon/sa/tasks/ike_reauth.h b/src/charon/sa/tasks/ike_reauth.h index 689550c92..5e97b719c 100644 --- a/src/charon/sa/tasks/ike_reauth.h +++ b/src/charon/sa/tasks/ike_reauth.h @@ -11,8 +11,6 @@ * 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: ike_reauth.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index e61d161bc..bead408a6 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -12,8 +12,6 @@ * 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: ike_rekey.c 4730 2008-12-01 18:38:28Z martin $ */ #include "ike_rekey.h" @@ -177,7 +175,7 @@ static status_t build_r(private_ike_rekey_t *this, message_t *message) this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->new_sa->get_name(this->new_sa), this->new_sa->get_unique_id(this->new_sa), this->ike_sa->get_my_host(this->ike_sa), @@ -193,13 +191,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 +210,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)) { @@ -235,7 +232,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) DBG1(DBG_IKE, "IKE_SA rekeying failed, " "trying again in %d seconds", retry); this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->scheduler->schedule_job(charon->scheduler, job, retry * 1000); + charon->scheduler->schedule_job(charon->scheduler, job, retry); } return SUCCESS; case NEED_MORE: @@ -245,17 +242,15 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) default: break; } - + this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->new_sa->get_name(this->new_sa), this->new_sa->get_unique_id(this->new_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)); - - to_delete = this->ike_sa->get_id(this->ike_sa); /* check for collisions */ if (this->collision && @@ -273,8 +268,13 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) if (memcmp(this_nonce.ptr, other_nonce.ptr, min(this_nonce.len, other_nonce.len)) < 0) { + /* peer should delete this SA. Add a timeout just in case. */ + job_t *job = (job_t*)delete_ike_sa_job_create( + other->new_sa->get_id(other->new_sa), TRUE); + charon->scheduler->schedule_job(charon->scheduler, job, 10); DBG1(DBG_IKE, "IKE_SA rekey collision won, deleting rekeyed IKE_SA"); charon->ike_sa_manager->checkin(charon->ike_sa_manager, other->new_sa); + other->new_sa = NULL; } else { @@ -285,11 +285,22 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) host = this->ike_sa->get_other_host(this->ike_sa); this->new_sa->set_other_host(this->new_sa, host->clone(host)); this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - to_delete = this->new_sa->get_id(this->new_sa); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa); + if (this->new_sa->delete(this->new_sa) == DESTROY_ME) + { + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, this->new_sa); + } + else + { + charon->ike_sa_manager->checkin( + charon->ike_sa_manager, this->new_sa); + } + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); /* inherit to other->new_sa in destroy() */ this->new_sa = other->new_sa; other->new_sa = NULL; + return SUCCESS; } /* set threads active IKE_SA after checkin */ charon->bus->set_sa(charon->bus, this->ike_sa); diff --git a/src/charon/sa/tasks/ike_rekey.h b/src/charon/sa/tasks/ike_rekey.h index ab82789f3..6748279ab 100644 --- a/src/charon/sa/tasks/ike_rekey.h +++ b/src/charon/sa/tasks/ike_rekey.h @@ -11,8 +11,6 @@ * 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: ike_rekey.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c index fd15379f3..9e35b62a5 100644 --- a/src/charon/sa/tasks/task.c +++ b/src/charon/sa/tasks/task.c @@ -12,8 +12,6 @@ * 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: task.c 4618 2008-11-11 09:22:00Z tobias $ */ #include "task.h" diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h index a5eb2caa3..f9b409f35 100644 --- a/src/charon/sa/tasks/task.h +++ b/src/charon/sa/tasks/task.h @@ -12,8 +12,6 @@ * 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: task.h 5003 2009-03-24 17:43:01Z martin $ */ /** diff --git a/src/charon/sa/trap_manager.c b/src/charon/sa/trap_manager.c new file mode 100644 index 000000000..a74fab93f --- /dev/null +++ b/src/charon/sa/trap_manager.c @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "trap_manager.h" + +#include <daemon.h> +#include <utils/mutex.h> +#include <utils/linked_list.h> + + +typedef struct private_trap_manager_t private_trap_manager_t; +typedef struct trap_listener_t trap_listener_t; + +/** + * listener to track acquires + */ +struct trap_listener_t { + + /** + * Implements listener interface + */ + listener_t listener; + + /** + * points to trap_manager + */ + private_trap_manager_t *traps; +}; + +/** + * Private data of an trap_manager_t object. + */ +struct private_trap_manager_t { + + /** + * Public trap_manager_t interface. + */ + trap_manager_t public; + + /** + * Installed traps, as entry_t + */ + linked_list_t *traps; + + /** + * read write lock for traps list + */ + rwlock_t *lock; + + /** + * listener to track acquiring IKE_SAs + */ + trap_listener_t listener; +}; + +/** + * A installed trap entry + */ +typedef struct { + /** ref to peer_cfg to initiate */ + peer_cfg_t *peer_cfg; + /** ref to instanciated CHILD_SA */ + child_sa_t *child_sa; + /** pending IKE_SA connecting upon acquire */ + ike_sa_t *pending; +} entry_t; + +/** + * actually uninstall and destroy an installed entry + */ +static void destroy_entry(entry_t *entry) +{ + entry->child_sa->destroy(entry->child_sa); + entry->peer_cfg->destroy(entry->peer_cfg); + free(entry); +} + +/** + * Implementation of trap_manager_t.install + */ +static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer, + child_cfg_t *child) +{ + entry_t *entry; + ike_cfg_t *ike_cfg; + child_sa_t *child_sa; + host_t *me, *other; + linked_list_t *my_ts, *other_ts; + enumerator_t *enumerator; + bool found = FALSE; + status_t status; + u_int32_t reqid; + + /* check if not already done */ + this->lock->read_lock(this->lock); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + if (streq(entry->child_sa->get_name(entry->child_sa), + child->get_name(child))) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + if (found) + { + DBG1(DBG_CFG, "CHILD_SA named '%s' already routed", + child->get_name(child)); + return 0; + } + + /* try to resolve addresses */ + ike_cfg = peer->get_ike_cfg(peer); + other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg), + 0, IKEV2_UDP_PORT); + if (!other) + { + DBG1(DBG_CFG, "installing trap failed, remote address unknown"); + return 0; + } + me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg), + other->get_family(other), IKEV2_UDP_PORT); + if (!me || me->is_anyaddr(me)) + { + DESTROY_IF(me); + me = charon->kernel_interface->get_source_addr( + charon->kernel_interface, other, NULL); + if (!me) + { + DBG1(DBG_CFG, "installing trap failed, local address unknown"); + other->destroy(other); + return 0; + } + me->set_port(me, IKEV2_UDP_PORT); + } + + /* create and route CHILD_SA */ + child_sa = child_sa_create(me, other, child, 0, FALSE); + my_ts = child->get_traffic_selectors(child, TRUE, NULL, me); + other_ts = child->get_traffic_selectors(child, FALSE, NULL, other); + me->destroy(me); + other->destroy(other); + + child_sa->set_mode(child_sa, child->get_mode(child)); + status = child_sa->add_policies(child_sa, 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 (status != SUCCESS) + { + child_sa->destroy(child_sa); + DBG1(DBG_CFG, "installing trap failed"); + return 0; + } + + reqid = child_sa->get_reqid(child_sa); + entry = malloc_thing(entry_t); + entry->child_sa = child_sa; + entry->peer_cfg = peer->get_ref(peer); + entry->pending = NULL; + + this->lock->write_lock(this->lock); + this->traps->insert_last(this->traps, entry); + this->lock->unlock(this->lock); + + return reqid; +} + +/** + * Implementation of trap_manager_t.uninstall + */ +static bool uninstall(private_trap_manager_t *this, u_int32_t reqid) +{ + enumerator_t *enumerator; + entry_t *entry, *found = NULL; + + this->lock->write_lock(this->lock); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->child_sa->get_reqid(entry->child_sa) == reqid) + { + this->traps->remove_at(this->traps, enumerator); + found = entry; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + if (!found) + { + DBG1(DBG_CFG, "trap %d not found to uninstall", reqid); + return FALSE; + } + + destroy_entry(found); + return TRUE; +} + +/** + * convert enumerated entries to peer_cfg, child_sa + */ +static bool trap_filter(rwlock_t *lock, entry_t **entry, peer_cfg_t **peer_cfg, + void *none, child_sa_t **child_sa) +{ + if (peer_cfg) + { + *peer_cfg = (*entry)->peer_cfg; + } + if (child_sa) + { + *child_sa = (*entry)->child_sa; + } + return TRUE; +} + +/** + * Implementation of trap_manager_t.create_enumerator + */ +static enumerator_t* create_enumerator(private_trap_manager_t *this) +{ + this->lock->read_lock(this->lock); + return enumerator_create_filter(this->traps->create_enumerator(this->traps), + (void*)trap_filter, this->lock, + (void*)this->lock->unlock); +} + +/** + * Implementation of trap_manager_t.acquire + */ +static void acquire(private_trap_manager_t *this, u_int32_t reqid, + traffic_selector_t *src, traffic_selector_t *dst) +{ + enumerator_t *enumerator; + entry_t *entry, *found = NULL; + peer_cfg_t *peer; + child_cfg_t *child; + ike_sa_t *ike_sa; + + this->lock->read_lock(this->lock); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->child_sa->get_reqid(entry->child_sa) == reqid) + { + found = entry; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid); + } + else if (found->pending) + { + DBG1(DBG_CFG, "ignoring acquire, connection attempt pending"); + } + else + { + child = found->child_sa->get_config(found->child_sa); + peer = found->peer_cfg; + ike_sa = charon->ike_sa_manager->checkout_by_config( + charon->ike_sa_manager, peer); + if (ike_sa->get_peer_cfg(ike_sa) == NULL) + { + ike_sa->set_peer_cfg(ike_sa, peer); + } + child->get_ref(child); + reqid = found->child_sa->get_reqid(found->child_sa); + if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) + { + found->pending = ike_sa; + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + } + this->lock->unlock(this->lock); +} + +/** + * Implementation of listener_t.ike_state_change + */ +static bool ike_state_change(trap_listener_t *listener, ike_sa_t *ike_sa, + ike_sa_state_t state) +{ + private_trap_manager_t *this; + enumerator_t *enumerator; + entry_t *entry; + + switch (state) + { + case IKE_ESTABLISHED: + case IKE_DESTROYING: + break; + default: + return TRUE; + } + + this = listener->traps; + this->lock->read_lock(this->lock); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->pending == ike_sa) + { + entry->pending = NULL; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return TRUE; +} + +/** + * Implementation of trap_manager_t.destroy. + */ +static void destroy(private_trap_manager_t *this) +{ + charon->bus->remove_listener(charon->bus, &this->listener.listener); + this->traps->invoke_function(this->traps, (void*)destroy_entry); + this->traps->destroy(this->traps); + this->lock->destroy(this->lock); + free(this); +} + +/** + * See header + */ +trap_manager_t *trap_manager_create() +{ + private_trap_manager_t *this = malloc_thing(private_trap_manager_t); + + this->public.install = (u_int(*)(trap_manager_t*, peer_cfg_t *peer, child_cfg_t *child))install; + this->public.uninstall = (bool(*)(trap_manager_t*, u_int32_t id))uninstall; + this->public.create_enumerator = (enumerator_t*(*)(trap_manager_t*))create_enumerator; + this->public.acquire = (void(*)(trap_manager_t*, u_int32_t reqid, traffic_selector_t *src, traffic_selector_t *dst))acquire; + this->public.destroy = (void(*)(trap_manager_t*))destroy; + + this->traps = linked_list_create(); + this->lock = rwlock_create(RWLOCK_DEFAULT); + + /* register listener for IKE state changes */ + this->listener.traps = this; + memset(&this->listener.listener, 0, sizeof(listener_t)); + this->listener.listener.ike_state_change = (void*)ike_state_change; + charon->bus->add_listener(charon->bus, &this->listener.listener); + + return &this->public; +} + diff --git a/src/charon/sa/trap_manager.h b/src/charon/sa/trap_manager.h new file mode 100644 index 000000000..cb6907cdc --- /dev/null +++ b/src/charon/sa/trap_manager.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup trap_manager trap_manager + * @{ @ingroup sa + */ + +#ifndef TRAP_MANAGER_H_ +#define TRAP_MANAGER_H_ + +#include <library.h> +#include <utils/enumerator.h> +#include <config/peer_cfg.h> + +typedef struct trap_manager_t trap_manager_t; + +/** + * Manage policies to create SAs from traffic. + */ +struct trap_manager_t { + + /** + * Install a policy as a trap. + * + * @param peer peer configuration to initiate on trap + * @param child child configuration to install as a trap + * @return reqid of installed CHILD_SA, 0 if failed + */ + u_int32_t (*install)(trap_manager_t *this, peer_cfg_t *peer, + child_cfg_t *child); + + /** + * Uninstall a trap policy. + * + * @param id reqid of CHILD_SA to uninstall, returned by install() + * @return TRUE if uninstalled successfully + */ + bool (*uninstall)(trap_manager_t *this, u_int32_t reqid); + + /** + * Create an enumerator over all installed traps. + * + * @return enumerator over (peer_cfg_t, child_sa_t) + */ + enumerator_t* (*create_enumerator)(trap_manager_t *this); + + /** + * Acquire an SA triggered by an installed trap. + * + * @param reqid requid of the triggering CHILD_SA + * @param src source of the triggering packet + * @param dst destination of the triggering packet + */ + void (*acquire)(trap_manager_t *this, u_int32_t reqid, + traffic_selector_t *src, traffic_selector_t *dst); + + /** + * Destroy a trap_manager_t. + */ + void (*destroy)(trap_manager_t *this); +}; + +/** + * Create a trap_manager instance. + */ +trap_manager_t *trap_manager_create(); + +#endif /* TRAP_MANAGER_ @}*/ |