child-sa: Add methods that allow partial installation of CHILD_SA

Using install() for the inbound SA and register_outbound() for the
outbound SA followed by install_policies(), will delay the installation of
the outbound SA as well as the installation of the outbound policies
in the kernel until install_outbound() is called later.
This commit is contained in:
Tobias Brunner
2017-05-23 18:46:03 +02:00
parent 83186d3cf7
commit 8a3a389e3d
2 changed files with 144 additions and 5 deletions
+117 -5
View File
@@ -92,6 +92,26 @@ struct private_child_sa_t {
*/ */
array_t *other_ts; array_t *other_ts;
/**
* Outbound encryption key cached during a rekeying
*/
chunk_t encr_r;
/**
* Outbound integrity key cached during a rekeying
*/
chunk_t integ_r;
/**
* Whether the outbound SA has only been registered yet during a rekeying
*/
bool outbound_registered;
/**
* Whether the peer supports TFCv3
*/
bool tfcv3;
/** /**
* Protocol used to protect this SA, ESP|AH * Protocol used to protect this SA, ESP|AH
*/ */
@@ -692,9 +712,12 @@ METHOD(child_sa_t, alloc_cpi, uint16_t,
return 0; return 0;
} }
METHOD(child_sa_t, install, status_t, /**
private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi, * Install the given SA in the kernel
uint16_t cpi, bool initiator, bool inbound, bool tfcv3) */
static status_t install_internal(private_child_sa_t *this, chunk_t encr,
chunk_t integ, uint32_t spi, uint16_t cpi, bool initiator, bool inbound,
bool tfcv3)
{ {
uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size; uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
uint16_t esn = NO_EXT_SEQ_NUMBERS; uint16_t esn = NO_EXT_SEQ_NUMBERS;
@@ -834,6 +857,14 @@ METHOD(child_sa_t, install, status_t,
return status; return status;
} }
METHOD(child_sa_t, install, status_t,
private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
uint16_t cpi, bool initiator, bool inbound, bool tfcv3)
{
return install_internal(this, encr, integ, spi, cpi, initiator, inbound,
tfcv3);
}
/** /**
* Check kernel interface if policy updates are required * Check kernel interface if policy updates are required
*/ */
@@ -1167,7 +1198,7 @@ METHOD(child_sa_t, install_policies, status_t,
/* install outbound drop policy to avoid packets leaving unencrypted /* install outbound drop policy to avoid packets leaving unencrypted
* when updating policies */ * when updating policies */
if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 && if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 &&
require_policy_update()) require_policy_update() && !this->outbound_registered)
{ {
status |= install_policies_outbound(this, this->my_addr, status |= install_policies_outbound(this, this->my_addr,
this->other_addr, my_ts, other_ts, this->other_addr, my_ts, other_ts,
@@ -1175,11 +1206,19 @@ METHOD(child_sa_t, install_policies, status_t,
POLICY_PRIORITY_FALLBACK, 0); POLICY_PRIORITY_FALLBACK, 0);
} }
status |= install_policies_internal(this, this->my_addr, status |= install_policies_inbound(this, this->my_addr,
this->other_addr, my_ts, other_ts, this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_IPSEC, &my_sa, &other_sa, POLICY_IPSEC,
priority, manual_prio); priority, manual_prio);
if (!this->outbound_registered)
{
status |= install_policies_outbound(this, this->my_addr,
this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_IPSEC,
priority, manual_prio);
}
if (status != SUCCESS) if (status != SUCCESS)
{ {
break; break;
@@ -1195,6 +1234,75 @@ METHOD(child_sa_t, install_policies, status_t,
return status; return status;
} }
METHOD(child_sa_t, register_outbound, void,
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);
this->other_spi = spi;
this->other_cpi = cpi;
this->encr_r = chunk_clone(encr);
this->integ_r = chunk_clone(integ);
this->tfcv3 = tfcv3;
this->outbound_registered = TRUE;
}
METHOD(child_sa_t, install_outbound, status_t,
private_child_sa_t *this)
{
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
status_t status;
this->outbound_registered = FALSE;
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 (status != SUCCESS)
{
return status;
}
if (!this->config->has_option(this->config, OPT_NO_POLICIES))
{
ipsec_sa_cfg_t my_sa, other_sa;
uint32_t manual_prio;
prepare_sa_cfg(this, &my_sa, &other_sa);
manual_prio = this->config->get_manual_prio(this->config);
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
{
/* install outbound drop policy to avoid packets leaving unencrypted
* when updating policies */
if (manual_prio == 0 && require_policy_update())
{
status |= install_policies_outbound(this, this->my_addr,
this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_DROP,
POLICY_PRIORITY_FALLBACK, 0);
}
status |= install_policies_outbound(this, this->my_addr,
this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_IPSEC,
POLICY_PRIORITY_DEFAULT, manual_prio);
if (status != SUCCESS)
{
break;
}
}
enumerator->destroy(enumerator);
}
return status;
}
/** /**
* Callback to reinstall a virtual IP * Callback to reinstall a virtual IP
*/ */
@@ -1451,6 +1559,8 @@ METHOD(child_sa_t, destroy, void,
this->other_addr->destroy(this->other_addr); this->other_addr->destroy(this->other_addr);
DESTROY_IF(this->proposal); DESTROY_IF(this->proposal);
this->config->destroy(this->config); this->config->destroy(this->config);
chunk_clear(&this->encr_r);
chunk_clear(&this->integ_r);
free(this); free(this);
} }
@@ -1530,6 +1640,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.alloc_spi = _alloc_spi, .alloc_spi = _alloc_spi,
.alloc_cpi = _alloc_cpi, .alloc_cpi = _alloc_cpi,
.install = _install, .install = _install,
.register_outbound = _register_outbound,
.install_outbound = _install_outbound,
.update = _update, .update = _update,
.set_policies = _set_policies, .set_policies = _set_policies,
.install_policies = _install_policies, .install_policies = _install_policies,
+27
View File
@@ -367,6 +367,29 @@ struct child_sa_t {
uint32_t spi, uint16_t cpi, uint32_t spi, uint16_t cpi,
bool initiator, bool inbound, bool tfcv3); bool initiator, bool inbound, bool tfcv3);
/**
* Register data for the installation of an outbound SA as responder during
* a rekeying.
*
* The SA is not 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
*/
void (*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.
*
* @return SUCCESS or FAILED
*/
status_t (*install_outbound)(child_sa_t *this);
/** /**
* Configure the policies using some traffic selectors. * Configure the policies using some traffic selectors.
* *
@@ -387,6 +410,10 @@ struct child_sa_t {
/** /**
* Install the configured policies. * Install the configured policies.
* *
* If register_outbound() was called previously this only installs the
* inbound and forward policies, the outbound policies are installed when
* install_outbound() is called.
*
* @return SUCCESS or FAILED * @return SUCCESS or FAILED
*/ */
status_t (*install_policies)(child_sa_t *this); status_t (*install_policies)(child_sa_t *this);