summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/tasks/child_rekey.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa/tasks/child_rekey.c')
-rw-r--r--src/libcharon/sa/tasks/child_rekey.c482
1 files changed, 0 insertions, 482 deletions
diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c
deleted file mode 100644
index 76d185590..000000000
--- a/src/libcharon/sa/tasks/child_rekey.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "child_rekey.h"
-
-#include <daemon.h>
-#include <encoding/payloads/notify_payload.h>
-#include <sa/tasks/child_create.h>
-#include <sa/tasks/child_delete.h>
-#include <processing/jobs/rekey_child_sa_job.h>
-#include <processing/jobs/rekey_ike_sa_job.h>
-
-
-typedef struct private_child_rekey_t private_child_rekey_t;
-
-/**
- * Private members of a child_rekey_t task.
- */
-struct private_child_rekey_t {
-
- /**
- * Public methods and task_t interface.
- */
- child_rekey_t public;
-
- /**
- * Assigned IKE_SA.
- */
- ike_sa_t *ike_sa;
-
- /**
- * Are we the initiator?
- */
- bool initiator;
-
- /**
- * Protocol of CHILD_SA to rekey
- */
- protocol_id_t protocol;
-
- /**
- * Inbound SPI of CHILD_SA to rekey
- */
- u_int32_t spi;
-
- /**
- * the CHILD_CREATE task which is reused to simplify rekeying
- */
- child_create_t *child_create;
-
- /**
- * the CHILD_DELETE task to delete rekeyed CHILD_SA
- */
- child_delete_t *child_delete;
-
- /**
- * CHILD_SA which gets rekeyed
- */
- child_sa_t *child_sa;
-
- /**
- * colliding task, may be delete or rekey
- */
- task_t *collision;
-
- /**
- * Indicate that peer destroyed the redundant child from collision.
- * This happens if a peer's delete notification for the redundant
- * child gets processed before the rekey job. If so, we must not
- * touch the child created in the collision since it points to
- * memory already freed.
- */
- bool other_child_destroyed;
-};
-
-/**
- * Implementation of task_t.build for initiator, after rekeying
- */
-static status_t build_i_delete(private_child_rekey_t *this, message_t *message)
-{
- /* update exchange type to INFORMATIONAL for the delete */
- message->set_exchange_type(message, INFORMATIONAL);
-
- return this->child_delete->task.build(&this->child_delete->task, message);
-}
-
-/**
- * Implementation of task_t.process for initiator, after rekeying
- */
-static status_t process_i_delete(private_child_rekey_t *this, message_t *message)
-{
- return this->child_delete->task.process(&this->child_delete->task, message);
-}
-
-/**
- * find a child using the REKEY_SA notify
- */
-static void find_child(private_child_rekey_t *this, message_t *message)
-{
- notify_payload_t *notify;
- protocol_id_t protocol;
- u_int32_t spi;
-
- notify = message->get_notify(message, REKEY_SA);
- if (notify)
- {
- protocol = notify->get_protocol_id(notify);
- spi = notify->get_spi(notify);
-
- if (protocol == PROTO_ESP || protocol == PROTO_AH)
- {
- this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
- spi, FALSE);
- }
- }
-}
-
-METHOD(task_t, build_i, status_t,
- private_child_rekey_t *this, message_t *message)
-{
- notify_payload_t *notify;
- u_int32_t reqid;
- child_cfg_t *config;
-
- this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
- this->spi, TRUE);
- if (!this->child_sa)
- { /* check if it is an outbound CHILD_SA */
- this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
- this->spi, FALSE);
- if (!this->child_sa)
- { /* CHILD_SA is gone, unable to rekey. As an empty CREATE_CHILD_SA
- * exchange is invalid, we fall back to an INFORMATIONAL exchange.*/
- message->set_exchange_type(message, INFORMATIONAL);
- return SUCCESS;
- }
- /* we work only with the inbound SPI */
- this->spi = this->child_sa->get_spi(this->child_sa, TRUE);
- }
- config = this->child_sa->get_config(this->child_sa);
-
- /* we just need the rekey notify ... */
- notify = notify_payload_create_from_protocol_and_type(this->protocol,
- REKEY_SA);
- notify->set_spi(notify, this->spi);
- message->add_payload(message, (payload_t*)notify);
-
- /* ... our CHILD_CREATE task does the hard work for us. */
- if (!this->child_create)
- {
- this->child_create = child_create_create(this->ike_sa, config, TRUE,
- NULL, NULL);
- }
- reqid = this->child_sa->get_reqid(this->child_sa);
- this->child_create->use_reqid(this->child_create, reqid);
- this->child_create->task.build(&this->child_create->task, message);
-
- this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
-
- return NEED_MORE;
-}
-
-METHOD(task_t, process_r, status_t,
- private_child_rekey_t *this, message_t *message)
-{
- /* let the CHILD_CREATE task process the message */
- this->child_create->task.process(&this->child_create->task, message);
-
- find_child(this, message);
-
- return NEED_MORE;
-}
-
-METHOD(task_t, build_r, status_t,
- private_child_rekey_t *this, message_t *message)
-{
- u_int32_t reqid;
-
- if (this->child_sa == NULL ||
- this->child_sa->get_state(this->child_sa) == CHILD_DELETING)
- {
- DBG1(DBG_IKE, "unable to rekey, CHILD_SA not found");
- message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
- return SUCCESS;
- }
-
- /* let the CHILD_CREATE task build the response */
- reqid = this->child_sa->get_reqid(this->child_sa);
- this->child_create->use_reqid(this->child_create, reqid);
- this->child_create->task.build(&this->child_create->task, message);
-
- if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
- {
- /* rekeying failed, reuse old child */
- this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
- return SUCCESS;
- }
-
- this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
-
- /* invoke rekey hook */
- charon->bus->child_rekey(charon->bus, this->child_sa,
- this->child_create->get_child(this->child_create));
- return SUCCESS;
-}
-
-/**
- * Handle a rekey collision
- */
-static child_sa_t *handle_collision(private_child_rekey_t *this)
-{
- child_sa_t *to_delete;
-
- if (this->collision->get_type(this->collision) == CHILD_REKEY)
- {
- chunk_t this_nonce, other_nonce;
- private_child_rekey_t *other = (private_child_rekey_t*)this->collision;
-
- this_nonce = this->child_create->get_lower_nonce(this->child_create);
- other_nonce = other->child_create->get_lower_nonce(other->child_create);
-
- /* if we have the lower nonce, delete rekeyed SA. If not, delete
- * the redundant. */
- if (memcmp(this_nonce.ptr, other_nonce.ptr,
- min(this_nonce.len, other_nonce.len)) > 0)
- {
- child_sa_t *child_sa;
-
- DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child");
- to_delete = this->child_sa;
- /* don't touch child other created, it has already been deleted */
- if (!this->other_child_destroyed)
- {
- /* disable close action for the redundand child */
- child_sa = other->child_create->get_child(other->child_create);
- if (child_sa)
- {
- child_sa->set_close_action(child_sa, ACTION_NONE);
- }
- }
- }
- else
- {
- DBG1(DBG_IKE, "CHILD_SA rekey collision lost, "
- "deleting rekeyed child");
- to_delete = this->child_create->get_child(this->child_create);
- }
- }
- else
- { /* CHILD_DELETE */
- child_delete_t *del = (child_delete_t*)this->collision;
-
- /* we didn't had a chance to compare the nonces, so we delete
- * the CHILD_SA the other is not deleting. */
- if (del->get_child(del) != this->child_sa)
- {
- DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, "
- "deleting rekeyed child");
- to_delete = this->child_sa;
- }
- else
- {
- DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, "
- "deleting redundant child");
- to_delete = this->child_create->get_child(this->child_create);
- }
- }
- return to_delete;
-}
-
-METHOD(task_t, process_i, status_t,
- private_child_rekey_t *this, message_t *message)
-{
- protocol_id_t protocol;
- u_int32_t spi;
- child_sa_t *to_delete;
-
- if (message->get_notify(message, NO_ADDITIONAL_SAS))
- {
- DBG1(DBG_IKE, "peer seems to not support CHILD_SA rekeying, "
- "starting reauthentication");
- this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
- lib->processor->queue_job(lib->processor,
- (job_t*)rekey_ike_sa_job_create(
- this->ike_sa->get_id(this->ike_sa), TRUE));
- return SUCCESS;
- }
-
- if (this->child_create->task.process(&this->child_create->task,
- message) == NEED_MORE)
- {
- /* bad DH group while rekeying, try again */
- this->child_create->task.migrate(&this->child_create->task, this->ike_sa);
- return NEED_MORE;
- }
- if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
- {
- /* establishing new child failed, reuse old. but not when we
- * received a delete in the meantime */
- if (!(this->collision &&
- this->collision->get_type(this->collision) == CHILD_DELETE))
- {
- job_t *job;
- u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
-
- job = (job_t*)rekey_child_sa_job_create(
- this->child_sa->get_reqid(this->child_sa),
- this->child_sa->get_protocol(this->child_sa),
- this->child_sa->get_spi(this->child_sa, TRUE));
- DBG1(DBG_IKE, "CHILD_SA rekeying failed, "
- "trying again in %d seconds", retry);
- this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
- lib->scheduler->schedule_job(lib->scheduler, job, retry);
- }
- return SUCCESS;
- }
-
- /* check for rekey collisions */
- if (this->collision)
- {
- to_delete = handle_collision(this);
- }
- else
- {
- to_delete = this->child_sa;
- }
-
- 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;
- }
- spi = to_delete->get_spi(to_delete, TRUE);
- protocol = to_delete->get_protocol(to_delete);
-
- /* rekeying done, delete the obsolete CHILD_SA using a subtask */
- this->child_delete = child_delete_create(this->ike_sa, protocol, spi);
- this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_delete;
- this->public.task.process = (status_t(*)(task_t*,message_t*))process_i_delete;
-
- return NEED_MORE;
-}
-
-METHOD(task_t, get_type, task_type_t,
- private_child_rekey_t *this)
-{
- return CHILD_REKEY;
-}
-
-METHOD(child_rekey_t, collide, void,
- private_child_rekey_t *this, task_t *other)
-{
- /* the task manager only detects exchange collision, but not if
- * the collision is for the same child. we check it here. */
- if (other->get_type(other) == CHILD_REKEY)
- {
- private_child_rekey_t *rekey = (private_child_rekey_t*)other;
- if (rekey->child_sa != this->child_sa)
- {
- /* not the same child => no collision */
- other->destroy(other);
- return;
- }
- }
- else if (other->get_type(other) == CHILD_DELETE)
- {
- child_delete_t *del = (child_delete_t*)other;
- if (del->get_child(del) == this->child_create->get_child(this->child_create))
- {
- /* peer deletes redundant child created in collision */
- this->other_child_destroyed = TRUE;
- other->destroy(other);
- return;
- }
- if (del->get_child(del) != this->child_sa)
- {
- /* not the same child => no collision */
- other->destroy(other);
- return;
- }
- }
- else
- {
- /* any other task is not critical for collisisions, ignore */
- other->destroy(other);
- return;
- }
- DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, CHILD_REKEY,
- task_type_names, other->get_type(other));
- DESTROY_IF(this->collision);
- this->collision = other;
-}
-
-METHOD(task_t, migrate, void,
- private_child_rekey_t *this, ike_sa_t *ike_sa)
-{
- if (this->child_create)
- {
- this->child_create->task.migrate(&this->child_create->task, ike_sa);
- }
- if (this->child_delete)
- {
- this->child_delete->task.migrate(&this->child_delete->task, ike_sa);
- }
- DESTROY_IF(this->collision);
-
- this->ike_sa = ike_sa;
- this->collision = NULL;
-}
-
-METHOD(task_t, destroy, void,
- private_child_rekey_t *this)
-{
- if (this->child_create)
- {
- this->child_create->task.destroy(&this->child_create->task);
- }
- if (this->child_delete)
- {
- this->child_delete->task.destroy(&this->child_delete->task);
- }
- DESTROY_IF(this->collision);
- free(this);
-}
-
-/*
- * Described in header.
- */
-child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol,
- u_int32_t spi)
-{
- private_child_rekey_t *this;
-
- INIT(this,
- .public = {
- .task = {
- .get_type = _get_type,
- .migrate = _migrate,
- .destroy = _destroy,
- },
- .collide = _collide,
- },
- .ike_sa = ike_sa,
- .protocol = protocol,
- .spi = spi,
- );
-
- if (protocol != PROTO_NONE)
- {
- this->public.task.build = _build_i;
- this->public.task.process = _process_i;
- this->initiator = TRUE;
- this->child_create = NULL;
- }
- else
- {
- this->public.task.build = _build_r;
- this->public.task.process = _process_r;
- this->initiator = FALSE;
- this->child_create = child_create_create(ike_sa, NULL, TRUE, NULL, NULL);
- }
-
- return &this->public;
-}