this->other_spi, this->other_cpi, this->initiator,
FALSE, this->tfcv3);
}
- else
+ else if (!this->rekey)
{
status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->my_spi, this->my_cpi, this->initiator,
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);
+ this->child_sa->register_outbound(this->child_sa, encr_r, integ_r,
+ this->other_spi, this->other_cpi, this->tfcv3);
+ status_o = SUCCESS;
+ }
}
if (status_i != SUCCESS || status_o != SUCCESS)
charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
this->dh, nonce_i, nonce_r);
- /* add to IKE_SA, and remove from task */
- this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+ if (this->rekey && !this->initiator)
+ {
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED_INBOUND);
+ }
+ else
+ {
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+ }
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
this->established = TRUE;
other_ts = linked_list_create_from_enumerator(
this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
- DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
+ DBG0(DBG_IKE, "%sCHILD_SA %s{%d} established "
"with SPIs %.8x_i %.8x_o and TS %#R === %#R",
+ this->rekey && !this->initiator ? "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)),
- ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
+ ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
+ my_ts, other_ts);
my_ts->destroy(my_ts);
other_ts->destroy(other_ts);
-
return SUCCESS;
}
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
}
-
DESTROY_IF(this->config);
DESTROY_IF(this->nonceg);
free(this);
}
/**
+ * Install the outbound CHILD_SA with the given SPI
+ */
+static void install_outbound(private_child_delete_t *this,
+ protocol_id_t protocol, uint32_t spi)
+{
+ child_sa_t *child_sa;
+ linked_list_t *my_ts, *other_ts;
+ status_t status;
+
+ child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
+ spi, FALSE);
+ if (!child_sa)
+ {
+ DBG1(DBG_IKE, "CHILD_SA not found after rekeying");
+ return;
+ }
+ if (this->initiator && is_redundant(this, child_sa))
+ { /* if we won the rekey collision we don't want to install the
+ * redundant SA created by the peer */
+ return;
+ }
+
+ status = child_sa->install_outbound(child_sa);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
+ charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
+ child_sa);
+ /* 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));
+ other_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, FALSE));
+
+ DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
+ "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
+ child_sa->get_name(child_sa),
+ child_sa->get_unique_id(child_sa),
+ ntohl(child_sa->get_spi(child_sa, TRUE)),
+ ntohl(child_sa->get_spi(child_sa, FALSE)),
+ my_ts, other_ts);
+
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
+}
+
+/**
* read in payloads and find the children to delete
*/
static void process_payloads(private_child_delete_t *this, message_t *message)
/* fall through */
case CHILD_REKEYING:
/* we reply as usual, rekeying will fail */
+ case CHILD_INSTALLED_INBOUND:
case CHILD_INSTALLED:
if (!this->initiator)
{
child_sa_t *child_sa;
child_cfg_t *child_cfg;
protocol_id_t protocol;
- uint32_t spi, reqid;
+ uint32_t spi, reqid, rekey_spi;
action_t action;
status_t status = SUCCESS;
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
/* signal child down event if we weren't rekeying */
+ protocol = child_sa->get_protocol(child_sa);
if (!this->rekeyed)
{
charon->bus->child_updown(charon->bus, child_sa, FALSE);
}
+ else
+ {
+ rekey_spi = child_sa->get_rekey_spi(child_sa);
+ if (rekey_spi)
+ {
+ install_outbound(this, protocol, rekey_spi);
+ }
+ }
spi = child_sa->get_spi(child_sa, TRUE);
reqid = child_sa->get_reqid(child_sa);
- protocol = child_sa->get_protocol(child_sa);
child_cfg = child_sa->get_config(child_sa);
child_cfg->get_ref(child_cfg);
action = child_sa->get_close_action(child_sa);
assert_notify(IN, REKEY_SA);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
assert_child_sa_state(b, spi_b, CHILD_REKEYED);
- assert_child_sa_state(b, 4, CHILD_INSTALLED);
+ assert_child_sa_state(b, 4, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
assert_notify(IN, REKEY_SA);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
assert_child_sa_state(b, spi_b, CHILD_REKEYED);
- assert_child_sa_state(b, 6, CHILD_INSTALLED);
+ assert_child_sa_state(b, 6, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
assert_notify(IN, REKEY_SA);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
assert_child_sa_state(b, 2, CHILD_REKEYED);
- assert_child_sa_state(b, 4, CHILD_INSTALLED);
+ assert_child_sa_state(b, 4, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
assert_notify(IN, REKEY_SA);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
assert_child_sa_state(b, 2, CHILD_REKEYED);
- assert_child_sa_state(b, 4, CHILD_INSTALLED);
+ assert_child_sa_state(b, 4, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
/* INFORMATIONAL { D } --> */
assert_single_payload(IN, PLV2_DELETE);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
- assert_child_sa_state(b, 4, CHILD_INSTALLED);
+ assert_child_sa_state(b, 4, CHILD_INSTALLED_INBOUND);
assert_child_sa_state(a, 2, CHILD_DELETING);
/* <-- INFORMATIONAL { D } */
assert_single_payload(IN, PLV2_DELETE);
assert_hook_rekey(child_rekey, 2, 5);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
assert_child_sa_state(b, 2, CHILD_REKEYED);
- assert_child_sa_state(b, 5, CHILD_INSTALLED);
+ assert_child_sa_state(b, 5, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
exchange_test_helper->nonce_first_byte = data[_i].nonces[3];
assert_hook_rekey(child_rekey, 1, 6);
exchange_test_helper->process_message(exchange_test_helper, a, NULL);
assert_child_sa_state(a, 1, CHILD_REKEYED);
- assert_child_sa_state(a, 6, CHILD_INSTALLED);
+ assert_child_sa_state(a, 6, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
}
assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED);
- assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
+ assert_child_sa_state(a, data[_i].spi_a,
+ data[_i].spi_del_a == 1 ? CHILD_INSTALLED
+ : CHILD_INSTALLED_INBOUND);
/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
if (data[_i].spi_del_b == 2)
{
}
assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
- assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+ assert_child_sa_state(b, data[_i].spi_b,
+ data[_i].spi_del_b == 2 ? CHILD_INSTALLED
+ : CHILD_INSTALLED_INBOUND);
/* we don't expect this hook to get called anymore */
assert_hook_not_called(child_rekey);
assert_hook_rekey(child_rekey, 2, 5);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
assert_child_sa_state(b, 2, CHILD_REKEYED);
- assert_child_sa_state(b, 5, CHILD_INSTALLED);
+ assert_child_sa_state(b, 5, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
exchange_test_helper->nonce_first_byte = data[_i].nonces[3];
assert_hook_rekey(child_rekey, 1, 6);
exchange_test_helper->process_message(exchange_test_helper, a, NULL);
assert_child_sa_state(a, 1, CHILD_REKEYED);
- assert_child_sa_state(a, 6, CHILD_INSTALLED);
+ assert_child_sa_state(a, 6, CHILD_INSTALLED_INBOUND);
assert_hook();
/* delay the CREATE_CHILD_SA response from b to a */
}
assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
- assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+ assert_child_sa_state(b, data[_i].spi_b,
+ data[_i].spi_del_b == 2 ? CHILD_INSTALLED
+ : CHILD_INSTALLED_INBOUND);
/* <-- INFORMATIONAL { D } */
assert_hook_not_called(child_rekey);
/* INFORMATIONAL { D } --> */
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
- assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+ assert_child_sa_state(b, data[_i].spi_b,
+ data[_i].spi_del_b == 2 ? CHILD_INSTALLED
+ : CHILD_INSTALLED_INBOUND);
assert_child_sa_count(b, 2);
assert_hook();
assert_hook_rekey(child_rekey, 1, 5);
exchange_test_helper->process_message(exchange_test_helper, a, NULL);
assert_child_sa_state(a, 1, CHILD_REKEYED);
- assert_child_sa_state(a, 5, CHILD_INSTALLED);
+ assert_child_sa_state(a, 5, CHILD_INSTALLED_INBOUND);
assert_hook();
/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
assert_hook_rekey(child_rekey, 2, 4);
assert_hook_rekey(child_rekey, 1, 5);
exchange_test_helper->process_message(exchange_test_helper, a, NULL);
assert_child_sa_state(a, 1, CHILD_REKEYED);
- assert_child_sa_state(a, 5, CHILD_INSTALLED);
+ assert_child_sa_state(a, 5, CHILD_INSTALLED_INBOUND);
assert_hook();
/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
assert_hook_rekey(child_rekey, 2, 4);
assert_hook_rekey(child_rekey, 2, 9);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
assert_child_sa_state(b, 2, CHILD_REKEYED);
- assert_child_sa_state(b, 9, CHILD_INSTALLED);
+ assert_child_sa_state(b, 9, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
exchange_test_helper->nonce_first_byte = data[_i].nonces[3];
assert_hook_rekey(child_rekey, 1, 10);
exchange_test_helper->process_message(exchange_test_helper, a, NULL);
assert_child_sa_state(a, 1, CHILD_REKEYED);
- assert_child_sa_state(a,10, CHILD_INSTALLED);
+ assert_child_sa_state(a,10, CHILD_INSTALLED_INBOUND);
assert_hook();
/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
}
assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED);
- assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
+ assert_child_sa_state(a, data[_i].spi_a,
+ data[_i].spi_del_a == 1 ? CHILD_INSTALLED
+ : CHILD_INSTALLED_INBOUND);
/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
if (data[_i].spi_del_b == 2)
{
}
assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
- assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+ assert_child_sa_state(b, data[_i].spi_b,
+ data[_i].spi_del_b == 2 ? CHILD_INSTALLED
+ : CHILD_INSTALLED_INBOUND);
/* we don't expect this hook to get called anymore */
assert_hook_not_called(child_rekey);
assert_hook_rekey(child_rekey, 1, 9);
exchange_test_helper->process_message(exchange_test_helper, a, NULL);
assert_child_sa_state(a, 1, CHILD_REKEYED);
- assert_child_sa_state(a, 9, CHILD_INSTALLED);
+ assert_child_sa_state(a, 9, CHILD_INSTALLED_INBOUND);
assert_hook();
/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
assert_hook_rekey(child_rekey, 2, 8);