diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-12-05 16:15:54 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-12-05 16:15:54 +0000 |
commit | c7f1b0530b85bc7654e68992f25ed8ced5d0a80d (patch) | |
tree | 861798cd7da646014ed6919766b053099646710d /src/charon/sa | |
parent | 8b80ab5a6950ce6515f477624794defd7531642a (diff) | |
download | vyos-strongswan-c7f1b0530b85bc7654e68992f25ed8ced5d0a80d.tar.gz vyos-strongswan-c7f1b0530b85bc7654e68992f25ed8ced5d0a80d.zip |
[svn-upgrade] Integrating new upstream version, strongswan (4.2.9)
Diffstat (limited to 'src/charon/sa')
27 files changed, 2143 insertions, 1854 deletions
diff --git a/src/charon/sa/authenticators/eap/eap_manager.c b/src/charon/sa/authenticators/eap/eap_manager.c index 44d84156c..c1c2d6fce 100644 --- a/src/charon/sa/authenticators/eap/eap_manager.c +++ b/src/charon/sa/authenticators/eap/eap_manager.c @@ -12,14 +12,13 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: eap_manager.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: eap_manager.c 4579 2008-11-05 11:29:56Z martin $ */ #include "eap_manager.h" -#include <pthread.h> - #include <utils/linked_list.h> +#include <utils/mutex.h> typedef struct private_eap_manager_t private_eap_manager_t; typedef struct eap_entry_t eap_entry_t; @@ -68,7 +67,7 @@ struct private_eap_manager_t { /** * mutex to lock methods */ - pthread_mutex_t mutex; + mutex_t *mutex; }; /** @@ -85,9 +84,9 @@ static void add_method(private_eap_manager_t *this, eap_type_t type, entry->role = role; entry->constructor = constructor; - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); this->methods->insert_last(this->methods, entry); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); } /** @@ -98,7 +97,7 @@ static void remove_method(private_eap_manager_t *this, eap_constructor_t constru enumerator_t *enumerator; eap_entry_t *entry; - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); enumerator = this->methods->create_enumerator(this->methods); while (enumerator->enumerate(enumerator, &entry)) { @@ -109,7 +108,7 @@ static void remove_method(private_eap_manager_t *this, eap_constructor_t constru } } enumerator->destroy(enumerator); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); } /** @@ -124,7 +123,7 @@ static eap_method_t* create_instance(private_eap_manager_t *this, eap_entry_t *entry; eap_method_t *method = NULL; - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); enumerator = this->methods->create_enumerator(this->methods); while (enumerator->enumerate(enumerator, &entry)) { @@ -139,7 +138,7 @@ static eap_method_t* create_instance(private_eap_manager_t *this, } } enumerator->destroy(enumerator); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); return method; } @@ -149,6 +148,7 @@ static eap_method_t* create_instance(private_eap_manager_t *this, static void destroy(private_eap_manager_t *this) { this->methods->destroy_function(this->methods, free); + this->mutex->destroy(this->mutex); free(this); } @@ -165,7 +165,7 @@ eap_manager_t *eap_manager_create() this->public.destroy = (void(*)(eap_manager_t*))destroy; this->methods = linked_list_create(); - pthread_mutex_init(&this->mutex, NULL); + this->mutex = mutex_create(MUTEX_DEFAULT); return &this->public; } diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c index 0909d6563..5c22f3df2 100644 --- a/src/charon/sa/authenticators/eap_authenticator.c +++ b/src/charon/sa/authenticators/eap_authenticator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: eap_authenticator.c 4292 2008-08-26 19:54:47Z andreas $ + * $Id: eap_authenticator.c 4495 2008-10-28 16:07:06Z martin $ */ #include <string.h> @@ -70,36 +70,24 @@ struct private_eap_authenticator_t { */ u_int32_t vendor; }; - -/** - * reuse shared key signature function from PSK authenticator - */ -extern chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce, - chunk_t secret, identification_t *id, - chunk_t skp, prf_t *prf); /** * Implementation of authenticator_t.verify. */ static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init, chunk_t my_nonce, auth_payload_t *auth_payload) { - chunk_t auth_data, recv_auth_data, secret; - identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa); + chunk_t auth_data, recv_auth_data; + identification_t *other_id; + keymat_t *keymat; - if (this->msk.len) - { /* use MSK if EAP method established one... */ - secret = this->msk; - } - else - { /* ... or use SKp if not */ - secret = this->ike_sa->get_skp_verify(this->ike_sa); - } - auth_data = build_shared_key_signature(ike_sa_init, my_nonce, secret, - other_id, this->ike_sa->get_skp_verify(this->ike_sa), - this->ike_sa->get_prf(this->ike_sa)); + 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); recv_auth_data = auth_payload->get_data(auth_payload); - if (!chunk_equals(auth_data, recv_auth_data)) + if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data)) { DBG1(DBG_IKE, "verification of AUTH payload created from EAP MSK failed"); chunk_free(&auth_data); @@ -118,23 +106,18 @@ static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init, static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init, chunk_t other_nonce, auth_payload_t **auth_payload) { - chunk_t auth_data, secret; - identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa); + 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); - - if (this->msk.len) - { /* use MSK if EAP method established one... */ - secret = this->msk; - } - else - { /* ... or use SKp if not */ - secret = this->ike_sa->get_skp_build(this->ike_sa); - } - auth_data = build_shared_key_signature(ike_sa_init, other_nonce, secret, - my_id, this->ike_sa->get_skp_build(this->ike_sa), - this->ike_sa->get_prf(this->ike_sa)); + + 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); diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c index d003dc2c9..ae5a66479 100644 --- a/src/charon/sa/authenticators/psk_authenticator.c +++ b/src/charon/sa/authenticators/psk_authenticator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: psk_authenticator.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: psk_authenticator.c 4495 2008-10-28 16:07:06Z martin $ */ #include <string.h> @@ -23,12 +23,6 @@ #include <daemon.h> #include <credentials/auth_info.h> -/** - * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE. - */ -#define IKEV2_KEY_PAD "Key Pad for IKEv2" -#define IKEV2_KEY_PAD_LENGTH 17 - typedef struct private_psk_authenticator_t private_psk_authenticator_t; @@ -49,55 +43,6 @@ struct private_psk_authenticator_t { }; /** - * Builds the octets to be signed as described in section 2.15 of RFC 4306 - */ -chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce, - identification_t *id, prf_t *prf) -{ - u_int8_t id_header_buf[] = {0x00, 0x00, 0x00, 0x00}; - chunk_t id_header = chunk_from_buf(id_header_buf); - chunk_t id_with_header, id_prfd, id_encoding; - - id_header_buf[0] = id->get_type(id); - id_encoding = id->get_encoding(id); - - id_with_header = chunk_cat("cc", id_header, id_encoding); - prf->allocate_bytes(prf, id_with_header, &id_prfd); - chunk_free(&id_with_header); - - return chunk_cat("ccm", ike_sa_init, nonce, id_prfd); -} - -/** - * Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE. - */ -chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce, - chunk_t secret, identification_t *id, - chunk_t skp, prf_t *prf) -{ - chunk_t key_pad, key, auth_data, octets; - - prf->set_key(prf, skp); - octets = build_tbs_octets(ike_sa_init, nonce, id, prf); - /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */ - key_pad.ptr = IKEV2_KEY_PAD; - key_pad.len = IKEV2_KEY_PAD_LENGTH; - prf->set_key(prf, secret); - prf->allocate_bytes(prf, key_pad, &key); - prf->set_key(prf, key); - prf->allocate_bytes(prf, octets, &auth_data); - DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets); - DBG3(DBG_IKE, "secret %B", &secret); - DBG3(DBG_IKE, "keypad %B", &key_pad); - DBG3(DBG_IKE, "prf(secret, keypad) %B", &key); - DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &auth_data); - chunk_free(&octets); - chunk_free(&key); - - return auth_data; -} - -/** * Implementation of authenticator_t.verify. */ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, @@ -105,25 +50,25 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, { chunk_t auth_data, recv_auth_data; identification_t *my_id, *other_id; - shared_key_t *shared_key; + shared_key_t *key; enumerator_t *enumerator; bool authenticated = FALSE; int keys_found = 0; + keymat_t *keymat; + 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); other_id = this->ike_sa->get_other_id(this->ike_sa); enumerator = charon->credentials->create_shared_enumerator( charon->credentials, SHARED_IKE, my_id, other_id); - while (!authenticated && enumerator->enumerate(enumerator, &shared_key, NULL, NULL)) + while (!authenticated && enumerator->enumerate(enumerator, &key, NULL, NULL)) { keys_found++; - auth_data = build_shared_key_signature(ike_sa_init, my_nonce, - shared_key->get_key(shared_key), other_id, - this->ike_sa->get_skp_verify(this->ike_sa), - this->ike_sa->get_prf(this->ike_sa)); - recv_auth_data = auth_payload->get_data(auth_payload); - if (auth_data.len == recv_auth_data.len && - memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len)) + + auth_data = keymat->get_psk_sig(keymat, TRUE, ike_sa_init, my_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", other_id, auth_method_names, AUTH_PSK); @@ -153,26 +98,26 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init, chunk_t other_nonce, auth_payload_t **auth_payload) { - shared_key_t *shared_key; - chunk_t auth_data; 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); - shared_key = charon->credentials->get_shared(charon->credentials, SHARED_IKE, - my_id, other_id); - if (shared_key == NULL) + 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 = build_shared_key_signature(ike_sa_init, other_nonce, - shared_key->get_key(shared_key), my_id, - this->ike_sa->get_skp_build(this->ike_sa), - this->ike_sa->get_prf(this->ike_sa)); - shared_key->destroy(shared_key); + 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); diff --git a/src/charon/sa/authenticators/pubkey_authenticator.c b/src/charon/sa/authenticators/pubkey_authenticator.c index 2c02ca84c..c16f3b888 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-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: pubkey_authenticator.c 4054 2008-06-10 20:31:53Z andreas $ + * $Id: pubkey_authenticator.c 4495 2008-10-28 16:07:06Z martin $ */ #include <string.h> @@ -44,12 +44,6 @@ struct private_pubkey_authenticator_t { }; /** - * Function implemented in psk_authenticator.c - */ -extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce, - identification_t *id, prf_t *prf); - -/** * Implementation of authenticator_t.verify. */ static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init, @@ -58,15 +52,15 @@ static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init public_key_t *public; auth_method_t auth_method; chunk_t auth_data, octets; - identification_t *other_id; - prf_t *prf; + 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; - other_id = this->ike_sa->get_other_id(this->ike_sa); + id = this->ike_sa->get_other_id(this->ike_sa); auth_method = auth_payload->get_auth_method(auth_payload); switch (auth_method) { @@ -89,19 +83,17 @@ static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init return INVALID_ARG; } auth_data = auth_payload->get_data(auth_payload); - prf = this->ike_sa->get_prf(this->ike_sa); - prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa)); - octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf); - + 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, other_id, auth); + 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", - other_id, auth_method_names, auth_method); + id, auth_method_names, auth_method); status = SUCCESS; auth->merge(auth, current_auth); break; @@ -125,19 +117,19 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init, chunk_t octets, auth_data; status_t status = FAILED; private_key_t *private; - identification_t *my_id; - prf_t *prf; + identification_t *id; auth_info_t *auth; auth_method_t auth_method; signature_scheme_t scheme; + keymat_t *keymat; - my_id = this->ike_sa->get_my_id(this->ike_sa); + id = this->ike_sa->get_my_id(this->ike_sa); auth = this->ike_sa->get_my_auth(this->ike_sa); private = charon->credentials->get_private(charon->credentials, KEY_ANY, - my_id, auth); + id, auth); if (private == NULL) { - DBG1(DBG_IKE, "no private key found for '%D'", my_id); + DBG1(DBG_IKE, "no private key found for '%D'", id); return NOT_FOUND; } @@ -176,9 +168,8 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init, key_type_names, private->get_type(private)); return status; } - prf = this->ike_sa->get_prf(this->ike_sa); - prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa)); - octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf); + keymat = this->ike_sa->get_keymat(this->ike_sa); + octets = keymat->get_auth_octets(keymat, FALSE, ike_sa_init, other_nonce, id); if (private->sign(private, scheme, octets, &auth_data)) { @@ -189,9 +180,9 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init, chunk_free(&auth_data); status = SUCCESS; } - DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", my_id, - auth_method_names, auth_method, - (status == SUCCESS)? "successful":"failed"); + DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", id, + auth_method_names, auth_method, + (status == SUCCESS)? "successful":"failed"); chunk_free(&octets); private->destroy(private); diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 7c4b398cf..d7a63d5e8 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2006-2008 Tobias Brunner - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_sa.c 4358 2008-09-25 13:56:23Z tobias $ + * $Id: child_sa.c 4665 2008-11-17 00:01:34Z andreas $ */ #define _GNU_SOURCE @@ -23,36 +23,21 @@ #include <stdio.h> #include <string.h> +#include <time.h> #include <daemon.h> -ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DELETING, +ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING, "CREATED", "ROUTED", + "INSTALLING", "INSTALLED", + "UPDATING", "REKEYING", "DELETING", + "DESTROYING", ); -typedef struct sa_policy_t sa_policy_t; - -/** - * Struct used to store information for a policy. This - * is needed since we must provide all this information - * for deleting a policy... - */ -struct sa_policy_t { - /** - * Traffic selector for us - */ - traffic_selector_t *my_ts; - - /** - * Traffic selector for other - */ - traffic_selector_t *other_ts; -}; - typedef struct private_child_sa_t private_child_sa_t; /** @@ -64,83 +49,77 @@ struct private_child_sa_t { */ child_sa_t public; - struct { - /** address of peer */ - host_t *addr; - /** id of peer */ - identification_t *id; - /** actual used SPI, 0 if unused */ - u_int32_t spi; - /** Compression Parameter Index (CPI) used, 0 if unused */ - u_int16_t cpi; - } me, other; - /** - * Allocated SPI for a ESP proposal candidates + * address of us */ - u_int32_t alloc_esp_spi; + host_t *my_addr; /** - * Allocated SPI for a AH proposal candidates + * address of remote */ - u_int32_t alloc_ah_spi; + host_t *other_addr; /** - * Protocol used to protect this SA, ESP|AH + * our actually used SPI, 0 if unused */ - protocol_id_t protocol; + u_int32_t my_spi; /** - * List containing sa_policy_t objects + * others used SPI, 0 if unused */ - linked_list_t *policies; + u_int32_t other_spi; /** - * Seperate list for local traffic selectors + * our Compression Parameter Index (CPI) used, 0 if unused */ - linked_list_t *my_ts; + u_int16_t my_cpi; /** - * Seperate list for remote traffic selectors + * others Compression Parameter Index (CPI) used, 0 if unused */ - linked_list_t *other_ts; + u_int16_t other_cpi; /** - * reqid used for this child_sa + * List for local traffic selectors */ - u_int32_t reqid; + linked_list_t *my_ts; /** - * encryption algorithm used for this SA + * List for remote traffic selectors */ - u_int16_t enc_alg; + linked_list_t *other_ts; /** - * key size of enc_alg + * Allocated SPI for a ESP proposal candidates */ - u_int16_t enc_size; + u_int32_t alloc_esp_spi; /** - * integrity protection algorithm used for this SA + * Allocated SPI for a AH proposal candidates */ - u_int16_t int_alg; + u_int32_t alloc_ah_spi; /** - * key size of int_alg + * Protocol used to protect this SA, ESP|AH */ - u_int16_t int_size; + protocol_id_t protocol; /** - * time, on which SA was installed + * reqid used for this child_sa */ - time_t install_time; + u_int32_t reqid; /** - * absolute time when rekeying is sceduled + * absolute time when rekeying is scheduled */ time_t rekey_time; /** + * absolute time when the SA expires + */ + time_t expire_time; + + /** * state of the CHILD_SA */ child_sa_state_t state; @@ -166,23 +145,18 @@ struct private_child_sa_t { ipsec_mode_t mode; /** - * virtual IP assinged to local host - */ - host_t *virtual_ip; + * selected proposal + */ + proposal_t *proposal; /** * config used to create this child */ child_cfg_t *config; - - /** - * cached interface name for iptables - */ - char *iface; }; /** - * Implementation of child_sa_t.get_name. + * Implementation of child_sa_t.get_name */ static char *get_name(private_child_sa_t *this) { @@ -202,11 +176,7 @@ static u_int32_t get_reqid(private_child_sa_t *this) */ u_int32_t get_spi(private_child_sa_t *this, bool inbound) { - if (inbound) - { - return this->me.spi; - } - return this->other.spi; + return inbound ? this->my_spi : this->other_spi; } /** @@ -214,11 +184,7 @@ u_int32_t get_spi(private_child_sa_t *this, bool inbound) */ u_int16_t get_cpi(private_child_sa_t *this, bool inbound) { - if (inbound) - { - return this->me.cpi; - } - return this->other.cpi; + return inbound ? this->my_cpi : this->other_cpi; } /** @@ -230,6 +196,30 @@ protocol_id_t get_protocol(private_child_sa_t *this) } /** + * Implementation of child_sa_t.get_mode + */ +static ipsec_mode_t get_mode(private_child_sa_t *this) +{ + return this->mode; +} + +/** + * Implementation of child_sa_t.has_encap + */ +static bool has_encap(private_child_sa_t *this) +{ + return this->encap; +} + +/** + * Implementation of child_sa_t.get_ipcomp + */ +static ipcomp_transform_t get_ipcomp(private_child_sa_t *this) +{ + return this->ipcomp; +} + +/** * Implements child_sa_t.get_state */ static child_sa_state_t get_state(private_child_sa_t *this) @@ -245,207 +235,134 @@ static child_cfg_t* get_config(private_child_sa_t *this) return this->config; } +typedef struct policy_enumerator_t policy_enumerator_t; + /** - * Implementation of child_sa_t.get_stats. + * Private policy enumerator */ -static void get_stats(private_child_sa_t *this, ipsec_mode_t *mode, - encryption_algorithm_t *encr_algo, size_t *encr_len, - integrity_algorithm_t *int_algo, size_t *int_len, - u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out, - u_int32_t *use_fwd) +struct policy_enumerator_t { + /** implements enumerator_t */ + enumerator_t public; + /** enumerator over own TS */ + enumerator_t *mine; + /** enumerator over others TS */ + enumerator_t *other; + /** list of others TS, to recreate enumerator */ + linked_list_t *list; + /** currently enumerating TS for "me" side */ + traffic_selector_t *ts; +}; + +/** + * enumerator function of create_policy_enumerator() + */ +static bool policy_enumerate(policy_enumerator_t *this, + traffic_selector_t **my_out, traffic_selector_t **other_out) { - sa_policy_t *policy; - iterator_t *iterator; - u_int32_t in = 0, out = 0, fwd = 0, time; + traffic_selector_t *other_ts; - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) + while (this->ts || this->mine->enumerate(this->mine, &this->ts)) { - - if (charon->kernel_interface->query_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_IN, &time) == SUCCESS) - { - in = max(in, time); + if (!this->other->enumerate(this->other, &other_ts)) + { /* end of others list, restart with new of mine */ + this->other->destroy(this->other); + this->other = this->list->create_enumerator(this->list); + this->ts = NULL; + continue; } - if (charon->kernel_interface->query_policy(charon->kernel_interface, - policy->my_ts, policy->other_ts, POLICY_OUT, &time) == SUCCESS) - { - out = max(out, time); + if (this->ts->get_type(this->ts) != other_ts->get_type(other_ts)) + { /* family mismatch */ + continue; } - if (charon->kernel_interface->query_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_FWD, &time) == SUCCESS) - { - fwd = max(fwd, time); + if (this->ts->get_protocol(this->ts) && + other_ts->get_protocol(other_ts) && + this->ts->get_protocol(this->ts) != other_ts->get_protocol(other_ts)) + { /* protocol mismatch */ + continue; } + *my_out = this->ts; + *other_out = other_ts; + return TRUE; } - iterator->destroy(iterator); + return FALSE; +} - *mode = this->mode; - *encr_algo = this->enc_alg; - *encr_len = this->enc_size; - *int_algo = this->int_alg; - *int_len = this->int_size; - *rekey = this->rekey_time; - *use_in = in; - *use_out = out; - *use_fwd = fwd; +/** + * destroy function of create_policy_enumerator() + */ +static void policy_destroy(policy_enumerator_t *this) +{ + this->mine->destroy(this->mine); + this->other->destroy(this->other); + free(this); } /** - * Run the up/down script + * Implementation of child_sa_t.create_policy_enumerator */ -static void updown(private_child_sa_t *this, bool up) +static enumerator_t* create_policy_enumerator(private_child_sa_t *this) { - sa_policy_t *policy; - iterator_t *iterator; - char *script; - - script = this->config->get_updown(this->config); + policy_enumerator_t *e = malloc_thing(policy_enumerator_t); - if (script == NULL) - { - return; - } + e->public.enumerate = (void*)policy_enumerate; + e->public.destroy = (void*)policy_destroy; + e->mine = this->my_ts->create_enumerator(this->my_ts); + e->other = this->other_ts->create_enumerator(this->other_ts); + e->list = this->other_ts; + e->ts = NULL; - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) - { - char command[1024]; - char *my_client, *other_client, *my_client_mask, *other_client_mask; - char *pos, *virtual_ip; - FILE *shell; - - /* get subnet/bits from string */ - asprintf(&my_client, "%R", policy->my_ts); - pos = strchr(my_client, '/'); - *pos = '\0'; - my_client_mask = pos + 1; - pos = strchr(my_client_mask, '['); - if (pos) - { - *pos = '\0'; - } - asprintf(&other_client, "%R", policy->other_ts); - pos = strchr(other_client, '/'); - *pos = '\0'; - other_client_mask = pos + 1; - pos = strchr(other_client_mask, '['); - if (pos) - { - *pos = '\0'; - } - - if (this->virtual_ip) - { - asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", - this->virtual_ip); - } - else - { - asprintf(&virtual_ip, ""); - } + return &e->public; +} - /* we cache the iface name, as it may not be available when - * the SA gets deleted */ - if (up) - { - free(this->iface); - this->iface = charon->kernel_interface->get_interface( - charon->kernel_interface, this->me.addr); - } - - /* build the command with all env variables. - * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing - */ - snprintf(command, sizeof(command), - "2>&1 " - "PLUTO_VERSION='1.1' " - "PLUTO_VERB='%s%s%s' " - "PLUTO_CONNECTION='%s' " - "PLUTO_INTERFACE='%s' " - "PLUTO_REQID='%u' " - "PLUTO_ME='%H' " - "PLUTO_MY_ID='%D' " - "PLUTO_MY_CLIENT='%s/%s' " - "PLUTO_MY_CLIENT_NET='%s' " - "PLUTO_MY_CLIENT_MASK='%s' " - "PLUTO_MY_PORT='%u' " - "PLUTO_MY_PROTOCOL='%u' " - "PLUTO_PEER='%H' " - "PLUTO_PEER_ID='%D' " - "PLUTO_PEER_CLIENT='%s/%s' " - "PLUTO_PEER_CLIENT_NET='%s' " - "PLUTO_PEER_CLIENT_MASK='%s' " - "PLUTO_PEER_PORT='%u' " - "PLUTO_PEER_PROTOCOL='%u' " - "%s" - "%s" - "%s", - up ? "up" : "down", - policy->my_ts->is_host(policy->my_ts, - this->me.addr) ? "-host" : "-client", - this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-v6", - this->config->get_name(this->config), - this->iface ? this->iface : "unknown", - this->reqid, - this->me.addr, - this->me.id, - my_client, my_client_mask, - my_client, my_client_mask, - policy->my_ts->get_from_port(policy->my_ts), - policy->my_ts->get_protocol(policy->my_ts), - this->other.addr, - this->other.id, - other_client, other_client_mask, - other_client, other_client_mask, - policy->other_ts->get_from_port(policy->other_ts), - policy->other_ts->get_protocol(policy->other_ts), - virtual_ip, - this->config->get_hostaccess(this->config) ? - "PLUTO_HOST_ACCESS='1' " : "", - script); - free(my_client); - free(other_client); - free(virtual_ip); - - DBG3(DBG_CHD, "running updown script: %s", command); - shell = popen(command, "r"); +/** + * Implementation of child_sa_t.get_usetime + */ +static u_int32_t get_usetime(private_child_sa_t *this, bool inbound) +{ + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; + u_int32_t last_use = 0; - if (shell == NULL) - { - DBG1(DBG_CHD, "could not execute updown script '%s'", script); - return; - } + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + u_int32_t in, out, fwd; - while (TRUE) + if (inbound) { - char resp[128]; - - if (fgets(resp, sizeof(resp), shell) == NULL) + if (charon->kernel_interface->query_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_IN, &in) == SUCCESS) { - if (ferror(shell)) - { - DBG1(DBG_CHD, "error reading output from updown script"); - return; - } - else + last_use = max(last_use, in); + } + if (this->mode != MODE_TRANSPORT) + { + if (charon->kernel_interface->query_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_FWD, &fwd) == SUCCESS) { - break; + last_use = max(last_use, fwd); } } - else + } + else + { + if (charon->kernel_interface->query_policy(charon->kernel_interface, + my_ts, other_ts, POLICY_OUT, &out) == SUCCESS) { - char *e = resp + strlen(resp); - if (e > resp && e[-1] == '\n') - { /* trim trailing '\n' */ - e[-1] = '\0'; - } - DBG1(DBG_CHD, "updown: %s", resp); + last_use = max(last_use, out); } } - pclose(shell); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); + return last_use; +} + +/** + * Implementation of child_sa_t.get_lifetime + */ +static u_int32_t get_lifetime(private_child_sa_t *this, bool hard) +{ + return hard ? this->expire_time : this->rekey_time; } /** @@ -453,11 +370,8 @@ static void updown(private_child_sa_t *this, bool up) */ static void set_state(private_child_sa_t *this, child_sa_state_t state) { + charon->bus->child_state_change(charon->bus, &this->public, state); this->state = state; - if (state == CHILD_INSTALLED) - { - updown(this, TRUE); - } } /** @@ -474,7 +388,7 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal) { if (charon->kernel_interface->get_spi( charon->kernel_interface, - this->other.addr, this->me.addr, + this->other_addr, this->my_addr, PROTO_AH, this->reqid, &this->alloc_ah_spi) != SUCCESS) { @@ -490,7 +404,7 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal) { if (charon->kernel_interface->get_spi( charon->kernel_interface, - this->other.addr, this->me.addr, + this->other_addr, this->my_addr, PROTO_ESP, this->reqid, &this->alloc_esp_spi) != SUCCESS) { @@ -502,7 +416,6 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal) return SUCCESS; } - /** * Implements child_sa_t.alloc */ @@ -525,237 +438,213 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) return SUCCESS; } +/** + * Install an SA for one direction + */ static status_t install(private_child_sa_t *this, proposal_t *proposal, - ipsec_mode_t mode, prf_plus_t *prf_plus, bool mine) + ipsec_mode_t mode, chunk_t integ, chunk_t encr, bool in) { - u_int32_t spi, soft, hard; - host_t *src; - host_t *dst; + u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size; + u_int32_t spi, soft, hard, now; + host_t *src, *dst; status_t status; - this->protocol = proposal->get_protocol(proposal); - - /* now we have to decide which spi to use. Use self allocated, if "mine", - * or the one in the proposal, if not "mine" (others). Additionally, + /* now we have to decide which spi to use. Use self allocated, if "in", + * or the one in the proposal, if not "in" (others). Additionally, * source and dest host switch depending on the role */ - if (mine) + if (in) { /* if we have allocated SPIs for AH and ESP, we must delete the unused * one. */ if (this->protocol == PROTO_ESP) { - this->me.spi = this->alloc_esp_spi; + this->my_spi = this->alloc_esp_spi; if (this->alloc_ah_spi) { - charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, - this->alloc_ah_spi, PROTO_AH); + charon->kernel_interface->del_sa(charon->kernel_interface, + this->my_addr, this->alloc_ah_spi, 0, PROTO_AH); } } else { - this->me.spi = this->alloc_ah_spi; + this->my_spi = this->alloc_ah_spi; if (this->alloc_esp_spi) { - charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, - this->alloc_esp_spi, PROTO_ESP); + charon->kernel_interface->del_sa(charon->kernel_interface, + this->my_addr, this->alloc_esp_spi, 0, PROTO_ESP); } } - spi = this->me.spi; - dst = this->me.addr; - src = this->other.addr; + spi = this->my_spi; + dst = this->my_addr; + src = this->other_addr; } else { - this->other.spi = proposal->get_spi(proposal); - spi = this->other.spi; - src = this->me.addr; - dst = this->other.addr; + this->other_spi = proposal->get_spi(proposal); + spi = this->other_spi; + src = this->my_addr; + dst = this->other_addr; } - DBG2(DBG_CHD, "adding %s %N SA", mine ? "inbound" : "outbound", + DBG2(DBG_CHD, "adding %s %N SA", in ? "inbound" : "outbound", protocol_id_names, this->protocol); - /* select encryption algo */ - if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, - &this->enc_alg, &this->enc_size)) - { - DBG2(DBG_CHD, " using %N for encryption", - encryption_algorithm_names, this->enc_alg); - } - - /* select integrity algo */ - if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, - &this->int_alg, &this->int_size)) - { - DBG2(DBG_CHD, " using %N for integrity", - integrity_algorithm_names, this->int_alg); - } - soft = this->config->get_lifetime(this->config, TRUE); - hard = this->config->get_lifetime(this->config, FALSE); - /* send SA down to the kernel */ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst); - if (this->ipcomp != IPCOMP_NONE) - { - /* we install an additional IPComp SA */ - u_int32_t cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi)); - status = charon->kernel_interface->add_sa(charon->kernel_interface, - src, dst, cpi, IPPROTO_COMP, this->reqid, 0, 0, - ENCR_UNDEFINED, 0, AUTH_UNDEFINED, 0, NULL, mode, - this->ipcomp, FALSE, mine); - } + proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, &size); + proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_alg, &size); + soft = this->config->get_lifetime(this->config, TRUE); + hard = this->config->get_lifetime(this->config, FALSE); + status = charon->kernel_interface->add_sa(charon->kernel_interface, - src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, - this->enc_alg, this->enc_size, this->int_alg, this->int_size, - prf_plus, mode, IPCOMP_NONE, this->encap, mine); - - this->install_time = time(NULL); - this->rekey_time = this->install_time + soft; + src, dst, spi, this->protocol, this->reqid, + in ? soft : 0, hard, enc_alg, encr, int_alg, integ, + mode, this->ipcomp, in ? this->my_cpi : this->other_cpi, + this->encap, in); + + now = time(NULL); + this->rekey_time = now + soft; + this->expire_time = now + hard; return status; } -static status_t add(private_child_sa_t *this, proposal_t *proposal, - ipsec_mode_t mode, prf_plus_t *prf_plus) +/** + * Implementation of child_sa_t.add + */ +static status_t add(private_child_sa_t *this, + proposal_t *proposal, ipsec_mode_t mode, + chunk_t integ_in, chunk_t integ_out, + chunk_t encr_in, chunk_t encr_out) { - u_int32_t outbound_spi, inbound_spi; - - /* backup outbound spi, as alloc overwrites it */ - outbound_spi = proposal->get_spi(proposal); + this->proposal = proposal->clone(proposal); + this->protocol = proposal->get_protocol(proposal); - /* get SPIs inbound SAs */ + /* get SPIs for inbound SAs, write to proposal */ if (alloc_proposal(this, proposal) != SUCCESS) { return FAILED; } - inbound_spi = proposal->get_spi(proposal); - - /* install inbound SAs */ - if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS) + /* install inbound SAs using allocated SPI */ + if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS) { return FAILED; } - - /* install outbound SAs, restore spi*/ - proposal->set_spi(proposal, outbound_spi); - if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS) + /* install outbound SAs using received SPI*/ + if (install(this, this->proposal, mode, integ_out, encr_out, FALSE) != SUCCESS) { return FAILED; } - proposal->set_spi(proposal, inbound_spi); - return SUCCESS; } -static status_t update(private_child_sa_t *this, proposal_t *proposal, - ipsec_mode_t mode, prf_plus_t *prf_plus) +/** + * Implementation of child_sa_t.update + */ +static status_t update(private_child_sa_t *this, + proposal_t *proposal, ipsec_mode_t mode, + chunk_t integ_in, chunk_t integ_out, + chunk_t encr_in, chunk_t encr_out) { - u_int32_t inbound_spi; - - /* backup received spi, as install() overwrites it */ - inbound_spi = proposal->get_spi(proposal); + this->proposal = proposal->clone(proposal); + this->protocol = proposal->get_protocol(proposal); /* install outbound SAs */ - if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS) + if (install(this, proposal, mode, integ_out, encr_out, FALSE) != SUCCESS) { return FAILED; } - - /* restore spi */ - proposal->set_spi(proposal, inbound_spi); /* install inbound SAs */ - if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS) + if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS) { return FAILED; } - return SUCCESS; } +/** + * Implementation of child_sa_t.get_proposal + */ +static proposal_t* get_proposal(private_child_sa_t *this) +{ + return this->proposal; +} + +/** + * Implementation of child_sa_t.add_policies + */ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list, ipsec_mode_t mode, protocol_id_t proto) { - iterator_t *my_iter, *other_iter; + enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; - /* use low prio for ROUTED policies */ - bool high_prio = (this->state != CHILD_CREATED); + status_t status = SUCCESS; + bool routed = (this->state == CHILD_CREATED); if (this->protocol == PROTO_NONE) { /* update if not set yet */ this->protocol = proto; } + + /* apply traffic selectors */ + enumerator = my_ts_list->create_enumerator(my_ts_list); + while (enumerator->enumerate(enumerator, &my_ts)) + { + this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts)); + } + enumerator->destroy(enumerator); + enumerator = other_ts_list->create_enumerator(other_ts_list); + while (enumerator->enumerate(enumerator, &other_ts)) + { + this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts)); + } + enumerator->destroy(enumerator); - /* iterate over both lists */ - my_iter = my_ts_list->create_iterator(my_ts_list, TRUE); - other_iter = other_ts_list->create_iterator(other_ts_list, TRUE); - while (my_iter->iterate(my_iter, (void**)&my_ts)) + if (this->config->install_policy(this->config)) { - other_iter->reset(other_iter); - while (other_iter->iterate(other_iter, (void**)&other_ts)) + /* enumerate pairs of traffic selectors */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - /* set up policies for every entry in my_ts_list to every entry in other_ts_list */ - status_t status; - sa_policy_t *policy; - - if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts)) - { - DBG2(DBG_CHD, - "CHILD_SA policy uses two different IP families - ignored"); - continue; - } - - /* only set up policies if protocol matches, or if one is zero (any) */ - if (my_ts->get_protocol(my_ts) != other_ts->get_protocol(other_ts) && - my_ts->get_protocol(my_ts) && other_ts->get_protocol(other_ts)) - { - DBG2(DBG_CHD, - "CHILD_SA policy uses two different protocols - ignored"); - continue; - } - /* install 3 policies: out, in and forward */ - status = charon->kernel_interface->add_policy(charon->kernel_interface, - this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT, - this->protocol, this->reqid, high_prio, mode, this->ipcomp); - status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN, - this->protocol, this->reqid, high_prio, mode, this->ipcomp); + this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT, + this->other_spi, this->protocol, this->reqid, mode, this->ipcomp, + this->other_cpi, routed); status |= charon->kernel_interface->add_policy(charon->kernel_interface, - this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD, - this->protocol, this->reqid, high_prio, mode, this->ipcomp); + this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN, + this->my_spi, this->protocol, this->reqid, mode, this->ipcomp, + this->my_cpi, routed); + if (mode != MODE_TRANSPORT) + { + status |= charon->kernel_interface->add_policy(charon->kernel_interface, + this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD, + this->my_spi, this->protocol, this->reqid, mode, this->ipcomp, + this->my_cpi, routed); + } if (status != SUCCESS) { - my_iter->destroy(my_iter); - other_iter->destroy(other_iter); - return status; + break; } - - /* store policy to delete/update them later */ - policy = malloc_thing(sa_policy_t); - policy->my_ts = my_ts->clone(my_ts); - policy->other_ts = other_ts->clone(other_ts); - this->policies->insert_last(this->policies, policy); - /* add to separate list to query them via get_*_traffic_selectors() */ - this->my_ts->insert_last(this->my_ts, policy->my_ts); - this->other_ts->insert_last(this->other_ts, policy->other_ts); } + enumerator->destroy(enumerator); } - my_iter->destroy(my_iter); - other_iter->destroy(other_iter); - /* switch to routed state if no SAD entry set up */ - if (this->state == CHILD_CREATED) + if (status == SUCCESS) { - this->state = CHILD_ROUTED; + /* switch to routed state if no SAD entry set up */ + if (this->state == CHILD_CREATED) + { + set_state(this, CHILD_ROUTED); + } + /* needed to update hosts */ + this->mode = mode; } - /* needed to update hosts */ - this->mode = mode; - return SUCCESS; + return status; } /** @@ -763,166 +652,143 @@ static status_t add_policies(private_child_sa_t *this, */ static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local) { - if (local) - { - return this->my_ts; - } - return this->other_ts; -} - -/** - * Implementation of child_sa_t.get_use_time - */ -static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use_time) -{ - iterator_t *iterator; - sa_policy_t *policy; - status_t status = FAILED; - - *use_time = UNDEFINED_TIME; - - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) - { - if (inbound) - { - time_t in = UNDEFINED_TIME, fwd = UNDEFINED_TIME; - - status = charon->kernel_interface->query_policy( - charon->kernel_interface, - policy->other_ts, policy->my_ts, - POLICY_IN, (u_int32_t*)&in); - status |= charon->kernel_interface->query_policy( - charon->kernel_interface, - policy->other_ts, policy->my_ts, - POLICY_FWD, (u_int32_t*)&fwd); - *use_time = max(in, fwd); - } - else - { - status = charon->kernel_interface->query_policy( - charon->kernel_interface, - policy->my_ts, policy->other_ts, - POLICY_OUT, (u_int32_t*)use_time); - } - } - iterator->destroy(iterator); - return status; + return local ? this->my_ts : this->other_ts; } /** * Implementation of child_sa_t.update_hosts. */ static status_t update_hosts(private_child_sa_t *this, - host_t *me, host_t *other, bool encap) + host_t *me, host_t *other, host_t *vip, bool encap) { + child_sa_state_t old; + bool transport_proxy_mode; + /* anything changed at all? */ - if (me->equals(me, this->me.addr) && - other->equals(other, this->other.addr) && this->encap == encap) + if (me->equals(me, this->my_addr) && + other->equals(other, this->other_addr) && this->encap == encap) { return SUCCESS; } - /* run updown script to remove iptables rules */ - updown(this, FALSE); - - this->encap = encap; - - if (this->ipcomp != IPCOMP_NONE) - { - /* update our (initator) IPComp SA */ - charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->me.cpi)), - IPPROTO_COMP, this->other.addr, this->me.addr, other, me, FALSE); - /* update his (responder) IPComp SA */ - charon->kernel_interface->update_sa(charon->kernel_interface, htonl(ntohs(this->other.cpi)), - IPPROTO_COMP, this->me.addr, this->other.addr, me, other, FALSE); - } - /* update our (initator) SA */ - charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi, - this->protocol, this->other.addr, this->me.addr, other, me, encap); - /* update his (responder) SA */ - charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi, - this->protocol, this->me.addr, this->other.addr, me, other, encap); + old = this->state; + set_state(this, CHILD_UPDATING); + transport_proxy_mode = this->config->use_proxy_mode(this->config) && + this->mode == MODE_TRANSPORT; - /* update policies */ - if (!me->ip_equals(me, this->me.addr) || - !other->ip_equals(other, this->other.addr)) + if (!transport_proxy_mode) { - iterator_t *iterator; - sa_policy_t *policy; - - /* always use high priorities, as hosts getting updated are INSTALLED */ - iterator = this->policies->create_iterator(this->policies, TRUE); - while (iterator->iterate(iterator, (void**)&policy)) + /* update our (initator) SA */ + if (this->my_spi) { - /* remove old policies first */ - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->my_ts, policy->other_ts, POLICY_OUT); - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_IN); - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, POLICY_FWD); - - /* check wether we have to update a "dynamic" traffic selector */ - if (!me->ip_equals(me, this->me.addr) && - policy->my_ts->is_host(policy->my_ts, this->me.addr)) + if (charon->kernel_interface->update_sa(charon->kernel_interface, + this->my_spi, this->protocol, + this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0, + this->other_addr, this->my_addr, other, me, + this->encap, encap) == NOT_SUPPORTED) { - policy->my_ts->set_address(policy->my_ts, me); + return NOT_SUPPORTED; } - if (!other->ip_equals(other, this->other.addr) && - policy->other_ts->is_host(policy->other_ts, this->other.addr)) + } + + /* update his (responder) SA */ + if (this->other_spi) + { + if (charon->kernel_interface->update_sa(charon->kernel_interface, + this->other_spi, this->protocol, + this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0, + this->my_addr, this->other_addr, me, other, + this->encap, encap) == NOT_SUPPORTED) { - policy->other_ts->set_address(policy->other_ts, other); + return NOT_SUPPORTED; } + } + } + + if (this->config->install_policy(this->config)) + { + /* update policies */ + if (!me->ip_equals(me, this->my_addr) || + !other->ip_equals(other, this->other_addr)) + { + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; - /* we reinstall the virtual IP to handle interface romaing - * correctly */ - if (this->virtual_ip) + /* always use high priorities, as hosts getting updated are INSTALLED */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - charon->kernel_interface->del_ip(charon->kernel_interface, - this->virtual_ip); - charon->kernel_interface->add_ip(charon->kernel_interface, - this->virtual_ip, me); + /* remove old policies first */ + charon->kernel_interface->del_policy(charon->kernel_interface, + my_ts, other_ts, POLICY_OUT, FALSE); + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_IN, FALSE); + if (this->mode != MODE_TRANSPORT) + { + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_FWD, FALSE); + } + + /* check whether we have to update a "dynamic" traffic selector */ + if (!me->ip_equals(me, this->my_addr) && + my_ts->is_host(my_ts, this->my_addr)) + { + my_ts->set_address(my_ts, me); + } + if (!other->ip_equals(other, this->other_addr) && + other_ts->is_host(other_ts, this->other_addr)) + { + other_ts->set_address(other_ts, other); + } + + /* we reinstall the virtual IP to handle interface roaming + * correctly */ + if (vip) + { + charon->kernel_interface->del_ip(charon->kernel_interface, vip); + charon->kernel_interface->add_ip(charon->kernel_interface, vip, me); + } + + /* reinstall updated policies */ + charon->kernel_interface->add_policy(charon->kernel_interface, + me, other, my_ts, other_ts, POLICY_OUT, this->other_spi, + this->protocol, this->reqid, this->mode, this->ipcomp, + this->other_cpi, FALSE); + charon->kernel_interface->add_policy(charon->kernel_interface, + other, me, other_ts, my_ts, POLICY_IN, this->my_spi, + this->protocol, this->reqid, this->mode, this->ipcomp, + this->my_cpi, FALSE); + if (this->mode != MODE_TRANSPORT) + { + charon->kernel_interface->add_policy(charon->kernel_interface, + other, me, other_ts, my_ts, POLICY_FWD, this->my_spi, + this->protocol, this->reqid, this->mode, this->ipcomp, + this->my_cpi, FALSE); + } } - - /* reinstall updated policies */ - charon->kernel_interface->add_policy(charon->kernel_interface, - me, other, policy->my_ts, policy->other_ts, POLICY_OUT, - this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); - charon->kernel_interface->add_policy(charon->kernel_interface, - other, me, policy->other_ts, policy->my_ts, POLICY_IN, - this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); - charon->kernel_interface->add_policy(charon->kernel_interface, - other, me, policy->other_ts, policy->my_ts, POLICY_FWD, - this->protocol, this->reqid, TRUE, this->mode, this->ipcomp); + enumerator->destroy(enumerator); } - iterator->destroy(iterator); } - /* apply hosts */ - if (!me->equals(me, this->me.addr)) + if (!transport_proxy_mode) { - this->me.addr->destroy(this->me.addr); - this->me.addr = me->clone(me); - } - if (!other->equals(other, this->other.addr)) - { - this->other.addr->destroy(this->other.addr); - this->other.addr = other->clone(other); + /* apply hosts */ + if (!me->equals(me, this->my_addr)) + { + this->my_addr->destroy(this->my_addr); + this->my_addr = me->clone(me); + } + if (!other->equals(other, this->other_addr)) + { + this->other_addr->destroy(this->other_addr); + this->other_addr = other->clone(other); + } } - - /* install new iptables rules */ - updown(this, TRUE); - - return SUCCESS; -} -/** - * Implementation of child_sa_t.set_virtual_ip. - */ -static void set_virtual_ip(private_child_sa_t *this, host_t *ip) -{ - this->virtual_ip = ip->clone(ip); + this->encap = encap; + set_state(this, old); + + return SUCCESS; } /** @@ -932,7 +798,7 @@ static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp, u_int16_t other_cpi) { this->ipcomp = ipcomp; - this->other.cpi = other_cpi; + this->other_cpi = other_cpi; } /** @@ -943,10 +809,10 @@ static u_int16_t allocate_cpi(private_child_sa_t *this) if (!this->cpi_allocated) { charon->kernel_interface->get_cpi(charon->kernel_interface, - this->other.addr, this->me.addr, this->reqid, &this->me.cpi); + this->other_addr, this->my_addr, this->reqid, &this->my_cpi); this->cpi_allocated = TRUE; } - return this->me.cpi; + return this->my_cpi; } /** @@ -954,75 +820,61 @@ static u_int16_t allocate_cpi(private_child_sa_t *this) */ static void destroy(private_child_sa_t *this) { - sa_policy_t *policy; + enumerator_t *enumerator; + traffic_selector_t *my_ts, *other_ts; + bool unrouted = (this->state == CHILD_ROUTED); - if (this->state == CHILD_DELETING || this->state == CHILD_INSTALLED) - { - updown(this, FALSE); - } + set_state(this, CHILD_DESTROYING); /* delete SAs in the kernel, if they are set up */ - if (this->me.spi) - { - charon->kernel_interface->del_sa(charon->kernel_interface, - this->me.addr, this->me.spi, this->protocol); - } - if (this->alloc_esp_spi && this->alloc_esp_spi != this->me.spi) + if (this->my_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->me.addr, this->alloc_esp_spi, PROTO_ESP); + this->my_addr, this->my_spi, this->protocol, + this->my_cpi); } - if (this->alloc_ah_spi && this->alloc_ah_spi != this->me.spi) + if (this->alloc_esp_spi && this->alloc_esp_spi != this->my_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->me.addr, this->alloc_ah_spi, PROTO_AH); + this->my_addr, this->alloc_esp_spi, PROTO_ESP, 0); } - if (this->other.spi) + if (this->alloc_ah_spi && this->alloc_ah_spi != this->my_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->other.addr, this->other.spi, this->protocol); + this->my_addr, this->alloc_ah_spi, PROTO_AH, 0); } - if (this->me.cpi) + if (this->other_spi) { charon->kernel_interface->del_sa(charon->kernel_interface, - this->me.addr, htonl(ntohs(this->me.cpi)), IPPROTO_COMP); - } - if (this->other.cpi) - { - charon->kernel_interface->del_sa(charon->kernel_interface, - this->other.addr, htonl(ntohs(this->other.cpi)), IPPROTO_COMP); + this->other_addr, this->other_spi, this->protocol, + this->other_cpi); } - /* delete all policies in the kernel */ - while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS) + if (this->config->install_policy(this->config)) { - /* let rekeyed policies, as they are used by another child_sa */ - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->my_ts, policy->other_ts, - POLICY_OUT); - - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, - POLICY_IN); - - charon->kernel_interface->del_policy(charon->kernel_interface, - policy->other_ts, policy->my_ts, - POLICY_FWD); - policy->my_ts->destroy(policy->my_ts); - policy->other_ts->destroy(policy->other_ts); - free(policy); + /* delete all policies in the kernel */ + enumerator = create_policy_enumerator(this); + while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) + { + charon->kernel_interface->del_policy(charon->kernel_interface, + my_ts, other_ts, POLICY_OUT, unrouted); + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_IN, unrouted); + if (this->mode != MODE_TRANSPORT) + { + charon->kernel_interface->del_policy(charon->kernel_interface, + other_ts, my_ts, POLICY_FWD, unrouted); + } + } + enumerator->destroy(enumerator); } - this->policies->destroy(this->policies); - this->my_ts->destroy(this->my_ts); - this->other_ts->destroy(this->other_ts); - this->me.addr->destroy(this->me.addr); - this->other.addr->destroy(this->other.addr); - this->me.id->destroy(this->me.id); - this->other.id->destroy(this->other.id); + this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy)); + this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy)); + this->my_addr->destroy(this->my_addr); + this->other_addr->destroy(this->other_addr); + DESTROY_IF(this->proposal); this->config->destroy(this->config); - free(this->iface); - DESTROY_IF(this->virtual_ip); free(this); } @@ -1030,7 +882,6 @@ static void destroy(private_child_sa_t *this) * Described in header. */ child_sa_t * child_sa_create(host_t *me, host_t* other, - identification_t *my_id, identification_t *other_id, child_cfg_t *config, u_int32_t rekey, bool encap) { static u_int32_t reqid = 0; @@ -1042,31 +893,33 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi; this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi; this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol; - this->public.get_stats = (void(*)(child_sa_t*, ipsec_mode_t*,encryption_algorithm_t*,size_t*,integrity_algorithm_t*,size_t*,u_int32_t*,u_int32_t*,u_int32_t*,u_int32_t*))get_stats; + this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode; + this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp; + this->public.has_encap = (bool(*)(child_sa_t*))has_encap; + this->public.get_lifetime = (u_int32_t(*)(child_sa_t*, bool))get_lifetime; + this->public.get_usetime = (u_int32_t(*)(child_sa_t*, bool))get_usetime; this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; - this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,prf_plus_t*))add; - this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,prf_plus_t*))update; - this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,bool))update_hosts; + this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))add; + this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))update; + this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal; + this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,ipsec_mode_t,protocol_id_t))add_policies; this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; - this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; + this->public.create_policy_enumerator = (enumerator_t*(*)(child_sa_t*))create_policy_enumerator; this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state; this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state; this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config; this->public.activate_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t,u_int16_t))activate_ipcomp; this->public.allocate_cpi = (u_int16_t(*)(child_sa_t*))allocate_cpi; - this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip; this->public.destroy = (void(*)(child_sa_t*))destroy; /* private data */ - this->me.addr = me->clone(me); - this->other.addr = other->clone(other); - this->me.id = my_id->clone(my_id); - this->other.id = other_id->clone(other_id); - this->me.spi = 0; - this->me.cpi = 0; - this->other.spi = 0; - this->other.cpi = 0; + this->my_addr = me->clone(me); + this->other_addr = other->clone(other); + this->my_spi = 0; + this->my_cpi = 0; + this->other_spi = 0; + this->other_cpi = 0; this->alloc_ah_spi = 0; this->alloc_esp_spi = 0; this->encap = encap; @@ -1075,19 +928,70 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->state = CHILD_CREATED; /* reuse old reqid if we are rekeying an existing CHILD_SA */ this->reqid = rekey ? rekey : ++reqid; - this->enc_alg = ENCR_UNDEFINED; - this->enc_size = 0; - this->int_alg = AUTH_UNDEFINED; - this->int_size = 0; - this->policies = linked_list_create(); this->my_ts = linked_list_create(); this->other_ts = linked_list_create(); this->protocol = PROTO_NONE; this->mode = MODE_TUNNEL; - this->virtual_ip = NULL; - this->iface = NULL; + this->proposal = NULL; this->config = config; config->get_ref(config); + + /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */ + if (config->get_mode(config) == MODE_TRANSPORT && + config->use_proxy_mode(config)) + { + ts_type_t type; + int family; + chunk_t addr; + host_t *host; + enumerator_t *enumerator; + linked_list_t *my_ts_list, *other_ts_list; + traffic_selector_t *my_ts, *other_ts; + + this->mode = MODE_TRANSPORT; + + my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me); + enumerator = my_ts_list->create_enumerator(my_ts_list); + if (enumerator->enumerate(enumerator, &my_ts)) + { + if (my_ts->is_host(my_ts, NULL) && + !my_ts->is_host(my_ts, this->my_addr)) + { + type = my_ts->get_type(my_ts); + family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; + addr = my_ts->get_from_address(my_ts); + host = host_create_from_chunk(family, addr, 0); + free(addr.ptr); + DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H", + this->my_addr, host); + this->my_addr->destroy(this->my_addr); + this->my_addr = host; + } + } + enumerator->destroy(enumerator); + my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy)); + + other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other); + enumerator = other_ts_list->create_enumerator(other_ts_list); + if (enumerator->enumerate(enumerator, &other_ts)) + { + if (other_ts->is_host(other_ts, NULL) && + !other_ts->is_host(other_ts, this->other_addr)) + { + type = other_ts->get_type(other_ts); + family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; + addr = other_ts->get_from_address(other_ts); + host = host_create_from_chunk(family, addr, 0); + free(addr.ptr); + DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H", + this->other_addr, host); + this->other_addr->destroy(this->other_addr); + this->other_addr = host; + } + } + enumerator->destroy(enumerator); + other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy)); + } return &this->public; } diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 2f7961e03..7109de5cd 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_sa.h 4358 2008-09-25 13:56:23Z tobias $ + * $Id: child_sa.h 4618 2008-11-11 09:22:00Z tobias $ */ /** @@ -50,11 +50,21 @@ enum child_sa_state_t { CHILD_ROUTED, /** + * Installing an in-use CHILD_SA + */ + CHILD_INSTALLING, + + /** * Installed an in-use CHILD_SA */ CHILD_INSTALLED, /** + * While updating hosts, in update_hosts() + */ + CHILD_UPDATING, + + /** * CHILD_SA which is rekeying */ CHILD_REKEYING, @@ -63,6 +73,11 @@ enum child_sa_state_t { * CHILD_SA in progress of delete */ CHILD_DELETING, + + /** + * CHILD_SA object gets destroyed + */ + CHILD_DESTROYING, }; /** @@ -138,23 +153,41 @@ struct child_sa_t { protocol_id_t (*get_protocol) (child_sa_t *this); /** - * Get info and statistics about this CHILD_SA. + * Get the IPsec mode of this CHILD_SA. + * + * @return TUNNEL | TRANSPORT | BEET + */ + ipsec_mode_t (*get_mode)(child_sa_t *this); + + /** + * Get the used IPComp algorithm. + * + * @return IPComp compression algorithm. + */ + ipcomp_transform_t (*get_ipcomp)(child_sa_t *this); + + /** + * Check if this CHILD_SA uses UDP encapsulation. + * + * @return TRUE if SA encapsulates ESP packets + */ + bool (*has_encap)(child_sa_t *this); + + /** + * Get the lifetime of the CHILD_SA. * - * @param mode mode this IKE_SA uses - * @param encr_algo encryption algorithm used by this CHILD_SA. - * @param encr_len key length of the algorithm, if any - * @param int_algo integrity algorithm used by this CHILD_SA - * @param int_len key length of the algorithm, if any - * @param rekey time when rekeying is scheduled - * @param use_in time when last traffic was seen coming in - * @param use_out time when last traffic was seen going out - * @param use_fwd time when last traffic was getting forwarded + * @param hard TRUE for hard lifetime, FALSE for soft (rekey) lifetime + * @return lifetime in seconds */ - void (*get_stats)(child_sa_t *this, ipsec_mode_t *mode, - encryption_algorithm_t *encr, size_t *encr_len, - integrity_algorithm_t *int_algo, size_t *int_len, - u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out, - u_int32_t *use_fwd); + u_int32_t (*get_lifetime)(child_sa_t *this, bool hard); + + /** + * Get last use time of the CHILD_SA. + * + * @param inbound TRUE for inbound traffic, FALSE for outbound + * @return time of last use in seconds + */ + u_int32_t (*get_usetime)(child_sa_t *this, bool inbound); /** * Allocate SPIs for given proposals. @@ -174,12 +207,15 @@ struct child_sa_t { * * @param proposal proposal for which SPIs are allocated * @param mode mode for the CHILD_SA - * @param prf_plus key material to use for key derivation + * @param integ_in integrity key for inbound traffic + * @param integ_out integrity key for outbound traffic + * @param encr_in encryption key for inbound traffic + * @param enc_out encryption key for outbound traffic * @return SUCCESS or FAILED */ status_t (*add)(child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode, - prf_plus_t *prf_plus); - + chunk_t integ_in, chunk_t integ_out, + chunk_t encr_in, chunk_t encr_out); /** * Install the kernel SAs for a proposal, after SPIs have been allocated. * @@ -187,12 +223,22 @@ struct child_sa_t { * * @param proposal proposal for which SPIs are allocated * @param mode mode for the CHILD_SA - * @param prf_plus key material to use for key derivation + * @param integ_in integrity key for inbound traffic + * @param integ_out integrity key for outbound traffic + * @param encr_in encryption key for inbound traffic + * @param enc_out encryption key for outbound traffic * @return SUCCESS or FAILED */ status_t (*update)(child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode, - prf_plus_t *prf_plus); - + chunk_t integ_in, chunk_t integ_out, + chunk_t encr_in, chunk_t encr_out); + /** + * Get the selected proposal passed to add()/update(). + * + * @return selected proposal + */ + proposal_t* (*get_proposal)(child_sa_t *this); + /** * Update the hosts in the kernel SAs and policies. * @@ -200,11 +246,12 @@ struct child_sa_t { * * @param me the new local host * @param other the new remote host + * @param vip virtual IP, if any * @param TRUE to use UDP encapsulation for NAT traversal * @return SUCCESS or FAILED */ status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other, - bool encap); + host_t *vip, bool encap); /** * Install the policies using some traffic selectors. @@ -231,13 +278,11 @@ struct child_sa_t { linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local); /** - * Get the time of this child_sa_t's last use (i.e. last use of any of its policies) - * - * @param inbound query for in- or outbound usage - * @param use_time the time - * @return SUCCESS or FAILED - */ - status_t (*get_use_time) (child_sa_t *this, bool inbound, time_t *use_time); + * Create an enumerator over installed policies. + * + * @return enumerator over pairs of traffic selectors. + */ + enumerator_t* (*create_policy_enumerator)(child_sa_t *this); /** * Get the state of the CHILD_SA. @@ -259,23 +304,13 @@ struct child_sa_t { child_cfg_t* (*get_config) (child_sa_t *this); /** - * Set the virtual IP used received from IRAS. - * - * To allow proper setup of firewall rules, the virtual IP is required - * for filtering. - * - * @param ip own virtual IP - */ - void (*set_virtual_ip) (child_sa_t *this, host_t *ip); - - /** * Activate IPComp by setting the transform ID and CPI values. * * @param ipcomp the IPComp transform to use * @param other_cpi other Compression Parameter Index */ void (*activate_ipcomp) (child_sa_t *this, ipcomp_transform_t ipcomp, - u_int16_t other_cpi); + u_int16_t other_cpi); /** * Returns the Compression Parameter Index (CPI) allocated from the kernel. @@ -293,17 +328,16 @@ struct child_sa_t { /** * Constructor to create a new child_sa_t. * - * @param me own address - * @param other remote address - * @param my_id id of own peer - * @param other_id id of remote peer - * @param config config to use for this CHILD_SA - * @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise - * @param encap TRUE to enable UDP encapsulation (NAT traversal) - * @return child_sa_t object + * @param me own address + * @param other remote address + * @param my_id id of own peer + * @param other_id id of remote peer + * @param config config to use for this CHILD_SA + * @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise + * @param encap TRUE to enable UDP encapsulation (NAT traversal) + * @return child_sa_t object */ -child_sa_t * child_sa_create(host_t *me, host_t *other, - identification_t *my_id, identification_t* other_id, - child_cfg_t *config, u_int32_t reqid, bool encap); +child_sa_t * child_sa_create(host_t *me, host_t *other, child_cfg_t *config, + u_int32_t reqid, bool encap); #endif /*CHILD_SA_H_ @} */ diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c index d24ce8fc7..b9141ffc1 100644 --- a/src/charon/sa/connect_manager.c +++ b/src/charon/sa/connect_manager.c @@ -12,15 +12,15 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: connect_manager.c 4192 2008-07-18 15:51:40Z martin $ + * $Id: connect_manager.c 4579 2008-11-05 11:29:56Z martin $ */ #include "connect_manager.h" -#include <pthread.h> #include <math.h> #include <daemon.h> +#include <utils/mutex.h> #include <utils/linked_list.h> #include <crypto/hashers/hasher.h> @@ -59,7 +59,7 @@ struct private_connect_manager_t { /** * Lock for exclusivly accessing the manager. */ - pthread_mutex_t mutex; + mutex_t *mutex; /** * Hasher to generate signatures @@ -845,20 +845,20 @@ static job_requeue_t initiator_finish(callback_data_t *data) { private_connect_manager_t *this = data->connect_manager; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); check_list_t *checklist; if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish connectivity checks", &data->connect_id); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return JOB_REQUEUE_NONE; } finish_checks(this, checklist); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return JOB_REQUEUE_NONE; } @@ -929,14 +929,14 @@ static job_requeue_t retransmit(callback_data_t *data) { private_connect_manager_t *this = data->connect_manager; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); check_list_t *checklist; if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit connectivity check", &data->connect_id); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return JOB_REQUEUE_NONE; } @@ -980,7 +980,7 @@ retransmit_end: break; } - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); /* we reschedule it manually */ return JOB_REQUEUE_NONE; @@ -1078,14 +1078,14 @@ static job_requeue_t sender(callback_data_t *data) { private_connect_manager_t *this = data->connect_manager; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); check_list_t *checklist; if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send connectivity check", &data->connect_id); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return JOB_REQUEUE_NONE; } @@ -1100,7 +1100,7 @@ static job_requeue_t sender(callback_data_t *data) if (checklist->pairs->find_first(checklist->pairs, (linked_list_match_t)match_waiting_pair, (void**)&pair) != SUCCESS) { - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); DBG1(DBG_IKE, "no pairs in waiting state, aborting"); return JOB_REQUEUE_NONE; } @@ -1126,7 +1126,7 @@ static job_requeue_t sender(callback_data_t *data) /* schedule this job again */ schedule_checks(this, checklist, ME_INTERVAL); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); /* we reschedule it manually */ return JOB_REQUEUE_NONE; @@ -1160,7 +1160,7 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa); if (sa->initiate_mediated(sa, pair->local, pair->remote, checklist->connect_id) != SUCCESS) { - SIG_IKE(UP_FAILED, "establishing the mediated connection failed"); + DBG1(DBG_IKE, "establishing mediated connection failed"); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa); } charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa); @@ -1345,7 +1345,7 @@ static void process_check(private_connect_manager_t *this, message_t *message) return; } - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); check_list_t *checklist; if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS) @@ -1353,7 +1353,7 @@ static void process_check(private_connect_manager_t *this, message_t *message) DBG1(DBG_IKE, "checklist with id '%#B' not found", &check->connect_id); check_destroy(check); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return; } @@ -1363,7 +1363,7 @@ static void process_check(private_connect_manager_t *this, message_t *message) DBG1(DBG_IKE, "connectivity check verification failed"); check_destroy(check); chunk_free(&sig); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return; } chunk_free(&sig); @@ -1377,7 +1377,7 @@ static void process_check(private_connect_manager_t *this, message_t *message) process_response(this, check, checklist); } - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); check_destroy(check); } @@ -1392,7 +1392,7 @@ static bool check_and_register(private_connect_manager_t *this, initiated_t *initiated; bool already_there = TRUE; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) { @@ -1408,7 +1408,7 @@ static bool check_and_register(private_connect_manager_t *this, initiated->mediated->insert_last(initiated->mediated, mediated_sa->clone(mediated_sa)); } - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return already_there; } @@ -1421,12 +1421,12 @@ static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *med { initiated_t *initiated; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) { DBG2(DBG_IKE, "no waiting mediated connections with '%D'", peer_id); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return; } @@ -1439,7 +1439,7 @@ static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *med } iterator->destroy(iterator); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); } /** @@ -1451,20 +1451,20 @@ static status_t set_initiator_data(private_connect_manager_t *this, { check_list_t *checklist; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting", &connect_id); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return FAILED; } checklist = check_list_create(initiator, responder, connect_id, key, endpoints, is_initiator); this->checklists->insert_last(this->checklists, checklist); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return SUCCESS; } @@ -1477,13 +1477,13 @@ static status_t set_responder_data(private_connect_manager_t *this, { check_list_t *checklist; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' not found", &connect_id); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return NOT_FOUND; } @@ -1496,7 +1496,7 @@ static status_t set_responder_data(private_connect_manager_t *this, /* send the first check immediately */ schedule_checks(this, checklist, 0); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return SUCCESS; } @@ -1508,13 +1508,13 @@ static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id) { check_list_t *checklist; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) { DBG1(DBG_IKE, "checklist with id '%#B' not found", &connect_id); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return NOT_FOUND; } @@ -1523,7 +1523,7 @@ static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id) remove_checklist(this, checklist); check_list_destroy(checklist); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return SUCCESS; } @@ -1533,14 +1533,14 @@ static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id) */ static void destroy(private_connect_manager_t *this) { - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); this->hasher->destroy(this->hasher); this->checklists->destroy_function(this->checklists, (void*)check_list_destroy); this->initiated->destroy_function(this->initiated, (void*)initiated_destroy); - pthread_mutex_unlock(&(this->mutex)); - pthread_mutex_destroy(&(this->mutex)); + this->mutex->unlock(this->mutex); + this->mutex->destroy(this->mutex); free(this); } @@ -1570,7 +1570,7 @@ connect_manager_t *connect_manager_create() this->checklists = linked_list_create(); this->initiated = linked_list_create(); - pthread_mutex_init(&(this->mutex), NULL); + this->mutex = mutex_create(MUTEX_DEFAULT); return (connect_manager_t*)this; } diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 7b2608e07..d9bb01c60 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-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_sa.c 4394 2008-10-09 08:25:11Z martin $ + * $Id: ike_sa.c 4652 2008-11-14 08:38:53Z martin $ */ #include <sys/time.h> @@ -23,6 +23,7 @@ #include <printf.h> #include <sys/stat.h> #include <errno.h> +#include <time.h> #include "ike_sa.h" @@ -30,17 +31,6 @@ #include <daemon.h> #include <utils/linked_list.h> #include <utils/lexparser.h> -#include <crypto/diffie_hellman.h> -#include <crypto/prf_plus.h> -#include <crypto/crypters/crypter.h> -#include <crypto/hashers/hasher.h> -#include <encoding/payloads/sa_payload.h> -#include <encoding/payloads/nonce_payload.h> -#include <encoding/payloads/ke_payload.h> -#include <encoding/payloads/delete_payload.h> -#include <encoding/payloads/transform_substructure.h> -#include <encoding/payloads/transform_attribute.h> -#include <encoding/payloads/ts_payload.h> #include <sa/task_manager.h> #include <sa/tasks/ike_init.h> #include <sa/tasks/ike_natd.h> @@ -72,12 +62,13 @@ #define RESOLV_CONF "/etc/resolv.conf" #endif -ENUM(ike_sa_state_names, IKE_CREATED, IKE_DELETING, +ENUM(ike_sa_state_names, IKE_CREATED, IKE_DESTROYING, "CREATED", "CONNECTING", "ESTABLISHED", "REKEYING", "DELETING", + "DESTROYING", ); typedef struct private_ike_sa_t private_ike_sa_t; @@ -128,6 +119,11 @@ struct private_ike_sa_t { auth_info_t *other_auth; /** + * Selected IKE proposal + */ + proposal_t *proposal; + + /** * Juggles tasks to process messages */ task_manager_t *task_manager; @@ -190,49 +186,9 @@ struct private_ike_sa_t { linked_list_t *child_sas; /** - * String describing the selected IKE proposal - */ - char *selected_proposal; - - /** - * crypter for inbound traffic - */ - crypter_t *crypter_in; - - /** - * crypter for outbound traffic - */ - crypter_t *crypter_out; - - /** - * Signer for inbound traffic - */ - signer_t *signer_in; - - /** - * Signer for outbound traffic + * keymat of this IKE_SA */ - signer_t *signer_out; - - /** - * Multi purpose prf, set key, use it, forget it - */ - prf_t *prf; - - /** - * Prf function for derivating keymat child SAs - */ - prf_t *child_prf; - - /** - * Key to build outging authentication data (SKp) - */ - chunk_t skp_build; - - /** - * Key to verify incoming authentication data (SKp) - */ - chunk_t skp_verify; + keymat_t *keymat; /** * Virtual IP on local host, if any @@ -268,34 +224,26 @@ struct private_ike_sa_t { * NAT keep alive interval */ u_int32_t keepalive_interval; - + /** * Timestamps for this IKE_SA */ - struct { - /** last IKE message received */ - u_int32_t inbound; - /** last IKE message sent */ - u_int32_t outbound; - /** when IKE_SA became established */ - u_int32_t established; - /** when IKE_SA gets rekeyed */ - u_int32_t rekey; - /** when IKE_SA gets reauthenticated */ - u_int32_t reauth; - /** when IKE_SA gets deleted */ - u_int32_t delete; - } time; + u_int32_t stats[STAT_MAX]; /** * how many times we have retried so far (keyingtries) */ u_int32_t keyingtry; - + /** - * are we the initiator of this IKE_SA (rekeying does not affect this flag) + * local host address to be used for IKE, set via MIGRATE kernel message */ - bool ike_initiator; + host_t *local_host; + + /** + * remote host address to be used for IKE, set via MIGRATE kernel message + */ + host_t *remote_host; }; /** @@ -303,28 +251,26 @@ struct private_ike_sa_t { */ static time_t get_use_time(private_ike_sa_t* this, bool inbound) { - iterator_t *iterator; + enumerator_t *enumerator; child_sa_t *child_sa; - time_t latest = 0, use_time; - - iterator = this->child_sas->create_iterator(this->child_sas, TRUE); - while (iterator->iterate(iterator, (void**)&child_sa)) - { - if (child_sa->get_use_time(child_sa, inbound, &use_time) == SUCCESS) - { - latest = max(latest, use_time); - } - } - iterator->destroy(iterator); + time_t use_time; if (inbound) { - return max(this->time.inbound, latest); + use_time = this->stats[STAT_INBOUND]; } else { - return max(this->time.outbound, latest); + use_time = this->stats[STAT_OUTBOUND]; + } + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, &child_sa)) + { + use_time = max(use_time, child_sa->get_usetime(child_sa, inbound)); } + enumerator->destroy(enumerator); + + return use_time; } /** @@ -352,24 +298,9 @@ static char *get_name(private_ike_sa_t *this) */ static u_int32_t get_statistic(private_ike_sa_t *this, statistic_t kind) { - time_t now = time(NULL); - - switch (kind) + if (kind < STAT_MAX) { - case STAT_REKEY_TIME: - if (this->time.rekey > now) - { - return this->time.rekey - now; - } - break; - case STAT_REAUTH_TIME: - if (this->time.reauth > now) - { - return this->time.reauth - now; - } - break; - default: - break; + return this->stats[kind]; } return 0; } @@ -462,6 +393,23 @@ static auth_info_t* get_other_auth(private_ike_sa_t *this) } /** + * Implementation of ike_sa_t.get_proposal + */ +static proposal_t* get_proposal(private_ike_sa_t *this) +{ + return this->proposal; +} + +/** + * Implementation of ike_sa_t.set_proposal + */ +static void set_proposal(private_ike_sa_t *this, proposal_t *proposal) +{ + DESTROY_IF(this->proposal); + this->proposal = proposal->clone(proposal); +} + +/** * Implementation of ike_sa_t.send_keepalive */ static void send_keepalive(private_ike_sa_t *this) @@ -518,14 +466,6 @@ static void set_ike_cfg(private_ike_sa_t *this, ike_cfg_t *ike_cfg) } /** - * Implementation of ike_sa_t.is_ike_initiator - */ -static bool is_ike_initiator(private_ike_sa_t *this) -{ - return this->ike_initiator; -} - -/** * Implementation of ike_sa_t.enable_extension. */ static void enable_extension(private_ike_sa_t *this, ike_extension_t extension) @@ -687,47 +627,48 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) u_int32_t t; /* calculate rekey, reauth and lifetime */ - this->time.established = time(NULL); + this->stats[STAT_ESTABLISHED] = time(NULL); /* schedule rekeying if we have a time which is smaller than * an already scheduled rekeying */ t = this->peer_cfg->get_rekey_time(this->peer_cfg); - if (t && (this->time.rekey == 0 || - (this->time.rekey > t + this->time.established))) + if (t && (this->stats[STAT_REKEY] == 0 || + (this->stats[STAT_REKEY] > t + this->stats[STAT_ESTABLISHED]))) { - this->time.rekey = t + this->time.established; + 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); DBG1(DBG_IKE, "scheduling rekeying in %ds", t); } t = this->peer_cfg->get_reauth_time(this->peer_cfg); - if (t && (this->time.reauth == 0 || - (this->time.reauth > t + this->time.established))) + if (t && (this->stats[STAT_REAUTH] == 0 || + (this->stats[STAT_REAUTH] > t + this->stats[STAT_ESTABLISHED]))) { - this->time.reauth = t + this->time.established; + 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); DBG1(DBG_IKE, "scheduling reauthentication in %ds", t); } t = this->peer_cfg->get_over_time(this->peer_cfg); - if (this->time.rekey || this->time.reauth) + if (this->stats[STAT_REKEY] || this->stats[STAT_REAUTH]) { - if (this->time.reauth == 0) + if (this->stats[STAT_REAUTH] == 0) { - this->time.delete = this->time.rekey; + this->stats[STAT_DELETE] = this->stats[STAT_REKEY]; } - else if (this->time.rekey == 0) + else if (this->stats[STAT_REKEY] == 0) { - this->time.delete = this->time.reauth; + this->stats[STAT_DELETE] = this->stats[STAT_REAUTH]; } else { - this->time.delete = min(this->time.rekey, this->time.reauth); + this->stats[STAT_DELETE] = min(this->stats[STAT_REKEY], + this->stats[STAT_REAUTH]); } - this->time.delete += t; - t = this->time.delete - this->time.established; + 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); @@ -750,7 +691,7 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) default: break; } - + charon->bus->ike_state_change(charon->bus, &this->public, state); this->state = state; } @@ -771,6 +712,14 @@ static void reset(private_ike_sa_t *this) } /** + * Implementation of ike_sa_t.get_keymat + */ +static keymat_t* get_keymat(private_ike_sa_t *this) +{ + return this->keymat; +} + +/** * Implementation of ike_sa_t.set_virtual_ip */ static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip) @@ -925,8 +874,14 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - child_sa->update_hosts(child_sa, this->my_host, this->other_host, - has_condition(this, COND_NAT_ANY)); + if (child_sa->update_hosts(child_sa, this->my_host, + this->other_host, this->my_virtual_ip, + has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED) + { + this->public.rekey_child_sa(&this->public, + child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)); + } } iterator->destroy(iterator); } @@ -938,9 +893,11 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) static status_t generate_message(private_ike_sa_t *this, message_t *message, packet_t **packet) { - this->time.outbound = time(NULL); + this->stats[STAT_OUTBOUND] = time(NULL); message->set_ike_sa_id(message, this->ike_sa_id); - return message->generate(message, this->crypter_out, this->signer_out, packet); + return message->generate(message, + this->keymat->get_crypter(this->keymat, FALSE), + this->keymat->get_signer(this->keymat, FALSE), packet); } /** @@ -978,6 +935,17 @@ static void send_notify_response(private_ike_sa_t *this, message_t *request, response->destroy(response); } +/** + * Implementation of ike_sa_t.set_kmaddress. + */ +static void set_kmaddress(private_ike_sa_t *this, host_t *local, host_t *remote) +{ + DESTROY_IF(this->local_host); + DESTROY_IF(this->remote_host); + this->local_host = local->clone(local); + this->remote_host = remote->clone(remote); +} + #ifdef ME /** * Implementation of ike_sa_t.act_as_mediation_server. @@ -1082,26 +1050,42 @@ static void resolve_hosts(private_ike_sa_t *this) { host_t *host; - host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg), - 0, IKEV2_UDP_PORT); + if (this->remote_host) + { + host = this->remote_host->clone(this->remote_host); + host->set_port(host, IKEV2_UDP_PORT); + } + else + { + host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg), + 0, IKEV2_UDP_PORT); + } if (host) { set_other_host(this, host); } - host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), - this->my_host->get_family(this->my_host), - IKEV2_UDP_PORT); - - if (host && host->is_anyaddr(host) && - !this->other_host->is_anyaddr(this->other_host)) + if (this->local_host) { - host->destroy(host); - host = charon->kernel_interface->get_source_addr( - charon->kernel_interface, this->other_host, NULL); - if (host) + host = this->local_host->clone(this->local_host); + host->set_port(host, IKEV2_UDP_PORT); + } + else + { + host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), + this->my_host->get_family(this->my_host), + IKEV2_UDP_PORT); + + if (host && host->is_anyaddr(host) && + !this->other_host->is_anyaddr(this->other_host)) { - host->set_port(host, IKEV2_UDP_PORT); + host->destroy(host); + host = charon->kernel_interface->get_source_addr( + charon->kernel_interface, this->other_host, NULL); + if (host) + { + host->set_port(host, IKEV2_UDP_PORT); + } } } if (host) @@ -1128,12 +1112,11 @@ static status_t initiate_with_reqid(private_ike_sa_t *this, child_cfg_t *child_c ) { child_cfg->destroy(child_cfg); - SIG_IKE(UP_START, "initiating IKE_SA"); - SIG_IKE(UP_FAILED, "unable to initiate to %%any"); + DBG1(DBG_IKE, "unable to initiate to %%any"); return DESTROY_ME; } - this->ike_initiator = TRUE; + set_condition(this, COND_ORIGINAL_INITIATOR, TRUE); task = (task_t*)ike_init_create(&this->public, TRUE, NULL); this->task_manager->queue_task(this->task_manager, task); @@ -1163,10 +1146,12 @@ static status_t initiate_with_reqid(private_ike_sa_t *this, child_cfg_t *child_c #ifdef ME if (this->peer_cfg->is_mediation(this->peer_cfg)) { - /* mediation connection */ if (this->state == IKE_ESTABLISHED) - { /* FIXME: we should try to find a better solution to this */ - SIG_CHD(UP_SUCCESS, NULL, "mediation connection is already up and running"); + { + /* mediation connection is already established, retrigger state change + * to notify bus listeners */ + DBG1(DBG_IKE, "mediation connection is already up"); + set_state(this, IKE_ESTABLISHED); } DESTROY_IF(child_cfg); } @@ -1216,9 +1201,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) if (this->state == IKE_DELETING) { - SIG_CHD(UP_START, NULL, "acquiring CHILD_SA on kernel request"); - SIG_CHD(UP_FAILED, NULL, "acquiring CHILD_SA {reqid %d} failed: " - "IKE_SA is deleting", reqid); + DBG1(DBG_IKE, "acquiring CHILD_SA {reqid %d} failed: " + "IKE_SA is deleting", reqid); return FAILED; } @@ -1235,9 +1219,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) iterator->destroy(iterator); if (!child_sa) { - SIG_CHD(UP_START, NULL, "acquiring CHILD_SA on kernel request"); - SIG_CHD(UP_FAILED, NULL, "acquiring CHILD_SA {reqid %d} failed: " - "CHILD_SA not found", reqid); + DBG1(DBG_IKE, "acquiring CHILD_SA {reqid %d} failed: " + "CHILD_SA not found", reqid); return FAILED; } @@ -1258,8 +1241,6 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) host_t *me, *other; status_t status; - SIG_CHD(ROUTE_START, NULL, "routing CHILD_SA"); - /* check if not already routed*/ iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) @@ -1268,7 +1249,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) streq(child_sa->get_name(child_sa), child_cfg->get_name(child_cfg))) { iterator->destroy(iterator); - SIG_CHD(ROUTE_FAILED, child_sa, "CHILD_SA with such a config already routed"); + DBG1(DBG_IKE, "routing CHILD_SA failed: already routed"); return FAILED; } } @@ -1278,8 +1259,8 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) { case IKE_DELETING: case IKE_REKEYING: - SIG_CHD(ROUTE_FAILED, NULL, - "unable to route CHILD_SA, as its IKE_SA gets deleted"); + 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: @@ -1291,8 +1272,8 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) resolve_hosts(this); /* install kernel policies */ - child_sa = child_sa_create(this->my_host, this->other_host, this->my_id, - this->other_id, child_cfg, 0, FALSE); + child_sa = child_sa_create(this->my_host, this->other_host, + child_cfg, 0, FALSE); me = this->my_host; if (this->my_virtual_ip) { @@ -1306,18 +1287,21 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, me); other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, other); + status = child_sa->add_policies(child_sa, my_ts, other_ts, - child_cfg->get_mode(child_cfg), PROTO_NONE); + child_cfg->get_mode(child_cfg), PROTO_NONE); + 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); - SIG_CHD(ROUTE_SUCCESS, child_sa, "CHILD_SA routed"); + DBG1(DBG_IKE, "CHILD_SA routed"); } else { - SIG_CHD(ROUTE_FAILED, child_sa, "routing CHILD_SA failed"); + child_sa->destroy(child_sa); + DBG1(DBG_IKE, "routing CHILD_SA failed"); } return status; } @@ -1331,8 +1315,6 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) child_sa_t *child_sa; bool found = FALSE; - SIG_CHD(UNROUTE_START, NULL, "unrouting CHILD_SA"); - /* find CHILD_SA in ROUTED state */ iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) @@ -1341,7 +1323,7 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) child_sa->get_reqid(child_sa) == reqid) { iterator->remove(iterator); - SIG_CHD(UNROUTE_SUCCESS, child_sa, "CHILD_SA unrouted"); + DBG1(DBG_IKE, "CHILD_SA unrouted"); child_sa->destroy(child_sa); found = TRUE; break; @@ -1351,7 +1333,7 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) if (!found) { - SIG_CHD(UNROUTE_FAILED, NULL, "CHILD_SA to unroute not 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 */ @@ -1362,6 +1344,7 @@ static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) } return SUCCESS; } + /** * Implementation of ike_sa_t.process_message. */ @@ -1372,7 +1355,9 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) is_request = message->get_request(message); - status = message->parse_body(message, this->crypter_in, this->signer_in); + status = message->parse_body(message, + this->keymat->get_crypter(this->keymat, TRUE), + this->keymat->get_signer(this->keymat, TRUE)); if (status != SUCCESS) { @@ -1431,7 +1416,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) 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) { @@ -1451,7 +1436,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) charon->scheduler->schedule_job(charon->scheduler, job, HALF_OPEN_IKE_SA_TIMEOUT); } - this->time.inbound = time(NULL); + this->stats[STAT_INBOUND] = time(NULL); /* check if message is trustworthy, and update host information */ if (this->state == IKE_CREATED || this->state == IKE_CONNECTING || message->get_exchange_type(message) != IKE_SA_INIT) @@ -1510,38 +1495,6 @@ static status_t process_message(private_ike_sa_t *this, message_t *message) } /** - * Implementation of ike_sa_t.get_prf. - */ -static prf_t *get_prf(private_ike_sa_t *this) -{ - return this->prf; -} - -/** - * Implementation of ike_sa_t.get_prf. - */ -static prf_t *get_child_prf(private_ike_sa_t *this) -{ - return this->child_prf; -} - -/** - * Implementation of ike_sa_t.get_skp_bild - */ -static chunk_t get_skp_build(private_ike_sa_t *this) -{ - return this->skp_build; -} - -/** - * Implementation of ike_sa_t.get_skp_verify - */ -static chunk_t get_skp_verify(private_ike_sa_t *this) -{ - return this->skp_verify; -} - -/** * Implementation of ike_sa_t.get_id. */ static ike_sa_id_t* get_id(private_ike_sa_t *this) @@ -1601,230 +1554,6 @@ static void set_eap_identity(private_ike_sa_t *this, identification_t *id) } /** - * Implementation of ike_sa_t.derive_keys. - */ -static status_t derive_keys(private_ike_sa_t *this, - proposal_t *proposal, chunk_t secret, - chunk_t nonce_i, chunk_t nonce_r, - bool initiator, prf_t *child_prf, prf_t *old_prf) -{ - prf_plus_t *prf_plus; - chunk_t skeyseed, key, full_nonce, fixed_nonce, prf_plus_seed; - u_int16_t alg, key_size; - crypter_t *crypter_i, *crypter_r; - signer_t *signer_i, *signer_r; - u_int8_t spi_i_buf[sizeof(u_int64_t)], spi_r_buf[sizeof(u_int64_t)]; - chunk_t spi_i = chunk_from_buf(spi_i_buf); - chunk_t spi_r = chunk_from_buf(spi_r_buf); - - /* Create SAs general purpose PRF first, we may use it here */ - if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) - { - DBG1(DBG_IKE, "no %N selected", - transform_type_names, PSEUDO_RANDOM_FUNCTION); - return FAILED; - } - this->prf = lib->crypto->create_prf(lib->crypto, alg); - if (this->prf == NULL) - { - DBG1(DBG_IKE, "%N %N not supported!", - transform_type_names, PSEUDO_RANDOM_FUNCTION, - pseudo_random_function_names, alg); - return FAILED; - } - DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret); - /* full nonce is used as seed for PRF+ ... */ - full_nonce = chunk_cat("cc", nonce_i, nonce_r); - /* but the PRF may need a fixed key which only uses the first bytes of - * the nonces. */ - switch (alg) - { - case PRF_AES128_XCBC: - /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does - * not and therefore fixed key semantics apply to XCBC for key - * derivation. */ - nonce_i.len = min(nonce_i.len, this->prf->get_key_size(this->prf)/2); - nonce_r.len = min(nonce_r.len, this->prf->get_key_size(this->prf)/2); - break; - default: - /* all other algorithms use variable key length, full nonce */ - break; - } - fixed_nonce = chunk_cat("cc", nonce_i, nonce_r); - *((u_int64_t*)spi_i.ptr) = this->ike_sa_id->get_initiator_spi(this->ike_sa_id); - *((u_int64_t*)spi_r.ptr) = this->ike_sa_id->get_responder_spi(this->ike_sa_id); - prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r); - - /* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr) - * - * if we are rekeying, SKEYSEED is built on another way - */ - if (child_prf == NULL) /* not rekeying */ - { - /* SKEYSEED = prf(Ni | Nr, g^ir) */ - this->prf->set_key(this->prf, fixed_nonce); - this->prf->allocate_bytes(this->prf, secret, &skeyseed); - DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); - this->prf->set_key(this->prf, skeyseed); - chunk_free(&skeyseed); - chunk_free(&secret); - prf_plus = prf_plus_create(this->prf, prf_plus_seed); - } - else - { - /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr) - * use OLD SAs PRF functions for both prf_plus and prf */ - secret = chunk_cat("mc", secret, full_nonce); - child_prf->allocate_bytes(child_prf, secret, &skeyseed); - DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); - old_prf->set_key(old_prf, skeyseed); - chunk_free(&skeyseed); - chunk_free(&secret); - prf_plus = prf_plus_create(old_prf, prf_plus_seed); - } - chunk_free(&full_nonce); - chunk_free(&fixed_nonce); - chunk_free(&prf_plus_seed); - - /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */ - - /* SK_d is used for generating CHILD_SA key mat => child_prf */ - proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL); - this->child_prf = lib->crypto->create_prf(lib->crypto, alg); - key_size = this->child_prf->get_key_size(this->child_prf); - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_d secret %B", &key); - this->child_prf->set_key(this->child_prf, key); - chunk_free(&key); - - /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */ - if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)) - { - DBG1(DBG_IKE, "no %N selected", - transform_type_names, INTEGRITY_ALGORITHM); - return FAILED; - } - signer_i = lib->crypto->create_signer(lib->crypto, alg); - signer_r = lib->crypto->create_signer(lib->crypto, alg); - if (signer_i == NULL || signer_r == NULL) - { - DBG1(DBG_IKE, "%N %N not supported!", - transform_type_names, INTEGRITY_ALGORITHM, - integrity_algorithm_names ,alg); - prf_plus->destroy(prf_plus); - return FAILED; - } - key_size = signer_i->get_key_size(signer_i); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ai secret %B", &key); - signer_i->set_key(signer_i, key); - chunk_free(&key); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ar secret %B", &key); - signer_r->set_key(signer_r, key); - chunk_free(&key); - - if (initiator) - { - this->signer_in = signer_r; - this->signer_out = signer_i; - } - else - { - this->signer_in = signer_i; - this->signer_out = signer_r; - } - - /* SK_ei/SK_er used for encryption => crypter_in/crypter_out */ - if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size)) - { - DBG1(DBG_IKE, "no %N selected", - transform_type_names, ENCRYPTION_ALGORITHM); - prf_plus->destroy(prf_plus); - return FAILED; - } - crypter_i = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); - crypter_r = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); - if (crypter_i == NULL || crypter_r == NULL) - { - DBG1(DBG_IKE, "%N %N (key size %d) not supported!", - transform_type_names, ENCRYPTION_ALGORITHM, - encryption_algorithm_names, alg, key_size); - prf_plus->destroy(prf_plus); - return FAILED; - } - key_size = crypter_i->get_key_size(crypter_i); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ei secret %B", &key); - crypter_i->set_key(crypter_i, key); - chunk_free(&key); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_er secret %B", &key); - crypter_r->set_key(crypter_r, key); - chunk_free(&key); - - if (initiator) - { - this->crypter_in = crypter_r; - this->crypter_out = crypter_i; - } - else - { - this->crypter_in = crypter_i; - this->crypter_out = crypter_r; - } - - /* SK_pi/SK_pr used for authentication => stored for later */ - key_size = this->prf->get_key_size(this->prf); - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_pi secret %B", &key); - if (initiator) - { - this->skp_build = key; - } - else - { - this->skp_verify = key; - } - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_pr secret %B", &key); - if (initiator) - { - this->skp_verify = key; - } - else - { - this->skp_build = key; - } - - /* all done, prf_plus not needed anymore */ - prf_plus->destroy(prf_plus); - - return SUCCESS; -} - -/** - * Implementation of ike_sa_t.get_proposal. - */ -static char* get_proposal(private_ike_sa_t *this) -{ - return this->selected_proposal; -} - -/** - * Implementation of ike_sa_t.set_proposal. - */ -static void set_proposal(private_ike_sa_t *this, char *proposal) -{ - free(this->selected_proposal); - this->selected_proposal = strdup(proposal); -} - -/** * Implementation of ike_sa_t.add_child_sa. */ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa) @@ -1939,10 +1668,10 @@ static status_t delete_(private_ike_sa_t *this) this->task_manager->queue_task(this->task_manager, &ike_delete->task); return this->task_manager->initiate(this->task_manager); case IKE_CREATED: - SIG_IKE(DOWN_SUCCESS, "deleting unestablished IKE_SA"); + DBG1(DBG_IKE, "deleting unestablished IKE_SA"); break; default: - SIG_IKE(DOWN_SUCCESS, "destroying IKE_SA in state %N " + DBG1(DBG_IKE, "destroying IKE_SA in state %N " "without notification", ike_sa_state_names, this->state); break; } @@ -1972,7 +1701,7 @@ static status_t reauth(private_ike_sa_t *this) /* we can't reauthenticate as responder when we use EAP or virtual IPs. * If the peer does not support RFC4478, there is no way to keep the * IKE_SA up. */ - if (!this->ike_initiator) + if (!has_condition(this, COND_ORIGINAL_INITIATOR)) { DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); if (this->other_virtual_ip != NULL || @@ -1985,7 +1714,8 @@ static status_t reauth(private_ike_sa_t *this) { time_t now = time(NULL); - DBG1(DBG_IKE, "IKE_SA will timeout in %#V", &now, &this->time.delete); + DBG1(DBG_IKE, "IKE_SA will timeout in %#V", + &now, &this->stats[STAT_DELETE]); return FAILED; } else @@ -2049,7 +1779,7 @@ static status_t reestablish(private_ike_sa_t *this) } /* check if we are able to reestablish this IKE_SA */ - if (!this->ike_initiator && + if (!has_condition(this, COND_ORIGINAL_INITIATOR) && (this->other_virtual_ip != NULL || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME @@ -2133,7 +1863,7 @@ static status_t reestablish(private_ike_sa_t *this) */ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) { - this->time.outbound = time(NULL); + this->stats[STAT_OUTBOUND] = time(NULL); if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS) { /* send a proper signal to brief interested bus listeners */ @@ -2146,19 +1876,19 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) this->keyingtry++; if (tries == 0 || tries > this->keyingtry) { - SIG_IKE(UP_FAILED, "peer not responding, trying again " - "(%d/%d) in background ", this->keyingtry + 1, tries); + DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)", + this->keyingtry + 1, tries); reset(this); return this->task_manager->initiate(this->task_manager); } - SIG_IKE(UP_FAILED, "establishing IKE_SA failed, peer not responding"); + DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding"); break; } case IKE_DELETING: - SIG_IKE(DOWN_FAILED, "proper IKE_SA delete failed, peer not responding"); + DBG1(DBG_IKE, "proper IKE_SA delete failed, peer not responding"); break; case IKE_REKEYING: - SIG_IKE(REKEY_FAILED, "rekeying IKE_SA failed, peer not responding"); + DBG1(DBG_IKE, "rekeying IKE_SA failed, peer not responding"); /* FALL */ default: reestablish(this); @@ -2184,9 +1914,10 @@ static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime) charon->processor->queue_job(charon->processor, (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE)); } - else if (this->time.reauth == 0 || this->time.reauth > reauth_time) + else if (this->stats[STAT_REAUTH] == 0 || + this->stats[STAT_REAUTH] > reauth_time) { - this->time.reauth = reauth_time; + this->stats[STAT_REAUTH] = reauth_time; DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" " in %ds", lifetime, lifetime - reduction); charon->scheduler->schedule_job(charon->scheduler, @@ -2196,7 +1927,7 @@ static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime) else { DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, reauthentication already " - "scheduled in %ds", lifetime, this->time.reauth - time(NULL)); + "scheduled in %ds", lifetime, this->stats[STAT_REAUTH] - time(NULL)); } } @@ -2275,7 +2006,6 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) this->other_host = other->other_host->clone(other->other_host); this->my_id = other->my_id->clone(other->my_id); this->other_id = other->other_id->clone(other->other_id); - this->ike_initiator = other->ike_initiator; /* apply virtual assigned IPs... */ if (other->my_virtual_ip) @@ -2296,7 +2026,7 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) this->dns_servers->insert_first(this->dns_servers, ip); } - /* inherit NAT-T conditions */ + /* inherit all conditions */ this->conditions = other->conditions; if (this->conditions & COND_NAT_HERE) { @@ -2326,14 +2056,14 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) this->task_manager->adopt_tasks(this->task_manager, other->task_manager); /* reauthentication timeout survives a rekeying */ - if (other->time.reauth) + if (other->stats[STAT_REAUTH]) { time_t reauth, delete, now = time(NULL); - this->time.reauth = other->time.reauth; - reauth = this->time.reauth - now; + this->stats[STAT_REAUTH] = other->stats[STAT_REAUTH]; + reauth = this->stats[STAT_REAUTH] - now; delete = reauth + this->peer_cfg->get_over_time(this->peer_cfg); - this->time.delete = this->time.reauth + delete; + this->stats[STAT_DELETE] = this->stats[STAT_REAUTH] + delete; DBG1(DBG_IKE, "rescheduling reauthentication in %ds after rekeying, " "lifetime reduced to %ds", reauth, delete); charon->scheduler->schedule_job(charon->scheduler, @@ -2421,7 +2151,7 @@ static void remove_dns_servers(private_ike_sa_t *this) if (!found) { /* write line untouched back to file */ - fwrite(orig_line.ptr, orig_line.len, 1, file); + ignore_result(fwrite(orig_line.ptr, orig_line.len, 1, file)); fprintf(file, "\n"); } } @@ -2475,7 +2205,7 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns) { this->dns_servers->insert_last(this->dns_servers, dns->clone(dns)); } - fwrite(contents.ptr, contents.len, 1, file); + ignore_result(fwrite(contents.ptr, contents.len, 1, file)); fclose(file); } @@ -2485,19 +2215,17 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns) */ static void destroy(private_ike_sa_t *this) { + charon->bus->set_sa(charon->bus, &this->public); + + set_state(this, IKE_DESTROYING); + this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy)); - this->task_manager->destroy(this->task_manager); + /* unset SA after here to avoid usage by the listeners */ + charon->bus->set_sa(charon->bus, NULL); - DESTROY_IF(this->crypter_in); - DESTROY_IF(this->crypter_out); - DESTROY_IF(this->signer_in); - DESTROY_IF(this->signer_out); - DESTROY_IF(this->prf); - DESTROY_IF(this->child_prf); - chunk_free(&this->skp_verify); - chunk_free(&this->skp_build); - free(this->selected_proposal); + this->task_manager->destroy(this->task_manager); + this->keymat->destroy(this->keymat); if (this->my_virtual_ip) { @@ -2535,12 +2263,15 @@ static void destroy(private_ike_sa_t *this) DESTROY_IF(this->other_host); DESTROY_IF(this->my_id); DESTROY_IF(this->other_id); + DESTROY_IF(this->local_host); + DESTROY_IF(this->remote_host); DESTROY_IF(this->eap_identity); 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->ike_sa_id->destroy(this->ike_sa_id); free(this); @@ -2570,6 +2301,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) 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_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; this->public.get_my_host = (host_t* (*)(ike_sa_t*)) get_my_host; this->public.set_my_host = (void (*)(ike_sa_t*,host_t*)) set_my_host; @@ -2588,7 +2321,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.has_condition = (bool (*)(ike_sa_t*,ike_condition_t)) has_condition; this->public.set_pending_updates = (void(*)(ike_sa_t*, u_int32_t updates))set_pending_updates; this->public.get_pending_updates = (u_int32_t(*)(ike_sa_t*))get_pending_updates; - this->public.is_ike_initiator = (bool (*)(ike_sa_t*))is_ike_initiator; this->public.create_additional_address_iterator = (iterator_t*(*)(ike_sa_t*))create_additional_address_iterator; this->public.add_additional_address = (void(*)(ike_sa_t*, host_t *host))add_additional_address; this->public.has_mapping_changed = (bool(*)(ike_sa_t*, chunk_t hash))has_mapping_changed; @@ -2597,13 +2329,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.destroy = (void (*)(ike_sa_t*))destroy; this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd; this->public.send_keepalive = (void (*)(ike_sa_t*)) send_keepalive; - this->public.get_prf = (prf_t* (*)(ike_sa_t*)) get_prf; - this->public.get_child_prf = (prf_t* (*)(ike_sa_t *)) get_child_prf; - this->public.get_skp_verify = (chunk_t (*)(ike_sa_t *)) get_skp_verify; - this->public.get_skp_build = (chunk_t (*)(ike_sa_t *)) get_skp_build; - this->public.derive_keys = (status_t (*)(ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys; - this->public.get_proposal = (char* (*)(ike_sa_t*)) get_proposal; - this->public.set_proposal = (void (*)(ike_sa_t*,char*)) set_proposal; + this->public.get_keymat = (keymat_t*(*)(ike_sa_t*))get_keymat; this->public.add_child_sa = (void (*)(ike_sa_t*,child_sa_t*)) add_child_sa; this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa; this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator; @@ -2622,6 +2348,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_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.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; this->public.get_server_reflexive_host = (host_t* (*)(ike_sa_t*)) get_server_reflexive_host; @@ -2637,34 +2364,24 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) /* initialize private fields */ this->ike_sa_id = ike_sa_id->clone(ike_sa_id); this->child_sas = linked_list_create(); - this->my_host = host_create_from_string("0.0.0.0", IKEV2_UDP_PORT); - this->other_host = host_create_from_string("0.0.0.0", IKEV2_UDP_PORT); + this->my_host = host_create_any(AF_INET); + this->other_host = host_create_any(AF_INET); this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->eap_identity = NULL; this->extensions = 0; this->conditions = 0; - this->selected_proposal = NULL; - this->crypter_in = NULL; - this->crypter_out = NULL; - this->signer_in = NULL; - this->signer_out = NULL; - this->prf = NULL; - this->skp_verify = chunk_empty; - this->skp_build = chunk_empty; - this->child_prf = NULL; + this->keymat = keymat_create(ike_sa_id->is_initiator(ike_sa_id)); this->state = IKE_CREATED; this->keepalive_interval = lib->settings->get_time(lib->settings, "charon.keep_alive", KEEPALIVE_INTERVAL); - this->time.inbound = this->time.outbound = time(NULL); - this->time.established = 0; - this->time.rekey = 0; - this->time.reauth = 0; - this->time.delete = 0; + memset(this->stats, 0, sizeof(this->stats)); + 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->proposal = NULL; this->task_manager = task_manager_create(&this->public); this->unique_id = ++unique_id; this->my_virtual_ip = NULL; @@ -2674,7 +2391,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->nat_detection_dest = chunk_empty; this->pending_updates = 0; this->keyingtry = 0; - this->ike_initiator = FALSE; + this->local_host = NULL; + this->remote_host = NULL; #ifdef ME this->is_mediation_server = FALSE; this->server_reflexive_host = NULL; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 717d41647..5aa458704 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-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -15,7 +15,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_sa.h 4368 2008-10-06 13:37:04Z martin $ + * $Id: ike_sa.h 4640 2008-11-12 16:07:17Z martin $ */ /** @@ -38,9 +38,7 @@ typedef struct ike_sa_t ike_sa_t; #include <sa/ike_sa_id.h> #include <sa/child_sa.h> #include <sa/tasks/task.h> -#include <crypto/prfs/prf.h> -#include <crypto/crypters/crypter.h> -#include <crypto/signers/signer.h> +#include <sa/keymat.h> #include <config/peer_cfg.h> #include <config/ike_cfg.h> #include <credentials/auth_info.h> @@ -110,32 +108,41 @@ enum ike_condition_t { * Faking NAT to enforce UDP encapsulation */ COND_NAT_FAKE = (1<<3), - + /** * peer has ben authenticated using EAP */ COND_EAP_AUTHENTICATED = (1<<4), - + /** * received a certificate request from the peer */ COND_CERTREQ_SEEN = (1<<5), + + /** + * Local peer is the "original" IKE initiator. Unaffected from rekeying. + */ + COND_ORIGINAL_INITIATOR = (1<<6), }; /** - * Information and statistics to query from an SA + * Timing information and statistics to query from an SA */ enum statistic_t { - - /** - * Relative time for scheduled rekeying - */ - STAT_REKEY_TIME, - - /** - * Relative time for scheduled reauthentication - */ - STAT_REAUTH_TIME, + /** Timestamp of SA establishement */ + STAT_ESTABLISHED = 0, + /** Timestamp of scheudled rekeying */ + STAT_REKEY, + /** Timestamp of scheudled reauthentication */ + STAT_REAUTH, + /** Timestamp of scheudled delete */ + STAT_DELETE, + /** Timestamp of last inbound IKE packet */ + STAT_INBOUND, + /** Timestamp of last outbound IKE packet */ + STAT_OUTBOUND, + + STAT_MAX }; /** @@ -201,6 +208,11 @@ enum ike_sa_state_t { * IKE_SA is in progress of deletion */ IKE_DELETING, + + /** + * IKE_SA object gets destroyed + */ + IKE_DESTROYING, }; /** @@ -388,6 +400,20 @@ struct ike_sa_t { auth_info_t* (*get_other_auth)(ike_sa_t *this); /** + * Get the selected proposal of this IKE_SA. + * + * @return selected proposal + */ + proposal_t* (*get_proposal)(ike_sa_t *this); + + /** + * Set the proposal selected for this IKE_SA. + * + * @param selected proposal + */ + void (*set_proposal)(ike_sa_t *this, proposal_t *proposal); + + /** * Add an additional address for the peer. * * In MOBIKE, a peer may transmit additional addresses where it is @@ -462,13 +488,6 @@ struct ike_sa_t { */ void (*set_pending_updates)(ike_sa_t *this, u_int32_t updates); - /** - * Check if we are the original initiator of this IKE_SA (rekeying does not - * change this flag). - */ - bool (*is_ike_initiator)(ike_sa_t *this); - - #ifdef ME /** * Activate mediation server functionality for this IKE_SA. @@ -705,70 +724,13 @@ struct ike_sa_t { * was sent. */ void (*send_keepalive) (ike_sa_t *this); - - /** - * Derive all keys and create the transforms for IKE communication. - * - * Keys are derived using the diffie hellman secret, nonces and internal - * stored SPIs. - * Key derivation differs when an IKE_SA is set up to replace an - * existing IKE_SA (rekeying). The SK_d key from the old IKE_SA - * is included in the derivation process. - * - * @param proposal proposal which contains algorithms to use - * @param secret secret derived from DH exchange, gets freed - * @param nonce_i initiators nonce - * @param nonce_r responders nonce - * @param initiator TRUE if initiator, FALSE otherwise - * @param child_prf PRF with SK_d key when rekeying, NULL otherwise - * @param old_prf general purpose PRF of old SA when rekeying - */ - status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal, chunk_t secret, - chunk_t nonce_i, chunk_t nonce_r, - bool initiator, prf_t *child_prf, prf_t *old_prf); /** - * Get the selected IKE proposal string + * Get the keying material of this IKE_SA. * - * @return string describing the selected IKE proposal - */ - char* (*get_proposal)(ike_sa_t *this); - - /** - * Set the selected IKE proposal string for status information purposes - * (the "%P" printf format handler is used) - * - * @param proposal string describing the selected IKE proposal - */ - void (*set_proposal)(ike_sa_t *this, char *proposal); - - /** - * Get a multi purpose prf for the negotiated PRF function. - * - * @return pointer to prf_t object - */ - prf_t *(*get_prf) (ike_sa_t *this); - - /** - * Get the prf-object, which is used to derive keys for child SAs. - * - * @return pointer to prf_t object - */ - prf_t *(*get_child_prf) (ike_sa_t *this); - - /** - * Get the key to build outgoing authentication data. - * - * @return pointer to prf_t object - */ - chunk_t (*get_skp_build) (ike_sa_t *this); - - /** - * Get the key to verify incoming authentication data. - * - * @return pointer to prf_t object + * @return per IKE_SA keymat instance */ - chunk_t (*get_skp_verify) (ike_sa_t *this); + keymat_t* (*get_keymat)(ike_sa_t *this); /** * Associates a child SA to this IKE SA @@ -901,6 +863,17 @@ struct ike_sa_t { void (*add_dns_server) (ike_sa_t *this, host_t *dns); /** + * Set local and remote host addresses to be used for IKE. + * + * These addresses are communicated via the KMADDRESS field of a MIGRATE + * message sent via the NETLINK or PF _KEY kernel socket interface. + * + * @param local local kmaddress + * @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. * * When rekeying is completed, all CHILD_SAs, the virtual IP and all diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index bd7b84c6f..a760409c0 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -13,10 +13,9 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_sa_manager.c 4234 2008-07-30 14:15:08Z martin $ + * $Id: ike_sa_manager.c 4579 2008-11-05 11:29:56Z martin $ */ -#include <pthread.h> #include <string.h> #include "ike_sa_manager.h" @@ -24,6 +23,7 @@ #include <daemon.h> #include <sa/ike_sa_id.h> #include <bus/bus.h> +#include <utils/mutex.h> #include <utils/linked_list.h> #include <crypto/hashers/hasher.h> @@ -42,7 +42,7 @@ struct entry_t { /** * Condvar where threads can wait until ike_sa_t object is free for use again. */ - pthread_cond_t condvar; + condvar_t *condvar; /** * Is this ike_sa currently checked out? @@ -107,6 +107,7 @@ static status_t entry_destroy(entry_t *this) DESTROY_IF(this->other); DESTROY_IF(this->my_id); DESTROY_IF(this->other_id); + this->condvar->destroy(this->condvar); free(this); return SUCCESS; } @@ -119,7 +120,7 @@ static entry_t *entry_create(ike_sa_id_t *ike_sa_id) entry_t *this = malloc_thing(entry_t); this->waiting_threads = 0; - pthread_cond_init(&this->condvar, NULL); + this->condvar = condvar_create(CONDVAR_DEFAULT); /* we set checkout flag when we really give it out */ this->checked_out = FALSE; @@ -155,7 +156,7 @@ struct private_ike_sa_manager_t { /** * Lock for exclusivly accessing the manager. */ - pthread_mutex_t mutex; + mutex_t *mutex; /** * Linked list with entries for the ike_sa_t objects. @@ -278,9 +279,9 @@ static status_t delete_entry(private_ike_sa_manager_t *this, entry_t *entry) while (entry->waiting_threads) { /* wake up all */ - pthread_cond_broadcast(&(entry->condvar)); + entry->condvar->broadcast(entry->condvar); /* they will wake us again when their work is done */ - pthread_cond_wait(&(entry->condvar), &(this->mutex)); + entry->condvar->wait(entry->condvar, this->mutex); } DBG2(DBG_MGR, "found entry by pointer, deleting it"); @@ -310,14 +311,14 @@ static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry) /* so wait until we can get it for us. * we register us as waiting. */ entry->waiting_threads++; - pthread_cond_wait(&(entry->condvar), &(this->mutex)); + entry->condvar->wait(entry->condvar, this->mutex); entry->waiting_threads--; } /* hm, a deletion request forbids us to get this SA, get next one */ if (entry->driveout_waiting_threads) { /* we must signal here, others may be waiting on it, too */ - pthread_cond_signal(&(entry->condvar)); + entry->condvar->signal(entry->condvar); return FALSE; } return TRUE; @@ -345,7 +346,7 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id DBG2(DBG_MGR, "checkout IKE_SA, %d IKE_SAs in manager", this->ike_sa_list->get_count(this->ike_sa_list)); - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) { if (wait_for_entry(this, entry)) @@ -355,7 +356,7 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id ike_sa = entry->ike_sa; } } - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; } @@ -378,10 +379,10 @@ static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator) } entry = entry_create(id); id->destroy(id); - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); this->ike_sa_list->insert_last(this->ike_sa_list, entry); entry->checked_out = TRUE; - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); DBG2(DBG_MGR, "created IKE_SA, %d IKE_SAs in manager", this->ike_sa_list->get_count(this->ike_sa_list)); return entry->ike_sa; @@ -413,7 +414,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, this->hasher->allocate_hash(this->hasher, data, &hash); chunk_free(&data); - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); while (enumerator->enumerate(enumerator, &entry)) { @@ -422,7 +423,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, if (entry->message_id == 0) { enumerator->destroy(enumerator); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); chunk_free(&hash); id->destroy(id); DBG1(DBG_MGR, "ignoring IKE_SA_INIT, already processing"); @@ -439,7 +440,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, } } enumerator->destroy(enumerator); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); if (ike_sa == NULL) { @@ -450,11 +451,11 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, id->set_responder_spi(id, get_next_spi(this)); entry = entry_create(id); - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); this->ike_sa_list->insert_last(this->ike_sa_list, entry); entry->checked_out = TRUE; entry->message_id = message->get_message_id(message); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); entry->init_hash = hash; ike_sa = entry->ike_sa; } @@ -473,7 +474,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, return ike_sa; } - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_entry_by_id(this, id, &entry) == SUCCESS) { /* only check out if we are not processing this request */ @@ -496,7 +497,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, ike_sa = entry->ike_sa; } } - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); id->destroy(id); charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; @@ -521,7 +522,7 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, 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); - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (my_host && other_host && this->reuse_ikesa) { @@ -553,8 +554,9 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, /* IKE_SA has no IDs yet, so we can't use it */ continue; } - DBG2(DBG_MGR, "candidate IKE_SA for \n\t" - "%H[%D]...%H[%D]\n\t%H[%D]...%H[%D]", + 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 @@ -603,7 +605,7 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, new_entry->checked_out = TRUE; ike_sa = new_entry->ike_sa; } - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; } @@ -620,7 +622,7 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id, ike_sa_t *ike_sa = NULL; child_sa_t *child_sa; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); while (enumerator->enumerate(enumerator, &entry)) @@ -657,7 +659,7 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id, } } enumerator->destroy(enumerator); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; @@ -675,7 +677,7 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name, ike_sa_t *ike_sa = NULL; child_sa_t *child_sa; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); while (enumerator->enumerate(enumerator, &entry)) @@ -712,7 +714,7 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name, } } enumerator->destroy(enumerator); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; @@ -732,7 +734,7 @@ static ike_sa_t* checkout_duplicate(private_ike_sa_manager_t *this, me = ike_sa->get_my_id(ike_sa); other = ike_sa->get_other_id(ike_sa); - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); while (enumerator->enumerate(enumerator, &entry)) { @@ -755,7 +757,7 @@ static ike_sa_t* checkout_duplicate(private_ike_sa_manager_t *this, } } enumerator->destroy(enumerator); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); return duplicate; } @@ -764,7 +766,7 @@ static ike_sa_t* checkout_duplicate(private_ike_sa_manager_t *this, */ static void enumerator_unlock(private_ike_sa_manager_t *this) { - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); } /** @@ -786,7 +788,7 @@ static bool enumerator_filter(private_ike_sa_manager_t *this, */ static enumerator_t *create_enumerator(private_ike_sa_manager_t* this) { - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); return enumerator_create_filter( this->ike_sa_list->create_enumerator(this->ike_sa_list), (void*)enumerator_filter, this, (void*)enumerator_unlock); @@ -812,7 +814,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) DBG2(DBG_MGR, "checkin IKE_SA"); - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); /* look for the entry */ if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) @@ -845,7 +847,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) entry->other_id = other_id->clone(other_id); } DBG2(DBG_MGR, "check-in of IKE_SA successful."); - pthread_cond_signal(&(entry->condvar)); + entry->condvar->signal(entry->condvar); retval = SUCCESS; } else @@ -857,7 +859,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) DBG2(DBG_MGR, "%d IKE_SAs in manager now", this->ike_sa_list->get_count(this->ike_sa_list)); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); charon->bus->set_sa(charon->bus, NULL); return retval; @@ -880,9 +882,8 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik ike_sa_id = ike_sa->get_id(ike_sa); DBG2(DBG_MGR, "checkin and destroy IKE_SA"); - charon->bus->set_sa(charon->bus, NULL); - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) { @@ -899,8 +900,9 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik DBG2(DBG_MGR, "tried to check-in and delete nonexisting IKE_SA"); retval = NOT_FOUND; } + charon->bus->set_sa(charon->bus, NULL); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return retval; } @@ -913,7 +915,7 @@ static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip) entry_t *entry; int count = 0; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); while (enumerator->enumerate(enumerator, &entry)) { @@ -937,7 +939,7 @@ static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip) } enumerator->destroy(enumerator); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return count; } @@ -950,7 +952,7 @@ static void flush(private_ike_sa_manager_t *this) enumerator_t *enumerator; entry_t *entry; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); DBG2(DBG_MGR, "going to destroy IKE_SA manager and all managed IKE_SA's"); /* Step 1: drive out all waiting threads */ DBG2(DBG_MGR, "set driveout flags for all stored IKE_SA's"); @@ -970,9 +972,9 @@ static void flush(private_ike_sa_manager_t *this) while (entry->waiting_threads) { /* wake up all */ - pthread_cond_broadcast(&(entry->condvar)); + entry->condvar->broadcast(entry->condvar); /* go sleeping until they are gone */ - pthread_cond_wait(&(entry->condvar), &(this->mutex)); + entry->condvar->wait(entry->condvar, this->mutex); } } enumerator->destroy(enumerator); @@ -981,6 +983,7 @@ static void flush(private_ike_sa_manager_t *this) enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); while (enumerator->enumerate(enumerator, &entry)) { + charon->bus->set_sa(charon->bus, entry->ike_sa); entry->ike_sa->delete(entry->ike_sa); } enumerator->destroy(enumerator); @@ -990,9 +993,11 @@ static void flush(private_ike_sa_manager_t *this) while (this->ike_sa_list->remove_last(this->ike_sa_list, (void**)&entry) == SUCCESS) { + charon->bus->set_sa(charon->bus, entry->ike_sa); entry_destroy(entry); } - pthread_mutex_unlock(&(this->mutex)); + charon->bus->set_sa(charon->bus, NULL); + this->mutex->unlock(this->mutex); } /** @@ -1003,7 +1008,7 @@ static void destroy(private_ike_sa_manager_t *this) this->ike_sa_list->destroy(this->ike_sa_list); this->rng->destroy(this->rng); this->hasher->destroy(this->hasher); - + this->mutex->destroy(this->mutex); free(this); } @@ -1046,7 +1051,7 @@ ike_sa_manager_t *ike_sa_manager_create() return NULL; } this->ike_sa_list = linked_list_create(); - pthread_mutex_init(&this->mutex, NULL); + this->mutex = mutex_create(MUTEX_DEFAULT); this->reuse_ikesa = lib->settings->get_bool(lib->settings, "charon.reuse_ikesa", TRUE); return &this->public; diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index 04b6d96c2..3f0752cc8 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_sa_manager.h 3819 2008-04-17 10:46:25Z martin $ + * $Id: ike_sa_manager.h 4624 2008-11-11 13:11:44Z tobias $ */ /** @@ -59,7 +59,7 @@ struct ike_sa_manager_t { * Create and check out a new IKE_SA. * * @param initiator TRUE for initiator, FALSE otherwise - * @returns created andchecked out IKE_SA + * @returns created and checked out IKE_SA */ ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, bool initiator); @@ -67,13 +67,13 @@ struct ike_sa_manager_t { * Checkout an IKE_SA by a message. * * In some situations, it is necessary that the manager knows the - * message to use for the checkout. This has the folloing reasons: + * message to use for the checkout. This has the following reasons: * * 1. If the targeted IKE_SA is already processing a message, we do not * check it out if the message ID is the same. * 2. If it is an IKE_SA_INIT request, we have to check if it is a * retransmission. If so, we have to drop the message, we would - * create another unneded IKE_SA for each retransmitted packet. + * create another unneeded IKE_SA for each retransmitted packet. * * A call to checkout_by_message() returns a (maybe new created) IKE_SA. * If processing the message does not make sense (for the reasons above), diff --git a/src/charon/sa/keymat.c b/src/charon/sa/keymat.c new file mode 100644 index 000000000..c65bfc3b7 --- /dev/null +++ b/src/charon/sa/keymat.c @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "keymat.h" + +#include <daemon.h> +#include <crypto/prf_plus.h> + +typedef struct private_keymat_t private_keymat_t; + +/** + * Private data of an keymat_t object. + */ +struct private_keymat_t { + + /** + * Public keymat_t interface. + */ + keymat_t public; + + /** + * IKE_SA Role, initiator or responder + */ + bool initiator; + + /** + * inbound signer (verify) + */ + signer_t *signer_in; + + /** + * outbound signer (sign) + */ + signer_t *signer_out; + + /** + * inbound crypter (decrypt) + */ + crypter_t *crypter_in; + + /** + * outbound crypter (encrypt) + */ + crypter_t *crypter_out; + + /** + * General purpose PRF + */ + prf_t *prf; + + /** + * Key to derive key material from for CHILD_SAs, rekeying + */ + chunk_t skd; + + /** + * Key to build outging authentication data (SKp) + */ + chunk_t skp_build; + + /** + * Key to verify incoming authentication data (SKp) + */ + chunk_t skp_verify; +}; + +typedef struct keylen_entry_t keylen_entry_t; + +/** + * Implicit key length for an algorithm + */ +struct keylen_entry_t { + /** IKEv2 algorithm identifier */ + int algo; + /** key length in bits */ + int len; +}; + +#define END_OF_LIST -1 + +/** + * Keylen for encryption algos + */ +keylen_entry_t keylen_enc[] = { + {ENCR_DES, 64}, + {ENCR_3DES, 192}, + {END_OF_LIST, 0} +}; + +/** + * Keylen for integrity algos + */ +keylen_entry_t keylen_int[] = { + {AUTH_HMAC_MD5_96, 128}, + {AUTH_HMAC_SHA1_96, 160}, + {AUTH_HMAC_SHA2_256_128, 256}, + {AUTH_HMAC_SHA2_384_192, 384}, + {AUTH_HMAC_SHA2_512_256, 512}, + {AUTH_AES_XCBC_96, 128}, + {END_OF_LIST, 0} +}; + +/** + * Lookup key length of an algorithm + */ +static int lookup_keylen(keylen_entry_t *list, int algo) +{ + while (list->algo != END_OF_LIST) + { + if (algo == list->algo) + { + return list->len; + } + list++; + } + return 0; +} + +/** + * Implementation of keymat_t.create_dh + */ +static diffie_hellman_t* create_dh(private_keymat_t *this, + diffie_hellman_group_t group) +{ + return lib->crypto->create_dh(lib->crypto, group);; +} + +/** + * Implementation of keymat_t.derive_keys + */ +static bool derive_ike_keys(private_keymat_t *this, proposal_t *proposal, + diffie_hellman_t *dh, chunk_t nonce_i, + chunk_t nonce_r, ike_sa_id_t *id, + private_keymat_t *rekey) +{ + chunk_t skeyseed, key, secret, full_nonce, fixed_nonce, prf_plus_seed; + chunk_t spi_i, spi_r; + crypter_t *crypter_i, *crypter_r; + signer_t *signer_i, *signer_r; + prf_plus_t *prf_plus; + u_int16_t alg, key_size; + + spi_i = chunk_alloca(sizeof(u_int64_t)); + spi_r = chunk_alloca(sizeof(u_int64_t)); + + if (dh->get_shared_secret(dh, &secret) != SUCCESS) + { + return FALSE; + } + + /* Create SAs general purpose PRF first, we may use it here */ + if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, PSEUDO_RANDOM_FUNCTION); + return FALSE; + } + this->prf = lib->crypto->create_prf(lib->crypto, alg); + if (this->prf == NULL) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, alg); + return FALSE; + } + DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret); + /* full nonce is used as seed for PRF+ ... */ + full_nonce = chunk_cat("cc", nonce_i, nonce_r); + /* but the PRF may need a fixed key which only uses the first bytes of + * the nonces. */ + switch (alg) + { + case PRF_AES128_XCBC: + /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does + * not and therefore fixed key semantics apply to XCBC for key + * derivation. */ + key_size = this->prf->get_key_size(this->prf)/2; + nonce_i.len = min(nonce_i.len, key_size); + nonce_r.len = min(nonce_r.len, key_size); + break; + default: + /* all other algorithms use variable key length, full nonce */ + break; + } + fixed_nonce = chunk_cat("cc", nonce_i, nonce_r); + *((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id); + *((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id); + prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r); + + /* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr) + * + * if we are rekeying, SKEYSEED is built on another way + */ + if (rekey == NULL) /* not rekeying */ + { + /* SKEYSEED = prf(Ni | Nr, g^ir) */ + this->prf->set_key(this->prf, fixed_nonce); + this->prf->allocate_bytes(this->prf, secret, &skeyseed); + this->prf->set_key(this->prf, skeyseed); + prf_plus = prf_plus_create(this->prf, prf_plus_seed); + } + else + { + /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr) + * use OLD SAs PRF functions for both prf_plus and prf */ + secret = chunk_cat("mc", secret, full_nonce); + rekey->prf->set_key(rekey->prf, rekey->skd); + rekey->prf->allocate_bytes(rekey->prf, secret, &skeyseed); + rekey->prf->set_key(rekey->prf, skeyseed); + prf_plus = prf_plus_create(rekey->prf, prf_plus_seed); + } + DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); + + chunk_clear(&skeyseed); + chunk_clear(&secret); + chunk_free(&full_nonce); + chunk_free(&fixed_nonce); + chunk_clear(&prf_plus_seed); + + /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */ + + /* SK_d is used for generating CHILD_SA key mat => store for later use */ + key_size = this->prf->get_key_size(this->prf); + prf_plus->allocate_bytes(prf_plus, key_size, &this->skd); + DBG4(DBG_IKE, "Sk_d secret %B", &this->skd); + + /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */ + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, INTEGRITY_ALGORITHM); + return FALSE; + } + signer_i = lib->crypto->create_signer(lib->crypto, alg); + signer_r = lib->crypto->create_signer(lib->crypto, alg); + if (signer_i == NULL || signer_r == NULL) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, INTEGRITY_ALGORITHM, + integrity_algorithm_names ,alg); + prf_plus->destroy(prf_plus); + return FALSE; + } + key_size = signer_i->get_key_size(signer_i); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_ai secret %B", &key); + signer_i->set_key(signer_i, key); + chunk_clear(&key); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_ar secret %B", &key); + signer_r->set_key(signer_r, key); + chunk_clear(&key); + + if (this->initiator) + { + this->signer_in = signer_r; + this->signer_out = signer_i; + } + else + { + this->signer_in = signer_i; + this->signer_out = signer_r; + } + + /* SK_ei/SK_er used for encryption => crypter_in/crypter_out */ + if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, ENCRYPTION_ALGORITHM); + prf_plus->destroy(prf_plus); + return FALSE; + } + crypter_i = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); + crypter_r = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); + if (crypter_i == NULL || crypter_r == NULL) + { + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, alg, key_size); + prf_plus->destroy(prf_plus); + return FALSE; + } + key_size = crypter_i->get_key_size(crypter_i); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_ei secret %B", &key); + crypter_i->set_key(crypter_i, key); + chunk_clear(&key); + + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_er secret %B", &key); + crypter_r->set_key(crypter_r, key); + chunk_clear(&key); + + if (this->initiator) + { + this->crypter_in = crypter_r; + this->crypter_out = crypter_i; + } + else + { + this->crypter_in = crypter_i; + this->crypter_out = crypter_r; + } + + /* SK_pi/SK_pr used for authentication => stored for later */ + key_size = this->prf->get_key_size(this->prf); + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_pi secret %B", &key); + if (this->initiator) + { + this->skp_build = key; + } + else + { + this->skp_verify = key; + } + prf_plus->allocate_bytes(prf_plus, key_size, &key); + DBG4(DBG_IKE, "Sk_pr secret %B", &key); + if (this->initiator) + { + this->skp_verify = key; + } + else + { + this->skp_build = key; + } + + /* all done, prf_plus not needed anymore */ + prf_plus->destroy(prf_plus); + + return TRUE; +} + +/** + * Implementation of keymat_t.derive_child_keys + */ +static bool derive_child_keys(private_keymat_t *this, + proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, + chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r) +{ + u_int16_t enc_alg, int_alg, enc_size = 0, int_size = 0; + chunk_t seed, secret = chunk_empty; + prf_plus_t *prf_plus; + + if (dh) + { + if (dh->get_shared_secret(dh, &secret) != SUCCESS) + { + return FALSE; + } + DBG4(DBG_CHD, "DH secret %B", &secret); + } + seed = chunk_cata("mcc", secret, nonce_i, nonce_r); + DBG4(DBG_CHD, "seed %B", &seed); + + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, + &enc_alg, &enc_size)) + { + DBG2(DBG_CHD, " using %N for encryption", + encryption_algorithm_names, enc_alg); + + if (!enc_size) + { + enc_size = lookup_keylen(keylen_enc, enc_alg); + } + if (!enc_size) + { + DBG1(DBG_CHD, "no keylenth defined for %N", + encryption_algorithm_names, enc_alg); + return FALSE; + } + /* to bytes */ + enc_size /= 8; + + /* CCM/GCM 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; + case ENCR_AES_GCM_ICV8: + case ENCR_AES_GCM_ICV12: + case ENCR_AES_GCM_ICV16: + enc_size += 4; + break; + default: + break; + } + } + + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &int_alg, &int_size)) + { + DBG2(DBG_CHD, " using %N for integrity", + integrity_algorithm_names, int_alg); + + if (!int_size) + { + int_size = lookup_keylen(keylen_int, int_alg); + } + if (!int_size) + { + DBG1(DBG_CHD, "no keylenth defined for %N", + integrity_algorithm_names, int_alg); + return FALSE; + } + /* to bytes */ + int_size /= 8; + } + + this->prf->set_key(this->prf, this->skd); + prf_plus = prf_plus_create(this->prf, seed); + + prf_plus->allocate_bytes(prf_plus, enc_size, encr_i); + prf_plus->allocate_bytes(prf_plus, int_size, integ_i); + prf_plus->allocate_bytes(prf_plus, enc_size, encr_r); + prf_plus->allocate_bytes(prf_plus, int_size, integ_r); + + prf_plus->destroy(prf_plus); + + return TRUE; +} + +/** + * Implementation of keymat_t.get_signer + */ +static signer_t* get_signer(private_keymat_t *this, bool in) +{ + return in ? this->signer_in : this->signer_out; +} + +/** + * Implementation of keymat_t.get_crypter + */ +static crypter_t* get_crypter(private_keymat_t *this, bool in) +{ + return in ? this->crypter_in : this->crypter_out; +} + +/** + * Implementation of keymat_t.get_auth_octets + */ +static chunk_t get_auth_octets(private_keymat_t *this, bool verify, + chunk_t ike_sa_init, chunk_t nonce, + identification_t *id) +{ + chunk_t chunk, idx, octets; + chunk_t skp; + + skp = verify ? this->skp_verify : this->skp_build; + + chunk = chunk_alloca(4); + memset(chunk.ptr, 0, chunk.len); + chunk.ptr[0] = id->get_type(id); + idx = chunk_cata("cc", chunk, id->get_encoding(id)); + + DBG3(DBG_IKE, "IDx' %B", &idx); + DBG3(DBG_IKE, "SK_p %B", &skp); + this->prf->set_key(this->prf, skp); + this->prf->allocate_bytes(this->prf, idx, &chunk); + + octets = chunk_cat("ccm", ike_sa_init, nonce, chunk); + DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets); + return octets; +} + +/** + * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE. + */ +#define IKEV2_KEY_PAD "Key Pad for IKEv2" +#define IKEV2_KEY_PAD_LENGTH 17 + +/** + * Implementation of keymat_t.get_psk_sig + */ +static chunk_t get_psk_sig(private_keymat_t *this, bool verify, + chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, + identification_t *id) +{ + chunk_t key_pad, key, sig, octets; + + if (!secret.len) + { /* EAP uses SK_p if no MSK has been established */ + secret = verify ? this->skp_verify : this->skp_build; + } + octets = get_auth_octets(this, verify, ike_sa_init, nonce, id); + /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */ + key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH); + this->prf->set_key(this->prf, secret); + this->prf->allocate_bytes(this->prf, key_pad, &key); + this->prf->set_key(this->prf, key); + this->prf->allocate_bytes(this->prf, octets, &sig); + DBG4(DBG_IKE, "secret %B", &secret); + DBG4(DBG_IKE, "prf(secret, keypad) %B", &key); + DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &sig); + chunk_free(&octets); + chunk_free(&key); + + return sig; +} + +/** + * Implementation of keymat_t.destroy. + */ +static void destroy(private_keymat_t *this) +{ + DESTROY_IF(this->signer_in); + DESTROY_IF(this->signer_out); + DESTROY_IF(this->crypter_in); + DESTROY_IF(this->crypter_out); + DESTROY_IF(this->prf); + chunk_clear(&this->skd); + chunk_clear(&this->skp_verify); + chunk_clear(&this->skp_build); + free(this); +} + +/** + * See header + */ +keymat_t *keymat_create(bool initiator) +{ + private_keymat_t *this = malloc_thing(private_keymat_t); + + this->public.create_dh = (diffie_hellman_t*(*)(keymat_t*, diffie_hellman_group_t group))create_dh; + this->public.derive_ike_keys = (bool(*)(keymat_t*, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey))derive_ike_keys; + this->public.derive_child_keys = (bool(*)(keymat_t*, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r))derive_child_keys; + this->public.get_signer = (signer_t*(*)(keymat_t*, bool in))get_signer; + this->public.get_crypter = (crypter_t*(*)(keymat_t*, bool in))get_crypter; + this->public.get_auth_octets = (chunk_t(*)(keymat_t *, bool verify, chunk_t ike_sa_init, chunk_t nonce, identification_t *id))get_auth_octets; + this->public.get_psk_sig = (chunk_t(*)(keymat_t*, bool verify, chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, identification_t *id))get_psk_sig; + this->public.destroy = (void(*)(keymat_t*))destroy; + + this->initiator = initiator; + + this->signer_in = NULL; + this->signer_out = NULL; + this->crypter_in = NULL; + this->crypter_out = NULL; + this->prf = NULL; + this->skd = chunk_empty; + this->skp_verify = chunk_empty; + this->skp_build = chunk_empty; + + return &this->public; +} + diff --git a/src/charon/sa/keymat.h b/src/charon/sa/keymat.h new file mode 100644 index 000000000..3ca25da9e --- /dev/null +++ b/src/charon/sa/keymat.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +/** + * @defgroup keymat keymat + * @{ @ingroup sa + */ + +#ifndef KEYMAT_H_ +#define KEYMAT_H_ + +#include <library.h> +#include <utils/identification.h> +#include <crypto/prfs/prf.h> +#include <crypto/crypters/crypter.h> +#include <crypto/signers/signer.h> +#include <config/proposal.h> +#include <sa/ike_sa_id.h> + +typedef struct keymat_t keymat_t; + +/** + * Derivation an management of sensitive keying material. + */ +struct keymat_t { + + /** + * Create a diffie hellman object for key agreement. + * + * The diffie hellman is either for IKE negotiation/rekeying or + * CHILD_SA rekeying (using PFS). The resulting DH object must be passed + * to derive_keys or to derive_child_keys and destroyed after use + * + * @param group diffie hellman group + * @return DH object, NULL if group not supported + */ + diffie_hellman_t* (*create_dh)(keymat_t *this, diffie_hellman_group_t group); + + /** + * Derive keys for the IKE_SA. + * + * These keys are not handed out, but are used by the associated signers, + * crypters and authentication functions. + * + * @param proposal selected algorithms + * @param dh diffie hellman key allocated by create_dh() + * @param nonce_i initiators nonce value + * @param nonce_r responders nonce value + * @param id IKE_SA identifier + * @param rekey keymat of old SA if we are rekeying + * @return TRUE on success + */ + bool (*derive_ike_keys)(keymat_t *this, proposal_t *proposal, + diffie_hellman_t *dh, chunk_t nonce_i, + chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey); + /** + * Derive keys for a CHILD_SA. + * + * The keys for the CHILD_SA are allocated in the integ and encr chunks. + * An implementation might hand out encrypted keys only, which are + * decrypted in the kernel before use. + * If no PFS is used for the CHILD_SA, dh can be NULL. + * + * @param proposal selected algorithms + * @param dh diffie hellman key allocated by create_dh(), or NULL + * @param nonce_i initiators nonce value + * @param nonce_r responders nonce value + * @param encr_i chunk to write initiators encryption key to + * @param integ_i chunk to write initiators integrity key to + * @param encr_r chunk to write responders encryption key to + * @param integ_r chunk to write responders integrity key to + * @return TRUE on success + */ + bool (*derive_child_keys)(keymat_t *this, + proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, + chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r); + /** + * Get a signer to sign/verify IKE messages. + * + * @param in TRUE for inbound (verify), FALSE for outbound (sign) + * @return signer + */ + signer_t* (*get_signer)(keymat_t *this, bool in); + + /* + * Get a crypter to en-/decrypt IKE messages. + * + * @param in TRUE for inbound (decrypt), FALSE for outbound (encrypt) + * @return crypter + */ + crypter_t* (*get_crypter)(keymat_t *this, bool in); + + /** + * Generate octets to use for authentication procedure (RFC4306 2.15). + * + * This method creates the plain octets and is usually signed by a private + * key. PSK and EAP authentication include a secret into the data, use + * the get_psk_sig() method instead. + * + * @param verify TRUE to create for verfification, FALSE to sign + * @param ike_sa_init encoded ike_sa_init message + * @param nonce nonce value + * @param id identity + * @return authentication octets + */ + chunk_t (*get_auth_octets)(keymat_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, identification_t *id); + /** + * Build the shared secret signature used for PSK and EAP authentication. + * + * This method wraps the get_auth_octets() method and additionally + * includes the secret into the signature. If no secret is given, SK_p is + * used as secret (used for EAP methods without MSK). + * + * @param verify TRUE to create for verfification, FALSE to sign + * @param ike_sa_init encoded ike_sa_init message + * @param nonce nonce value + * @param secret optional secret to include into signature + * @param id identity + * @return signature octets + */ + chunk_t (*get_psk_sig)(keymat_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, chunk_t secret, identification_t *id); + /** + * Destroy a keymat_t. + */ + void (*destroy)(keymat_t *this); +}; + +/** + * Create a keymat instance. + * + * @param initiator TRUE if we are the initiator + * @return keymat instance + */ +keymat_t *keymat_create(bool initiator); + +#endif /* KEYMAT_ @}*/ diff --git a/src/charon/sa/mediation_manager.c b/src/charon/sa/mediation_manager.c index d15f4c100..b508c48c3 100644 --- a/src/charon/sa/mediation_manager.c +++ b/src/charon/sa/mediation_manager.c @@ -12,13 +12,13 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: mediation_manager.c 3773 2008-04-07 09:36:52Z tobias $ + * $Id: mediation_manager.c 4579 2008-11-05 11:29:56Z martin $ */ #include "mediation_manager.h" -#include <pthread.h> #include <daemon.h> +#include <utils/mutex.h> #include <utils/linked_list.h> #include <processing/jobs/mediation_job.h> @@ -80,7 +80,7 @@ struct private_mediation_manager_t { /** * Lock for exclusivly accessing the manager. */ - pthread_mutex_t mutex; + mutex_t *mutex; /** * Linked list with state entries. @@ -182,7 +182,7 @@ static void remove_sa(private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id) iterator_t *iterator; peer_t *peer; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); iterator = this->peers->create_iterator(this->peers, TRUE); while (iterator->iterate(iterator, (void**)&peer)) @@ -199,7 +199,7 @@ static void remove_sa(private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id) } iterator->destroy(iterator); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); } /** @@ -211,7 +211,7 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe peer_t *peer; bool found = FALSE; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); iterator = this->peers->create_iterator(this->peers, TRUE); while (iterator->iterate(iterator, (void**)&peer)) @@ -244,7 +244,7 @@ static void update_sa_id(private_mediation_manager_t *this, identification_t *pe requester->destroy(requester); } - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); } /** @@ -256,17 +256,17 @@ static ike_sa_id_t *check(private_mediation_manager_t *this, peer_t *peer; ike_sa_id_t *ike_sa_id; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_peer_by_id(this, peer_id, &peer) != SUCCESS) { - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return NULL; } ike_sa_id = peer->ike_sa_id; - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return ike_sa_id; } @@ -280,7 +280,7 @@ static ike_sa_id_t *check_and_register(private_mediation_manager_t *this, peer_t *peer; ike_sa_id_t *ike_sa_id; - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); if (get_peer_by_id(this, peer_id, &peer) != SUCCESS) { @@ -294,13 +294,13 @@ static ike_sa_id_t *check_and_register(private_mediation_manager_t *this, /* the peer is not online */ DBG2(DBG_IKE, "requested peer '%D' is offline, registering peer '%D'", peer_id, requester); register_peer(peer, requester); - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return NULL; } ike_sa_id = peer->ike_sa_id; - pthread_mutex_unlock(&(this->mutex)); + this->mutex->unlock(this->mutex); return ike_sa_id; } @@ -310,12 +310,12 @@ static ike_sa_id_t *check_and_register(private_mediation_manager_t *this, */ static void destroy(private_mediation_manager_t *this) { - pthread_mutex_lock(&(this->mutex)); + this->mutex->lock(this->mutex); this->peers->destroy_function(this->peers, (void*)peer_destroy); - pthread_mutex_unlock(&(this->mutex)); - pthread_mutex_destroy(&(this->mutex)); + this->mutex->unlock(this->mutex); + this->mutex->destroy(this->mutex); free(this); } @@ -333,7 +333,7 @@ mediation_manager_t *mediation_manager_create() this->public.check_and_register = (ike_sa_id_t*(*)(mediation_manager_t*,identification_t*,identification_t*))check_and_register; this->peers = linked_list_create(); - pthread_mutex_init(&(this->mutex), NULL); + this->mutex = mutex_create(MUTEX_DEFAULT); return (mediation_manager_t*)this; } diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index 25089477b..0630647c9 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: task_manager.c 4320 2008-09-02 14:02:40Z martin $ + * $Id: task_manager.c 4484 2008-10-27 11:13:33Z martin $ */ #include "task_manager.h" @@ -145,44 +145,15 @@ struct private_task_manager_t { */ static void flush(private_task_manager_t *this) { - task_t *task; - this->queued_tasks->destroy_offset(this->queued_tasks, offsetof(task_t, destroy)); this->passive_tasks->destroy_offset(this->passive_tasks, offsetof(task_t, destroy)); - - /* emmit outstanding signals for tasks */ - while (this->active_tasks->remove_last(this->active_tasks, - (void**)&task) == SUCCESS) - { - switch (task->get_type(task)) - { - case IKE_AUTH: - SIG_IKE(UP_FAILED, "establishing IKE_SA failed"); - break; - case IKE_DELETE: - SIG_IKE(DOWN_FAILED, "IKE_SA deleted"); - break; - case IKE_REKEY: - SIG_IKE(REKEY_FAILED, "rekeying IKE_SA failed"); - break; - case CHILD_CREATE: - SIG_CHD(UP_FAILED, NULL, "establishing CHILD_SA failed"); - break; - case CHILD_DELETE: - SIG_CHD(DOWN_FAILED, NULL, "deleting CHILD_SA failed"); - break; - case CHILD_REKEY: - SIG_IKE(REKEY_FAILED, "rekeying CHILD_SA failed"); - break; - default: - break; - } - task->destroy(task); - } + this->active_tasks->destroy_offset(this->active_tasks, + offsetof(task_t, destroy)); this->queued_tasks = linked_list_create(); this->passive_tasks = linked_list_create(); + this->active_tasks = linked_list_create(); } /** @@ -648,6 +619,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) DESTROY_IF(this->responding.packet); status = this->ike_sa->generate_message(this->ike_sa, message, &this->responding.packet); + charon->bus->message(charon->bus, message, FALSE); message->destroy(message); if (status != SUCCESS) { @@ -867,6 +839,7 @@ static status_t process_message(private_task_manager_t *this, message_t *msg) { if (mid == this->responding.mid) { + charon->bus->message(charon->bus, msg, TRUE); if (process_request(this, msg) != SUCCESS) { flush(this); diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index bddca621b..767ceef55 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_create.c 4358 2008-09-25 13:56:23Z tobias $ + * $Id: child_create.c 4618 2008-11-11 09:22:00Z tobias $ */ #include "child_create.h" @@ -97,6 +97,11 @@ struct private_child_create_t { diffie_hellman_group_t dh_group; /** + * IKE_SAs keymat + */ + keymat_t *keymat; + + /** * mode the new CHILD_SA uses (transport/tunnel/beet) */ ipsec_mode_t mode; @@ -191,38 +196,22 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host) */ static status_t select_and_install(private_child_create_t *this, bool no_dh) { - prf_plus_t *prf_plus; status_t status; - chunk_t nonce_i, nonce_r, secret, seed; + chunk_t nonce_i, nonce_r, encr_i, integ_i, encr_r, integ_r; linked_list_t *my_ts, *other_ts; host_t *me, *other, *other_vip, *my_vip; if (this->proposals == NULL) { - SIG_CHD(UP_FAILED, this->child_sa, "SA payload missing in message"); + DBG1(DBG_IKE, "SA payload missing in message"); return FAILED; } if (this->tsi == NULL || this->tsr == NULL) { - SIG_CHD(UP_FAILED, this->child_sa, "TS payloads missing in message"); + DBG1(DBG_IKE, "TS payloads missing in message"); return NOT_FOUND; } - if (this->initiator) - { - nonce_i = this->my_nonce; - nonce_r = this->other_nonce; - my_ts = this->tsi; - other_ts = this->tsr; - } - else - { - nonce_r = this->my_nonce; - nonce_i = this->other_nonce; - my_ts = this->tsr; - other_ts = this->tsi; - } - me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); @@ -232,7 +221,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) no_dh); if (this->proposal == NULL) { - SIG_CHD(UP_FAILED, this->child_sa, "no acceptable proposal found"); + DBG1(DBG_IKE, "no acceptable proposal found"); return FAILED; } @@ -243,15 +232,15 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { - SIG_CHD(UP_FAILED, this->child_sa, "DH group %N inacceptable, " - "requesting %N", diffie_hellman_group_names, this->dh_group, - diffie_hellman_group_names, group); + DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N", + diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); this->dh_group = group; return INVALID_ARG; } else { - SIG_CHD(UP_FAILED, this->child_sa, "no acceptable proposal found"); + DBG1(DBG_IKE, "no acceptable proposal found"); return FAILED; } } @@ -260,16 +249,25 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) { my_vip = me; } - else if (this->initiator) - { - /* to setup firewall rules correctly, CHILD_SA needs the virtual IP */ - this->child_sa->set_virtual_ip(this->child_sa, my_vip); - } if (other_vip == NULL) { other_vip = other; } + if (this->initiator) + { + nonce_i = this->my_nonce; + nonce_r = this->other_nonce; + my_ts = this->tsi; + other_ts = this->tsr; + } + else + { + nonce_r = this->my_nonce; + nonce_i = this->other_nonce; + my_ts = this->tsr; + other_ts = this->tsi; + } my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts, my_vip); other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts, @@ -279,7 +277,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) { my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); - SIG_CHD(UP_FAILED, this->child_sa, "no acceptable traffic selectors found"); + DBG1(DBG_IKE, "no acceptable traffic selectors found"); return NOT_FOUND; } @@ -302,16 +300,18 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) switch (this->mode) { case MODE_TRANSPORT: - if (!ts_list_is_host(this->tsi, other) || - !ts_list_is_host(this->tsr, me)) + if (!this->config->use_proxy_mode(this->config) && + (!ts_list_is_host(this->tsi, other) || + !ts_list_is_host(this->tsr, me)) + ) { this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using tranport mode, not host-to-host"); + DBG1(DBG_IKE, "not using transport mode, not host-to-host"); } else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) { this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using tranport mode, connection NATed"); + DBG1(DBG_IKE, "not using transport mode, connection NATed"); } break; case MODE_BEET: @@ -327,55 +327,51 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh) } } - if (this->dh) + this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); + + if (this->ipcomp != IPCOMP_NONE) { - if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) - { - SIG_CHD(UP_FAILED, this->child_sa, "DH exchange incomplete"); - return FAILED; - } - DBG3(DBG_IKE, "DH secret %B", &secret); - seed = chunk_cata("mcc", secret, nonce_i, nonce_r); + this->child_sa->activate_ipcomp(this->child_sa, this->ipcomp, + this->other_cpi); } - else + + status = FAILED; + if (this->keymat->derive_child_keys(this->keymat, this->proposal, + this->dh, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) { - seed = chunk_cata("cc", nonce_i, nonce_r); + if (this->initiator) + { + status = this->child_sa->update(this->child_sa, this->proposal, + this->mode, integ_r, integ_i, encr_r, encr_i); + } + else + { + status = this->child_sa->add(this->child_sa, this->proposal, + this->mode, integ_i, integ_r, encr_i, encr_r); + } } + chunk_clear(&integ_i); + chunk_clear(&integ_r); + chunk_clear(&encr_i); + chunk_clear(&encr_r); - if (this->ipcomp != IPCOMP_NONE) + if (status != SUCCESS) { - this->child_sa->activate_ipcomp(this->child_sa, this->ipcomp, - this->other_cpi); + DBG1(DBG_IKE, "unable to install IPsec SA (SAD) in kernel"); + return FAILED; } status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts, this->mode, this->proposal->get_protocol(this->proposal)); if (status != SUCCESS) { - SIG_CHD(UP_FAILED, this->child_sa, - "unable to install IPsec policies (SPD) in kernel"); + DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); return NOT_FOUND; } - prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); - if (this->initiator) - { - status = this->child_sa->update(this->child_sa, this->proposal, - this->mode, prf_plus); - } - else - { - status = this->child_sa->add(this->child_sa, this->proposal, - this->mode, prf_plus); - } - prf_plus->destroy(prf_plus); + charon->bus->child_keys(charon->bus, this->child_sa, this->dh, + nonce_i, nonce_r); - if (status != SUCCESS) - { - SIG_CHD(UP_FAILED, this->child_sa, - "unable to install IPsec SA (SAD) in kernel"); - return FAILED; - } /* add to IKE_SA, and remove from task */ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); @@ -499,7 +495,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) if (!this->initiator) { this->dh_group = ke_payload->get_dh_group_number(ke_payload); - this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); + this->dh = this->keymat->create_dh(this->keymat, this->dh_group); } if (this->dh) { @@ -592,13 +588,13 @@ static status_t build_i(private_child_create_t *this, message_t *message) if (this->reqid) { - SIG_CHD(UP_START, NULL, "establishing CHILD_SA %s{%d}", - this->config->get_name(this->config), this->reqid); + DBG0(DBG_IKE, "establishing CHILD_SA %s{%d}", + this->config->get_name(this->config), this->reqid); } else { - SIG_CHD(UP_START, NULL, "establishing CHILD_SA %s", - this->config->get_name(this->config)); + DBG0(DBG_IKE, "establishing CHILD_SA %s", + this->config->get_name(this->config)); } /* reuse virtual IP if we already have one */ @@ -641,23 +637,19 @@ static status_t build_i(private_child_create_t *this, message_t *message) this->dh_group == MODP_NONE); this->mode = this->config->get_mode(this->config); - 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->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid, + 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, this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS) { - SIG_CHD(UP_FAILED, this->child_sa, - "unable to allocate SPIs from kernel"); + DBG1(DBG_IKE, "unable to allocate SPIs from kernel"); return FAILED; } if (this->dh_group != MODP_NONE) { - this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); + this->dh = this->keymat->create_dh(this->keymat, this->dh_group); } if (this->config->use_ipcomp(this->config)) { @@ -679,7 +671,7 @@ static status_t build_i(private_child_create_t *this, message_t *message) } /** - * Implementation of task_t.process for initiator + * Implementation of task_t.process for responder */ static status_t process_r(private_child_create_t *this, message_t *message) { @@ -785,16 +777,15 @@ static status_t build_r(private_child_create_t *this, message_t *message) if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) { - SIG_CHD(UP_FAILED, NULL, - "unable to create CHILD_SA while rekeying IKE_SA"); + DBG1(DBG_IKE, "unable to create CHILD_SA while rekeying IKE_SA"); message->add_notify(message, TRUE, NO_ADDITIONAL_SAS, chunk_empty); return SUCCESS; } if (this->config == NULL) { - SIG_CHD(UP_FAILED, NULL, "traffic selectors %#R=== %#R inacceptable", - this->tsr, this->tsi); + DBG1(DBG_IKE, "traffic selectors %#R=== %#R inacceptable", + this->tsr, this->tsi); message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); handle_child_sa_failure(this, message); return SUCCESS; @@ -813,8 +804,8 @@ static status_t build_r(private_child_create_t *this, message_t *message) case INTERNAL_ADDRESS_FAILURE: case FAILED_CP_REQUIRED: { - SIG_CHD(UP_FAILED, NULL, "configuration payload negotation " - "failed, no CHILD_SA built"); + DBG1(DBG_IKE,"configuration payload negotation " + "failed, no CHILD_SA built"); iterator->destroy(iterator); handle_child_sa_failure(this, message); return SUCCESS; @@ -826,11 +817,8 @@ static status_t build_r(private_child_create_t *this, message_t *message) } iterator->destroy(iterator); - 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->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid, + 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, this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); if (this->config->use_ipcomp(this->config) && @@ -870,14 +858,14 @@ static status_t build_r(private_child_create_t *this, message_t *message) build_payloads(this, message); - SIG_CHD(UP_SUCCESS, this->child_sa, "CHILD_SA %s{%d} established " - "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", - this->child_sa->get_name(this->child_sa), - this->child_sa->get_reqid(this->child_sa), - ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), - ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), - this->child_sa->get_traffic_selectors(this->child_sa, TRUE), - this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); + DBG0(DBG_IKE, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + this->child_sa->get_traffic_selectors(this->child_sa, TRUE), + this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); return SUCCESS; } @@ -929,8 +917,8 @@ static status_t process_i(private_child_create_t *this, message_t *message) case TS_UNACCEPTABLE: case INVALID_SELECTORS: { - SIG_CHD(UP_FAILED, this->child_sa, "received %N notify, " - "no CHILD_SA built", notify_type_names, type); + DBG1(DBG_IKE, "received %N notify, no CHILD_SA built", + notify_type_names, type); iterator->destroy(iterator); handle_child_sa_failure(this, message); /* an error in CHILD_SA creation is not critical */ @@ -963,35 +951,35 @@ static status_t process_i(private_child_create_t *this, message_t *message) if (this->ipcomp == IPCOMP_NONE && this->ipcomp_received != IPCOMP_NONE) { - SIG_CHD(UP_FAILED, this->child_sa, "received an IPCOMP_SUPPORTED notify" - " but we did not send one previously, no CHILD_SA built"); + DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify without requesting" + " one, no CHILD_SA built"); handle_child_sa_failure(this, message); return SUCCESS; } else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE) { DBG1(DBG_IKE, "peer didn't accept our proposed IPComp transforms, " - "IPComp is disabled"); + "IPComp is disabled"); this->ipcomp = IPCOMP_NONE; } else if (this->ipcomp != IPCOMP_NONE && this->ipcomp != this->ipcomp_received) { - SIG_CHD(UP_FAILED, this->child_sa, "received an IPCOMP_SUPPORTED notify" - " for a transform we did not propose, no CHILD_SA built"); + DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify we didn't propose, " + "no CHILD_SA built"); handle_child_sa_failure(this, message); return SUCCESS; } if (select_and_install(this, no_dh) == SUCCESS) { - SIG_CHD(UP_SUCCESS, this->child_sa, "CHILD_SA %s{%d} established " - "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", - this->child_sa->get_name(this->child_sa), - this->child_sa->get_reqid(this->child_sa), - ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), - ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), - this->child_sa->get_traffic_selectors(this->child_sa, TRUE), - this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); + DBG0(DBG_IKE, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + this->child_sa->get_traffic_selectors(this->child_sa, TRUE), + this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); } else { @@ -1144,6 +1132,7 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config) this->tsr = NULL; this->dh = NULL; this->dh_group = MODP_NONE; + this->keymat = ike_sa->get_keymat(ike_sa); this->child_sa = NULL; this->mode = MODE_TUNNEL; this->ipcomp = IPCOMP_NONE; diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index a3c74dc90..cab1d63f0 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_delete.c 4366 2008-10-03 16:01:14Z martin $ + * $Id: child_delete.c 4434 2008-10-14 08:52:13Z martin $ */ #include "child_delete.h" @@ -222,14 +222,13 @@ static void log_children(private_child_delete_t *this) iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - SIG_CHD(DOWN_START, child_sa, "closing CHILD_SA %s{%d} " - "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", - child_sa->get_name(child_sa), - child_sa->get_reqid(child_sa), - ntohl(child_sa->get_spi(child_sa, TRUE)), - ntohl(child_sa->get_spi(child_sa, FALSE)), - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + DBG0(DBG_IKE, "closing CHILD_SA %s{%d} " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), + ntohl(child_sa->get_spi(child_sa, FALSE)), + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); } iterator->destroy(iterator); } @@ -254,7 +253,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message) this->child_sas = linked_list_create(); process_payloads(this, message); - SIG_CHD(DOWN_SUCCESS, NULL, "CHILD_SA closed"); + DBG1(DBG_IKE, "CHILD_SA closed"); return destroy_and_reestablish(this); } @@ -278,7 +277,7 @@ static status_t build_r(private_child_delete_t *this, message_t *message) { build_payloads(this, message); } - SIG_CHD(DOWN_SUCCESS, NULL, "CHILD_SA closed"); + DBG1(DBG_IKE, "CHILD_SA closed"); return destroy_and_reestablish(this); } diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 3953951a3..e50ad33be 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: child_rekey.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: child_rekey.c 4659 2008-11-14 14:05:47Z martin $ */ #include "child_rekey.h" @@ -23,6 +23,7 @@ #include <sa/tasks/child_create.h> #include <sa/tasks/child_delete.h> #include <processing/jobs/rekey_child_sa_job.h> +#include <processing/jobs/rekey_ike_sa_job.h> typedef struct private_child_rekey_t private_child_rekey_t; @@ -177,6 +178,31 @@ 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; + payload_t *payload; + + /* handle NO_ADDITIONAL_SAS notify */ + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + + if (notify->get_notify_type(notify) == NO_ADDITIONAL_SAS) + { + DBG1(DBG_IKE, "peer seems to not support CHILD_SA rekeying, " + "starting reauthentication"); + this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); + 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); + return SUCCESS; + } + } + } + iterator->destroy(iterator); if (this->child_create->task.process(&this->child_create->task, message) == NEED_MORE) { diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index 51f37f1b0..5c3f33cbd 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details * - * $Id: ike_auth.c 4276 2008-08-22 10:44:51Z martin $ + * $Id: ike_auth.c 4463 2008-10-20 11:38:16Z martin $ */ #include "ike_auth.h" @@ -146,6 +146,8 @@ static bool check_uniqueness(private_ike_auth_t *this) charon->ike_sa_manager->checkin(charon->ike_sa_manager, duplicate); } } + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); return cancel; } @@ -201,15 +203,15 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message) config = this->ike_sa->get_peer_cfg(this->ike_sa); if (!config) { - SIG_IKE(UP_FAILED, "unable to authenticate, no peer config found"); + 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) { - SIG_IKE(UP_FAILED, "configured authentication class %N not supported", - auth_class_names, get_auth_class(config)); + DBG1(DBG_IKE, "configured authentication class %N not supported", + auth_class_names, get_auth_class(config)); return FAILED; } @@ -218,7 +220,7 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message) auth->destroy(auth); if (status != SUCCESS) { - SIG_IKE(UP_FAILED, "generating authentication data failed"); + DBG1(DBG_IKE, "generating authentication data failed"); return FAILED; } message->add_payload(message, (payload_t*)auth_payload); @@ -243,7 +245,7 @@ static status_t build_id(private_ike_auth_t *this, message_t *message) me = config->get_my_id(config); if (me->contains_wildcards(me)) { - SIG_IKE(UP_FAILED, "negotiation of own ID failed"); + DBG1(DBG_IKE, "negotiation of own ID failed"); return FAILED; } this->ike_sa->set_my_id(this->ike_sa, me->clone(me)); @@ -284,8 +286,8 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message) auth_payload->get_auth_method(auth_payload)); if (auth == NULL) { - SIG_IKE(UP_FAILED, "authentication method %N used by '%D' not " - "supported", auth_method_names, auth_method, + 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; } @@ -294,7 +296,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message) auth->destroy(auth); if (status != SUCCESS) { - SIG_IKE(UP_FAILED, "authentication of '%D' with %N failed", + 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; @@ -315,7 +317,7 @@ static status_t process_id(private_ike_auth_t *this, message_t *message) if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL)) { - SIG_IKE(UP_FAILED, "ID payload missing in message"); + DBG1(DBG_IKE, "ID payload missing in message"); return FAILED; } @@ -325,7 +327,7 @@ static status_t process_id(private_ike_auth_t *this, message_t *message) req = this->ike_sa->get_other_id(this->ike_sa); if (!id->matches(id, req)) { - SIG_IKE(UP_FAILED, "peer ID '%D' unacceptable, '%D' required", id, req); + DBG0(DBG_IKE, "peer ID '%D' unacceptable, '%D' required", id, req); id->destroy(id); return FAILED; } @@ -402,7 +404,7 @@ static status_t build_auth_eap(private_ike_auth_t *this, message_t *message) if (auth->build(auth, this->my_packet->get_data(this->my_packet), this->other_nonce, &auth_payload) != SUCCESS) { - SIG_IKE(UP_FAILED, "generating authentication data failed"); + DBG1(DBG_IKE, "generating authentication data failed"); if (!this->initiator) { message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); @@ -413,13 +415,13 @@ static status_t build_auth_eap(private_ike_auth_t *this, message_t *message) if (!this->initiator) { this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - SIG_IKE(UP_SUCCESS, "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)); + 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; @@ -448,7 +450,7 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message) if (!this->peer_authenticated) { - SIG_IKE(UP_FAILED, "authentication of '%D' with %N failed", + 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) @@ -460,13 +462,13 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message) if (this->initiator) { this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - SIG_IKE(UP_SUCCESS, "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)); + 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; @@ -482,7 +484,7 @@ static status_t process_eap_i(private_ike_auth_t *this, message_t *message) eap = (eap_payload_t*)message->get_payload(message, EXTENSIBLE_AUTHENTICATION); if (eap == NULL) { - SIG_IKE(UP_FAILED, "EAP payload missing"); + DBG1(DBG_IKE, "EAP payload missing"); return FAILED; } switch (this->eap_auth->process(this->eap_auth, eap, &eap)) @@ -498,7 +500,7 @@ static status_t process_eap_i(private_ike_auth_t *this, message_t *message) return NEED_MORE; default: this->eap_payload = NULL; - SIG_IKE(UP_FAILED, "failed to authenticate against '%D' using EAP", + DBG0(DBG_IKE, "failed to authenticate against '%D' using EAP", this->ike_sa->get_other_id(this->ike_sa)); return FAILED; } @@ -533,7 +535,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) if (this->eap_payload == NULL) { - SIG_IKE(UP_FAILED, "EAP payload missing"); + DBG1(DBG_IKE, "EAP payload missing"); return FAILED; } @@ -548,9 +550,9 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap; break; default: - SIG_IKE(UP_FAILED, "authentication of '%D' with %N failed", - this->ike_sa->get_other_id(this->ike_sa), - auth_class_names, AUTH_CLASS_EAP); + 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; } @@ -665,9 +667,9 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) config = this->ike_sa->get_peer_cfg(this->ike_sa); if (config == NULL) { - SIG_IKE(UP_FAILED, "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)); + 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; } @@ -689,13 +691,13 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) if (this->peer_authenticated) { this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - SIG_IKE(UP_SUCCESS, "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)); + 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; } @@ -706,7 +708,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) message->add_payload(message, (payload_t*)eap_payload); if (status != NEED_MORE) { - SIG_IKE(UP_FAILED, "unable to initiate EAP authentication"); + DBG1(DBG_IKE, "unable to initiate EAP authentication"); return FAILED; } @@ -766,7 +768,7 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) { if (type < 16383) { - SIG_IKE(UP_FAILED, "received %N notify error", + DBG1(DBG_IKE, "received %N notify error", notify_type_names, type); iterator->destroy(iterator); return FAILED; @@ -798,18 +800,18 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) auth = this->ike_sa->get_other_auth(this->ike_sa); if (!auth->complies(auth, config->get_auth(config))) { - SIG_IKE(UP_FAILED, "authorization of '%D' for config %s failed", + 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->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - SIG_IKE(UP_SUCCESS, "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)); + 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; } diff --git a/src/charon/sa/tasks/ike_auth_lifetime.c b/src/charon/sa/tasks/ike_auth_lifetime.c index 2d18c6a1e..cb17cc2dc 100644 --- a/src/charon/sa/tasks/ike_auth_lifetime.c +++ b/src/charon/sa/tasks/ike_auth_lifetime.c @@ -12,11 +12,13 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_auth_lifetime.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: ike_auth_lifetime.c 4576 2008-11-05 08:32:38Z martin $ */ #include "ike_auth_lifetime.h" +#include <time.h> + #include <daemon.h> #include <encoding/payloads/notify_payload.h> @@ -47,9 +49,10 @@ static void add_auth_lifetime(private_ike_auth_lifetime_t *this, message_t *mess chunk_t chunk; u_int32_t lifetime; - lifetime = this->ike_sa->get_statistic(this->ike_sa, STAT_REAUTH_TIME); + lifetime = this->ike_sa->get_statistic(this->ike_sa, STAT_REAUTH); if (lifetime) { + lifetime -= time(NULL); chunk = chunk_from_thing(lifetime); *(u_int32_t*)chunk.ptr = htonl(lifetime); message->add_notify(message, FALSE, AUTH_LIFETIME, chunk); diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c index 295f908cb..1c051853c 100644 --- a/src/charon/sa/tasks/ike_delete.c +++ b/src/charon/sa/tasks/ike_delete.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_delete.c 4211 2008-07-23 18:46:34Z andreas $ + * $Id: ike_delete.c 4458 2008-10-17 03:44:06Z andreas $ */ #include "ike_delete.h" @@ -56,21 +56,21 @@ static status_t build_i(private_ike_delete_t *this, message_t *message) { delete_payload_t *delete_payload; - SIG_IKE(DOWN_START, "deleting IKE_SA %s[%d] 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)); + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] 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)); delete_payload = delete_payload_create(PROTO_IKE); message->add_payload(message, (payload_t*)delete_payload); this->ike_sa->set_state(this->ike_sa, IKE_DELETING); DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa)); + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); return NEED_MORE; } @@ -80,6 +80,7 @@ static status_t build_i(private_ike_delete_t *this, message_t *message) */ static status_t process_i(private_ike_delete_t *this, message_t *message) { + DBG0(DBG_IKE, "IKE_SA deleted"); /* completed, delete IKE_SA by returning FAILED */ return FAILED; } @@ -92,15 +93,15 @@ static status_t process_r(private_ike_delete_t *this, message_t *message) /* we don't even scan the payloads, as the message wouldn't have * come so far without being correct */ 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)); - SIG_IKE(DOWN_START, "deleting IKE_SA %s[%d] 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)); + 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]", + 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)); switch (this->ike_sa->get_state(this->ike_sa)) { @@ -123,7 +124,7 @@ static status_t process_r(private_ike_delete_t *this, message_t *message) */ static status_t build_r(private_ike_delete_t *this, message_t *message) { - SIG_IKE(DOWN_SUCCESS, "IKE_SA deleted"); + DBG0(DBG_IKE, "IKE_SA deleted"); if (this->simultaneous) { diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c index 609b37a39..bd2cd39bb 100644 --- a/src/charon/sa/tasks/ike_init.c +++ b/src/charon/sa/tasks/ike_init.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_init.c 4206 2008-07-22 17:10:10Z andreas $ + * $Id: ike_init.c 4531 2008-10-30 12:58:54Z martin $ */ #include "ike_init.h" @@ -64,11 +64,16 @@ struct private_ike_init_t { diffie_hellman_group_t dh_group; /** - * Diffie hellman object used to generate public DH value. + * diffie hellman key exchange */ diffie_hellman_t *dh; /** + * Keymat derivation (from IKE_SA) + */ + keymat_t *keymat; + + /** * nonce chosen by us */ chunk_t my_nonce; @@ -192,7 +197,8 @@ static void process_payloads(private_ike_init_t *this, message_t *message) this->dh_group = ke_payload->get_dh_group_number(ke_payload); if (!this->initiator) { - this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); + this->dh = this->keymat->create_dh(this->keymat, + this->dh_group); } if (this->dh) { @@ -230,26 +236,26 @@ static status_t build_i(private_ike_init_t *this, message_t *message) rng_t *rng; this->config = this->ike_sa->get_ike_cfg(this->ike_sa); - SIG_IKE(UP_START, "initiating IKE_SA %s[%d] to %H", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); + DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); if (this->retry++ >= MAX_RETRIES) { - SIG_IKE(UP_FAILED, "giving up after %d retries", MAX_RETRIES); + DBG1(DBG_IKE, "giving up after %d retries", MAX_RETRIES); return FAILED; } - + /* if the DH group is set via use_dh_group(), we already have a DH object */ if (!this->dh) { this->dh_group = this->config->get_dh_group(this->config); - this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); - if (this->dh == NULL) + this->dh = this->keymat->create_dh(this->keymat, this->dh_group); + if (!this->dh) { - SIG_IKE(UP_FAILED, "configured DH group %N not supported", + DBG1(DBG_IKE, "configured DH group %N not supported", diffie_hellman_group_names, this->dh_group); return FAILED; } @@ -261,7 +267,7 @@ static status_t build_i(private_ike_init_t *this, message_t *message) rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); if (!rng) { - SIG_IKE(UP_FAILED, "error generating nonce"); + DBG1(DBG_IKE, "error generating nonce"); return FAILED; } rng->allocate_bytes(rng, NONCE_SIZE, &this->my_nonce); @@ -296,8 +302,7 @@ static status_t process_r(private_ike_init_t *this, message_t *message) rng_t *rng; this->config = this->ike_sa->get_ike_cfg(this->ike_sa); - SIG_IKE(UP_START, "%H is initiating an IKE_SA", - message->get_source(message)); + DBG0(DBG_IKE, "%H is initiating an IKE_SA", message->get_source(message)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); @@ -369,30 +374,30 @@ static status_t process_r(private_ike_init_t *this, message_t *message) */ static status_t build_r(private_ike_init_t *this, message_t *message) { - chunk_t secret; - status_t status; - + keymat_t *old_keymat = NULL; + ike_sa_id_t *id; + /* check if we have everything we need */ if (this->proposal == NULL || this->other_nonce.len == 0 || this->my_nonce.len == 0) { - SIG_IKE(UP_FAILED, "received proposals inacceptable"); + DBG1(DBG_IKE, "received proposals inacceptable"); message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); return FAILED; } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); if (this->dh == NULL || - !this->proposal->has_dh_group(this->proposal, this->dh_group) || - this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) + !this->proposal->has_dh_group(this->proposal, this->dh_group)) { u_int16_t group; if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { - SIG_CHD(UP_FAILED, NULL, "DH group %N inacceptable, requesting %N", - diffie_hellman_group_names, this->dh_group, - diffie_hellman_group_names, group); + DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N", + diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); this->dh_group = group; group = htons(group); message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, @@ -400,49 +405,28 @@ static status_t build_r(private_ike_init_t *this, message_t *message) } else { - SIG_IKE(UP_FAILED, "no acceptable proposal found"); + DBG1(DBG_IKE, "no acceptable proposal found"); } return FAILED; } + id = this->ike_sa->get_id(this->ike_sa); if (this->old_sa) - { - ike_sa_id_t *id; - prf_t *prf, *child_prf; - - /* Apply SPI if we are rekeying */ - id = this->ike_sa->get_id(this->ike_sa); + { /* rekeying: Apply SPI, include keymat from old SA in key derivation */ id->set_initiator_spi(id, this->proposal->get_spi(this->proposal)); - - /* setup crypto keys for the rekeyed SA */ - prf = this->old_sa->get_prf(this->old_sa); - child_prf = this->old_sa->get_child_prf(this->old_sa); - status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, - this->other_nonce, this->my_nonce, - FALSE, child_prf, prf); + old_keymat = this->old_sa->get_keymat(this->old_sa); } - else + if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, + this->other_nonce, this->my_nonce, id, old_keymat)) { - /* setup crypto keys */ - status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, - this->other_nonce, this->my_nonce, - FALSE, NULL, NULL); - } - if (status != SUCCESS) - { - SIG_IKE(UP_FAILED, "key derivation failed"); + DBG1(DBG_IKE, "key derivation failed"); message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); return FAILED; } - - /* Keep the selected IKE proposal for status information purposes */ - { - char buf[BUF_LEN]; - - snprintf(buf, BUF_LEN, "%P", this->proposal); - this->ike_sa->set_proposal(this->ike_sa, buf+4); - } - + + charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, + this->other_nonce, this->my_nonce, this->old_sa); + build_payloads(this, message); return SUCCESS; } @@ -452,8 +436,8 @@ 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) { - chunk_t secret; - status_t status; + keymat_t *old_keymat = NULL; + ike_sa_id_t *id; iterator_t *iterator; payload_t *payload; @@ -505,7 +489,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) { if (type < 16383) { - SIG_IKE(UP_FAILED, "received %N notify error", + DBG1(DBG_IKE, "received %N notify error", notify_type_names, type); iterator->destroy(iterator); return FAILED; @@ -525,55 +509,34 @@ static status_t process_i(private_ike_init_t *this, message_t *message) if (this->proposal == NULL || this->other_nonce.len == 0 || this->my_nonce.len == 0) { - SIG_IKE(UP_FAILED, "peer's proposal selection invalid"); + DBG1(DBG_IKE, "peers proposal selection invalid"); return FAILED; } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); if (this->dh == NULL || - !this->proposal->has_dh_group(this->proposal, this->dh_group) || - this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) + !this->proposal->has_dh_group(this->proposal, this->dh_group)) { - SIG_IKE(UP_FAILED, "peer's DH group selection invalid"); + DBG1(DBG_IKE, "peer DH group selection invalid"); return FAILED; } - /* Apply SPI if we are rekeying */ + id = this->ike_sa->get_id(this->ike_sa); if (this->old_sa) - { - ike_sa_id_t *id; - prf_t *prf, *child_prf; - - id = this->ike_sa->get_id(this->ike_sa); + { /* rekeying: Apply SPI, include keymat from old SA in key derivation */ id->set_responder_spi(id, this->proposal->get_spi(this->proposal)); - - /* setup crypto keys for the rekeyed SA */ - prf = this->old_sa->get_prf(this->old_sa); - child_prf = this->old_sa->get_child_prf(this->old_sa); - status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, - this->my_nonce, this->other_nonce, - TRUE, child_prf, prf); + old_keymat = this->old_sa->get_keymat(this->old_sa); } - else + if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, + this->my_nonce, this->other_nonce, id, old_keymat)) { - /* setup crypto keys for a new SA */ - status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, - this->my_nonce, this->other_nonce, - TRUE, NULL, NULL); - } - if (status != SUCCESS) - { - SIG_IKE(UP_FAILED, "key derivation failed"); + DBG1(DBG_IKE, "key derivation failed"); return FAILED; } - - /* Keep the selected IKE proposal for status information purposes */ - { - char buf[BUF_LEN]; - - snprintf(buf, BUF_LEN, "%P", this->proposal); - this->ike_sa->set_proposal(this->ike_sa, buf+4); - } - + + charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, + this->my_nonce, this->other_nonce, this->old_sa); + return SUCCESS; } @@ -607,12 +570,12 @@ static chunk_t get_lower_nonce(private_ike_init_t *this) static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) { DESTROY_IF(this->proposal); - DESTROY_IF(this->dh); chunk_free(&this->other_nonce); this->ike_sa = ike_sa; this->proposal = NULL; - this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); + DESTROY_IF(this->dh); + this->dh = this->keymat->create_dh(this->keymat, this->dh_group); } /** @@ -620,8 +583,8 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) */ static void destroy(private_ike_init_t *this) { - DESTROY_IF(this->proposal); DESTROY_IF(this->dh); + DESTROY_IF(this->proposal); chunk_free(&this->my_nonce); chunk_free(&this->other_nonce); chunk_free(&this->cookie); @@ -654,6 +617,7 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) this->initiator = initiator; this->dh_group = MODP_NONE; this->dh = NULL; + this->keymat = ike_sa->get_keymat(ike_sa); this->my_nonce = chunk_empty; this->other_nonce = chunk_empty; this->cookie = chunk_empty; diff --git a/src/charon/sa/tasks/ike_me.c b/src/charon/sa/tasks/ike_me.c index a203dee58..f58d51341 100644 --- a/src/charon/sa/tasks/ike_me.c +++ b/src/charon/sa/tasks/ike_me.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_me.c 4355 2008-09-25 07:56:58Z tobias $ + * $Id: ike_me.c 4640 2008-11-12 16:07:17Z martin $ */ #include "ike_me.h" @@ -461,8 +461,7 @@ static status_t process_i(private_ike_me_t *this, message_t *message) this->ike_sa->set_server_reflexive_host(this->ike_sa, endpoint->clone(endpoint)); } /* FIXME: what if it failed? e.g. AUTH failure */ - SIG_CHD(UP_SUCCESS, NULL, "established mediation connection " - "without CHILD_SA successfully"); + DBG1(DBG_IKE, "established mediation connection successfully"); break; } @@ -642,8 +641,7 @@ static status_t build_r_ms(private_ike_me_t *this, message_t *message) /* FIXME: we actually must delete any existing IKE_SAs with the same remote id */ this->ike_sa->act_as_mediation_server(this->ike_sa); - SIG_CHD(UP_SUCCESS, NULL, "established mediation connection " - "without CHILD_SA successfully"); + DBG1(DBG_IKE, "established mediation connection successfully"); break; } @@ -787,7 +785,7 @@ ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator) this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; this->public.task.destroy = (void(*)(task_t*))destroy; - if (ike_sa->is_ike_initiator(ike_sa)) + if (ike_sa->has_condition(ike_sa, COND_ORIGINAL_INITIATOR)) { if (initiator) { diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index f6ee3f6ad..a791d1892 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_mobike.c 4394 2008-10-09 08:25:11Z martin $ + * $Id: ike_mobike.c 4618 2008-11-11 09:22:00Z tobias $ */ #include "ike_mobike.h" @@ -251,10 +251,16 @@ static void update_children(private_ike_mobike_t *this) iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa); while (iterator->iterate(iterator, (void**)&child_sa)) { - child_sa->update_hosts(child_sa, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); + if (child_sa->update_hosts(child_sa, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_virtual_ip(this->ike_sa, TRUE), + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED) + { + this->ike_sa->rekey_child_sa(this->ike_sa, + child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)); + } } iterator->destroy(iterator); } diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c index b84b2a387..61701075f 100644 --- a/src/charon/sa/tasks/ike_reauth.c +++ b/src/charon/sa/tasks/ike_reauth.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Martin Willi + * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_reauth.c 4211 2008-07-23 18:46:34Z andreas $ + * $Id: ike_reauth.c 4495 2008-10-28 16:07:06Z martin $ */ #include "ike_reauth.h" @@ -65,7 +65,6 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message) /* process delete response first */ this->ike_delete->task.process(&this->ike_delete->task, message); - SIG_IKE(DOWN_SUCCESS, "IKE_SA deleted"); peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); @@ -105,6 +104,8 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message) { charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, new); + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); return FAILED; } @@ -132,6 +133,8 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message) iterator->destroy(iterator); charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, new); + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); return FAILED; } @@ -141,6 +144,8 @@ static status_t process_i(private_ike_reauth_t *this, message_t *message) } iterator->destroy(iterator); charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); /* we always return failed to delete the obsolete IKE_SA */ return FAILED; diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index 6c4ef4354..28d63cca7 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: ike_rekey.c 4211 2008-07-23 18:46:34Z andreas $ + * $Id: ike_rekey.c 4659 2008-11-14 14:05:47Z martin $ */ #include "ike_rekey.h" @@ -144,7 +144,7 @@ static status_t build_r(private_ike_rekey_t *this, message_t *message) message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); return SUCCESS; } - + if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED) { return SUCCESS; @@ -152,13 +152,13 @@ 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); - SIG_IKE(UP_SUCCESS, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", - 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)); + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", + 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)); return SUCCESS; } @@ -170,7 +170,32 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) { job_t *job; ike_sa_id_t *to_delete; + iterator_t *iterator; + payload_t *payload; + /* handle NO_ADDITIONAL_SAS notify */ + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + + if (notify->get_notify_type(notify) == NO_ADDITIONAL_SAS) + { + DBG1(DBG_IKE, "peer seems to not support IKE rekeying, " + "starting reauthentication"); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + 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); + return SUCCESS; + } + } + } + iterator->destroy(iterator); + switch (this->ike_init->task.process(&this->ike_init->task, message)) { case FAILED: @@ -198,13 +223,13 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) } this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); - SIG_IKE(UP_SUCCESS, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", - 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)); + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", + 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); @@ -242,6 +267,8 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) this->new_sa = other->new_sa; other->new_sa = NULL; } + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); } job = (job_t*)delete_ike_sa_job_create(to_delete, TRUE); @@ -277,6 +304,8 @@ static void migrate(private_ike_rekey_t *this, ike_sa_t *ike_sa) { charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, this->new_sa); + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); } DESTROY_IF(this->collision); @@ -303,6 +332,8 @@ static void destroy(private_ike_rekey_t *this) charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, this->new_sa); } + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); } if (this->ike_init) { diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c index 3192b688a..fd15379f3 100644 --- a/src/charon/sa/tasks/task.c +++ b/src/charon/sa/tasks/task.c @@ -13,11 +13,12 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: task.c 3666 2008-03-26 18:40:19Z tobias $ + * $Id: task.c 4618 2008-11-11 09:22:00Z tobias $ */ #include "task.h" +#ifdef ME ENUM(task_type_names, IKE_INIT, CHILD_REKEY, "IKE_INIT", "IKE_NATD", @@ -31,11 +32,27 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY, "IKE_REAUTH", "IKE_DELETE", "IKE_DPD", -#ifdef ME "IKE_ME", -#endif /* ME */ "CHILD_CREATE", "CHILD_DELETE", "CHILD_REKEY", ); - +#else +ENUM(task_type_names, IKE_INIT, CHILD_REKEY, + "IKE_INIT", + "IKE_NATD", + "IKE_MOBIKE", + "IKE_AUTHENTICATE", + "IKE_AUTH_LIFETIME", + "IKE_CERT_PRE", + "IKE_CERT_POST", + "IKE_CONFIG", + "IKE_REKEY", + "IKE_REAUTH", + "IKE_DELETE", + "IKE_DPD", + "CHILD_CREATE", + "CHILD_DELETE", + "CHILD_REKEY", +); +#endif /* ME */ |