old child_sa gets deleted after rekeying
authorMartin Willi <martin@strongswan.org>
Fri, 9 Jun 2006 15:12:43 +0000 (15:12 -0000)
committerMartin Willi <martin@strongswan.org>
Fri, 9 Jun 2006 15:12:43 +0000 (15:12 -0000)
rekeying almost complete, but:
IKE_SA get in an invalid state when both initiate rekeying at the same time,

19 files changed:
src/charon/Makefile.am
src/charon/config/policies/policy.c
src/charon/encoding/payloads/delete_payload.c
src/charon/encoding/payloads/delete_payload.h
src/charon/encoding/payloads/payload.c
src/charon/queues/jobs/delete_child_sa_job.c
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/states/create_child_sa_requested.c
src/charon/sa/states/create_child_sa_requested.h
src/charon/sa/states/delete_child_sa_requested.c [new file with mode: 0644]
src/charon/sa/states/delete_child_sa_requested.h [new file with mode: 0644]
src/charon/sa/states/ike_sa_established.c
src/charon/testing/Makefile.am
src/charon/testing/generator_test.c
src/charon/testing/kernel_interface_test.c
src/charon/testing/testcases.c

index 93546c9..e5779fe 100644 (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 \
index 4e238a3..5f6706b 100644 (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;
 }
 
 /**
index 28e7880..eb8dee1 100644 (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);
 }
index a25d0f1..2314610 100644 (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,28 +117,41 @@ 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.
+        * Returned data are NOT copied.
         *
         * @param this                  calling delete_payload_t object
-        * @return                              SPI's chunk_t
+        * @return                              SPI's as chunk_t
+        * 
+        * @deprecated use create_spi_iterator
         */
-       chunk_t (*get_spis_clone) (delete_payload_t *this);
+       chunk_t (*get_spis) (delete_payload_t *this);
        
        /**
-        * @brief Get the SPI's.
+        * @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.
         * 
-        * Returned data are NOT copied.
+        * The resulting interators current() function returns
+        * u_int32_t SPIs directly.
         *
         * @param this                  calling delete_payload_t object
-        * @return                              SPI's as chunk_t
+        * @return                              iterator over SPIs
         */
-       chunk_t (*get_spis) (delete_payload_t *this);
+       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_ */
index b89e80a..be58adf 100644 (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:
index ccad910..2e5f024 100644 (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;
index 5c09b73..e1dff27 100644 (file)
@@ -93,6 +93,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
         */
        logger_t *logger;
@@ -379,6 +384,14 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
 }
 
 /**
+ * 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.
  */
 static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
@@ -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);
 }
index 921b570..2bbe95f 100644 (file)
@@ -146,6 +146,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.
         *
         * The status of ESP/AH SAs is logged with the supplied logger in
index 8dbca19..7ddf0d8 100644 (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);
index d73dc71..6b9d9b6 100644 (file)
@@ -464,6 +464,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.
         *  
         * @param this                          calling object
index cb53139..b9bf280 100644 (file)
@@ -86,6 +86,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.
         * 
         * Is logger of ike_sa!
@@ -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);
index ced6273..20c17b6 100644 (file)
@@ -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_*/
diff --git a/src/charon/sa/states/delete_child_sa_requested.c b/src/charon/sa/states/delete_child_sa_requested.c
new file mode 100644 (file)
index 0000000..4d4ea5f
--- /dev/null
@@ -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);
+}
diff --git a/src/charon/sa/states/delete_child_sa_requested.h b/src/charon/sa/states/delete_child_sa_requested.h
new file mode 100644 (file)
index 0000000..e70ff18
--- /dev/null
@@ -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_*/
index d408988..5841f74 100644 (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);
                }
        }
        
index 6648fbb..32f80d2 100644 (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 \
index 38f4c36..1b37985 100644 (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);
index 1df26e8..96b3aa6 100644 (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);
        
index ebcc01b..2c8c04a 100644 (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;