old child_sa gets deleted after rekeying

rekeying almost complete, but:
	IKE_SA get in an invalid state when both initiate rekeying at the same time,
This commit is contained in:
Martin Willi
2006-06-09 15:12:43 +00:00
parent 2a13996de0
commit 695723d4e8
19 changed files with 586 additions and 102 deletions
+1
View File
@@ -13,6 +13,7 @@ sa/states/ike_sa_init_responded.c sa/states/ike_sa_established.c sa/states/ike_s
sa/states/responder_init.c sa/states/responder_init.h sa/states/initiator_init.c sa/states/initiator_init.h \
sa/states/ike_sa_init_responded.h sa/states/ike_auth_requested.c sa/states/ike_auth_requested.h \
sa/states/delete_ike_sa_requested.h sa/states/delete_ike_sa_requested.c \
sa/states/delete_child_sa_requested.h sa/states/delete_child_sa_requested.c \
sa/states/create_child_sa_requested.c sa/states/create_child_sa_requested.h \
sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \
sa/ike_sa_id.c sa/ike_sa_id.h sa/authenticator.c sa/authenticator.h encoding/payloads/encryption_payload.c \
+3 -3
View File
@@ -315,8 +315,8 @@ static void add_proposal(private_policy_t *this, proposal_t *proposal)
*/
static u_int32_t get_soft_lifetime(policy_t *this)
{
srandom(time(NULL));
return 0; //5 + random() % 3;
srandom(time(NULL)+getpid());
return 5 + (random() % 10);
}
/**
@@ -324,7 +324,7 @@ static u_int32_t get_soft_lifetime(policy_t *this)
*/
static u_int32_t get_hard_lifetime(policy_t *this)
{
return 0; //9;
return 20;
}
/**
+69 -30
View File
@@ -71,6 +71,11 @@ struct private_delete_payload_t {
* The contained SPI's.
*/
chunk_t spis;
/**
* List containing u_int32_t spis
*/
linked_list_t *spi_list;
};
/**
@@ -121,23 +126,30 @@ encoding_rule_t delete_payload_encodings[] = {
*/
static status_t verify(private_delete_payload_t *this)
{
if ((this->protocol_id == 0) ||
(this->protocol_id > 3))
switch (this->protocol_id)
{
/* reserved IDs */
return FAILED;
case PROTO_AH:
case PROTO_ESP:
if (this->spi_size != 4)
{
return FAILED;
}
break;
case PROTO_IKE:
case 0:
/* IKE deletion has no spi assigned! */
if (this->spi_size != 0)
{
return FAILED;
}
break;
default:
return FAILED;
}
if (this->spis.len != (this->spi_count * this->spi_size))
{
return FAILED;
}
if ((this->protocol_id == PROTO_IKE) && (this->spis.len != 0))
{
/* IKE deletion has no spi assigned! */
return FAILED;
}
return SUCCESS;
}
@@ -225,16 +237,15 @@ static void set_spi_count (private_delete_payload_t *this, u_int16_t spi_count)
/**
* Implementation of delete_payload_t.get_spi_count.
*/
static u_int16_t get_spi_count (private_delete_payload_t *this)
static u_int16_t get_spi_count(private_delete_payload_t *this)
{
return (this->spi_count);
}
/**
* Implementation of delete_payload_t.set_spis.
*/
static void set_spis (private_delete_payload_t *this, chunk_t spis)
static void set_spis(private_delete_payload_t *this, chunk_t spis)
{
if (this->spis.ptr != NULL)
{
@@ -254,18 +265,41 @@ static chunk_t get_spis (private_delete_payload_t *this)
}
/**
* Implementation of delete_payload_t.get_spis_clone.
* Implementation of delete_payload_t.add_spi.
*/
static chunk_t get_spis_clone (private_delete_payload_t *this)
static void add_spi(private_delete_payload_t *this, u_int32_t spi)
{
chunk_t cloned_spis;
if (this->spis.ptr == NULL)
/* only add SPIs if AH|ESP, ignore others */
if (this->protocol_id == PROTO_AH || this->protocol_id == PROTO_ESP)
{
return (this->spis);
this->spi_count += 1;
this->spis.len += this->spi_size;
this->spis.ptr = realloc(this->spis.ptr, this->spis.len);
*(u_int32_t*)(this->spis.ptr + (this->spis.len / this->spi_size - 1)) = spi;
}
cloned_spis.ptr = clalloc(this->spis.ptr,this->spis.len);
cloned_spis.len = this->spis.len;
return cloned_spis;
}
/**
* Implementation of delete_payload_t.create_spi_iterator.
*/
static iterator_t* create_spi_iterator(private_delete_payload_t *this)
{
int i;
if (this->spi_list == NULL)
{
this->spi_list = linked_list_create();
/* only parse SPIs if AH|ESP */
if (this->protocol_id == PROTO_AH || this->protocol_id == PROTO_ESP)
{
for (i = 0; i < this->spi_count; i++)
{
u_int32_t spi = *(u_int32_t*)(this->spis.ptr + i * this->spi_size);
this->spi_list->insert_last(this->spi_list, (void*)spi);
}
}
}
return this->spi_list->create_iterator(this->spi_list, TRUE);
}
/**
@@ -275,16 +309,19 @@ static void destroy(private_delete_payload_t *this)
{
if (this->spis.ptr != NULL)
{
chunk_free(&(this->spis));
chunk_free(&this->spis);
}
if (this->spi_list)
{
this->spi_list->destroy(this->spi_list);
}
free(this);
}
/*
* Described in header
*/
delete_payload_t *delete_payload_create()
delete_payload_t *delete_payload_create(protocol_id_t protocol_id)
{
private_delete_payload_t *this = malloc_thing(private_delete_payload_t);
@@ -306,17 +343,19 @@ delete_payload_t *delete_payload_create()
this->public.set_spi_count = (void (*) (delete_payload_t *,u_int16_t)) set_spi_count;
this->public.get_spi_count = (u_int16_t (*) (delete_payload_t *)) get_spi_count;
this->public.set_spis = (void (*) (delete_payload_t *,chunk_t)) set_spis;
this->public.get_spis_clone = (chunk_t (*) (delete_payload_t *)) get_spis_clone;
this->public.get_spis = (chunk_t (*) (delete_payload_t *)) get_spis;
this->public.add_spi = (void (*) (delete_payload_t *,u_int32_t))add_spi;
this->public.create_spi_iterator = (iterator_t* (*) (delete_payload_t *)) create_spi_iterator;
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length =DELETE_PAYLOAD_HEADER_LENGTH;
this->protocol_id = PROTO_NONE;
this->spi_size = 0;
this->payload_length = DELETE_PAYLOAD_HEADER_LENGTH;
this->protocol_id = protocol_id;
this->spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0;
this->spi_count = 0;
this->spis = CHUNK_INITIALIZER;
this->spi_list = NULL;
return (&(this->public));
return (&this->public);
}
+32 -14
View File
@@ -61,6 +61,8 @@ struct delete_payload_t {
*
* @param this calling delete_payload_t object
* @param protocol_id protocol ID
*
* @deprecated is set by constructor
*/
void (*set_protocol_id) (delete_payload_t *this, protocol_id_t protocol_id);
@@ -74,10 +76,11 @@ struct delete_payload_t {
/**
* @brief Set the SPI size.
*
*
* @param this calling delete_payload_t object
* @param spi_size SPI size
*
* @deprecated is set by constructor
*/
void (*set_spi_size) (delete_payload_t *this, u_int8_t spi_size);
@@ -94,6 +97,8 @@ struct delete_payload_t {
*
* @param this calling delete_payload_t object
* @param spi_count SPI count
*
* @deprecated is incremented via add_spi
*/
void (*set_spi_count) (delete_payload_t *this, u_int16_t spi_count);
@@ -112,19 +117,11 @@ struct delete_payload_t {
*
* @param this calling delete_payload_t object
* @param data SPI's as chunk_t
*
* @deprecated use add_spi
*/
void (*set_spis) (delete_payload_t *this, chunk_t spis);
/**
* @brief Get the SPI's.
*
* Returned data are a copy of the internal one.
*
* @param this calling delete_payload_t object
* @return SPI's chunk_t
*/
chunk_t (*get_spis_clone) (delete_payload_t *this);
/**
* @brief Get the SPI's.
*
@@ -132,9 +129,30 @@ struct delete_payload_t {
*
* @param this calling delete_payload_t object
* @return SPI's as chunk_t
*
* @deprecated use create_spi_iterator
*/
chunk_t (*get_spis) (delete_payload_t *this);
/**
* @brief Add an SPI to the list of deleted SAs.
*
* @param this calling delete_payload_t object
* @param spi spi to add
*/
void (*add_spi) (delete_payload_t *this, u_int32_t spi);
/**
* @brief Get an iterator over the SPIs.
*
* The resulting interators current() function returns
* u_int32_t SPIs directly.
*
* @param this calling delete_payload_t object
* @return iterator over SPIs
*/
iterator_t *(*create_spi_iterator) (delete_payload_t *this);
/**
* @brief Destroys an delete_payload_t object.
*
@@ -146,11 +164,11 @@ struct delete_payload_t {
/**
* @brief Creates an empty delete_payload_t object.
*
* @return delete_payload_t object
* @param protocol_id protocol, such as AH|ESP
* @return delete_payload_t object
*
* @ingroup payloads
*/
delete_payload_t *delete_payload_create(void);
delete_payload_t *delete_payload_create(protocol_id_t protocol_id);
#endif /* DELETE_PAYLOAD_H_ */
+1 -1
View File
@@ -113,7 +113,7 @@ payload_t *payload_create(payload_type_t type)
case NOTIFY:
return (payload_t*)notify_payload_create();
case DELETE:
return (payload_t*)delete_payload_create();
return (payload_t*)delete_payload_create(0);
case VENDOR_ID:
return (payload_t*)vendor_id_payload_create();
case CONFIGURATION:
+1 -1
View File
@@ -70,7 +70,7 @@ static status_t execute(private_delete_child_sa_job_t *this)
return DESTROY_ME;
}
/* TODO */
ike_sa->delete_child_sa(ike_sa, this->reqid);
status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return DESTROY_ME;
+48 -28
View File
@@ -92,6 +92,11 @@ struct private_child_sa_t {
*/
u_int32_t hard_lifetime;
/**
* reqid of a CHILD_SA which rekeyed this one
*/
u_int32_t rekeyed;
/**
* CHILD_SAs own logger
*/
@@ -378,6 +383,14 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
return SUCCESS;
}
/**
* Implementation of child_sa_t.set_rekeyed.
*/
static void set_rekeyed(private_child_sa_t *this, u_int32_t reqid)
{
this->rekeyed = reqid;
}
/**
* Implementation of child_sa_t.log_status.
*/
@@ -428,42 +441,47 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
*/
static void destroy(private_child_sa_t *this)
{
/* delete all policies in the kernel */
sa_policy_t *policy;
while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
{
charon->kernel_interface->del_policy(charon->kernel_interface,
this->me.addr, this->other.addr,
policy->me.net, policy->other.net,
policy->me.net_mask, policy->other.net_mask,
XFRM_POLICY_OUT, policy->upper_proto);
charon->kernel_interface->del_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_IN, policy->upper_proto);
charon->kernel_interface->del_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_FWD, policy->upper_proto);
policy->me.net->destroy(policy->me.net);
policy->other.net->destroy(policy->other.net);
free(policy);
}
this->policies->destroy(this->policies);
/* delete SAs in the kernel, if they are set up */
if (this->protocol != PROTO_NONE)
{
charon->kernel_interface->del_sa(charon->kernel_interface,
this->other.addr, this->me.spi, this->protocol);
this->me.addr, this->me.spi, this->protocol);
charon->kernel_interface->del_sa(charon->kernel_interface,
this->me.addr, this->other.spi, this->protocol);
this->other.addr, this->other.spi, this->protocol);
}
/* delete all policies in the kernel */
while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
{
if (!this->rekeyed)
{
/* let rekeyed policies, as they are used by another child_sa */
charon->kernel_interface->del_policy(charon->kernel_interface,
this->me.addr, this->other.addr,
policy->me.net, policy->other.net,
policy->me.net_mask, policy->other.net_mask,
XFRM_POLICY_OUT, policy->upper_proto);
charon->kernel_interface->del_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_IN, policy->upper_proto);
charon->kernel_interface->del_policy(charon->kernel_interface,
this->other.addr, this->me.addr,
policy->other.net, policy->me.net,
policy->other.net_mask, policy->me.net_mask,
XFRM_POLICY_FWD, policy->upper_proto);
}
policy->me.net->destroy(policy->me.net);
policy->other.net->destroy(policy->other.net);
free(policy);
}
this->policies->destroy(this->policies);
free(this);
}
@@ -483,6 +501,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, u_int32_t soft_lifetime,
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
this->public.set_rekeyed = (void (*)(child_sa_t*,u_int32_t))set_rekeyed;
this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status;
this->public.destroy = (void(*)(child_sa_t*))destroy;
@@ -497,6 +516,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, u_int32_t soft_lifetime,
this->reqid = ++reqid;
this->policies = linked_list_create();
this->protocol = PROTO_NONE;
this->rekeyed = 0;
return (&this->public);
}
+12
View File
@@ -145,6 +145,18 @@ struct child_sa_t {
*/
status_t (*add_policies) (child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list);
/**
* @brief Mark this child_sa as rekeyed.
*
* Since an SA which rekeys a old SA shares the same policy,
* we must mark a child_sa as rekeyed. A so marked SA does
* not remove its policy, as the new SA uses it.
*
* @param this calling object
* @param reqid reqid of the SA which replaces this one.
*/
void (*set_rekeyed) (child_sa_t *this, u_int32_t reqid);
/**
* @brief Log the status of a child_sa to a logger.
*
+93 -7
View File
@@ -42,6 +42,7 @@
#include <sa/states/initiator_init.h>
#include <sa/states/responder_init.h>
#include <sa/states/create_child_sa_requested.h>
#include <sa/states/delete_child_sa_requested.h>
#include <sa/states/delete_ike_sa_requested.h>
#include <queues/jobs/retransmit_request_job.h>
#include <queues/jobs/delete_established_ike_sa_job.h>
@@ -898,7 +899,92 @@ static child_sa_t *get_child_sa(private_ike_sa_t *this, u_int32_t reqid)
*/
static status_t delete_child_sa(private_ike_sa_t *this, u_int32_t reqid)
{
return NOT_FOUND;
message_t *request;
child_sa_t *child_sa;
delete_payload_t *delete_payload;
state_t *old_state;
if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"Delete of a CHILD_SA whose IKE_SA not in state IKE_SA_ESTABLISHED, aborting");
return FAILED;
}
child_sa = get_child_sa(this, reqid);
if (child_sa == NULL)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"IKE_SA does not contain a CHILD_SA with reqid %d", reqid);
return FAILED;
}
build_message(this, INFORMATIONAL, TRUE, &request);
delete_payload = delete_payload_create(child_sa->get_protocol(child_sa));
delete_payload->add_spi(delete_payload, child_sa->get_spi(child_sa, FALSE));
request->add_payload(request, (payload_t*)delete_payload);
send_request(this, request);
old_state = this->current_state;
set_new_state(this, (state_t*)delete_child_sa_requested_create(&this->protected));
old_state->destroy(old_state);
return SUCCESS;
}
/**
* Implementation of protected_ike_sa_t.destroy_child_sa.
*/
static u_int32_t destroy_child_sa(private_ike_sa_t *this, u_int32_t spi)
{
iterator_t *iterator;
child_sa_t *child_sa;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->has_next(iterator))
{
iterator->current(iterator, (void**)&child_sa);
if (child_sa->get_spi(child_sa, TRUE) == spi)
{
iterator->remove(iterator);
break;
}
else
{
child_sa = NULL;
}
}
iterator->destroy(iterator);
if (child_sa == NULL)
{
this->logger->log(this->logger, ERROR,
"IKE_SA does not contain a CHILD_SA with spi 0x%x", spi);
return 0;
}
spi = child_sa->get_spi(child_sa, FALSE);
child_sa->destroy(child_sa);
return spi;
}
/**
* Implementation of protected_ike_sa_t.get_child_sa.
*/
static child_sa_t* get_child_sa_by_spi(private_ike_sa_t *this, u_int32_t spi)
{
iterator_t *iterator;
child_sa_t *current, *found = NULL;
iterator = this->child_sas->create_iterator(this->child_sas, FALSE);
while (iterator->has_next(iterator))
{
iterator->current(iterator, (void**)&current);
if (current->get_spi(current, TRUE) == spi)
{
found = current;
}
}
iterator->destroy(iterator);
return found;
}
/**
@@ -920,7 +1006,7 @@ static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
if (this->current_state->get_state(this->current_state) != IKE_SA_ESTABLISHED)
{
this->logger->log(this->logger, ERROR|LEVEL1,
"Rekeying of an IKE_SA not in state IKE_SA_ESTABLISHED, aborting", reqid);
"Rekeying of an CHILD_SA whose IKE_SA not in state IKE_SA_ESTABLISHED, aborting");
return FAILED;
}
@@ -935,7 +1021,7 @@ static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
build_message(this, CREATE_CHILD_SA, TRUE, &request);
notify = notify_payload_create_from_protocol_and_type(
child_sa->get_protocol(child_sa), REKEY_SA);
notify->set_spi(notify, child_sa->get_spi(child_sa, TRUE));
notify->set_spi(notify, child_sa->get_spi(child_sa, FALSE));
request->add_payload(request, (payload_t*)notify);
proposals = this->policy->get_proposals(this->policy);
@@ -967,7 +1053,7 @@ static status_t rekey_child_sa(private_ike_sa_t *this, u_int32_t reqid)
send_request(this, request);
old_state = this->current_state;
set_new_state(this, (state_t*)create_child_sa_requested_create(&this->protected, child_sa, nonce));
set_new_state(this, (state_t*)create_child_sa_requested_create(&this->protected, child_sa, nonce, reqid));
old_state->destroy(old_state);
return SUCCESS;
@@ -1074,8 +1160,7 @@ static status_t delete_(private_ike_sa_t *this)
build_message(this, INFORMATIONAL, TRUE, &informational_request);
/* delete for the full IKE_SA, this deletes all child_sa's implicit */
delete_payload = delete_payload_create();
delete_payload->set_protocol_id(delete_payload, PROTO_IKE);
delete_payload = delete_payload_create(PROTO_IKE);
informational_request->add_payload(informational_request, (payload_t*)delete_payload);
@@ -1241,8 +1326,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->protected.reset_message_buffers = (void (*) (protected_ike_sa_t *)) reset_message_buffers;
this->protected.get_last_responded_message = (message_t * (*) (protected_ike_sa_t *)) get_last_responded_message;
this->protected.get_last_requested_message = (message_t * (*) (protected_ike_sa_t *)) get_last_requested_message;
this->protected.set_last_replied_message_id = (void (*) (protected_ike_sa_t *,u_int32_t)) set_last_replied_message_id;
this->protected.destroy_child_sa = (u_int32_t (*)(protected_ike_sa_t*,u_int32_t))destroy_child_sa;
this->protected.get_child_sa = (child_sa_t* (*)(protected_ike_sa_t*,u_int32_t))get_child_sa_by_spi;
/* initialize private fields */
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
+18
View File
@@ -463,6 +463,24 @@ struct protected_ike_sa_t {
*/
void (*add_child_sa) (protected_ike_sa_t *this, child_sa_t *child_sa);
/**
* @brief Destroys a CHILD_SA upon request from the other peer.
*
* @param this calling object
* @param spi inbound spi of the CHILD_SA to destroy
* @return outbound spi of the destroyed CHILD_SA
*/
u_int32_t (*destroy_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
/**
* @brief Get a CHILD_SA upon request from the other peer.
*
* @param this calling object
* @param spi spi of the CHILD_SA
* @return child_sa, or NULL if none found
*/
child_sa_t* (*get_child_sa) (protected_ike_sa_t *this, u_int32_t spi);
/**
* @brief Get the last responded message.
*
@@ -85,6 +85,11 @@ struct private_create_child_sa_requested_t {
*/
child_sa_t *child_sa;
/**
* Reqid of the old CHILD_SA, when rekeying
*/
u_int32_t reqid;
/**
* Assigned logger.
*
@@ -205,6 +210,7 @@ static status_t process_message(private_create_child_sa_requested_t *this, messa
status_t status;
chunk_t seed;
prf_plus_t *prf_plus;
child_sa_t *old_child_sa;
this->policy = this->ike_sa->get_policy(this->ike_sa);
if (response->get_exchange_type(response) != CREATE_CHILD_SA)
@@ -339,7 +345,7 @@ static status_t process_message(private_create_child_sa_requested_t *this, messa
memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
this->logger->log_chunk(this->logger, CONTROL, "Seed", seed);
this->logger->log_chunk(this->logger, RAW|LEVEL2, "Rekey seed", seed);
chunk_free(&seed);
status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
@@ -364,6 +370,17 @@ static status_t process_message(private_create_child_sa_requested_t *this, messa
this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
this->public.state_interface.destroy(&this->public.state_interface);
/* if we are rekeying, inform the old child SA that it has been superseeded and
* start its delete */
if (this->reqid)
{
old_child_sa = this->ike_sa->public.get_child_sa(&this->ike_sa->public, this->reqid);
if (old_child_sa)
{
old_child_sa->set_rekeyed(old_child_sa, this->child_sa->get_reqid(this->child_sa));
}
this->ike_sa->public.delete_child_sa(&this->ike_sa->public, this->reqid);
}
return SUCCESS;
}
@@ -388,7 +405,7 @@ static void destroy(private_create_child_sa_requested_t *this)
/*
* Described in header.
*/
create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i)
create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i, u_int32_t reqid)
{
private_create_child_sa_requested_t *this = malloc_thing(private_create_child_sa_requested_t);
@@ -402,6 +419,7 @@ create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t
this->child_sa = child_sa;
this->nonce_i = nonce_i;
this->nonce_r = CHUNK_INITIALIZER;
this->reqid = reqid;
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
return &(this->public);
@@ -47,13 +47,18 @@ struct create_child_sa_requested_t {
/**
* @brief Constructor of class create_child_sa_requested_t
*
* If this CREATE_CHILD_SA message is to rekey a CHILD_SA,
* the child_sa with the specified reqid gets deleted after a new
* one is set up.
*
* @param ike_sa assigned ike_sa
* @param child_sa newly created child sa to complete
* @param nonce nonce sent at initialization
* @param reqid reqid, when rekeying a child SA.
* @return created create_child_sa_requested_t object
*
* @ingroup states
*/
create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i);
create_child_sa_requested_t *create_child_sa_requested_create(protected_ike_sa_t *ike_sa, child_sa_t *child_sa, chunk_t nonce_i, u_int32_t reqid);
#endif /*CREATE_CHILD_SA_REQEUSTED_H_*/
@@ -0,0 +1,177 @@
/**
* @file delete_child_sa_requested.c
*
* @brief State after a CREATE_CHILD_SA request was sent.
*
*/
/*
* Copyright (C) 2006 Martin Willi
* 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 <string.h>
#include "delete_child_sa_requested.h"
#include <sa/child_sa.h>
#include <sa/states/delete_ike_sa_requested.h>
#include <sa/states/ike_sa_established.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/delete_payload.h>
#include <utils/logger_manager.h>
typedef struct private_delete_child_sa_requested_t private_delete_child_sa_requested_t;
/**
* Private data of a delete_child_sa_requested_t object.
*/
struct private_delete_child_sa_requested_t {
/**
* Public interface of delete_child_sa_requested_t.
*/
delete_child_sa_requested_t public;
/**
* Assigned IKE_SA.
*/
protected_ike_sa_t *ike_sa;
/**
* Assigned logger.
*
* Is logger of ike_sa!
*/
logger_t *logger;
};
/**
* Process the response
*/
static status_t process_message(private_delete_child_sa_requested_t *this, message_t *response)
{
ike_sa_id_t *ike_sa_id;
crypter_t *crypter;
signer_t *signer;
status_t status;
iterator_t *iterator;
payload_t *payload;
delete_payload_t *delete_response;
if (response->get_exchange_type(response) != INFORMATIONAL)
{
this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state delete_child_sa_requested",
mapping_find(exchange_type_m, response->get_exchange_type(response)));
return FAILED;
}
if (response->get_request(response))
{
this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL requests not allowed state delete_child_sa_requested");
return FAILED;
}
/* get signer for verification and crypter for decryption */
ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public);
if (!ike_sa_id->is_initiator(ike_sa_id))
{
crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
signer = this->ike_sa->get_signer_initiator(this->ike_sa);
}
else
{
crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
signer = this->ike_sa->get_signer_responder(this->ike_sa);
}
/* parse incoming message */
status = response->parse_body(response, crypter, signer);
if (status != SUCCESS)
{
this->logger->log(this->logger, AUDIT, "INFORMATIONAL response decryption failed. Ignoring message");
return status;
}
iterator = response->get_payload_iterator(response);
while (iterator->has_next(iterator)) {
iterator->current(iterator, (void**)&payload);
switch (payload->get_type(payload))
{
case DELETE:
delete_response = (delete_payload_t*)payload;
break;
default:
break;
}
}
iterator->destroy(iterator);
if (delete_response)
{
iterator = delete_response->create_spi_iterator(delete_response);
while (iterator->has_next(iterator))
{
u_int32_t spi;
iterator->current(iterator, (void**)&spi);
this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA with SPI 0x%x received", spi);
this->ike_sa->destroy_child_sa(this->ike_sa, spi);
}
iterator->destroy(iterator);
}
this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
/* create new state */
this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
this->public.state_interface.destroy(&this->public.state_interface);
return SUCCESS;
}
/**
* Implements state_t.get_state
*/
static ike_sa_state_t get_state(private_delete_child_sa_requested_t *this)
{
return DELETE_CHILD_SA_REQUESTED;
}
/**
* Implementation of state_t.destroy.
*/
static void destroy(private_delete_child_sa_requested_t *this)
{
free(this);
}
/*
* Described in header.
*/
delete_child_sa_requested_t *delete_child_sa_requested_create(protected_ike_sa_t *ike_sa)
{
private_delete_child_sa_requested_t *this = malloc_thing(private_delete_child_sa_requested_t);
/* interface functions */
this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
/* private data */
this->ike_sa = ike_sa;
this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
return &(this->public);
}
@@ -0,0 +1,57 @@
/**
* @file delete_child_sa_requested.h
*
* @brief Interface of delete_child_sa_requested_t.
*
*/
/*
* Copyright (C) 2006 Martin Willi
* 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.
*/
#ifndef DELETE_CHILD_SA_REQEUSTED_H_
#define DELETE_CHILD_SA_REQEUSTED_H_
#include <sa/states/state.h>
#include <sa/ike_sa.h>
#include <sa/child_sa.h>
typedef struct delete_child_sa_requested_t delete_child_sa_requested_t;
/**
* @brief State after a CREATE_CHILD_SA request was sent.
*
* @b Constructors:
* - delete_child_sa_requested_create()
*
* @ingroup states
*/
struct delete_child_sa_requested_t {
/**
* methods of the state_t interface
*/
state_t state_interface;
};
/**
* @brief Constructor of class delete_child_sa_requested_t
*
* @param ike_sa assigned ike_sa
* @return created delete_child_sa_requested_t object
*
* @ingroup states
*/
delete_child_sa_requested_t *delete_child_sa_requested_create(protected_ike_sa_t *ike_sa);
#endif /*DELETE_CHILD_SA_REQEUSTED_H_*/
+31 -5
View File
@@ -125,7 +125,7 @@ static status_t build_sa_payload(private_ike_sa_established_t *this, sa_payload_
memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
this->logger->log_chunk(this->logger, CONTROL, "Seed", seed);
this->logger->log_chunk(this->logger, RAW|LEVEL2, "Rekey seed", seed);
chunk_free(&seed);
policy = this->ike_sa->get_policy(this->ike_sa);
@@ -240,8 +240,10 @@ static status_t process_create_child_sa(private_ike_sa_established_t *this, mess
ts_payload_t *tsi_request = NULL, *tsr_request = NULL;
sa_payload_t *sa_request = NULL;
nonce_payload_t *nonce_request = NULL;
notify_payload_t *notify = NULL;
iterator_t *payloads;
status_t status;
child_sa_t *old_child_sa;
/* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
payloads = request->get_payload_iterator(request);
@@ -260,7 +262,7 @@ static status_t process_create_child_sa(private_ike_sa_established_t *this, mess
case TRAFFIC_SELECTOR_INITIATOR:
{
tsi_request = (ts_payload_t*)payload;
break;
break;
}
case TRAFFIC_SELECTOR_RESPONDER:
{
@@ -274,7 +276,7 @@ static status_t process_create_child_sa(private_ike_sa_established_t *this, mess
}
case NOTIFY:
{
/* TODO: handle notifys */
notify = (notify_payload_t*)payload;
break;
}
default:
@@ -351,6 +353,16 @@ static status_t process_create_child_sa(private_ike_sa_established_t *this, mess
{
this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy!");
}
if (notify && notify->get_notify_message_type(notify) == REKEY_SA)
{
/* mark old child sa as rekeyed */
old_child_sa = this->ike_sa->get_child_sa(this->ike_sa, notify->get_spi(notify));
if (old_child_sa)
{
old_child_sa->set_rekeyed(old_child_sa, this->child_sa->get_reqid(this->child_sa));
}
}
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
}
@@ -403,8 +415,22 @@ static status_t process_informational(private_ike_sa_established_t *this, messag
}
else
{
this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA received. Ignored");
return SUCCESS;
iterator_t *iterator;
delete_payload_t *delete_response = delete_payload_create(delete_request->get_protocol_id(delete_request));
iterator = delete_request->create_spi_iterator(delete_request);
while (iterator->has_next(iterator))
{
u_int32_t spi;
iterator->current(iterator, (void**)&spi);
this->logger->log(this->logger, CONTROL, "DELETE request for CHILD_SA with SPI 0x%x received", spi);
spi = this->ike_sa->destroy_child_sa(this->ike_sa, spi);
if (spi)
{
delete_response->add_spi(delete_response, spi);
}
}
iterator->destroy(iterator);
response->add_payload(response, (payload_t*)delete_response);
}
}
+1
View File
@@ -20,6 +20,7 @@ $(top_srcdir)/src/charon/local_policy_store.o $(top_srcdir)/src/charon/local_cre
$(top_srcdir)/src/charon/proposal.o $(top_srcdir)/src/charon/configuration.o $(top_srcdir)/src/charon/state.o $(top_srcdir)/src/charon/ike_sa_init_requested.o \
$(top_srcdir)/src/charon/ike_sa_init_responded.o $(top_srcdir)/src/charon/ike_sa_established.o $(top_srcdir)/src/charon/responder_init.o \
$(top_srcdir)/src/charon/initiator_init.o $(top_srcdir)/src/charon/ike_auth_requested.o $(top_srcdir)/src/charon/delete_ike_sa_requested.o \
$(top_srcdir)/src/charon/delete_child_sa_requested.o \
$(top_srcdir)/src/charon/child_sa.o $(top_srcdir)/src/charon/ike_sa.o $(top_srcdir)/src/charon/ike_sa_manager.o $(top_srcdir)/src/charon/ike_sa_id.o \
$(top_srcdir)/src/charon/authenticator.o $(top_srcdir)/src/charon/encryption_payload.o $(top_srcdir)/src/charon/cert_payload.o \
$(top_srcdir)/src/charon/traffic_selector_substructure.o $(top_srcdir)/src/charon/transform_attribute.o $(top_srcdir)/src/charon/configuration_attribute.o \
+1 -2
View File
@@ -1091,13 +1091,12 @@ void test_generator_with_delete_payload(protected_tester_t *tester)
generator = generator_create();
tester->assert_true(tester,(generator != NULL), "generator create check");
delete_payload = delete_payload_create();
delete_payload = delete_payload_create(PROTO_AH);
spis.ptr = "123456789012";
spis.len = strlen(spis.ptr);
delete_payload->set_protocol_id(delete_payload, PROTO_AH);
delete_payload->set_spi_count(delete_payload,3);
delete_payload->set_spi_size(delete_payload,4);
delete_payload->set_spis(delete_payload,spis);
+13 -6
View File
@@ -57,28 +57,35 @@ void test_kernel_interface(protected_tester_t *tester)
me = host_create(AF_INET, "192.168.0.2", 0);
other = host_create(AF_INET, "192.168.0.3", 0);
status = kernel_interface->get_spi(kernel_interface, me, other, 50, 1234, &spi);
status = kernel_interface->get_spi(kernel_interface, me, other, PROTO_ESP, 1234, &spi);
tester->assert_true(tester, status == SUCCESS, "spi get");
status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, 1234, 5, 10, &enc_alg, &int_alg, prf_plus, TRUE);
status = kernel_interface->add_sa(kernel_interface, me, other, spi, PROTO_ESP, 1234, 0, 0, &enc_alg, &int_alg, prf_plus, TRUE);
tester->assert_true(tester, status == SUCCESS, "add sa");
left = host_create(AF_INET, "10.1.0.0", 0);
right = host_create(AF_INET, "10.2.0.0", 0);
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0, PROTO_ESP, 1234);
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 24, 24, XFRM_POLICY_OUT, 0, PROTO_ESP, 1234);
tester->assert_true(tester, status == SUCCESS, "add policy OUT");
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_IN, 0, PROTO_ESP, 1234);
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 24, 24, XFRM_POLICY_OUT, 0, PROTO_ESP, 2345);
tester->assert_true(tester, status == SUCCESS, "add policy OUT");
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 24, 24, XFRM_POLICY_IN, 0, PROTO_ESP, 1234);
tester->assert_true(tester, status == SUCCESS, "add policy IN");
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_FWD, 0, PROTO_ESP, 1234);
status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 24, 24, XFRM_POLICY_FWD, 0, PROTO_ESP, 1234);
tester->assert_true(tester, status == SUCCESS, "add policy FWD");
kernel_interface->del_sa(kernel_interface, other, spi, PROTO_ESP);
sleep(10);
me->destroy(me);
other->destroy(other);
left->destroy(left);
right->destroy(right);
sleep(15);
kernel_interface->destroy(kernel_interface);
+2 -2
View File
@@ -159,12 +159,12 @@ daemon_t *daemon_create()
/* assign methods */
charon->kill = daemon_kill;
charon->socket = socket_create(500);
//charon->socket = socket_create(500);
charon->ike_sa_manager = ike_sa_manager_create();
charon->job_queue = job_queue_create();
charon->event_queue = event_queue_create();
charon->send_queue = send_queue_create();
charon->kernel_interface = kernel_interface_create();
//charon->kernel_interface = kernel_interface_create();
//charon->configuration = configuration_create(RETRANSMIT_TIMEOUT,MAX_RETRANSMIT_COUNT,HALF_OPEN_IKE_SA_TIMEOUT);
charon->sender = NULL;
charon->receiver = NULL;