diff options
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r-- | src/libcharon/sa/child_sa.c | 19 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 18 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa.h | 10 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa_manager.c | 88 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa_manager.h | 15 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c | 4 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/iv_manager.c | 1 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/main_mode.c | 3 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c | 173 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/keymat_v2.h | 5 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/task_manager_v2.c | 22 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/child_create.c | 1 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/child_delete.c | 2 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_auth.c | 1 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_init.c | 15 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_vendor.c | 2 | ||||
-rw-r--r-- | src/libcharon/sa/shunt_manager.c | 21 |
17 files changed, 305 insertions, 95 deletions
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 4133d9182..91da4d3e6 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -254,7 +254,7 @@ struct private_child_sa_t { }; /** - * convert an IKEv2 specific protocol identifier to the IP protocol identifier. + * Convert an IKEv2 specific protocol identifier to the IP protocol identifier */ static inline uint8_t proto_ike2ip(protocol_id_t protocol) { @@ -269,6 +269,18 @@ static inline uint8_t proto_ike2ip(protocol_id_t protocol) } } +/** + * Returns the mark to use on the inbound SA + */ +static inline mark_t mark_in_sa(private_child_sa_t *this) +{ + if (this->config->has_option(this->config, OPT_MARK_IN_SA)) + { + return this->mark_in; + } + return (mark_t){}; +} + METHOD(child_sa_t, get_name, char*, private_child_sa_t *this) { @@ -525,6 +537,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) .dst = this->my_addr, .spi = this->my_spi, .proto = proto_ike2ip(this->protocol), + .mark = mark_in_sa(this), }; kernel_ipsec_query_sa_t query = {}; @@ -857,7 +870,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr, .dst = dst, .spi = spi, .proto = proto_ike2ip(this->protocol), - .mark = inbound ? (mark_t){} : this->mark_out, + .mark = inbound ? mark_in_sa(this) : this->mark_out, }; sa = (kernel_ipsec_add_sa_t){ .reqid = this->reqid, @@ -1475,6 +1488,7 @@ METHOD(child_sa_t, update, status_t, .dst = this->my_addr, .spi = this->my_spi, .proto = proto_ike2ip(this->protocol), + .mark = mark_in_sa(this), }; kernel_ipsec_update_sa_t sa = { .cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0, @@ -1660,6 +1674,7 @@ METHOD(child_sa_t, destroy, void, .dst = this->my_addr, .spi = this->my_spi, .proto = proto_ike2ip(this->protocol), + .mark = mark_in_sa(this), }; kernel_ipsec_del_sa_t sa = { .cpi = this->my_cpi, diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 045858792..823cf2579 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2016 Tobias Brunner + * Copyright (C) 2006-2017 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -914,9 +914,15 @@ METHOD(ike_sa_t, set_state, void, } METHOD(ike_sa_t, reset, void, - private_ike_sa_t *this) + private_ike_sa_t *this, bool new_spi) { - /* the responder ID is reset, as peer may choose another one */ + /* reset the initiator SPI if requested */ + if (new_spi) + { + charon->ike_sa_manager->new_initiator_spi(charon->ike_sa_manager, + &this->public); + } + /* the responder ID is reset, as peer may choose another one */ if (this->ike_sa_id->is_initiator(this->ike_sa_id)) { this->ike_sa_id->set_responder_spi(this->ike_sa_id, 0); @@ -1849,7 +1855,7 @@ METHOD(ike_sa_t, reauth, status_t, { DBG0(DBG_IKE, "reinitiating IKE_SA %s[%d]", get_name(this), this->unique_id); - reset(this); + reset(this, TRUE); return this->task_manager->initiate(this->task_manager); } /* we can't reauthenticate as responder when we use EAP or virtual IPs. @@ -2222,7 +2228,7 @@ static bool redirect_connecting(private_ike_sa_t *this, identification_t *to) { return FALSE; } - reset(this); + reset(this, TRUE); DESTROY_IF(this->redirected_from); this->redirected_from = this->other_host->clone(this->other_host); DESTROY_IF(this->remote_host); @@ -2351,7 +2357,7 @@ METHOD(ike_sa_t, retransmit, status_t, { DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)", this->keyingtry + 1, tries); - reset(this); + reset(this, TRUE); resolve_hosts(this); return this->task_manager->initiate(this->task_manager); } diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index c8ba2fd2a..fbc367292 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2016 Tobias Brunner + * Copyright (C) 2006-2017 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -1014,7 +1014,7 @@ struct ike_sa_t { /** * Rekey the IKE_SA. * - * Sets up a new IKE_SA, moves all CHILDs to it and deletes this IKE_SA. + * Sets up a new IKE_SA, moves all CHILD_SAs to it and deletes this IKE_SA. * * @return - SUCCESS, if IKE_SA rekeying initiated */ @@ -1169,9 +1169,11 @@ struct ike_sa_t { void (*inherit_post) (ike_sa_t *this, ike_sa_t *other); /** - * Reset the IKE_SA, useable when initiating fails + * Reset the IKE_SA, useable when initiating fails. + * + * @param new_spi TRUE to allocate a new initiator SPI */ - void (*reset) (ike_sa_t *this); + void (*reset) (ike_sa_t *this, bool new_spi); /** * Destroys a ike_sa_t object. diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index c0bfebb83..101d98678 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1,9 +1,10 @@ /* * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2011 revosec AG - * Copyright (C) 2008-2016 Tobias Brunner + * + * Copyright (C) 2008-2017 Tobias Brunner * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR 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 @@ -1572,6 +1573,88 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*, return ike_sa; } +METHOD(ike_sa_manager_t, new_initiator_spi, bool, + private_ike_sa_manager_t *this, ike_sa_t *ike_sa) +{ + ike_sa_state_t state; + ike_sa_id_t *ike_sa_id; + entry_t *entry; + u_int segment; + uint64_t new_spi, spi; + + state = ike_sa->get_state(ike_sa); + if (state != IKE_CONNECTING) + { + DBG1(DBG_MGR, "unable to change initiator SPI for IKE_SA in state " + "%N", ike_sa_state_names, state); + return FALSE; + } + + ike_sa_id = ike_sa->get_id(ike_sa); + if (!ike_sa_id->is_initiator(ike_sa_id)) + { + DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA as responder"); + return FALSE; + } + + if (ike_sa != charon->bus->get_sa(charon->bus)) + { + DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA not checked " + "out by current thread"); + return FALSE; + } + + new_spi = get_spi(this); + if (!new_spi) + { + DBG1(DBG_MGR, "unable to allocate new initiator SPI for IKE_SA"); + return FALSE; + } + + if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS) + { + if (entry->driveout_waiting_threads && entry->driveout_new_threads) + { /* it looks like flush() has been called and the SA is being deleted + * anyway, no need for a new SPI */ + DBG2(DBG_MGR, "ignored change of initiator SPI during shutdown"); + unlock_single_segment(this, segment); + return FALSE; + } + /* threads waiting for this entry do so using the (soon) wrong IKE_SA + * ID and, therefore, likely on the wrong segment, so drive them out */ + entry->driveout_waiting_threads = TRUE; + entry->driveout_new_threads = TRUE; + while (entry->waiting_threads) + { + entry->condvar->broadcast(entry->condvar); + entry->condvar->wait(entry->condvar, this->segments[segment].mutex); + } + remove_entry(this, entry); + unlock_single_segment(this, segment); + } + else + { + DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA, not found"); + return FALSE; + } + + spi = ike_sa_id->get_initiator_spi(ike_sa_id); + + DBG2(DBG_MGR, "change initiator SPI of IKE_SA %s[%u] from %.16"PRIx64" to " + "%.16"PRIx64, ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + be64toh(spi), be64toh(new_spi)); + + ike_sa_id->set_initiator_spi(ike_sa_id, new_spi); + entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa_id); + + entry->driveout_waiting_threads = FALSE; + entry->driveout_new_threads = FALSE; + + segment = put_entry(this, entry); + unlock_single_segment(this, segment); + return TRUE; +} + CALLBACK(enumerator_filter_wait, bool, private_ike_sa_manager_t *this, enumerator_t *orig, va_list args) { @@ -2277,6 +2360,7 @@ ike_sa_manager_t *ike_sa_manager_create() .checkout_by_config = _checkout_by_config, .checkout_by_id = _checkout_by_id, .checkout_by_name = _checkout_by_name, + .new_initiator_spi = _new_initiator_spi, .check_uniqueness = _check_uniqueness, .has_contact = _has_contact, .create_enumerator = _create_enumerator, diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index 4298c54e2..efad2e4d6 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2008-2017 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR 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 @@ -109,6 +109,17 @@ struct ike_sa_manager_t { peer_cfg_t *peer_cfg); /** + * Reset initiator SPI. + * + * Allocate a new initiator SPI for the given IKE_SA in state IKE_CONNECTING + * and update internal data. + * + * @param ike_sa IKE_SA to update + * @return TRUE if SPI successfully changed + */ + bool (*new_initiator_spi)(ike_sa_manager_t* this, ike_sa_t *ike_sa); + + /** * Check for duplicates of the given IKE_SA. * * Measures are taken according to the uniqueness policy of the IKE_SA. diff --git a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c index 344c1bf5d..41be15a08 100644 --- a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c +++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c @@ -110,7 +110,7 @@ METHOD(authenticator_t, build, status_t, } free(dh.ptr); - if (private->sign(private, scheme, hash, &sig)) + if (private->sign(private, scheme, NULL, hash, &sig)) { sig_payload = hash_payload_create(PLV1_SIGNATURE); sig_payload->set_hash(sig_payload, sig); @@ -176,7 +176,7 @@ METHOD(authenticator_t, process, status_t, id, auth, TRUE); while (enumerator->enumerate(enumerator, &public, ¤t_auth)) { - if (public->verify(public, scheme, hash, sig)) + if (public->verify(public, scheme, NULL, hash, sig)) { DBG1(DBG_IKE, "authentication of '%Y' with %N successful", id, signature_scheme_names, scheme); diff --git a/src/libcharon/sa/ikev1/iv_manager.c b/src/libcharon/sa/ikev1/iv_manager.c index c9f737ccd..2a6e5c04f 100644 --- a/src/libcharon/sa/ikev1/iv_manager.c +++ b/src/libcharon/sa/ikev1/iv_manager.c @@ -15,6 +15,7 @@ #include "iv_manager.h" +#include <library.h> #include <collections/linked_list.h> /** diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index 628ea0de8..4c16adba3 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -221,8 +221,7 @@ static void add_initial_contact(private_main_mode_t *this, message_t *message, idr = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE); if (idr && !idr->contains_wildcards(idr)) { - if (this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO && - this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NEVER) + if (this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NEVER) { host = this->ike_sa->get_other_host(this->ike_sa); if (!charon->ike_sa_manager->has_contact(charon->ike_sa_manager, diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c index 19ea72d0b..65baf8771 100644 --- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2008-2017 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR 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 @@ -61,10 +61,9 @@ struct private_pubkey_authenticator_t { * Parse authentication data used for Signature Authentication as per RFC 7427 */ static bool parse_signature_auth_data(chunk_t *auth_data, key_type_t *key_type, - signature_scheme_t *scheme) + signature_params_t *params) { uint8_t len; - int oid; if (!auth_data->len) { @@ -72,14 +71,11 @@ static bool parse_signature_auth_data(chunk_t *auth_data, key_type_t *key_type, } len = auth_data->ptr[0]; *auth_data = chunk_skip(*auth_data, 1); - /* we currently don't support schemes that require parameters */ - oid = asn1_parse_algorithmIdentifier(*auth_data, 1, NULL); - *scheme = signature_scheme_from_oid(oid); - if (*scheme == SIGN_UNKNOWN) + if (!signature_params_parse(*auth_data, 1, params)) { return FALSE; } - *key_type = key_type_from_signature_scheme(*scheme); + *key_type = key_type_from_signature_scheme(params->scheme); *auth_data = chunk_skip(*auth_data, len); return TRUE; } @@ -88,18 +84,16 @@ static bool parse_signature_auth_data(chunk_t *auth_data, key_type_t *key_type, * Build authentication data used for Signature Authentication as per RFC 7427 */ static bool build_signature_auth_data(chunk_t *auth_data, - signature_scheme_t scheme) + signature_params_t *params) { chunk_t data; uint8_t len; - int oid; - oid = signature_scheme_to_oid(scheme); - if (oid == OID_UNKNOWN) + if (!signature_params_build(params, &data)) { + chunk_free(auth_data); return FALSE; } - data = asn1_algorithmIdentifier(oid); len = data.len; *auth_data = chunk_cat("cmm", chunk_from_thing(len), data, *auth_data); return TRUE; @@ -114,13 +108,13 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, { enumerator_t *enumerator; signature_scheme_t scheme; - uintptr_t config; + signature_params_t *config; auth_rule_t rule; key_type_t key_type; bool have_config = FALSE; array_t *selected; - selected = array_create(sizeof(signature_scheme_t), 0); + selected = array_create(0, 0); key_type = private->get_type(private); enumerator = auth->create_enumerator(auth); while (enumerator->enumerate(enumerator, &rule, &config)) @@ -130,12 +124,12 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, continue; } have_config = TRUE; - if (key_type == key_type_from_signature_scheme(config) && + if (key_type == key_type_from_signature_scheme(config->scheme) && keymat->hash_algorithm_supported(keymat, - hasher_from_signature_scheme(config))) + hasher_from_signature_scheme(config->scheme, + config->params))) { - scheme = config; - array_insert(selected, ARRAY_TAIL, &scheme); + array_insert(selected, ARRAY_TAIL, signature_params_clone(config)); } } enumerator->destroy(enumerator); @@ -146,24 +140,30 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, * and supported by the other peer */ enumerator = signature_schemes_for_key(key_type, private->get_keysize(private)); - while (enumerator->enumerate(enumerator, &scheme)) + while (enumerator->enumerate(enumerator, &config)) { + if (config->scheme == SIGN_RSA_EMSA_PSS && + !lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE, + lib->ns)) + { + continue; + } if (keymat->hash_algorithm_supported(keymat, - hasher_from_signature_scheme(scheme))) + hasher_from_signature_scheme(config->scheme, + config->params))) { - array_insert(selected, ARRAY_TAIL, &scheme); + array_insert(selected, ARRAY_TAIL, + signature_params_clone(config)); } } enumerator->destroy(enumerator); - /* for RSA we tried at least SHA-512, also try other schemes down to - * what we'd use with classic authentication */ + /* for RSA we tried at least SHA-512, also try other schemes */ if (key_type == KEY_RSA) { signature_scheme_t schemes[] = { SIGN_RSA_EMSA_PKCS1_SHA2_384, SIGN_RSA_EMSA_PKCS1_SHA2_256, - SIGN_RSA_EMSA_PKCS1_SHA1, }, contained; bool found; int i, j; @@ -182,9 +182,13 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, } } if (!found && keymat->hash_algorithm_supported(keymat, - hasher_from_signature_scheme(scheme))) + hasher_from_signature_scheme(scheme, + NULL))) { - array_insert(selected, ARRAY_TAIL, &scheme); + INIT(config, + .scheme = scheme, + ) + array_insert(selected, ARRAY_TAIL, config); } } } @@ -192,6 +196,12 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, return selected; } +CALLBACK(destroy_scheme, void, + signature_params_t *params, int idx, void *user) +{ + signature_params_destroy(params); +} + /** * Create a signature using RFC 7427 signature authentication */ @@ -201,7 +211,7 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this, { enumerator_t *enumerator; keymat_v2_t *keymat; - signature_scheme_t scheme = SIGN_UNKNOWN, *schemep; + signature_params_t *params = NULL; array_t *schemes; chunk_t octets = chunk_empty; status_t status = FAILED; @@ -221,11 +231,11 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this, schemes)) { enumerator = array_create_enumerator(schemes); - while (enumerator->enumerate(enumerator, &schemep)) + while (enumerator->enumerate(enumerator, ¶ms)) { - scheme = *schemep; - if (private->sign(private, scheme, octets, auth_data) && - build_signature_auth_data(auth_data, scheme)) + if (private->sign(private, params->scheme, params->params, octets, + auth_data) && + build_signature_auth_data(auth_data, params)) { status = SUCCESS; break; @@ -233,16 +243,34 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this, else { DBG2(DBG_IKE, "unable to create %N signature for %N key", - signature_scheme_names, scheme, key_type_names, + signature_scheme_names, params->scheme, key_type_names, private->get_type(private)); } } enumerator->destroy(enumerator); } - DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id, - signature_scheme_names, scheme, - status == SUCCESS ? "successful" : "failed"); - array_destroy(schemes); + if (params) + { + if (params->scheme == SIGN_RSA_EMSA_PSS) + { + rsa_pss_params_t *pss = params->params; + DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N_%N %s", id, + signature_scheme_names, params->scheme, + hash_algorithm_short_names_upper, pss->hash, + status == SUCCESS ? "successful" : "failed"); + } + else + { + DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id, + signature_scheme_names, params->scheme, + status == SUCCESS ? "successful" : "failed"); + } + } + else + { + DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id); + } + array_destroy_function(schemes, destroy_scheme, NULL); chunk_free(&octets); return status; } @@ -253,23 +281,27 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this, */ static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this, bool verify, identification_t *id, - chunk_t *octets, signature_scheme_t *scheme) + chunk_t *octets, signature_params_t **scheme) { keymat_v2_t *keymat; array_t *schemes; bool success = FALSE; - schemes = array_create(sizeof(signature_scheme_t), 0); - array_insert(schemes, ARRAY_TAIL, scheme); + schemes = array_create(0, 0); + array_insert(schemes, ARRAY_TAIL, *scheme); keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); if (keymat->get_auth_octets(keymat, verify, this->ike_sa_init, this->nonce, id, this->reserved, octets, schemes) && - array_get(schemes, 0, &scheme)) + array_remove(schemes, 0, scheme)) { success = TRUE; } - array_destroy(schemes); + else + { + *scheme = NULL; + } + array_destroy_function(schemes, destroy_scheme, NULL); return success; } @@ -282,6 +314,7 @@ static status_t sign_classic(private_pubkey_authenticator_t *this, chunk_t *auth_data) { signature_scheme_t scheme; + signature_params_t *params; chunk_t octets = chunk_empty; status_t status = FAILED; @@ -319,11 +352,18 @@ static status_t sign_classic(private_pubkey_authenticator_t *this, return FAILED; } - if (get_auth_octets_scheme(this, FALSE, id, &octets, &scheme) && - private->sign(private, scheme, octets, auth_data)) + INIT(params, + .scheme = scheme, + ); + if (get_auth_octets_scheme(this, FALSE, id, &octets, ¶ms) && + private->sign(private, params->scheme, NULL, octets, auth_data)) { status = SUCCESS; } + if (params) + { + signature_params_destroy(params); + } DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id, auth_method_names, *auth_method, status == SUCCESS ? "successful" : "failed"); @@ -385,7 +425,7 @@ METHOD(authenticator_t, process, status_t, auth_cfg_t *auth, *current_auth; enumerator_t *enumerator; key_type_t key_type = KEY_ECDSA; - signature_scheme_t scheme; + signature_params_t *params; status_t status = NOT_FOUND; const char *reason = "unsupported"; bool online; @@ -395,25 +435,26 @@ METHOD(authenticator_t, process, status_t, { return FAILED; } + INIT(params); auth_method = auth_payload->get_auth_method(auth_payload); auth_data = auth_payload->get_data(auth_payload); switch (auth_method) { case AUTH_RSA: key_type = KEY_RSA; - scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + params->scheme = SIGN_RSA_EMSA_PKCS1_SHA1; break; case AUTH_ECDSA_256: - scheme = SIGN_ECDSA_256; + params->scheme = SIGN_ECDSA_256; break; case AUTH_ECDSA_384: - scheme = SIGN_ECDSA_384; + params->scheme = SIGN_ECDSA_384; break; case AUTH_ECDSA_521: - scheme = SIGN_ECDSA_521; + params->scheme = SIGN_ECDSA_521; break; case AUTH_DS: - if (parse_signature_auth_data(&auth_data, &key_type, &scheme)) + if (parse_signature_auth_data(&auth_data, &key_type, params)) { break; } @@ -422,10 +463,11 @@ METHOD(authenticator_t, process, status_t, default: DBG1(DBG_IKE, "%N authentication %s", auth_method_names, auth_method, reason); + signature_params_destroy(params); return INVALID_ARG; } id = this->ike_sa->get_other_id(this->ike_sa); - if (!get_auth_octets_scheme(this, TRUE, id, &octets, &scheme)) + if (!get_auth_octets_scheme(this, TRUE, id, &octets, ¶ms)) { return FAILED; } @@ -436,15 +478,31 @@ METHOD(authenticator_t, process, status_t, key_type, id, auth, online); while (enumerator->enumerate(enumerator, &public, ¤t_auth)) { - if (public->verify(public, scheme, octets, auth_data)) + if (public->verify(public, params->scheme, params->params, octets, + auth_data)) { - DBG1(DBG_IKE, "authentication of '%Y' with %N successful", id, - auth_method == AUTH_DS ? signature_scheme_names : auth_method_names, - auth_method == AUTH_DS ? scheme : auth_method); + if (auth_method != AUTH_DS) + { + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", id, + auth_method_names, auth_method); + } + else if (params->scheme == SIGN_RSA_EMSA_PSS) + { + rsa_pss_params_t *pss = params->params; + DBG1(DBG_IKE, "authentication of '%Y' with %N_%N successful", + id, signature_scheme_names, params->scheme, + hash_algorithm_short_names_upper, pss->hash); + } + else + { + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", id, + signature_scheme_names, params->scheme); + } status = SUCCESS; auth->merge(auth, current_auth, FALSE); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); - auth->add(auth, AUTH_RULE_IKE_SIGNATURE_SCHEME, (uintptr_t)scheme); + auth->add(auth, AUTH_RULE_IKE_SIGNATURE_SCHEME, + signature_params_clone(params)); if (!online) { auth->add(auth, AUTH_RULE_CERT_VALIDATION_SUSPENDED, TRUE); @@ -459,6 +517,7 @@ METHOD(authenticator_t, process, status_t, } enumerator->destroy(enumerator); chunk_free(&octets); + signature_params_destroy(params); if (status == NOT_FOUND) { DBG1(DBG_IKE, "no trusted %N public key found for '%Y'", diff --git a/src/libcharon/sa/ikev2/keymat_v2.h b/src/libcharon/sa/ikev2/keymat_v2.h index 36bf149fe..084ed40f0 100644 --- a/src/libcharon/sa/ikev2/keymat_v2.h +++ b/src/libcharon/sa/ikev2/keymat_v2.h @@ -101,8 +101,9 @@ struct keymat_v2_t { * @param id identity * @param reserved reserved bytes of id_payload * @param octests chunk receiving allocated auth octets - * @param schemes array containing signature schemes in case they - * need to be modified by the keymat implementation + * @param schemes array containing signature schemes + * (signature_params_t*) in case they need to be + * modified by the keymat implementation * @return TRUE if octets created successfully */ bool (*get_auth_octets)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index c2ddbc588..361eb0fe1 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -131,7 +131,7 @@ struct private_task_manager_t { array_t *queued_tasks; /** - * Array of active tasks, initiated by ourselve + * Array of active tasks, initiated by ourselves */ array_t *active_tasks; @@ -1780,9 +1780,11 @@ static void trigger_mbb_reauth(private_task_manager_t *this) enumerator_t *enumerator; child_sa_t *child_sa; child_cfg_t *cfg; + peer_cfg_t *peer; ike_sa_t *new; host_t *host; queued_task_t *queued; + bool children = FALSE; new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, this->ike_sa->get_version(this->ike_sa), TRUE); @@ -1791,7 +1793,8 @@ static void trigger_mbb_reauth(private_task_manager_t *this) return; } - new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa)); + peer = this->ike_sa->get_peer_cfg(this->ike_sa); + new->set_peer_cfg(new, peer); host = this->ike_sa->get_other_host(this->ike_sa); new->set_other_host(new, host->clone(host)); host = this->ike_sa->get_my_host(this->ike_sa); @@ -1809,6 +1812,7 @@ static void trigger_mbb_reauth(private_task_manager_t *this) cfg = child_sa->get_config(child_sa); new->queue_task(new, &child_create_create(new, cfg->get_ref(cfg), FALSE, NULL, NULL)->task); + children = TRUE; } enumerator->destroy(enumerator); @@ -1821,10 +1825,24 @@ static void trigger_mbb_reauth(private_task_manager_t *this) new->queue_task(new, queued->task); array_remove_at(this->queued_tasks, enumerator); free(queued); + children = TRUE; } } enumerator->destroy(enumerator); + if (!children +#ifdef ME + /* allow reauth of mediation connections without CHILD_SAs */ + && !peer->is_mediation(peer) +#endif /* ME */ + ) + { + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new); + DBG1(DBG_IKE, "unable to reauthenticate IKE_SA, no CHILD_SA " + "to recreate"); + return; + } + /* suspend online revocation checking until the SA is established */ new->set_condition(new, COND_ONLINE_VALIDATION_SUSPENDED, TRUE); diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index cac3bc0a2..4d4d72e0b 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -1377,7 +1377,6 @@ METHOD(task_t, build_r, status_t, uint16_t group = htons(this->dh_group); message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, chunk_from_thing(group)); - handle_child_sa_failure(this, message); return SUCCESS; } case FAILED: diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c index 2217295b6..164f8fc03 100644 --- a/src/libcharon/sa/ikev2/tasks/child_delete.c +++ b/src/libcharon/sa/ikev2/tasks/child_delete.c @@ -349,7 +349,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this) child_sa->get_unique_id(child_sa)), delay); continue; } - else if (expire) + else if (now < expire) { /* let it expire naturally */ continue; } diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c index 53daaf2ad..aeaa701c9 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_auth.c +++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c @@ -471,7 +471,6 @@ METHOD(task_t, build_i, status_t, if (idr && !idr->contains_wildcards(idr) && message->get_message_id(message) == 1 && - this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO && this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NEVER) { host_t *host; diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c index 58b710616..d75d21715 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_init.c +++ b/src/libcharon/sa/ikev2/tasks/ike_init.c @@ -158,7 +158,7 @@ static void send_supported_hash_algorithms(private_ike_init_t *this, peer_cfg_t *peer; auth_cfg_t *auth; auth_rule_t rule; - uintptr_t config; + signature_params_t *config; int written; size_t len = BUF_LEN; char buf[len]; @@ -177,7 +177,8 @@ static void send_supported_hash_algorithms(private_ike_init_t *this, { if (rule == AUTH_RULE_IKE_SIGNATURE_SCHEME) { - hash = hasher_from_signature_scheme(config); + hash = hasher_from_signature_scheme(config->scheme, + config->params); if (hasher_algorithm_for_ikev2(hash)) { algos->add(algos, hash); @@ -502,7 +503,11 @@ static void process_payloads(private_ike_init_t *this, message_t *message) this->dh = this->keymat->keymat.create_dh( &this->keymat->keymat, this->dh_group); } - if (this->dh) + else if (this->dh) + { + this->dh_failed = this->dh->get_dh_group(this->dh) != this->dh_group; + } + if (this->dh && !this->dh_failed) { this->dh_failed = !this->dh->set_other_public_value(this->dh, ke_payload->get_key_exchange_data(ke_payload)); @@ -811,7 +816,7 @@ METHOD(task_t, process_i, status_t, if (this->old_sa == NULL) { /* reset the IKE_SA if we are not rekeying */ - this->ike_sa->reset(this->ike_sa); + this->ike_sa->reset(this->ike_sa, FALSE); } enumerator->destroy(enumerator); @@ -829,7 +834,7 @@ METHOD(task_t, process_i, status_t, { chunk_free(&this->cookie); this->cookie = chunk_clone(notify->get_notification_data(notify)); - this->ike_sa->reset(this->ike_sa); + this->ike_sa->reset(this->ike_sa, FALSE); enumerator->destroy(enumerator); DBG2(DBG_IKE, "received %N notify", notify_type_names, type); this->retry++; diff --git a/src/libcharon/sa/ikev2/tasks/ike_vendor.c b/src/libcharon/sa/ikev2/tasks/ike_vendor.c index e85b276e8..f72fbc437 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_vendor.c +++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.c @@ -97,6 +97,8 @@ static vid_data_t vids[] = { "\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"}, { "Cisco Delete Reason", 0, NULL, 0, "CISCO-DELETE-REASON" }, + { "Cisco FlexVPN Supported", 0, NULL, 0, + "FLEXVPN-SUPPORTED" }, { "Cisco Copyright (c) 2009", 0, NULL, 0, "CISCO(COPYRIGHT)&Copyright (c) 2009 Cisco Systems, Inc." }, { "FRAGMENTATION", 0, NULL, 16, diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index ad12f0579..3a254cea5 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -96,6 +96,7 @@ static bool install_shunt_policy(child_cfg_t *child) status_t status = SUCCESS; uint32_t manual_prio; char *interface; + bool fwd_out; ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT }; switch (child->get_mode(child)) @@ -122,6 +123,7 @@ static bool install_shunt_policy(child_cfg_t *child) manual_prio = child->get_manual_prio(child); interface = child->get_interface(child); + fwd_out = child->has_option(child, OPT_FWD_OUT_POLICIES); /* enumerate pairs of traffic selectors */ e_my_ts = my_ts_list->create_enumerator(my_ts_list); @@ -157,9 +159,11 @@ static bool install_shunt_policy(child_cfg_t *child) .sa = &sa, }; status |= charon->kernel->add_policy(charon->kernel, &id, &policy); - /* install "outbound" forward policy */ - id.dir = POLICY_FWD; - status |= charon->kernel->add_policy(charon->kernel, &id, &policy); + if (fwd_out) + { /* install "outbound" forward policy */ + id.dir = POLICY_FWD; + status |= charon->kernel->add_policy(charon->kernel, &id, &policy); + } /* install in policy */ id = (kernel_ipsec_policy_id_t){ .dir = POLICY_IN, @@ -255,6 +259,7 @@ static void uninstall_shunt_policy(child_cfg_t *child) status_t status = SUCCESS; uint32_t manual_prio; char *interface; + bool fwd_out; ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT }; switch (child->get_mode(child)) @@ -281,6 +286,7 @@ static void uninstall_shunt_policy(child_cfg_t *child) manual_prio = child->get_manual_prio(child); interface = child->get_interface(child); + fwd_out = child->has_option(child, OPT_FWD_OUT_POLICIES); /* enumerate pairs of traffic selectors */ e_my_ts = my_ts_list->create_enumerator(my_ts_list); @@ -316,9 +322,12 @@ static void uninstall_shunt_policy(child_cfg_t *child) .sa = &sa, }; status |= charon->kernel->del_policy(charon->kernel, &id, &policy); - /* uninstall "outbound" forward policy */ - id.dir = POLICY_FWD; - status |= charon->kernel->del_policy(charon->kernel, &id, &policy); + if (fwd_out) + { + /* uninstall "outbound" forward policy */ + id.dir = POLICY_FWD; + status |= charon->kernel->del_policy(charon->kernel, &id, &policy); + } /* uninstall in policy */ id = (kernel_ipsec_policy_id_t){ .dir = POLICY_IN, |