From a46d233c0e2d0454cc3f865ed6fe72a13b2dbf86 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 11 Jul 2017 10:58:15 +0200 Subject: [PATCH 01/16] kernel-interface: Not all kernel interfaces support SPIs on policies --- src/libcharon/kernel/kernel_interface.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcharon/kernel/kernel_interface.h b/src/libcharon/kernel/kernel_interface.h index d601ebd4e..f4f55adfe 100644 --- a/src/libcharon/kernel/kernel_interface.h +++ b/src/libcharon/kernel/kernel_interface.h @@ -77,6 +77,8 @@ enum kernel_feature_t { KERNEL_REQUIRE_UDP_ENCAPSULATION = (1<<2), /** IPsec backend does not require a policy reinstall on SA updates */ KERNEL_NO_POLICY_UPDATES = (1<<3), + /** IPsec backend supports installing SPIs on policies */ + KERNEL_POLICY_SPI = (1<<4), }; /** From 2699c8387a443d16fb3135153317a7f0447674a3 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 11 Jul 2017 10:59:11 +0200 Subject: [PATCH 02/16] kernel-netlink: Set SPI on outbound policy This should cause the right SA to get used if there are multiple outbound SAs and the policies are installed properly. --- .../plugins/kernel_netlink/kernel_netlink_ipsec.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index c411b829d..8ddaa71d3 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1141,7 +1141,7 @@ static bool receive_events(private_kernel_netlink_ipsec_t *this, int fd, METHOD(kernel_ipsec_t, get_features, kernel_feature_t, private_kernel_netlink_ipsec_t *this) { - return KERNEL_ESP_V3_TFC; + return KERNEL_ESP_V3_TFC | KERNEL_POLICY_SPI; } /** @@ -2409,11 +2409,13 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, struct xfrm_user_tmpl *tmpl; struct { uint8_t proto; + uint32_t spi; bool use; } protos[] = { - { IPPROTO_COMP, ipsec->cfg.ipcomp.transform != IPCOMP_NONE }, - { IPPROTO_ESP, ipsec->cfg.esp.use }, - { IPPROTO_AH, ipsec->cfg.ah.use }, + { IPPROTO_COMP, htonl(ntohs(ipsec->cfg.ipcomp.cpi)), + ipsec->cfg.ipcomp.transform != IPCOMP_NONE }, + { IPPROTO_ESP, ipsec->cfg.esp.spi, ipsec->cfg.esp.use }, + { IPPROTO_AH, ipsec->cfg.ah.spi, ipsec->cfg.ah.use }, }; ipsec_mode_t proto_mode = ipsec->cfg.mode; int count = 0; @@ -2441,6 +2443,10 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, } tmpl->reqid = ipsec->cfg.reqid; tmpl->id.proto = protos[i].proto; + if (policy->direction == POLICY_OUT) + { + tmpl->id.spi = protos[i].spi; + } tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; tmpl->mode = mode2kernel(proto_mode); tmpl->optional = protos[i].proto == IPPROTO_COMP && From 2c116ef589b76b78216f5c61dfc1afefd3ae8f87 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 11 Jul 2017 13:12:02 +0200 Subject: [PATCH 03/16] child-sa: Use flags to track installation of outbound SA and policies separately --- src/libcharon/sa/child_sa.c | 51 ++++++++++++++------------ src/libcharon/sa/child_sa.h | 21 ++++++++--- src/libcharon/tests/utils/sa_asserts.h | 3 +- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 3d9f6133b..77d71ab15 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -40,10 +40,10 @@ ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING, "DESTROYING", ); -ENUM(child_sa_outbound_state_names, CHILD_OUTBOUND_NONE, CHILD_OUTBOUND_INSTALLED, - "NONE", +ENUM_FLAGS(child_sa_outbound_state_names, CHILD_OUTBOUND_REGISTERED, CHILD_OUTBOUND_POLICIES, "REGISTERED", - "INSTALLED", + "SA", + "POLICIES", ); typedef struct private_child_sa_t private_child_sa_t; @@ -547,7 +547,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound) } else { - if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED) + if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA)) { kernel_ipsec_sa_id_t id = { .src = this->my_addr, @@ -788,7 +788,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr, { tfc = this->config->get_tfc(this->config); } - this->outbound_state = CHILD_OUTBOUND_INSTALLED; + this->outbound_state |= CHILD_OUTBOUND_SA; } DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound", @@ -1188,6 +1188,7 @@ METHOD(child_sa_t, install_policies, status_t, linked_list_t *my_ts_list, *other_ts_list; traffic_selector_t *my_ts, *other_ts; status_t status = SUCCESS; + bool install_outbound = FALSE; if (!this->reqid_allocated && !this->static_reqid) { @@ -1207,12 +1208,17 @@ METHOD(child_sa_t, install_policies, status_t, this->reqid_allocated = TRUE; } + if (!(this->outbound_state & CHILD_OUTBOUND_REGISTERED)) + { + install_outbound = TRUE; + this->outbound_state |= CHILD_OUTBOUND_POLICIES; + } + if (!this->config->has_option(this->config, OPT_NO_POLICIES)) { policy_priority_t priority; ipsec_sa_cfg_t my_sa, other_sa; uint32_t manual_prio; - bool install_outbound; prepare_sa_cfg(this, &my_sa, &other_sa); manual_prio = this->config->get_manual_prio(this->config); @@ -1222,7 +1228,6 @@ METHOD(child_sa_t, install_policies, status_t, this->trap = this->state == CHILD_CREATED; priority = this->trap ? POLICY_PRIORITY_ROUTED : POLICY_PRIORITY_DEFAULT; - install_outbound = this->outbound_state != CHILD_OUTBOUND_REGISTERED; /* enumerate pairs of traffic selectors */ enumerator = create_policy_enumerator(this); @@ -1250,7 +1255,6 @@ METHOD(child_sa_t, install_policies, status_t, this->other_addr, my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC, priority, manual_prio); - } if (status != SUCCESS) { @@ -1281,7 +1285,7 @@ METHOD(child_sa_t, register_outbound, void, this->encr_r = chunk_clone(encr); this->integ_r = chunk_clone(integ); this->tfcv3 = tfcv3; - this->outbound_state = CHILD_OUTBOUND_REGISTERED; + this->outbound_state |= CHILD_OUTBOUND_REGISTERED; } METHOD(child_sa_t, install_outbound, status_t, @@ -1289,17 +1293,19 @@ METHOD(child_sa_t, install_outbound, status_t, { enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; - status_t status; + status_t status = SUCCESS; status = install_internal(this, this->encr_r, this->integ_r, - this->other_spi, this->other_cpi, FALSE, FALSE, - this->tfcv3); + this->other_spi, this->other_cpi, FALSE, + FALSE, this->tfcv3); chunk_clear(&this->encr_r); chunk_clear(&this->integ_r); + this->outbound_state &= ~CHILD_OUTBOUND_REGISTERED; if (status != SUCCESS) { return status; } + this->outbound_state |= CHILD_OUTBOUND_POLICIES; if (!this->config->has_option(this->config, OPT_NO_POLICIES)) { ipsec_sa_cfg_t my_sa, other_sa; @@ -1340,20 +1346,19 @@ METHOD(child_sa_t, remove_outbound, void, enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; - switch (this->outbound_state) + if (!(this->outbound_state & CHILD_OUTBOUND_SA)) { - case CHILD_OUTBOUND_INSTALLED: - break; - case CHILD_OUTBOUND_REGISTERED: + if (this->outbound_state & CHILD_OUTBOUND_REGISTERED) + { chunk_clear(&this->encr_r); chunk_clear(&this->integ_r); this->outbound_state = CHILD_OUTBOUND_NONE; - /* fall-through */ - case CHILD_OUTBOUND_NONE: - return; + } + return; } - if (!this->config->has_option(this->config, OPT_NO_POLICIES)) + if (!this->config->has_option(this->config, OPT_NO_POLICIES) && + (this->outbound_state & CHILD_OUTBOUND_POLICIES)) { ipsec_sa_cfg_t my_sa, other_sa; uint32_t manual_prio; @@ -1598,8 +1603,8 @@ METHOD(child_sa_t, destroy, void, prepare_sa_cfg(this, &my_sa, &other_sa); manual_prio = this->config->get_manual_prio(this->config); - del_outbound = this->trap || - this->outbound_state == CHILD_OUTBOUND_INSTALLED; + del_outbound = (this->outbound_state & CHILD_OUTBOUND_POLICIES) || + this->trap; /* delete all policies in the kernel */ enumerator = create_policy_enumerator(this); @@ -1640,7 +1645,7 @@ METHOD(child_sa_t, destroy, void, }; charon->kernel->del_sa(charon->kernel, &id, &sa); } - if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED) + if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA)) { kernel_ipsec_sa_id_t id = { .src = this->my_addr, diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index b9a913da1..e41157e79 100644 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -102,17 +102,28 @@ enum child_sa_outbound_state_t { /** * Outbound SA is not installed */ - CHILD_OUTBOUND_NONE, + CHILD_OUTBOUND_NONE = 0, /** - * Data for the outbound SA has been registered, but not installed yet + * Data for the outbound SA has been registered during a rekeying (not set + * once the SA and policies are both installed) */ - CHILD_OUTBOUND_REGISTERED, + CHILD_OUTBOUND_REGISTERED = (1<<0), /** - * The outbound SA is currently installed + * The outbound SA has been installed */ - CHILD_OUTBOUND_INSTALLED, + CHILD_OUTBOUND_SA = (1<<1), + + /** + * The outbound policies have been installed + */ + CHILD_OUTBOUND_POLICIES = (1<<2), + + /** + * The outbound SA and policies are both installed + */ + CHILD_OUTBOUND_INSTALLED = (CHILD_OUTBOUND_SA|CHILD_OUTBOUND_POLICIES), }; /** diff --git a/src/libcharon/tests/utils/sa_asserts.h b/src/libcharon/tests/utils/sa_asserts.h index d23f724f1..216c15065 100644 --- a/src/libcharon/tests/utils/sa_asserts.h +++ b/src/libcharon/tests/utils/sa_asserts.h @@ -121,7 +121,8 @@ test_assert_msg(_state == _child->get_state(_child), "%N != %N", \ child_sa_state_names, _state, \ child_sa_state_names, _child->get_state(_child)); \ - test_assert_msg(_outbound == _child->get_outbound_state(_child), "%N != %N", \ + typeof(outbound) _cur_out = _child->get_outbound_state(_child); \ + test_assert_msg(_outbound == _cur_out || _outbound & _cur_out, "%N != %N", \ child_sa_outbound_state_names, _outbound, \ child_sa_outbound_state_names, _child->get_outbound_state(_child)); \ }) From a146b4c9efa46c537d04b5089a54f10dc106e14a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 11 Jul 2017 13:42:06 +0200 Subject: [PATCH 04/16] child-sa: Install outbound SA immediately if kernel supports SPIs on policies --- src/libcharon/sa/child_sa.c | 52 ++++++++++++++------- src/libcharon/sa/child_sa.h | 13 ++++-- src/libcharon/sa/ikev2/tasks/child_create.c | 6 +-- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 77d71ab15..6c6804c64 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -1271,21 +1271,35 @@ METHOD(child_sa_t, install_policies, status_t, return status; } -METHOD(child_sa_t, register_outbound, void, +METHOD(child_sa_t, register_outbound, status_t, private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi, uint16_t cpi, bool tfcv3) { - DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names, - this->protocol); - DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr, - this->other_addr); + status_t status; - this->other_spi = spi; - this->other_cpi = cpi; - this->encr_r = chunk_clone(encr); - this->integ_r = chunk_clone(integ); - this->tfcv3 = tfcv3; + /* if the kernel supports installing SPIs with policies we install the + * SA immediately as it will only be used once we update the policies */ + if (charon->kernel->get_features(charon->kernel) & KERNEL_POLICY_SPI) + { + status = install_internal(this, encr, integ, spi, cpi, FALSE, FALSE, + tfcv3); + } + else + { + DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names, + this->protocol); + DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr, + this->other_addr); + + this->other_spi = spi; + this->other_cpi = cpi; + this->encr_r = chunk_clone(encr); + this->integ_r = chunk_clone(integ); + this->tfcv3 = tfcv3; + status = SUCCESS; + } this->outbound_state |= CHILD_OUTBOUND_REGISTERED; + return status; } METHOD(child_sa_t, install_outbound, status_t, @@ -1295,18 +1309,21 @@ METHOD(child_sa_t, install_outbound, status_t, traffic_selector_t *my_ts, *other_ts; status_t status = SUCCESS; - status = install_internal(this, this->encr_r, this->integ_r, - this->other_spi, this->other_cpi, FALSE, - FALSE, this->tfcv3); - chunk_clear(&this->encr_r); - chunk_clear(&this->integ_r); + if (!(this->outbound_state & CHILD_OUTBOUND_SA)) + { + status = install_internal(this, this->encr_r, this->integ_r, + this->other_spi, this->other_cpi, FALSE, + FALSE, this->tfcv3); + chunk_clear(&this->encr_r); + chunk_clear(&this->integ_r); + } this->outbound_state &= ~CHILD_OUTBOUND_REGISTERED; if (status != SUCCESS) { return status; } - this->outbound_state |= CHILD_OUTBOUND_POLICIES; - if (!this->config->has_option(this->config, OPT_NO_POLICIES)) + if (!this->config->has_option(this->config, OPT_NO_POLICIES) && + !(this->outbound_state & CHILD_OUTBOUND_POLICIES)) { ipsec_sa_cfg_t my_sa, other_sa; uint32_t manual_prio; @@ -1337,6 +1354,7 @@ METHOD(child_sa_t, install_outbound, status_t, } enumerator->destroy(enumerator); } + this->outbound_state |= CHILD_OUTBOUND_POLICIES; return status; } diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index e41157e79..082404d93 100644 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -411,20 +411,23 @@ struct child_sa_t { * Register data for the installation of an outbound SA as responder during * a rekeying. * - * The SA is not installed until install_outbound() is called. + * If the kernel is able to handle SPIs on policies the SA is installed + * immediately, if not it won't be installed until install_outbound() is + * called. * * @param encr encryption key, if any (cloned) * @param integ integrity key (cloned) * @param spi SPI to use, allocated for inbound * @param cpi CPI to use, allocated for outbound * @param tfcv3 TRUE if peer supports ESPv3 TFC + * @return SUCCESS or FAILED */ - void (*register_outbound)(child_sa_t *this, chunk_t encr, chunk_t integ, - uint32_t spi, uint16_t cpi, bool tfcv3); + status_t (*register_outbound)(child_sa_t *this, chunk_t encr, chunk_t integ, + uint32_t spi, uint16_t cpi, bool tfcv3); /** - * Install the outbound SA and the outbound policies as responder during a - * rekeying. + * Install the outbound policies and, if not already done, the outbound SA + * as responder during a rekeying. * * @return SUCCESS or FAILED */ diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index 747b9fac4..9d7d08c3b 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -698,9 +698,9 @@ static status_t select_and_install(private_child_create_t *this, status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, this->my_spi, this->my_cpi, this->initiator, TRUE, this->tfcv3); - this->child_sa->register_outbound(this->child_sa, encr_r, integ_r, - this->other_spi, this->other_cpi, this->tfcv3); - status_o = SUCCESS; + status_o = this->child_sa->register_outbound(this->child_sa, encr_r, + integ_r, this->other_spi, this->other_cpi, + this->tfcv3); } } From 0d42a762759c80748a003da46a99970b860535f9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 11 Jul 2017 13:49:21 +0200 Subject: [PATCH 05/16] charon-tkm: Claim to support SPIs on policies This fixes rekeying as the delayed installation of the outbound SA caused the nonce context to be expired already. --- src/charon-tkm/src/tkm/tkm_kernel_ipsec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c index c9be8989a..9229c3d67 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c +++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c @@ -52,6 +52,12 @@ struct private_tkm_kernel_ipsec_t { }; +METHOD(kernel_ipsec_t, get_features, kernel_feature_t, + private_tkm_kernel_ipsec_t *this) +{ + return KERNEL_POLICY_SPI; +} + METHOD(kernel_ipsec_t, get_spi, status_t, private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, uint8_t protocol, uint32_t *spi) @@ -358,6 +364,7 @@ tkm_kernel_ipsec_t *tkm_kernel_ipsec_create() INIT(this, .public = { .interface = { + .get_features = _get_features, .get_spi = _get_spi, .get_cpi = _get_cpi, .add_sa = _add_sa, From d24b831fe7def230cc604a2a2bf3f1a05a523c23 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 11 Jul 2017 14:05:01 +0200 Subject: [PATCH 06/16] charon-tkm: Don't select new outbound SA until the policy is installed This tries to avoid packet loss during rekeying by delaying the usage of the new outbound IKE_SA until the old one is deleted. Note that esa_select() is a no-op in the current TKM implementation. And the implementation also doesn't benefit from the delayed deletion of the inbound SA as it calls esa_reset() when the outbound SA is deleted. --- src/charon-tkm/src/tkm/tkm_kernel_ipsec.c | 62 +++++++++++++++-------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c index 9229c3d67..8ccae4cc2 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c +++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c @@ -1,7 +1,8 @@ /* + * Copyright (C) 2017 Tobias Brunner * Copyright (C) 2012-2014 Reto Buerki * Copyright (C) 2012 Adrian-Ken Rueegsegger - * 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 @@ -182,15 +183,6 @@ METHOD(kernel_ipsec_t, add_sa, status_t, tkm->chunk_map->remove(tkm->chunk_map, nonce_loc); tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id); } - if (ike_esa_select(esa_id) != TKM_OK) - { - DBG1(DBG_KNL, "error selecting new child SA (%llu)", esa_id); - if (ike_esa_reset(esa_id) != TKM_OK) - { - DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id); - } - goto failure; - } DBG1(DBG_KNL, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, " "esp_spi_rem: %x, role: %s)", esa_id, esa.isa_id, ntohl(spi_loc), @@ -221,23 +213,12 @@ METHOD(kernel_ipsec_t, del_sa, status_t, private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id, kernel_ipsec_del_sa_t *data) { - esa_id_type esa_id, other_esa_id; + esa_id_type esa_id; esa_id = tkm->sad->get_esa_id(tkm->sad, id->src, id->dst, id->spi, id->proto); if (esa_id) { - other_esa_id = tkm->sad->get_other_esa_id(tkm->sad, esa_id); - if (other_esa_id) - { - DBG1(DBG_KNL, "selecting child SA (esa: %llu)", other_esa_id); - if (ike_esa_select(other_esa_id) != TKM_OK) - { - DBG1(DBG_KNL, "error selecting other child SA (esa: %llu)", - other_esa_id); - } - } - DBG1(DBG_KNL, "deleting child SA (esa: %llu, spi: %x)", esa_id, ntohl(id->spi)); if (ike_esa_reset(esa_id) != TKM_OK) @@ -269,6 +250,43 @@ METHOD(kernel_ipsec_t, add_policy, status_t, private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id, kernel_ipsec_manage_policy_t *data) { + esa_id_type esa_id; + uint32_t spi; + uint8_t proto; + + if (id->dir == POLICY_OUT && data->type == POLICY_IPSEC && + data->prio == POLICY_PRIORITY_DEFAULT) + { + if (data->sa->esp.use) + { + spi = data->sa->esp.spi; + proto = IPPROTO_ESP; + } + else if (data->sa->ah.use) + { + spi = data->sa->ah.spi; + proto = IPPROTO_AH; + } + else + { + return FAILED; + } + esa_id = tkm->sad->get_esa_id(tkm->sad, data->src, data->dst, + spi, proto); + if (!esa_id) + { + DBG1(DBG_KNL, "unable to find esa ID for policy (spi: %x)", + ntohl(spi)); + return FAILED; + } + DBG1(DBG_KNL, "selecting child SA (esa: %llu, spi: %x)", esa_id, + ntohl(spi)); + if (ike_esa_select(esa_id) != TKM_OK) + { + DBG1(DBG_KNL, "error selecting new child SA (%llu)", esa_id); + return FAILED; + } + } return SUCCESS; } From f9fbcbb1a00d631bbd9d6ee1209251b3ee85dbaf Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 12 Jul 2017 13:00:59 +0200 Subject: [PATCH 07/16] bus: Don't trigger child_updown() for rekeyed CHILD_SAs We don't trigger it either when they are deleted individually. --- src/libcharon/bus/bus.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c index 77a910197..19943d060 100644 --- a/src/libcharon/bus/bus.c +++ b/src/libcharon/bus/bus.c @@ -827,7 +827,10 @@ METHOD(bus_t, ike_updown, void, enumerator = ike_sa->create_child_sa_enumerator(ike_sa); while (enumerator->enumerate(enumerator, (void**)&child_sa)) { - child_updown(this, child_sa, FALSE); + if (child_sa->get_state(child_sa) != CHILD_REKEYED) + { + child_updown(this, child_sa, FALSE); + } } enumerator->destroy(enumerator); } From 99cf64e960eddac09e4d362bc79a5194217ecb87 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 12 Jul 2017 16:53:13 +0200 Subject: [PATCH 08/16] testing: Add support for counting matching lines in tests Specifying an integer instead of YES in evaltest.dat causes the number to get compared against the actual number of lines matching the pattern. This may be used to count matching packets or log lines. --- testing/do-tests | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/testing/do-tests b/testing/do-tests index 230403b9f..2ebc96ee9 100755 --- a/testing/do-tests +++ b/testing/do-tests @@ -416,29 +416,38 @@ do STATUS="passed" eval `awk -F "::" '{ - host=$1 - command=$2 - pattern=$3 - hit=$4 - if (host !~ /^#.*/ && command != "") - { + host=$1 + command=$2 + pattern=$3 + hit=$4 + if (host ~ /^#.*/ || command == "") + { + next + } if (command == "tcpdump") { - printf("if [ \044TDUP_%s == \"true\" ]; then stop_tcpdump %s; fi; \n", host, host) - printf("echo \"%s# cat /tmp/tcpdump.log | grep \047%s\047 [%s]\"; ", host, pattern, hit) - printf("ssh \044SSHCONF root@\044ipv4_%s cat /tmp/tcpdump.log | grep \"%s\"; ", host, pattern) + printf("if [ \044TDUP_%s == \"true\" ]; then stop_tcpdump %s; fi; \n", host, host) + printf("echo \"%s# cat /tmp/tcpdump.log | grep \047%s\047 [%s]\"; ", host, pattern, hit) + printf("cmd_out=\044(ssh \044SSHCONF root@\044ipv4_%s cat /tmp/tcpdump.log | grep \"%s\"); ", host, pattern) } else { - printf("echo \"%s# %s | grep \047%s\047 [%s]\"; ", host, command, pattern, hit) - printf("ssh \044SSHCONF root@\044ipv4_%s %s | grep \"%s\"; ", host, command, pattern) + printf("echo \"%s# %s | grep \047%s\047 [%s]\"; ", host, command, pattern, hit) + printf("cmd_out=\044(ssh \044SSHCONF root@\044ipv4_%s %s | grep \"%s\"); ", host, command, pattern) } printf("cmd_exit=\044?; ") + printf("echo \"\044cmd_out\"; ") printf("echo; ") - printf("if [ \044cmd_exit -eq 0 -a \"%s\" = \"NO\" ] ", hit) - printf("|| [ \044cmd_exit -ne 0 -a \"%s\" = \"YES\" ] ", hit) + if (hit ~ /^[0-9]+$/) + { + printf("if [ \044(echo \"\044cmd_out\" | wc -l) -ne %d ] ", hit) + } + else + { + printf("if [ \044cmd_exit -eq 0 -a \"%s\" = \"NO\" ] ", hit) + printf("|| [ \044cmd_exit -ne 0 -a \"%s\" = \"YES\" ] ", hit) + } printf("; then STATUS=\"failed\"; fi; \n") - } }' $TESTDIR/evaltest.dat` >> $CONSOLE_LOG 2>&1 From 37a91758c9bd3f822014cd905e76c842d69e3569 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 12 Jul 2017 16:58:11 +0200 Subject: [PATCH 09/16] testing: Add ikev2/net2net-rekey scenario --- .../tests/ikev2/net2net-rekey/description.txt | 10 ++++++++ .../tests/ikev2/net2net-rekey/evaltest.dat | 14 +++++++++++ .../net2net-rekey/hosts/moon/etc/ipsec.conf | 24 +++++++++++++++++++ .../hosts/moon/etc/strongswan.conf | 7 ++++++ .../net2net-rekey/hosts/sun/etc/ipsec.conf | 22 +++++++++++++++++ .../hosts/sun/etc/strongswan.conf | 5 ++++ .../tests/ikev2/net2net-rekey/posttest.dat | 5 ++++ testing/tests/ikev2/net2net-rekey/pretest.dat | 7 ++++++ testing/tests/ikev2/net2net-rekey/test.conf | 21 ++++++++++++++++ 9 files changed, 115 insertions(+) create mode 100644 testing/tests/ikev2/net2net-rekey/description.txt create mode 100644 testing/tests/ikev2/net2net-rekey/evaltest.dat create mode 100644 testing/tests/ikev2/net2net-rekey/hosts/moon/etc/ipsec.conf create mode 100644 testing/tests/ikev2/net2net-rekey/hosts/moon/etc/strongswan.conf create mode 100644 testing/tests/ikev2/net2net-rekey/hosts/sun/etc/ipsec.conf create mode 100644 testing/tests/ikev2/net2net-rekey/hosts/sun/etc/strongswan.conf create mode 100644 testing/tests/ikev2/net2net-rekey/posttest.dat create mode 100644 testing/tests/ikev2/net2net-rekey/pretest.dat create mode 100644 testing/tests/ikev2/net2net-rekey/test.conf diff --git a/testing/tests/ikev2/net2net-rekey/description.txt b/testing/tests/ikev2/net2net-rekey/description.txt new file mode 100644 index 000000000..c3122a76f --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/description.txt @@ -0,0 +1,10 @@ +A connection between the subnets behind the gateways moon and sun is set up. +The authentication is based on X.509 certificates. Upon the successful +establishment of the IPsec tunnel, leftfirewall=yes automatically +inserts iptables-based firewall rules that let pass the tunneled traffic. +After a while the CHILD_SA is rekeyed by moon (after a deliberately short +time in this test scenario). +In order to test both tunnel and firewall after the rekeying, client alice +behind gateway moon pings client bob located behind gateway sun +twice, once right after the rekeying and once after the old inbound SA has been +deleted. diff --git a/testing/tests/ikev2/net2net-rekey/evaltest.dat b/testing/tests/ikev2/net2net-rekey/evaltest.dat new file mode 100644 index 000000000..0a34efe9d --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/evaltest.dat @@ -0,0 +1,14 @@ +moon::ipsec status 2> /dev/null::net-net.*ESTABLISHED.*moon.strongswan.org.*sun.strongswan.org::YES +sun:: ipsec status 2> /dev/null::net-net.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES +moon::ipsec status 2> /dev/null::net-net.*INSTALLED, TUNNEL::YES +sun:: ipsec status 2> /dev/null::net-net.*INSTALLED, TUNNEL::YES +moon::sleep 6::wait for rekeying::NO +moon::cat /var/log/daemon.log::creating rekey job for CHILD_SA::YES +moon::cat /var/log/daemon.log::generating CREATE_CHILD_SA request.*REKEY_SA::YES +moon::cat /var/log/daemon.log::deleted SAD entry with SPI::1 +alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES +moon::sleep 2::wait until inbound SA is deleted::NO +moon::cat /var/log/daemon.log::deleted SAD entry with SPI::2 +alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES +sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES +sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES diff --git a/testing/tests/ikev2/net2net-rekey/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/net2net-rekey/hosts/moon/etc/ipsec.conf new file mode 100644 index 000000000..dcd98b4de --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/hosts/moon/etc/ipsec.conf @@ -0,0 +1,24 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + charondebug="knl 2" + +conn %default + ikelifetime=60m + lifetime=10s + margintime=5s + rekeyfuzz=0% + keyingtries=1 + keyexchange=ikev2 + mobike=no + +conn net-net + left=PH_IP_MOON + leftcert=moonCert.pem + leftid=@moon.strongswan.org + leftsubnet=10.1.0.0/16 + leftfirewall=yes + right=PH_IP_SUN + rightid=@sun.strongswan.org + rightsubnet=10.2.0.0/16 + auto=add diff --git a/testing/tests/ikev2/net2net-rekey/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/net2net-rekey/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..3dcbf76ea --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/hosts/moon/etc/strongswan.conf @@ -0,0 +1,7 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac stroke kernel-netlink socket-default updown + # remove rekeyed inbound SA a bit quicker for the test scenario + delete_rekeyed_delay = 2 +} diff --git a/testing/tests/ikev2/net2net-rekey/hosts/sun/etc/ipsec.conf b/testing/tests/ikev2/net2net-rekey/hosts/sun/etc/ipsec.conf new file mode 100644 index 000000000..5b391db4b --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/hosts/sun/etc/ipsec.conf @@ -0,0 +1,22 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + mobike=no + +conn net-net + left=PH_IP_SUN + leftcert=sunCert.pem + leftid=@sun.strongswan.org + leftsubnet=10.2.0.0/16 + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + auto=add diff --git a/testing/tests/ikev2/net2net-rekey/hosts/sun/etc/strongswan.conf b/testing/tests/ikev2/net2net-rekey/hosts/sun/etc/strongswan.conf new file mode 100644 index 000000000..93f434598 --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/hosts/sun/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/ikev2/net2net-rekey/posttest.dat b/testing/tests/ikev2/net2net-rekey/posttest.dat new file mode 100644 index 000000000..837738fc6 --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/posttest.dat @@ -0,0 +1,5 @@ +moon::ipsec stop +sun::ipsec stop +moon::iptables-restore < /etc/iptables.flush +sun::iptables-restore < /etc/iptables.flush + diff --git a/testing/tests/ikev2/net2net-rekey/pretest.dat b/testing/tests/ikev2/net2net-rekey/pretest.dat new file mode 100644 index 000000000..bcc2cb04d --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/pretest.dat @@ -0,0 +1,7 @@ +moon::iptables-restore < /etc/iptables.rules +sun::iptables-restore < /etc/iptables.rules +sun::ipsec start +moon::ipsec start +sun::expect-connection net-net +moon::expect-connection net-net +moon::ipsec up net-net diff --git a/testing/tests/ikev2/net2net-rekey/test.conf b/testing/tests/ikev2/net2net-rekey/test.conf new file mode 100644 index 000000000..afa2accbe --- /dev/null +++ b/testing/tests/ikev2/net2net-rekey/test.conf @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This configuration file provides information on the +# guest instances used for this test + +# All guest instances that are required for this test +# +VIRTHOSTS="alice moon winnetou sun bob" + +# Corresponding block diagram +# +DIAGRAM="a-m-w-s-b.png" + +# Guest instances on which tcpdump is to be started +# +TCPDUMPHOSTS="sun" + +# Guest instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon sun" From a721b9c53d2e28a23b30e82023d24841c0d9f883 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 14 Jul 2017 12:29:04 +0200 Subject: [PATCH 10/16] testing: Add pfkey/net2net-rekey scenario --- .../tests/pfkey/net2net-rekey/description.txt | 10 ++++++++ .../tests/pfkey/net2net-rekey/evaltest.dat | 16 +++++++++++++ .../net2net-rekey/hosts/moon/etc/ipsec.conf | 24 +++++++++++++++++++ .../hosts/moon/etc/strongswan.conf | 7 ++++++ .../net2net-rekey/hosts/sun/etc/ipsec.conf | 22 +++++++++++++++++ .../hosts/sun/etc/strongswan.conf | 5 ++++ .../tests/pfkey/net2net-rekey/posttest.dat | 5 ++++ testing/tests/pfkey/net2net-rekey/pretest.dat | 7 ++++++ testing/tests/pfkey/net2net-rekey/test.conf | 21 ++++++++++++++++ 9 files changed, 117 insertions(+) create mode 100644 testing/tests/pfkey/net2net-rekey/description.txt create mode 100644 testing/tests/pfkey/net2net-rekey/evaltest.dat create mode 100644 testing/tests/pfkey/net2net-rekey/hosts/moon/etc/ipsec.conf create mode 100644 testing/tests/pfkey/net2net-rekey/hosts/moon/etc/strongswan.conf create mode 100644 testing/tests/pfkey/net2net-rekey/hosts/sun/etc/ipsec.conf create mode 100644 testing/tests/pfkey/net2net-rekey/hosts/sun/etc/strongswan.conf create mode 100644 testing/tests/pfkey/net2net-rekey/posttest.dat create mode 100644 testing/tests/pfkey/net2net-rekey/pretest.dat create mode 100644 testing/tests/pfkey/net2net-rekey/test.conf diff --git a/testing/tests/pfkey/net2net-rekey/description.txt b/testing/tests/pfkey/net2net-rekey/description.txt new file mode 100644 index 000000000..c3122a76f --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/description.txt @@ -0,0 +1,10 @@ +A connection between the subnets behind the gateways moon and sun is set up. +The authentication is based on X.509 certificates. Upon the successful +establishment of the IPsec tunnel, leftfirewall=yes automatically +inserts iptables-based firewall rules that let pass the tunneled traffic. +After a while the CHILD_SA is rekeyed by moon (after a deliberately short +time in this test scenario). +In order to test both tunnel and firewall after the rekeying, client alice +behind gateway moon pings client bob located behind gateway sun +twice, once right after the rekeying and once after the old inbound SA has been +deleted. diff --git a/testing/tests/pfkey/net2net-rekey/evaltest.dat b/testing/tests/pfkey/net2net-rekey/evaltest.dat new file mode 100644 index 000000000..3bf3b274b --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/evaltest.dat @@ -0,0 +1,16 @@ +moon::ipsec status 2> /dev/null::net-net.*ESTABLISHED.*moon.strongswan.org.*sun.strongswan.org::YES +sun:: ipsec status 2> /dev/null::net-net.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES +moon::ipsec status 2> /dev/null::net-net.*INSTALLED, TUNNEL::YES +sun:: ipsec status 2> /dev/null::net-net.*INSTALLED, TUNNEL::YES +# deleting the inbound SPI +moon::cat /var/log/daemon.log::deleted SAD entry with SPI::1 +moon::sleep 6::wait for rekeying::NO +moon::cat /var/log/daemon.log::creating rekey job for CHILD_SA::YES +moon::cat /var/log/daemon.log::generating CREATE_CHILD_SA request.*REKEY_SA::YES +moon::cat /var/log/daemon.log::deleted SAD entry with SPI::3 +alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES +moon::sleep 2::wait until inbound SA is deleted::NO +moon::cat /var/log/daemon.log::deleted SAD entry with SPI::4 +alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES +sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES +sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES diff --git a/testing/tests/pfkey/net2net-rekey/hosts/moon/etc/ipsec.conf b/testing/tests/pfkey/net2net-rekey/hosts/moon/etc/ipsec.conf new file mode 100644 index 000000000..dcd98b4de --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/hosts/moon/etc/ipsec.conf @@ -0,0 +1,24 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + charondebug="knl 2" + +conn %default + ikelifetime=60m + lifetime=10s + margintime=5s + rekeyfuzz=0% + keyingtries=1 + keyexchange=ikev2 + mobike=no + +conn net-net + left=PH_IP_MOON + leftcert=moonCert.pem + leftid=@moon.strongswan.org + leftsubnet=10.1.0.0/16 + leftfirewall=yes + right=PH_IP_SUN + rightid=@sun.strongswan.org + rightsubnet=10.2.0.0/16 + auto=add diff --git a/testing/tests/pfkey/net2net-rekey/hosts/moon/etc/strongswan.conf b/testing/tests/pfkey/net2net-rekey/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..4234eb134 --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/hosts/moon/etc/strongswan.conf @@ -0,0 +1,7 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac stroke kernel-pfkey kernel-netlink socket-default updown + # remove rekeyed inbound SA a bit quicker for the test scenario + delete_rekeyed_delay = 2 +} diff --git a/testing/tests/pfkey/net2net-rekey/hosts/sun/etc/ipsec.conf b/testing/tests/pfkey/net2net-rekey/hosts/sun/etc/ipsec.conf new file mode 100644 index 000000000..5b391db4b --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/hosts/sun/etc/ipsec.conf @@ -0,0 +1,22 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev2 + mobike=no + +conn net-net + left=PH_IP_SUN + leftcert=sunCert.pem + leftid=@sun.strongswan.org + leftsubnet=10.2.0.0/16 + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + auto=add diff --git a/testing/tests/pfkey/net2net-rekey/hosts/sun/etc/strongswan.conf b/testing/tests/pfkey/net2net-rekey/hosts/sun/etc/strongswan.conf new file mode 100644 index 000000000..0ecc2f847 --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/hosts/sun/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac stroke kernel-pfkey kernel-netlink socket-default updown +} diff --git a/testing/tests/pfkey/net2net-rekey/posttest.dat b/testing/tests/pfkey/net2net-rekey/posttest.dat new file mode 100644 index 000000000..837738fc6 --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/posttest.dat @@ -0,0 +1,5 @@ +moon::ipsec stop +sun::ipsec stop +moon::iptables-restore < /etc/iptables.flush +sun::iptables-restore < /etc/iptables.flush + diff --git a/testing/tests/pfkey/net2net-rekey/pretest.dat b/testing/tests/pfkey/net2net-rekey/pretest.dat new file mode 100644 index 000000000..bcc2cb04d --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/pretest.dat @@ -0,0 +1,7 @@ +moon::iptables-restore < /etc/iptables.rules +sun::iptables-restore < /etc/iptables.rules +sun::ipsec start +moon::ipsec start +sun::expect-connection net-net +moon::expect-connection net-net +moon::ipsec up net-net diff --git a/testing/tests/pfkey/net2net-rekey/test.conf b/testing/tests/pfkey/net2net-rekey/test.conf new file mode 100644 index 000000000..afa2accbe --- /dev/null +++ b/testing/tests/pfkey/net2net-rekey/test.conf @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This configuration file provides information on the +# guest instances used for this test + +# All guest instances that are required for this test +# +VIRTHOSTS="alice moon winnetou sun bob" + +# Corresponding block diagram +# +DIAGRAM="a-m-w-s-b.png" + +# Guest instances on which tcpdump is to be started +# +TCPDUMPHOSTS="sun" + +# Guest instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon sun" From 5163bd4b86bbcb54ab52cfec4e537626bc7bafe0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 13 Jul 2017 18:41:36 +0200 Subject: [PATCH 11/16] testing: Add tkm/xfrmproxy-rekey scenario Similar to the xfrmproxy-expire scenario but here the TKM host is the responder to a rekeying. --- .../tests/tkm/xfrmproxy-rekey/description.txt | 6 +++++ .../tests/tkm/xfrmproxy-rekey/evaltest.dat | 19 +++++++++++++++ .../hosts/moon/etc/strongswan.conf | 8 +++++++ .../hosts/moon/etc/tkm/moonKey.der | Bin 0 -> 1191 bytes .../hosts/moon/etc/tkm/strongswanCert.der | Bin 0 -> 956 bytes .../hosts/moon/etc/tkm/tkm.conf | 21 +++++++++++++++++ .../xfrmproxy-rekey/hosts/sun/etc/ipsec.conf | 22 ++++++++++++++++++ .../hosts/sun/etc/strongswan.conf | 5 ++++ .../tests/tkm/xfrmproxy-rekey/posttest.dat | 5 ++++ testing/tests/tkm/xfrmproxy-rekey/pretest.dat | 12 ++++++++++ testing/tests/tkm/xfrmproxy-rekey/test.conf | 21 +++++++++++++++++ 11 files changed, 119 insertions(+) create mode 100644 testing/tests/tkm/xfrmproxy-rekey/description.txt create mode 100644 testing/tests/tkm/xfrmproxy-rekey/evaltest.dat create mode 100644 testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf create mode 100644 testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/tkm/moonKey.der create mode 100644 testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/tkm/strongswanCert.der create mode 100644 testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/tkm/tkm.conf create mode 100644 testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/ipsec.conf create mode 100644 testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/strongswan.conf create mode 100644 testing/tests/tkm/xfrmproxy-rekey/posttest.dat create mode 100644 testing/tests/tkm/xfrmproxy-rekey/pretest.dat create mode 100644 testing/tests/tkm/xfrmproxy-rekey/test.conf diff --git a/testing/tests/tkm/xfrmproxy-rekey/description.txt b/testing/tests/tkm/xfrmproxy-rekey/description.txt new file mode 100644 index 000000000..648011b11 --- /dev/null +++ b/testing/tests/tkm/xfrmproxy-rekey/description.txt @@ -0,0 +1,6 @@ +A transport connection between the hosts moon and sun is set up. +The host moon starts the Trusted Key Manager (TKM) and the Ada XFRM +proxy, which relays XFRM kernel messages to charon. The authentication is based +on X.509 certificates. The connection is initiated by a ping from moon +to sun. The test asserts that a rekeying initiated by sun works +as expected. diff --git a/testing/tests/tkm/xfrmproxy-rekey/evaltest.dat b/testing/tests/tkm/xfrmproxy-rekey/evaltest.dat new file mode 100644 index 000000000..328b4854b --- /dev/null +++ b/testing/tests/tkm/xfrmproxy-rekey/evaltest.dat @@ -0,0 +1,19 @@ +moon::ipsec stroke status 2> /dev/null::conn1.*ESTABLISHED.*moon.strongswan.org.*sun.strongswan.org::YES +sun::ipsec status 2> /dev/null::host-host.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES +moon::ipsec stroke status 2> /dev/null::conn1.*INSTALLED, TRANSPORT::YES +sun::ipsec status 2> /dev/null::host-host.*INSTALLED, TRANSPORT::YES +moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_.eq=1::YES +sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES +sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES +sun::cat /var/log/daemon.log::creating rekey job for CHILD_SA ESP/0x.*/192.168.0.2::YES +moon::cat /var/log/daemon.log::deleting child SA (esa: 1, spi:.*)::YES +moon::cat /tmp/tkm.log::RSA private key '/etc/tkm/moonKey.der' loaded::YES +moon::cat /tmp/tkm.log::Adding policy \[ 1, 192.168.0.1 <-> 192.168.0.2 \]::YES +moon::cat /tmp/tkm.log::Checked CA certificate of CC context 1::YES +moon::cat /tmp/tkm.log::Authentication of ISA context 1 successful::YES +moon::cat /tmp/tkm.log::Creating first new ESA context with ID 1 (Isa 1, Sp 1, Ea 1, Initiator TRUE, spi_loc.*, spi_rem.*)::YES +moon::cat /tmp/tkm.log::Creating ESA context with ID 2 (Isa 1, Sp 1, Ea 1, Dh_Id 1, Nc_Loc_Id 1, Initiator FALSE, spi_loc.*, spi_rem.*)::YES +moon::cat /tmp/tkm.log | grep 'Adding ESA \[ 1, 192.168.0.1 <-> 192.168.0.2, SPI_in.*, SPI_out.*, soft 30, hard 60 \]' | wc -l::2::YES +moon::cat /tmp/tkm.log::Resetting ESA context 1::YES +moon::cat /tmp/tkm.log::Deleting ESA \[ 1, 192.168.0.1 <=> 192.168.0.2, SPI_in.*, SPI_out.* \]::YES +moon::cat /tmp/xfrm_proxy.log::Initiating ESA acquire for reqid 1::YES diff --git a/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf b/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..cc9d6e072 --- /dev/null +++ b/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf @@ -0,0 +1,8 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon-tkm { + dh_mapping { + 15 = 1 + 16 = 2 + } +} diff --git a/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/tkm/moonKey.der b/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/tkm/moonKey.der new file mode 100644 index 0000000000000000000000000000000000000000..d3748930a7da99c460214bae2eedf2d58d011de0 GIT binary patch literal 1191 zcmV;Y1X%kpf&`-i0RRGm0RaG{dhq;DHNNyXk+g2SP10pz-}d5!ZX^}-fB~=0%k+>hYo3H0fFe-KhVf{#Rk8{q z6eVTP653)g0c{C$p(dV!Z}vWg{?$YG?yB$B*P(tUHAFmNsr5=!aKU zg`u9IZmDf7DZD)e&O{2N17$cW|K+)DR~eg}ckLtl1_t#I7>1?ibCDD1;8$OgE21=@ z0v3oWRN97VV8AV>wXr&QEC7~75yrqLO1I0TV z^mG+CxWmlkKE8dnUOwPZAtS)K0)c@5*hXNw?8$c&NLUo7BP{6)H|m=~Aj!I3F5*>x zHKl7zidc?-c(_(_zq_N=1oCi@9arBXxFcFiBXjh*797I$HWD6_+VL~sd9=_gg>jt! zP?8_lMv`L+s0s2-jAB=ZV-~&uq%Z$&ayAm(qX`X1NR-w_;%S6QF#Q&a048(=0)c@5 z!m?gta=>c?q-s({FjVa=dn#m4bxd3gx75&|JggXf(ChC_`mCu-l7f29xzp;PuK-m> zWKDBevC35FKX7yera3r2!NAOQFZ|Lwe0w8?Lu$aT-+Z>ZL5p!zv9A=*OlMv3_(X|Q zwFoubGfzK}Cy;ASJtxfKV{<;>(A3{KCP)z7P| zFWi{5=Xc&KHp;JLZmi6myO05bk%yoj^aIhm0(Krd$a)yvr3)XN)UWvRWH1toJAEDZ4?<WeaP3qCjNe!i8&xoYjClnj9{Oy<~0Uu)pa zIqlTCe_|Y*k8t zNrNw+8fCkXXBpCzo&!&pII!KwF;kq^9!$Rifq;9R0iy4Uf+(aKSj_7R*y}`}qfqTE z2hbA4Qt3y^#)qk?`JhZ@Ggjtd=&vw0J%&9PEpRyQypSC{c)T7>zjVm_x)d9wYYO&n zp~Mbd@8|6}F2D%MkGG!_o<_^bR}B#j$deD&_@CU}q94bQ)C8aMPyT{%O_DUFVI+`H FH`OpGI1&H= literal 0 HcmV?d00001 diff --git a/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/tkm/strongswanCert.der b/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/tkm/strongswanCert.der new file mode 100644 index 0000000000000000000000000000000000000000..a5a631f4b5f8b29a990ab4b075e44e0d961c6286 GIT binary patch literal 956 zcmXqLV%}lU#I#@mGZP~d6C;BGFB_*;n@8JsUPeZ4Rt5uCLv903Hs(+kHen`b4?{@< zaS(?~SimPUue3s;xTGjQFFm+CG0#xiKoTUyEG&c&R0zt?FHvxIG>{YLH83%-G&C?Y zFfcTDv^20ZFo$xfWla;K60!#vSs9p{82K3tni#p5niv@w_J4{`dSx4y7qR(7 zmFKC?YZA||OfE0>ZPDHQ<8R&qVr3m&D^Z!e>5hr^J|7ip;*q&X7;J9nJMy%`F{u86ZU_r zKi%fNl%kd_PMW94}Puv*8AYCiO2emHylag=VxMO zWMEv}xXGY#y@3!gwq%7F8UM3z7_b2;CPqdBZjcy13kxtYuo=jLID9N(EF!VX?-sBH z8r41Dmb-cD(+3H!^nBkN;%VE(+*PTKbXwG3(qzs@zZJ zGO5X|urkr(i+z5@#=OMO{@h~8a)ncZEmz)8dA9F0uZpn zO<5(yvOZRAu^X3LC!@PVa?^LSM*f5(vbm~p5 zWc{Ll0keeWtb7-8Uz_hvj;%$Qzkq7qpBwv{HoZxiUT2jb_hH7X + + moon.strongswan.org + moonCert.pem + + + transport + + 1 + 192.168.0.1 + + + sun.strongswan.org + 192.168.0.2 + + + 30 + 60 + + + diff --git a/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/ipsec.conf b/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/ipsec.conf new file mode 100644 index 000000000..99ffb301e --- /dev/null +++ b/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/ipsec.conf @@ -0,0 +1,22 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +config setup + +conn %default + ikelifetime=60m + keylife=10s + rekeymargin=8s + rekeyfuzz=0% + keyingtries=1 + keyexchange=ikev2 + +conn host-host + left=PH_IP_SUN + leftcert=sunCert.pem + leftid=sun.strongswan.org + right=PH_IP_MOON + rightid=moon.strongswan.org + ike=aes256-sha512-modp4096! + esp=aes256-sha512-modp4096! + type=transport + auto=add diff --git a/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/strongswan.conf b/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/strongswan.conf new file mode 100644 index 000000000..f585edfca --- /dev/null +++ b/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/strongswan.conf @@ -0,0 +1,5 @@ +# /etc/strongswan.conf - strongSwan configuration file + +charon { + load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown +} diff --git a/testing/tests/tkm/xfrmproxy-rekey/posttest.dat b/testing/tests/tkm/xfrmproxy-rekey/posttest.dat new file mode 100644 index 000000000..99efe7b00 --- /dev/null +++ b/testing/tests/tkm/xfrmproxy-rekey/posttest.dat @@ -0,0 +1,5 @@ +moon::DAEMON_NAME=charon-tkm ipsec stop +moon::killall xfrm_proxy +moon::killall tkm_keymanager +moon::rm -f /tmp/tkm.rpc.ike /tmp/tkm.rpc.ees /tmp/tkm.log /tmp/xfrm_proxy.log +sun::ipsec stop diff --git a/testing/tests/tkm/xfrmproxy-rekey/pretest.dat b/testing/tests/tkm/xfrmproxy-rekey/pretest.dat new file mode 100644 index 000000000..d645ddbfe --- /dev/null +++ b/testing/tests/tkm/xfrmproxy-rekey/pretest.dat @@ -0,0 +1,12 @@ +sun::ipsec start +moon::rm /etc/ipsec.secrets +moon::tkm_cfgtool -c /etc/tkm/tkm.conf -i /etc/ipsec.conf -t /etc/tkm/tkm.bin -s /usr/local/share/tkm/tkmconfig.xsd +moon::cat /etc/ipsec.conf +moon::tkm_keymanager -c /etc/tkm/tkm.bin -k /etc/tkm/moonKey.der -r /etc/tkm/strongswanCert.der >/tmp/tkm.log 2>&1 & +moon::expect-file /tmp/tkm.rpc.ike +moon::DAEMON_NAME=charon-tkm ipsec start +moon::expect-file /tmp/tkm.rpc.ees +moon::xfrm_proxy >/tmp/xfrm_proxy.log 2>&1 & +moon::DAEMON_NAME=charon-tkm expect-connection conn1 +sun::expect-connection host-host +moon::ping -c 3 192.168.0.2 diff --git a/testing/tests/tkm/xfrmproxy-rekey/test.conf b/testing/tests/tkm/xfrmproxy-rekey/test.conf new file mode 100644 index 000000000..9647dc6a2 --- /dev/null +++ b/testing/tests/tkm/xfrmproxy-rekey/test.conf @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This configuration file provides information on the +# guest instances used for this test + +# All guest instances that are required for this test +# +VIRTHOSTS="moon winnetou sun" + +# Corresponding block diagram +# +DIAGRAM="m-w-s.png" + +# Guest instances on which tcpdump is to be started +# +TCPDUMPHOSTS="sun" + +# Guest instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon sun" From 87c6247e0d0436690caa073a6d3acf7e51399837 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 13 Jul 2017 19:09:07 +0200 Subject: [PATCH 12/16] testing: Clearly mark the tests that failed --- testing/do-tests | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/testing/do-tests b/testing/do-tests index 2ebc96ee9..97d7e45f7 100755 --- a/testing/do-tests +++ b/testing/do-tests @@ -427,17 +427,14 @@ do if (command == "tcpdump") { printf("if [ \044TDUP_%s == \"true\" ]; then stop_tcpdump %s; fi; \n", host, host) - printf("echo \"%s# cat /tmp/tcpdump.log | grep \047%s\047 [%s]\"; ", host, pattern, hit) printf("cmd_out=\044(ssh \044SSHCONF root@\044ipv4_%s cat /tmp/tcpdump.log | grep \"%s\"); ", host, pattern) } else { - printf("echo \"%s# %s | grep \047%s\047 [%s]\"; ", host, command, pattern, hit) printf("cmd_out=\044(ssh \044SSHCONF root@\044ipv4_%s %s | grep \"%s\"); ", host, command, pattern) } printf("cmd_exit=\044?; ") - printf("echo \"\044cmd_out\"; ") - printf("echo; ") + printf("cmd_fail=0; ") if (hit ~ /^[0-9]+$/) { printf("if [ \044(echo \"\044cmd_out\" | wc -l) -ne %d ] ", hit) @@ -447,7 +444,20 @@ do printf("if [ \044cmd_exit -eq 0 -a \"%s\" = \"NO\" ] ", hit) printf("|| [ \044cmd_exit -ne 0 -a \"%s\" = \"YES\" ] ", hit) } - printf("; then STATUS=\"failed\"; fi; \n") + printf("; then STATUS=\"failed\"; cmd_fail=1; fi; \n") + + printf("if [ \044cmd_fail -ne 0 ]; then echo \"~~~~~~~ FAIL ~~~~~~~\"; fi; \n") + if (command == "tcpdump") + { + printf("echo \"%s# cat /tmp/tcpdump.log | grep \047%s\047 [%s]\"; ", host, pattern, hit) + } + else + { + printf("echo \"%s# %s | grep \047%s\047 [%s]\"; ", host, command, pattern, hit) + } + printf("if [ -n \"\044cmd_out\" ]; then echo \"\044cmd_out\"; fi; \n") + printf("if [ \044cmd_fail -ne 0 ]; then echo \"~~~~~~~~~~~~~~~~~~~~\"; fi; \n") + printf("echo; ") }' $TESTDIR/evaltest.dat` >> $CONSOLE_LOG 2>&1 From f0d051f19225c7b9e99c9d522a4b304c57ed3337 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 14 Jul 2017 11:22:27 +0200 Subject: [PATCH 13/16] testing: Also capture stderr during test cases The output was not correct otherwise due to the reordering of commands. --- testing/do-tests | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testing/do-tests b/testing/do-tests index 97d7e45f7..ba2abb655 100755 --- a/testing/do-tests +++ b/testing/do-tests @@ -424,6 +424,7 @@ do { next } + printf("cmd_err=\044(tempfile -p test -s err); ") if (command == "tcpdump") { printf("if [ \044TDUP_%s == \"true\" ]; then stop_tcpdump %s; fi; \n", host, host) @@ -431,7 +432,7 @@ do } else { - printf("cmd_out=\044(ssh \044SSHCONF root@\044ipv4_%s %s | grep \"%s\"); ", host, command, pattern) + printf("cmd_out=\044(ssh \044SSHCONF root@\044ipv4_%s %s 2>\044cmd_err | grep \"%s\"); ", host, command, pattern) } printf("cmd_exit=\044?; ") printf("cmd_fail=0; ") @@ -456,6 +457,7 @@ do printf("echo \"%s# %s | grep \047%s\047 [%s]\"; ", host, command, pattern, hit) } printf("if [ -n \"\044cmd_out\" ]; then echo \"\044cmd_out\"; fi; \n") + printf("cat \044cmd_err; rm -f -- \044cmd_err; \n") printf("if [ \044cmd_fail -ne 0 ]; then echo \"~~~~~~~~~~~~~~~~~~~~\"; fi; \n") printf("echo; ") }' $TESTDIR/evaltest.dat` >> $CONSOLE_LOG 2>&1 From 15e745cf4d1257df2b1cdf83961e0838b601ade5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Aug 2017 13:12:57 +0200 Subject: [PATCH 14/16] child-rekey: Don't install outbound SA in case of lost collisions This splits the SA installation also on the initiator, so we can avoid installing the outbound SA if we lost a rekey collision, which might have caused traffic loss depending on the timing of the DELETEs that are sent in both directions. --- src/libcharon/sa/ikev2/tasks/child_create.c | 45 ++++++---- src/libcharon/sa/ikev2/tasks/child_delete.c | 1 - src/libcharon/sa/ikev2/tasks/child_rekey.c | 39 ++++++++- src/libcharon/tests/suites/test_child_rekey.c | 82 +++++++++++++------ 4 files changed, 122 insertions(+), 45 deletions(-) diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index 9d7d08c3b..9fe6929c1 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -478,6 +478,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh, bool ike_auth) { status_t status, status_i, status_o; + child_sa_outbound_state_t out_state; chunk_t nonce_i, nonce_r; chunk_t encr_i = chunk_empty, encr_r = chunk_empty; chunk_t integ_i = chunk_empty, integ_r = chunk_empty; @@ -678,29 +679,42 @@ static status_t select_and_install(private_child_create_t *this, status_i = this->child_sa->install(this->child_sa, encr_r, integ_r, this->my_spi, this->my_cpi, this->initiator, TRUE, this->tfcv3); - status_o = this->child_sa->install(this->child_sa, encr_i, integ_i, - this->other_spi, this->other_cpi, this->initiator, - FALSE, this->tfcv3); } - else if (!this->rekey) + else { status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, this->my_spi, this->my_cpi, this->initiator, TRUE, this->tfcv3); - status_o = this->child_sa->install(this->child_sa, encr_r, integ_r, + } + if (this->rekey) + { /* during rekeyings we install the outbound SA and/or policies + * separately: as responder when we receive the delete for the old + * SA, as initiator pretty much immediately in the ike-rekey task, + * unless there was a rekey collision that we lost */ + if (this->initiator) + { + status_o = this->child_sa->register_outbound(this->child_sa, + encr_i, integ_i, this->other_spi, this->other_cpi, + this->tfcv3); + } + else + { + status_o = this->child_sa->register_outbound(this->child_sa, + encr_r, integ_r, this->other_spi, this->other_cpi, + this->tfcv3); + } + } + else if (this->initiator) + { + status_o = this->child_sa->install(this->child_sa, encr_i, integ_i, this->other_spi, this->other_cpi, this->initiator, FALSE, this->tfcv3); } else - { /* as responder during a rekeying we only install the inbound - * SA now, the outbound SA and policies are installed when we - * receive the delete for the old SA */ - status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, - this->my_spi, this->my_cpi, this->initiator, - TRUE, this->tfcv3); - status_o = this->child_sa->register_outbound(this->child_sa, encr_r, - integ_r, this->other_spi, this->other_cpi, - this->tfcv3); + { + status_o = this->child_sa->install(this->child_sa, encr_r, integ_r, + this->other_spi, this->other_cpi, this->initiator, + FALSE, this->tfcv3); } } @@ -749,10 +763,11 @@ static status_t select_and_install(private_child_create_t *this, this->child_sa->create_ts_enumerator(this->child_sa, TRUE)); other_ts = linked_list_create_from_enumerator( this->child_sa->create_ts_enumerator(this->child_sa, FALSE)); + out_state = this->child_sa->get_outbound_state(this->child_sa); DBG0(DBG_IKE, "%sCHILD_SA %s{%d} established " "with SPIs %.8x_i %.8x_o and TS %#R === %#R", - this->rekey && !this->initiator ? "inbound " : "", + (out_state == CHILD_OUTBOUND_INSTALLED) ? "" : "inbound ", this->child_sa->get_name(this->child_sa), this->child_sa->get_unique_id(this->child_sa), ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c index 626796383..2217295b6 100644 --- a/src/libcharon/sa/ikev2/tasks/child_delete.c +++ b/src/libcharon/sa/ikev2/tasks/child_delete.c @@ -196,7 +196,6 @@ static void install_outbound(private_child_delete_t *this, /* FIXME: delete the new child_sa? */ return; } - child_sa->set_state(child_sa, CHILD_INSTALLED); my_ts = linked_list_create_from_enumerator( child_sa->create_ts_enumerator(child_sa, TRUE)); diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c index 761c860e7..619ec4171 100644 --- a/src/libcharon/sa/ikev2/tasks/child_rekey.c +++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c @@ -283,7 +283,8 @@ METHOD(task_t, build_r, status_t, /** * Handle a rekey collision */ -static child_sa_t *handle_collision(private_child_rekey_t *this) +static child_sa_t *handle_collision(private_child_rekey_t *this, + child_sa_t **to_install) { child_sa_t *to_delete; @@ -303,6 +304,7 @@ static child_sa_t *handle_collision(private_child_rekey_t *this) child_sa_t *child_sa; DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child"); + *to_install = this->child_create->get_child(this->child_create); to_delete = this->child_sa; /* don't touch child other created, it has already been deleted */ if (!this->other_child_destroyed) @@ -353,7 +355,7 @@ METHOD(task_t, process_i, status_t, { protocol_id_t protocol; uint32_t spi; - child_sa_t *to_delete; + child_sa_t *to_delete, *to_install = NULL; if (message->get_notify(message, NO_ADDITIONAL_SAS)) { @@ -415,19 +417,48 @@ METHOD(task_t, process_i, status_t, /* check for rekey collisions */ if (this->collision) { - to_delete = handle_collision(this); + to_delete = handle_collision(this, &to_install); } else { + to_install = this->child_create->get_child(this->child_create); to_delete = this->child_sa; } + if (to_install) + { + if (to_install->install_outbound(to_install) != SUCCESS) + { + DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel"); + charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED, + to_install); + /* FIXME: delete the child_sa? fail the task? */ + } + else + { + linked_list_t *my_ts, *other_ts; + my_ts = linked_list_create_from_enumerator( + to_install->create_ts_enumerator(to_install, TRUE)); + other_ts = linked_list_create_from_enumerator( + to_install->create_ts_enumerator(to_install, FALSE)); + + DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R === %#R", + to_install->get_name(to_install), + to_install->get_unique_id(to_install), + ntohl(to_install->get_spi(to_install, TRUE)), + ntohl(to_install->get_spi(to_install, FALSE)), + my_ts, other_ts); + + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); + } + } if (to_delete != this->child_create->get_child(this->child_create)) { /* invoke rekey hook if rekeying successful */ charon->bus->child_rekey(charon->bus, this->child_sa, this->child_create->get_child(this->child_create)); } - if (to_delete == NULL) { return SUCCESS; diff --git a/src/libcharon/tests/suites/test_child_rekey.c b/src/libcharon/tests/suites/test_child_rekey.c index 76b23f589..ac169723f 100644 --- a/src/libcharon/tests/suites/test_child_rekey.c +++ b/src/libcharon/tests/suites/test_child_rekey.c @@ -483,6 +483,9 @@ START_TEST(test_collision) CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, 1, 2, 3, 5, 6); } else { @@ -493,10 +496,10 @@ START_TEST(test_collision) CHILD_OUTBOUND_INSTALLED); assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(a, 1, 2, 3, 6); } - assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); - assert_ipsec_sas_installed(a, 1, 2, 3, 5, 6); /* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */ if (data[_i].spi_del_b == 2) { @@ -507,6 +510,9 @@ START_TEST(test_collision) CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6); } else { @@ -517,10 +523,10 @@ START_TEST(test_collision) CHILD_OUTBOUND_INSTALLED); assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5); } - assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); - assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6); /* we don't expect this hook to get called anymore */ assert_hook_not_called(child_rekey); @@ -528,27 +534,41 @@ START_TEST(test_collision) assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); + data[_i].spi_del_b == 2 ? CHILD_OUTBOUND_INSTALLED + : CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING, CHILD_OUTBOUND_NONE); assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(b, 3); - assert_ipsec_sas_installed(b, 2, 4, 5, 6, - data[_i].spi_del_b == 2 ? 1 : 3); + if (data[_i].spi_del_b == 2) + { + assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6); + } + else + { + assert_ipsec_sas_installed(b, 2, 3, 4, 5); + } assert_scheduler(); /* <-- INFORMATIONAL { D } */ assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); + data[_i].spi_del_a == 1 ? CHILD_OUTBOUND_INSTALLED + : CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, CHILD_OUTBOUND_NONE); assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); assert_child_sa_count(a, 3); - assert_ipsec_sas_installed(a, 1, 3, 5, 6, - data[_i].spi_del_a == 1 ? 2 : 4); + if (data[_i].spi_del_a == 1) + { + assert_ipsec_sas_installed(a, 1, 2, 3, 5, 6); + } + else + { + assert_ipsec_sas_installed(a, 1, 3, 4, 6); + } assert_scheduler(); /* <-- INFORMATIONAL { D } */ assert_jobs_scheduled(1); @@ -682,6 +702,9 @@ START_TEST(test_collision_delayed_response) CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6); } else { @@ -692,10 +715,10 @@ START_TEST(test_collision_delayed_response) CHILD_OUTBOUND_INSTALLED); assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(b, 1, 2, 4, 5); } - assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); - assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6); /* <-- INFORMATIONAL { D } */ assert_hook_not_called(child_rekey); @@ -748,21 +771,23 @@ START_TEST(test_collision_delayed_response) assert_hook_rekey(child_rekey, 1, data[_i].spi_a); exchange_test_helper->process_message(exchange_test_helper, a, msg); assert_hook(); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); + assert_ipsec_sas_installed(a, 1, 2, 3, 5, 6); } else { assert_hook_not_called(child_rekey); exchange_test_helper->process_message(exchange_test_helper, a, msg); assert_hook(); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_REGISTERED); + assert_ipsec_sas_installed(a, 1, 3, 4, 6); } - assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, CHILD_OUTBOUND_NONE); assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); - assert_ipsec_sas_installed(a, 1, 3, 5, 6, - data[_i].spi_del_a == 1 ? 2 : 4); assert_child_sa_count(a, 3); /* we don't expect this hook to get called anymore */ @@ -1173,6 +1198,8 @@ START_TEST(test_collision_ke_invalid) CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); } else { @@ -1181,9 +1208,9 @@ START_TEST(test_collision_ke_invalid) CHILD_OUTBOUND_INSTALLED); assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, + CHILD_OUTBOUND_REGISTERED); } - assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); /* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */ if (data[_i].spi_del_b == 2) { @@ -1194,6 +1221,8 @@ START_TEST(test_collision_ke_invalid) CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_INSTALLED); } else { @@ -1202,9 +1231,10 @@ START_TEST(test_collision_ke_invalid) CHILD_OUTBOUND_INSTALLED); assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED); + assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, + CHILD_OUTBOUND_REGISTERED); } - assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); + /* we don't expect this hook to get called anymore */ assert_hook_not_called(child_rekey); @@ -1212,7 +1242,8 @@ START_TEST(test_collision_ke_invalid) assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, b, NULL); assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); + data[_i].spi_del_b == 2 ? CHILD_OUTBOUND_INSTALLED + : CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING, CHILD_OUTBOUND_NONE); assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED, @@ -1223,7 +1254,8 @@ START_TEST(test_collision_ke_invalid) assert_jobs_scheduled(1); exchange_test_helper->process_message(exchange_test_helper, a, NULL); assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING, - CHILD_OUTBOUND_INSTALLED); + data[_i].spi_del_a == 1 ? CHILD_OUTBOUND_INSTALLED + : CHILD_OUTBOUND_REGISTERED); assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING, CHILD_OUTBOUND_NONE); assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED, From dbaeaaf6057fcdff397765a317b6eadf751acac1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Aug 2017 13:59:40 +0200 Subject: [PATCH 15/16] charon-tkm: Remove unused get_other_esa_id() method --- src/charon-tkm/src/tkm/tkm_kernel_sad.c | 55 ------------------------- src/charon-tkm/src/tkm/tkm_kernel_sad.h | 10 ----- src/charon-tkm/tests/kernel_sad_tests.c | 36 ---------------- 3 files changed, 101 deletions(-) diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.c b/src/charon-tkm/src/tkm/tkm_kernel_sad.c index c888f2561..92ea25e43 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_sad.c +++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.c @@ -131,26 +131,6 @@ CALLBACK(sad_entry_match_dst, bool, entry->proto == *proto; } -CALLBACK(sad_entry_match_esa_id, bool, - sad_entry_t * const entry, va_list args) -{ - const esa_id_type *esa_id; - - VA_ARGS_VGET(args, esa_id); - return entry->esa_id == *esa_id; -} - -CALLBACK(sad_entry_match_other_esa, bool, - sad_entry_t * const entry, va_list args) -{ - const esa_id_type *esa_id; - const uint32_t *reqid; - - VA_ARGS_VGET(args, esa_id, reqid); - return entry->reqid == *reqid && - entry->esa_id != *esa_id; -} - CALLBACK(sad_entry_equal, bool, sad_entry_t * const left, va_list args) { @@ -237,40 +217,6 @@ METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type, return id; } -METHOD(tkm_kernel_sad_t, get_other_esa_id, esa_id_type, - private_tkm_kernel_sad_t * const this, const esa_id_type esa_id) -{ - esa_id_type id = 0; - sad_entry_t *entry = NULL; - uint32_t reqid; - bool res; - - this->mutex->lock(this->mutex); - res = this->data->find_first(this->data, sad_entry_match_esa_id, - (void**)&entry, &esa_id); - if (res && entry) - { - reqid = entry->reqid; - } - else - { - DBG3(DBG_KNL, "no SAD entry found for ESA id %llu", esa_id); - this->mutex->unlock(this->mutex); - return id; - } - - res = this->data->find_first(this->data, sad_entry_match_other_esa, - (void**)&entry, &esa_id, &reqid); - if (res && entry) - { - id = entry->esa_id; - DBG3(DBG_KNL, "returning ESA id %llu of other SAD entry with reqid %u", - id, reqid); - } - this->mutex->unlock(this->mutex); - return id; -} - METHOD(tkm_kernel_sad_t, get_dst_host, host_t *, private_tkm_kernel_sad_t * const this, const uint32_t reqid, const uint32_t spi, const uint8_t proto) @@ -350,7 +296,6 @@ tkm_kernel_sad_t *tkm_kernel_sad_create() .public = { .insert = _insert, .get_esa_id = _get_esa_id, - .get_other_esa_id = _get_other_esa_id, .get_dst_host = _get_dst_host, .remove = __remove, .destroy = _destroy, diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.h b/src/charon-tkm/src/tkm/tkm_kernel_sad.h index 63d02b7e4..bcb3b4344 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_sad.h +++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.h @@ -63,16 +63,6 @@ struct tkm_kernel_sad_t { const host_t * const src, const host_t * const dst, const uint32_t spi, const uint8_t proto); - /** - * Get ESA id for entry associated with same security policy as the - * specified ESA. - * - * @param esa_id id of ESA identifying the security policy - * @return ESA id of entry if found, 0 otherwise - */ - esa_id_type (*get_other_esa_id)(tkm_kernel_sad_t * const this, - const esa_id_type esa_id); - /** * Get destination host for entry with given parameters. * diff --git a/src/charon-tkm/tests/kernel_sad_tests.c b/src/charon-tkm/tests/kernel_sad_tests.c index 2a033d237..5dbe0aec9 100644 --- a/src/charon-tkm/tests/kernel_sad_tests.c +++ b/src/charon-tkm/tests/kernel_sad_tests.c @@ -81,37 +81,6 @@ START_TEST(test_get_esa_id_nonexistent) } END_TEST -START_TEST(test_get_other_esa_id) -{ - host_t *addr = host_create_from_string("127.0.0.1", 1024); - tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); - fail_unless(sad->insert(sad, 23, 54, addr, addr, 27, 42, 50), - "Error inserting SAD entry"); - fail_unless(sad->insert(sad, 24, 54, addr, addr, 27, 42, 50), - "Error inserting SAD entry"); - fail_unless(sad->get_other_esa_id(sad, 23) == 24, - "Error getting other esa id"); - sad->destroy(sad); - addr->destroy(addr); -} -END_TEST - -START_TEST(test_get_other_esa_id_nonexistent) -{ - host_t *addr = host_create_from_string("127.0.0.1", 1024); - tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); - fail_unless(sad->get_other_esa_id(sad, 1) == 0, - "Got other esa id for nonexistent SAD entry"); - fail_unless(sad->insert(sad, 23, 54, addr, addr, 27, 42, 50), - "Error inserting SAD entry"); - fail_unless(sad->get_other_esa_id(sad, 23) == 0, - "Got own esa id"); - - sad->destroy(sad); - addr->destroy(addr); -} -END_TEST - START_TEST(test_get_dst_host) { host_t *addr = host_create_from_string("127.0.0.1", 1024); @@ -182,11 +151,6 @@ Suite *make_kernel_sad_tests() tcase_add_test(tc, test_get_esa_id_nonexistent); suite_add_tcase(s, tc); - tc = tcase_create("get_other_esa_id"); - tcase_add_test(tc, test_get_other_esa_id); - tcase_add_test(tc, test_get_other_esa_id_nonexistent); - suite_add_tcase(s, tc); - tc = tcase_create("get_dst_host"); tcase_add_test(tc, test_get_dst_host); tcase_add_test(tc, test_get_dst_host_nonexistent); From 772957778ccf1705e2d0bcf62203a1abb041b6ff Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 4 Aug 2017 14:02:42 +0200 Subject: [PATCH 16/16] charon-tkm: Call esa_reset() when the inbound SA is deleted After a rekeying the outbound SA and policy is deleted immediately, however, the inbound SA is not removed until a few seconds later, so delayed packets can still be processed. This adds a flag to get_esa_id() that specifies the location of the given SPI. --- src/charon-tkm/src/tkm/tkm_kernel_ipsec.c | 4 +-- src/charon-tkm/src/tkm/tkm_kernel_sad.c | 29 ++++++++++++------- src/charon-tkm/src/tkm/tkm_kernel_sad.h | 5 ++-- src/charon-tkm/tests/kernel_sad_tests.c | 18 ++++++++++-- .../tests/tkm/xfrmproxy-expire/evaltest.dat | 12 +++++--- .../hosts/moon/etc/strongswan.conf | 2 ++ .../hosts/moon/etc/tkm/tkm.conf | 2 +- .../tests/tkm/xfrmproxy-rekey/evaltest.dat | 6 +++- .../hosts/moon/etc/strongswan.conf | 2 ++ .../xfrmproxy-rekey/hosts/sun/etc/ipsec.conf | 2 +- 10 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c index 8ccae4cc2..5decde92b 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c +++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c @@ -216,7 +216,7 @@ METHOD(kernel_ipsec_t, del_sa, status_t, esa_id_type esa_id; esa_id = tkm->sad->get_esa_id(tkm->sad, id->src, id->dst, - id->spi, id->proto); + id->spi, id->proto, TRUE); if (esa_id) { DBG1(DBG_KNL, "deleting child SA (esa: %llu, spi: %x)", esa_id, @@ -272,7 +272,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, return FAILED; } esa_id = tkm->sad->get_esa_id(tkm->sad, data->src, data->dst, - spi, proto); + spi, proto, FALSE); if (!esa_id) { DBG1(DBG_KNL, "unable to find esa ID for policy (spi: %x)", diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.c b/src/charon-tkm/src/tkm/tkm_kernel_sad.c index 92ea25e43..acc3ff10a 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_sad.c +++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.c @@ -107,16 +107,23 @@ CALLBACK(sad_entry_match, bool, const host_t *src, *dst; const uint32_t *spi; const uint8_t *proto; + const bool *local; - VA_ARGS_VGET(args, src, dst, spi, proto); + VA_ARGS_VGET(args, src, dst, spi, proto, local); - if (entry->src == NULL || entry->dst == NULL) + if (entry->src == NULL || entry->dst == NULL || entry->proto != *proto) { return FALSE; } - return src->ip_equals(entry->src, (host_t *)src) && - dst->ip_equals(entry->dst, (host_t *)dst) && - entry->spi_rem == *spi && entry->proto == *proto; + if (*local) + { + return entry->src->ip_equals(entry->src, (host_t *)dst) && + entry->dst->ip_equals(entry->dst, (host_t *)src) && + entry->spi_loc == *spi; + } + return entry->src->ip_equals(entry->src, (host_t *)src) && + entry->dst->ip_equals(entry->dst, (host_t *)dst) && + entry->spi_rem == *spi; } CALLBACK(sad_entry_match_dst, bool, @@ -193,7 +200,8 @@ METHOD(tkm_kernel_sad_t, insert, bool, METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type, private_tkm_kernel_sad_t * const this, const host_t * const src, - const host_t * const dst, const uint32_t spi, const uint8_t proto) + const host_t * const dst, const uint32_t spi, const uint8_t proto, + const bool local) { esa_id_type id = 0; sad_entry_t *entry = NULL; @@ -201,17 +209,18 @@ METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type, this->mutex->lock(this->mutex); const bool res = this->data->find_first(this->data, sad_entry_match, (void**)&entry, src, dst, &spi, - &proto); + &proto, &local); if (res && entry) { id = entry->esa_id; DBG3(DBG_KNL, "returning ESA id %llu of SAD entry (src: %H, dst: %H, " - "spi: %x, proto: %u)", id, src, dst, ntohl(spi), proto); + "%sbound spi: %x, proto: %u)", id, src, dst, local ? "in" : "out", + ntohl(spi), proto); } else { - DBG3(DBG_KNL, "no SAD entry found for src %H, dst %H, spi %x, proto %u", - src, dst, ntohl(spi), proto); + DBG3(DBG_KNL, "no SAD entry found for src %H, dst %H, %sbound spi %x, " + "proto %u", src, dst, local ? "in" : "out", ntohl(spi), proto); } this->mutex->unlock(this->mutex); return id; diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.h b/src/charon-tkm/src/tkm/tkm_kernel_sad.h index bcb3b4344..3d9f5f3f8 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_sad.h +++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.h @@ -55,13 +55,14 @@ struct tkm_kernel_sad_t { * * @param src source address of CHILD SA * @param dst destination address of CHILD SA - * @param spi Remote SPI of CHILD SA + * @param spi SPI of CHILD SA * @param proto protocol of CHILD SA (ESP/AH) + * @param local whether the SPI is local or remote * @return ESA id of entry if found, 0 otherwise */ esa_id_type (*get_esa_id)(tkm_kernel_sad_t * const this, const host_t * const src, const host_t * const dst, - const uint32_t spi, const uint8_t proto); + const uint32_t spi, const uint8_t proto, const bool local); /** * Get destination host for entry with given parameters. diff --git a/src/charon-tkm/tests/kernel_sad_tests.c b/src/charon-tkm/tests/kernel_sad_tests.c index 5dbe0aec9..39d8a790a 100644 --- a/src/charon-tkm/tests/kernel_sad_tests.c +++ b/src/charon-tkm/tests/kernel_sad_tests.c @@ -63,7 +63,20 @@ START_TEST(test_get_esa_id) tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); fail_unless(sad->insert(sad, 23, 54, addr, addr, 27, 42, 50), "Error inserting SAD entry"); - fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 23, + fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50, FALSE) == 23, + "Error getting esa id"); + sad->destroy(sad); + addr->destroy(addr); +} +END_TEST + +START_TEST(test_get_esa_id_local) +{ + host_t *addr = host_create_from_string("127.0.0.1", 1024); + tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); + fail_unless(sad->insert(sad, 23, 54, addr, addr, 27, 42, 50), + "Error inserting SAD entry"); + fail_unless(sad->get_esa_id(sad, addr, addr, 27, 50, TRUE) == 23, "Error getting esa id"); sad->destroy(sad); addr->destroy(addr); @@ -74,7 +87,7 @@ START_TEST(test_get_esa_id_nonexistent) { host_t *addr = host_create_from_string("127.0.0.1", 1024); tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); - fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 0, + fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50, FALSE) == 0, "Got esa id for nonexistent SAD entry"); sad->destroy(sad); addr->destroy(addr); @@ -148,6 +161,7 @@ Suite *make_kernel_sad_tests() tc = tcase_create("get_esa_id"); tcase_add_test(tc, test_get_esa_id); + tcase_add_test(tc, test_get_esa_id_local); tcase_add_test(tc, test_get_esa_id_nonexistent); suite_add_tcase(s, tc); diff --git a/testing/tests/tkm/xfrmproxy-expire/evaltest.dat b/testing/tests/tkm/xfrmproxy-expire/evaltest.dat index 05bf42057..a3f45871c 100644 --- a/testing/tests/tkm/xfrmproxy-expire/evaltest.dat +++ b/testing/tests/tkm/xfrmproxy-expire/evaltest.dat @@ -2,20 +2,24 @@ moon::ipsec stroke status 2> /dev/null::conn1.*ESTABLISHED.*moon.strongswan.org. sun::ipsec status 2> /dev/null::host-host.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES moon::ipsec stroke status 2> /dev/null::conn1.*INSTALLED, TRANSPORT::YES sun::ipsec status 2> /dev/null::host-host.*INSTALLED, TRANSPORT::YES -moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_.eq=1::YES -sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES -sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES +moon::sleep 2::wait for rekeying::NO moon::cat /var/log/daemon.log::ees: acquire received for reqid 1::YES moon::cat /var/log/daemon.log::ees: expire received for reqid 1, spi.*, dst 192.168.0.2::YES moon::cat /var/log/daemon.log::creating rekey job for CHILD_SA ESP/0x.*/192.168.0.2::YES +moon::cat /var/log/daemon.log::deleting child SA (esa: 1, spi:.*)::NO +moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_.eq=1::YES +sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES +sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES +moon::sleep 2::wait until inbound SA is deleted::NO moon::cat /var/log/daemon.log::deleting child SA (esa: 1, spi:.*)::YES +moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_.eq=1::YES moon::cat /tmp/tkm.log::RSA private key '/etc/tkm/moonKey.der' loaded::YES moon::cat /tmp/tkm.log::Adding policy \[ 1, 192.168.0.1 <-> 192.168.0.2 \]::YES moon::cat /tmp/tkm.log::Checked CA certificate of CC context 1::YES moon::cat /tmp/tkm.log::Authentication of ISA context 1 successful::YES moon::cat /tmp/tkm.log::Creating first new ESA context with ID 1 (Isa 1, Sp 1, Ea 1, Initiator TRUE, spi_loc.*, spi_rem.*)::YES moon::cat /tmp/tkm.log::Creating ESA context with ID 2 (Isa 1, Sp 1, Ea 1, Dh_Id 1, Nc_Loc_Id 1, Initiator TRUE, spi_loc.*, spi_rem.*)::YES -moon::cat /tmp/tkm.log | grep 'Adding ESA \[ 1, 192.168.0.1 <-> 192.168.0.2, SPI_in.*, SPI_out.*, soft 2, hard 60 \]' | wc -l::2::YES +moon::cat /tmp/tkm.log | grep 'Adding ESA \[ 1, 192.168.0.1 <-> 192.168.0.2, SPI_in.*, SPI_out.*, soft 4, hard 60 \]' | wc -l::2::YES moon::cat /tmp/tkm.log::Resetting ESA context 1::YES moon::cat /tmp/tkm.log::Deleting ESA \[ 1, 192.168.0.1 <=> 192.168.0.2, SPI_in.*, SPI_out.* \]::YES moon::cat /tmp/xfrm_proxy.log::Initiating ESA acquire for reqid 1::YES diff --git a/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/strongswan.conf b/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/strongswan.conf index cc9d6e072..5b79af9f4 100644 --- a/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/strongswan.conf +++ b/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/strongswan.conf @@ -1,6 +1,8 @@ # /etc/strongswan.conf - strongSwan configuration file charon-tkm { + # remove rekeyed inbound SA a bit quicker for the test scenario + delete_rekeyed_delay = 2 dh_mapping { 15 = 1 16 = 2 diff --git a/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/tkm/tkm.conf b/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/tkm/tkm.conf index 23e958ab0..62b103a80 100644 --- a/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/tkm/tkm.conf +++ b/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/tkm/tkm.conf @@ -14,7 +14,7 @@ 192.168.0.2 - 2 + 4 60 diff --git a/testing/tests/tkm/xfrmproxy-rekey/evaltest.dat b/testing/tests/tkm/xfrmproxy-rekey/evaltest.dat index 328b4854b..15bdf3b39 100644 --- a/testing/tests/tkm/xfrmproxy-rekey/evaltest.dat +++ b/testing/tests/tkm/xfrmproxy-rekey/evaltest.dat @@ -2,11 +2,15 @@ moon::ipsec stroke status 2> /dev/null::conn1.*ESTABLISHED.*moon.strongswan.org. sun::ipsec status 2> /dev/null::host-host.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES moon::ipsec stroke status 2> /dev/null::conn1.*INSTALLED, TRANSPORT::YES sun::ipsec status 2> /dev/null::host-host.*INSTALLED, TRANSPORT::YES +moon::sleep 2::wait for rekeying::NO +sun::cat /var/log/daemon.log::creating rekey job for CHILD_SA ESP/0x.*/192.168.0.2::YES moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_.eq=1::YES sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES -sun::cat /var/log/daemon.log::creating rekey job for CHILD_SA ESP/0x.*/192.168.0.2::YES +moon::cat /var/log/daemon.log::deleting child SA (esa: 1, spi:.*)::NO +moon::sleep 2::wait until inbound SA is deleted::NO moon::cat /var/log/daemon.log::deleting child SA (esa: 1, spi:.*)::YES +moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_.eq=1::YES moon::cat /tmp/tkm.log::RSA private key '/etc/tkm/moonKey.der' loaded::YES moon::cat /tmp/tkm.log::Adding policy \[ 1, 192.168.0.1 <-> 192.168.0.2 \]::YES moon::cat /tmp/tkm.log::Checked CA certificate of CC context 1::YES diff --git a/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf b/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf index cc9d6e072..5b79af9f4 100644 --- a/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf +++ b/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf @@ -1,6 +1,8 @@ # /etc/strongswan.conf - strongSwan configuration file charon-tkm { + # remove rekeyed inbound SA a bit quicker for the test scenario + delete_rekeyed_delay = 2 dh_mapping { 15 = 1 16 = 2 diff --git a/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/ipsec.conf b/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/ipsec.conf index 99ffb301e..9dc641240 100644 --- a/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/ipsec.conf +++ b/testing/tests/tkm/xfrmproxy-rekey/hosts/sun/etc/ipsec.conf @@ -5,7 +5,7 @@ config setup conn %default ikelifetime=60m keylife=10s - rekeymargin=8s + rekeymargin=6s rekeyfuzz=0% keyingtries=1 keyexchange=ikev2